Update to Angelscript 2.35.1

This commit is contained in:
Deukhoofd 2022-04-02 15:12:50 +02:00
parent badd37a7d3
commit 6734aa44ec
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
33 changed files with 650 additions and 316 deletions

View File

@ -551,12 +551,9 @@ struct Id {
template <typename T>
Id<T> id(T /*fn_ptr*/) { return Id<T>(); }
// On some versions of GNUC it is necessary to use the template keyword as disambiguator,
// on others the template keyword gives an error, hence the need for the following define.
// MSVC on the other hand seems to accept both with or without the template keyword.
#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
// GNUC 4.4.3 doesn't need the template keyword, and
// hopefully upcoming versions won't need it either
// On GNUC it is necessary to use the template keyword as disambiguator.
// MSVC seems to accept both with or without the template keyword.
#if defined(__GNUC__)
#define TMPL template
#else
#define TMPL
@ -568,7 +565,7 @@ Id<T> id(T /*fn_ptr*/) { return Id<T>(); }
#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >())
#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (*)Parameters>::TMPL f< name >))
#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::TMPL f< &ClassType::name >))
#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::TMPL f< AS_METHOD_AMBIGUITY_CAST(ReturnType (ClassType::*)Parameters)(&ClassType::name) >))
#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst<ReturnType (*)Parameters>::TMPL f< name >))
#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast<ReturnType (*)Parameters>::TMPL f< name >))

View File

@ -113,12 +113,9 @@ int main()
"template <typename T>\n"
"Id<T> id(T fn_ptr) { return Id<T>(); }\n"
"\n"
"// On some versions of GNUC it is necessary to use the template keyword as disambiguator,\n"
"// on others the template keyword gives an error, hence the need for the following define.\n"
"// MSVC on the other hand seems to accept both with or without the template keyword.\n"
"#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))\n"
" // GNUC 4.4.3 doesn't need the template keyword, and\n"
" // hopefully upcoming versions won't need it either\n"
"// On GNUC it is necessary to use the template keyword as disambiguator.\n"
"// MSVC seems to accept both with or without the template keyword.\n"
"#if defined(__GNUC__)\n"
" #define TMPL template\n"
"#else\n"
" #define TMPL\n"
@ -130,7 +127,7 @@ int main()
"#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >())\n"
"\n"
"#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (*)Parameters>::TMPL f< name >))\n"
"#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::TMPL f< &ClassType::name >))\n"
"#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::TMPL f< AS_METHOD_AMBIGUITY_CAST(ReturnType (ClassType::*)Parameters)(&ClassType::name) >))\n"
"#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst<ReturnType (*)Parameters>::TMPL f< name >))\n"
"#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast<ReturnType (*)Parameters>::TMPL f< name >))\n"
"\n"

View File

@ -20,6 +20,7 @@ static tm time_point_to_tm(const std::chrono::time_point<std::chrono::system_clo
#ifdef _MSC_VER
gmtime_s(&local, &t);
#else
// TODO: gmtime is not threadsafe
local = *gmtime(&t);
#endif
return local;
@ -33,23 +34,15 @@ static bool tm_to_time_point(const tm &_tm, std::chrono::time_point<std::chrono:
// Do not rely on timezone, as it is not portable
// ref: https://stackoverflow.com/questions/38298261/why-there-is-no-inverse-function-for-gmtime-in-libc
// ref: https://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
localTm.tm_isdst = -1; // Always use current settings, so mktime doesn't modify the time for daylight savings
// TODO: mktime is not threadsafe
time_t t = mktime(&localTm);
if (t == -1)
return false;
// Adjust the time_t since epoch with the difference of the local timezone to the universal timezone
// TODO: localtime, gmtime, and mktime are not threadsafe
t += (mktime(localtime(&t)) - mktime(gmtime(&t)));
// Verify if the members were modified, indicating an out-of-range value in input
if (localTm.tm_year != _tm.tm_year ||
localTm.tm_mon != _tm.tm_mon ||
localTm.tm_mday != _tm.tm_mday ||
localTm.tm_hour != _tm.tm_hour ||
localTm.tm_min != _tm.tm_min ||
localTm.tm_sec != _tm.tm_sec)
return false;
tp = system_clock::from_time_t(t);
return true;
}
@ -111,7 +104,20 @@ bool CDateTime::setDate(asUINT year, asUINT month, asUINT day)
local.tm_mon = month - 1;
local.tm_mday = day;
return tm_to_time_point(local, tp);
std::chrono::time_point<std::chrono::system_clock> newTp;
if (!tm_to_time_point(local, newTp))
return false;
// Check if the date was actually valid
tm local2 = time_point_to_tm(newTp);
if (local.tm_year != local2.tm_year ||
local.tm_mon != local2.tm_mon ||
local.tm_mday != local2.tm_mday)
return false;
tp = newTp;
return true;
}
bool CDateTime::setTime(asUINT hour, asUINT minute, asUINT second)
@ -121,7 +127,20 @@ bool CDateTime::setTime(asUINT hour, asUINT minute, asUINT second)
local.tm_min = minute;
local.tm_sec = second;
return tm_to_time_point(local, tp);
std::chrono::time_point<std::chrono::system_clock> newTp;
if (!tm_to_time_point(local, newTp))
return false;
// Check if the time was actually valid
tm local2 = time_point_to_tm(newTp);
if (local.tm_hour != local2.tm_hour ||
local.tm_min != local2.tm_min ||
local.tm_sec != local2.tm_sec)
return false;
tp = newTp;
return true;
}
CDateTime::CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second)

