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> template <typename T>
Id<T> id(T /*fn_ptr*/) { return Id<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 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 seems to accept both with or without the template keyword.
// MSVC on the other hand seems to accept both with or without the template keyword. #if defined(__GNUC__)
#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
#define TMPL template #define TMPL template
#else #else
#define TMPL #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_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_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_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 >)) #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" "template <typename T>\n"
"Id<T> id(T fn_ptr) { return Id<T>(); }\n" "Id<T> id(T fn_ptr) { return Id<T>(); }\n"
"\n" "\n"
"// On some versions of GNUC it is necessary to use the template keyword as disambiguator,\n" "// On 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 seems to accept both with or without the template keyword.\n"
"// MSVC on the other hand seems to accept both with or without the template keyword.\n" "#if defined(__GNUC__)\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"
" #define TMPL template\n" " #define TMPL template\n"
"#else\n" "#else\n"
" #define TMPL\n" " #define TMPL\n"
@ -130,7 +127,7 @@ int main()
"#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >())\n" "#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >())\n"
"\n" "\n"
"#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (*)Parameters>::TMPL f< name >))\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_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" "#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast<ReturnType (*)Parameters>::TMPL f< name >))\n"
"\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 #ifdef _MSC_VER
gmtime_s(&local, &t); gmtime_s(&local, &t);
#else #else
// TODO: gmtime is not threadsafe
local = *gmtime(&t); local = *gmtime(&t);
#endif #endif
return local; 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 // 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/38298261/why-there-is-no-inverse-function-for-gmtime-in-libc
// ref: https://stackoverflow.com/questions/8558919/mktime-and-tm-isdst // 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); time_t t = mktime(&localTm);
if (t == -1) if (t == -1)
return false; return false;
// Adjust the time_t since epoch with the difference of the local timezone to the universal timezone // 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))); 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); tp = system_clock::from_time_t(t);
return true; return true;
} }
@ -111,7 +104,20 @@ bool CDateTime::setDate(asUINT year, asUINT month, asUINT day)
local.tm_mon = month - 1; local.tm_mon = month - 1;
local.tm_mday = day; 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) 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_min = minute;
local.tm_sec = second; 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) 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 // internal
// Return pointer to array item (object handle or primitive value) // Return pointer to array item (object handle or primitive value)
void *CScriptArray::GetArrayItemPointer(int index) void *CScriptArray::GetArrayItemPointer(int index)
@ -1574,32 +1587,31 @@ void CScriptArray::Sort(asIScriptFunction *func, asUINT startAt, asUINT count)
if (cmpContext == 0) if (cmpContext == 0)
cmpContext = objType->GetEngine()->RequestContext(); cmpContext = objType->GetEngine()->RequestContext();
// Insertion sort // TODO: Security issue: If the array is accessed from the callback while the sort is going on the result may be unpredictable
asBYTE tmp[16]; // For example, the callback resizes the array in the middle of the sort
for (asUINT i = start + 1; i < end; i++) // 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 best = i;
for (asUINT j = i + 1; j < end; j++)
asUINT j = i - 1;
while (j != 0xFFFFFFFF && j >= start )
{ {
cmpContext->Prepare(func); cmpContext->Prepare(func);
cmpContext->SetArgAddress(0, GetDataPointer(tmp)); cmpContext->SetArgAddress(0, At(j));
cmpContext->SetArgAddress(1, At(j)); cmpContext->SetArgAddress(1, At(best));
int r = cmpContext->Execute(); int r = cmpContext->Execute();
if (r != asEXECUTION_FINISHED) if (r != asEXECUTION_FINISHED)
break; break;
if (*(bool*)(cmpContext->GetAddressOfReturnValue())) if (*(bool*)(cmpContext->GetAddressOfReturnValue()))
{ best = j;
Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j));
j--;
}
else
break;
} }
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) 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>", "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 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->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); 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 #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>", "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 ); 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 *GetArrayItemPointer(int index);
void *GetDataPointer(void *buffer); void *GetDataPointer(void *buffer);
void Copy(void *dst, void *src); void Copy(void *dst, void *src);
void Swap(void *a, void *b);
void Precache(); void Precache();
bool CheckMaxSize(asUINT numElements); bool CheckMaxSize(asUINT numElements);
void Resize(int delta, asUINT at); void Resize(int delta, asUINT at);

View File

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

View File

@ -1140,7 +1140,6 @@ void RegisterScriptDictionary_Native(asIScriptEngine *engine)
// Same as deleteAll // Same as deleteAll
r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
#endif #endif
(void)r;
// Cache some things the dictionary will need at runtime // Cache some things the dictionary will need at runtime
SDictionaryCache::Setup(engine); 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_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 ); 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 // Cache some things the dictionary will need at runtime
SDictionaryCache::Setup(engine); SDictionaryCache::Setup(engine);
} }

View File

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

View File

@ -222,9 +222,8 @@ void CScriptHandle::EnumReferences(asIScriptEngine *inEngine)
inEngine->GCEnumCallback(m_type); inEngine->GCEnumCallback(m_type);
} }
void CScriptHandle::ReleaseReferences(asIScriptEngine *inEngine) void CScriptHandle::ReleaseReferences(asIScriptEngine * /*inEngine*/)
{ {
(void)inEngine;
// Simply clear the content to release the references // Simply clear the content to release the references
Set(0, 0); 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", "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 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 ); 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) 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", "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 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 ); r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 );
(void)r;
} }
void RegisterScriptHandle(asIScriptEngine *engine) void RegisterScriptHandle(asIScriptEngine *engine)

View File

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

View File

@ -72,45 +72,27 @@ double fraction(double v)
} }
#endif #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 // 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 // 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 // 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 // about whether the CPU uses IEEE 754 floats or some other representation
float fpFromIEEE(asUINT raw) float fpFromIEEE(asUINT raw)
{ {
// TODO: Identify CPU family to provide proper conversion // TODO: Identify CPU family to provide proper conversion
// if the CPU doesn't natively use IEEE style floats // if the CPU doesn't natively use IEEE style floats
alias_cast_t<asUINT, float> t; return *reinterpret_cast<float*>(&raw);
t.raw = raw;
return t.data;
} }
asUINT fpToIEEE(float fp) asUINT fpToIEEE(float fp)
{ {
alias_cast_t<float, asUINT> t; return *reinterpret_cast<asUINT*>(&fp);
t.raw = fp;
return t.data;
} }
double fpFromIEEE(asQWORD raw) double fpFromIEEE(asQWORD raw)
{ {
alias_cast_t<asQWORD, double> t; return *reinterpret_cast<double*>(&raw);
t.raw = raw;
return t.data;
} }
asQWORD fpToIEEE(double fp) asQWORD fpToIEEE(double fp)
{ {
alias_cast_t<double, asQWORD> t; return *reinterpret_cast<asQWORD*>(&fp);
t.raw = fp;
return t.data;
} }
// closeTo() is used to determine if the binary representation of two numbers are // 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 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 ); r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 );
#endif #endif
(void)r;
} }
#if AS_USE_FLOAT #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 floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 );
#endif #endif
(void)r;
} }
void RegisterScriptMath(asIScriptEngine *engine) void RegisterScriptMath(asIScriptEngine *engine)

View File