View File

@ -1331,6 +1331,19 @@ void CScriptArray::Copy(void *dst, void *src)
}
// internal
// Swap two elements
// Even in arrays of objects the objects are allocated on
// the heap and the array stores the pointers to the objects.
void CScriptArray::Swap(void* a, void* b)
{
asBYTE tmp[16];
Copy(tmp, a);
Copy(a, b);
Copy(b, tmp);
}
// internal
// Return pointer to array item (object handle or primitive value)
void *CScriptArray::GetArrayItemPointer(int index)
@ -1574,32 +1587,31 @@ void CScriptArray::Sort(asIScriptFunction *func, asUINT startAt, asUINT count)
if (cmpContext == 0)
cmpContext = objType->GetEngine()->RequestContext();
// Insertion sort
asBYTE tmp[16];
for (asUINT i = start + 1; i < end; i++)
// TODO: Security issue: If the array is accessed from the callback while the sort is going on the result may be unpredictable
// For example, the callback resizes the array in the middle of the sort
// Possible solution: set a lock flag on the array, and prohibit modifications while the lock flag is set
// Bubble sort
// TODO: optimize: Use an efficient sort algorithm
for (asUINT i = start; i+1 < end; i++)
{
Copy(tmp, GetArrayItemPointer(i));
asUINT j = i - 1;
while (j != 0xFFFFFFFF && j >= start )
asUINT best = i;
for (asUINT j = i + 1; j < end; j++)
{
cmpContext->Prepare(func);
cmpContext->SetArgAddress(0, GetDataPointer(tmp));
cmpContext->SetArgAddress(1, At(j));
cmpContext->SetArgAddress(0, At(j));
cmpContext->SetArgAddress(1, At(best));
int r = cmpContext->Execute();
if (r != asEXECUTION_FINISHED)
break;
if (*(bool*)(cmpContext->GetAddressOfReturnValue()))
{
Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j));
j--;
}
else
break;
best = j;
}
Copy(GetArrayItemPointer(j + 1), tmp);
// With Swap we guarantee that the array always sees all references
// if the GC calls the EnumReferences in the middle of the sorting
if( best != i )
Swap(GetArrayItemPointer(i), GetArrayItemPointer(best));
}
if (cmpContext)
@ -2170,8 +2182,9 @@ static void RegisterScriptArray_Generic(asIScriptEngine *engine)
r = engine->RegisterObjectMethod("array<T>", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef2_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("array<T>", "bool opEquals(const array<T>&in) const", asFUNCTION(ScriptArrayEquals_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("array<T>", "bool isEmpty() const", asFUNCTION(ScriptArrayIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterFuncdef("bool array<T>::less(const T&in a, const T&in b)");
r = engine->RegisterFuncdef("bool array<T>::less(const T&in if_handle_then_const a, const T&in if_handle_then_const b)");
r = engine->RegisterObjectMethod("array<T>", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asFUNCTION(ScriptArraySortCallback_Generic), asCALL_GENERIC); assert(r >= 0);
#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1
r = engine->RegisterObjectMethod("array<T>", "uint get_length() const property", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("array<T>", "void set_length(uint) property", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 );

View File

@ -124,6 +124,7 @@ protected:
void *GetArrayItemPointer(int index);
void *GetDataPointer(void *buffer);
void Copy(void *dst, void *src);
void Swap(void *a, void *b);
void Precache();
bool CheckMaxSize(asUINT numElements);
void Resize(int delta, asUINT at);

View File

@ -302,7 +302,7 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
declaration.reserve(100);
#endif
// Then check for meta data and #include directives
// Then check for meta data and pre-processor directives
pos = 0;
while( pos < modifiedScript.size() )
{
@ -313,10 +313,19 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
pos += len;
continue;
}
string token;
token.assign(&modifiedScript[pos], len);
#if AS_PROCESS_METADATA == 1
// Check if class
if( currentClass == "" && modifiedScript.substr(pos,len) == "class" )
// Skip possible decorators before class and interface declarations
if (token == "shared" || token == "abstract" || token == "mixin" || token == "external")
{
pos += len;
continue;
}
// Check if class or interface so the metadata for members can be gathered
if( currentClass == "" && (token == "class" || token == "interface") )
{
// Get the identifier after "class"
do
@ -362,15 +371,15 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
}
// Check if end of class
if( currentClass != "" && modifiedScript[pos] == '}' )
if( currentClass != "" && token == "}" )
{
currentClass = "";
pos += len;
continue;
}
// Check if namespace
if( modifiedScript.substr(pos,len) == "namespace" )
// Check if namespace so the metadata for members can be gathered
if( token == "namespace" )
{
// Get the identifier after "namespace"
do
@ -403,7 +412,7 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
}
// Check if end of namespace
if( currentNamespace != "" && modifiedScript[pos] == '}' )
if( currentNamespace != "" && token == "}" )
{
size_t found = currentNamespace.rfind( "::" );
if( found != string::npos )
@ -419,7 +428,7 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
}
// Is this the start of metadata?
if( modifiedScript[pos] == '[' )
if( token == "[" )
{
// Get the metadata string
pos = ExtractMetadata(pos, metadata);
@ -438,37 +447,36 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
else
#endif
// Is this a preprocessor directive?
if( modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) )
if( token == "#" && (pos + 1 < modifiedScript.size()) )
{
int start = pos++;
t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len);
if( t == asTC_IDENTIFIER )
if (t == asTC_IDENTIFIER)
{
string token;
token.assign(&modifiedScript[pos], len);
if( token == "include" )
if (token == "include")
{
pos += len;
t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len);
if( t == asTC_WHITESPACE )
if (t == asTC_WHITESPACE)
{
pos += len;
t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len);
}
if( t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\'') )
if (t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\''))
{
// Get the include file
string includefile;
includefile.assign(&modifiedScript[pos+1], len-2);
includefile.assign(&modifiedScript[pos + 1], len - 2);
pos += len;
// Store it for later processing
includes.push_back(includefile);
// Overwrite the include directive with space characters to avoid compiler error
OverwriteCode(start, pos-start);
OverwriteCode(start, pos - start);
}
}
else if (token == "pragma")
@ -491,6 +499,19 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
OverwriteCode(start, pos - start);
}
}
else
{
// Check for lines starting with #!, e.g. shebang interpreter directive. These will be treated as comments and removed by the preprocessor
if (modifiedScript[pos] == '!')
{
// Read until the end of the line
pos += len;
for (; pos < modifiedScript.size() && modifiedScript[pos] != '\n'; pos++);
// Overwrite the directive with space characters to avoid compiler error
OverwriteCode(start, pos - start);
}
}
}
// Don't search for metadata/includes within statement blocks or between tokens in statements
else

View File

@ -1140,7 +1140,6 @@ void RegisterScriptDictionary_Native(asIScriptEngine *engine)
// Same as deleteAll
r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
#endif
(void)r;
// Cache some things the dictionary will need at runtime
SDictionaryCache::Setup(engine);
@ -1209,7 +1208,6 @@ void RegisterScriptDictionary_Generic(asIScriptEngine *engine)
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
(void)r;
// Cache some things the dictionary will need at runtime
SDictionaryCache::Setup(engine);
}

View File

@ -1,5 +1,6 @@
#include "scriptfilesystem.h"
#include "../autowrapper/aswrappedcall.h"
#include <string.h> // strstr()
#if defined(_WIN32)
#include <direct.h> // _getcwd
@ -383,6 +384,7 @@ asINT64 CScriptFileSystem::GetSize(const string &path) const
// - path not found
// - access denied
// TODO: Should be able to define the permissions for the directory
// TODO: Should support recursively creating directories
int CScriptFileSystem::MakeDir(const string &path)
{
string search;

View File

@ -222,9 +222,8 @@ void CScriptHandle::EnumReferences(asIScriptEngine *inEngine)
inEngine->GCEnumCallback(m_type);
}
void CScriptHandle::ReleaseReferences(asIScriptEngine *inEngine)
void CScriptHandle::ReleaseReferences(asIScriptEngine * /*inEngine*/)
{
(void)inEngine;
// Simply clear the content to release the references
Set(0, 0);
}
@ -250,7 +249,6 @@ void RegisterScriptHandle_Native(asIScriptEngine *engine)
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 );
(void)r;
}
void CScriptHandle_Construct_Generic(asIScriptGeneric *gen)
@ -348,7 +346,6 @@ void RegisterScriptHandle_Generic(asIScriptEngine *engine)
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 );
(void)r;
}
void RegisterScriptHandle(asIScriptEngine *engine)