@ -34,8 +34,9 @@ static CScriptArray *StringSplit(const string &delim, const string &str)
CScriptArray *array = CScriptArray::Create(arrayType); CScriptArray *array = CScriptArray::Create(arrayType);
// Find the existence of the delimiter in the input string // Find the existence of the delimiter in the input string
int pos = 0, prev = 0, count = 0; size_t pos = 0, prev = 0;
while( (pos = (int)str.find(delim, prev)) != (int)string::npos ) asUINT count = 0;
while( (pos = str.find(delim, prev)) != string::npos )
{ {
// Add the part to the array // Add the part to the array
array->Resize(array->GetSize()+1); array->Resize(array->GetSize()+1);
@ -43,7 +44,7 @@ static CScriptArray *StringSplit(const string &delim, const string &str)
// Find the next part // Find the next part
count++; count++;
prev = pos + (int)delim.length(); prev = pos + delim.length();
} }
// Add the remaining part // 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->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)", 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_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 ); 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->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)", 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_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 ); 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->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)", 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_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 ); 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->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)", 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_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 ); 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" #include "as_atomic.h"
BEGIN_AS_NAMESPACE BEGIN_AS_NAMESPACE
const asUINT MAX_VALUE = 100000000;
asCAtomic::asCAtomic() asCAtomic::asCAtomic()
{ {
@ -48,7 +47,7 @@ asDWORD asCAtomic::get() const
{ {
// A very high ref count is highly unlikely. It most likely a problem with // 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. // memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < MAX_VALUE); asASSERT(value < 1000000);
return value; 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 // 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. // memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < MAX_VALUE); asASSERT(value < 1000000);
value = val; value = val;
} }
@ -66,7 +65,7 @@ asDWORD asCAtomic::atomicInc()
{ {
// A very high ref count is highly unlikely. It most likely a problem with // 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. // memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < MAX_VALUE); asASSERT(value < 1000000);
return asAtomicInc((int&)value); 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 // 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. // memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < MAX_VALUE); asASSERT(value < 1000000);
return asAtomicDec((int&)value); return asAtomicDec((int&)value);
} }

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any 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 #ifndef AS_NO_COMPILER
// Check against class types // Check against interface types
asUINT n; 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++ ) for( n = 0; n < classDeclarations.GetLength(); n++ )
{ {
if( classDeclarations[n]->name == name && if( classDeclarations[n]->name == name &&
@ -2080,10 +2101,12 @@ int asCBuilder::RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asS
asCScriptNode *n = cl->firstChild; asCScriptNode *n = cl->firstChild;
// Skip potential 'final' and 'shared' tokens // Skip potential decorator tokens
while( n->tokenType == ttIdentifier && while( n->tokenType == ttIdentifier &&
(file->TokenEquals(n->tokenPos, n->tokenLength, FINAL_TOKEN) || (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 // Report error, because mixin class cannot be final or shared
asCString msg; 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 // 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++ ) 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.RemoveIndex(n);
interfaceDeclarations.PushLast(intfDecl); 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); 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 // Get the parameter names from the node
asCArray<asCString> parameterNames; asCArray<asCString> parameterNames;
@ -4785,7 +4809,9 @@ asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode
// Get the return and parameter types from the funcDef // Get the return and parameter types from the funcDef
asCString funcName = name; 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 ) if( r < 0 )
return 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> // TODO: child funcdef: A scope can include a template type, e.g. array<ns::type>
int n = scope.FindLast("::"); int n = scope.FindLast("::");
asCString className = n >= 0 ? scope.SubString(n+2) : scope; 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 // If a namespace was specifically defined, then this must be used
asSNameSpace *ns = 0; asSNameSpace *ns = 0;
@ -5954,6 +5980,19 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
{ {
if( n->tokenType == ttOpenBracket ) 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 // Make sure the sub type can be instantiated
if( !dt.CanBeInstantiated() ) if( !dt.CanBeInstantiated() )
{ {

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any 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 RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent); 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 CompleteFuncDef(sFuncDef *funcDef);
void CompileInterfaces(); void CompileInterfaces();
void CompileClasses(asUINT originalNumTempl); void CompileClasses(asUINT originalNumTempl);

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any 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) 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->func = ptr.ptr.f.func;
internal->auxiliary = 0; internal->auxiliary = 0;

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -119,13 +119,35 @@ struct asSSystemFunctionInterface
}; };
asCArray<SClean> cleanArgs; 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) asSSystemFunctionInterface(const asSSystemFunctionInterface &in)
{ {
*this = 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) asSSystemFunctionInterface &operator=(const asSSystemFunctionInterface &in)
{ {
func = in.func; func = in.func;
@ -136,12 +158,14 @@ struct asSSystemFunctionInterface
hostReturnSize = in.hostReturnSize; hostReturnSize = in.hostReturnSize;
paramSize = in.paramSize; paramSize = in.paramSize;
takesObjByVal = in.takesObjByVal; takesObjByVal = in.takesObjByVal;
paramAutoHandles = in.paramAutoHandles;
returnAutoHandle = in.returnAutoHandle; returnAutoHandle = in.returnAutoHandle;
compositeOffset = in.compositeOffset; compositeOffset = in.compositeOffset;
isCompositeIndirect = in.isCompositeIndirect; isCompositeIndirect = in.isCompositeIndirect;
auxiliary = in.auxiliary; auxiliary = in.auxiliary;
cleanArgs = in.cleanArgs; cleanArgs = in.cleanArgs;
paramAutoHandles = in.paramAutoHandles;
return *this; return *this;
} }
}; };

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any 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 || if( typeInfo == nullptr ||
(typeInfo->flags & asOBJ_APP_CLASS_ALLFLOATS) == 0 || (typeInfo->flags & asOBJ_APP_CLASS_ALLFLOATS) == 0 ||
type.IsObjectHandle() && type.IsReference() ) type.IsObjectHandle() || type.IsReference() )
return false; return false;
const bool doubles = (typeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0; const bool doubles = (typeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0;

View File

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

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any 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() ) else if( ctx->type.dataType.IsNullHandle() )
{ {
// Make sure the argument type can support handles (or is itself a handle) // 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; asCString str;
str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf()); 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 // For types that support handles auto should prefer handle
// as it is more efficient than making a copy // 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() ) if( newType.SupportHandles() )
newType.MakeHandle(true); newType.MakeHandle(true);
@ -3163,7 +3163,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, co
} }
else else
{ {
// Call the default constructur, then call the assignment operator // Call the default constructor, then call the assignment operator
asCExprContext ctx(engine); asCExprContext ctx(engine);
// Call the default constructor here // Call the default constructor here
@ -3812,7 +3812,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
asCExprContext ctx(engine); asCExprContext ctx(engine);
DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
if( !lctx.type.dataType.IsPrimitive() ) if( !ctx.type.dataType.IsPrimitive() )
ctx.bc.Instr(asBC_PopPtr); ctx.bc.Instr(asBC_PopPtr);
// Release temporary variables used by expression // Release temporary variables used by expression
@ -3904,7 +3904,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
asCExprContext ctx(engine); asCExprContext ctx(engine);
DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
if( !lctx.type.dataType.IsPrimitive() ) if( !ctx.type.dataType.IsPrimitive() )
ctx.bc.Instr(asBC_PopPtr); ctx.bc.Instr(asBC_PopPtr);
// Release temporary variables used by expression // Release temporary variables used by expression
@ -4855,7 +4855,7 @@ void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *
{ {
ctx->bc.Instr(asBC_PopPtr); ctx->bc.Instr(asBC_PopPtr);
ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
ctx->type.dataType.MakeReference(true); ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
} }
return; return;
@ -5273,7 +5273,7 @@ int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, boo
bool isOnHeap = true; bool isOnHeap = true;
if( t.IsPrimitive() || 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 // Primitives and value types (unless overridden) are allocated on the stack
isOnHeap = false; isOnHeap = false;
@ -6106,7 +6106,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const
// Start by implicitly converting constant values // Start by implicitly converting constant values
if( ctx->type.isConstant ) if( ctx->type.isConstant )
{ {
ImplicitConversionConstant(ctx, to, node, convType); ImplicitConversionConstant(ctx, to, generateCode ? node : 0, convType);
ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
return cost; return cost;
} }
@ -6482,7 +6482,7 @@ asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataT
name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++); name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
// Register the lambda with the builder for later compilation // 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) ); asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
ctx->bc.InstrPTR(asBC_FuncPtr, 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); 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 // 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 ) if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
{ {
asCArray<int> funcs; asCArray<int> funcs;
funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors; 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; asCArray<asCExprContext *> args;
args.PushLast(ctx); args.PushLast(ctx);
@ -8049,17 +8060,28 @@ void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCData
// Verify if it is possible // Verify if it is possible
if( to.GetSizeInMemoryBytes() == 1 ) 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); 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 ) 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); 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) else if (to.GetSizeInMemoryBytes() == 4)
{ {
@ -8650,7 +8672,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
{ {
Error(TXT_EXPR_MUST_BE_BOOL, cexpr); Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
} }
ctype = e.type; ctype = e.type;
if( ProcessPropertyGetAccessor(&e, cexpr) < 0) if( ProcessPropertyGetAccessor(&e, cexpr) < 0)
@ -8673,44 +8695,22 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
int rr = CompileAssignment(cexpr->next->next, &re); int rr = CompileAssignment(cexpr->next->next, &re);
DetermineSingleFunc(&re, cexpr->next->next); 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 // 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); Error(TXT_INVALID_OP_ON_METHOD, expr);
return -1; return -1;
} }
if( ProcessPropertyGetAccessor(&le, cexpr->next) < 0 ) if (ProcessPropertyGetAccessor(&le, cexpr->next) < 0)
return -1; return -1;
if( ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0 ) if (ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0)
return -1; return -1;
bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle; 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 // 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) 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); ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
} }
if (le.IsAnonymousInitList() ) if (le.IsAnonymousInitList())
{ {
Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next); Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next);
return -1; return -1;
@ -8738,6 +8738,81 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
return -1; 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);
}
else if (costAtoB > costBtoA && costBtoA != 0xFFFFFFFF)
{
Dereference(&re, true);
ImplicitConversion(&re, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, true);
}
// If the cost for conversion is the same in both directions we have an ambigious situation,
// which we do not resolve. In that case the script need to perform an explicit conversion
}
// Allow a 0 to be implicitly converted to the other 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( re.type.isConstant && re.type.GetConstantData() == 0 && re.type.dataType.IsIntegerType())
{
asCDataType to = le.type.dataType;
to.MakeReference(false);
to.MakeReadOnly(true);
ImplicitConversionConstant(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
}
// Allow expression to be converted to handle if the other is handle
if (!le.type.dataType.IsObjectHandle() && re.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo() )
{
asCDataType dt = le.type.dataType;
dt.MakeHandle(true);
ImplicitConversion(&le, dt, cexpr->next, asIC_IMPLICIT_CONV);
}
if (!re.type.dataType.IsObjectHandle() && le.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo())
{
asCDataType dt = re.type.dataType;
dt.MakeHandle(true);
ImplicitConversion(&re, dt, cexpr->next->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);
}
// Make sure both expressions have the same type
if (!le.type.dataType.IsEqualExceptRefAndConst(re.type.dataType))
{
Error(TXT_BOTH_MUST_BE_SAME, expr);
return -1;
}
//--------------------------------- //---------------------------------
// Output the byte code // Output the byte code
int afterLabel = nextLabel++; int afterLabel = nextLabel++;
@ -8766,10 +8841,6 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
MergeExprBytecode(ctx, &re); MergeExprBytecode(ctx, &re);
ctx->bc.Label((short)afterLabel); ctx->bc.Label((short)afterLabel);
// Make sure both expressions have the same type
if( le.type.dataType != re.type.dataType )
Error(TXT_BOTH_MUST_BE_SAME, expr);
// Set the type of the result // Set the type of the result
ctx->type = le.type; ctx->type = le.type;
} }
@ -8810,7 +8881,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
// with a stack offset (i.e. it will not be allowed to use asBC_VAR) // with a stack offset (i.e. it will not be allowed to use asBC_VAR)
if( le.type.isLValue && re.type.isLValue && if( le.type.isLValue && re.type.isLValue &&
le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 && le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() == 0 &&
!le.type.isTemporary && !re.type.isTemporary && !le.type.isTemporary && !re.type.isTemporary &&
le.type.dataType == re.type.dataType ) le.type.dataType == re.type.dataType )
{ {
@ -8928,6 +8999,9 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
// Release the old temporary variable // Release the old temporary variable
ReleaseTemporaryVariable(le.type, &ctx->bc); ReleaseTemporaryVariable(le.type, &ctx->bc);
// Process any deferred arguments in the expressions as these must not survive until after the condition returns
ProcessDeferredParams(ctx);
ctx->bc.InstrINT(asBC_JMP, afterLabel); ctx->bc.InstrINT(asBC_JMP, afterLabel);
// Start of the right expression // Start of the right expression
@ -8950,11 +9024,10 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
// Release the old temporary variable // Release the old temporary variable
ReleaseTemporaryVariable(re.type, &ctx->bc); ReleaseTemporaryVariable(re.type, &ctx->bc);
ctx->bc.Label((short)afterLabel); // Process any deferred arguments in the expressions as these must not survive until after the condition returns
ProcessDeferredParams(ctx);
// Make sure both expressions have the same type ctx->bc.Label((short)afterLabel);
if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
Error(TXT_BOTH_MUST_BE_SAME, expr);
// Set the temporary variable as output // Set the temporary variable as output
ctx->type = rtemp; ctx->type = rtemp;
@ -9366,7 +9439,7 @@ asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const a
// TODO: child funcdef: A scope can include a template type, e.g. array<ns::type> // TODO: child funcdef: A scope can include a template type, e.g. array<ns::type>
int n = currScope.FindLast("::"); int n = currScope.FindLast("::");
asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope; asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope;
asCString nsName = n >= 0 ? currScope.SubString(0, n) : ""; asCString nsName = n >= 0 ? currScope.SubString(0, n) : asCString("");
// If the scope represents a type that the current class inherits // If the scope represents a type that the current class inherits
// from then that should be used instead of going through the namespaces // from then that should be used instead of going through the namespaces
@ -10988,7 +11061,8 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 ) if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
{ {
// Make sure the result is a reference, just as if to a local variable // Make sure the result is a reference, just as if to a local variable
dt.MakeReference(true); if( !dt.IsFuncdef() )
dt.MakeReference(true);
// Make sure any property accessor is already evaluated // Make sure any property accessor is already evaluated
if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 ) if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 )

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -252,26 +252,27 @@
// compiler is the same for both, when this is so these flags are used to produce the // compiler is the same for both, when this is so these flags are used to produce the
// right code. // right code.
// AS_WIN - Microsoft Windows // AS_WIN - Microsoft Windows
// AS_LINUX - Linux // AS_LINUX - Linux
// AS_MAC - Apple Macintosh // AS_MAC - Apple Macintosh
// AS_BSD - BSD based OS (FreeBSD, DragonFly, OpenBSD, etc) // AS_BSD - BSD based OS (FreeBSD, DragonFly, OpenBSD, etc)
// AS_XBOX - Microsoft XBox // AS_XBOX - Microsoft XBox
// AS_XBOX360 - Microsoft XBox 360 // AS_XBOX360 - Microsoft XBox 360
// AS_PSP - Sony Playstation Portable // AS_PSP - Sony Playstation Portable
// AS_PSVITA - Sony Playstation Vita // AS_PSVITA - Sony Playstation Vita
// AS_PS2 - Sony Playstation 2 // AS_PS2 - Sony Playstation 2
// AS_PS3 - Sony Playstation 3 // AS_PS3 - Sony Playstation 3
// AS_DC - Sega Dreamcast // AS_DC - Sega Dreamcast
// AS_GC - Nintendo GameCube // AS_GC - Nintendo GameCube
// AS_WII - Nintendo Wii // AS_WII - Nintendo Wii
// AS_WIIU - Nintendo Wii U // AS_WIIU - Nintendo Wii U
// AS_IPHONE - Apple IPhone // AS_NINTENDOSWITCH - Nintendo Switch
// AS_ANDROID - Android // AS_IPHONE - Apple IPhone
// AS_HAIKU - Haiku // AS_ANDROID - Android
// AS_ILLUMOS - Illumos like (OpenSolaris, OpenIndiana, NCP, etc) // AS_HAIKU - Haiku
// AS_MARMALADE - Marmalade cross platform SDK (a layer on top of the OS) // AS_ILLUMOS - Illumos like (OpenSolaris, OpenIndiana, NCP, etc)
// AS_SUN - Sun UNIX // AS_MARMALADE - Marmalade cross platform SDK (a layer on top of the OS)
// AS_SUN - Sun UNIX
@ -656,6 +657,37 @@
// Native calling conventions are not yet supported // Native calling conventions are not yet supported
#define AS_MAX_PORTABILITY #define AS_MAX_PORTABILITY
// Nintendo Switch
// Note, __SWITCH__ is not an official define in the Nintendo dev kit.
// You need to manually add this to the project when compiling for Switch.
#elif defined(__SWITCH__)
#define AS_NINTENDOSWITCH
#if (!defined(__LP64__))
#error write me
#else
#define AS_ARM64
#undef STDCALL
#define STDCALL
#undef GNU_STYLE_VIRTUAL_METHOD
#undef AS_NO_THISCALL_FUNCTOR_METHOD
#define HAS_128_BIT_PRIMITIVES
#define CDECL_RETURN_SIMPLE_IN_MEMORY
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
#undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5
#endif
// Marmalade is a cross platform SDK. It uses g++ to compile for iOS and Android // Marmalade is a cross platform SDK. It uses g++ to compile for iOS and Android
#elif defined(__S3E__) #elif defined(__S3E__)
#ifndef AS_MARMALADE #ifndef AS_MARMALADE
@ -757,7 +789,7 @@
#undef STDCALL #undef STDCALL
#define STDCALL #define STDCALL
#elif (defined(__arm64__)) #elif (defined(__aarch64__))
// The IPhone 5S+ uses an ARM64 processor // The IPhone 5S+ uses an ARM64 processor
// AngelScript currently doesn't support native calling // AngelScript currently doesn't support native calling
@ -779,7 +811,7 @@
#undef COMPLEX_RETURN_MASK #undef COMPLEX_RETURN_MASK
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
#elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__) && !defined(__arm64__) #elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__) && !defined(__aarch64__)
// http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html#//apple_ref/doc/uid/TP40005035-SW1 // http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html#//apple_ref/doc/uid/TP40005035-SW1
#define AS_X64_GCC #define AS_X64_GCC
#undef AS_NO_THISCALL_FUNCTOR_METHOD #undef AS_NO_THISCALL_FUNCTOR_METHOD
@ -1091,30 +1123,40 @@
#undef COMPLEX_RETURN_MASK #undef COMPLEX_RETURN_MASK
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
#if (defined(_ARM_) || defined(__arm__)) #if (defined(_ARM_) || defined(__arm__) || defined(__aarch64__) || defined(__AARCH64EL__))
// Android ARM // Android ARM
// TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S
#define AS_NO_EXCEPTIONS
#undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
// The stdcall calling convention is not used on the arm cpu // The stdcall calling convention is not used on the arm cpu
#undef STDCALL #undef STDCALL
#define STDCALL #define STDCALL
#undef GNU_STYLE_VIRTUAL_METHOD #undef GNU_STYLE_VIRTUAL_METHOD
#define AS_ARM
#undef AS_NO_THISCALL_FUNCTOR_METHOD #undef AS_NO_THISCALL_FUNCTOR_METHOD
#define AS_SOFTFP
#define AS_CALLEE_DESTROY_OBJ_BY_VAL #if (!defined(__LP64__))
// TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S
#define AS_NO_EXCEPTIONS
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
#define AS_ARM
#define AS_SOFTFP
#define AS_CALLEE_DESTROY_OBJ_BY_VAL
#elif (defined(__LP64__) || defined(__aarch64__))
#define AS_ARM64
#define HAS_128_BIT_PRIMITIVES
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5
#endif
#elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) #elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__)
// Android Intel x86 (same config as Linux x86). Tested with Intel x86 Atom System Image. // Android Intel x86 (same config as Linux x86). Tested with Intel x86 Atom System Image.

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -2882,7 +2882,8 @@ void asCContext::ExecuteNext()
m_regs.stackPointer = l_sp; m_regs.stackPointer = l_sp;
m_regs.stackFramePointer = l_fp; m_regs.stackFramePointer = l_fp;
if( !(objType->flags & asOBJ_NOCOUNT) ) // Update ref counter for object types that require it
if( !(objType->flags & (asOBJ_NOCOUNT | asOBJ_VALUE)) )
{ {
// Release previous object held by destination pointer // Release previous object held by destination pointer
if( *d != 0 && beh->release ) if( *d != 0 && beh->release )
@ -3912,21 +3913,21 @@ void asCContext::ExecuteNext()
} }
else else
{ {
if( func->funcType == asFUNC_SCRIPT ) if (func->funcType == asFUNC_SCRIPT)
{ {
m_regs.programPointer++; m_regs.programPointer++;
CallScriptFunction(func); CallScriptFunction(func);
} }
else if( func->funcType == asFUNC_DELEGATE ) else if (func->funcType == asFUNC_DELEGATE)
{ {
// Push the object pointer on the stack. There is always a reserved space for this so // Push the object pointer on the stack. There is always a reserved space for this so
// we don't don't need to worry about overflowing the allocated memory buffer // we don't don't need to worry about overflowing the allocated memory buffer
asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] ); asASSERT(m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex]);
m_regs.stackPointer -= AS_PTR_SIZE; m_regs.stackPointer -= AS_PTR_SIZE;
*(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate); *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate);
// Call the delegated method // Call the delegated method
if( func->funcForDelegate->funcType == asFUNC_SYSTEM ) if (func->funcForDelegate->funcType == asFUNC_SYSTEM)
{ {
m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this); m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this);
@ -3942,16 +3943,33 @@ void asCContext::ExecuteNext()
CallInterfaceMethod(func->funcForDelegate); CallInterfaceMethod(func->funcForDelegate);
} }
} }
else else if (func->funcType == asFUNC_SYSTEM)
{ {
asASSERT( func->funcType == asFUNC_SYSTEM );
m_regs.stackPointer += CallSystemFunction(func->id, this); m_regs.stackPointer += CallSystemFunction(func->id, this);
// Update program position after the call so the line number // Update program position after the call so the line number
// is correct in case the system function queries it // is correct in case the system function queries it
m_regs.programPointer++; m_regs.programPointer++;
} }
else if (func->funcType == asFUNC_IMPORTED)
{
m_regs.programPointer++;
int funcId = m_engine->importedFunctions[func->id & ~FUNC_IMPORTED]->boundFunctionId;
if (funcId > 0)
CallScriptFunction(m_engine->scriptFunctions[funcId]);
else
{
// Tell the exception handler to clean up the arguments to this method
m_needToCleanupArgs = true;
SetInternalException(TXT_UNBOUND_FUNCTION);
}
}
else
{
// Should not get here
asASSERT(false);
}
} }
// Extract the values from the context again // Extract the values from the context again
@ -4141,7 +4159,8 @@ void asCContext::ExecuteNext()
m_regs.stackPointer = l_sp; m_regs.stackPointer = l_sp;
m_regs.stackFramePointer = l_fp; m_regs.stackFramePointer = l_fp;
if( !(objType->flags & asOBJ_NOCOUNT) ) // Update ref counter for object types that require it
if( !(objType->flags & (asOBJ_NOCOUNT | asOBJ_VALUE)) )
{ {
// Release previous object held by destination pointer // Release previous object held by destination pointer
if( *d != 0 && beh->release ) if( *d != 0 && beh->release )

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -1470,7 +1470,8 @@ const char *asCModule::GetImportedFunctionDeclaration(asUINT index) const
if( func == 0 ) return 0; if( func == 0 ) return 0;
asCString *tempString = &asCThreadManager::GetLocalData()->string; asCString *tempString = &asCThreadManager::GetLocalData()->string;
*tempString = func->GetDeclarationStr(); // TODO: Allow the application to decide if the parameter name should be included or not (requires change in the interface)
*tempString = func->GetDeclarationStr(true, true, false);
return tempString->AddressOf(); return tempString->AddressOf();
} }
@ -1536,28 +1537,28 @@ int asCModule::UnbindAllImportedFunctions()
void asCModule::AddClassType(asCObjectType* type) void asCModule::AddClassType(asCObjectType* type)
{ {
m_classTypes.PushLast(type); m_classTypes.PushLast(type);
m_typeLookup.Insert({type->nameSpace, type->name}, type); m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
} }
// internal // internal
void asCModule::AddEnumType(asCEnumType* type) void asCModule::AddEnumType(asCEnumType* type)
{ {
m_enumTypes.PushLast(type); m_enumTypes.PushLast(type);
m_typeLookup.Insert({type->nameSpace, type->name}, type); m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
} }
// internal // internal
void asCModule::AddTypeDef(asCTypedefType* type) void asCModule::AddTypeDef(asCTypedefType* type)
{ {
m_typeDefs.PushLast(type); m_typeDefs.PushLast(type);
m_typeLookup.Insert({type->nameSpace, type->name}, type); m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
} }
// internal // internal
void asCModule::AddFuncDef(asCFuncdefType* type) void asCModule::AddFuncDef(asCFuncdefType* type)
{ {
m_funcDefs.PushLast(type); m_funcDefs.PushLast(type);
m_typeLookup.Insert({type->nameSpace, type->name}, type); m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
} }
// internal // internal
@ -1569,8 +1570,8 @@ void asCModule::ReplaceFuncDef(asCFuncdefType* type, asCFuncdefType* newType)
m_funcDefs[i] = newType; m_funcDefs[i] = newType;
// Replace it in the lookup map too // Replace it in the lookup map too
asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = nullptr; asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = 0;
if(m_typeLookup.MoveTo(&result, {type->nameSpace, type->name})) if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(type->nameSpace, type->name)))
{ {
asASSERT( result->value == type ); asASSERT( result->value == type );
result->value = newType; result->value = newType;
@ -1581,8 +1582,8 @@ void asCModule::ReplaceFuncDef(asCFuncdefType* type, asCFuncdefType* newType)
// internal // internal
asCTypeInfo *asCModule::GetType(const asCString &type, asSNameSpace *ns) const asCTypeInfo *asCModule::GetType(const asCString &type, asSNameSpace *ns) const
{ {
asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = nullptr; asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = 0;
if(m_typeLookup.MoveTo(&result, {ns, type})) if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(ns, type)))
{ {
return result->value; return result->value;
} }
@ -1592,8 +1593,8 @@ asCTypeInfo *asCModule::GetType(const asCString &type, asSNameSpace *ns) const
// internal // internal
asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) const asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) const
{ {
asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = nullptr; asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = 0;
if(m_typeLookup.MoveTo(&result, {ns, type})) if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(ns, type)))
{ {
return CastToObjectType(result->value); return CastToObjectType(result->value);
} }
@ -1759,11 +1760,11 @@ int asCModule::CompileGlobalVar(const char *sectionName, const char *code, int l
} }
// interface // interface
int asCModule::CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asIScriptFunction **outFunc) int asCModule::CompileFunction(const char* sectionName, const char* code, int lineOffset, asDWORD compileFlags, asIScriptFunction** outFunc)
{ {
// Make sure the outFunc is null if the function fails, so the // Make sure the outFunc is null if the function fails, so the
// application doesn't attempt to release a non-existent function // application doesn't attempt to release a non-existent function
if( outFunc ) if (outFunc)
*outFunc = 0; *outFunc = 0;
#ifdef AS_NO_COMPILER #ifdef AS_NO_COMPILER
@ -1774,19 +1775,19 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li
return asNOT_SUPPORTED; return asNOT_SUPPORTED;
#else #else
// Validate arguments // Validate arguments
if( code == 0 || if (code == 0 ||
(compileFlags != 0 && compileFlags != asCOMP_ADD_TO_MODULE) ) (compileFlags != 0 && compileFlags != asCOMP_ADD_TO_MODULE))
return asINVALID_ARG; return asINVALID_ARG;
// Only one thread may build at one time // Only one thread may build at one time
// TODO: It should be possible to have multiple threads perform compilations // TODO: It should be possible to have multiple threads perform compilations
int r = m_engine->RequestBuild(); int r = m_engine->RequestBuild();
if( r < 0 ) if (r < 0)
return r; return r;
// Prepare the engine // Prepare the engine
m_engine->PrepareEngine(); m_engine->PrepareEngine();
if( m_engine->configFailed ) if (m_engine->configFailed)
{ {
m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION);
m_engine->BuildCompleted(); m_engine->BuildCompleted();
@ -1796,9 +1797,19 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li
// Compile the single function // Compile the single function
asCBuilder funcBuilder(m_engine, this); asCBuilder funcBuilder(m_engine, this);
asCString str = code; asCString str = code;
asCScriptFunction *func = 0; asCScriptFunction* func = 0;
r = funcBuilder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func); r = funcBuilder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func);
if (r >= 0)
{
// Invoke the JIT compiler if it has been set
asIJITCompiler* jit = m_engine->GetJITCompiler();
if (jit)
{
func->JITCompile();
}
}
m_engine->BuildCompleted(); m_engine->BuildCompleted();
if( r >= 0 && outFunc && func ) if( r >= 0 && outFunc && func )

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -2488,7 +2488,7 @@ asCScriptNode *asCParser::ParseScript(bool inBlock)
UNREACHABLE_RETURN; UNREACHABLE_RETURN;
} }
// BNF:1: NAMESPACE ::= 'namespace' IDENTIFIER '{' SCRIPT '}' // BNF:1: NAMESPACE ::= 'namespace' IDENTIFIER {'::' IDENTIFIER} '{' SCRIPT '}'
asCScriptNode *asCParser::ParseNamespace() asCScriptNode *asCParser::ParseNamespace()
{ {
asCScriptNode *node = CreateNode(snNamespace); asCScriptNode *node = CreateNode(snNamespace);
@ -2505,11 +2505,32 @@ asCScriptNode *asCParser::ParseNamespace()
Error(InsteadFound(t1), &t1); Error(InsteadFound(t1), &t1);
} }
// TODO: namespace: Allow declaration of multiple nested namespace with namespace A::B::C { }
node->AddChildLast(ParseIdentifier()); node->AddChildLast(ParseIdentifier());
if( isSyntaxError ) return node; if( isSyntaxError ) return node;
asCScriptNode *lowestNode = node;
GetToken(&t1); GetToken(&t1);
while (t1.type == ttScope)
{
lowestNode->UpdateSourcePos(t1.pos, t1.length);
asCScriptNode *scopeNode = CreateNode(snScript);
if (scopeNode == 0)
return 0;
lowestNode->AddChildLast(scopeNode);
lowestNode = CreateNode(snNamespace);
if (lowestNode == 0)
return 0;
scopeNode->AddChildLast(lowestNode);
lowestNode->AddChildLast(ParseIdentifier());
if (isSyntaxError)
return node;
GetToken(&t1);
}
if( t1.type == ttStartStatementBlock ) if( t1.type == ttStartStatementBlock )
node->UpdateSourcePos(t1.pos, t1.length); node->UpdateSourcePos(t1.pos, t1.length);
else else
@ -2521,7 +2542,7 @@ asCScriptNode *asCParser::ParseNamespace()
sToken start = t1; sToken start = t1;
node->AddChildLast(ParseScript(true)); lowestNode->AddChildLast(ParseScript(true));
if( !isSyntaxError ) if( !isSyntaxError )
{ {

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -155,7 +155,7 @@ int asCReader::ReadInner()
noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0; noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0;
// Read enums // Read enums
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
module->m_enumTypes.Allocate(count, false); module->m_enumTypes.Allocate(count, false);
for( i = 0; i < count && !error; i++ ) for( i = 0; i < count && !error; i++ )
{ {
@ -228,7 +228,7 @@ int asCReader::ReadInner()
// classTypes[] // classTypes[]
// First restore the structure names, then the properties // First restore the structure names, then the properties
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
module->m_classTypes.Allocate(count, false); module->m_classTypes.Allocate(count, false);
for( i = 0; i < count && !error; ++i ) for( i = 0; i < count && !error; ++i )
{ {
@ -299,7 +299,7 @@ int asCReader::ReadInner()
if( error ) return asERROR; if( error ) return asERROR;
// Read func defs // Read func defs
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
module->m_funcDefs.Allocate(count, false); module->m_funcDefs.Allocate(count, false);
for( i = 0; i < count && !error; i++ ) for( i = 0; i < count && !error; i++ )
{ {
@ -401,7 +401,7 @@ int asCReader::ReadInner()
if( error ) return asERROR; if( error ) return asERROR;
// Read typedefs // Read typedefs
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
module->m_typeDefs.Allocate(count, false); module->m_typeDefs.Allocate(count, false);
for( i = 0; i < count && !error; i++ ) for( i = 0; i < count && !error; i++ )
{ {
@ -422,7 +422,7 @@ int asCReader::ReadInner()
if( error ) return asERROR; if( error ) return asERROR;
// scriptGlobals[] // scriptGlobals[]
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
if( count && engine->ep.disallowGlobalVars ) if( count && engine->ep.disallowGlobalVars )
{ {
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GLOBAL_VARS_NOT_ALLOWED); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GLOBAL_VARS_NOT_ALLOWED);
@ -435,7 +435,7 @@ int asCReader::ReadInner()
} }
// scriptFunctions[] // scriptFunctions[]
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
for( i = 0; i < count && !error; ++i ) for( i = 0; i < count && !error; ++i )
{ {
size_t len = module->m_scriptFunctions.GetLength(); size_t len = module->m_scriptFunctions.GetLength();
@ -496,7 +496,7 @@ int asCReader::ReadInner()
} }
// globalFunctions[] // globalFunctions[]
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
for( i = 0; i < count && !error; ++i ) for( i = 0; i < count && !error; ++i )
{ {
bool isNew; bool isNew;
@ -516,7 +516,7 @@ int asCReader::ReadInner()
if( error ) return asERROR; if( error ) return asERROR;
// bindInformations[] // bindInformations[]
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
module->m_bindInformations.Allocate(count, false); module->m_bindInformations.Allocate(count, false);
for( i = 0; i < count && !error; ++i ) for( i = 0; i < count && !error; ++i )
{ {
@ -554,7 +554,7 @@ int asCReader::ReadInner()
if( error ) return asERROR; if( error ) return asERROR;
// usedTypes[] // usedTypes[]
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
usedTypes.Allocate(count, false); usedTypes.Allocate(count, false);
for( i = 0; i < count && !error; ++i ) for( i = 0; i < count && !error; ++i )
{ {
@ -660,7 +660,7 @@ void asCReader::ReadUsedStringConstants()
asCString str; asCString str;
asUINT count; asUINT count;
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
if (count > 0 && engine->stringFactory == 0) if (count > 0 && engine->stringFactory == 0)
{ {
@ -681,7 +681,7 @@ void asCReader::ReadUsedFunctions()
TimeIt("asCReader::ReadUsedFunctions"); TimeIt("asCReader::ReadUsedFunctions");
asUINT count; asUINT count;
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
usedFunctions.SetLength(count); usedFunctions.SetLength(count);
if( usedFunctions.GetLength() != count ) if( usedFunctions.GetLength() != count )
{ {
@ -1026,13 +1026,7 @@ void asCReader::ReadFunctionSignature(asCScriptFunction *func, asCObjectType **p
ReadDataType(&func->returnType); ReadDataType(&func->returnType);
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 256);
if( count > 256 )
{
// Too many arguments, must be something wrong in the file
Error(TXT_INVALID_BYTECODE_d);
return;
}
func->parameterTypes.Allocate(count, false); func->parameterTypes.Allocate(count, false);
for( i = 0; i < count; ++i ) for( i = 0; i < count; ++i )
{ {
@ -1253,12 +1247,12 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
ReadByteCode(func); ReadByteCode(func);
func->scriptData->variableSpace = ReadEncodedUInt(); func->scriptData->variableSpace = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->objVariablesOnHeap = 0; func->scriptData->objVariablesOnHeap = 0;
if (bits & 8) if (bits & 8)
{ {
count = ReadEncodedUInt(); count = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->objVariablePos.Allocate(count, false); func->scriptData->objVariablePos.Allocate(count, false);
func->scriptData->objVariableTypes.Allocate(count, false); func->scriptData->objVariableTypes.Allocate(count, false);
for (i = 0; i < count; ++i) for (i = 0; i < count; ++i)
@ -1275,14 +1269,14 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
} }
} }
if (count > 0) if (count > 0)
func->scriptData->objVariablesOnHeap = ReadEncodedUInt(); func->scriptData->objVariablesOnHeap = SanityCheck(ReadEncodedUInt(), 10000);
int length = ReadEncodedUInt(); int length = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->objVariableInfo.SetLength(length); func->scriptData->objVariableInfo.SetLength(length);
for (i = 0; i < length; ++i) for (i = 0; i < length; ++i)
{ {
func->scriptData->objVariableInfo[i].programPos = ReadEncodedUInt(); func->scriptData->objVariableInfo[i].programPos = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->objVariableInfo[i].variableOffset = ReadEncodedUInt(); func->scriptData->objVariableInfo[i].variableOffset = SanityCheck(ReadEncodedInt(), 10000);
asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt(); asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt();
func->scriptData->objVariableInfo[i].option = option; func->scriptData->objVariableInfo[i].option = option;
if (option != asOBJ_INIT && if (option != asOBJ_INIT &&
@ -1301,19 +1295,19 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
if (bits & 16) if (bits & 16)
{ {
// Read info on try/catch blocks // Read info on try/catch blocks
int length = ReadEncodedUInt(); int length = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->tryCatchInfo.SetLength(length); func->scriptData->tryCatchInfo.SetLength(length);
for (i = 0; i < length; ++i) for (i = 0; i < length; ++i)
{ {
// The program position must be adjusted to be in number of instructions // The program position must be adjusted to be in number of instructions
func->scriptData->tryCatchInfo[i].tryPos = ReadEncodedUInt(); func->scriptData->tryCatchInfo[i].tryPos = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->tryCatchInfo[i].catchPos = ReadEncodedUInt(); func->scriptData->tryCatchInfo[i].catchPos = SanityCheck(ReadEncodedUInt(), 1000000);
} }
} }
if (!noDebugInfo) if (!noDebugInfo)
{ {
int length = ReadEncodedUInt(); int length = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->lineNumbers.SetLength(length); func->scriptData->lineNumbers.SetLength(length);
if (int(func->scriptData->lineNumbers.GetLength()) != length) if (int(func->scriptData->lineNumbers.GetLength()) != length)
{ {
@ -1326,7 +1320,7 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
func->scriptData->lineNumbers[i] = ReadEncodedUInt(); func->scriptData->lineNumbers[i] = ReadEncodedUInt();
// Read the array of script sections // Read the array of script sections
length = ReadEncodedUInt(); length = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->sectionIdxs.SetLength(length); func->scriptData->sectionIdxs.SetLength(length);
if (int(func->scriptData->sectionIdxs.GetLength()) != length) if (int(func->scriptData->sectionIdxs.GetLength()) != length)
{ {
@ -1351,7 +1345,7 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
// Read the variable information // Read the variable information
if (!noDebugInfo) if (!noDebugInfo)
{ {
int length = ReadEncodedUInt(); int length = SanityCheck(ReadEncodedUInt(), 1000000);
func->scriptData->variables.Allocate(length, false); func->scriptData->variables.Allocate(length, false);
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
{ {
@ -1366,7 +1360,7 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
func->scriptData->variables.PushLast(var); func->scriptData->variables.PushLast(var);
var->declaredAtProgramPos = ReadEncodedUInt(); var->declaredAtProgramPos = ReadEncodedUInt();
var->stackOffset = ReadEncodedUInt(); var->stackOffset = SanityCheck(ReadEncodedInt(),10000);
ReadString(&var->name); ReadString(&var->name);
ReadDataType(&var->type); ReadDataType(&var->type);
@ -1551,7 +1545,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern
// Read the initial attributes // Read the initial attributes
ReadString(&type->name); ReadString(&type->name);
ReadData(&type->flags, 4); ReadData(&type->flags, 4);
type->size = ReadEncodedUInt(); type->size = SanityCheck(ReadEncodedUInt(), 1000000);
asCString ns; asCString ns;
ReadString(&ns); ReadString(&ns);
type->nameSpace = engine->AddNameSpace(ns.AddressOf()); type->nameSpace = engine->AddNameSpace(ns.AddressOf());
@ -1613,7 +1607,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern
if( type->flags & asOBJ_ENUM ) if( type->flags & asOBJ_ENUM )
{ {
asCEnumType *t = CastToEnumType(type); asCEnumType *t = CastToEnumType(type);
int count = ReadEncodedUInt(); int count = SanityCheck(ReadEncodedUInt(), 1000000);
bool sharedExists = existingShared.MoveTo(0, type); bool sharedExists = existingShared.MoveTo(0, type);
if( !sharedExists ) if( !sharedExists )
{ {
@ -1695,7 +1689,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern
} }
// interfaces[] / interfaceVFTOffsets[] // interfaces[] / interfaceVFTOffsets[]
int size = ReadEncodedUInt(); int size = SanityCheck(ReadEncodedUInt(), 1000000);
if( sharedExists ) if( sharedExists )
{ {
for( int n = 0; n < size; n++ ) for( int n = 0; n < size; n++ )
@ -1725,7 +1719,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern
if (!ot->IsInterface()) if (!ot->IsInterface())
{ {
asUINT offset = ReadEncodedUInt(); asUINT offset = SanityCheck(ReadEncodedUInt(), 1000000);
ot->interfaceVFTOffsets.PushLast(offset); ot->interfaceVFTOffsets.PushLast(offset);
} }
} }
@ -1776,7 +1770,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern
ot->beh.destruct = 0; ot->beh.destruct = 0;
} }
size = ReadEncodedUInt(); size = SanityCheck(ReadEncodedUInt(), 1000000);
for( int n = 0; n < size; n++ ) for( int n = 0; n < size; n++ )
{ {
func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
@ -1880,7 +1874,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern
} }
// methods[] // methods[]
size = ReadEncodedUInt(); size = SanityCheck(ReadEncodedUInt(), 1000000);
int n; int n;
for( n = 0; n < size; n++ ) for( n = 0; n < size; n++ )
{ {
@ -1946,7 +1940,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern
} }
// virtualFunctionTable[] // virtualFunctionTable[]
size = ReadEncodedUInt(); size = SanityCheck(ReadEncodedUInt(), 1000000);
for( n = 0; n < size; n++ ) for( n = 0; n < size; n++ )
{ {
bool isNew; bool isNew;
@ -2011,7 +2005,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern
asASSERT(ot); asASSERT(ot);
// properties[] // properties[]
asUINT size = ReadEncodedUInt(); asUINT size = SanityCheck(ReadEncodedUInt(), 1000000);
for( asUINT n = 0; n < size; n++ ) for( asUINT n = 0; n < size; n++ )
ReadObjectProperty(ot); ReadObjectProperty(ot);
} }
@ -2039,10 +2033,15 @@ asUINT asCReader::ReadEncodedUInt()
return asUINT(qw & 0xFFFFFFFFu); return asUINT(qw & 0xFFFFFFFFu);
} }
int asCReader::ReadEncodedInt()
{
return int(ReadEncodedUInt());
}
asQWORD asCReader::ReadEncodedUInt64() asQWORD asCReader::ReadEncodedUInt64()
{ {
asQWORD i = 0; asQWORD i = 0;
asBYTE b; asBYTE b = 0xFF; // set to 0xFF to better catch if the stream doesn't update the value
ReadData(&b, 1); ReadData(&b, 1);
bool isNegative = ( b & 0x80 ) ? true : false; bool isNegative = ( b & 0x80 ) ? true : false;
b &= 0x7F; b &= 0x7F;
@ -2113,9 +2112,35 @@ asQWORD asCReader::ReadEncodedUInt64()
return i; return i;
} }
asUINT asCReader::SanityCheck(asUINT val, asUINT max)
{
if (val > max)
{
Error(TXT_INVALID_BYTECODE_d);
// Return 0 as default value
return 0;
}
return val;
}
int asCReader::SanityCheck(int val, asUINT max)
{
if (val > int(max) || val < -int(max))
{
Error(TXT_INVALID_BYTECODE_d);
// Return 0 as default value
return 0;
}
return val;
}
void asCReader::ReadString(asCString* str) void asCReader::ReadString(asCString* str)
{ {
asUINT len = ReadEncodedUInt(); asUINT len = SanityCheck(ReadEncodedUInt(), 1000000);
if( len & 1 ) if( len & 1 )
{ {
asUINT idx = len/2; asUINT idx = len/2;
@ -2261,7 +2286,7 @@ asCTypeInfo* asCReader::ReadTypeInfo()
return 0; return 0;
} }
asUINT numSubTypes = ReadEncodedUInt(); asUINT numSubTypes = SanityCheck(ReadEncodedUInt(), 100);
asCArray<asCDataType> subTypes; asCArray<asCDataType> subTypes;
for( asUINT n = 0; n < numSubTypes; n++ ) for( asUINT n = 0; n < numSubTypes; n++ )
{ {
@ -2422,7 +2447,7 @@ void asCReader::ReadByteCode(asCScriptFunction *func)
// Read number of instructions // Read number of instructions
asUINT total, numInstructions; asUINT total, numInstructions;
total = numInstructions = ReadEncodedUInt(); total = numInstructions = SanityCheck(ReadEncodedUInt(), 1000000);
// Reserve some space for the instructions // Reserve some space for the instructions
func->scriptData->byteCode.AllocateNoConstruct(numInstructions, false); func->scriptData->byteCode.AllocateNoConstruct(numInstructions, false);
@ -2664,7 +2689,7 @@ void asCReader::ReadUsedTypeIds()
{ {
TimeIt("asCReader::ReadUsedTypeIds"); TimeIt("asCReader::ReadUsedTypeIds");
asUINT count = ReadEncodedUInt(); asUINT count = SanityCheck(ReadEncodedUInt(), 1000000);
usedTypeIds.Allocate(count, false); usedTypeIds.Allocate(count, false);
for( asUINT n = 0; n < count; n++ ) for( asUINT n = 0; n < count; n++ )
{ {
@ -2678,7 +2703,7 @@ void asCReader::ReadUsedGlobalProps()
{ {
TimeIt("asCReader::ReadUsedGlobalProps"); TimeIt("asCReader::ReadUsedGlobalProps");
int c = ReadEncodedUInt(); int c = SanityCheck(ReadEncodedUInt(), 1000000);
usedGlobalProperties.Allocate(c, false); usedGlobalProperties.Allocate(c, false);
@ -2719,7 +2744,7 @@ void asCReader::ReadUsedObjectProps()
{ {
TimeIt("asCReader::ReadUsedObjectProps"); TimeIt("asCReader::ReadUsedObjectProps");
asUINT c = ReadEncodedUInt(); asUINT c = SanityCheck(ReadEncodedUInt(), 1000000);
usedObjectProperties.SetLength(c); usedObjectProperties.SetLength(c);
for( asUINT n = 0; n < c; n++ ) for( asUINT n = 0; n < c; n++ )

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library AngelCode Scripting Library
Copyright (c) 2003-2017 Andreas Jonsson Copyright (c) 2003-2021 Andreas Jonsson
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -76,7 +76,10 @@ protected:
void ReadByteCode(asCScriptFunction *func); void ReadByteCode(asCScriptFunction *func);
asWORD ReadEncodedUInt16(); asWORD ReadEncodedUInt16();
asUINT ReadEncodedUInt(); asUINT ReadEncodedUInt();
int ReadEncodedInt();
asQWORD ReadEncodedUInt64(); asQWORD ReadEncodedUInt64();
asUINT SanityCheck(asUINT val, asUINT max);
int SanityCheck(int val, asUINT max);
void ReadUsedTypeIds(); void ReadUsedTypeIds();
void ReadUsedFunctions(); void ReadUsedFunctions();

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -951,12 +951,16 @@ asCModule *asCScriptEngine::FindNewOwnerForSharedFunc(asCScriptFunction *in_func
if( in_func->module != in_mod) if( in_func->module != in_mod)
return in_func->module; return in_func->module;
if (in_func->objectType && in_func->objectType->module && // Check if this is a class method or class factory for a type that has already been moved to a different module
in_func->objectType->module != in_func->module) if ((in_func->objectType && in_func->objectType->module && in_func->objectType->module != in_func->module) ||
(in_func->IsFactory() && in_func->returnType.GetTypeInfo()->module && in_func->returnType.GetTypeInfo()->module != in_func->module))
{ {
// The object type for the method has already been transferred to // The object type for the method has already been transferred to
// another module, so transfer the method to the same module // another module, so transfer the method to the same module
in_func->module = in_func->objectType->module; if (in_func->objectType)
in_func->module = in_func->objectType->module;
else
in_func->module = in_func->returnType.GetTypeInfo()->module;
// Make sure the function is listed in the module // Make sure the function is listed in the module
// The compiler may not have done this earlier, since the object // The compiler may not have done this earlier, since the object
@ -1370,7 +1374,9 @@ int asCScriptEngine::GetFactoryIdByDecl(const asCObjectType *ot, const char *dec
for( asUINT n = 0; n < ot->beh.factories.GetLength(); n++ ) for( asUINT n = 0; n < ot->beh.factories.GetLength(); n++ )
{ {
asCScriptFunction *f = scriptFunctions[ot->beh.factories[n]]; asCScriptFunction *f = scriptFunctions[ot->beh.factories[n]];
if( f->IsSignatureEqual(&func) )
// We don't really care if the name of the function is correct
if( f->IsSignatureExceptNameEqual(&func) )
{ {
id = ot->beh.factories[n]; id = ot->beh.factories[n];
break; break;
@ -2156,7 +2162,9 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as
} }
// Verify the parameters // Verify the parameters
if( func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference() ) // The templates take a hidden parameter with the object type
if( (!(objectType->flags & asOBJ_TEMPLATE) && (func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference())) ||
((objectType->flags & asOBJ_TEMPLATE) && (func.parameterTypes.GetLength() != 2 || !func.parameterTypes[0].IsReference() || !func.parameterTypes[1].IsReference())) )
{ {
if( listPattern ) if( listPattern )
listPattern->Destroy(this); listPattern->Destroy(this);
@ -4960,7 +4968,8 @@ int asCScriptEngine::RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo
// Look for ref cast behaviours // Look for ref cast behaviours
asCScriptFunction *universalCastFunc = 0; asCScriptFunction *universalCastFunc = 0;
asCObjectType *from = reinterpret_cast<asCObjectType*>(fromType); asCObjectType *from = CastToObjectType(reinterpret_cast< asCTypeInfo*>(fromType));
if( from == 0 ) return asINVALID_ARG;
for( asUINT n = 0; n < from->methods.GetLength(); n++ ) for( asUINT n = 0; n < from->methods.GetLength(); n++ )
{ {
asCScriptFunction *func = scriptFunctions[from->methods[n]]; asCScriptFunction *func = scriptFunctions[from->methods[n]];
@ -5044,7 +5053,8 @@ void *asCScriptEngine::CreateScriptObject(const asITypeInfo *type)
{ {
if( type == 0 ) return 0; if( type == 0 ) return 0;
asCObjectType *objType = const_cast<asCObjectType*>(reinterpret_cast<const asCObjectType *>(type)); asCObjectType *objType = CastToObjectType(const_cast<asCTypeInfo*>(reinterpret_cast<const asCTypeInfo*>(type)));
if (objType == 0) return 0;
void *ptr = 0; void *ptr = 0;
// Check that there is a default factory for ref types // Check that there is a default factory for ref types
@ -5243,7 +5253,9 @@ void *asCScriptEngine::CreateUninitializedScriptObject(const asITypeInfo *type)
if( type == 0 || !(type->GetFlags() & asOBJ_SCRIPT_OBJECT) ) if( type == 0 || !(type->GetFlags() & asOBJ_SCRIPT_OBJECT) )
return 0; return 0;
asCObjectType *objType = const_cast<asCObjectType*>(reinterpret_cast<const asCObjectType*>(type)); asCObjectType *objType = CastToObjectType(const_cast<asCTypeInfo*>(reinterpret_cast<const asCTypeInfo*>(type)));
if (objType == 0)
return 0;
// Construct the object, but do not call the actual constructor that initializes the members // Construct the object, but do not call the actual constructor that initializes the members
// The initialization will be done by the application afterwards, e.g. through serialization. // The initialization will be done by the application afterwards, e.g. through serialization.
@ -5260,9 +5272,11 @@ void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asITypeInfo *
{ {
if( origObj == 0 || type == 0 ) return 0; if( origObj == 0 || type == 0 ) return 0;
const asCObjectType* ot = CastToObjectType(const_cast<asCTypeInfo*>(reinterpret_cast<const asCTypeInfo*>(type)));
if (ot == 0) return 0;
void *newObj = 0; void *newObj = 0;
const asCObjectType *ot = reinterpret_cast<const asCObjectType*>(type);
if ((ot->flags & asOBJ_SCRIPT_OBJECT) && ot->beh.copyfactory) if ((ot->flags & asOBJ_SCRIPT_OBJECT) && ot->beh.copyfactory)
{ {
// Call the script class' default factory with a context // Call the script class' default factory with a context
@ -5286,7 +5300,7 @@ void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asITypeInfo *
} }
#endif #endif
} }
else if( ot->beh.copyconstruct ) else if(ot->beh.copyconstruct )
{ {
// Manually allocate the memory, then call the copy constructor // Manually allocate the memory, then call the copy constructor
newObj = CallAlloc(ot); newObj = CallAlloc(ot);
@ -5351,7 +5365,8 @@ int asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asITyp
// TODO: Warn about invalid call in message stream (make it optional) // TODO: Warn about invalid call in message stream (make it optional)
if( type == 0 || dstObj == 0 || srcObj == 0 ) return asINVALID_ARG; if( type == 0 || dstObj == 0 || srcObj == 0 ) return asINVALID_ARG;
const asCObjectType *objType = reinterpret_cast<const asCObjectType*>(type); const asCObjectType *objType = CastToObjectType(const_cast<asCTypeInfo*>(reinterpret_cast<const asCTypeInfo*>(type)));
if (objType == 0) return asINVALID_ARG;
// If value assign for ref types has been disabled, then don't do anything if the type is a ref type // If value assign for ref types has been disabled, then don't do anything if the type is a ref type
if (ep.disallowValueAssignForRefType && (objType->flags & asOBJ_REF) && !(objType->flags & asOBJ_SCOPED)) if (ep.disallowValueAssignForRefType && (objType->flags & asOBJ_REF) && !(objType->flags & asOBJ_SCOPED))
@ -5389,7 +5404,7 @@ void asCScriptEngine::AddRefScriptObject(void *obj, const asITypeInfo *type)
// Make sure it is not a null pointer // Make sure it is not a null pointer
if( obj == 0 || type == 0 ) return; if( obj == 0 || type == 0 ) return;
const asCTypeInfo *ti = static_cast<const asCTypeInfo*>(type); const asCTypeInfo *ti = reinterpret_cast<const asCTypeInfo*>(type);
if (ti->flags & asOBJ_FUNCDEF) if (ti->flags & asOBJ_FUNCDEF)
{ {
CallObjectMethod(obj, functionBehaviours.beh.addref); CallObjectMethod(obj, functionBehaviours.beh.addref);
@ -5411,7 +5426,7 @@ void asCScriptEngine::ReleaseScriptObject(void *obj, const asITypeInfo *type)
// Make sure it is not a null pointer // Make sure it is not a null pointer
if( obj == 0 || type == 0 ) return; if( obj == 0 || type == 0 ) return;
const asCTypeInfo *ti = static_cast<const asCTypeInfo*>(type); const asCTypeInfo *ti = reinterpret_cast<const asCTypeInfo*>(type);
if (ti->flags & asOBJ_FUNCDEF) if (ti->flags & asOBJ_FUNCDEF)
{ {
CallObjectMethod(obj, functionBehaviours.beh.release); CallObjectMethod(obj, functionBehaviours.beh.release);

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -306,7 +306,9 @@ int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char
asCBuilder builder(engine, 0); asCBuilder builder(engine, 0);
asCScriptCode code; asCScriptCode code;
code.SetCode("", decl, 0, false); code.SetCode("", decl, 0, false);
dt = builder.CreateDataTypeFromNode(listNodes, &code, engine->defaultNamespace, false, CastToObjectType(returnType.GetTypeInfo()));
// For list factory we get the object type from the return type, for list constructor we get it from the object type directly
dt = builder.CreateDataTypeFromNode(listNodes, &code, engine->defaultNamespace, false, objectType ? objectType : CastToObjectType(returnType.GetTypeInfo()));
node->next = asNEW(asSListPatternDataTypeNode)(dt); node->next = asNEW(asSListPatternDataTypeNode)(dt);
node = node->next; node = node->next;
@ -1722,5 +1724,20 @@ bool asCScriptFunction::IsProperty() const
return traits.GetTrait(asTRAIT_PROPERTY); return traits.GetTrait(asTRAIT_PROPERTY);
} }
// internal
bool asCScriptFunction::IsFactory() const
{
if (objectType) return false;
asCObjectType* type = CastToObjectType(returnType.GetTypeInfo());
if (type == 0) return false;
if (type->name != name) return false;
if (type->nameSpace != nameSpace) return false;
return true;
}
END_AS_NAMESPACE END_AS_NAMESPACE

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -215,6 +215,7 @@ public:
void SetProtected(bool set) { traits.SetTrait(asTRAIT_PROTECTED, set); } void SetProtected(bool set) { traits.SetTrait(asTRAIT_PROTECTED, set); }
void SetPrivate(bool set) { traits.SetTrait(asTRAIT_PRIVATE, set); } void SetPrivate(bool set) { traits.SetTrait(asTRAIT_PRIVATE, set); }
void SetProperty(bool set) { traits.SetTrait(asTRAIT_PROPERTY, set); } void SetProperty(bool set) { traits.SetTrait(asTRAIT_PROPERTY, set); }
bool IsFactory() const;
asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType funcType); asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType funcType);
~asCScriptFunction(); ~asCScriptFunction();

View File

@ -336,6 +336,7 @@ asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize)
{ {
refCount.set(1); refCount.set(1);
objType = ot; objType = ot;
objType->AddRef();
isDestructCalled = false; isDestructCalled = false;
extra = 0; extra = 0;
hasRefCountReachedZero = false; hasRefCountReachedZero = false;
@ -480,6 +481,7 @@ asCScriptObject::~asCScriptObject()
} }
} }
objType->Release();
objType = 0; objType = 0;
// Something is really wrong if the refCount is not 0 by now // Something is really wrong if the refCount is not 0 by now

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library AngelCode Scripting Library
Copyright (c) 2012-2015 Andreas Jonsson Copyright (c) 2012-2021 Andreas Jonsson
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any

View File

@ -1,6 +1,6 @@
/* /*
AngelCode Scripting Library 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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -48,7 +48,7 @@
#define TXT_ATTR_s_INFORMED_MULTIPLE_TIMES "Attribute '%s' informed multiple times" #define TXT_ATTR_s_INFORMED_MULTIPLE_TIMES "Attribute '%s' informed multiple times"
#define TXT_AUTO_NOT_ALLOWED "Auto is not allowed here" #define TXT_AUTO_NOT_ALLOWED "Auto is not allowed here"
#define TXT_BOTH_MUST_BE_SAME "Both expressions must have the same type" #define TXT_BOTH_MUST_BE_SAME "Can't find unambiguous implicit conversion to make both expressions have the same type"
#define TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR "Both conditions must call constructor" #define TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR "Both conditions must call constructor"
#define TEXT_BASE_DOESNT_HAVE_DEF_CONSTR "Base class doesn't have default constructor. Make explicit call to base constructor" #define TEXT_BASE_DOESNT_HAVE_DEF_CONSTR "Base class doesn't have default constructor. Make explicit call to base constructor"
@ -189,6 +189,7 @@
#define TXT_NAME_CONFLICT_s_IS_MIXIN "Name conflict. '%s' is a mixin class." #define TXT_NAME_CONFLICT_s_IS_MIXIN "Name conflict. '%s' is a mixin class."
#define TXT_NAME_CONFLICT_s_IS_VIRTPROP "Name conflict. '%s' is a virtual property." #define TXT_NAME_CONFLICT_s_IS_VIRTPROP "Name conflict. '%s' is a virtual property."
#define TXT_NAME_CONFLICT_s_STRUCT "Name conflict. '%s' is a class." #define TXT_NAME_CONFLICT_s_STRUCT "Name conflict. '%s' is a class."
#define TXT_NAME_CONFLICT_s_INTF "Name conflict. '%s' is an interface."
#define TXT_NAME_CONFLICT_s_OBJ_PROPERTY "Name conflict. '%s' is an object property." #define TXT_NAME_CONFLICT_s_OBJ_PROPERTY "Name conflict. '%s' is an object property."
#define TXT_NAME_CONFLICT_s_METHOD "Name conflict. '%s' is a class method." #define TXT_NAME_CONFLICT_s_METHOD "Name conflict. '%s' is a class method."
#define TXT_NAME_CONFLICT_s_ALREADY_USED "Name conflict. '%s' is already used." #define TXT_NAME_CONFLICT_s_ALREADY_USED "Name conflict. '%s' is already used."