View File

@ -5,6 +5,7 @@
#include <fstream>
#include <set>
#include <stdlib.h>
#include "../autowrapper/aswrappedcall.h"
using namespace std;
@ -980,9 +981,16 @@ void RegisterExceptionRoutines(asIScriptEngine *engine)
// The string type must be available
assert(engine->GetTypeInfoByDecl("string"));
r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0);
(void)r;
if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") == 0)
{
r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0);
}
else
{
r = engine->RegisterGlobalFunction("void throw(const string &in)", WRAP_FN(ScriptThrow), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterGlobalFunction("string getExceptionInfo()", WRAP_FN(ScriptGetExceptionInfo), asCALL_GENERIC); assert(r >= 0);
}
}
END_AS_NAMESPACE

View File

@ -72,45 +72,27 @@ double fraction(double v)
}
#endif
template<typename T, typename F>
struct alias_cast_t
{
union
{
F raw;
T data;
};
};
// As AngelScript doesn't allow bitwise manipulation of float types we'll provide a couple of
// functions for converting float values to IEEE 754 formatted values etc. This also allow us to
// provide a platform agnostic representation to the script so the scripts don't have to worry
// about whether the CPU uses IEEE 754 floats or some other representation
float fpFromIEEE(asUINT raw)
{
// TODO: Identify CPU family to provide proper conversion
// if the CPU doesn't natively use IEEE style floats
alias_cast_t<asUINT, float> t;
t.raw = raw;
return t.data;
// TODO: Identify CPU family to provide proper conversion
// if the CPU doesn't natively use IEEE style floats
return *reinterpret_cast<float*>(&raw);
}
asUINT fpToIEEE(float fp)
{
alias_cast_t<float, asUINT> t;
t.raw = fp;
return t.data;
return *reinterpret_cast<asUINT*>(&fp);
}
double fpFromIEEE(asQWORD raw)
{
alias_cast_t<asQWORD, double> t;
t.raw = raw;
return t.data;
return *reinterpret_cast<double*>(&raw);
}
asQWORD fpToIEEE(double fp)
{
alias_cast_t<double, asQWORD> t;
t.raw = fp;
return t.data;
return *reinterpret_cast<asQWORD*>(&fp);
}
// closeTo() is used to determine if the binary representation of two numbers are
@ -214,7 +196,6 @@ void RegisterScriptMath_Native(asIScriptEngine *engine)
r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 );
#endif
(void)r;
}
#if AS_USE_FLOAT
@ -351,7 +332,6 @@ void RegisterScriptMath_Generic(asIScriptEngine *engine)
r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 );
#endif
(void)r;
}
void RegisterScriptMath(asIScriptEngine *engine)

View File

@ -34,8 +34,9 @@ static CScriptArray *StringSplit(const string &delim, const string &str)
CScriptArray *array = CScriptArray::Create(arrayType);
// Find the existence of the delimiter in the input string
int pos = 0, prev = 0, count = 0;
while( (pos = (int)str.find(delim, prev)) != (int)string::npos )
size_t pos = 0, prev = 0;
asUINT count = 0;
while( (pos = str.find(delim, prev)) != string::npos )
{
// Add the part to the array
array->Resize(array->GetSize()+1);
@ -43,7 +44,7 @@ static CScriptArray *StringSplit(const string &delim, const string &str)
// Find the next part
count++;
prev = pos + (int)delim.length();
prev = pos + delim.length();
}
// Add the remaining part

View File

@ -226,7 +226,7 @@ void RegisterScriptWeakRef_Native(asIScriptEngine *engine)
r = engine->RegisterObjectType("weakref<class T>", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in, T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 );
@ -242,7 +242,7 @@ void RegisterScriptWeakRef_Native(asIScriptEngine *engine)
r = engine->RegisterObjectType("const_weakref<class T>", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 );
@ -332,7 +332,7 @@ void RegisterScriptWeakRef_Generic(asIScriptEngine *engine)
r = engine->RegisterObjectType("weakref<class T>", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in, T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("weakref<T>", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 );
@ -348,7 +348,7 @@ void RegisterScriptWeakRef_Generic(asIScriptEngine *engine)
r = engine->RegisterObjectType("const_weakref<class T>", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("const_weakref<T>", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 );

View File

@ -37,7 +37,6 @@
#include "as_atomic.h"
BEGIN_AS_NAMESPACE
const asUINT MAX_VALUE = 100000000;
asCAtomic::asCAtomic()
{
@ -48,7 +47,7 @@ asDWORD asCAtomic::get() const
{
// A very high ref count is highly unlikely. It most likely a problem with
// memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < MAX_VALUE);
asASSERT(value < 1000000);
return value;
}
@ -57,7 +56,7 @@ void asCAtomic::set(asDWORD val)
{
// A very high ref count is highly unlikely. It most likely a problem with
// memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < MAX_VALUE);
asASSERT(value < 1000000);
value = val;
}
@ -66,7 +65,7 @@ asDWORD asCAtomic::atomicInc()
{
// A very high ref count is highly unlikely. It most likely a problem with
// memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < MAX_VALUE);
asASSERT(value < 1000000);
return asAtomicInc((int&)value);
}
@ -75,7 +74,7 @@ asDWORD asCAtomic::atomicDec()
{
// A very high ref count is highly unlikely. It most likely a problem with
// memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < MAX_VALUE);
asASSERT(value < 1000000);
return asAtomicDec((int&)value);
}

View File

@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
Copyright (c) 2003-2020 Andreas Jonsson
Copyright (c) 2003-2021 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@ -1602,8 +1602,29 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
}
#ifndef AS_NO_COMPILER
// Check against class types
// Check against interface types
asUINT n;
for (n = 0; n < interfaceDeclarations.GetLength(); n++)
{
if (interfaceDeclarations[n]->name == name &&
interfaceDeclarations[n]->typeInfo->nameSpace == ns)
{
if (code)
{
asCString str;
if (ns->name != "")
str = ns->name + "::" + name;
else
str = name;
str.Format(TXT_NAME_CONFLICT_s_INTF, str.AddressOf());
WriteError(str, code, node);
}
return -1;
}
}
// Check against class types
for( n = 0; n < classDeclarations.GetLength(); n++ )
{
if( classDeclarations[n]->name == name &&
@ -2080,10 +2101,12 @@ int asCBuilder::RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asS
asCScriptNode *n = cl->firstChild;
// Skip potential 'final' and 'shared' tokens
// Skip potential decorator tokens
while( n->tokenType == ttIdentifier &&
(file->TokenEquals(n->tokenPos, n->tokenLength, FINAL_TOKEN) ||
file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN)) )
file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN) ||
file->TokenEquals(n->tokenPos, n->tokenLength, ABSTRACT_TOKEN) ||
file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN)) )
{
// Report error, because mixin class cannot be final or shared
asCString msg;
@ -2921,7 +2944,8 @@ void asCBuilder::CompileInterfaces()
// If any of the derived interfaces are found after this interface, then move this to the end of the list
for( asUINT m = n+1; m < interfaceDeclarations.GetLength(); m++ )
{
if( intfType->Implements(interfaceDeclarations[m]->typeInfo) )
if( intfType != interfaceDeclarations[m]->typeInfo &&
intfType->Implements(interfaceDeclarations[m]->typeInfo) )
{
interfaceDeclarations.RemoveIndex(n);
interfaceDeclarations.PushLast(intfDecl);
@ -4762,7 +4786,7 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod
return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits);
}
asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns)
asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns, bool isShared)
{
// Get the parameter names from the node
asCArray<asCString> parameterNames;
@ -4785,7 +4809,9 @@ asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode
// Get the return and parameter types from the funcDef
asCString funcName = name;
int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, asSFunctionTraits());
asSFunctionTraits traits;
traits.SetTrait(asTRAIT_SHARED, isShared);
int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, traits);
if( r < 0 )
return 0;
@ -5470,7 +5496,7 @@ void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *ob
// TODO: child funcdef: A scope can include a template type, e.g. array<ns::type>
int n = scope.FindLast("::");
asCString className = n >= 0 ? scope.SubString(n+2) : scope;
asCString nsName = n >= 0 ? scope.SubString(0, n) : "";
asCString nsName = n >= 0 ? scope.SubString(0, n) : asCString("");
// If a namespace was specifically defined, then this must be used
asSNameSpace *ns = 0;
@ -5954,6 +5980,19 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
{
if( n->tokenType == ttOpenBracket )
{
if (isImplicitHandle)
{
// Make the type a handle
if (dt.MakeHandle(true, acceptHandleForScope) < 0)
{
if (reportError)
WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n);
if (isValid)
*isValid = false;
}
isImplicitHandle = false;
}
// Make sure the sub type can be instantiated
if( !dt.CanBeInstantiated() )
{

View File

@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
Copyright (c) 2003-2019 Andreas Jonsson
Copyright (c) 2003-2021 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@ -217,7 +217,7 @@ protected:
int RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent);
asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns);
asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns, bool isShared);
void CompleteFuncDef(sFuncDef *funcDef);
void CompileInterfaces();
void CompileClasses(asUINT originalNumTempl);

View File

@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
Copyright (c) 2003-2020 Andreas Jonsson
Copyright (c) 2003-2021 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@ -55,8 +55,7 @@ BEGIN_AS_NAMESPACE
int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal)
{
memset(internal, 0, sizeof(asSSystemFunctionInterface));
internal->Clear();
internal->func = ptr.ptr.f.func;
internal->auxiliary = 0;

View File

@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
Copyright (c) 2003-2020 Andreas Jonsson
Copyright (c) 2003-2021 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@ -119,13 +119,35 @@ struct asSSystemFunctionInterface
};
asCArray<SClean> cleanArgs;
asSSystemFunctionInterface() : func(0), baseOffset(0), callConv(ICC_GENERIC_FUNC), hostReturnInMemory(false), hostReturnFloat(false), hostReturnSize(0), paramSize(0), takesObjByVal(false), returnAutoHandle(false), compositeOffset(0), isCompositeIndirect(false), auxiliary(0) {}
asSSystemFunctionInterface()
{
Clear();
}
asSSystemFunctionInterface(const asSSystemFunctionInterface &in)
{
*this = in;
}
void Clear()
{
func = 0;
baseOffset = 0;
callConv = ICC_GENERIC_FUNC;
hostReturnInMemory = false;
hostReturnFloat = false;
hostReturnSize = 0;
paramSize = 0;
takesObjByVal = false;
returnAutoHandle = false;
compositeOffset = 0;
isCompositeIndirect = false;
auxiliary = 0;
paramAutoHandles.SetLength(0);
cleanArgs.SetLength(0);
}
asSSystemFunctionInterface &operator=(const asSSystemFunctionInterface &in)
{
func = in.func;
@ -136,12 +158,14 @@ struct asSSystemFunctionInterface
hostReturnSize = in.hostReturnSize;
paramSize = in.paramSize;
takesObjByVal = in.takesObjByVal;
paramAutoHandles = in.paramAutoHandles;
returnAutoHandle = in.returnAutoHandle;
compositeOffset = in.compositeOffset;
isCompositeIndirect = in.isCompositeIndirect;
auxiliary = in.auxiliary;
cleanArgs = in.cleanArgs;
paramAutoHandles = in.paramAutoHandles;
return *this;
}
};

View File

@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
Copyright (c) 2020-2020 Andreas Jonsson
Copyright (c) 2020-2021 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@ -110,7 +110,7 @@ static inline bool IsRegisterHFA(const asCDataType &type)
if( typeInfo == nullptr ||
(typeInfo->flags & asOBJ_APP_CLASS_ALLFLOATS) == 0 ||
type.IsObjectHandle() && type.IsReference() )
type.IsObjectHandle() || type.IsReference() )
return false;
const bool doubles = (typeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0;

View File

@ -1,6 +1,6 @@
//
// AngelCode Scripting Library
// Copyright (c) 2020-2020 Andreas Jonsson
// Copyright (c) 2020-2021 Andreas Jonsson
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any
@ -35,6 +35,10 @@
// Compile with GCC/GAS
#if !defined(AS_MAX_PORTABILITY)
#if defined(__aarch64__)
.arch armv8-a
.text
@ -217,3 +221,7 @@ CallARM64RetInMemory:
.cfi_def_cfa_offset 0
ret
.cfi_endproc
#endif /* __aarch64__ */
#endif /* !AS_MAX_PORTABILITY */

View File

@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
Copyright (c) 2003-2020 Andreas Jonsson
Copyright (c) 2003-2021 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@ -1513,7 +1513,8 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, as
else if( ctx->type.dataType.IsNullHandle() )
{
// Make sure the argument type can support handles (or is itself a handle)
if( !dt.SupportHandles() && !dt.IsObjectHandle() )
// Don't allow null handle to be converted to an object type of ASHANDLE here, that would require more logic to call the constructor (which should be handled in ImplicitConversion)
if( (!dt.SupportHandles() && !dt.IsObjectHandle()) || (dt.GetTypeInfo() && (dt.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) )
{
asCString str;
str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
@ -2696,7 +2697,6 @@ bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx
// For types that support handles auto should prefer handle
// as it is more efficient than making a copy
// TODO: 'auto a = ...;' and 'auto @a = ...;' works the same in this case. Is this what we want?
if( newType.SupportHandles() )
newType.MakeHandle(true);
@ -3163,7 +3163,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, co
}
else
{
// Call the default constructur, then call the assignment operator
// Call the default constructor, then call the assignment operator
asCExprContext ctx(engine);
// Call the default constructor here
@ -3812,7 +3812,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
asCExprContext ctx(engine);
DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
if( !lctx.type.dataType.IsPrimitive() )
if( !ctx.type.dataType.IsPrimitive() )
ctx.bc.Instr(asBC_PopPtr);
// Release temporary variables used by expression
@ -3904,7 +3904,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
asCExprContext ctx(engine);
DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
if( !lctx.type.dataType.IsPrimitive() )
if( !ctx.type.dataType.IsPrimitive() )
ctx.bc.Instr(asBC_PopPtr);
// Release temporary variables used by expression
@ -4855,7 +4855,7 @@ void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *
{
ctx->bc.Instr(asBC_PopPtr);
ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
ctx->type.dataType.MakeReference(true);
ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
}
return;
@ -5273,7 +5273,7 @@ int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, boo
bool isOnHeap = true;
if( t.IsPrimitive() ||
(t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
(t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap && !asReference) )
{
// Primitives and value types (unless overridden) are allocated on the stack
isOnHeap = false;
@ -6106,7 +6106,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const
// Start by implicitly converting constant values
if( ctx->type.isConstant )
{
ImplicitConversionConstant(ctx, to, node, convType);
ImplicitConversionConstant(ctx, to, generateCode ? node : 0, convType);
ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
return cost;
}
@ -6482,7 +6482,7 @@ asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataT
name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
// Register the lambda with the builder for later compilation
asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace);
asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace, outFunc->IsShared());
asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
ctx->bc.InstrPTR(asBC_FuncPtr, func);
@ -7174,12 +7174,23 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDat
asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
// If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
// construct the object through any of the available constructors
// construct the object through any of the available constructors (except those marked as explicit)
if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
{
asCArray<int> funcs;
funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
// Don't allow use of explicit constructors/factories in implicit conversions
if (convType == asIC_IMPLICIT_CONV)
{
for (asUINT n = 0; n < funcs.GetLength(); n++)
{
asCScriptFunction* desc = builder->GetFunctionDescription(funcs[n]);
if (desc->IsExplicit())
funcs.RemoveIndex(n--);
}
}
asCArray<asCExprContext *> args;
args.PushLast(ctx);
@ -8049,17 +8060,28 @@ void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCData
// Verify if it is possible
if( to.GetSizeInMemoryBytes() == 1 )
{
if( asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW() )
if( (from->type.dataType.GetSizeInMemoryBytes() == 2 && asBYTE(from->type.GetConstantW()) != from->type.GetConstantW()) ||
(from->type.dataType.GetSizeInMemoryBytes() == 4 && asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW()) ||
(from->type.dataType.GetSizeInMemoryBytes() == 8 && asBYTE(from->type.GetConstantQW()) != from->type.GetConstantQW()) )
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantW()));
else if (from->type.dataType.GetSizeInMemoryBytes() == 4)
from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
else if (from->type.dataType.GetSizeInMemoryBytes() == 8)
from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantQW()));
}
else if( to.GetSizeInMemoryBytes() == 2 )
{
if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW())
if( (from->type.dataType.GetSizeInMemoryBytes() == 4 && asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) ||
(from->type.dataType.GetSizeInMemoryBytes() == 8 && asWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) )
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
if (from->type.dataType.GetSizeInMemoryBytes() == 4)
from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
else if (from->type.dataType.GetSizeInMemoryBytes() == 8)
from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantQW()));
}
else if (to.GetSizeInMemoryBytes() == 4)
{
@ -8650,7 +8672,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
{
Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
}
}
ctype = e.type;
if( ProcessPropertyGetAccessor(&e, cexpr) < 0)
@ -8673,44 +8695,22 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
int rr = CompileAssignment(cexpr->next->next, &re);
DetermineSingleFunc(&re, cexpr->next->next);
if( lr >= 0 && rr >= 0 )
if (lr >= 0 && rr >= 0)
{
// Don't allow any operators on expressions that take address of class method
if( le.IsClassMethod() || re.IsClassMethod() )
if (le.IsClassMethod() || re.IsClassMethod())
{
Error(TXT_INVALID_OP_ON_METHOD, expr);
return -1;
}
if( ProcessPropertyGetAccessor(&le, cexpr->next) < 0 )
if (ProcessPropertyGetAccessor(&le, cexpr->next) < 0)
return -1;
if( ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0 )
if (ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0)
return -1;
bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
// Allow a 0 or null in the first case to be implicitly converted to the second type
if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() )
{
asCDataType to = re.type.dataType;
to.MakeReference(false);
to.MakeReadOnly(true);
ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
}
else if( le.type.IsNullConstant() )
{
asCDataType to = re.type.dataType;
to.MakeHandle(true);
ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
}
// Allow either case to be converted to const @ if the other is const @
if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
{
le.type.dataType.MakeHandleToConst(true);
re.type.dataType.MakeHandleToConst(true);
}
// Allow an anonymous initialization list to be converted to the type in the other condition
if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory)
{
@ -8727,7 +8727,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
}
if (le.IsAnonymousInitList() )
if (le.IsAnonymousInitList())
{
Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next);
return -1;
@ -8738,6 +8738,81 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
return -1;
}
// Try to perform an implicit cast to make the two operands of the same type
// Choose the conversion that is the least costly
if (le.type.dataType != re.type.dataType)
{
asCExprContext tmp(engine);
tmp.type = le.type;
tmp.type.dataType.MakeReference(false);
asUINT costAtoB = ImplicitConversion(&tmp, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, false);
if (!tmp.type.dataType.IsEqualExceptRef(re.type.dataType))
costAtoB = 0xFFFFFFFF;
tmp.type = re.type;
tmp.type.dataType.MakeReference(false);
asUINT costBtoA = ImplicitConversion(&tmp, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, false);
if (!tmp.type.dataType.IsEqualExceptRef(le.type.dataType))
costBtoA = 0xFFFFFFFF;
if (costAtoB < costBtoA && costAtoB != 0xFFFFFFFF)
{
Dereference(&le, true);
ImplicitConversion(&le, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, true);