From aec7ca0ce911544e18722cf6387050acf347f852 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Mon, 20 Nov 2017 14:02:33 +0100 Subject: [PATCH] libs: update angelscript to 2.32.0 Fixes: https://github.com/supertuxkart/stk-code/issues/2528 Signed-off-by: Igor Gnatenko --- lib/angelscript/include/angelscript.h | 209 +- lib/angelscript/projects/cmake/CMakeLists.txt | 8 +- lib/angelscript/source/as_array.h | 6 +- lib/angelscript/source/as_builder.cpp | 2284 +++++++----- lib/angelscript/source/as_builder.h | 47 +- lib/angelscript/source/as_bytecode.cpp | 64 +- lib/angelscript/source/as_bytecode.h | 2 +- lib/angelscript/source/as_callfunc.cpp | 166 +- lib/angelscript/source/as_callfunc.h | 40 +- lib/angelscript/source/as_callfunc_arm.cpp | 22 +- lib/angelscript/source/as_callfunc_arm_gcc.S | 9 +- lib/angelscript/source/as_callfunc_mips.cpp | 6 +- lib/angelscript/source/as_callfunc_ppc.cpp | 4 +- lib/angelscript/source/as_callfunc_ppc_64.cpp | 11 +- lib/angelscript/source/as_callfunc_sh4.cpp | 4 +- .../source/as_callfunc_x64_gcc.cpp | 14 +- .../source/as_callfunc_x64_mingw.cpp | 4 +- .../source/as_callfunc_x64_msvc.cpp | 4 +- lib/angelscript/source/as_callfunc_x86.cpp | 184 +- lib/angelscript/source/as_callfunc_xenon.cpp | 2 +- lib/angelscript/source/as_compiler.cpp | 3251 +++++++++++------ lib/angelscript/source/as_compiler.h | 365 +- lib/angelscript/source/as_config.h | 114 +- lib/angelscript/source/as_configgroup.cpp | 76 +- lib/angelscript/source/as_configgroup.h | 9 +- lib/angelscript/source/as_context.cpp | 231 +- lib/angelscript/source/as_criticalsection.h | 42 +- lib/angelscript/source/as_datatype.cpp | 202 +- lib/angelscript/source/as_datatype.h | 28 +- lib/angelscript/source/as_debug.h | 4 +- lib/angelscript/source/as_gc.cpp | 2 +- lib/angelscript/source/as_gc.h | 4 +- lib/angelscript/source/as_generic.cpp | 70 +- lib/angelscript/source/as_generic.h | 3 +- lib/angelscript/source/as_globalproperty.cpp | 10 +- lib/angelscript/source/as_memory.cpp | 5 +- lib/angelscript/source/as_module.cpp | 430 ++- lib/angelscript/source/as_module.h | 63 +- lib/angelscript/source/as_objecttype.cpp | 330 +- lib/angelscript/source/as_objecttype.h | 107 +- lib/angelscript/source/as_parser.cpp | 681 ++-- lib/angelscript/source/as_parser.h | 23 +- lib/angelscript/source/as_property.h | 24 +- lib/angelscript/source/as_restore.cpp | 1897 ++++++---- lib/angelscript/source/as_restore.h | 50 +- lib/angelscript/source/as_scriptcode.cpp | 40 +- lib/angelscript/source/as_scriptengine.cpp | 1542 ++++---- lib/angelscript/source/as_scriptengine.h | 174 +- lib/angelscript/source/as_scriptfunction.cpp | 213 +- lib/angelscript/source/as_scriptfunction.h | 88 +- lib/angelscript/source/as_scriptnode.cpp | 8 +- lib/angelscript/source/as_scriptnode.h | 5 +- lib/angelscript/source/as_scriptobject.cpp | 131 +- lib/angelscript/source/as_scriptobject.h | 26 +- lib/angelscript/source/as_string.cpp | 24 +- lib/angelscript/source/as_string_util.cpp | 18 +- lib/angelscript/source/as_string_util.h | 4 +- lib/angelscript/source/as_texts.h | 17 +- lib/angelscript/source/as_thread.h | 4 +- lib/angelscript/source/as_tokendef.h | 44 +- lib/angelscript/source/as_tokenizer.cpp | 23 +- lib/angelscript/source/as_typeinfo.cpp | 476 ++- lib/angelscript/source/as_typeinfo.h | 230 +- src/scriptengine/script_engine.cpp | 2 +- src/scriptengine/scriptarray.cpp | 480 ++- src/scriptengine/scriptarray.hpp | 40 +- src/scriptengine/scriptstdstring.cpp | 792 ++-- src/scriptengine/scriptstdstring.hpp | 16 +- src/scriptengine/scriptstdstring_utils.cpp | 2 +- 69 files changed, 9307 insertions(+), 6203 deletions(-) diff --git a/lib/angelscript/include/angelscript.h b/lib/angelscript/include/angelscript.h index 98d33c516..d8bfab156 100644 --- a/lib/angelscript/include/angelscript.h +++ b/lib/angelscript/include/angelscript.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -58,8 +58,8 @@ BEGIN_AS_NAMESPACE // AngelScript version -#define ANGELSCRIPT_VERSION 23002 -#define ANGELSCRIPT_VERSION_STRING "2.30.2" +#define ANGELSCRIPT_VERSION 23200 +#define ANGELSCRIPT_VERSION_STRING "2.32.0" // Data types @@ -68,12 +68,13 @@ class asIScriptModule; class asIScriptContext; class asIScriptGeneric; class asIScriptObject; -class asIObjectType; +class asITypeInfo; class asIScriptFunction; class asIBinaryStream; class asIJITCompiler; class asIThreadManager; class asILockableSharedBool; +class asIStringFactory; // Enumerations and constants @@ -138,6 +139,9 @@ enum asEEngineProp asEP_DISABLE_INTEGER_DIVISION = 22, asEP_DISALLOW_EMPTY_LIST_ELEMENTS = 23, asEP_PRIVATE_PROP_AS_PROTECTED = 24, + asEP_ALLOW_UNICODE_IDENTIFIERS = 25, + asEP_HEREDOC_TRIM_MODE = 26, + asEP_MAX_NESTED_CALLS = 27, asEP_LAST_PROPERTY }; @@ -200,7 +204,7 @@ enum asEObjTypeFlags asOBJ_SCRIPT_OBJECT = (1<<21), asOBJ_SHARED = (1<<22), asOBJ_NOINHERIT = (1<<23), - asOBJ_SCRIPT_FUNCTION = (1<<24), + asOBJ_FUNCDEF = (1<<24), asOBJ_LIST_PATTERN = (1<<25), asOBJ_ENUM = (1<<26), asOBJ_TEMPLATE_SUBTYPE = (1<<27), @@ -225,14 +229,6 @@ enum asEBehaviours asBEHAVE_GET_WEAKREF_FLAG, // Object operators -#ifdef AS_DEPRECATED - // Deprecated since 2.30.0, 2014-10-24 - asBEHAVE_VALUE_CAST, - asBEHAVE_IMPLICIT_VALUE_CAST, - // Deprecated since 2.30.0, 2014-12-30 - asBEHAVE_REF_CAST, - asBEHAVE_IMPLICIT_REF_CAST, -#endif asBEHAVE_TEMPLATE_CALLBACK, // Garbage collection behaviours @@ -356,29 +352,31 @@ enum asEFuncType // asQWORD = 64 bits // asPWORD = size of pointer // +typedef signed char asINT8; +typedef signed short asINT16; typedef unsigned char asBYTE; typedef unsigned short asWORD; typedef unsigned int asUINT; -#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__S3E__) +#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__S3E__) || (defined(_MSC_VER) && defined(__clang__)) // size_t is not really correct, since it only guaranteed to be large enough to hold the segment size. // For example, on 16bit systems the size_t may be 16bits only even if pointers are 32bit. But nobody // is likely to use MSVC6 to compile for 16bit systems anymore, so this should be ok. - typedef size_t asPWORD; + typedef size_t asPWORD; #else typedef uintptr_t asPWORD; #endif #ifdef __LP64__ - typedef unsigned int asDWORD; - typedef unsigned long asQWORD; - typedef long asINT64; + typedef unsigned int asDWORD; + typedef unsigned long asQWORD; + typedef long asINT64; #else - typedef unsigned long asDWORD; - #if defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_CC) || defined(__psp2__) - typedef uint64_t asQWORD; - typedef int64_t asINT64; + typedef unsigned long asDWORD; + #if !defined(_MSC_VER) && (defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_CC) || defined(__psp2__)) + typedef uint64_t asQWORD; + typedef int64_t asINT64; #else - typedef unsigned __int64 asQWORD; - typedef __int64 asINT64; + typedef unsigned __int64 asQWORD; + typedef __int64 asINT64; #endif #endif @@ -397,20 +395,20 @@ typedef void (*asCLEANENGINEFUNC_t)(asIScriptEngine *); typedef void (*asCLEANMODULEFUNC_t)(asIScriptModule *); typedef void (*asCLEANCONTEXTFUNC_t)(asIScriptContext *); typedef void (*asCLEANFUNCTIONFUNC_t)(asIScriptFunction *); -typedef void (*asCLEANOBJECTTYPEFUNC_t)(asIObjectType *); +typedef void (*asCLEANTYPEINFOFUNC_t)(asITypeInfo *); typedef void (*asCLEANSCRIPTOBJECTFUNC_t)(asIScriptObject *); typedef asIScriptContext *(*asREQUESTCONTEXTFUNC_t)(asIScriptEngine *, void *); typedef void (*asRETURNCONTEXTFUNC_t)(asIScriptEngine *, asIScriptContext *, void *); // Check if the compiler can use C++11 features #if !defined(_MSC_VER) || _MSC_VER >= 1700 // MSVC 2012 -#if !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) // gnuc 4.7 -#if !(defined(__GNUC__) && defined(__cplusplus) && __cplusplus < 201103L) // g++ -std=c++11 -#if !defined(__SUNPRO_CC) -#define AS_CAN_USE_CPP11 1 -#endif -#endif -#endif + #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) // gnuc 4.7 or clang + #if !(defined(__GNUC__) && defined(__cplusplus) && __cplusplus < 201103L) // gnuc and clang require compiler flag -std=c++11 + #if !defined(__SUNPRO_CC) // Oracle Solaris Studio + #define AS_CAN_USE_CPP11 1 + #endif + #endif + #endif #endif // This macro does basically the same thing as offsetof defined in stddef.h, but @@ -425,7 +423,7 @@ typedef void (*asRETURNCONTEXTFUNC_t)(asIScriptEngine *, asIScriptContext *, voi // BCC v5.8 (C++Builder 2006) and earlier have a similar bug which forces us to fall back to a C-style cast. #define asFUNCTIONPR(f,p,r) asFunctionPtr((void (*)())((r (*)p)(f))) #else -#define asFUNCTIONPR(f,p,r) asFunctionPtr((void (*)())(static_cast(f))) +#define asFUNCTIONPR(f,p,r) asFunctionPtr(reinterpret_cast(static_cast(f))) #endif #ifndef AS_NO_CLASS_METHODS @@ -584,7 +582,7 @@ BEGIN_AS_NAMESPACE template asUINT asGetTypeTraits() { -#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5) +#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5) || defined(__clang__) // MSVC, XCode/Clang, and gnuc 5+ // C++11 compliant code bool hasConstructor = std::is_default_constructible::value && !std::is_trivially_default_constructible::value; @@ -665,7 +663,7 @@ public: virtual asIJITCompiler *GetJITCompiler() const = 0; // Global functions - virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0) = 0; + virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0) = 0; virtual asUINT GetGlobalFunctionCount() const = 0; virtual asIScriptFunction *GetGlobalFunctionByIndex(asUINT index) const = 0; virtual asIScriptFunction *GetGlobalFunctionByDecl(const char *declaration) const = 0; @@ -679,18 +677,16 @@ public: // Object types virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags) = 0; - virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset) = 0; - virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0) = 0; - virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0) = 0; + virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; + virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; + virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; virtual int RegisterInterface(const char *name) = 0; virtual int RegisterInterfaceMethod(const char *intf, const char *declaration) = 0; virtual asUINT GetObjectTypeCount() const = 0; - virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const = 0; - virtual asIObjectType *GetObjectTypeByName(const char *name) const = 0; - virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const = 0; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0; // String factory - virtual int RegisterStringFactory(const char *datatype, const asSFuncPtr &factoryFunc, asDWORD callConv, void *objForThiscall = 0) = 0; + virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory) = 0; virtual int GetStringFactoryReturnTypeId(asDWORD *flags = 0) const = 0; // Default array type @@ -698,22 +694,20 @@ public: virtual int GetDefaultArrayTypeId() const = 0; // Enums - virtual int RegisterEnum(const char *type) = 0; - virtual int RegisterEnumValue(const char *type, const char *name, int value) = 0; - virtual asUINT GetEnumCount() const = 0; - virtual const char *GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace = 0, const char **configGroup = 0, asDWORD *accessMask = 0) const = 0; - virtual int GetEnumValueCount(int enumTypeId) const = 0; - virtual const char *GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const = 0; + virtual int RegisterEnum(const char *type) = 0; + virtual int RegisterEnumValue(const char *type, const char *name, int value) = 0; + virtual asUINT GetEnumCount() const = 0; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0; // Funcdefs - virtual int RegisterFuncdef(const char *decl) = 0; - virtual asUINT GetFuncdefCount() const = 0; - virtual asIScriptFunction *GetFuncdefByIndex(asUINT index) const = 0; + virtual int RegisterFuncdef(const char *decl) = 0; + virtual asUINT GetFuncdefCount() const = 0; + virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const = 0; // Typedefs - virtual int RegisterTypedef(const char *type, const char *decl) = 0; - virtual asUINT GetTypedefCount() const = 0; - virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace = 0, const char **configGroup = 0, asDWORD *accessMask = 0) const = 0; + virtual int RegisterTypedef(const char *type, const char *decl) = 0; + virtual asUINT GetTypedefCount() const = 0; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) const = 0; // Configuration groups virtual int BeginConfigGroup(const char *groupName) = 0; @@ -731,29 +725,26 @@ public: // Script functions virtual asIScriptFunction *GetFunctionById(int funcId) const = 0; - virtual asIScriptFunction *GetFuncDefFromTypeId(int typeId) const = 0; // Type identification - virtual asIObjectType *GetObjectTypeById(int typeId) const = 0; virtual int GetTypeIdByDecl(const char *decl) const = 0; virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const = 0; virtual int GetSizeOfPrimitiveType(int typeId) const = 0; + virtual asITypeInfo *GetTypeInfoById(int typeId) const = 0; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0; // Script execution virtual asIScriptContext *CreateContext() = 0; - virtual void *CreateScriptObject(const asIObjectType *type) = 0; - virtual void *CreateScriptObjectCopy(void *obj, const asIObjectType *type) = 0; - virtual void *CreateUninitializedScriptObject(const asIObjectType *type) = 0; + virtual void *CreateScriptObject(const asITypeInfo *type) = 0; + virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type) = 0; + virtual void *CreateUninitializedScriptObject(const asITypeInfo *type) = 0; virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj) = 0; - virtual int AssignScriptObject(void *dstObj, void *srcObj, const asIObjectType *type) = 0; - virtual void ReleaseScriptObject(void *obj, const asIObjectType *type) = 0; - virtual void AddRefScriptObject(void *obj, const asIObjectType *type) = 0; - virtual int RefCastObject(void *obj, asIObjectType *fromType, asIObjectType *toType, void **newPtr, bool useOnlyImplicitCast = false) = 0; -#ifdef AS_DEPRECATED - // Deprecated since 2.30.0, 2014-11-04 - virtual bool IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const = 0; -#endif - virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const = 0; + virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type) = 0; + virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type) = 0; + virtual void AddRefScriptObject(void *obj, const asITypeInfo *type) = 0; + virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false) = 0; + virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const = 0; // Context pooling virtual asIScriptContext *RequestContext() = 0; @@ -766,8 +757,8 @@ public: // Garbage collection virtual int GarbageCollect(asDWORD flags = asGC_FULL_CYCLE, asUINT numIterations = 1) = 0; virtual void GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed = 0, asUINT *totalDetected = 0, asUINT *newObjects = 0, asUINT *totalNewDestroyed = 0) const = 0; - virtual int NotifyGarbageCollectorOfNewObject(void *obj, asIObjectType *type) = 0; - virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr = 0, void **obj = 0, asIObjectType **type = 0) = 0; + virtual int NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type) = 0; + virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr = 0, void **obj = 0, asITypeInfo **type = 0) = 0; virtual void GCEnumCallback(void *reference) = 0; // User data @@ -777,13 +768,24 @@ public: virtual void SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type = 0) = 0; virtual void SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type = 0) = 0; virtual void SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type = 0) = 0; - virtual void SetObjectTypeUserDataCleanupCallback(asCLEANOBJECTTYPEFUNC_t callback, asPWORD type = 0) = 0; + virtual void SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type = 0) = 0; virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type = 0) = 0; protected: virtual ~asIScriptEngine() {} }; +class asIStringFactory +{ +public: + virtual const void *GetStringConstant(const char *data, asUINT length) = 0; + virtual int ReleaseStringConstant(const void *str) = 0; + virtual int GetRawStringData(const void *str, char *data, asUINT *length) const = 0; + +protected: + virtual ~asIStringFactory() {} +}; + class asIThreadManager { protected: @@ -826,20 +828,18 @@ public: // Type identification virtual asUINT GetObjectTypeCount() const = 0; - virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const = 0; - virtual asIObjectType *GetObjectTypeByName(const char *name) const = 0; - virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const = 0; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0; virtual int GetTypeIdByDecl(const char *decl) const = 0; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0; // Enums - virtual asUINT GetEnumCount() const = 0; - virtual const char *GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace = 0) const = 0; - virtual int GetEnumValueCount(int enumTypeId) const = 0; - virtual const char *GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const = 0; + virtual asUINT GetEnumCount() const = 0; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0; // Typedefs - virtual asUINT GetTypedefCount() const = 0; - virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace = 0) const = 0; + virtual asUINT GetTypedefCount() const = 0; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) const = 0; // Dynamic binding between modules virtual asUINT GetImportedFunctionCount() const = 0; @@ -948,6 +948,7 @@ public: // Miscellaneous virtual asIScriptEngine *GetEngine() const = 0; virtual asIScriptFunction *GetFunction() const = 0; + virtual void *GetAuxiliary() const = 0; // Object virtual void *GetObject() = 0; @@ -992,7 +993,7 @@ public: // Type info virtual int GetTypeId() const = 0; - virtual asIObjectType *GetObjectType() const = 0; + virtual asITypeInfo *GetObjectType() const = 0; // Class properties virtual asUINT GetPropertyCount() const = 0; @@ -1012,7 +1013,7 @@ protected: virtual ~asIScriptObject() {} }; -class asIObjectType +class asITypeInfo { public: // Miscellaneous @@ -1028,19 +1029,19 @@ public: // Type info virtual const char *GetName() const = 0; virtual const char *GetNamespace() const = 0; - virtual asIObjectType *GetBaseType() const = 0; - virtual bool DerivesFrom(const asIObjectType *objType) const = 0; + virtual asITypeInfo *GetBaseType() const = 0; + virtual bool DerivesFrom(const asITypeInfo *objType) const = 0; virtual asDWORD GetFlags() const = 0; virtual asUINT GetSize() const = 0; virtual int GetTypeId() const = 0; virtual int GetSubTypeId(asUINT subTypeIndex = 0) const = 0; - virtual asIObjectType *GetSubType(asUINT subTypeIndex = 0) const = 0; + virtual asITypeInfo *GetSubType(asUINT subTypeIndex = 0) const = 0; virtual asUINT GetSubTypeCount() const = 0; // Interfaces virtual asUINT GetInterfaceCount() const = 0; - virtual asIObjectType *GetInterface(asUINT index) const = 0; - virtual bool Implements(const asIObjectType *objType) const = 0; + virtual asITypeInfo *GetInterface(asUINT index) const = 0; + virtual bool Implements(const asITypeInfo *objType) const = 0; // Factories virtual asUINT GetFactoryCount() const = 0; @@ -1055,19 +1056,34 @@ public: // Properties virtual asUINT GetPropertyCount() const = 0; - virtual int GetProperty(asUINT index, const char **name, int *typeId = 0, bool *isPrivate = 0, bool *isProtected = 0, int *offset = 0, bool *isReference = 0, asDWORD *accessMask = 0) const = 0; + virtual int GetProperty(asUINT index, const char **name, int *typeId = 0, bool *isPrivate = 0, bool *isProtected = 0, int *offset = 0, bool *isReference = 0, asDWORD *accessMask = 0, int *compositeOffset = 0, bool *isCompositeIndirect = 0) const = 0; virtual const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const = 0; // Behaviours virtual asUINT GetBehaviourCount() const = 0; virtual asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const = 0; + // Child types + virtual asUINT GetChildFuncdefCount() const = 0; + virtual asITypeInfo *GetChildFuncdef(asUINT index) const = 0; + virtual asITypeInfo *GetParentType() const = 0; + + // Enums + virtual asUINT GetEnumValueCount() const = 0; + virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const = 0; + + // Typedef + virtual int GetTypedefTypeId() const = 0; + + // Funcdef + virtual asIScriptFunction *GetFuncdefSignature() const = 0; + // User data virtual void *SetUserData(void *data, asPWORD type = 0) = 0; virtual void *GetUserData(asPWORD type = 0) const = 0; protected: - virtual ~asIObjectType() {} + virtual ~asITypeInfo() {} }; class asIScriptFunction @@ -1087,9 +1103,10 @@ public: virtual const char *GetScriptSectionName() const = 0; virtual const char *GetConfigGroup() const = 0; virtual asDWORD GetAccessMask() const = 0; + virtual void *GetAuxiliary() const = 0; // Function signature - virtual asIObjectType *GetObjectType() const = 0; + virtual asITypeInfo *GetObjectType() const = 0; virtual const char *GetObjectName() const = 0; virtual const char *GetName() const = 0; virtual const char *GetNamespace() const = 0; @@ -1102,10 +1119,6 @@ public: virtual bool IsShared() const = 0; virtual asUINT GetParamCount() const = 0; virtual int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const = 0; -#ifdef AS_DEPRECATED - // Deprecated since 2.29.0, 2014-04-06 - virtual int GetParamTypeId(asUINT index, asDWORD *flags = 0) const = 0; -#endif virtual int GetReturnTypeId(asDWORD *flags = 0) const = 0; // Type id for function pointers @@ -1114,7 +1127,7 @@ public: // Delegates virtual void *GetDelegateObject() const = 0; - virtual asIObjectType *GetDelegateObjectType() const = 0; + virtual asITypeInfo *GetDelegateObjectType() const = 0; virtual asIScriptFunction *GetDelegateFunction() const = 0; // Debug information @@ -1137,8 +1150,8 @@ protected: class asIBinaryStream { public: - virtual void Read(void *ptr, asUINT size) = 0; - virtual void Write(const void *ptr, asUINT size) = 0; + virtual int Read(void *ptr, asUINT size) = 0; + virtual int Write(const void *ptr, asUINT size) = 0; public: virtual ~asIBinaryStream() {} @@ -1337,7 +1350,7 @@ struct asSVMRegisters asDWORD *stackPointer; // top of stack (grows downward) asQWORD valueRegister; // temp register for primitives void *objectRegister; // temp register for objects and handles - asIObjectType *objectType; // type of object held in object register + asITypeInfo *objectType; // type of object held in object register bool doProcessSuspend; // whether or not the JIT should break out when it encounters a suspend instruction asIScriptContext *ctx; // the active context }; diff --git a/lib/angelscript/projects/cmake/CMakeLists.txt b/lib/angelscript/projects/cmake/CMakeLists.txt index 755d8378c..9ad244006 100644 --- a/lib/angelscript/projects/cmake/CMakeLists.txt +++ b/lib/angelscript/projects/cmake/CMakeLists.txt @@ -2,10 +2,6 @@ cmake_minimum_required(VERSION 2.6) set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE) cmake_policy(SET CMP0003 NEW) -if(NOT (CMAKE_MAJOR_VERSION VERSION_LESS 3)) - cmake_policy(SET CMP0048 OLD) -endif() - project(angelscript) option(BUILD_SHARED_LIBS "Build shared library" OFF) @@ -137,8 +133,10 @@ else() set(ANGELSCRIPT_LIBRARY_NAME Angelscript) # OS X frameworks should have capitalized name set(BUILD_SHARED_LIBS TRUE) endif() +set(ANGELSCRIPT_LIBRARY_NAME ${ANGELSCRIPT_LIBRARY_NAME} CACHE STRING "" FORCE) add_library(${ANGELSCRIPT_LIBRARY_NAME} ${ANGELSCRIPT_SOURCE} ${ANGELSCRIPT_HEADERS}) +# Don't override the default library output path to avoid conflicts when building for multiple target platforms #set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib) target_link_libraries(${ANGELSCRIPT_LIBRARY_NAME} ${CMAKE_THREAD_LIBS_INIT}) @@ -160,7 +158,7 @@ if(MSVC) set_target_properties(${ANGELSCRIPT_LIBRARY_NAME} PROPERTIES COMPILE_FLAGS "/MP") endif() +# Don't override the default runtime output path to avoid conflicts when building for multiple target platforms #set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../bin) -#add_subdirectory(../../../samples/game/projects/cmake/ ./game) diff --git a/lib/angelscript/source/as_array.h b/lib/angelscript/source/as_array.h index e1487e48d..647495177 100644 --- a/lib/angelscript/source/as_array.h +++ b/lib/angelscript/source/as_array.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -468,10 +468,10 @@ bool asCArray::Concatenate(const asCArray &other) } template -void asCArray::Concatenate(T* array, unsigned int count) +void asCArray::Concatenate(T* other, unsigned int count) { for( unsigned int c = 0; c < count; c++ ) - PushLast(array[c]); + PushLast(other[c]); } template diff --git a/lib/angelscript/source/as_builder.cpp b/lib/angelscript/source/as_builder.cpp index 2ff191c3a..4a852b2f1 100644 --- a/lib/angelscript/source/as_builder.cpp +++ b/lib/angelscript/source/as_builder.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -248,10 +248,10 @@ void asCBuilder::EvaluateTemplateInstances(asUINT startIdx, bool keepSilent) if( callback && !engine->CallGlobalFunctionRetBool(tmpl, &dontGarbageCollect, callback->sysFuncIntf, callback) ) { asCString sub = tmpl->templateSubTypes[0].Format(engine->nameSpaces[0]); - for( asUINT n = 1; n < tmpl->templateSubTypes.GetLength(); n++ ) + for( asUINT m = 1; m < tmpl->templateSubTypes.GetLength(); m++ ) { sub += ","; - sub += tmpl->templateSubTypes[n].Format(engine->nameSpaces[0]); + sub += tmpl->templateSubTypes[m].Format(engine->nameSpaces[0]); } asCString str; str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, tmpl->name.AddressOf(), sub.AddressOf()); @@ -279,11 +279,11 @@ int asCBuilder::Build() Reset(); // The template callbacks must only be called after the subtypes have a known structure, - // otherwise the callback may think it is not possible to create the template instance, + // otherwise the callback may think it is not possible to create the template instance, // even though it is. - // TODO: This flag shouldn't be set globally in the engine, as it would mean that another - // thread requesting a template instance in parallel to the compilation wouldn't - // evaluate the template instance. + // TODO: This flag shouldn't be set globally in the engine, as it would mean that another + // thread requesting a template instance in parallel to the compilation wouldn't + // evaluate the template instance. engine->deferValidationOfTemplateTypes = true; asUINT numTempl = (asUINT)engine->templateInstanceTypes.GetLength(); @@ -293,7 +293,7 @@ int asCBuilder::Build() CompileInterfaces(); CompileClasses(numTempl); - // Evaluate the template instances one last time, this time with error messages, as we know + // Evaluate the template instances one last time, this time with error messages, as we know // all classes have been fully built and it is known which ones will need garbage collection. EvaluateTemplateInstances(numTempl, false); engine->deferValidationOfTemplateTypes = false; @@ -376,7 +376,7 @@ int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); - // None of the functions should be added to the module if any error occurred, + // None of the functions should be added to the module if any error occurred, // or it was requested that the functions wouldn't be added to the scope if( numErrors > 0 ) { @@ -520,12 +520,12 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l node = node->firstChild; // Create the function - bool isConstructor, isDestructor, isPrivate, isProtected, isFinal, isOverride, isShared; + asSFunctionTraits funcTraits; asCScriptFunction *func = asNEW(asCScriptFunction)(engine, compileFlags & asCOMP_ADD_TO_MODULE ? module : 0, asFUNC_SCRIPT); if( func == 0 ) return asOUT_OF_MEMORY; - GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, func->defaultArgs, func->isReadOnly, isConstructor, isDestructor, isPrivate, isProtected, isFinal, isOverride, isShared, module->defaultNamespace); + GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, func->defaultArgs, funcTraits, module->defaultNamespace); func->id = engine->GetNextScriptFunctionId(); func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : ""); int row, col; @@ -544,7 +544,7 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l // Tell the engine that the function exists already so the compiler can access it if( compileFlags & asCOMP_ADD_TO_MODULE ) { - int r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->defaultNamespace); + r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->defaultNamespace); if( r < 0 ) { func->ReleaseInternal(); @@ -552,7 +552,7 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l } module->globalFunctions.Put(func); - + module->AddScriptFunction(func); } else @@ -579,8 +579,8 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l for( asUINT n = 0; n < functions.GetLength(); n++ ) { asCCompiler compiler(engine); - asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId]; - int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0); + asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId]; + r = compiler.CompileFunction(this, functions[n]->script, f->parameterNames, functions[n]->node, f, 0); if( r < 0 ) break; } @@ -588,18 +588,18 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); - // None of the functions should be added to the module if any error occurred, + // None of the functions should be added to the module if any error occurred, // or it was requested that the functions wouldn't be added to the scope if( !(compileFlags & asCOMP_ADD_TO_MODULE) || numErrors > 0 ) { for( asUINT n = 0; n < functions.GetLength(); n++ ) { - asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId]; - if( module->globalFunctions.GetIndex(func) >= 0 ) + asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId]; + if( module->globalFunctions.GetIndex(f) >= 0 ) { - module->globalFunctions.Erase(module->globalFunctions.GetIndex(func)); - module->scriptFunctions.RemoveValue(func); - func->ReleaseInternal(); + module->globalFunctions.Erase(module->globalFunctions.GetIndex(f)); + module->scriptFunctions.RemoveValue(f); + f->ReleaseInternal(); } } } @@ -638,16 +638,20 @@ void asCBuilder::ParseScripts() } } - if( numErrors == 0 ) + if (numErrors == 0) { // Find all type declarations - for( n = 0; n < scripts.GetLength(); n++ ) + for (n = 0; n < scripts.GetLength(); n++) { asCScriptNode *node = parsers[n]->GetScriptNode(); RegisterTypesFromScript(node, scripts[n], engine->nameSpaces[0]); } - // Register the complete function definitions + // Before moving forward the builder must establish the relationship between types + // so that a derived type can see the child types of the parent type. + DetermineTypeRelations(); + + // Complete function definitions (defining returntype and parameters) for( n = 0; n < funcDefs.GetLength(); n++ ) CompleteFuncDef(funcDefs[n]); @@ -667,12 +671,12 @@ void asCBuilder::ParseScripts() if( node->nodeType == snFunction ) { node->DisconnectParent(); - RegisterScriptFunctionFromNode(node, decl->script, decl->objType, true, false, 0, decl->isExistingShared); + RegisterScriptFunctionFromNode(node, decl->script, CastToObjectType(decl->typeInfo), true, false, 0, decl->isExistingShared); } else if( node->nodeType == snVirtualProperty ) { node->DisconnectParent(); - RegisterVirtualProperty(node, decl->script, decl->objType, true, false, 0, decl->isExistingShared); + RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), true, false, 0, decl->isExistingShared); } node = next; @@ -696,44 +700,45 @@ void asCBuilder::ParseScripts() if( node->nodeType == snFunction ) { node->DisconnectParent(); - RegisterScriptFunctionFromNode(node, decl->script, decl->objType, false, false, 0, decl->isExistingShared); + RegisterScriptFunctionFromNode(node, decl->script, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared); } else if( node->nodeType == snVirtualProperty ) { node->DisconnectParent(); - RegisterVirtualProperty(node, decl->script, decl->objType, false, false, 0, decl->isExistingShared); + RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared); } node = next; } // Make sure the default factory & constructor exists for classes - if( decl->objType->beh.construct == engine->scriptTypeBehaviours.beh.construct ) + asCObjectType *ot = CastToObjectType(decl->typeInfo); + if( ot->beh.construct == engine->scriptTypeBehaviours.beh.construct ) { - if( decl->objType->beh.constructors.GetLength() == 1 || engine->ep.alwaysImplDefaultConstruct ) + if( ot->beh.constructors.GetLength() == 1 || engine->ep.alwaysImplDefaultConstruct ) { - AddDefaultConstructor(decl->objType, decl->script); + AddDefaultConstructor(ot, decl->script); } else { // As the class has another constructor we shouldn't provide the default constructor - if( decl->objType->beh.construct ) + if( ot->beh.construct ) { - engine->scriptFunctions[decl->objType->beh.construct]->ReleaseInternal(); - decl->objType->beh.construct = 0; - decl->objType->beh.constructors.RemoveIndex(0); + engine->scriptFunctions[ot->beh.construct]->ReleaseInternal(); + ot->beh.construct = 0; + ot->beh.constructors.RemoveIndex(0); } - if( decl->objType->beh.factory ) + if( ot->beh.factory ) { - engine->scriptFunctions[decl->objType->beh.factory]->ReleaseInternal(); - decl->objType->beh.factory = 0; - decl->objType->beh.factories.RemoveIndex(0); + engine->scriptFunctions[ot->beh.factory]->ReleaseInternal(); + ot->beh.factory = 0; + ot->beh.factories.RemoveIndex(0); } // Only remove the opAssign method if the script hasn't provided one - if( decl->objType->beh.copy == engine->scriptTypeBehaviours.beh.copy ) + if( ot->beh.copy == engine->scriptTypeBehaviours.beh.copy ) { - engine->scriptFunctions[decl->objType->beh.copy]->ReleaseInternal(); - decl->objType->beh.copy = 0; + engine->scriptFunctions[ot->beh.copy]->ReleaseInternal(); + ot->beh.copy = 0; } } } @@ -799,7 +804,7 @@ void asCBuilder::RegisterTypesFromScript(asCScriptNode *node, asCScriptCode *scr else if( node->nodeType == snFuncDef ) { node->DisconnectParent(); - RegisterFuncDef(node, script, ns); + RegisterFuncDef(node, script, ns, 0); } else if( node->nodeType == snMixin ) { @@ -868,6 +873,10 @@ void asCBuilder::CompileFunctions() // Don't compile the function again if it was an existing shared function if( current->isExistingShared ) continue; + // Don't compile if there is no statement block + if (current->node && !(current->node->nodeType == snStatementBlock || current->node->lastChild->nodeType == snStatementBlock)) + continue; + asCCompiler compiler(engine); asCScriptFunction *func = engine->scriptFunctions[current->funcId]; @@ -875,11 +884,11 @@ void asCBuilder::CompileFunctions() sClassDeclaration *classDecl = 0; if( current->objType && current->name == current->objType->name ) { - for( asUINT n = 0; n < classDeclarations.GetLength(); n++ ) + for( asUINT c = 0; c < classDeclarations.GetLength(); c++ ) { - if( classDeclarations[n]->objType == current->objType ) + if( classDeclarations[c]->typeInfo == current->objType ) { - classDecl = classDeclarations[n]; + classDecl = classDeclarations[c]; break; } } @@ -994,7 +1003,7 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam if( dt ) { // Verify that the object type exist - if( dt->GetObjectType() == 0 ) + if( CastToObjectType(dt->GetTypeInfo()) == 0 ) return asINVALID_OBJECT; } @@ -1018,14 +1027,14 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam // If an object property is registered, then use the // object's namespace, otherwise use the specified namespace - type = CreateDataTypeFromNode(dataType, &source, dt ? dt->GetObjectType()->nameSpace : ns); + type = CreateDataTypeFromNode(dataType, &source, dt ? dt->GetTypeInfo()->nameSpace : ns); name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength); type.MakeReference(isReference); // Validate that the type really can be a registered property // We cannot use CanBeInstantiated, as it is allowed to register // properties of type that cannot otherwise be instantiated - if( type.GetFuncDef() && !type.IsObjectHandle() ) + if( type.IsFuncdef() && !type.IsObjectHandle() ) { // Function definitions must always be handles return asINVALID_DECLARATION; @@ -1034,7 +1043,7 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam // Verify property name if( dt ) { - if( CheckNameConflictMember(dt->GetObjectType(), name.AddressOf(), nameNode, &source, true) < 0 ) + if( CheckNameConflictMember(dt->GetTypeInfo(), name.AddressOf(), nameNode, &source, true) < 0 ) return asNAME_TAKEN; } else @@ -1052,10 +1061,10 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam #ifndef AS_NO_COMPILER asCObjectProperty *asCBuilder::GetObjectProperty(asCDataType &obj, const char *prop) { - asASSERT(obj.GetObjectType() != 0); + asASSERT(CastToObjectType(obj.GetTypeInfo()) != 0); // TODO: optimize: Improve linear search - asCArray &props = obj.GetObjectType()->properties; + asCArray &props = CastToObjectType(obj.GetTypeInfo())->properties; for( asUINT n = 0; n < props.GetLength(); n++ ) { if( props[n]->name == prop ) @@ -1131,7 +1140,7 @@ asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, asSNameSpace if( isPureConstant ) *isPureConstant = globDesc->isPureConstant; if( constantValue ) *constantValue = globDesc->constantValue; } - else + else #endif if( isAppProp ) { @@ -1145,10 +1154,15 @@ asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, asSNameSpace return 0; } -int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles, bool *returnAutoHandle, asSNameSpace *ns, asCScriptNode **listPattern) +int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles, bool *returnAutoHandle, asSNameSpace *ns, asCScriptNode **listPattern, asCObjectType **outParentClass) { asASSERT( objType || ns ); + if (listPattern) + *listPattern = 0; + if (outParentClass) + *outParentClass = 0; + // TODO: Can't we use GetParsedFunctionDetails to do most of what is done in this function? Reset(); @@ -1165,13 +1179,15 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec // Determine scope asCScriptNode *n = node->firstChild->next->next; - asCString scope = GetScopeFromNode(n, &source, &n); - if( scope == "::" ) - func->nameSpace = engine->nameSpaces[0]; - else - func->nameSpace = engine->FindNameSpace(scope.AddressOf()); - if( func->nameSpace == 0 ) + asCObjectType *parentClass = 0; + func->nameSpace = GetNameSpaceFromNode(n, &source, ns, &n, &parentClass); + if( func->nameSpace == 0 && parentClass == 0 ) return asINVALID_DECLARATION; + if (parentClass && func->funcType != asFUNC_FUNCDEF) + return asINVALID_DECLARATION; + + if (outParentClass) + *outParentClass = parentClass; // Find name func->name.Assign(&source.code[n->tokenPos], n->tokenLength); @@ -1180,7 +1196,7 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec bool autoHandle; // Scoped reference types are allowed to use handle when returned from application functions - func->returnType = CreateDataTypeFromNode(node->firstChild, &source, objType ? objType->nameSpace : ns, true, objType); + func->returnType = CreateDataTypeFromNode(node->firstChild, &source, objType ? objType->nameSpace : ns, true, parentClass ? parentClass : objType); func->returnType = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle); if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) ) return asINVALID_DECLARATION; @@ -1188,8 +1204,8 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec // Reference types cannot be returned by value from system functions if( isSystemFunction && - (func->returnType.GetObjectType() && - (func->returnType.GetObjectType()->flags & asOBJ_REF)) && + (func->returnType.GetTypeInfo() && + (func->returnType.GetTypeInfo()->flags & asOBJ_REF)) && !(func->returnType.IsReference() || func->returnType.IsObjectHandle()) ) return asINVALID_DECLARATION; @@ -1221,13 +1237,13 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec while( n ) { asETypeModifiers inOutFlags; - asCDataType type = CreateDataTypeFromNode(n, &source, objType ? objType->nameSpace : ns, false, objType); + asCDataType type = CreateDataTypeFromNode(n, &source, objType ? objType->nameSpace : ns, false, parentClass ? parentClass : objType); type = ModifyDataTypeFromNode(type, n->next, &source, &inOutFlags, &autoHandle); // Reference types cannot be passed by value to system functions if( isSystemFunction && - (type.GetObjectType() && - (type.GetObjectType()->flags & asOBJ_REF)) && + (type.GetTypeInfo() && + (type.GetTypeInfo()->flags & asOBJ_REF)) && !(type.IsReference() || type.IsObjectHandle()) ) return asINVALID_DECLARATION; @@ -1252,7 +1268,7 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec // Move to next parameter n = n->next->next; - if( n && n->nodeType == snIdentifier ) + if( n && n->nodeType == snIdentifier ) { func->parameterNames[index] = asCString(&source.code[n->tokenPos], n->tokenLength); n = n->next; @@ -1281,17 +1297,17 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec { if( objType == 0 ) return asINVALID_DECLARATION; - func->isReadOnly = true; + func->SetReadOnly(true); n = n->next; } else - func->isReadOnly = false; + func->SetReadOnly(false); // If the caller expects a list pattern, check for the existence, else report an error if not if( listPattern ) { - if( n == 0 || n->nodeType != snListPattern ) + if( n == 0 || n->nodeType != snListPattern ) return asINVALID_DECLARATION; else { @@ -1304,7 +1320,7 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec if( n ) return asINVALID_DECLARATION; } - + // Make sure the default args are declared correctly ValidateDefaultArgs(&source, node, func); @@ -1331,6 +1347,7 @@ int asCBuilder::ParseVariableDeclaration(const char *decl, asSNameSpace *implici // Determine the scope from declaration asCScriptNode *n = node->firstChild->next; + // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace outNamespace = GetNameSpaceFromNode(n, &source, implicitNamespace, &n); if( outNamespace == 0 ) return asINVALID_DECLARATION; @@ -1347,12 +1364,16 @@ int asCBuilder::ParseVariableDeclaration(const char *decl, asSNameSpace *implici return 0; } -int asCBuilder::CheckNameConflictMember(asCObjectType *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty) +int asCBuilder::CheckNameConflictMember(asCTypeInfo *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty) { // It's not necessary to check against object types + asCObjectType *ot = CastToObjectType(t); + if (!ot) + return 0; + // TODO: optimize: Improve linear search - asCArray &props = t->properties; + asCArray &props = ot->properties; for( asUINT n = 0; n < props.GetLength(); n++ ) { if( props[n]->name == name ) @@ -1368,10 +1389,26 @@ int asCBuilder::CheckNameConflictMember(asCObjectType *t, const char *name, asCS } } + asCArray &funcdefs = ot->childFuncDefs; + for (asUINT n = 0; n < funcdefs.GetLength(); n++) + { + if (funcdefs[n]->name == name) + { + if (code) + { + asCString str; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name); + WriteError(str, code, node); + } + + return -1; + } + } + // Property names must be checked against method names if( isProperty ) { - asCArray methods = t->methods; + asCArray methods = ot->methods; for( asUINT n = 0; n < methods.GetLength(); n++ ) { if( engine->scriptFunctions[methods[n]]->name == name ) @@ -1395,7 +1432,7 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri { // Check against registered object types // TODO: Must check against registered funcdefs too - if( engine->GetRegisteredObjectType(name, ns) != 0 ) + if( engine->GetRegisteredType(name, ns) != 0 ) { if( code ) { @@ -1428,7 +1465,7 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri for( n = 0; n < classDeclarations.GetLength(); n++ ) { if( classDeclarations[n]->name == name && - classDeclarations[n]->objType->nameSpace == ns ) + classDeclarations[n]->typeInfo->nameSpace == ns ) { if( code ) { @@ -1445,7 +1482,7 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri for( n = 0; n < namedTypeDeclarations.GetLength(); n++ ) { if( namedTypeDeclarations[n]->name == name && - namedTypeDeclarations[n]->objType->nameSpace == ns ) + namedTypeDeclarations[n]->typeInfo->nameSpace == ns ) { if( code ) { @@ -1503,25 +1540,41 @@ sMixinClass *asCBuilder::GetMixinClass(const char *name, asSNameSpace *ns) return 0; } -int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) +int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent) { - // TODO: redesign: Allow funcdefs to be explicitly declared as 'shared'. In this case - // an error should be given if any of the arguments/return type is not - // shared. + // namespace and parent are exclusively mutual + asASSERT((ns == 0 && parent) || (ns && parent == 0)); + + // Skip leading 'shared' and 'external' keywords + asCScriptNode *n = node->firstChild; + while (n->nodeType == snIdentifier) + n = n->next; // Find the name - asASSERT( node->firstChild->nodeType == snDataType ); - asCScriptNode *n = node->firstChild->next->next; + asASSERT( n->nodeType == snDataType ); + n = n->next->next; asCString name; name.Assign(&file->code[n->tokenPos], n->tokenLength); // Check for name conflict with other types - int r = CheckNameConflict(name.AddressOf(), node, file, ns); - if( asSUCCESS != r ) + if (ns) { - node->Destroy(engine); - return r; + int r = CheckNameConflict(name.AddressOf(), node, file, ns); + if (asSUCCESS != r) + { + node->Destroy(engine); + return r; + } + } + else + { + int r = CheckNameConflictMember(parent, name.AddressOf(), node, file, false); + if (asSUCCESS != r) + { + node->Destroy(engine); + return r; + } } // The function definition should be stored as a asCScriptFunction so that the application @@ -1541,7 +1594,7 @@ int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNam fd->name = name; fd->node = node; fd->script = file; - fd->idx = module->AddFuncDef(name, ns); + fd->idx = module->AddFuncDef(name, ns, parent); funcDefs.PushLast(fd); @@ -1551,20 +1604,14 @@ int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNam void asCBuilder::CompleteFuncDef(sFuncDef *funcDef) { asCArray defaultArgs; - bool isConstMethod; - bool isConstructor; - bool isDestructor; - bool isProtected; - bool isPrivate; - bool isOverride; - bool isFinal; - bool isShared; + asSFunctionTraits funcTraits; - asCScriptFunction *func = module->funcDefs[funcDef->idx]; - asASSERT( func ); + asCFuncdefType *fdt = module->funcDefs[funcDef->idx]; + asASSERT( fdt ); + asCScriptFunction *func = fdt->funcdef; - // TODO: It should be possible to declare funcdef as shared. In this case a compiler error will be given if any of the types it uses are not shared - GetParsedFunctionDetails(funcDef->node, funcDef->script, 0, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared, func->nameSpace); + asSNameSpace *implicitNs = func->nameSpace ? func->nameSpace : fdt->parentClass->nameSpace; + GetParsedFunctionDetails(funcDef->node, funcDef->script, fdt->parentClass, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, funcTraits, implicitNs); // There should not be any defaultArgs, but if there are any we need to delete them to avoid leaks for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) @@ -1572,48 +1619,73 @@ void asCBuilder::CompleteFuncDef(sFuncDef *funcDef) asDELETE(defaultArgs[n], asCString); // All funcdefs are shared, unless one of the parameter types or return type is not shared - isShared = true; - if( func->returnType.GetObjectType() && !func->returnType.GetObjectType()->IsShared() ) - isShared = false; - if( func->returnType.GetFuncDef() && !func->returnType.GetFuncDef()->IsShared() ) - isShared = false; - for( asUINT n = 0; isShared && n < func->parameterTypes.GetLength(); n++ ) + bool declaredShared = funcTraits.GetTrait(asTRAIT_SHARED); + funcTraits.SetTrait(asTRAIT_SHARED, true); + if (func->returnType.GetTypeInfo() && !func->returnType.GetTypeInfo()->IsShared()) { - if( func->parameterTypes[n].GetObjectType() && !func->parameterTypes[n].GetObjectType()->IsShared() ) - isShared = false; - if( func->parameterTypes[n].GetFuncDef() && !func->parameterTypes[n].GetFuncDef()->IsShared() ) - isShared = false; + if (declaredShared) + { + asCString s; + s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->returnType.GetTypeInfo()->name.AddressOf()); + WriteError(s.AddressOf(), funcDef->script, funcDef->node); + } + funcTraits.SetTrait(asTRAIT_SHARED, false); } - func->isShared = isShared; + for( asUINT n = 0; funcTraits.GetTrait(asTRAIT_SHARED) && n < func->parameterTypes.GetLength(); n++ ) + if (func->parameterTypes[n].GetTypeInfo() && !func->parameterTypes[n].GetTypeInfo()->IsShared()) + { + if (declaredShared) + { + asCString s; + s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); + WriteError(s.AddressOf(), funcDef->script, funcDef->node); + } + funcTraits.SetTrait(asTRAIT_SHARED, false); + } + func->SetShared(funcTraits.GetTrait(asTRAIT_SHARED)); // Check if there is another identical funcdef from another module and if so reuse that instead - if( func->isShared ) + bool found = false; + if( func->IsShared() ) { for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) { - asCScriptFunction *f2 = engine->funcDefs[n]; - if( f2 == 0 || func == f2 ) + asCFuncdefType *fdt2 = engine->funcDefs[n]; + if( fdt2 == 0 || fdt == fdt2 ) continue; - if( !f2->isShared ) + if( !fdt2->funcdef->IsShared() ) continue; - if( f2->name == func->name && - f2->nameSpace == func->nameSpace && - f2->IsSignatureExceptNameEqual(func) ) + if( fdt2->name == fdt->name && + fdt2->nameSpace == fdt->nameSpace && + fdt2->funcdef->IsSignatureExceptNameEqual(func) ) { // Replace our funcdef for the existing one - funcDef->idx = f2->id; - module->funcDefs[module->funcDefs.IndexOf(func)] = f2; - f2->AddRefInternal(); + funcDef->idx = fdt2->funcdef->id; + module->funcDefs[module->funcDefs.IndexOf(fdt)] = fdt2; + fdt2->AddRefInternal(); - engine->funcDefs.RemoveValue(func); + engine->funcDefs.RemoveValue(fdt); - func->ReleaseInternal(); + fdt->ReleaseInternal(); + found = true; break; } } } + + // If the funcdef was declared as external then the existing shared declaration must have been found + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !found) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf()); + WriteError(str, funcDef->script, funcDef->node); + } + + // Remember if the type was declared as external so the saved bytecode can be flagged accordingly + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && found) + module->externalTypes.PushLast(engine->scriptFunctions[funcDef->idx]->funcdefType); } int asCBuilder::RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) @@ -1741,6 +1813,19 @@ int asCBuilder::RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asS cl->DisconnectParent(); node->Destroy(engine); + // Check that the mixin class doesn't contain any child types + // TODO: Add support for child types in mixin classes + n = cl->firstChild; + while (n) + { + if (n->nodeType == snFuncDef) + { + WriteError(TXT_MIXIN_CANNOT_HAVE_CHILD_TYPES, file, n); + break; + } + n = n->next; + } + return 0; } @@ -1750,6 +1835,7 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS bool isFinal = false; bool isShared = false; bool isAbstract = false; + bool isExternal = false; // Check the class modifiers while( n->tokenType == ttIdentifier ) @@ -1779,6 +1865,16 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS } isShared = true; } + else if (file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN)) + { + if (isExternal) + { + asCString msg; + msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); + WriteWarning(msg, file, n); + } + isExternal = true; + } else if( file->TokenEquals(n->tokenPos, n->tokenLength, ABSTRACT_TOKEN) ) { if( isFinal ) @@ -1822,14 +1918,29 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS decl->script = file; decl->node = node; + // External shared interfaces must not try to redefine the interface + if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement)) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, n); + } + else if (!isExternal && n->next && n->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, n); + } + // If this type is shared and there already exist another shared // type of the same name, then that one should be used instead of // creating a new one. + asCObjectType *st = 0; if( isShared ) { - for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) + for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ ) { - asCObjectType *st = engine->sharedScriptTypes[n]; + st = CastToObjectType(engine->sharedScriptTypes[i]); if( st && st->IsShared() && st->name == name && @@ -1838,68 +1949,106 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS { // We'll use the existing type decl->isExistingShared = true; - decl->objType = st; + decl->typeInfo = st; module->classTypes.PushLast(st); st->AddRefInternal(); - return 0; + break; } } } - // Create a new object type for this class - asCObjectType *st = asNEW(asCObjectType)(engine); - if( st == 0 ) - return asOUT_OF_MEMORY; - - // By default all script classes are marked as garbage collected. - // Only after the complete structure and relationship between classes - // is known, can the flag be cleared for those objects that truly cannot - // form circular references. This is important because a template - // callback may be called with a script class before the compilation - // completes, and until it is known, the callback must assume the class - // is garbage collected. - st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_GC; - - if( isShared ) - st->flags |= asOBJ_SHARED; - - if( isFinal ) - st->flags |= asOBJ_NOINHERIT; - - if( isAbstract ) - st->flags |= asOBJ_ABSTRACT; - - if( node->tokenType == ttHandle ) - st->flags |= asOBJ_IMPLICIT_HANDLE; - - st->size = sizeof(asCScriptObject); - st->name = name; - st->nameSpace = ns; - st->module = module; - module->classTypes.PushLast(st); - if( isShared ) + // If the class was declared as external then it must have been compiled in a different module first + if (isExternal && decl->typeInfo == 0) { - engine->sharedScriptTypes.PushLast(st); - st->AddRefInternal(); + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, n); } - decl->objType = st; - // Use the default script class behaviours - st->beh = engine->scriptTypeBehaviours.beh; + // Remember if the class was declared as external so the saved bytecode can be flagged accordingly + if (isExternal) + module->externalTypes.PushLast(st); - // TODO: Move this to asCObjectType so that the asCRestore can reuse it - engine->scriptFunctions[st->beh.addref]->AddRefInternal(); - engine->scriptFunctions[st->beh.release]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcEnumReferences]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcGetFlag]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcGetRefCount]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcSetFlag]->AddRefInternal(); - engine->scriptFunctions[st->beh.copy]->AddRefInternal(); - engine->scriptFunctions[st->beh.factory]->AddRefInternal(); - engine->scriptFunctions[st->beh.construct]->AddRefInternal(); - // TODO: weak: Should not do this if the class has been declared with noweak - engine->scriptFunctions[st->beh.getWeakRefFlag]->AddRefInternal(); + if (!decl->isExistingShared) + { + // Create a new object type for this class + st = asNEW(asCObjectType)(engine); + if (st == 0) + return asOUT_OF_MEMORY; + + // By default all script classes are marked as garbage collected. + // Only after the complete structure and relationship between classes + // is known, can the flag be cleared for those objects that truly cannot + // form circular references. This is important because a template + // callback may be called with a script class before the compilation + // completes, and until it is known, the callback must assume the class + // is garbage collected. + st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_GC; + + if (isShared) + st->flags |= asOBJ_SHARED; + + if (isFinal) + st->flags |= asOBJ_NOINHERIT; + + if (isAbstract) + st->flags |= asOBJ_ABSTRACT; + + if (node->tokenType == ttHandle) + st->flags |= asOBJ_IMPLICIT_HANDLE; + + st->size = sizeof(asCScriptObject); + st->name = name; + st->nameSpace = ns; + st->module = module; + module->classTypes.PushLast(st); + if (isShared) + { + engine->sharedScriptTypes.PushLast(st); + st->AddRefInternal(); + } + decl->typeInfo = st; + + // Use the default script class behaviours + st->beh = engine->scriptTypeBehaviours.beh; + + // TODO: Move this to asCObjectType so that the asCRestore can reuse it + engine->scriptFunctions[st->beh.addref]->AddRefInternal(); + engine->scriptFunctions[st->beh.release]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcEnumReferences]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcGetFlag]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcGetRefCount]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcSetFlag]->AddRefInternal(); + engine->scriptFunctions[st->beh.copy]->AddRefInternal(); + engine->scriptFunctions[st->beh.factory]->AddRefInternal(); + engine->scriptFunctions[st->beh.construct]->AddRefInternal(); + // TODO: weak: Should not do this if the class has been declared with noweak + engine->scriptFunctions[st->beh.getWeakRefFlag]->AddRefInternal(); + + // Skip to the content of the class + while (n && n->nodeType == snIdentifier) + n = n->next; + } + + // Register possible child types + while (n) + { + node = n->next; + if (n->nodeType == snFuncDef) + { + n->DisconnectParent(); + if (!decl->isExistingShared) + RegisterFuncDef(n, file, 0, st); + else + { + // Destroy the node, since it won't be used + // TODO: Should verify that the funcdef is identical to the one in the existing shared class + n->Destroy(engine); + } + } + n = node; + } return 0; } @@ -1907,20 +2056,25 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) { asCScriptNode *n = node->firstChild; - asCString name(&file->code[n->tokenPos], n->tokenLength); bool isShared = false; - if( name == SHARED_TOKEN ) + bool isExternal = false; + while( n->nodeType == snIdentifier ) { - isShared = true; - + if (file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN)) + isShared = true; + else if (file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN)) + isExternal = true; + else + break; n = n->next; - name.Assign(&file->code[n->tokenPos], n->tokenLength); } int r, c; file->ConvertPosToRowCol(n->tokenPos, &r, &c); + asCString name; + name.Assign(&file->code[n->tokenPos], n->tokenLength); CheckNameConflict(name.AddressOf(), n, file, ns); sClassDeclaration *decl = asNEW(sClassDeclaration); @@ -1935,14 +2089,28 @@ int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSN decl->script = file; decl->node = node; + // External shared interfaces must not try to redefine the interface + if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement) ) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, n); + } + else if (!isExternal && n->next && n->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, n); + } + // If this type is shared and there already exist another shared // type of the same name, then that one should be used instead of // creating a new one. if( isShared ) { - for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) + for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ ) { - asCObjectType *st = engine->sharedScriptTypes[n]; + asCObjectType *st = CastToObjectType(engine->sharedScriptTypes[i]); if( st && st->IsShared() && st->name == name && @@ -1951,14 +2119,27 @@ int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSN { // We'll use the existing type decl->isExistingShared = true; - decl->objType = st; + decl->typeInfo = st; module->classTypes.PushLast(st); st->AddRefInternal(); + + // Remember if the interface was declared as external so the saved bytecode can be flagged accordingly + if (isExternal) + module->externalTypes.PushLast(st); + return 0; } } } + // If the interface was declared as external then it must have been compiled in a different module first + if (isExternal) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, n); + } + // Register the object type for the interface asCObjectType *st = asNEW(asCObjectType)(engine); if( st == 0 ) @@ -1979,7 +2160,7 @@ int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSN engine->sharedScriptTypes.PushLast(st); st->AddRefInternal(); } - decl->objType = st; + decl->typeInfo = st; // Use the default script class behaviours st->beh.construct = 0; @@ -2067,7 +2248,7 @@ void asCBuilder::CompileGlobalVariables() asCScriptFunction func(engine, module, asFUNC_SCRIPT); // Set the namespace that should be used during the compilation - func.nameSpace = gvar->datatype.GetObjectType()->nameSpace; + func.nameSpace = gvar->datatype.GetTypeInfo()->nameSpace; // Temporarily switch the type of the variable to int so it can be compiled properly asCDataType saveType; @@ -2092,8 +2273,7 @@ void asCBuilder::CompileGlobalVariables() sGlobalVariableDescription *gvar2 = *prev_it; if(gvar2->datatype == gvar->datatype ) { - // The integer value is stored in the lower bytes - enumVal = (*(int*)&gvar2->constantValue) + 1; + enumVal = int(gvar2->constantValue) + 1; if( !gvar2->isCompiled ) { @@ -2112,8 +2292,7 @@ void asCBuilder::CompileGlobalVariables() } } - // The integer value is stored in the lower bytes - *(int*)&gvar->constantValue = enumVal; + gvar->constantValue = enumVal; } if( r >= 0 ) @@ -2200,8 +2379,8 @@ void asCBuilder::CompileGlobalVariables() // Convert enums to true enum values, so subsequent compilations can access it as an enum if( gvar->isEnumValue ) { - asCObjectType *objectType = gvar->datatype.GetObjectType(); - asASSERT(NULL != objectType); + asCEnumType *enumType = CastToEnumType(gvar->datatype.GetTypeInfo()); + asASSERT(NULL != enumType); asSEnumValue *e = asNEW(asSEnumValue); if( e == 0 ) @@ -2212,9 +2391,9 @@ void asCBuilder::CompileGlobalVariables() } e->name = gvar->name; - e->value = *(int*)&gvar->constantValue; + e->value = int(gvar->constantValue); - objectType->enumValues.PushLast(e); + enumType->enumValues.PushLast(e); } } else @@ -2303,9 +2482,11 @@ void asCBuilder::CompileGlobalVariables() int asCBuilder::GetNamespaceAndNameFromNode(asCScriptNode *n, asCScriptCode *script, asSNameSpace *implicitNs, asSNameSpace *&outNs, asCString &outName) { + // TODO: child funcdef: The node might be a snScope now asASSERT( n->nodeType == snIdentifier ); // Get the optional scope from the node + // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace asSNameSpace *ns = GetNameSpaceFromNode(n->firstChild, script, implicitNs, 0); if( ns == 0 ) return -1; @@ -2345,7 +2526,7 @@ void asCBuilder::AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScript if( objType && objType->IsInterface() ) { // Only add the interface if the class doesn't already implement it - if( !decl->objType->Implements(objType) ) + if( !decl->typeInfo->Implements(objType) ) AddInterfaceToClass(decl, errNode, objType); } else @@ -2371,7 +2552,7 @@ void asCBuilder::AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScript void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *errNode, asCObjectType *intfType) { // A shared type may only implement from shared interfaces - if( decl->objType->IsShared() && !intfType->IsShared() ) + if( decl->typeInfo->IsShared() && !intfType->IsShared() ) { asCString msg; msg.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, intfType->name.AddressOf()); @@ -2383,10 +2564,10 @@ void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *err { // If the class is an existing shared class, then just check if the // interface exists in the original declaration too - if( !decl->objType->Implements(intfType) ) + if( !decl->typeInfo->Implements(intfType) ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName()); WriteError(str, decl->script, errNode); return; } @@ -2394,15 +2575,15 @@ void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *err else { // If the interface is already in the class then don't add it again - if( decl->objType->Implements(intfType) ) + if( decl->typeInfo->Implements(intfType) ) return; // Add the interface to the class - decl->objType->interfaces.PushLast(intfType); + CastToObjectType(decl->typeInfo)->interfaces.PushLast(intfType); // Add the inherited interfaces too // For interfaces this will be done outside to handle out-of-order declarations - if( !decl->objType->IsInterface() ) + if( !CastToObjectType(decl->typeInfo)->IsInterface() ) { for( asUINT n = 0; n < intfType->interfaces.GetLength(); n++ ) AddInterfaceToClass(decl, errNode, intfType->interfaces[n]); @@ -2413,107 +2594,20 @@ void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *err void asCBuilder::CompileInterfaces() { asUINT n; - for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) - { - sClassDeclaration *intfDecl = interfaceDeclarations[n]; - asCObjectType *intfType = intfDecl->objType; - - asCScriptNode *node = intfDecl->node; - asASSERT(node && node->nodeType == snInterface); - node = node->firstChild; - - // Skip the 'shared' keyword - if( intfType->IsShared() ) - node = node->next; - - // Skip the name - node = node->next; - - // Verify the inherited interfaces - while( node && node->nodeType == snIdentifier ) - { - asSNameSpace *ns; - asCString name; - if( GetNamespaceAndNameFromNode(node, intfDecl->script, intfType->nameSpace, ns, name) < 0 ) - { - node = node->next; - continue; - } - - // Find the object type for the interface - asCObjectType *objType = 0; - while( ns ) - { - objType = GetObjectType(name.AddressOf(), ns); - if( objType ) break; - - ns = engine->GetParentNameSpace(ns); - } - - // Check that the object type is an interface - bool ok = true; - if( objType && objType->IsInterface() ) - { - // Check that the implemented interface is shared if the base interface is shared - if( intfType->IsShared() && !objType->IsShared() ) - { - asCString str; - str.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, objType->GetName()); - WriteError(str, intfDecl->script, node); - ok = false; - } - } - else - { - WriteError(TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE, intfDecl->script, node); - ok = false; - } - - if( ok ) - { - // Make sure none of the implemented interfaces implement from this one - asCObjectType *base = objType; - while( base != 0 ) - { - if( base == intfType ) - { - WriteError(TXT_CANNOT_IMPLEMENT_SELF, intfDecl->script, node); - ok = false; - break; - } - - // At this point there is at most one implemented interface - if( base->interfaces.GetLength() ) - base = base->interfaces[0]; - else - break; - } - } - - if( ok ) - AddInterfaceToClass(intfDecl, node, objType); - - // Remove the nodes so they aren't parsed again - asCScriptNode *delNode = node; - node = node->next; - delNode->DisconnectParent(); - delNode->Destroy(engine); - } - } // Order the interfaces with inheritances so that the inherited // of inherited interfaces can be added properly for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) { sClassDeclaration *intfDecl = interfaceDeclarations[n]; - asCObjectType *intfType = intfDecl->objType; + asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); if( intfType->interfaces.GetLength() == 0 ) continue; // If any of the derived interfaces are found after this interface, then move this to the end of the list for( asUINT m = n+1; m < interfaceDeclarations.GetLength(); m++ ) { - if( intfType->Implements(interfaceDeclarations[m]->objType) ) + if( intfType->Implements(interfaceDeclarations[m]->typeInfo) ) { interfaceDeclarations.RemoveIndex(n); interfaceDeclarations.PushLast(intfDecl); @@ -2529,7 +2623,7 @@ void asCBuilder::CompileInterfaces() for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) { sClassDeclaration *intfDecl = interfaceDeclarations[n]; - asCObjectType *intfType = intfDecl->objType; + asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); // TODO: Is this really at the correct place? Hasn't the vfTableIdx already been set here? // Co-opt the vfTableIdx value in our own methods to indicate the @@ -2553,10 +2647,10 @@ void asCBuilder::CompileInterfaces() AddInterfaceToClass(intfDecl, intfDecl->node, base->interfaces[l]); // Add the methods from the implemented interface - for( asUINT m = 0; m < base->methods.GetLength(); m++ ) + for( asUINT l = 0; l < base->methods.GetLength(); l++ ) { // If the derived interface implements the same method, then don't add the base interface' method - asCScriptFunction *baseFunc = GetFunctionDescription(base->methods[m]); + asCScriptFunction *baseFunc = GetFunctionDescription(base->methods[l]); asCScriptFunction *derivedFunc = 0; bool found = false; for( asUINT d = 0; d < intfType->methods.GetLength(); d++ ) @@ -2580,14 +2674,101 @@ void asCBuilder::CompileInterfaces() } } -// numTempl is the number of template instances that existed in the engine before the build begun -void asCBuilder::CompileClasses(asUINT numTempl) +void asCBuilder::DetermineTypeRelations() { - asUINT n; - asCArray toValidate((int)classDeclarations.GetLength()); + // Determine inheritance between interfaces + for (asUINT n = 0; n < interfaceDeclarations.GetLength(); n++) + { + sClassDeclaration *intfDecl = interfaceDeclarations[n]; + asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); + + asCScriptNode *node = intfDecl->node; + asASSERT(node && node->nodeType == snInterface); + node = node->firstChild; + + // Skip the 'shared' & 'external' keywords + while( node->nodeType == snIdentifier && + (intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) || + intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) ) + node = node->next; + + // Skip the name + node = node->next; + + // Verify the inherited interfaces + while (node && node->nodeType == snIdentifier) + { + asSNameSpace *ns; + asCString name; + if (GetNamespaceAndNameFromNode(node, intfDecl->script, intfType->nameSpace, ns, name) < 0) + { + node = node->next; + continue; + } + + // Find the object type for the interface + asCObjectType *objType = 0; + while (ns) + { + objType = GetObjectType(name.AddressOf(), ns); + if (objType) break; + + ns = engine->GetParentNameSpace(ns); + } + + // Check that the object type is an interface + bool ok = true; + if (objType && objType->IsInterface()) + { + // Check that the implemented interface is shared if the base interface is shared + if (intfType->IsShared() && !objType->IsShared()) + { + asCString str; + str.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, objType->GetName()); + WriteError(str, intfDecl->script, node); + ok = false; + } + } + else + { + WriteError(TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE, intfDecl->script, node); + ok = false; + } + + if (ok) + { + // Make sure none of the implemented interfaces implement from this one + asCObjectType *base = objType; + while (base != 0) + { + if (base == intfType) + { + WriteError(TXT_CANNOT_IMPLEMENT_SELF, intfDecl->script, node); + ok = false; + break; + } + + // At this point there is at most one implemented interface + if (base->interfaces.GetLength()) + base = base->interfaces[0]; + else + break; + } + } + + if (ok) + AddInterfaceToClass(intfDecl, node, objType); + + // Remove the nodes so they aren't parsed again + asCScriptNode *delNode = node; + node = node->next; + delNode->DisconnectParent(); + delNode->Destroy(engine); + } + } // Determine class inheritances and interfaces - for( n = 0; n < classDeclarations.GetLength(); n++ ) + for (asUINT n = 0; n < classDeclarations.GetLength(); n++) { sClassDeclaration *decl = classDeclarations[n]; asCScriptCode *file = decl->script; @@ -2596,9 +2777,10 @@ void asCBuilder::CompileClasses(asUINT numTempl) bool multipleInheritance = false; asCScriptNode *node = decl->node->firstChild; - while( file->TokenEquals(node->tokenPos, node->tokenLength, FINAL_TOKEN) || - file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) || - file->TokenEquals(node->tokenPos, node->tokenLength, ABSTRACT_TOKEN) ) + while (file->TokenEquals(node->tokenPos, node->tokenLength, FINAL_TOKEN) || + file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) || + file->TokenEquals(node->tokenPos, node->tokenLength, ABSTRACT_TOKEN) || + file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) { node = node->next; } @@ -2607,11 +2789,11 @@ void asCBuilder::CompileClasses(asUINT numTempl) asASSERT(node->tokenType == ttIdentifier); node = node->next; - while( node && node->nodeType == snIdentifier ) + while (node && node->nodeType == snIdentifier) { asSNameSpace *ns; asCString name; - if( GetNamespaceAndNameFromNode(node, file, decl->objType->nameSpace, ns, name) < 0 ) + if (GetNamespaceAndNameFromNode(node, file, decl->typeInfo->nameSpace, ns, name) < 0) { node = node->next; continue; @@ -2621,33 +2803,33 @@ void asCBuilder::CompileClasses(asUINT numTempl) asCObjectType *objType = 0; sMixinClass *mixin = 0; asSNameSpace *origNs = ns; - while( ns ) + while (ns) { objType = GetObjectType(name.AddressOf(), ns); - if( objType == 0 ) + if (objType == 0) mixin = GetMixinClass(name.AddressOf(), ns); - if( objType || mixin ) + if (objType || mixin) break; ns = engine->GetParentNameSpace(ns); } - if( objType == 0 && mixin == 0 ) + if (objType == 0 && mixin == 0) { asCString str; - if( origNs->name == "" ) + if (origNs->name == "") str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, name.AddressOf()); else str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, name.AddressOf(), origNs->name.AddressOf()); WriteError(str, file, node); } - else if( mixin ) + else if (mixin) { AddInterfaceFromMixinToClass(decl, node, mixin); } - else if( !(objType->flags & asOBJ_SCRIPT_OBJECT) || - (objType->flags & asOBJ_NOINHERIT) ) + else if (!(objType->flags & asOBJ_SCRIPT_OBJECT) || + (objType->flags & asOBJ_NOINHERIT)) { // Either the class is not a script class or interface // or the class has been declared as 'final' @@ -2655,12 +2837,12 @@ void asCBuilder::CompileClasses(asUINT numTempl) str.Format(TXT_CANNOT_INHERIT_FROM_s_FINAL, objType->name.AddressOf()); WriteError(str, file, node); } - else if( objType->size != 0 ) + else if (objType->size != 0) { // The class inherits from another script class - if( !decl->isExistingShared && decl->objType->derivedFrom != 0 ) + if (!decl->isExistingShared && CastToObjectType(decl->typeInfo)->derivedFrom != 0) { - if( !multipleInheritance ) + if (!multipleInheritance) { WriteError(TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES, file, node); multipleInheritance = true; @@ -2671,9 +2853,9 @@ void asCBuilder::CompileClasses(asUINT numTempl) // Make sure none of the base classes inherit from this one asCObjectType *base = objType; bool error = false; - while( base != 0 ) + while (base != 0) { - if( base == decl->objType ) + if (base == decl->typeInfo) { WriteError(TXT_CANNOT_INHERIT_FROM_SELF, file, node); error = true; @@ -2683,10 +2865,10 @@ void asCBuilder::CompileClasses(asUINT numTempl) base = base->derivedFrom; } - if( !error ) + if (!error) { // A shared type may only inherit from other shared types - if( (decl->objType->IsShared()) && !(objType->IsShared()) ) + if ((decl->typeInfo->IsShared()) && !(objType->IsShared())) { asCString msg; msg.Format(TXT_SHARED_CANNOT_INHERIT_FROM_NON_SHARED_s, objType->name.AddressOf()); @@ -2695,22 +2877,22 @@ void asCBuilder::CompileClasses(asUINT numTempl) } } - if( !error ) + if (!error) { - if( decl->isExistingShared ) + if (decl->isExistingShared) { // Verify that the base class is the same as the original shared type - if( decl->objType->derivedFrom != objType ) + if (CastToObjectType(decl->typeInfo)->derivedFrom != objType) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName()); WriteError(str, file, node); } } else { // Set the base class - decl->objType->derivedFrom = objType; + CastToObjectType(decl->typeInfo)->derivedFrom = objType; objType->AddRefInternal(); } } @@ -2725,13 +2907,21 @@ void asCBuilder::CompileClasses(asUINT numTempl) node = node->next; } } +} + +// numTempl is the number of template instances that existed in the engine before the build begun +void asCBuilder::CompileClasses(asUINT numTempl) +{ + asUINT n; + asCArray toValidate((int)classDeclarations.GetLength()); + // Order class declarations so that base classes are compiled before derived classes. // This will allow the derived classes to copy properties and methods in the next step. for( n = 0; n < classDeclarations.GetLength(); n++ ) { sClassDeclaration *decl = classDeclarations[n]; - asCObjectType *derived = decl->objType; + asCObjectType *derived = CastToObjectType(decl->typeInfo); asCObjectType *base = derived->derivedFrom; if( base == 0 ) continue; @@ -2740,7 +2930,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) for( asUINT m = n+1; m < classDeclarations.GetLength(); m++ ) { sClassDeclaration *declBase = classDeclarations[m]; - if( base == declBase->objType ) + if( base == declBase->typeInfo ) { classDeclarations.RemoveIndex(n); classDeclarations.PushLast(decl); @@ -2756,6 +2946,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) for( n = 0; n < classDeclarations.GetLength(); n++ ) { sClassDeclaration *decl = classDeclarations[n]; + asCObjectType *ot = CastToObjectType(decl->typeInfo); if( decl->isExistingShared ) { // Set the declaration as validated already, so that other @@ -2767,22 +2958,22 @@ void asCBuilder::CompileClasses(asUINT numTempl) // compilation. We do not care if something that is there in the previous // declaration is not included in the new declaration though. - asASSERT( decl->objType->interfaces.GetLength() == decl->objType->interfaceVFTOffsets.GetLength() ); + asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() ); } // Methods included from mixin classes should take precedence over inherited methods IncludeMethodsFromMixins(decl); // Add all properties and methods from the base class - if( !decl->isExistingShared && decl->objType->derivedFrom ) + if( !decl->isExistingShared && ot->derivedFrom ) { - asCObjectType *baseType = decl->objType->derivedFrom; + asCObjectType *baseType = ot->derivedFrom; // The derived class inherits all interfaces from the base class - for( unsigned int n = 0; n < baseType->interfaces.GetLength(); n++ ) + for( unsigned int m = 0; m < baseType->interfaces.GetLength(); m++ ) { - if( !decl->objType->Implements(baseType->interfaces[n]) ) - decl->objType->interfaces.PushLast(baseType->interfaces[n]); + if( !ot->Implements(baseType->interfaces[m]) ) + ot->interfaces.PushLast(baseType->interfaces[m]); } // TODO: Need to check for name conflict with new class methods @@ -2803,9 +2994,9 @@ void asCBuilder::CompileClasses(asUINT numTempl) asCScriptFunction *baseFunc = GetFunctionDescription(baseType->methods[m]); asCScriptFunction *derivedFunc = 0; bool found = false; - for( asUINT d = 0; d < decl->objType->methods.GetLength(); d++ ) + for( asUINT d = 0; d < ot->methods.GetLength(); d++ ) { - derivedFunc = GetFunctionDescription(decl->objType->methods[d]); + derivedFunc = GetFunctionDescription(ot->methods[d]); if( baseFunc->name == "opConv" || baseFunc->name == "opImplConv" || baseFunc->name == "opCast" || baseFunc->name == "opImplCast" ) { @@ -2821,8 +3012,8 @@ void asCBuilder::CompileClasses(asUINT numTempl) } // Move the function from the methods array to the virtualFunctionTable - decl->objType->methods.RemoveIndex(d); - decl->objType->virtualFunctionTable.PushLast(derivedFunc); + ot->methods.RemoveIndex(d); + ot->virtualFunctionTable.PushLast(derivedFunc); found = true; break; } @@ -2847,8 +3038,8 @@ void asCBuilder::CompileClasses(asUINT numTempl) } // Move the function from the methods array to the virtualFunctionTable - decl->objType->methods.RemoveIndex(d); - decl->objType->virtualFunctionTable.PushLast(derivedFunc); + ot->methods.RemoveIndex(d); + ot->virtualFunctionTable.PushLast(derivedFunc); found = true; break; } @@ -2858,13 +3049,13 @@ void asCBuilder::CompileClasses(asUINT numTempl) if( !found ) { // Push the base class function on the virtual function table - decl->objType->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]); + ot->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]); baseType->virtualFunctionTable[m]->AddRefInternal(); - CheckForConflictsDueToDefaultArgs(decl->script, decl->node, baseType->virtualFunctionTable[m], decl->objType); + CheckForConflictsDueToDefaultArgs(decl->script, decl->node, baseType->virtualFunctionTable[m], ot); } - decl->objType->methods.PushLast(baseType->methods[m]); + ot->methods.PushLast(baseType->methods[m]); engine->scriptFunctions[baseType->methods[m]]->AddRefInternal(); } } @@ -2872,30 +3063,30 @@ void asCBuilder::CompileClasses(asUINT numTempl) if( !decl->isExistingShared ) { // Move this class' methods into the virtual function table - for( asUINT m = 0; m < decl->objType->methods.GetLength(); m++ ) + for( asUINT m = 0; m < ot->methods.GetLength(); m++ ) { - asCScriptFunction *func = GetFunctionDescription(decl->objType->methods[m]); + asCScriptFunction *func = GetFunctionDescription(ot->methods[m]); if( func->funcType != asFUNC_VIRTUAL ) { // Move the reference from the method list to the virtual function list - decl->objType->methods.RemoveIndex(m); - decl->objType->virtualFunctionTable.PushLast(func); + ot->methods.RemoveIndex(m); + ot->virtualFunctionTable.PushLast(func); // Substitute the function description in the method list for a virtual method // Make sure the methods are in the same order as the virtual function table - decl->objType->methods.PushLast(CreateVirtualFunction(func, (int)decl->objType->virtualFunctionTable.GetLength() - 1)); + ot->methods.PushLast(CreateVirtualFunction(func, (int)ot->virtualFunctionTable.GetLength() - 1)); m--; } } // Make virtual function table chunks for each implemented interface - for( asUINT n = 0; n < decl->objType->interfaces.GetLength(); n++ ) + for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ ) { - asCObjectType *intf = decl->objType->interfaces[n]; + asCObjectType *intf = ot->interfaces[m]; // Add all the interface's functions to the virtual function table - asUINT offset = asUINT(decl->objType->virtualFunctionTable.GetLength()); - decl->objType->interfaceVFTOffsets.PushLast(offset); + asUINT offset = asUINT(ot->virtualFunctionTable.GetLength()); + ot->interfaceVFTOffsets.PushLast(offset); for( asUINT j = 0; j < intf->methods.GetLength(); j++ ) { @@ -2910,15 +3101,15 @@ void asCBuilder::CompileClasses(asUINT numTempl) //Find the interface function in the list of methods asCScriptFunction *realFunc = 0; - for( asUINT p = 0; p < decl->objType->methods.GetLength(); p++ ) + for( asUINT p = 0; p < ot->methods.GetLength(); p++ ) { - asCScriptFunction *func = GetFunctionDescription(decl->objType->methods[p]); + asCScriptFunction *func = GetFunctionDescription(ot->methods[p]); if( func->signatureId == intfFunc->signatureId ) { if( func->funcType == asFUNC_VIRTUAL ) { - realFunc = decl->objType->virtualFunctionTable[func->vfTableIdx]; + realFunc = ot->virtualFunctionTable[func->vfTableIdx]; } else { @@ -2931,7 +3122,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) // If realFunc is still null, the interface was not // implemented and we error out later in the checks. - decl->objType->virtualFunctionTable.PushLast(realFunc); + ot->virtualFunctionTable.PushLast(realFunc); if( realFunc ) realFunc->AddRefInternal(); } @@ -2945,82 +3136,77 @@ void asCBuilder::CompileClasses(asUINT numTempl) while( node && node->nodeType == snIdentifier ) node = node->next; - while( node ) + while( node && node->nodeType == snDeclaration ) { - if( node->nodeType == snDeclaration ) + asCScriptNode *nd = node->firstChild; + + // Is the property declared as private or protected? + bool isPrivate = false, isProtected = false; + if( nd && nd->tokenType == ttPrivate ) { - asCScriptNode *n = node->firstChild; - - // Is the property declared as private or protected? - bool isPrivate = false, isProtected = false; - if( n && n->tokenType == ttPrivate ) - { - isPrivate = true; - n = n->next; - } - else if( n && n->tokenType == ttProtected ) - { - isProtected = true; - n = n->next; - } - - // Determine the type of the property - asCScriptCode *file = decl->script; - asCDataType dt = CreateDataTypeFromNode(n, file, decl->objType->nameSpace); - if( decl->objType->IsShared() && dt.GetObjectType() && !dt.GetObjectType()->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf()); - WriteError(msg, file, node); - } - - if( dt.IsReadOnly() ) - WriteError(TXT_PROPERTY_CANT_BE_CONST, file, node); - - // Multiple properties can be declared separated by , - n = n->next; - while( n ) - { - asCString name(&file->code[n->tokenPos], n->tokenLength); - - if( !decl->isExistingShared ) - { - CheckNameConflictMember(decl->objType, name.AddressOf(), n, file, true); - AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, n); - } - else - { - // Verify that the property exists in the original declaration - bool found = false; - for( asUINT p = 0; p < decl->objType->properties.GetLength(); p++ ) - { - asCObjectProperty *prop = decl->objType->properties[p]; - if( prop->isPrivate == isPrivate && - prop->isProtected == isProtected && - prop->name == name && - prop->type.IsEqualExceptRef(dt) ) - { - found = true; - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName()); - WriteError(str, file, n); - } - } - - // Skip the initialization node - if( n->next && n->next->nodeType != snIdentifier ) - n = n->next; - - n = n->next; - } + isPrivate = true; + nd = nd->next; + } + else if( nd && nd->tokenType == ttProtected ) + { + isProtected = true; + nd = nd->next; + } + + // Determine the type of the property + asCScriptCode *file = decl->script; + asCDataType dt = CreateDataTypeFromNode(nd, file, ot->nameSpace, false, ot); + if( ot->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + WriteError(msg, file, node); + } + + if( dt.IsReadOnly() ) + WriteError(TXT_PROPERTY_CANT_BE_CONST, file, node); + + // Multiple properties can be declared separated by , + nd = nd->next; + while( nd ) + { + asCString name(&file->code[nd->tokenPos], nd->tokenLength); + + if( !decl->isExistingShared ) + { + CheckNameConflictMember(ot, name.AddressOf(), nd, file, true); + AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, nd); + } + else + { + // Verify that the property exists in the original declaration + bool found = false; + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) + { + asCObjectProperty *prop = ot->properties[p]; + if( prop->isPrivate == isPrivate && + prop->isProtected == isProtected && + prop->name == name && + prop->type.IsEqualExceptRef(dt) ) + { + found = true; + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + WriteError(str, file, nd); + } + } + + // Skip the initialization node + if( nd->next && nd->next->nodeType != snIdentifier ) + nd = nd->next; + + nd = nd->next; } - else - asASSERT(false); node = node->next; } @@ -3031,7 +3217,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) if( !decl->isExistingShared ) toValidate.PushLast(decl); - asASSERT( decl->objType->interfaces.GetLength() == decl->objType->interfaceVFTOffsets.GetLength() ); + asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() ); } // TODO: Warn if a method overrides a base method without marking it as 'override'. @@ -3048,13 +3234,14 @@ void asCBuilder::CompileClasses(asUINT numTempl) sClassDeclaration *decl = classDeclarations[n]; if( decl->isExistingShared ) continue; - asCArray overrideValidations(decl->objType->GetMethodCount()); - for( asUINT k = 0; k < decl->objType->methods.GetLength(); k++ ) - overrideValidations.PushLast( !static_cast(decl->objType->GetMethodByIndex(k, false))->IsOverride() ); + asCObjectType *ot = CastToObjectType(decl->typeInfo); + asCArray overrideValidations(ot->GetMethodCount()); + for( asUINT k = 0; k < ot->methods.GetLength(); k++ ) + overrideValidations.PushLast( !static_cast(ot->GetMethodByIndex(k, false))->IsOverride() ); - for( asUINT m = 0; m < decl->objType->interfaces.GetLength(); m++ ) + for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ ) { - asCObjectType *objType = decl->objType->interfaces[m]; + asCObjectType *objType = ot->interfaces[m]; for( asUINT i = 0; i < objType->methods.GetLength(); i++ ) { // Only check the interface methods that was explicitly declared in this interface @@ -3063,7 +3250,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) continue; asUINT overrideIndex; - if( !DoesMethodExist(decl->objType, objType->methods[i], &overrideIndex) ) + if( !DoesMethodExist(ot, objType->methods[i], &overrideIndex) ) { asCString str; str.Format(TXT_MISSING_IMPLEMENTATION_OF_s, @@ -3075,14 +3262,14 @@ void asCBuilder::CompileClasses(asUINT numTempl) } } - bool hasBaseClass = decl->objType->derivedFrom != 0; + bool hasBaseClass = ot->derivedFrom != 0; for( asUINT j = 0; j < overrideValidations.GetLength(); j++ ) { - if( !overrideValidations[j] && (!hasBaseClass || !DoesMethodExist(decl->objType->derivedFrom, decl->objType->methods[j])) ) + if( !overrideValidations[j] && (!hasBaseClass || !DoesMethodExist(ot->derivedFrom, ot->methods[j])) ) { asCString msg; - msg.Format(TXT_METHOD_s_DOES_NOT_OVERRIDE, decl->objType->GetMethodByIndex(j, false)->GetDeclaration()); + msg.Format(TXT_METHOD_s_DOES_NOT_OVERRIDE, ot->GetMethodByIndex(j, false)->GetDeclaration()); WriteError(msg, decl->script, decl->node); } } @@ -3098,15 +3285,16 @@ void asCBuilder::CompileClasses(asUINT numTempl) while( toValidate.GetLength() > 0 ) { sClassDeclaration *decl = toValidate[toValidate.GetLength()-1]; + asCObjectType *ot = CastToObjectType(decl->typeInfo); int validState = 1; - for( asUINT n = 0; n < decl->objType->properties.GetLength(); n++ ) + for( n = 0; n < ot->properties.GetLength(); n++ ) { // A valid structure is one that uses only primitives or other valid objects - asCObjectProperty *prop = decl->objType->properties[n]; + asCObjectProperty *prop = ot->properties[n]; asCDataType dt = prop->type; // TODO: Add this check again, once solving the issues commented below - /* + /* if( dt.IsTemplate() ) { // TODO: This must verify all sub types, not just the first one @@ -3127,7 +3315,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) sClassDeclaration *pdecl = 0; for( asUINT p = 0; p < classDeclarations.GetLength(); p++ ) { - if( classDeclarations[p]->objType == dt.GetObjectType() ) + if( classDeclarations[p]->typeInfo == dt.GetTypeInfo() ) { pdecl = classDeclarations[p]; break; @@ -3136,7 +3324,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) if( pdecl ) { - if( pdecl->objType == decl->objType ) + if( pdecl->typeInfo == decl->typeInfo ) { WriteError(TXT_ILLEGAL_MEMBER_TYPE, decl->script, decl->node); validState = 2; @@ -3198,9 +3386,11 @@ void asCBuilder::CompileClasses(asUINT numTempl) // Existing shared classes won't need evaluating, nor interfaces sClassDeclaration *decl = classDeclarations[n]; if( decl->isExistingShared ) continue; - if( decl->objType->IsInterface() ) continue; - typesToValidate.PushLast(decl->objType); + asCObjectType *ot = CastToObjectType(decl->typeInfo); + if( ot->IsInterface() ) continue; + + typesToValidate.PushLast(ot); } asUINT numReevaluations = 0; @@ -3208,7 +3398,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) { if( numReevaluations > typesToValidate.GetLength() ) { - // No types could be completely evaluated in the last iteration so + // No types could be completely evaluated in the last iteration so // we consider the remaining types in the array as garbage collected break; } @@ -3233,7 +3423,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) // Evaluate template instances (silently) before verifying each of the classes, since it is possible that // a class will be marked as non-garbage collected, which in turn will mark the template instance that uses - // it as non-garbage collected, which in turn means the class that contains the array also do not have to be + // it as non-garbage collected, which in turn means the class that contains the array also do not have to be // garbage collected EvaluateTemplateInstances(numTempl, true); @@ -3244,10 +3434,28 @@ void asCBuilder::CompileClasses(asUINT numTempl) for( asUINT p = 0; p < type->properties.GetLength(); p++ ) { asCDataType dt = type->properties[p]->type; + + if (dt.IsFuncdef()) + { + // If a class holds a function pointer as member then the class must be garbage collected as the + // function pointer can form circular references with the class through use of a delegate. Example: + // + // class A { B @b; void f(); } + // class B { F @f; } + // funcdef void F(); + // + // A a; + // @a.b = B(); // instance of A refers to instance of B + // @a.b.f = F(a.f); // instance of B refers to delegate that refers to instance of A + // + gc = true; + break; + } + if( !dt.IsObject() ) continue; - if( typesToValidate.Exists(dt.GetObjectType()) ) + if( typesToValidate.Exists(CastToObjectType(dt.GetTypeInfo())) ) mustReevaluate = true; else { @@ -3255,9 +3463,9 @@ void asCBuilder::CompileClasses(asUINT numTempl) { // Check if any of the subtypes are yet to be evaluated bool skip = false; - for( asUINT s = 0; s < dt.GetObjectType()->GetSubTypeCount(); s++ ) + for( asUINT s = 0; s < dt.GetTypeInfo()->GetSubTypeCount(); s++ ) { - asCObjectType *t = reinterpret_cast(dt.GetObjectType()->GetSubType(s)); + asCObjectType *t = reinterpret_cast(dt.GetTypeInfo()->GetSubType(s)); if( typesToValidate.Exists(t) ) { mustReevaluate = true; @@ -3273,7 +3481,7 @@ void asCBuilder::CompileClasses(asUINT numTempl) { // If it is known that the handle can't be involved in a circular reference // then this object doesn't need to be marked as garbage collected. - asCObjectType *prop = dt.GetObjectType(); + asCObjectType *prop = CastToObjectType(dt.GetTypeInfo()); if( prop->flags & asOBJ_SCRIPT_OBJECT ) { @@ -3292,13 +3500,13 @@ void asCBuilder::CompileClasses(asUINT numTempl) if( sdt.IsObjectHandle() ) { // TODO: runtime optimize: If the handle is again to a final class, then we can recursively check if the circular reference can occur - if( sdt.GetObjectType()->flags & (asOBJ_SCRIPT_OBJECT | asOBJ_GC) ) + if( sdt.GetTypeInfo()->flags & (asOBJ_SCRIPT_OBJECT | asOBJ_GC) ) { gc = true; break; } } - else if( sdt.GetObjectType()->flags & asOBJ_GC ) + else if( sdt.GetTypeInfo()->flags & asOBJ_GC ) { // TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is. // Only if the object is of a type that can reference this type, either directly or indirectly @@ -3321,14 +3529,14 @@ void asCBuilder::CompileClasses(asUINT numTempl) else if( prop->flags & asOBJ_GC ) { // If a type is not a script object, adopt its GC flag - // TODO: runtime optimize: Just because an application registered class is garbage collected, doesn't mean it + // TODO: runtime optimize: Just because an application registered class is garbage collected, doesn't mean it // can form a circular reference with this script class. Perhaps need a flag to tell // if the script classes that contains the type should be garbage collected or not. gc = true; break; } } - else if( dt.GetObjectType()->flags & asOBJ_GC ) + else if( dt.GetTypeInfo()->flags & asOBJ_GC ) { // TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is. // Only if the object is of a type that can reference this type, either directly or indirectly @@ -3338,8 +3546,8 @@ void asCBuilder::CompileClasses(asUINT numTempl) } } - // If the class wasn't found to require garbage collection, but it - // contains another type that has yet to be evaluated then it must be + // If the class wasn't found to require garbage collection, but it + // contains another type that has yet to be evaluated then it must be // re-evaluated. if( !gc && mustReevaluate ) { @@ -3376,7 +3584,7 @@ void asCBuilder::IncludeMethodsFromMixins(sClassDeclaration *decl) { asSNameSpace *ns; asCString name; - if( GetNamespaceAndNameFromNode(node, decl->script, decl->objType->nameSpace, ns, name) < 0 ) + if( GetNamespaceAndNameFromNode(node, decl->script, decl->typeInfo->nameSpace, ns, name) < 0 ) { node = node->next; continue; @@ -3385,11 +3593,11 @@ void asCBuilder::IncludeMethodsFromMixins(sClassDeclaration *decl) sMixinClass *mixin = 0; while( ns ) { - // Need to make sure the name is not an object type + // Need to make sure the name is not an object type asCObjectType *objType = GetObjectType(name.AddressOf(), ns); if( objType == 0 ) mixin = GetMixinClass(name.AddressOf(), ns); - + if( objType || mixin ) break; @@ -3416,7 +3624,7 @@ void asCBuilder::IncludeMethodsFromMixins(sClassDeclaration *decl) asCScriptNode *copy = n->CreateCopy(engine); // Register the method, but only if it doesn't already exist in the class - RegisterScriptFunctionFromNode(copy, mixin->script, decl->objType, false, false, mixin->ns, false, true); + RegisterScriptFunctionFromNode(copy, mixin->script, CastToObjectType(decl->typeInfo), false, false, mixin->ns, false, true); } else if( n->nodeType == snVirtualProperty ) { @@ -3450,7 +3658,7 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) { asSNameSpace *ns; asCString name; - if( GetNamespaceAndNameFromNode(node, decl->script, decl->objType->nameSpace, ns, name) < 0 ) + if( GetNamespaceAndNameFromNode(node, decl->script, decl->typeInfo->nameSpace, ns, name) < 0 ) { node = node->next; continue; @@ -3459,11 +3667,11 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) sMixinClass *mixin = 0; while( ns ) { - // Need to make sure the name is not an object type + // Need to make sure the name is not an object type asCObjectType *objType = GetObjectType(name.AddressOf(), ns); if( objType == 0 ) mixin = GetMixinClass(name.AddressOf(), ns); - + if( objType || mixin ) break; @@ -3501,10 +3709,10 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) asCScriptCode *file = mixin->script; asCDataType dt = CreateDataTypeFromNode(n2, file, mixin->ns); - if( decl->objType->IsShared() && dt.GetObjectType() && !dt.GetObjectType()->IsShared() ) + if( decl->typeInfo->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) { asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf()); + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); WriteError(msg, file, n); WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); } @@ -3515,12 +3723,13 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) n2 = n2->next; while( n2 ) { - asCString name(&file->code[n2->tokenPos], n2->tokenLength); + name.Assign(&file->code[n2->tokenPos], n2->tokenLength); // Add the property only if it doesn't already exist in the class bool exists = false; - for( asUINT p = 0; p < decl->objType->properties.GetLength(); p++ ) - if( decl->objType->properties[p]->name == name ) + asCObjectType *ot = CastToObjectType(decl->typeInfo); + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) + if( ot->properties[p]->name == name ) { exists = true; break; @@ -3531,7 +3740,7 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) if( !decl->isExistingShared ) { // It must not conflict with the name of methods - int r = CheckNameConflictMember(decl->objType, name.AddressOf(), n2, file, true); + int r = CheckNameConflictMember(ot, name.AddressOf(), n2, file, true); if( r < 0 ) WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); @@ -3541,9 +3750,9 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) { // Verify that the property exists in the original declaration bool found = false; - for( asUINT p = 0; p < decl->objType->properties.GetLength(); p++ ) + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) { - asCObjectProperty *prop = decl->objType->properties[p]; + asCObjectProperty *prop = ot->properties[p]; if( prop->isPrivate == isPrivate && prop->isProtected == isProtected && prop->name == name && @@ -3556,7 +3765,7 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) if( !found ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); WriteError(str, decl->script, decl->node); WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); } @@ -3590,15 +3799,14 @@ int asCBuilder::CreateVirtualFunction(asCScriptFunction *func, int idx) vf->parameterTypes = func->parameterTypes; vf->inOutFlags = func->inOutFlags; vf->id = engine->GetNextScriptFunctionId(); - vf->isReadOnly = func->isReadOnly; vf->objectType = func->objectType; vf->objectType->AddRefInternal(); vf->signatureId = func->signatureId; - vf->isPrivate = func->isPrivate; - vf->isProtected = func->isProtected; - vf->isFinal = func->isFinal; - vf->isOverride = func->isOverride; vf->vfTableIdx = idx; + vf->traits = func->traits; + + // Clear the shared trait since the virtual function should not have that + vf->SetShared(false); // It is not necessary to copy the default args, as they have no meaning in the virtual function @@ -3623,12 +3831,12 @@ asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const { asCString str; if( dt.IsAbstractClass() ) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->objType->nameSpace).AddressOf()); + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->typeInfo->nameSpace).AddressOf()); else if( dt.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->objType->nameSpace).AddressOf()); + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->typeInfo->nameSpace).AddressOf()); else // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(decl->objType->nameSpace).AddressOf()); + str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(decl->typeInfo->nameSpace).AddressOf()); WriteError(str, file, node); } return 0; @@ -3654,7 +3862,7 @@ asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const } // Add the property to the object type - return decl->objType->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); + return CastToObjectType(decl->typeInfo)->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); } bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex) @@ -3667,7 +3875,7 @@ bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId, asUINT *m if( m->name != method->name ) continue; if( m->returnType != method->returnType ) continue; - if( m->isReadOnly != method->isReadOnly ) continue; + if( m->IsReadOnly() != method->IsReadOnly() ) continue; if( m->parameterTypes != method->parameterTypes ) continue; if( m->inOutFlags != method->inOutFlags ) continue; @@ -3692,7 +3900,7 @@ void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *fi // Add the script function // TODO: declaredAt should be set to where the class has been declared - module->AddScriptFunction(file->idx, 0, funcId, objType->name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, false, objType); + module->AddScriptFunction(file->idx, 0, funcId, objType->name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, false, objType, false, asSFunctionTraits(), objType->nameSpace); // Set it as default constructor if( objType->beh.construct ) @@ -3735,18 +3943,24 @@ void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *fi // If the object is shared, then the factory must also be marked as shared if( objType->flags & asOBJ_SHARED ) - engine->scriptFunctions[funcId]->isShared = true; + engine->scriptFunctions[funcId]->SetShared(true); } int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) { // Is it a shared enum? bool isShared = false; - asCObjectType *existingSharedType = 0; + bool isExternal = false; + asCEnumType *existingSharedType = 0; asCScriptNode *tmp = node->firstChild; - if( tmp->nodeType == snIdentifier && file->TokenEquals(tmp->tokenPos, tmp->tokenLength, SHARED_TOKEN) ) + while( tmp->nodeType == snIdentifier ) { - isShared = true; + if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, SHARED_TOKEN)) + isShared = true; + else if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, EXTERNAL_TOKEN)) + isExternal = true; + else + break; tmp = tmp->next; } @@ -3761,24 +3975,36 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp // Look for a pre-existing shared enum with the same signature for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) { - asCObjectType *o = engine->sharedScriptTypes[n]; + asCTypeInfo *o = engine->sharedScriptTypes[n]; if( o && o->IsShared() && (o->flags & asOBJ_ENUM) && o->name == name && o->nameSpace == ns ) { - existingSharedType = o; + existingSharedType = CastToEnumType(o); break; } } } + // If the enum was declared as external then it must have been compiled in a different module first + if (isExternal && existingSharedType == 0) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, tmp); + } + + // Remember if the type was declared as external so the saved bytecode can be flagged accordingly + if (isExternal && existingSharedType) + module->externalTypes.PushLast(existingSharedType); + // Check the name and add the enum int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file, ns); if( asSUCCESS == r ) { - asCObjectType *st; + asCEnumType *st; if( existingSharedType ) { @@ -3787,7 +4013,7 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp } else { - st = asNEW(asCObjectType)(engine); + st = asNEW(asCEnumType)(engine); if( st == 0 ) return asOUT_OF_MEMORY; @@ -3814,19 +4040,31 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp decl->name = name; decl->script = file; - decl->objType = st; + decl->typeInfo = st; namedTypeDeclarations.PushLast(decl); asCDataType type = CreateDataTypeFromNode(tmp, file, ns); asASSERT(!type.IsReference()); + // External shared enums must not redeclare the enum values + if (isExternal && (tmp->next == 0 || tmp->next->tokenType != ttEndStatement) ) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, tmp); + } + else if (!isExternal && tmp->next && tmp->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, tmp); + } + // Register the enum values tmp = tmp->next; - while( tmp ) + while( tmp && tmp->nodeType == snIdentifier ) { - asASSERT(snIdentifier == tmp->nodeType); - - asCString name(&file->code[tmp->tokenPos], tmp->tokenLength); + name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength); if( existingSharedType ) { @@ -3890,7 +4128,7 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp gvar->ns = ns; // No need to allocate space on the global memory stack since the values are stored in the asCObjectType // Set the index to a negative to allow compiler to diferentiate from ordinary global var when compiling the initialization - gvar->index = -1; + gvar->index = -1; gvar->isCompiled = false; gvar->isPureConstant = true; gvar->isEnumValue = true; @@ -3935,11 +4173,11 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam // If the name is not already in use add it int r = CheckNameConflict(name.AddressOf(), tmp, file, ns); - asCObjectType *st = 0; + asCTypedefType *st = 0; if( asSUCCESS == r ) { // Create the new type - st = asNEW(asCObjectType)(engine); + st = asNEW(asCTypedefType)(engine); if( st == 0 ) r = asOUT_OF_MEMORY; } @@ -3950,7 +4188,7 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam st->size = dataType.GetSizeInMemoryBytes(); st->name = name; st->nameSpace = ns; - st->templateSubTypes.PushLast(dataType); + st->aliasForType = dataType; st->module = module; module->typeDefs.PushLast(st); @@ -3963,7 +4201,7 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam { decl->name = name; decl->script = file; - decl->objType = st; + decl->typeInfo = st; namedTypeDeclarations.PushLast(decl); } } @@ -3973,34 +4211,41 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam return r; } -void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, bool &isConstMethod, bool &isConstructor, bool &isDestructor, bool &isPrivate, bool &isProtected, bool &isOverride, bool &isFinal, bool &isShared, asSNameSpace *implicitNamespace) +void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits &funcTraits, asSNameSpace *implicitNamespace) { node = node->firstChild; + // Is the function shared? + funcTraits.SetTrait(asTRAIT_SHARED, false); + funcTraits.SetTrait(asTRAIT_EXTERNAL, false); + while (node->tokenType == ttIdentifier) + { + if (file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN)) + funcTraits.SetTrait(asTRAIT_SHARED, true); + else if (file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) + funcTraits.SetTrait(asTRAIT_EXTERNAL, true); + else + break; + node = node->next; + } + // Is the function a private or protected class method? - isPrivate = false, isProtected = false; + funcTraits.SetTrait(asTRAIT_PRIVATE, false); + funcTraits.SetTrait(asTRAIT_PROTECTED, false); if( node->tokenType == ttPrivate ) { - isPrivate = true; + funcTraits.SetTrait(asTRAIT_PRIVATE, true); node = node->next; } else if( node->tokenType == ttProtected ) { - isProtected = true; - node = node->next; - } - - // Is the function shared? - isShared = false; - if( node->tokenType == ttIdentifier && file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) ) - { - isShared = true; + funcTraits.SetTrait(asTRAIT_PROTECTED, true); node = node->next; } // Find the name - isConstructor = false; - isDestructor = false; + funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, false); + funcTraits.SetTrait(asTRAIT_DESTRUCTOR, false); asCScriptNode *n = 0; if( node->nodeType == snDataType ) n = node->next->next; @@ -4010,27 +4255,26 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi if( node->tokenType == ttBitNot ) { n = node->next; - isDestructor = true; + funcTraits.SetTrait(asTRAIT_DESTRUCTOR, true); } else { n = node; - isConstructor = true; + funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, true); } } name.Assign(&file->code[n->tokenPos], n->tokenLength); - // Initialize a script function object for registration - if( !isConstructor && !isDestructor ) + if( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) { - returnType = CreateDataTypeFromNode(node, file, implicitNamespace); + returnType = CreateDataTypeFromNode(node, file, implicitNamespace, false, objType); returnType = ModifyDataTypeFromNode(returnType, node->next, file, 0, 0); if( engine->ep.disallowValueAssignForRefType && - returnType.GetObjectType() && - (returnType.GetObjectType()->flags & asOBJ_REF) && - !(returnType.GetObjectType()->flags & asOBJ_SCOPED) && - !returnType.IsReference() && + returnType.GetTypeInfo() && + (returnType.GetTypeInfo()->flags & asOBJ_REF) && + !(returnType.GetTypeInfo()->flags & asOBJ_SCOPED) && + !returnType.IsReference() && !returnType.IsObjectHandle() ) { WriteError(TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL, file, node); @@ -4039,9 +4283,9 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi else returnType = asCDataType::CreatePrimitive(ttVoid, false); - isConstMethod = false; - isFinal = false; - isOverride = false; + funcTraits.SetTrait(asTRAIT_CONST, false); + funcTraits.SetTrait(asTRAIT_FINAL, false); + funcTraits.SetTrait(asTRAIT_OVERRIDE, false); if( objType && n->next->next ) { @@ -4050,16 +4294,16 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi // Is this a const method? if( decorator->tokenType == ttConst ) { - isConstMethod = true; + funcTraits.SetTrait(asTRAIT_CONST, true); decorator = decorator->next; } while( decorator ) { if( decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, FINAL_TOKEN) ) - isFinal = true; + funcTraits.SetTrait(asTRAIT_FINAL, true); else if( decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, OVERRIDE_TOKEN) ) - isOverride = true; + funcTraits.SetTrait(asTRAIT_OVERRIDE, true); decorator = decorator->next; } @@ -4087,14 +4331,14 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi while( n ) { asETypeModifiers inOutFlag; - asCDataType type = CreateDataTypeFromNode(n, file, implicitNamespace); + asCDataType type = CreateDataTypeFromNode(n, file, implicitNamespace, false, objType); type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0); if( engine->ep.disallowValueAssignForRefType && - type.GetObjectType() && - (type.GetObjectType()->flags & asOBJ_REF) && - !(type.GetObjectType()->flags & asOBJ_SCOPED) && - !type.IsReference() && + type.GetTypeInfo() && + (type.GetTypeInfo()->flags & asOBJ_REF) && + !(type.GetTypeInfo()->flags & asOBJ_SCOPED) && + !type.IsReference() && !type.IsObjectHandle() ) { WriteError(TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL, file, node); @@ -4108,9 +4352,8 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi n = n->next->next; if( n && n->nodeType == snIdentifier ) { - asCString name; - name.Assign(&file->code[n->tokenPos], n->tokenLength); - parameterNames.PushLast(name); + asCString paramName(&file->code[n->tokenPos], n->tokenLength); + parameterNames.PushLast(paramName); n = n->next; } else @@ -4167,14 +4410,7 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod asCArray parameterTypes; asCArray inOutFlags; asCArray defaultArgs; - bool isConstMethod; - bool isOverride; - bool isFinal; - bool isConstructor; - bool isDestructor; - bool isPrivate; - bool isProtected; - bool isShared; + asSFunctionTraits funcTraits; asASSERT( (objType && ns == 0) || isGlobalFunction || isMixin ); @@ -4187,9 +4423,9 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod ns = engine->nameSpaces[0]; } - GetParsedFunctionDetails(node, file, objType, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared, ns); + GetParsedFunctionDetails(node, file, objType, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns); - return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared); + 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) @@ -4212,7 +4448,7 @@ asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode // Get the return and parameter types from the funcDef asCString funcName = name; - int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, false, false, false, false, false, false, false, false); + int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, asSFunctionTraits()); if( r < 0 ) return 0; @@ -4220,7 +4456,7 @@ asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode return engine->scriptFunctions[functions[functions.GetLength()-1]->funcId]; } -int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isProtected, bool isOverride, bool isFinal, bool isShared) +int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits funcTraits) { // Determine default namespace if not specified if( ns == 0 ) @@ -4237,7 +4473,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, // Should validate that the function really exists in the class/interface bool found = false; - if( isConstructor || isDestructor ) + if(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) || funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) { // TODO: shared: Should check the existance of these too found = true; @@ -4248,7 +4484,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, { asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]]; if( func->name == name && - func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, isConstMethod) ) + func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) ) { // Add the shared function in this module too module->AddScriptFunction(func); @@ -4276,7 +4512,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, } // Check for name conflicts - if( !isConstructor && !isDestructor ) + if( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) { if( objType ) { @@ -4308,14 +4544,14 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, if( name != objType->name ) { asCString str; - if( isDestructor ) + if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) str.Format(TXT_DESTRUCTOR_s_s_NAME_ERROR, objType->name.AddressOf(), name.AddressOf()); else str.Format(TXT_METHOD_s_s_HAS_NO_RETURN_TYPE, objType->name.AddressOf(), name.AddressOf()); WriteError(str, file, node); } - if( isDestructor ) + if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR)) name = "~" + name; } @@ -4344,14 +4580,14 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, func->isExistingShared = false; func->paramNames = parameterNames; - if( isShared ) + if(funcTraits.GetTrait(asTRAIT_SHARED)) { // Look for a pre-existing shared function with the same signature for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) { asCScriptFunction *f = engine->scriptFunctions[n]; if( f && - f->isShared && + f->IsShared() && f->name == name && f->nameSpace == ns && f->objectType == objType && @@ -4363,30 +4599,58 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, } } } + + // Remember if the function was declared as external so the saved bytecode can be flagged accordingly + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && func->isExistingShared) + module->externalFunctions.PushLast(engine->scriptFunctions[func->funcId]); + + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !func->isExistingShared) + { + // Mark it as existing shared to avoid compiling it + func->isExistingShared = true; + + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, node); + } + + // External shared function must not try to redefine the interface + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->tokenType == ttEndStatement || node->lastChild->tokenType == ttEndStatement)) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, node); + } + else if (!funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->nodeType == snStatementBlock || node->lastChild->nodeType == snStatementBlock) ) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, node); + } } // Destructors may not have any parameters - if( isDestructor && parameterTypes.GetLength() > 0 ) + if (funcTraits.GetTrait(asTRAIT_DESTRUCTOR) && parameterTypes.GetLength() > 0) WriteError(TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM, file, node); // If a function, class, or interface is shared then only shared types may be used in the signature - if( (objType && objType->IsShared()) || isShared ) + if( (objType && objType->IsShared()) || funcTraits.GetTrait(asTRAIT_SHARED)) { - asCObjectType *ot = returnType.GetObjectType(); - if( ot && !ot->IsShared() ) + asCTypeInfo *ti = returnType.GetTypeInfo(); + if( ti && !ti->IsShared() ) { asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf()); + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->name.AddressOf()); WriteError(msg, file, node); } for( asUINT p = 0; p < parameterTypes.GetLength(); ++p ) { - asCObjectType *ot = parameterTypes[p].GetObjectType(); - if( ot && !ot->IsShared() ) + ti = parameterTypes[p].GetTypeInfo(); + if( ti && !ti->IsShared() ) { asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf()); + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->name.AddressOf()); WriteError(msg, file, node); } } @@ -4404,7 +4668,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, for( asUINT n = 0; n < funcs.GetLength(); ++n ) { asCScriptFunction *func = GetFunctionDescription(funcs[n]); - if( func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, isConstMethod) ) + if( func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) ) { // TODO: clean up: Reuse the same error handling for both opConv and normal methods if( isMixin ) @@ -4412,11 +4676,11 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, // Clean up the memory, as the function will not be registered if( node ) node->Destroy(engine); - sFunctionDescription *func = functions.PopLast(); - asDELETE(func, sFunctionDescription); + sFunctionDescription *funcDesc = functions.PopLast(); + asDELETE(funcDesc, sFunctionDescription); // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + for( n = 0; n < defaultArgs.GetLength(); n++ ) if( defaultArgs[n] ) asDELETE(defaultArgs[n], asCString); @@ -4433,18 +4697,18 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, for( asUINT n = 0; n < funcs.GetLength(); ++n ) { asCScriptFunction *func = GetFunctionDescription(funcs[n]); - if( func->IsSignatureExceptNameAndReturnTypeEqual(parameterTypes, inOutFlags, objType, isConstMethod) ) + if( func->IsSignatureExceptNameAndReturnTypeEqual(parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) ) { if( isMixin ) { // Clean up the memory, as the function will not be registered if( node ) node->Destroy(engine); - sFunctionDescription *func = functions.PopLast(); - asDELETE(func, sFunctionDescription); + sFunctionDescription *funcDesc = functions.PopLast(); + asDELETE(funcDesc, sFunctionDescription); // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + for( n = 0; n < defaultArgs.GetLength(); n++ ) if( defaultArgs[n] ) asDELETE(defaultArgs[n], asCString); @@ -4476,7 +4740,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, int row = 0, col = 0; if( node ) file->ConvertPosToRowCol(node->tokenPos, &row, &col); - module->AddScriptFunction(file->idx, (row&0xFFFFF)|((col&0xFFF)<<20), funcId, name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, isInterface, objType, isConstMethod, isGlobalFunction, isPrivate, isProtected, isFinal, isOverride, isShared, ns); + module->AddScriptFunction(file->idx, (row&0xFFFFF)|((col&0xFFF)<<20), funcId, name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, isInterface, objType, isGlobalFunction, funcTraits, ns); } // Make sure the default args are declared correctly @@ -4488,7 +4752,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asASSERT( !isExistingShared ); engine->scriptFunctions[funcId]->AddRefInternal(); - if( isConstructor ) + if(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR)) { int factoryId = engine->GetNextScriptFunctionId(); if( parameterTypes.GetLength() == 0 ) @@ -4521,7 +4785,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, // If the object is shared, then the factory must also be marked as shared if( objType->flags & asOBJ_SHARED ) - engine->scriptFunctions[factoryId]->isShared = true; + engine->scriptFunctions[factoryId]->SetShared(true); // Add a dummy function to the builder so that it doesn't mix up the fund Ids functions.PushLast(0); @@ -4531,14 +4795,14 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]); engine->scriptFunctions[factoryId]->AddRefInternal(); } - else if( isDestructor ) + else if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR)) objType->beh.destruct = funcId; else { // If the method is the assignment operator we need to replace the default implementation asCScriptFunction *f = engine->scriptFunctions[funcId]; if( f->name == "opAssign" && f->parameterTypes.GetLength() == 1 && - f->parameterTypes[0].GetObjectType() == f->objectType && + f->parameterTypes[0].GetTypeInfo() == f->objectType && (f->inOutFlags[0] & asTM_INREF) ) { engine->scriptFunctions[objType->beh.copy]->ReleaseInternal(); @@ -4603,14 +4867,12 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file WriteError(TXT_PROPERTY_WITHOUT_ACCESSOR, file, node); node = node->next; - while( node ) + while (node) { - asCScriptNode *next = node->next; - asCScriptNode *funcNode = 0; - bool success = false; - bool isConst = false; - bool isFinal = false; - bool isOverride = false; + asCScriptNode *next = node->next; + asCScriptNode *funcNode = 0; + bool success = false; + asSFunctionTraits funcTraits; asCDataType returnType; asCArray paramNames; asCArray paramTypes; @@ -4618,33 +4880,44 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file asCArray defaultArgs; asCString name; + funcTraits.SetTrait(asTRAIT_PRIVATE, isPrivate); + funcTraits.SetTrait(asTRAIT_PROTECTED, isProtected); + // TODO: getset: Allow private for individual property accessors // TODO: getset: If the accessor uses its own name, then the property should be automatically declared - if( node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, GET_TOKEN) ) + if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, GET_TOKEN)) + name = "get_"; + else if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, SET_TOKEN)) + name = "set_"; + else + WriteError(TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE, file, node); + + if (name != "") { - funcNode = node->firstChild->next; + success = true; + funcNode = node->firstChild->next; - if( funcNode && funcNode->tokenType == ttConst ) + if (funcNode && funcNode->tokenType == ttConst) { - isConst = true; + funcTraits.SetTrait(asTRAIT_CONST, true); funcNode = funcNode->next; } - while( funcNode && funcNode->nodeType != snStatementBlock ) + while (funcNode && funcNode->nodeType != snStatementBlock) { - if( funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN) ) - isFinal = true; - else if( funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN) ) - isOverride = true; + if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN)) + funcTraits.SetTrait(asTRAIT_FINAL, true); + else if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN)) + funcTraits.SetTrait(asTRAIT_OVERRIDE, true); funcNode = funcNode->next; } - if( funcNode ) + if (funcNode) funcNode->DisconnectParent(); - if( funcNode == 0 && (objType == 0 || !objType->IsInterface()) ) + if (funcNode == 0 && (objType == 0 || !objType->IsInterface())) { // TODO: getset: If no implementation is supplied the builder should provide an automatically generated implementation // The compiler needs to be able to handle the different types, primitive, value type, and handle @@ -4652,53 +4925,28 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file WriteError(TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED, file, node); } - // Setup the signature for the get accessor method - returnType = emulatedType; - name = "get_" + emulatedName; - success = true; - } - else if( node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, SET_TOKEN) ) - { - funcNode = node->firstChild->next; - - if( funcNode && funcNode->tokenType == ttConst ) + if (name == "get_") { - isConst = true; - funcNode = funcNode->next; + // Setup the signature for the get accessor method + returnType = emulatedType; + name = "get_" + emulatedName; } - - while( funcNode && funcNode->nodeType != snStatementBlock ) + else if (name == "set_") { - if( funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN) ) - isFinal = true; - else if( funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN) ) - isOverride = true; - - funcNode = funcNode->next; + // Setup the signature for the set accessor method + returnType = asCDataType::CreatePrimitive(ttVoid, false); + paramModifiers.PushLast(asTM_NONE); + paramNames.PushLast("value"); + paramTypes.PushLast(emulatedType); + defaultArgs.PushLast(0); + name = "set_" + emulatedName; } - - if( funcNode ) - funcNode->DisconnectParent(); - - if( funcNode == 0 && (objType == 0 || !objType->IsInterface()) ) - WriteError(TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED, file, node); - - // Setup the signature for the set accessor method - returnType = asCDataType::CreatePrimitive(ttVoid, false); - paramModifiers.PushLast(asTM_NONE); - paramNames.PushLast("value"); - paramTypes.PushLast(emulatedType); - defaultArgs.PushLast(0); - name = "set_" + emulatedName; - success = true; } - else - WriteError(TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE, file, node); if( success ) { if( !isExistingShared ) - RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, isConst, false, false, isPrivate, isProtected, isOverride, isFinal, false); + RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, funcTraits); else { // Free the funcNode as it won't be used @@ -4710,7 +4958,7 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file { asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]]; if( func->name == name && - func->IsSignatureExceptNameEqual(returnType, paramTypes, paramModifiers, objType, isConst) ) + func->IsSignatureExceptNameEqual(returnType, paramTypes, paramModifiers, objType, funcTraits.GetTrait(asTRAIT_CONST)) ) { found = true; break; @@ -4742,12 +4990,12 @@ int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCS asCArray parameterTypes; asCArray inOutFlags; asCArray defaultArgs; - bool isConstMethod, isOverride, isFinal, isConstructor, isDestructor, isPrivate, isProtected, isShared; + asSFunctionTraits funcTraits; if( ns == 0 ) ns = engine->nameSpaces[0]; - GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared, ns); + GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns); CheckNameConflict(name.AddressOf(), node, file, ns); // Check that the same function hasn't been registered already in the namespace @@ -4823,73 +5071,70 @@ void asCBuilder::GetFunctionDescriptions(const char *name, asCArray &funcs, } } +// scope is only informed when looking for a base class' method void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray &methods, bool objIsConst, const asCString &scope, asCScriptNode *errNode, asCScriptCode *script) { + asASSERT(objectType); + if( scope != "" ) { // If searching with a scope informed, then the node and script must also be informed for potential error reporting asASSERT( errNode && script ); // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace + // TODO: child funcdef: A scope can include a template type, e.g. array int n = scope.FindLast("::"); asCString className = n >= 0 ? scope.SubString(n+2) : scope; asCString nsName = n >= 0 ? scope.SubString(0, n) : ""; - // Check if the namespace actually exist, if not return silently as this cannot be the referring to a base class - asSNameSpace *ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, false); - if( ns == 0 ) - return; + // If a namespace was specifically defined, then this must be used + asSNameSpace *ns = 0; + if (n >= 0) + { + if (nsName == "") + ns = engine->nameSpaces[0]; + else + ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, 0, false); + + // If the namespace isn't found return silently and let the calling + // function report the error if it cannot resolve the symbol + if (ns == 0) + return; + } // Find the base class with the specified scope - while( objectType && (objectType->name != className || objectType->nameSpace != ns) ) + while (objectType) + { + // If the name and namespace matches it is the correct class. If no + // specific namespace was given, then don't compare the namespace + if (objectType->name == className && (ns == 0 || objectType->nameSpace == ns)) + break; + objectType = objectType->derivedFrom; + } // If the scope is not any of the base classes, then return no methods if( objectType == 0 ) return; } + // Find the methods in the object that match the name // TODO: optimize: Improve linear search - if( objIsConst ) + for( asUINT n = 0; n < objectType->methods.GetLength(); n++ ) { - // Only add const methods to the list - for( asUINT n = 0; n < objectType->methods.GetLength(); n++ ) + asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]]; + if( func->name == name && + (!objIsConst || func->IsReadOnly()) && + (func->accessMask & module->accessMask) ) { - asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]]; - if( func->name == name && - func->isReadOnly && - (func->accessMask & module->accessMask) ) + // When the scope is defined the returned methods should be the true methods, not the virtual method stubs + if( scope == "" ) + methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id); + else { - // When the scope is defined the returned methods should be the true methods, not the virtual method stubs - if( scope == "" ) - methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id); - else - { - asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]]; - asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx]; - methods.PushLast(realFunc->id); - } - } - } - } - else - { - // TODO: Prefer non-const over const - for( asUINT n = 0; n < objectType->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]]; - if( func->name == name && - (func->accessMask & module->accessMask) ) - { - // When the scope is defined the returned methods should be the true methods, not the virtual method stubs - if( scope == "" ) - methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id); - else - { - asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]]; - asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx]; - methods.PushLast(realFunc->id); - } + asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]]; + asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx]; + methods.PushLast(realFunc->id); } } } @@ -4962,16 +5207,25 @@ void asCBuilder::WriteWarning(const asCString &message, asCScriptCode *file, asC WriteWarning(file ? file->name : asCString(""), message, r, c); } +// TODO: child funcdef: Should try to eliminate this function. GetNameSpaceFromNode is more complete asCString asCBuilder::GetScopeFromNode(asCScriptNode *node, asCScriptCode *script, asCScriptNode **next) { + if (node->nodeType != snScope) + { + if (next) + *next = node; + return ""; + } + asCString scope; - asCScriptNode *sn = node; + asCScriptNode *sn = node->firstChild; if( sn->tokenType == ttScope ) { scope = "::"; sn = sn->next; } + // TODO: child funcdef: A scope can have a template type as the innermost while( sn && sn->next && sn->next->tokenType == ttScope ) { asCString tmp; @@ -4983,26 +5237,128 @@ asCString asCBuilder::GetScopeFromNode(asCScriptNode *node, asCScriptCode *scrip } if( next ) - *next = sn; + *next = node->next; return scope; } -asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next) +asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next, asCObjectType **objType) { - asCString scope = GetScopeFromNode(node, script, next); - return GetNameSpaceByString(scope, implicitNs, node, script); + if (objType) + *objType = 0; + + // If no scope has been informed, then return the implicit namespace + if (node->nodeType != snScope) + { + if (next) + *next = node; + return implicitNs ? implicitNs : engine->nameSpaces[0]; + } + + if (next) + *next = node->next; + + asCString scope; + asCScriptNode *sn = node->firstChild; + if (sn && sn->tokenType == ttScope) + { + scope = "::"; + sn = sn->next; + } + + while (sn) + { + if (sn->next->tokenType == ttScope) + { + asCString tmp; + tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength); + if (scope != "" && scope != "::") + scope += "::"; + scope += tmp; + sn = sn->next->next; + } + else + { + // This is a template type + asASSERT(sn->next->nodeType == snDataType); + + asSNameSpace *ns = implicitNs; + if (scope != "") + ns = engine->FindNameSpace(scope.AddressOf()); + + asCString templateName(&script->code[sn->tokenPos], sn->tokenLength); + asCObjectType *templateType = GetObjectType(templateName.AddressOf(), ns); + if (templateType == 0 || (templateType->flags & asOBJ_TEMPLATE) == 0) + { + // TODO: child funcdef: Report error + return ns; + } + + if (objType) + *objType = GetTemplateInstanceFromNode(sn, script, templateType, implicitNs, 0); + + // Return no namespace, since this is an object type + return 0; + } + } + + asCTypeInfo *ti = 0; + asSNameSpace *ns = GetNameSpaceByString(scope, implicitNs ? implicitNs : engine->nameSpaces[0], node, script, &ti); + if (ti && objType) + *objType = CastToObjectType(ti); + return ns; } -asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, bool isRequired) +asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType, bool isRequired) { + if( scopeType ) + *scopeType = 0; + asSNameSpace *ns = implicitNs; if( nsName == "::" ) ns = engine->nameSpaces[0]; else if( nsName != "" ) { ns = engine->FindNameSpace(nsName.AddressOf()); - if( ns == 0 && isRequired ) + if (ns == 0 && scopeType) + { + asCString typeName; + asCString searchNs; + + // Split the scope with at the inner most :: + int pos = nsName.FindLast("::"); + bool recursive = false; + if (pos >= 0) + { + // Fully qualified namespace + typeName = nsName.SubString(pos + 2); + searchNs = nsName.SubString(0, pos); + } + else + { + // Partially qualified, use the implicit namespace and then search recursively for the type + typeName = nsName; + searchNs = implicitNs->name; + recursive = true; + } + + asSNameSpace *nsTmp = searchNs == "::" ? engine->nameSpaces[0] : engine->FindNameSpace(searchNs.AddressOf()); + asCTypeInfo *ti = 0; + while( !ti && nsTmp ) + { + // Check if the typeName is an existing type in the namespace + ti = GetType(typeName.AddressOf(), nsTmp, 0); + if (ti) + { + // The informed scope is not a namespace, but it does match a type + *scopeType = ti; + return 0; + } + nsTmp = recursive ? engine->GetParentNameSpace(nsTmp) : 0; + } + } + + if (ns == 0 && isRequired) { asCString msg; msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, nsName.AddressOf()); @@ -5013,14 +5369,22 @@ asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameS return ns; } -asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope, asCObjectType *currentType) +asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope, asCObjectType *currentType, bool reportError, bool *isValid) { - asASSERT(node->nodeType == snDataType); + asASSERT(node->nodeType == snDataType || node->nodeType == snIdentifier || node->nodeType == snScope ); asCDataType dt; asCScriptNode *n = node->firstChild; + if (isValid) + *isValid = true; + + // If the informed node is an identifier or scope, then the + // datatype should be identified directly from that + if (node->nodeType != snDataType) + n = node; + bool isConst = false; bool isImplicitHandle = false; if( n->tokenType == ttConst ) @@ -5029,12 +5393,15 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod n = n->next; } - // Determine namespace - asSNameSpace *ns = GetNameSpaceFromNode(n, file, implicitNamespace, &n); - if( ns == 0 ) + // Determine namespace (or parent type) to search for the data type in + asCObjectType *parentType = 0; + asSNameSpace *ns = GetNameSpaceFromNode(n, file, implicitNamespace, &n, &parentType); + if( ns == 0 && parentType == 0 ) { - // The namespace doesn't exist. Return a dummy type instead. + // The namespace and parent type doesn't exist. Return a dummy type instead. dt = asCDataType::CreatePrimitive(ttInt, false); + if (isValid) + *isValid = false; return dt; } @@ -5042,189 +5409,146 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod { bool found = false; - asCScriptNode *nameToken = n; asCString str; str.Assign(&file->code[n->tokenPos], n->tokenLength); // Recursively search parent namespaces for matching type asSNameSpace *origNs = ns; - while( ns && !found ) + asCObjectType *origParentType = parentType; + while( (ns || parentType) && !found ) { - asCObjectType *ot = 0; + asCTypeInfo *ti = 0; - // If this is for a template type, then we must first determine if the - // identifier matches any of the template subtypes - if( currentType && (currentType->flags & asOBJ_TEMPLATE) ) + if (currentType) { - for( asUINT subtypeIndex = 0; subtypeIndex < currentType->templateSubTypes.GetLength(); subtypeIndex++) + // If this is for a template type, then we must first determine if the + // identifier matches any of the template subtypes + if (currentType->flags & asOBJ_TEMPLATE) { - asCObjectType *type = currentType->templateSubTypes[subtypeIndex].GetObjectType(); - if( type && str == type->name ) + for (asUINT subtypeIndex = 0; subtypeIndex < currentType->templateSubTypes.GetLength(); subtypeIndex++) { - ot = type; - break; + asCTypeInfo *type = currentType->templateSubTypes[subtypeIndex].GetTypeInfo(); + if (type && str == type->name) + { + ti = type; + break; + } + } + } + + if (ti == 0) + { + // Check if the type is a child type of the current type + ti = GetFuncDef(str.AddressOf(), 0, currentType); + if (ti) + { + dt = asCDataType::CreateType(ti, false); + found = true; } } } - if( ot == 0 ) - ot = GetObjectType(str.AddressOf(), ns); - if( ot == 0 && !module && currentType ) - ot = GetObjectTypeFromTypesKnownByObject(str.AddressOf(), currentType); + if( ti == 0 ) + ti = GetType(str.AddressOf(), ns, parentType); + if( ti == 0 && !module && currentType ) + ti = GetTypeFromTypesKnownByObject(str.AddressOf(), currentType); - if( ot ) + if( ti && !found ) { found = true; - if( ot->flags & asOBJ_IMPLICIT_HANDLE ) + if( ti->flags & asOBJ_IMPLICIT_HANDLE ) isImplicitHandle = true; // Make sure the module has access to the object type - if( !module || (module->accessMask & ot->accessMask) ) + if( !module || (module->accessMask & ti->accessMask) ) { - if( asOBJ_TYPEDEF == (ot->flags & asOBJ_TYPEDEF) ) + if( asOBJ_TYPEDEF == (ti->flags & asOBJ_TYPEDEF) ) { // TODO: typedef: A typedef should be considered different from the original type (though with implicit conversions between the two) // Create primitive data type based on object flags - dt = ot->templateSubTypes[0]; + dt = CastToTypedefType(ti)->aliasForType; dt.MakeReadOnly(isConst); } else { - if( ot->flags & asOBJ_TEMPLATE ) + if( ti->flags & asOBJ_TEMPLATE ) { - // Check if the subtype is a type or the template's subtype - // if it is the template's subtype then this is the actual template type, - // orderwise it is a template instance. - // Only do this for application registered interface, as the - // scripts cannot implement templates. - asCArray subTypes; - asUINT subtypeIndex; - while( n && n->next && n->next->nodeType == snDataType ) + ti = GetTemplateInstanceFromNode(n, file, CastToObjectType(ti), implicitNamespace, currentType, &n); + if (ti == 0) { - n = n->next; - - // When parsing function definitions for template registrations (currentType != 0) it is necessary - // to pass in the current template type to the recursive call since it is this ones sub-template types - // that should be allowed. - asCDataType subType = CreateDataTypeFromNode(n, file, implicitNamespace, false, module ? 0 : (currentType ? currentType : ot)); - subTypes.PushLast(subType); - - if( subType.IsReadOnly() ) - { - asCString msg; - msg.Format(TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY); - WriteError(msg, file, n); - - // Return a dummy - return asCDataType::CreatePrimitive(ttInt, false); - } - } - - if( subTypes.GetLength() != ot->templateSubTypes.GetLength() ) - { - asCString msg; - msg.Format(TXT_TMPL_s_EXPECTS_d_SUBTYPES, ot->name.AddressOf(), int(ot->templateSubTypes.GetLength())); - WriteError(msg, file, nameToken); + if (isValid) + *isValid = false; // Return a dummy return asCDataType::CreatePrimitive(ttInt, false); } - - // Check if any of the given subtypes are different from the template's declared subtypes - bool isDifferent = false; - for( subtypeIndex = 0; subtypeIndex < subTypes.GetLength(); subtypeIndex++ ) - { - if( subTypes[subtypeIndex].GetObjectType() != ot->templateSubTypes[subtypeIndex].GetObjectType() ) - { - isDifferent = true; - break; - } - } - - if( isDifferent ) - { - // This is a template instance - // Need to find the correct object type - asCObjectType *otInstance = engine->GetTemplateInstanceType(ot, subTypes, module); - - if( otInstance && otInstance->scriptSectionIdx < 0 ) - { - // If this is the first time the template instance is used, store where it was declared from - otInstance->scriptSectionIdx = engine->GetScriptSectionNameIndex(file->name.AddressOf()); - int row, column; - file->ConvertPosToRowCol(n->tokenPos, &row, &column); - otInstance->declaredAt = (row&0xFFFFF)|(column<<20); - } - - if( !otInstance ) - { - asCString sub = subTypes[0].Format(ot->nameSpace); - for( asUINT s = 1; s < subTypes.GetLength(); s++ ) - { - sub += ","; - sub += subTypes[s].Format(ot->nameSpace); - } - asCString str; - str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf()); - WriteError(str, file, n); - } - - ot = otInstance; - } } else if( n && n->next && n->next->nodeType == snDataType ) { - asCString str; - str.Format(TXT_TYPE_s_NOT_TEMPLATE, ot->name.AddressOf()); - WriteError(str, file, n); + if (reportError) + { + asCString msg; + msg.Format(TXT_TYPE_s_NOT_TEMPLATE, ti->name.AddressOf()); + WriteError(msg, file, n); + } + if (isValid) + *isValid = false; } // Create object data type - if( ot ) - dt = asCDataType::CreateObject(ot, isConst); + if( ti ) + dt = asCDataType::CreateType(ti, isConst); else dt = asCDataType::CreatePrimitive(ttInt, isConst); } } else { - asCString msg; - msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf()); - WriteError(msg, file, n); + if (reportError) + { + asCString msg; + msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf()); + WriteError(msg, file, n); + } dt.SetTokenType(ttInt); - } - } - else if( ot == 0 ) - { - // It can still be a function definition - asCScriptFunction *funcdef = GetFuncDef(str.AddressOf()); - - if( funcdef ) - { - dt = asCDataType::CreateFuncDef(funcdef); - found = true; + if (isValid) + *isValid = false; } } if( !found ) { // Try to find it in the parent namespace - ns = engine->GetParentNameSpace(ns); + if( ns ) + ns = engine->GetParentNameSpace(ns); + if (parentType) + parentType = 0; } } if( !found ) { - asCString msg; - if( origNs->name == "" ) - msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, str.AddressOf()); - else - msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), origNs->name.AddressOf()); - WriteError(msg, file, n); + if (reportError) + { + asCString msg; + if (origNs && origNs->name == "") + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, str.AddressOf()); + else if (origNs) + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), origNs->name.AddressOf()); + else + { + // TODO: child funcdef: Message should explain that the identifier is not a type of the parent type + asCDataType pt = asCDataType::CreateType(origParentType, false); + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), pt.Format(origParentType->nameSpace, false).AddressOf()); + } + WriteError(msg, file, n); + } dt = asCDataType::CreatePrimitive(ttInt, isConst); + if (isValid) + *isValid = false; return dt; } } @@ -5247,22 +5571,30 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod // Make sure the sub type can be instantiated if( !dt.CanBeInstantiated() ) { - asCString str; - if( dt.IsAbstractClass() ) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); - else if( dt.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(ns).AddressOf()); + if (reportError) + { + asCString str; + if (dt.IsAbstractClass()) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); + else if (dt.IsInterface()) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(ns).AddressOf()); - WriteError(str, file, n); + WriteError(str, file, n); + } + if (isValid) + *isValid = false; } // Make the type an array (or multidimensional array) if( dt.MakeArray(engine, module) < 0 ) { - WriteError(TXT_NO_DEFAULT_ARRAY_TYPE, file, n); + if( reportError ) + WriteError(TXT_NO_DEFAULT_ARRAY_TYPE, file, n); + if (isValid) + *isValid = false; break; } } @@ -5271,12 +5603,18 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod // Make the type a handle if( dt.IsObjectHandle() ) { - WriteError(TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED, file, n); + if( reportError ) + WriteError(TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED, file, n); + if (isValid) + *isValid = false; break; } else if( dt.MakeHandle(true, acceptHandleForScope) < 0 ) { - WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if( reportError ) + WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if (isValid) + *isValid = false; break; } } @@ -5286,13 +5624,107 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod if( isImplicitHandle ) { // Make the type a handle - if( dt.MakeHandle(true, acceptHandleForScope) < 0 ) - WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if (dt.MakeHandle(true, acceptHandleForScope) < 0) + { + if( reportError ) + WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if (isValid) + *isValid = false; + } } return dt; } +asCObjectType *asCBuilder::GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next) +{ + // Check if the subtype is a type or the template's subtype + // if it is the template's subtype then this is the actual template type, + // orderwise it is a template instance. + // Only do this for application registered interface, as the + // scripts cannot implement templates. + asCArray subTypes; + asUINT subtypeIndex; + asCScriptNode *n = node; + while (n && n->next && n->next->nodeType == snDataType) + { + n = n->next; + + // When parsing function definitions for template registrations (currentType != 0) it is necessary + // to pass in the current template type to the recursive call since it is this ones sub-template types + // that should be allowed. + asCDataType subType = CreateDataTypeFromNode(n, file, implicitNamespace, false, module ? 0 : (currentType ? currentType : templateType)); + subTypes.PushLast(subType); + + if (subType.IsReadOnly()) + { + asCString msg; + msg.Format(TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY); + WriteError(msg, file, n); + + // Return a dummy + return 0; + } + } + + if (next) + *next = n; + + if (subTypes.GetLength() != templateType->templateSubTypes.GetLength()) + { + asCString msg; + msg.Format(TXT_TMPL_s_EXPECTS_d_SUBTYPES, templateType->name.AddressOf(), int(templateType->templateSubTypes.GetLength())); + WriteError(msg, file, node); + + // Return a dummy + return 0; + } + + // Check if any of the given subtypes are different from the template's declared subtypes + bool isDifferent = false; + for (subtypeIndex = 0; subtypeIndex < subTypes.GetLength(); subtypeIndex++) + { + if (subTypes[subtypeIndex].GetTypeInfo() != templateType->templateSubTypes[subtypeIndex].GetTypeInfo()) + { + isDifferent = true; + break; + } + } + + if (isDifferent) + { + // This is a template instance + // Need to find the correct object type + asCObjectType *otInstance = engine->GetTemplateInstanceType(templateType, subTypes, module); + + if (otInstance && otInstance->scriptSectionIdx < 0) + { + // If this is the first time the template instance is used, store where it was declared from + otInstance->scriptSectionIdx = engine->GetScriptSectionNameIndex(file->name.AddressOf()); + int row, column; + file->ConvertPosToRowCol(n->tokenPos, &row, &column); + otInstance->declaredAt = (row & 0xFFFFF) | (column << 20); + } + + if (!otInstance) + { + asCString sub = subTypes[0].Format(templateType->nameSpace); + for (asUINT s = 1; s < subTypes.GetLength(); s++) + { + sub += ","; + sub += subTypes[s].Format(templateType->nameSpace); + } + asCString msg; + msg.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, templateType->name.AddressOf(), sub.AddressOf()); + WriteError(msg, file, n); + } + + return otInstance; + } + + return templateType; +} + asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlags, bool *autoHandle) { asCDataType dt = type; @@ -5303,6 +5735,14 @@ asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScrip asCScriptNode *n = node->firstChild; if( n && n->tokenType == ttAmp ) { + if (dt.GetTokenType() == ttVoid) + { + asCString msg; + msg.Format(TXT_TYPE_s_CANNOT_BE_REFERENCE, type.Format(0).AddressOf()); + WriteError(msg, file, node->firstChild); + return dt; + } + dt.MakeReference(true); n = n->next; @@ -5332,7 +5772,7 @@ asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScrip inOutFlags && *inOutFlags == asTM_INOUTREF ) { // Verify that the base type support &inout parameter types - if( !dt.IsObject() || dt.IsObjectHandle() || !((dt.GetObjectType()->flags & asOBJ_NOCOUNT) || (dt.GetObjectType()->beh.addref && dt.GetObjectType()->beh.release)) ) + if( !dt.IsObject() || dt.IsObjectHandle() || !((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || (CastToObjectType(dt.GetTypeInfo())->beh.addref && CastToObjectType(dt.GetTypeInfo())->beh.release)) ) WriteError(TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, file, node->firstChild); } } @@ -5342,24 +5782,65 @@ asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScrip if( n && n->tokenType == ttPlus ) { // Autohandles are not supported for types with NOCOUNT - // If the type is not a handle then there was an error with building the type, but + // If the type is not a handle then there was an error with building the type, but // this error would already have been reported so no need to report another error here - if( dt.IsObjectHandle() && (dt.GetObjectType()->flags & asOBJ_NOCOUNT) ) + if( dt.IsObjectHandle() && (dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) ) WriteError(TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT, file, node->firstChild); if( autoHandle ) *autoHandle = true; } + if (n && n->tokenType == ttIdentifier) + { + asCString str; + str.Assign(&file->code[n->tokenPos], n->tokenLength); + if (str == IF_HANDLE_TOKEN) + dt.SetIfHandleThenConst(true); + else + { + // TODO: Should give error if not currently parsing template registration + asCString msg; + msg.Format(TXT_UNEXPECTED_TOKEN_s, str.AddressOf()); + WriteError(msg, file, node->firstChild); + } + } + return dt; } +asCTypeInfo *asCBuilder::GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType) +{ + asASSERT((ns == 0 && parentType) || (ns && parentType == 0)); + + if (ns) + { + asCTypeInfo *ti = engine->GetRegisteredType(type, ns); + if (!ti && module) + ti = module->GetType(type, ns); + return ti; + } + else + { + // Recursively check base classes + asCObjectType *currType = parentType; + while (currType) + { + for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = currType->childFuncDefs[n]; + if (funcDef && funcDef->name == type) + return funcDef; + } + currType = currType->derivedFrom; + } + } + + return 0; +} + asCObjectType *asCBuilder::GetObjectType(const char *type, asSNameSpace *ns) { - asCObjectType *ot = engine->GetRegisteredObjectType(type, ns); - if( !ot && module ) - ot = module->GetObjectType(type, ns); - - return ot; + return CastToObjectType(GetType(type, ns, 0)); } #ifndef AS_NO_COMPILER @@ -5378,8 +5859,8 @@ bool asCBuilder::DoesTypeExist(const asCString &type) // Only do this once hasCachedKnownTypes = true; - // Add registered object types - asSMapNode *cursor; + // Add registered types + asSMapNode *cursor; engine->allRegisteredTypes.MoveFirst(&cursor); while( cursor ) { @@ -5389,31 +5870,26 @@ bool asCBuilder::DoesTypeExist(const asCString &type) engine->allRegisteredTypes.MoveNext(&cursor, cursor); } - // Add registered funcdefs - for( n = 0; n < engine->registeredFuncDefs.GetLength(); n++ ) - if( !knownTypes.MoveTo(0, engine->registeredFuncDefs[n]->name) ) - knownTypes.Insert(engine->registeredFuncDefs[n]->name, true); - - if( module ) + if (module) { // Add script classes and interfaces - for( n = 0; n < module->classTypes.GetLength(); n++ ) - if( !knownTypes.MoveTo(0, module->classTypes[n]->name) ) + for (n = 0; n < module->classTypes.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->classTypes[n]->name)) knownTypes.Insert(module->classTypes[n]->name, true); // Add script enums - for( n = 0; n < module->enumTypes.GetLength(); n++ ) - if( !knownTypes.MoveTo(0, module->enumTypes[n]->name) ) + for (n = 0; n < module->enumTypes.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->enumTypes[n]->name)) knownTypes.Insert(module->enumTypes[n]->name, true); // Add script typedefs - for( n = 0; n < module->typeDefs.GetLength(); n++ ) - if( !knownTypes.MoveTo(0, module->typeDefs[n]->name) ) + for (n = 0; n < module->typeDefs.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->typeDefs[n]->name)) knownTypes.Insert(module->typeDefs[n]->name, true); // Add script funcdefs - for( n = 0; n < module->funcDefs.GetLength(); n++ ) - if( !knownTypes.MoveTo(0, module->funcDefs[n]->name) ) + for (n = 0; n < module->funcDefs.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->funcDefs[n]->name)) knownTypes.Insert(module->funcDefs[n]->name, true); } } @@ -5423,56 +5899,82 @@ bool asCBuilder::DoesTypeExist(const asCString &type) } #endif -asCObjectType *asCBuilder::GetObjectTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType) +asCTypeInfo *asCBuilder::GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType) { - if( currentType->name == type ) + if (currentType->name == type) return currentType; asUINT n; - asCObjectType *found = 0; + asCTypeInfo *found = 0; - for( n = 0; found == 0 && n < currentType->properties.GetLength(); n++ ) - if( currentType->properties[n]->type.GetObjectType() && - currentType->properties[n]->type.GetObjectType()->name == type ) - found = currentType->properties[n]->type.GetObjectType(); + for (n = 0; found == 0 && n < currentType->properties.GetLength(); n++) + if (currentType->properties[n]->type.GetTypeInfo() && + currentType->properties[n]->type.GetTypeInfo()->name == type) + found = currentType->properties[n]->type.GetTypeInfo(); - for( n = 0; found == 0 && n < currentType->methods.GetLength(); n++ ) + for (n = 0; found == 0 && n < currentType->methods.GetLength(); n++) { asCScriptFunction *func = engine->scriptFunctions[currentType->methods[n]]; - if( func->returnType.GetObjectType() && - func->returnType.GetObjectType()->name == type ) - found = func->returnType.GetObjectType(); - - for( asUINT f = 0; found == 0 && f < func->parameterTypes.GetLength(); f++ ) - if( func->parameterTypes[f].GetObjectType() && - func->parameterTypes[f].GetObjectType()->name == type ) - found = func->parameterTypes[f].GetObjectType(); + if (func->returnType.GetTypeInfo() && + func->returnType.GetTypeInfo()->name == type) + found = func->returnType.GetTypeInfo(); + + for (asUINT f = 0; found == 0 && f < func->parameterTypes.GetLength(); f++) + if (func->parameterTypes[f].GetTypeInfo() && + func->parameterTypes[f].GetTypeInfo()->name == type) + found = func->parameterTypes[f].GetTypeInfo(); } - if( found ) + if (found) { // In case we find a template instance it mustn't be returned // because it is not known if the subtype is really matching - if( found->flags & asOBJ_TEMPLATE ) + if (found->flags & asOBJ_TEMPLATE) return 0; } return found; } -asCScriptFunction *asCBuilder::GetFuncDef(const char *type) +asCFuncdefType *asCBuilder::GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType) { - for( asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++ ) - // TODO: access: Only return the definitions that the module has access to - if( engine->registeredFuncDefs[n]->name == type ) - return engine->registeredFuncDefs[n]; + asASSERT((ns == 0 && parentType) || (ns && parentType == 0)); - if( module ) + if (ns) { - for( asUINT n = 0; n < module->funcDefs.GetLength(); n++ ) - if( module->funcDefs[n]->name == type ) - return module->funcDefs[n]; + for (asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = engine->registeredFuncDefs[n]; + // TODO: access: Only return the definitions that the module has access to + if (funcDef && funcDef->nameSpace == ns && funcDef->name == type) + return funcDef; + } + + if (module) + { + for (asUINT n = 0; n < module->funcDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = module->funcDefs[n]; + if (funcDef && funcDef->nameSpace == ns && funcDef->name == type) + return funcDef; + } + } + } + else + { + // Recursively check base classes + asCObjectType *currType = parentType; + while (currType) + { + for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = currType->childFuncDefs[n]; + if (funcDef && funcDef->name == type) + return funcDef; + } + currType = currType->derivedFrom; + } } return 0; @@ -5480,17 +5982,17 @@ asCScriptFunction *asCBuilder::GetFuncDef(const char *type) #ifndef AS_NO_COMPILER -int asCBuilder::GetEnumValueFromObjectType(asCObjectType *objType, const char *name, asCDataType &outDt, asDWORD &outValue) +int asCBuilder::GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue) { - if( !objType || !(objType->flags & asOBJ_ENUM) ) + if( !type || !(type->flags & asOBJ_ENUM) ) return 0; - for( asUINT n = 0; n < objType->enumValues.GetLength(); ++n ) + for( asUINT n = 0; n < type->enumValues.GetLength(); ++n ) { - if( objType->enumValues[n]->name == name ) + if( type->enumValues[n]->name == name ) { - outDt = asCDataType::CreateObject(objType, true); - outValue = objType->enumValues[n]->value; + outDt = asCDataType::CreateType(type, true); + outValue = type->enumValues[n]->value; return 1; } } @@ -5506,14 +6008,14 @@ int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outV asUINT t; for( t = 0; t < engine->registeredEnums.GetLength(); t++ ) { - asCObjectType *ot = engine->registeredEnums[t]; - if( ns != ot->nameSpace ) continue; + asCEnumType *et = engine->registeredEnums[t]; + if( ns != et->nameSpace ) continue; // Don't bother with types the module doesn't have access to - if( (ot->accessMask & module->accessMask) == 0 ) + if( (et->accessMask & module->accessMask) == 0 ) continue; - if( GetEnumValueFromObjectType(ot, name, outDt, outValue) ) + if( GetEnumValueFromType(et, name, outDt, outValue) ) { if( !found ) found = true; @@ -5527,10 +6029,10 @@ int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outV for( t = 0; t < module->enumTypes.GetLength(); t++ ) { - asCObjectType *ot = module->enumTypes[t]; - if( ns != ot->nameSpace ) continue; + asCEnumType *et = module->enumTypes[t]; + if( ns != et->nameSpace ) continue; - if( GetEnumValueFromObjectType(ot, name, outDt, outValue) ) + if( GetEnumValueFromType(et, name, outDt, outValue) ) { if( !found ) found = true; diff --git a/lib/angelscript/source/as_builder.h b/lib/angelscript/source/as_builder.h index 11c9ed917..988273123 100644 --- a/lib/angelscript/source/as_builder.h +++ b/lib/angelscript/source/as_builder.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -99,13 +99,13 @@ struct sPropertyInitializer struct sClassDeclaration { - sClassDeclaration() {script = 0; node = 0; validState = 0; objType = 0; isExistingShared = false; isFinal = false;} + sClassDeclaration() {script = 0; node = 0; validState = 0; typeInfo = 0; isExistingShared = false; isFinal = false;} asCScriptCode *script; asCScriptNode *node; asCString name; int validState; - asCObjectType *objType; + asCTypeInfo *typeInfo; bool isExistingShared; bool isFinal; @@ -140,10 +140,10 @@ public: int VerifyProperty(asCDataType *dt, const char *decl, asCString &outName, asCDataType &outType, asSNameSpace *ns); int ParseDataType(const char *datatype, asCDataType *result, asSNameSpace *implicitNamespace, bool isReturnType = false); int ParseTemplateDecl(const char *decl, asCString *name, asCArray &subtypeNames); - int ParseFunctionDeclaration(asCObjectType *type, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles = 0, bool *returnAutoHandle = 0, asSNameSpace *ns = 0, asCScriptNode **listPattern = 0); + int ParseFunctionDeclaration(asCObjectType *type, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles = 0, bool *returnAutoHandle = 0, asSNameSpace *ns = 0, asCScriptNode **outListPattern = 0, asCObjectType **outParentClass = 0); int ParseVariableDeclaration(const char *decl, asSNameSpace *implicitNamespace, asCString &outName, asSNameSpace *&outNamespace, asCDataType &outDt); int CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns); - int CheckNameConflictMember(asCObjectType *type, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty); + int CheckNameConflictMember(asCTypeInfo *type, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty); #ifndef AS_NO_COMPILER int AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy); @@ -173,14 +173,16 @@ protected: int ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func); asCString GetCleanExpressionString(asCScriptNode *n, asCScriptCode *file); - asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next); - asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, bool isRequired = true); + asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next, asCObjectType **objType = 0); + asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType = 0, bool isRequired = true); asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0); + asCTypeInfo *GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType); asCObjectType *GetObjectType(const char *type, asSNameSpace *ns); - asCScriptFunction *GetFuncDef(const char *type); - asCObjectType *GetObjectTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType); - asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0); + asCFuncdefType *GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType); + asCTypeInfo *GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType); + asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0, bool reportError = true, bool *isValid = 0); + asCObjectType *GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next = 0); asCDataType ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlag, bool *autoHandle); int numErrors; @@ -204,7 +206,7 @@ protected: void AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScriptNode *errNode, sMixinClass *mixin); int RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false, bool isMixin = false); - int RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isProtected, bool isOverride, bool isFinal, bool isShared); + int RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits funcTraits); int RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false); int RegisterImportedFunction(int funcID, asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); int RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); @@ -212,12 +214,13 @@ protected: int RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); int RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); - int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent); asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns); void CompleteFuncDef(sFuncDef *funcDef); void CompileInterfaces(); void CompileClasses(asUINT originalNumTempl); - void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, bool &isConstMethod, bool &isConstructor, bool &isDestructor, bool &isPrivate, bool &isProtected, bool &isOverride, bool &isFinal, bool &isShared, asSNameSpace *implicitNamespace); + void DetermineTypeRelations(); + void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits &traits, asSNameSpace *implicitNamespace); bool DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex = 0); void AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file); asCObjectProperty *AddPropertyToClass(sClassDeclaration *c, const asCString &name, const asCDataType &type, bool isPrivate, bool isProtected, bool isInherited, asCScriptCode *file = 0, asCScriptNode *node = 0); @@ -227,7 +230,7 @@ protected: void RegisterNonTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns); void CompileFunctions(); void CompileGlobalVariables(); - int GetEnumValueFromObjectType(asCObjectType *objType, const char *name, asCDataType &outDt, asDWORD &outValue); + int GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue); int GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue, asSNameSpace *ns); bool DoesTypeExist(const asCString &type); asCObjectProperty *GetObjectProperty(asCDataType &obj, const char *prop); diff --git a/lib/angelscript/source/as_bytecode.cpp b/lib/angelscript/source/as_bytecode.cpp index b0777d4f8..d16dbc201 100644 --- a/lib/angelscript/source/as_bytecode.cpp +++ b/lib/angelscript/source/as_bytecode.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -1045,7 +1045,7 @@ void asCByteCode::OptimizeLocally(const asCArray &tempVariableOffsets) short tempVar = last->wArg[0]; asCArray freedVars; - asCByteInstruction *instr = last->prev; + instr = last->prev; asASSERT( instr && instr->op == asBC_Block ); instr = instr->prev; while( instr && instr->op == asBC_FREE ) @@ -1164,6 +1164,12 @@ void asCByteCode::Optimize() DeleteInstruction(instr); instr = GoBack(DeleteInstruction(curr)); } + // LINE, VarDecl, LINE -> VarDecl, LINE + else if (instrOp == asBC_VarDecl && instr->next && instr->next->op == asBC_LINE ) + { + // Delete the first instruction + instr = GoBack(DeleteInstruction(curr)); + } // LINE, LINE -> LINE else if( instrOp == asBC_LINE ) { @@ -1390,6 +1396,7 @@ bool asCByteCode::IsTempRegUsed(asCByteInstruction *curr) curr->op == asBC_PopRPtr || curr->op == asBC_CALLSYS || curr->op == asBC_CALLBND || + curr->op == asBC_Thiscall1 || curr->op == asBC_SUSPEND || curr->op == asBC_ALLOC || curr->op == asBC_CpyVtoR4 || @@ -1444,7 +1451,8 @@ bool asCByteCode::IsSimpleExpression() instr->op == asBC_FREE || instr->op == asBC_CallPtr || instr->op == asBC_CALLINTF || - instr->op == asBC_CALLBND ) + instr->op == asBC_CALLBND || + instr->op == asBC_Thiscall1 ) return false; instr = instr->next; @@ -1536,7 +1544,7 @@ void asCByteCode::ExtractObjectVariableInfo(asCScriptFunction *outFunc) asSObjectVariableInfo info; info.programPos = pos; info.variableOffset = (short)instr->wArg[0]; - info.option = *(int*)ARG_DW(instr->arg); + info.option = (asEObjVarInfoOption)*(int*)ARG_DW(instr->arg); outFunc->scriptData->objVariableInfo.PushLast(info); } else if( instr->op == asBC_VarDecl ) @@ -2064,18 +2072,23 @@ void asCByteCode::PostProcess() } #ifdef AS_DEBUG -void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScriptFunction *func) +void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func) { _mkdir("AS_DEBUG"); - asCString str = "AS_DEBUG/"; - str += name; + asCString path = "AS_DEBUG/"; + path += name; + + // Anonymous functions created from within class methods will contain :: as part of the name + // Replace :: with __ to avoid error when creating the file for debug output + for (asUINT n = 0; n < path.GetLength(); n++) + if (path[n] == ':') path[n] = '_'; #if _MSC_VER >= 1500 && !defined(AS_MARMALADE) FILE *file; - fopen_s(&file, str.AddressOf(), "w"); + fopen_s(&file, path.AddressOf(), "w"); #else - FILE *file = fopen(str.AddressOf(), "w"); + FILE *file = fopen(path.AddressOf(), "w"); #endif #if !defined(AS_XENON) // XBox 360: When running in DVD Emu, no write is allowed @@ -2186,14 +2199,7 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri switch( asBCInfo[instr->op].type ) { case asBCTYPE_W_ARG: - if( instr->op == asBC_STR ) - { - int id = asWORD(instr->wArg[0]); - const asCString &str = engine->GetConstantString(id); - fprintf(file, " %-8s %d (l:%ld s:\"%.10s\")\n", asBCInfo[instr->op].name, asWORD(instr->wArg[0]), (long int)str.GetLength(), str.AddressOf()); - } - else - fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, instr->wArg[0]); + fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, instr->wArg[0]); break; case asBCTYPE_wW_ARG: @@ -2237,8 +2243,8 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri case asBC_FuncPtr: { - asCScriptFunction *func = *(asCScriptFunction**)ARG_DW(instr->arg); - fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), func->GetDeclaration()); + asCScriptFunction *f = *(asCScriptFunction**)ARG_DW(instr->arg); + fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), f->GetDeclaration()); } break; @@ -2298,8 +2304,8 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri case asBC_FuncPtr: { - asCScriptFunction *func = *(asCScriptFunction**)ARG_QW(instr->arg); - fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), func->GetDeclaration()); + asCScriptFunction *f = *(asCScriptFunction**)ARG_QW(instr->arg); + fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), f->GetDeclaration()); } break; @@ -2345,8 +2351,8 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri if( instr->op == asBC_ALLOC ) { asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg); - asCScriptFunction *func = engine->scriptFunctions[instr->wArg[0]]; - fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), func ? func->GetDeclaration() : "{no func}"); + asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]]; + fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); } else fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1)); @@ -2360,19 +2366,19 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri if( instr->op == asBC_ALLOC ) { asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); - asCScriptFunction *func = engine->scriptFunctions[instr->wArg[0]]; -#ifdef __GNUC__ + asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]]; +#if defined(__GNUC__) && !defined(_MSC_VER) #ifdef AS_64BIT_PTR - fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}"); + fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); #else - fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}"); + fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); #endif #else - fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}"); + fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); #endif } else -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(_MSC_VER) #ifdef AS_64BIT_PTR fprintf(file, " %-8s %lu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2)); #else diff --git a/lib/angelscript/source/as_bytecode.h b/lib/angelscript/source/as_bytecode.h index b1bb1127b..1c1067d7d 100644 --- a/lib/angelscript/source/as_bytecode.h +++ b/lib/angelscript/source/as_bytecode.h @@ -83,7 +83,7 @@ public: void PostProcess(); #ifdef AS_DEBUG - void DebugOutput(const char *name, asCScriptEngine *engine, asCScriptFunction *func); + void DebugOutput(const char *name, asCScriptFunction *func); #endif int GetLastInstr(); diff --git a/lib/angelscript/source/as_callfunc.cpp b/lib/angelscript/source/as_callfunc.cpp index 81095ab8b..00d04a9c1 100644 --- a/lib/angelscript/source/as_callfunc.cpp +++ b/lib/angelscript/source/as_callfunc.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -53,12 +53,12 @@ BEGIN_AS_NAMESPACE // describes the structure for class method pointers on Itanium and arm64 ABI // http://clang.llvm.org/doxygen/CodeGen_2ItaniumCXXABI_8cpp_source.html#l00937 -int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal) +int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal) { memset(internal, 0, sizeof(asSSystemFunctionInterface)); - internal->func = ptr.ptr.f.func; - internal->objForThiscall = 0; + internal->func = ptr.ptr.f.func; + internal->auxiliary = 0; // Was a compatible calling convention specified? if( internal->func ) @@ -80,21 +80,26 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, internal->callConv = ICC_STDCALL; else if( base == asCALL_THISCALL_ASGLOBAL ) { - if( objForThiscall == 0 ) + if(auxiliary == 0) return asINVALID_ARG; - internal->objForThiscall = objForThiscall; - internal->callConv = ICC_THISCALL; + internal->auxiliary = auxiliary; + internal->callConv = ICC_THISCALL; // This is really a thiscall, so it is necessary to check for virtual method pointers base = asCALL_THISCALL; isMethod = true; } - else if( base == asCALL_GENERIC ) + else if (base == asCALL_GENERIC) + { internal->callConv = ICC_GENERIC_FUNC; + + // The auxiliary object is optional for generic calling convention + internal->auxiliary = auxiliary; + } else return asNOT_SUPPORTED; } - + if( isMethod ) { #ifndef AS_NO_CLASS_METHODS @@ -103,7 +108,7 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, internalCallConv thisCallConv; if( base == asCALL_THISCALL ) { - if( callConv != asCALL_THISCALL_ASGLOBAL && objForThiscall ) + if(callConv != asCALL_THISCALL_ASGLOBAL && auxiliary) return asINVALID_ARG; thisCallConv = ICC_THISCALL; @@ -113,10 +118,10 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, #ifdef AS_NO_THISCALL_FUNCTOR_METHOD return asNOT_SUPPORTED; #else - if( objForThiscall == 0 ) + if(auxiliary == 0) return asINVALID_ARG; - internal->objForThiscall = objForThiscall; + internal->auxiliary = auxiliary; if( base == asCALL_THISCALL_OBJFIRST ) thisCallConv = ICC_THISCALL_OBJFIRST; else //if( base == asCALL_THISCALL_OBJLAST ) @@ -151,8 +156,11 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, internal->callConv = ICC_CDECL_OBJLAST; else if( base == asCALL_CDECL_OBJFIRST ) internal->callConv = ICC_CDECL_OBJFIRST; - else if( base == asCALL_GENERIC ) + else if (base == asCALL_GENERIC) + { internal->callConv = ICC_GENERIC_METHOD; + internal->auxiliary = auxiliary; + } else return asNOT_SUPPORTED; } @@ -161,7 +169,7 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, } // This function should prepare system functions so that it will be faster to call them -int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine * /*engine*/) +int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine) { asASSERT(internal->callConv == ICC_GENERIC_METHOD || internal->callConv == ICC_GENERIC_FUNC); @@ -175,17 +183,25 @@ int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInter { asCDataType &dt = func->parameterTypes[n]; - if( dt.IsObject() && !dt.IsReference() ) + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() ) { - asSTypeBehaviour *beh = &dt.GetObjectType()->beh; - if( dt.GetObjectType()->flags & asOBJ_REF ) + if (dt.IsFuncdef()) { - asASSERT( (dt.GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release ); + asSSystemFunctionInterface::SClean clean; + clean.op = 0; // call release + clean.ot = &engine->functionBehaviours; + clean.off = short(offset); + internal->cleanArgs.PushLast(clean); + } + else if( dt.GetTypeInfo()->flags & asOBJ_REF ) + { + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; + asASSERT( (dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); if( beh->release ) { asSSystemFunctionInterface::SClean clean; clean.op = 0; // call release - clean.ot = dt.GetObjectType(); + clean.ot = CastToObjectType(dt.GetTypeInfo()); clean.off = short(offset); internal->cleanArgs.PushLast(clean); } @@ -194,10 +210,11 @@ int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInter { asSSystemFunctionInterface::SClean clean; clean.op = 1; // call free - clean.ot = dt.GetObjectType(); + clean.ot = CastToObjectType(dt.GetTypeInfo()); clean.off = short(offset); // Call the destructor then free the memory + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; if( beh->destruct ) clean.op = 2; // call destruct, then free @@ -222,7 +239,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i UNUSED_VAR(internal); UNUSED_VAR(engine); - // This should never happen, as when AS_MAX_PORTABILITY is on, all functions + // This should never happen, as when AS_MAX_PORTABILITY is on, all functions // are asCALL_GENERIC, which are prepared by PrepareSystemFunctionGeneric asASSERT(false); #else @@ -236,8 +253,8 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i // Registered types have special flags that determine how they are returned else if( func->returnType.IsObject() ) { - asDWORD objType = func->returnType.GetObjectType()->flags; - + asDWORD objType = func->returnType.GetTypeInfo()->flags; + // Only value types can be returned by value asASSERT( objType & asOBJ_VALUE ); @@ -247,7 +264,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); asCString str; - str.Format(TXT_CANNOT_RET_TYPE_s_BY_VAL, func->returnType.GetObjectType()->name.AddressOf()); + str.Format(TXT_CANNOT_RET_TYPE_s_BY_VAL, func->returnType.GetTypeInfo()->name.AddressOf()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); } @@ -282,7 +299,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i internal->hostReturnInMemory = false; internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords(); #ifdef SPLIT_OBJS_BY_MEMBER_TYPES - if( func->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS ) + if( func->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) internal->hostReturnFloat = true; #endif } @@ -329,7 +346,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i // Ref: http://www.agner.org/optimize/calling_conventions.pdf // If the application informs that the class should be treated as all integers, then we allow it if( !internal->hostReturnInMemory && - !(func->returnType.GetObjectType()->flags & (asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) ) + !(func->returnType.GetTypeInfo()->flags & (asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) ) { engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); @@ -405,12 +422,12 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i internal->takesObjByVal = true; // Can't pass objects by value unless the application type is informed - if( !(func->parameterTypes[n].GetObjectType()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) ) + if( !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) ) { engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); - + asCString str; - str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetObjectType()->name.AddressOf()); + str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); } @@ -421,19 +438,19 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i // will be used depending on the memory layout of the object // Ref: http://www.x86-64.org/documentation/abi.pdf // Ref: http://www.agner.org/optimize/calling_conventions.pdf - if( + if( #ifdef COMPLEX_OBJS_PASSED_BY_REF - !(func->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) && + !(func->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) && #endif #ifdef LARGE_OBJS_PASS_BY_REF func->parameterTypes[n].GetSizeInMemoryDWords() < AS_LARGE_OBJ_MIN_SIZE && #endif - !(func->parameterTypes[n].GetObjectType()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) ) + !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) ) { engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); asCString str; - str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetObjectType()->name.AddressOf()); + str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); } @@ -452,24 +469,24 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i #if defined(COMPLEX_OBJS_PASSED_BY_REF) || defined(AS_LARGE_OBJS_PASSED_BY_REF) bool needFree = false; #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( dt.GetObjectType() && dt.GetObjectType()->flags & COMPLEX_MASK ) needFree = true; + if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & COMPLEX_MASK ) needFree = true; #endif #ifdef AS_LARGE_OBJS_PASSED_BY_REF if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ) needFree = true; #endif if( needFree && dt.IsObject() && - !dt.IsObjectHandle() && + !dt.IsObjectHandle() && !dt.IsReference() ) { asSSystemFunctionInterface::SClean clean; clean.op = 1; // call free - clean.ot = dt.GetObjectType(); + clean.ot = CastToObjectType(dt.GetTypeInfo()); clean.off = short(offset); #ifndef AS_CALLEE_DESTROY_OBJ_BY_VAL // If the called function doesn't destroy objects passed by value we must do so here - asSTypeBehaviour *beh = &dt.GetObjectType()->beh; + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; if( beh->destruct ) clean.op = 2; // call destruct, then free #endif @@ -482,7 +499,10 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i { asSSystemFunctionInterface::SClean clean; clean.op = 0; // call release - clean.ot = dt.GetObjectType(); + if (dt.IsFuncdef()) + clean.ot = &engine->functionBehaviours; + else + clean.ot = CastToObjectType(dt.GetTypeInfo()); clean.off = short(offset); internal->cleanArgs.PushLast(clean); } @@ -533,7 +553,7 @@ int CallSystemFunction(int id, asCContext *context) // // Return value: // -// The function should return the value that is returned in registers. +// The function should return the value that is returned in registers. asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObj); @@ -553,16 +573,22 @@ int CallSystemFunction(int id, asCContext *context) void *retPointer = 0; int popSize = sysFunc->paramSize; + // TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers + // objForThiscall is the object pointer that should be used for the thiscall + // objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST + + // Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST + void *obj = 0; + void *secondObj = 0; + #ifdef AS_NO_THISCALL_FUNCTOR_METHOD - void *obj = 0; - void *secondObj = 0; if( callConv >= ICC_THISCALL ) { - if( sysFunc->objForThiscall ) + if(sysFunc->auxiliary) { // This class method is being called as if it is a global function - obj = sysFunc->objForThiscall; + obj = sysFunc->auxiliary; } else { @@ -593,13 +619,6 @@ int CallSystemFunction(int id, asCContext *context) } } #else - // TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers - // objForThiscall is the object pointer that should be used for the thiscall - // objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST - - // Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST - void *obj = 0; - void *secondObj = 0; if( callConv >= ICC_THISCALL ) { @@ -608,15 +627,15 @@ int CallSystemFunction(int id, asCContext *context) if( callConv >= ICC_THISCALL_OBJLAST ) { - asASSERT( sysFunc->objForThiscall != 0 ); - // This class method is being called as object method (sysFunc->objForThiscall must be set). - obj = sysFunc->objForThiscall; + asASSERT( sysFunc->auxiliary != 0 ); + // This class method is being called as object method (sysFunc->auxiliary must be set). + obj = sysFunc->auxiliary; continueCheckIndex = 1; } - else if( sysFunc->objForThiscall ) + else if(sysFunc->auxiliary) { // This class method is being called as if it is a global function - obj = sysFunc->objForThiscall; + obj = sysFunc->auxiliary; continueCheck = false; } @@ -667,14 +686,21 @@ int CallSystemFunction(int id, asCContext *context) popSize += AS_PTR_SIZE; args += AS_PTR_SIZE; - // When returning the value on the location allocated by the called + // When returning the value on the location allocated by the called // we shouldn't set the object type in the register context->m_regs.objectType = 0; } else { // Set the object type of the reference held in the register - context->m_regs.objectType = descr->returnType.GetObjectType(); + context->m_regs.objectType = descr->returnType.GetTypeInfo(); + } + + // For composition we need to add the offset and/or dereference the pointer + if(obj) + { + obj = (void*) ((char*) obj + sysFunc->compositeOffset); + if(sysFunc->isCompositeIndirect) obj = *((void**)obj); } context->m_callingSystemFunction = descr; @@ -682,10 +708,10 @@ int CallSystemFunction(int id, asCContext *context) #ifdef AS_NO_EXCEPTIONS retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj); #else - // This try/catch block is to catch potential exception that may + // This try/catch block is to catch potential exception that may // be thrown by the registered function. The implementation of the // CallSystemFunctionNative() must make sure not to have any manual - // clean-up after the call to the real function, or that won't be + // clean-up after the call to the real function, or that won't be // executed in case of an exception. try { @@ -695,7 +721,7 @@ int CallSystemFunction(int id, asCContext *context) { cppException = true; - // Convert the exception to a script exception so the VM can + // Convert the exception to a script exception so the VM can // properly report the error to the application and then clean up context->SetException(TXT_EXCEPTION_CAUGHT); } @@ -703,7 +729,7 @@ int CallSystemFunction(int id, asCContext *context) context->m_callingSystemFunction = 0; // Store the returned value in our stack - if( descr->returnType.IsObject() && !descr->returnType.IsReference() ) + if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() ) { if( descr->returnType.IsObjectHandle() ) { @@ -717,8 +743,8 @@ int CallSystemFunction(int id, asCContext *context) if( sysFunc->returnAutoHandle && context->m_regs.objectRegister ) { - asASSERT( !(descr->returnType.GetObjectType()->flags & asOBJ_NOCOUNT) ); - engine->CallObjectMethod(context->m_regs.objectRegister, descr->returnType.GetObjectType()->beh.addref); + asASSERT( !(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ); + engine->CallObjectMethod(context->m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref); } } else @@ -754,12 +780,12 @@ int CallSystemFunction(int id, asCContext *context) if( context->m_status == asEXECUTION_EXCEPTION && !cppException ) { - // If the function raised a script exception it really shouldn't have - // initialized the object. However, as it is a soft exception there is + // If the function raised a script exception it really shouldn't have + // initialized the object. However, as it is a soft exception there is // no way for the application to not return a value, so instead we simply // destroy it here, to pretend it was never created. - if( descr->returnType.GetObjectType()->beh.destruct ) - engine->CallObjectMethod(retPointer, descr->returnType.GetObjectType()->beh.destruct); + if(CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct ) + engine->CallObjectMethod(retPointer, CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct); } } } @@ -833,7 +859,7 @@ int CallSystemFunction(int id, asCContext *context) // Skip the object pointer on the stack // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction - if( callConv >= ICC_THISCALL && sysFunc->objForThiscall == 0 ) + if( callConv >= ICC_THISCALL && sysFunc->auxiliary == 0 ) args += AS_PTR_SIZE; asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf(); @@ -848,14 +874,14 @@ int CallSystemFunction(int id, asCContext *context) *addr = 0; } } - else + else { asASSERT( clean->op == 1 || clean->op == 2 ); asASSERT( *addr ); if( clean->op == 2 ) engine->CallObjectMethod(*addr, clean->ot->beh.destruct); - + engine->CallFree(*addr); } } diff --git a/lib/angelscript/source/as_callfunc.h b/lib/angelscript/source/as_callfunc.h index dde7f72d7..c77a4d708 100644 --- a/lib/angelscript/source/as_callfunc.h +++ b/lib/angelscript/source/as_callfunc.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -49,7 +49,7 @@ class asCScriptFunction; class asCObjectType; struct asSSystemFunctionInterface; -int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal); +int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal); int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine); @@ -59,7 +59,7 @@ int CallSystemFunction(int id, asCContext *context); inline asPWORD FuncPtrToUInt(asFUNCTION_t func) { - // A little trickery as the C++ standard doesn't allow direct + // A little trickery as the C++ standard doesn't allow direct // conversion between function pointer and data pointer union { asFUNCTION_t func; asPWORD idx; } u; u.func = func; @@ -108,7 +108,9 @@ struct asSSystemFunctionInterface bool takesObjByVal; asCArray paramAutoHandles; // TODO: Should be able to remove this array. Perhaps the flags can be stored together with the inOutFlags in asCScriptFunction? bool returnAutoHandle; - void *objForThiscall; + int compositeOffset; + bool isCompositeIndirect; + void *auxiliary; // can be used for functors, e.g. by asCALL_THISCALL_ASGLOBAL or asCALL_THISCALL_OBJFIRST struct SClean { @@ -118,7 +120,7 @@ struct asSSystemFunctionInterface }; asCArray cleanArgs; - asSSystemFunctionInterface() {} + asSSystemFunctionInterface() : func(0), baseOffset(0), callConv(ICC_GENERIC_FUNC), scriptReturnSize(0), hostReturnInMemory(false), hostReturnFloat(false), hostReturnSize(0), paramSize(0), takesObjByVal(false), returnAutoHandle(false), compositeOffset(0), isCompositeIndirect(false), auxiliary(0) {} asSSystemFunctionInterface(const asSSystemFunctionInterface &in) { @@ -127,19 +129,21 @@ struct asSSystemFunctionInterface asSSystemFunctionInterface &operator=(const asSSystemFunctionInterface &in) { - func = in.func; - baseOffset = in.baseOffset; - callConv = in.callConv; - scriptReturnSize = in.scriptReturnSize; - hostReturnInMemory = in.hostReturnInMemory; - hostReturnFloat = in.hostReturnFloat; - hostReturnSize = in.hostReturnSize; - paramSize = in.paramSize; - takesObjByVal = in.takesObjByVal; - paramAutoHandles = in.paramAutoHandles; - returnAutoHandle = in.returnAutoHandle; - objForThiscall = in.objForThiscall; - cleanArgs = in.cleanArgs; + func = in.func; + baseOffset = in.baseOffset; + callConv = in.callConv; + scriptReturnSize = in.scriptReturnSize; + hostReturnInMemory = in.hostReturnInMemory; + hostReturnFloat = in.hostReturnFloat; + hostReturnSize = in.hostReturnSize; + paramSize = in.paramSize; + takesObjByVal = in.takesObjByVal; + paramAutoHandles = in.paramAutoHandles; + returnAutoHandle = in.returnAutoHandle; + compositeOffset = in.compositeOffset; + isCompositeIndirect = in.isCompositeIndirect; + auxiliary = in.auxiliary; + cleanArgs = in.cleanArgs; return *this; } }; diff --git a/lib/angelscript/source/as_callfunc_arm.cpp b/lib/angelscript/source/as_callfunc_arm.cpp index a5d20355e..6d820702f 100644 --- a/lib/angelscript/source/as_callfunc_arm.cpp +++ b/lib/angelscript/source/as_callfunc_arm.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -150,7 +150,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) { paramBuffer[dpos++] = args[spos++]; paramSize++; @@ -159,7 +159,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, #endif { #if defined(AS_ANDROID) || defined(AS_LINUX) - if( (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) && + if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && ((dpos & 1) == mask) ) { // 64 bit value align @@ -337,8 +337,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, if( sysFunc->hostReturnInMemory ) { // TODO: runtime optimize: This check should be done in PrepareSystemFunction - if ( !( descr->returnType.GetObjectType()->flags & COMPLEX_RETURN_MASK ) && - ( descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS ) && + if ( !( descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK ) && + ( descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) && descr->returnType.GetSizeInMemoryBytes() <= 8 ) callConv--; @@ -396,10 +396,10 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, { // TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() && - !(descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_ARRAY) ) + !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) ) { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) { paramBuffer[dpos++] = args[spos++]; paramSize++; @@ -407,7 +407,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, else #endif { - if( (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) ) + if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) ) { if ( (dpos & 1) == mask ) { @@ -425,7 +425,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, } // Copy the object's memory to the buffer - if (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS) + if (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) { int target = (freeFloatSlot > freeDoubleSlot) ? freeFloatSlot : freeDoubleSlot; @@ -645,8 +645,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, // TODO: runtime optimize: This should be identified with a flag determined in PrepareSystemFunction if ( !descr->returnType.IsObjectHandle() && !descr->returnType.IsReference() && - !(descr->returnType.GetObjectType()->flags & COMPLEX_RETURN_MASK) && - (descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS) ) + !(descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK) && + (descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) ) memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() ); } diff --git a/lib/angelscript/source/as_callfunc_arm_gcc.S b/lib/angelscript/source/as_callfunc_arm_gcc.S index 3ce5566a4..a311ee773 100644 --- a/lib/angelscript/source/as_callfunc_arm_gcc.S +++ b/lib/angelscript/source/as_callfunc_arm_gcc.S @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -717,13 +717,14 @@ nomoreargsarmFuncR0R1: #endif /* hard float abi */ +#endif /* arm */ + #if defined(__linux__) && defined(__ELF__) -/* ref: http://hardened.gentoo.org/gnu-stack.xml */ +/* ref: http://hardened.gentoo.org/gnu-stack.xml + ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */ .section .note.GNU-stack,"",%progbits #endif -#endif /* arm */ - #endif /* !AS_MAX_PORTABILITY */ diff --git a/lib/angelscript/source/as_callfunc_mips.cpp b/lib/angelscript/source/as_callfunc_mips.cpp index 0b2e3b4fc..be7d18952 100644 --- a/lib/angelscript/source/as_callfunc_mips.cpp +++ b/lib/angelscript/source/as_callfunc_mips.cpp @@ -135,7 +135,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, asCDataType ¶mType = descr->parameterTypes[n]; if( paramType.IsObject() && !paramType.IsObjectHandle() && !paramType.IsReference() ) { - if( paramType.GetObjectType()->flags & COMPLEX_MASK ) + if( paramType.GetTypeInfo()->flags & COMPLEX_MASK ) { // The object is passed by reference argBuffer[argOffset++] = args[spos++]; @@ -143,7 +143,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, else { // Ensure 8byte alignment for classes that need it - if( (paramType.GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) ) + if( (paramType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) ) argOffset++; // Copy the object's memory to the buffer @@ -557,7 +557,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) { paramBuffer[dpos++] = args[spos++]; paramSize++; diff --git a/lib/angelscript/source/as_callfunc_ppc.cpp b/lib/angelscript/source/as_callfunc_ppc.cpp index 32a73f8f8..053221fe9 100644 --- a/lib/angelscript/source/as_callfunc_ppc.cpp +++ b/lib/angelscript/source/as_callfunc_ppc.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -576,7 +576,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) { argsType[a++] = ppcINTARG; paramBuffer[dpos++] = args[spos++]; diff --git a/lib/angelscript/source/as_callfunc_ppc_64.cpp b/lib/angelscript/source/as_callfunc_ppc_64.cpp index a2c62f2b9..275f6152b 100644 --- a/lib/angelscript/source/as_callfunc_ppc_64.cpp +++ b/lib/angelscript/source/as_callfunc_ppc_64.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -41,6 +41,10 @@ #ifndef AS_MAX_PORTABILITY #ifdef AS_PPC_64 +#if AS_PTR_SIZE == 2 +// TODO: Add support for PPC 64bit platforms with 64bit pointers, for example Linux PPC64 (big endian) and PPC64 (little endian) +#error This code has not been prepared for PPC with 64bit pointers. Most likely the ABI is different +#else #include "as_callfunc.h" #include "as_scriptengine.h" @@ -666,10 +670,10 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) { if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() && - !(descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_ARRAY) ) + !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) ) { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) { paramBuffer[dpos++] = args[spos++]; ++paramSize; @@ -763,6 +767,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, END_AS_NAMESPACE +#endif // AS_PTR_SIZE == 2 #endif // AS_PPC_64 #endif // AS_MAX_PORTABILITY diff --git a/lib/angelscript/source/as_callfunc_sh4.cpp b/lib/angelscript/source/as_callfunc_sh4.cpp index 2fb4ff68f..b24be9a54 100644 --- a/lib/angelscript/source/as_callfunc_sh4.cpp +++ b/lib/angelscript/source/as_callfunc_sh4.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -313,7 +313,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) { paramBuffer[dpos++] = args[spos++]; paramSize++; diff --git a/lib/angelscript/source/as_callfunc_x64_gcc.cpp b/lib/angelscript/source/as_callfunc_x64_gcc.cpp index e05ae986f..ad6c27fb6 100644 --- a/lib/angelscript/source/as_callfunc_x64_gcc.cpp +++ b/lib/angelscript/source/as_callfunc_x64_gcc.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -157,7 +157,7 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i " movq %%rdx, %4 \n" "endcall: \n" - : : "r" ((asQWORD)cnt), "r" (args), "r" (func), "m" (retQW1), "m" (retQW2), "m" (returnFloat) + : : "g" ((asQWORD)cnt), "g" (args), "g" (func), "m" (retQW1), "m" (retQW2), "m" (returnFloat) : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%rdi", "%rsi", "%rax", "%rdx", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r15"); @@ -345,7 +345,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, else { // An object is being passed by value - if( (parmType.GetObjectType()->flags & COMPLEX_MASK) || + if( (parmType.GetTypeInfo()->flags & COMPLEX_MASK) || parmType.GetSizeInMemoryDWords() > 4 ) { // Copy the address of the object @@ -353,8 +353,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asQWORD)); argIndex++; } - else if( (parmType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLINTS) || - (parmType.GetObjectType()->flags & asOBJ_APP_PRIMITIVE) ) + else if( (parmType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLINTS) || + (parmType.GetTypeInfo()->flags & asOBJ_APP_PRIMITIVE) ) { // Copy the value of the object if( parmType.GetSizeInMemoryDWords() > 2 ) @@ -373,8 +373,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, // Delete the original memory engine->CallFree(*(void**)stack_pointer); } - else if( (parmType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS) || - (parmType.GetObjectType()->flags & asOBJ_APP_FLOAT) ) + else if( (parmType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) || + (parmType.GetTypeInfo()->flags & asOBJ_APP_FLOAT) ) { // Copy the value of the object if( parmType.GetSizeInMemoryDWords() > 2 ) diff --git a/lib/angelscript/source/as_callfunc_x64_mingw.cpp b/lib/angelscript/source/as_callfunc_x64_mingw.cpp index 35e775fe9..1c5bdb552 100644 --- a/lib/angelscript/source/as_callfunc_x64_mingw.cpp +++ b/lib/angelscript/source/as_callfunc_x64_mingw.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -248,7 +248,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) { if( descr->parameterTypes[n].GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE || - (descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) ) + (descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) ) { allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; spos += AS_PTR_SIZE; diff --git a/lib/angelscript/source/as_callfunc_x64_msvc.cpp b/lib/angelscript/source/as_callfunc_x64_msvc.cpp index 84b96c2dd..8af5adc01 100644 --- a/lib/angelscript/source/as_callfunc_x64_msvc.cpp +++ b/lib/angelscript/source/as_callfunc_x64_msvc.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -119,7 +119,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) { if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE || - (dt.GetObjectType()->flags & COMPLEX_MASK) ) + (dt.GetTypeInfo()->flags & COMPLEX_MASK) ) { allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; spos += AS_PTR_SIZE; diff --git a/lib/angelscript/source/as_callfunc_x86.cpp b/lib/angelscript/source/as_callfunc_x86.cpp index d6f50db81..0ac690ed7 100644 --- a/lib/angelscript/source/as_callfunc_x86.cpp +++ b/lib/angelscript/source/as_callfunc_x86.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -126,7 +126,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) { paramBuffer[dpos++] = args[spos++]; paramSize++; @@ -340,6 +340,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)}; asm __volatile__( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -374,7 +385,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" @@ -444,6 +462,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -479,7 +508,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" @@ -549,6 +585,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -584,7 +631,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" @@ -663,6 +717,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -702,7 +767,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" @@ -777,6 +849,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -813,7 +896,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" @@ -890,6 +980,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -929,7 +1030,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" @@ -994,6 +1102,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)}; asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -1026,7 +1145,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" @@ -1107,6 +1233,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -1148,7 +1285,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" @@ -1236,6 +1380,17 @@ endcopy: volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif _S(CLEAR_FPU_STACK) "\n" "pushl %%ebx \n" "movl %%edx, %%ebx \n" @@ -1290,7 +1445,14 @@ endcopy: // Pop the alignment bytes "popl %%esp \n" "popl %%ebx \n" - +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif // Copy EAX:EDX to retQW. As the stack pointer has been // restored it is now safe to access the local variable "leal %1, %%ecx \n" diff --git a/lib/angelscript/source/as_callfunc_xenon.cpp b/lib/angelscript/source/as_callfunc_xenon.cpp index aaa4d8586..c52055e99 100644 --- a/lib/angelscript/source/as_callfunc_xenon.cpp +++ b/lib/angelscript/source/as_callfunc_xenon.cpp @@ -552,7 +552,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, !descr->parameterTypes[n].IsReference() ) { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) { paramBuffer[dpos++] = args[spos++]; paramSize++; diff --git a/lib/angelscript/source/as_compiler.cpp b/lib/angelscript/source/as_compiler.cpp index 337e209df..e0f487c73 100644 --- a/lib/angelscript/source/as_compiler.cpp +++ b/lib/angelscript/source/as_compiler.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -64,7 +64,7 @@ BEGIN_AS_NAMESPACE -// TODO: I must correct the interpretation of a references to objects in the compiler. +// TODO: I must correct the interpretation of a reference to objects in the compiler. // A reference should mean that a pointer to the object is on the stack. // No expression should end up as non-references to objects, as the actual object is // never put on the stack. @@ -96,14 +96,20 @@ asCCompiler::~asCCompiler() asDELETE(var,asCVariableScope); } + + // Clean up all the string constants that were allocated. By now the script + // functions that were compiled successfully already holds their own references + for (asUINT n = 0; n < usedStringConstants.GetLength(); n++) + engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]); + usedStringConstants.SetLength(0); } -void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc) +void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc) { - this->builder = builder; - this->engine = builder->engine; - this->script = script; - this->outFunc = outFunc; + this->builder = in_builder; + this->engine = in_builder->engine; + this->script = in_script; + this->outFunc = in_outFunc; hasCompileErrors = false; @@ -121,11 +127,11 @@ void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFun byteCode.ClearAll(); } -int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl) +int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl) { - Reset(builder, script, outFunc); + Reset(in_builder, in_script, in_outFunc); - m_classDecl = classDecl; + m_classDecl = in_classDecl; // Insert a JitEntry at the start of the function for JIT compilers byteCode.InstrPTR(asBC_JitEntry, 0); @@ -144,7 +150,7 @@ int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *s { // Make sure the base class really has a default constructor if( outFunc->objectType->derivedFrom->beh.construct == 0 ) - Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, node); + Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node); // Call the base class' default constructor byteCode.InstrSHORT(asBC_PSF, 0); @@ -172,21 +178,21 @@ int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *s #ifdef AS_DEBUG // DEBUG: output byte code - byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), engine, outFunc); + byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc); #endif return 0; } -int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc) +int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc) { - Reset(builder, script, outFunc); + Reset(in_builder, in_script, in_outFunc); // Insert a JitEntry at the start of the function for JIT compilers byteCode.InstrPTR(asBC_JitEntry, 0); // Find the corresponding constructor - asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false); + asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false); int constructor = 0; for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ ) { @@ -230,7 +236,7 @@ int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCS } int argDwords = (int)outFunc->GetSpaceNeededForArguments(); - byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE); + byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE); // Return a handle to the newly created object byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset); @@ -269,12 +275,11 @@ void asCCompiler::FinalizeFunction() // Start with the variables allocated on the heap, and then the ones allocated on the stack for( n = 0; n < variableAllocations.GetLength(); n++ ) { - if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() ) + if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() ) { if( variableIsOnHeap[n] ) { - outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType()); - outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef()); + outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo()); outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n)); } } @@ -282,12 +287,11 @@ void asCCompiler::FinalizeFunction() outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength()); for( n = 0; n < variableAllocations.GetLength(); n++ ) { - if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() ) + if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() ) { if( !variableIsOnHeap[n] ) { - outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType()); - outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef()); + outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo()); outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n)); } } @@ -413,7 +417,7 @@ int asCCompiler::SetupParametersAndReturnVariable(asCArray ¶meter return stackPos; } -void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDefaults) +void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults) { asASSERT( m_classDecl ); @@ -477,11 +481,11 @@ void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDe // here we should just validate that the member has a default constructor if( prop->type.IsObject() && !prop->type.IsObjectHandle() && - (((prop->type.GetObjectType()->flags & asOBJ_REF) && + (((prop->type.GetTypeInfo()->flags & asOBJ_REF) && prop->type.GetBehaviour()->factory == 0) || - ((prop->type.GetObjectType()->flags & asOBJ_VALUE) && + ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && prop->type.GetBehaviour()->construct == 0 && - !(prop->type.GetObjectType()->flags & asOBJ_POD))) ) + !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) ) { // Class has no default factory/constructor. asCString str; @@ -489,7 +493,7 @@ void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDe if( prop->type.GetFuncDef() ) str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName()); else - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetObjectType()->GetName()); + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName()); Error(str, declNode); } #else @@ -499,14 +503,14 @@ void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDe script = initScript; // Add a line instruction with the position of the declaration - LineInstr(byteCode, declNode->tokenPos); + LineInstr(bc, declNode->tokenPos); // Compile the initialization asQWORD constantValue; - asCByteCode bc(engine); - CompileInitialization(initNode, &bc, prop->type, declNode, prop->byteOffset, &constantValue, 2); - bc.OptimizeLocally(tempVariableOffsets); - byteCode->AddCode(&bc); + asCByteCode bcInit(engine); + CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2); + bcInit.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&bcInit); script = origScript; #endif @@ -515,30 +519,30 @@ void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDe } // Entry -int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray ¶meterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl) +int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl) { TimeIt("asCCompiler::CompileFunction"); - Reset(builder, script, outFunc); + Reset(in_builder, in_script, in_outFunc); int buildErrors = builder->numErrors; - int stackPos = SetupParametersAndReturnVariable(parameterNames, func); + int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func); //-------------------------------------------- // Compile the statement block if( m_isConstructor ) - m_classDecl = classDecl; + m_classDecl = in_classDecl; // We need to parse the statement block now asCScriptNode *blockBegin; // If the function signature was implicit, e.g. virtual property accessor or // lambda function, then the received node already is the statement block - if( func->nodeType != snStatementBlock ) - blockBegin = func->lastChild; + if( in_func->nodeType != snStatementBlock ) + blockBegin = in_func->lastChild; else - blockBegin = func; + blockBegin = in_func; // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory // TODO: optimize: For large functions, the parsing of the statement block can take a long time. Presumably because a lot of memory needs to be allocated @@ -656,7 +660,7 @@ int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asC // Check if the number of labels in the functions isn't too many to be handled if( nextLabel >= (1<<15) ) - Error(TXT_TOO_MANY_JUMP_LABELS, func); + Error(TXT_TOO_MANY_JUMP_LABELS, in_func); // If there are compile errors, there is no reason to build the final code if( hasCompileErrors || builder->numErrors != buildErrors ) @@ -675,15 +679,15 @@ int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asC #ifdef AS_DEBUG // DEBUG: output byte code if( outFunc->objectType ) - byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc); + byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc); else - byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc); + byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc); #endif return 0; } -int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest) +int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest) { if( !type.IsObject() ) return 0; @@ -691,20 +695,20 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec // CallCopyConstructor should not be called for object handles. asASSERT( !type.IsObjectHandle() ); - asCArray args; + asCArray args; args.PushLast(arg); // The reference parameter must be pushed on the stack - asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() ); + asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() ); // Since we're calling the copy constructor, we have to trust the function to not do // anything stupid otherwise we will just enter a loop, as we try to make temporary // copies of the argument in order to guarantee safety. - if( type.GetObjectType()->flags & asOBJ_REF ) + if( type.GetTypeInfo()->flags & asOBJ_REF ) { - asSExprContext ctx(engine); + asCExprContext ctx(engine); int func = 0; asSTypeBehaviour *beh = type.GetBehaviour(); @@ -715,7 +719,7 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec if( !isGlobalVar ) { // Call factory and store the handle in the given variable - PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset); + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset); // Pop the reference left by the function call ctx.bc.Instr(asBC_PopPtr); @@ -723,12 +727,12 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec else { // Call factory - PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType()); + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo())); // Store the returned handle in the global variable ctx.bc.Instr(asBC_RDSPtr); ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); - ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType()); + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); ctx.bc.Instr(asBC_PopPtr); ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); } @@ -769,8 +773,8 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec } } - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType()); + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo())); bc->AddCode(&ctx.bc); @@ -786,7 +790,7 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec // Class has no copy constructor/factory. asCString str; - str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName()); + str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName()); Error(str, node); return -1; @@ -797,9 +801,9 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo if( !type.IsObject() || type.IsObjectHandle() ) return 0; - if( type.GetObjectType()->flags & asOBJ_REF ) + if( type.GetTypeInfo()->flags & asOBJ_REF ) { - asSExprContext ctx(engine); + asCExprContext ctx(engine); ctx.exprNode = node; int func = 0; @@ -826,12 +830,12 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo if( func > 0 ) { - asCArray args; + asCArray args; asCScriptFunction *f = engine->scriptFunctions[func]; if( f->parameterTypes.GetLength() ) { // Add the default values for arguments not explicitly supplied - CompileDefaultAndNamedArgs(node, args, func, type.GetObjectType()); + CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo())); PrepareFunctionCall(func, &ctx.bc, args); @@ -841,7 +845,7 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo if( isVarGlobOrMem == 0 ) { // Call factory and store the handle in the given variable - PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset); + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset); // Pop the reference left by the function call ctx.bc.Instr(asBC_PopPtr); @@ -849,13 +853,13 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo else { // Call factory - PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType()); + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo())); // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination // instead of first storing it in a local variable and then copying it to the // destination. - if( !(type.GetObjectType()->flags & asOBJ_SCOPED) ) + if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) ) { // Only dereference the variable if not a scoped type ctx.bc.Instr(asBC_RDSPtr); @@ -871,10 +875,10 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo // Store the returned handle in the class member ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } - if( type.GetObjectType()->flags & asOBJ_SCOPED ) + if( type.GetTypeInfo()->flags & asOBJ_SCOPED ) { // For scoped typed we must move the reference from the local // variable rather than copy it as there is no AddRef behaviour @@ -885,7 +889,10 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo } else { - ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType()); + if( type.IsFuncdef() ) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); } ctx.bc.Instr(asBC_PopPtr); ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); @@ -897,7 +904,7 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo for( asUINT n = 0; n < args.GetLength(); n++ ) if( args[n] ) { - asDELETE(args[n],asSExprContext); + asDELETE(args[n], asCExprContext); } return 0; @@ -905,7 +912,7 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo } else { - asSExprContext ctx(engine); + asCExprContext ctx(engine); ctx.exprNode = node; asSTypeBehaviour *beh = type.GetBehaviour(); @@ -932,14 +939,14 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo } // Allocate and initialize with the default constructor - if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) ) + if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) ) { - asCArray args; + asCArray args; asCScriptFunction *f = engine->scriptFunctions[func]; if( f && f->parameterTypes.GetLength() ) { // Add the default values for arguments not explicitly supplied - CompileDefaultAndNamedArgs(node, args, func, type.GetObjectType()); + CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo())); PrepareFunctionCall(func, &ctx.bc, args); @@ -959,9 +966,9 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo if( derefDest ) bc->Instr(asBC_RDSPtr); - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType()); - bc->AddCode(&ctx.bc); + asCExprContext ctxCall(engine); + PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo())); + bc->AddCode(&ctxCall.bc); // TODO: value on stack: This probably needs to be done in PerformFunctionCall // Mark the object as initialized @@ -971,18 +978,18 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo else if( isVarGlobOrMem == 2 ) { // Only POD types can be allocated inline in script classes - asASSERT( type.GetObjectType()->flags & asOBJ_POD ); + asASSERT( type.GetTypeInfo()->flags & asOBJ_POD ); if( func ) { // Call the constructor as a normal function bc->InstrSHORT(asBC_PSF, 0); bc->Instr(asBC_RDSPtr); - bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType()); - bc->AddCode(&ctx.bc); + asCExprContext ctxCall(engine); + PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo())); + bc->AddCode(&ctxCall.bc); } } else @@ -1000,10 +1007,10 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo { bc->InstrSHORT(asBC_PSF, 0); bc->Instr(asBC_RDSPtr); - bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } - if( (type.GetObjectType()->flags & asOBJ_TEMPLATE) ) + if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) { asCScriptFunction *descr = engine->scriptFunctions[func]; asASSERT( descr->funcType == asFUNC_SCRIPT ); @@ -1023,18 +1030,18 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo asASSERT( id ); - bc->InstrPTR(asBC_OBJTYPE, type.GetObjectType()); - bc->Alloc(asBC_ALLOC, type.GetObjectType(), id, AS_PTR_SIZE + AS_PTR_SIZE); + bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo()); + bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE); } else - bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE); + bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE); } // Cleanup for( asUINT n = 0; n < args.GetLength(); n++ ) if( args[n] ) { - asDELETE(args[n],asSExprContext); + asDELETE(args[n], asCExprContext); } return 0; @@ -1043,11 +1050,7 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo // Class has no default factory/constructor. asCString str; - // TODO: funcdef: asCDataType should have a GetTypeName() - if( type.GetFuncDef() ) - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName()); - else - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName()); + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName()); Error(str, node); return -1; @@ -1058,29 +1061,32 @@ void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnH if( !type.IsReference() ) { // Call destructor for the data type - if( type.IsObject() ) + if( type.IsObject() || type.IsFuncdef() ) { // The null pointer doesn't need to be destroyed if( type.IsNullHandle() ) return; // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method - if( type.GetObjectType()->flags & asOBJ_LIST_PATTERN ) + if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN ) return; if( isObjectOnHeap || type.IsObjectHandle() ) { // Free the memory - bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType()); + if (type.IsFuncdef()) + bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours); + else + bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo()); } else { - asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE ); + asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE ); if( type.GetBehaviour()->destruct ) { // Call the destructor as a regular function - asSExprContext ctx(engine); + asCExprContext ctx(engine); ctx.bc.InstrSHORT(asBC_PSF, (short)offset); PerformFunctionCall(type.GetBehaviour()->destruct, &ctx); ctx.bc.OptimizeLocally(tempVariableOffsets); @@ -1187,47 +1193,56 @@ void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableSc } // Entry -int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc) +int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc) { - Reset(builder, script, outFunc); - m_globalVar = gvar; + Reset(in_builder, in_script, in_outFunc); + m_globalVar = in_gvar; // Add a variable scope (even though variables can't be declared) AddVariableScope(); - gvar->isPureConstant = false; + in_gvar->isPureConstant = false; // Parse the initialization nodes asCParser parser(builder); - if( node ) + if (in_node) { - int r = parser.ParseVarInit(script, node); - if( r < 0 ) + int r = parser.ParseVarInit(in_script, in_node); + if (r < 0) return r; - node = parser.GetScriptNode(); + in_node = parser.GetScriptNode(); } - asSExprContext compiledCtx(engine); + asCExprContext compiledCtx(engine); bool preCompiled = false; - if( gvar->datatype.IsAuto() ) - preCompiled = CompileAutoType(gvar->datatype, compiledCtx, node, gvar->declaredAtNode); - if( gvar->property == 0 ) + if (in_gvar->datatype.IsAuto()) { - gvar->property = builder->module->AllocateGlobalProperty(gvar->name.AddressOf(), gvar->datatype, gvar->ns); - gvar->index = gvar->property->id; + preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode); + if (!preCompiled) + { + // If it wasn't possible to determine the type from the expression then there + // is no need to continue with the initialization. The error was already reported + // in CompileAutoType. + return -1; + } + } + if( in_gvar->property == 0 ) + { + in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns); + in_gvar->index = in_gvar->property->id; } // Compile the expression - asSExprContext ctx(engine); + asCExprContext ctx(engine); asQWORD constantValue = 0; - if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->declaredAtNode, gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) ) + if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) ) { // Should the variable be marked as pure constant? - if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() ) + if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() ) { - gvar->isPureConstant = true; - gvar->constantValue = constantValue; + in_gvar->isPureConstant = true; + in_gvar->constantValue = constantValue; } } @@ -1236,10 +1251,10 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip // Add information on the line number for the global variable size_t pos = 0; - if( gvar->declaredAtNode ) - pos = gvar->declaredAtNode->tokenPos; - else if( gvar->initializationNode ) - pos = gvar->initializationNode->tokenPos; + if( in_gvar->declaredAtNode ) + pos = in_gvar->declaredAtNode->tokenPos; + else if( in_gvar->initializationNode ) + pos = in_gvar->initializationNode->tokenPos; LineInstr(&byteCode, pos); // Reserve space for all local variables @@ -1274,13 +1289,13 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip #ifdef AS_DEBUG // DEBUG: output byte code - byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc); + byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc); #endif return 0; } -void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node) +void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node) { // Don't do anything if this is not a deferred global function if( !ctx->IsGlobalFunc() ) @@ -1336,20 +1351,18 @@ void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node) // Push the function pointer on the stack ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0])); - ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0]))); + ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false)); ctx->type.dataType.MakeHandle(true); ctx->type.isExplicitHandle = true; ctx->methodName = ""; } -void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination) +void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination) { - asASSERT( dt.GetObjectType() ); - bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset); // Use copy constructor if available. - if( dt.GetObjectType()->beh.copyconstruct ) + if(CastToObjectType(dt.GetTypeInfo()) && CastToObjectType(dt.GetTypeInfo())->beh.copyconstruct ) { PrepareForAssignment(&dt, arg, node, true); int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination); @@ -1380,7 +1393,7 @@ void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc // Call the opAssign method to assign the value to the temporary object dt.MakeReference(isObjectOnHeap); - asCTypeInfo type; + asCExprValue type; type.Set(dt); type.isTemporary = true; type.stackOffset = (short)offset; @@ -1401,7 +1414,7 @@ void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc } // Pop the reference that was pushed on the stack if the result is an object - if( type.dataType.IsObject() ) + if( type.dataType.IsObject() || type.dataType.IsFuncdef() ) bc->Instr(asBC_PopPtr); // If the assignment operator returned an object by value it will @@ -1414,7 +1427,7 @@ void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc } } -int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy) +int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy) { asCDataType param = *paramType; if( paramType->GetTokenType() == ttQuestion ) @@ -1433,7 +1446,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as // If value assign is disabled for reference types, then make // sure to always pass the handle to ? parameters if( builder->engine->ep.disallowValueAssignForRefType && - ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) ) + ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) ) { param.MakeHandle(true); } @@ -1454,7 +1467,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as dt.MakeReadOnly(false); int offset; - if( refType == 1 ) // &in + if( refType == asTM_INREF ) { ProcessPropertyGetAccessor(ctx, node); @@ -1511,6 +1524,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as ctx->bc.InstrWORD(asBC_PSF, (short)offset); ctx->type.SetVariable(dt, offset, true); + ctx->type.isExplicitHandle = true; } else { @@ -1540,12 +1554,14 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as // the function as it is, since the local variable will stay alive, and since it // is temporary there is no side effect if the function modifies it. - // If the parameter is read-only and therefor guaranteed not to be modified by the + // If the parameter is read-only and therefore guaranteed not to be modified by the // function, then it is enough that the variable is local to guarantee the lifetime. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) ) { - if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) ) + if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) ) { + // Funcdefs only need an extra handle to guarantee the lifetime. + // If the object is a reference type (except scoped reference types), and the // parameter is a const reference, then it is not necessary to make a copy of the // object. The compiler just needs to hold a handle to guarantee the lifetime. @@ -1557,17 +1573,26 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as // Copy the handle Dereference(ctx, true); ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType()); + if (ctx->type.dataType.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); ctx->bc.Instr(asBC_PopPtr); ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); // The type should be set to the param type instead of dt to guarantee // that the expression keeps the correct type for variable ? args. Otherwise // MoveArgsToStack will use the wrong bytecode to move the arg to the stack + bool isExplicitHandle = ctx->type.isExplicitHandle; ctx->type.SetVariable(param, offset, true); + ctx->type.dataType.MakeHandle(true); + ctx->type.isExplicitHandle = isExplicitHandle; } else { + // Make a copy of the object to guarantee that the original isn't modified + asASSERT(!dt.IsFuncdef()); + // Allocate and initialize a temporary local object offset = AllocateVariableNotIn(dt, true, false, ctx); CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false); @@ -1588,18 +1613,49 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as ctx->type.dataType.MakeReadOnly(true); } } + + // When calling a function expecting a var arg with a parameter received as reference to handle + // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will + // not be able to do the correct double dereference to put the reference to the object on the stack. + if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable) + { + sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset); + if (var && var->type.IsReference() && var->type.IsObjectHandle()) + { + // Copy the handle to local variable + + // Allocate a handle variable + dt.MakeHandle(true); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Copy the handle + Dereference(ctx, true); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + if (ctx->type.dataType.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + // The type should be set to the param type instead of dt to guarantee + // that the expression keeps the correct type for variable ? args. Otherwise + // MoveArgsToStack will use the wrong bytecode to move the arg to the stack + ctx->type.SetVariable(param, offset, true); + } + } } else { // We must guarantee that the address to the value is on the stack - if( ctx->type.dataType.IsObject() && + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() ) Dereference(ctx, true); } } } - else if( refType == 2 ) // &out + else if( refType == asTM_OUTREF ) { // Add the type id as hidden arg if the parameter is a ? type if( paramType->GetTokenType() == ttQuestion ) @@ -1624,6 +1680,11 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as } else { + // Null handles and void expressions must be marked as explicit + // handles for correct treatement in MoveArgsToStack + if (dt.IsNullHandle()) + ctx->type.isExplicitHandle = true; + // Make sure the variable is not used in the expression offset = AllocateVariableNotIn(dt, true, false, ctx); @@ -1634,9 +1695,6 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as } else { - // TODO: Need to reserve variables, as the default constructor may need - // to allocate temporary variables to compute default args - // Allocate and construct the temporary object asCByteCode tmpBC(engine); CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node); @@ -1645,16 +1703,17 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as tmpBC.AddCode(&ctx->bc); ctx->bc.AddCode(&tmpBC); - dt.MakeReference(!dt.IsObject() || dt.IsObjectHandle()); - asCTypeInfo type; + dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle()); + asCExprValue type; type.Set(dt); type.isTemporary = true; type.stackOffset = (short)offset; + type.isExplicitHandle = ctx->type.isExplicitHandle; ctx->type = type; ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - if( dt.IsObject() && !dt.IsObjectHandle() ) + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() ) ctx->bc.Instr(asBC_RDSPtr); } @@ -1680,7 +1739,9 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as } // Literal constants cannot be passed to inout ref arguments - if( !ctx->type.isVariable && ctx->type.isConstant ) + if( !ctx->type.isVariable && + ctx->type.isConstant && + !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) ) { // Unless unsafe references are turned on and the reference is const if( param.IsReadOnly() && engine->ep.allowUnsafeReferences ) @@ -1697,7 +1758,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as } // Perform implicit ref cast if necessary, but don't allow the implicit conversion to create new objects - if( ctx->type.dataType.IsObject() && ctx->type.dataType.GetObjectType() != dt.GetObjectType() ) + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() ) ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false); // Only objects that support object handles @@ -1706,15 +1767,16 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as // references if( !engine->ep.allowUnsafeReferences && !ctx->type.isVariable && - ctx->type.dataType.IsObject() && + (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() && ((ctx->type.dataType.GetBehaviour()->addref && ctx->type.dataType.GetBehaviour()->release) || - (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ) + (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) || + ctx->type.dataType.IsFuncdef()) ) { // Store a handle to the object as local variable - asSExprContext tmp(engine); - asCDataType dt = ctx->type.dataType; + asCExprContext tmp(engine); + dt = ctx->type.dataType; dt.MakeHandle(true); dt.MakeReference(false); @@ -1724,7 +1786,10 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() ) ctx->bc.Instr(asBC_RDSPtr); ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType()); + if( ctx->type.dataType.IsFuncdef() ) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); ctx->bc.Instr(asBC_PopPtr); ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); @@ -1741,9 +1806,9 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as // Make sure the reference to the value is on the stack // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle - if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !param.IsObjectHandle() ) + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() ) Dereference(ctx, true); - else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() ) + else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) ) ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); else if( ctx->type.dataType.IsPrimitive() ) ctx->bc.Instr(asBC_PshRPtr); @@ -1795,41 +1860,31 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as if( dt.IsObjectHandle() ) ctx->type.isExplicitHandle = true; - if( dt.IsObject() && !dt.IsNullHandle() ) + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() ) { - if( !dt.IsReference() ) - { - // Objects passed by value must be placed in temporary variables - // so that they are guaranteed to not be referenced anywhere else. - // The object must also be allocated on the heap, as the memory will - // be deleted by in as_callfunc_xxx. - // TODO: value on stack: How can we avoid this unnecessary allocation? + // Objects passed by value must be placed in temporary variables + // so that they are guaranteed to not be referenced anywhere else. + // The object must also be allocated on the heap, as the memory will + // be deleted by the called function. - // Local variables doesn't need to be copied into - // a temp if we're already compiling an assignment - if( !isMakingCopy || !ctx->type.dataType.IsObjectHandle() || !ctx->type.isVariable ) - PrepareTemporaryObject(node, ctx, true); + // Handles passed by value must also be placed in a temporary variable + // to guarantee that the object referred to isn't freed too early. - // The implicit conversion shouldn't convert the object to - // non-reference yet. It will be dereferenced just before the call. - // Otherwise the object might be missed by the exception handler. - dt.MakeReference(true); - } - else - { - // An object passed by reference should place the pointer to - // the object on the stack. - dt.MakeReference(false); - } + // TODO: value on stack: How can we avoid this unnecessary allocation? + + // Don't make temporary copies of handles if it is going to be used + // for handle assignment anyway, i.e. REFCPY. + if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) ) + PrepareTemporaryVariable(node, ctx, true); } } } // Don't put any pointer on the stack yet - if( param.IsReference() || (param.IsObject() && !param.IsNullHandle()) ) + if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) ) { // &inout parameter may leave the reference on the stack already - if( refType != 3 ) + if( refType != asTM_INOUTREF ) { asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy ); @@ -1846,7 +1901,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as return 0; } -void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args) +void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args) { // When a match has been found, compile the final byte code using correct parameter types asCScriptFunction *descr = builder->GetFunctionDescription(funcId); @@ -1858,18 +1913,18 @@ void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArrayparameterTypes.GetLength() == 1 && descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) && - (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) || - (descr->objectType == 0 && args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) ) + (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) || + (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) ) makingCopy = true; // Add code for arguments - asSExprContext e(engine); + asCExprContext e(engine); for( int n = (int)args.GetLength()-1; n >= 0; n-- ) { // Make sure PrepareArgument doesn't use any variable that is already - // being used by any of the following argument expressions + // being used by the argument or any of the following argument expressions int l = int(reservedVariables.GetLength()); - for( int m = n-1; m >= 0; m-- ) + for( int m = n; m >= 0; m-- ) args[m]->bc.GetVarsUsed(reservedVariables); PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy); @@ -1879,7 +1934,7 @@ void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArrayAddCode(&e.bc); } -void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset) +void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset) { asCScriptFunction *descr = builder->GetFunctionDescription(funcId); @@ -1897,8 +1952,8 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArrayparameterTypes.GetLength() == 1 && descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) && - (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) || - (descr->objectType == 0 && args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) ) + (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) || + (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) ) makingCopy = true; #endif @@ -1907,11 +1962,12 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArrayparameterTypes[n].IsReference() ) { - if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() ) + if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() ) { if( descr->inOutFlags[n] != asTM_INOUTREF ) { #ifdef AS_DEBUG + // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy ); #endif @@ -1931,7 +1987,8 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArrayinOutFlags[n] != asTM_INOUTREF ) { if( descr->parameterTypes[n].GetTokenType() == ttQuestion && - args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() ) + (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) && + !args[n]->type.dataType.IsObjectHandle() ) { // Send the object as a reference to the object, // and not to the variable holding the object @@ -1942,21 +1999,42 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArrayInstrWORD(asBC_GETOBJREF, (asWORD)offset); } + else if (descr->parameterTypes[n].GetTokenType() == ttQuestion && + args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle) + { + // The object handle is being passed as an object, so dereference it before + // the call so the reference will be to the object rather than to the handle + if (engine->ep.disallowValueAssignForRefType ) + { + // With disallow value assign all ref type objects are always passed by handle + bc->InstrWORD(asBC_GETREF, (asWORD)offset); + } + else + bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); + } else { - bc->InstrWORD(asBC_GETREF, (asWORD)offset); + // If the variable is really an argument of @& type, then it is necessary + // to use asBC_GETOBJREF so the pointer is correctly dereferenced. + sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset); + if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle()) + bc->InstrWORD(asBC_GETREF, (asWORD)offset); + else + bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); } } } - else if( descr->parameterTypes[n].IsObject() ) + else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() ) { // TODO: value on stack: What can we do to avoid this unnecessary allocation? // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx asASSERT(IsVariableOnHeap(args[n]->type.stackOffset)); + // The pointer in the variable will be moved to the stack bc->InstrWORD(asBC_GETOBJ, (asWORD)offset); - // The temporary variable must not be freed as it will no longer hold an object + // Deallocate the variable slot so it can be reused, but do not attempt to + // free the content of the variable since it was moved to the stack for the call DeallocateVariable(args[n]->type.stackOffset); args[n]->type.isTemporary = false; } @@ -1965,7 +2043,7 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, asCArray &namedArgs) +int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs) { asASSERT(node->nodeType == snArgList); @@ -2009,11 +2087,11 @@ int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *objectType, asCArray *namedArgs) +int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *objectType, asCArray *namedArgs) { asCScriptFunction *func = builder->GetFunctionDescription(funcId); if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() ) @@ -2068,7 +2146,7 @@ int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArraynameSpace; outFunc->nameSpace = func->nameSpace; - asSExprContext expr(engine); + asCExprContext expr(engine); r = CompileExpression(arg, &expr); // Restore the namespace outFunc->nameSpace = origNameSpace; // Don't allow address of class method - if( expr.methodName != "" ) + if( expr.IsClassMethod() ) { // TODO: Improve error message Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg); @@ -2178,7 +2256,7 @@ int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope) +asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope) { asCArray origFuncs = funcs; // Keep the original list for error message asUINT cost = 0; @@ -2348,7 +2426,7 @@ asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArray &funcs, asCArrayIsClassMethod() ) { attemptsPassingClassMethod = true; - str += args[n]->type.dataType.GetObjectType()->GetName(); + str += args[n]->type.dataType.GetTypeInfo()->GetName(); str += "::"; } str += args[n]->methodName; } + else if (args[n]->IsAnonymousInitList()) + { + str += "{...}"; + } else str += args[n]->type.dataType.Format(outFunc->nameSpace); } @@ -2428,7 +2510,7 @@ asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArraymethodName != "" ) str += named.ctx->methodName; else @@ -2480,43 +2562,63 @@ asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArraynodeType == snAssignment ) { int r = CompileAssignment(node, &compiledCtx); if( r >= 0 ) { + // Must not have unused ambiguous names + if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc()) + { + // TODO: Should mention that the problem is the ambiguous name + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + + // Must not have unused anonymous functions + if (compiledCtx.IsLambda()) + { + // TODO: Should mention that the problem is the anonymous function + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + + // Must not be a null handle + if (compiledCtx.type.dataType.IsNullHandle()) + { + // TODO: Should mention that the problem is the null pointer + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + asCDataType newType = compiledCtx.type.dataType; - bool success = true; // Handle const qualifier on auto - if( type.IsReadOnly() ) + if (type.IsReadOnly()) newType.MakeReadOnly(true); - else if( newType.IsPrimitive() ) + else if (newType.IsPrimitive()) newType.MakeReadOnly(false); // Handle reference/value stuff newType.MakeReference(false); - if( !newType.IsObjectHandle() ) + if (!newType.IsObjectHandle()) { // We got a value object or an object reference. // Turn the variable into a handle if specified // as auto@, otherwise make it a 'value'. - if( type.IsHandleToAuto() ) + if (type.IsHandleToAuto()) { - if( newType.MakeHandle(true) < 0 ) + if (newType.MakeHandle(true) < 0) { Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode); - success = false; + return false; } } } - if(success) - type = newType; - else - type = asCDataType::CreatePrimitive(ttInt, false); + type = newType; return true; } @@ -2533,17 +2635,26 @@ bool asCCompiler::CompileAutoType(asCDataType &type, asSExprContext &compiledCtx void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc) { // Get the data type - asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace); + asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType); // Declare all variables in this declaration asCScriptNode *node = decl->firstChild->next; while( node ) { // If this is an auto type, we have to compile the assignment now to figure out the type - asSExprContext compiledCtx(engine); + asCExprContext compiledCtx(engine); bool preCompiled = false; - if( type.IsAuto() ) + if (type.IsAuto()) + { preCompiled = CompileAutoType(type, compiledCtx, node->next, node); + if (!preCompiled) + { + // If it wasn't possible to determine the type from the expression then there + // is no need to continue with the initialization. The error was already reported + // in CompileAutoType. + return; + } + } // Is the type allowed? if( !type.CanBeInstantiated() ) @@ -2558,14 +2669,15 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc) str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf()); Error(str, node); - // Use int instead to avoid further problems - type = asCDataType::CreatePrimitive(ttInt, false); + // Don't continue, as it will most likely lead to further + // errors that may just mislead the script writer + return; } // A shared object may not declare variables of non-shared types if( outFunc->IsShared() ) { - asCObjectType *ot = type.GetObjectType(); + asCTypeInfo *ot = type.GetTypeInfo(); if( ot && !ot->IsShared() ) { asCString msg; @@ -2579,7 +2691,7 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc) // Verify that the name isn't used by a dynamic data type // TODO: Must check against registered funcdefs too - if( engine->GetRegisteredObjectType(name.AddressOf(), outFunc->nameSpace) != 0 ) + if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 ) { asCString str; str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf()); @@ -2646,20 +2758,20 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc) } // Returns true if the initialization expression is a constant expression -bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asSExprContext *preCompiled) +bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled) { bool isConstantExpression = false; if( node && node->nodeType == snArgList ) { // Make sure it is an object and not a handle - if( type.GetObjectType() == 0 || type.IsObjectHandle() ) + if( type.GetTypeInfo() == 0 || type.IsObjectHandle() ) { Error(TXT_MUST_BE_OBJECT, node); } else { // Compile the arguments - asCArray args; + asCArray args; asCArray namedArgs; if( CompileArgumentList(node, args, namedArgs) >= 0 ) { @@ -2668,7 +2780,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as asSTypeBehaviour *beh = type.GetBehaviour(); if( beh ) { - if( type.GetObjectType()->flags & asOBJ_REF ) + if( type.GetTypeInfo()->flags & asOBJ_REF ) funcs = beh->factories; else funcs = beh->constructors; @@ -2680,12 +2792,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as if( funcs.GetLength() == 1 ) { // Add the default values for arguments not explicitly supplied - int r = CompileDefaultAndNamedArgs(node, args, funcs[0], type.GetObjectType(), &namedArgs); + int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs); if( r == asSUCCESS ) { - asSExprContext ctx(engine); - if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) ) + asCExprContext ctx(engine); + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) ) { if( isVarGlobOrMem == 0 ) MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset); @@ -2703,9 +2815,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as // Store the returned handle in the member ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } - ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType()); + if( type.IsFuncdef()) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); } @@ -2736,12 +2851,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as else { // Value types may be allocated inline if they are POD types - onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF); + onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF); if( onHeap ) { ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } } @@ -2756,7 +2871,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as { ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } else { @@ -2764,7 +2879,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as } } - PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType()); + PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo())); if( isVarGlobOrMem == 0 ) { @@ -2781,18 +2896,18 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as for( asUINT n = 0; n < args.GetLength(); n++ ) if( args[n] ) { - asDELETE(args[n],asSExprContext); + asDELETE(args[n], asCExprContext); } for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) if( namedArgs[n].ctx ) { - asDELETE(namedArgs[n].ctx,asSExprContext); + asDELETE(namedArgs[n].ctx, asCExprContext); } } } else if( node && node->nodeType == snInitList ) { - asCTypeInfo ti; + asCExprValue ti; ti.Set(type); ti.isVariable = (isVarGlobOrMem == 0); ti.isTemporary = false; @@ -2803,11 +2918,9 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as } else if( node && node->nodeType == snAssignment ) { - asSExprContext ctx(engine); - // Compile the expression - asSExprContext newExpr(engine); - asSExprContext* expr; + asCExprContext newExpr(engine); + asCExprContext* expr; int r = 0; if( preCompiled ) @@ -2820,24 +2933,29 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as r = CompileAssignment(node, expr); } + // handles initialized with null doesn't need any bytecode + // since handles will be initialized to null by default anyway + if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() ) + return false; + // Look for appropriate constructor asCArray funcs; - asCArray args; + asCArray args; // Handles must use the handle assignment operation. // Types that are ASHANDLE must not allow the use of the constructor in this case, // because it is ambiguous whether a value assignment or handle assignment will be done. - // Only do this if the expression is of the same type, as the expression is an assignment + // Only do this if the expression is of the same type, as the expression is an assignment // and an initialization constructor may not have the same meaning. // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions. if( !type.IsObjectHandle() && !expr->type.isExplicitHandle && - !(type.GetObjectType() && (type.GetObjectType()->GetFlags() & asOBJ_ASHANDLE)) && + !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) && type.IsEqualExceptRefAndConst(expr->type.dataType) ) { asSTypeBehaviour *beh = type.GetBehaviour(); if( beh ) { - if( type.GetObjectType()->flags & asOBJ_REF ) + if( type.GetTypeInfo()->flags & asOBJ_REF ) funcs = beh->factories; else funcs = beh->constructors; @@ -2846,6 +2964,14 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as asCString str = type.Format(outFunc->nameSpace); args.PushLast(expr); MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true); + + // Make sure the argument is of the right type (and not just compatible with the expression) + if (funcs.GetLength() == 1) + { + asCScriptFunction *f = engine->scriptFunctions[funcs[0]]; + if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType)) + funcs.PopLast(); + } } if( funcs.GetLength() == 1 ) @@ -2855,12 +2981,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as // TODO: clean-up: A large part of this is identical to the initalization with argList above // Add the default values for arguments not explicitly supplied - int r = CompileDefaultAndNamedArgs(node, args, funcs[0], type.GetObjectType()); + r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo())); if( r == asSUCCESS ) { - asSExprContext ctx(engine); - if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) ) + asCExprContext ctx(engine); + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) ) { if( isVarGlobOrMem == 0 ) MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset); @@ -2878,9 +3004,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as // Store the returned handle in the member ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } - ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType()); + if( type.IsFuncdef() ) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); } @@ -2911,12 +3040,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as else { // Value types may be allocated inline if they are POD types - onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF); + onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF); if( onHeap ) { ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } } @@ -2931,7 +3060,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as { ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } else { @@ -2939,7 +3068,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as } } - PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType()); + PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo())); if( isVarGlobOrMem == 0 ) { @@ -2953,6 +3082,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as else { // Call the default constructur, then call the assignment operator + asCExprContext ctx(engine); // Call the default constructor here if( isVarGlobOrMem == 0 ) @@ -2972,10 +3102,10 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as // Tell caller that the expression is a constant so it can mark the variable as pure constant isConstantExpression = true; - *constantValue = expr->type.qwordValue; + *constantValue = expr->type.GetConstantData(); } - asSExprContext lctx(engine); + asCExprContext lctx(engine); if( isVarGlobOrMem == 0 ) lctx.type.SetVariable(type, offset, false); else if( isVarGlobOrMem == 1 ) @@ -2997,7 +3127,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as // Load the reference of the primitive member into the register lctx.bc.InstrSHORT(asBC_PSF, 0); lctx.bc.Instr(asBC_RDSPtr); - lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); lctx.bc.Instr(asBC_PopRPtr); } lctx.type.dataType.MakeReadOnly(false); @@ -3012,7 +3142,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as // just the copy constructor. Only if no appropriate constructor is // available should the assignment operator be used. - asSExprContext lexpr(engine); + asCExprContext lexpr(engine); lexpr.type.Set(type); if( isVarGlobOrMem == 0 ) lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset)); @@ -3020,7 +3150,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as lexpr.type.dataType.MakeReference(true); else if( isVarGlobOrMem == 2 ) { - if( !lexpr.type.dataType.IsObject() || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_REF) ) + if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) ) lexpr.type.dataType.MakeReference(true); } @@ -3044,7 +3174,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as { lexpr.bc.InstrSHORT(asBC_PSF, 0); lexpr.bc.Instr(asBC_RDSPtr); - lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); lexpr.type.stackOffset = -1; } lexpr.type.isLValue = true; @@ -3057,10 +3187,10 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as // and a simple assignment. bool assigned = false; // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called - if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ) + if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) ) { bool useHndlAssign = lexpr.type.dataType.IsHandleToAsHandleType(); - assigned = CompileOverloadedDualOperator(node, &lexpr, expr, &ctx, useHndlAssign); + assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign); if( assigned ) { // Pop the resulting value @@ -3085,7 +3215,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as if( type.IsReadOnly() && expr->type.isConstant ) { isConstantExpression = true; - *constantValue = expr->type.qwordValue; + *constantValue = expr->type.GetConstantQW(); } // Add expression code to bytecode @@ -3120,7 +3250,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem); else if( isVarGlobOrMem == 2 ) { - if( !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF) ) + if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) ) CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem); else CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem); @@ -3130,10 +3260,10 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as return isConstantExpression; } -void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem) +void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem) { // Check if the type supports initialization lists - if( var->dataType.GetObjectType() == 0 || + if( var->dataType.GetTypeInfo() == 0 || var->dataType.GetBehaviour()->listFactory == 0 ) { asCString str; @@ -3156,20 +3286,25 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte asCObjectType *listPatternType = engine->GetListPatternType(funcId); // Allocate a temporary variable to hold the pointer to the buffer - int bufferVar = AllocateVariable(asCDataType::CreateObject(listPatternType, false), true); + int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true); asUINT bufferSize = 0; // Evaluate all elements of the list - asSExprContext valueExpr(engine); + asCExprContext valueExpr(engine); asCScriptNode *el = node; asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; int elementsInSubList = -1; - int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateObject(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList); + int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList); asASSERT( r || patternNode == 0 ); - UNUSED_VAR(r); + if (r < 0) + { + asCString msg; + msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf()); + Error(msg, node); + } // After all values have been evaluated we know the final size of the buffer - asSExprContext allocExpr(engine); + asCExprContext allocExpr(engine); allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize); // Merge the bytecode into the final sequence @@ -3177,20 +3312,20 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte bc->AddCode(&valueExpr.bc); // The object itself is the last to be created and will receive the pointer to the buffer - asCArray args; - asSExprContext arg1(engine); + asCArray args; + asCExprContext arg1(engine); arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false)); arg1.type.dataType.MakeReference(true); arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar)); args.PushLast(&arg1); - asSExprContext ctx(engine); + asCExprContext ctx(engine); if( var->isVariable ) { asASSERT( isVarGlobOrMem == 0 ); - if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF ) + if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF ) { ctx.bc.AddCode(&arg1.bc); @@ -3217,7 +3352,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte if( !onHeap ) ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset); - PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType()); + PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo())); // Mark the object in the local variable as initialized ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT); @@ -3225,7 +3360,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte } else { - if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF ) + if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF ) { ctx.bc.AddCode(&arg1.bc); @@ -3242,9 +3377,12 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte // Store the returned handle in the member ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } - ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType()); + if (var->dataType.IsFuncdef()) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo()); ctx.bc.Instr(asBC_PopPtr); ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); } @@ -3257,12 +3395,12 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue()); else { - onHeap = !var->dataType.IsObject() || var->dataType.IsReference() || (var->dataType.GetObjectType()->flags & asOBJ_REF); + onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF); if( onHeap ) { ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } } @@ -3273,11 +3411,11 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte { ctx.bc.InstrSHORT(asBC_PSF, 0); ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); } // Call the ALLOC instruction to allocate memory and invoke constructor - PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType()); + PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo())); } } @@ -3289,7 +3427,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte ReleaseTemporaryVariable(bufferVar, bc); } -int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList) +int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList) { if( patternNode->type == asLPT_START ) { @@ -3312,7 +3450,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr } asCScriptNode *errNode = node; - int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, byteCode, elementsInSubList); + int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList); if( r < 0 ) return r; if( r == 1 ) @@ -3360,7 +3498,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr int elementsInSubSubList = -1; - asSExprContext ctx(engine); + asCExprContext ctx(engine); while( valueNode ) { patternNode = nextNode; @@ -3370,7 +3508,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr if( r == 0 ) countElements++; - else + else { asASSERT( r == 1 && engine->ep.disallowEmptyListElements ); if( valueNode ) @@ -3419,10 +3557,10 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr } // The first dword in the buffer will hold the number of elements - byteCode.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements); + bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements); // Add the values - byteCode.AddCode(&ctx.bc); + bcInit.AddCode(&ctx.bc); } else if( patternNode->type == asLPT_TYPE ) { @@ -3435,8 +3573,8 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList ) { - asSExprContext lctx(engine); - asSExprContext rctx(engine); + asCExprContext lctx(engine); + asCExprContext rctx(engine); if( valueNode->nodeType == snAssignment ) { @@ -3445,6 +3583,9 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr if( dt.GetTokenType() == ttQuestion ) { + // Make sure the type is not ambiguous + DetermineSingleFunc(&rctx, valueNode); + // We now know the type dt = rctx.type.dataType; dt.MakeReadOnly(false); @@ -3455,7 +3596,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr bufferSize += 4 - (bufferSize & 0x3); // Place the type id in the buffer - byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt)); + bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt)); bufferSize += 4; } } @@ -3491,7 +3632,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr } // Determine size of the element - if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) ) + if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) ) size = dt.GetSizeInMemoryBytes(); else size = AS_PTR_SIZE*4; @@ -3510,51 +3651,47 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr lctx.type.dataType.MakeReference(true); } else if( dt.IsObjectHandle() || - dt.GetObjectType()->flags & asOBJ_REF ) + dt.GetTypeInfo()->flags & asOBJ_REF ) { lctx.type.isExplicitHandle = true; lctx.type.dataType.MakeReference(true); } else { - asASSERT( dt.GetObjectType()->flags & asOBJ_VALUE ); + asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE ); // Make sure the object has been constructed before the assignment // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects asSTypeBehaviour *beh = dt.GetBehaviour(); int func = 0; if( beh ) func = beh->construct; - if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 ) + if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 ) { asCString str; - // TODO: funcdef: asCDataType should have a GetTypeName() - if( dt.GetFuncDef() ) - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName()); - else - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName()); + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); Error(str, valueNode); } else if( func ) { // Call the constructor as a normal function - byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType()); - byteCode.AddCode(&ctx.bc); + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo())); + bcInit.AddCode(&ctx.bc); } } if( lctx.type.dataType.IsNullHandle() ) { - // Don't add any code to assign a null handle. RefCpy doesn't work without a known type. + // Don't add any code to assign a null handle. RefCpy doesn't work without a known type. // The buffer is already initialized to zero in asBC_AllocMem anyway. asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull ); asASSERT( reinterpret_cast(patternNode)->dataType.GetTokenType() == ttQuestion ); } else { - asSExprContext ctx(engine); + asCExprContext ctx(engine); DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); if( !lctx.type.dataType.IsPrimitive() ) @@ -3565,7 +3702,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr ProcessDeferredParams(&ctx); - byteCode.AddCode(&ctx.bc); + bcInit.AddCode(&ctx.bc); } } else @@ -3585,27 +3722,23 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr bufferSize += 4 - (bufferSize & 0x3); // Place the type id for a null handle in the buffer - byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0); + bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0); bufferSize += 4; dt = asCDataType::CreateNullHandle(); // No need to initialize the handle as the buffer is already initialized with zeroes } - else if( dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_VALUE ) + else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE ) { // For value types with default constructor we need to call the constructor asSTypeBehaviour *beh = dt.GetBehaviour(); int func = 0; if( beh ) func = beh->construct; - if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 ) + if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 ) { asCString str; - // TODO: funcdef: asCDataType should have a GetTypeName() - if( dt.GetFuncDef() ) - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName()); - else - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName()); + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); Error(str, valueNode); } else if( func ) @@ -3615,14 +3748,14 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr bufferSize += 4 - (bufferSize & 0x3); // Call the constructor as a normal function - byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType()); - byteCode.AddCode(&ctx.bc); + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo())); + bcInit.AddCode(&ctx.bc); } } - else if( !dt.IsObjectHandle() && dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_REF ) + else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF ) { // For ref types (not handles) we need to call the default factory asSTypeBehaviour *beh = dt.GetBehaviour(); @@ -3631,30 +3764,26 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr if( func == 0 ) { asCString str; - // TODO: funcdef: asCDataType should have a GetTypeName() - if( dt.GetFuncDef() ) - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName()); - else - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName()); + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); Error(str, valueNode); } else if( func ) { - asSExprContext rctx(engine); - PerformFunctionCall(func, &rctx, false, 0, dt.GetObjectType()); + asCExprContext rctx(engine); + PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo())); // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. if( bufferSize & 0x3 ) bufferSize += 4 - (bufferSize & 0x3); - asSExprContext lctx(engine); + asCExprContext lctx(engine); lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); lctx.type.Set(dt); lctx.type.isLValue = true; lctx.type.isExplicitHandle = true; lctx.type.dataType.MakeReference(true); - asSExprContext ctx(engine); + asCExprContext ctx(engine); DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); if( !lctx.type.dataType.IsPrimitive() ) @@ -3665,7 +3794,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr ProcessDeferredParams(&ctx); - byteCode.AddCode(&ctx.bc); + bcInit.AddCode(&ctx.bc); } } } @@ -3674,7 +3803,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr if( !isEmpty ) { // Determine size of the element - if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) ) + if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) ) size = dt.GetSizeInMemoryBytes(); else size = AS_PTR_SIZE*4; @@ -3748,7 +3877,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo //------------------------------- // Compile the switch expression - asSExprContext expr(engine); + asCExprContext expr(engine); CompileAssignment(snode->firstChild, &expr); // Verify that the expression is a primitive type @@ -3799,7 +3928,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo if( cnode->firstChild && cnode->firstChild->nodeType == snExpression ) { // Compile expression - asSExprContext c(engine); + asCExprContext c(engine); CompileExpression(cnode->firstChild, &c); // Verify that the result is a constant @@ -3807,24 +3936,24 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild); // Verify that the result is an integral number - if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() ) + if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType()) Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild); - - ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true); - - // Has this case been declared already? - if( caseValues.IndexOf(c.type.intValue) >= 0 ) + else { - Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild); + ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true); + + // Has this case been declared already? + if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0) + Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild); + + // TODO: Optimize: We can insert the numbers sorted already + + // Store constant for later use + caseValues.PushLast(c.type.GetConstantDW()); + + // Reserve label for this case + caseLabels.PushLast(nextLabel++); } - - // TODO: Optimize: We can insert the numbers sorted already - - // Store constant for later use - caseValues.PushLast(c.type.intValue); - - // Reserve label for this case - caseLabels.PushLast(nextLabel++); } else { @@ -3843,7 +3972,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo cnode = cnode->next; } - // check for empty switch + // check for empty switch if (caseValues.GetLength() == 0) { Error(TXT_EMPTY_SWITCH, snode); @@ -3854,7 +3983,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo defaultLabel = breakLabel; //--------------------------------- - // Output the optimized case comparisons + // Output the optimized case comparisons // with jumps to the case code //------------------------------------ @@ -3944,9 +4073,9 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo // Add the list of jumps to the correct labels (any holes, jump to default) index = ranges[range]; - for( int n = caseValues[index]; n <= maxRange; n++ ) + for( int i = caseValues[index]; i <= maxRange; i++ ) { - if( caseValues[index] == n ) + if( caseValues[index] == i ) expr.bc.InstrINT(asBC_JMP, caseLabels[index++]); else expr.bc.InstrINT(asBC_JMP, defaultLabel); @@ -3957,13 +4086,12 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo else { // Simply make a comparison with each value - int n; - for( n = ranges[range]; n < index; ++n ) + for( int i = ranges[range]; i < index; ++i ) { tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); - expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]); + expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]); expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); - expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]); + expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]); ReleaseTemporaryVariable(tmpOffset, &expr.bc); } } @@ -4066,12 +4194,12 @@ void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCB int afterLabel = nextLabel++; // Compile the expression - asSExprContext expr(engine); + asCExprContext expr(engine); int r = CompileAssignment(inode->firstChild, &expr); if( r == 0 ) { // Allow value types to be converted to bool using 'bool opImplConv()' - if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) ) + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV); if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) @@ -4096,7 +4224,11 @@ void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCB expr.bc.OptimizeLocally(tempVariableOffsets); bc->AddCode(&expr.bc); } - else if( expr.type.dwordValue == 0 ) +#if AS_SIZEOF_BOOL == 1 + else if( expr.type.GetConstantB() == 0 ) +#else + else if (expr.type.GetConstantDW() == 0) +#endif { // Jump to the else case bc->InstrINT(asBC_JMP, afterLabel); @@ -4216,7 +4348,7 @@ void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc) //----------------------------------- // Compile the condition statement - asSExprContext expr(engine); + asCExprContext expr(engine); asCScriptNode *second = fnode->firstChild->next; if( second->firstChild ) { @@ -4224,7 +4356,7 @@ void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc) if( r >= 0 ) { // Allow value types to be converted to bool using 'bool opImplConv()' - if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) ) + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV); if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) @@ -4333,12 +4465,12 @@ void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc) bc->Label((short)beforeLabel); // Compile expression - asSExprContext expr(engine); + asCExprContext expr(engine); int r = CompileAssignment(wnode->firstChild, &expr); if( r == 0 ) { // Allow value types to be converted to bool using 'bool opImplConv()' - if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) ) + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV); if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) @@ -4427,11 +4559,11 @@ void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc) LineInstr(bc, wnode->lastChild->tokenPos); // Compile expression - asSExprContext expr(engine); + asCExprContext expr(engine); CompileAssignment(wnode->lastChild, &expr); // Allow value types to be converted to bool using 'bool opImplConv()' - if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) ) + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV); if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) @@ -4518,7 +4650,7 @@ void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode * if( enode->firstChild ) { // Compile the expression - asSExprContext expr(engine); + asCExprContext expr(engine); CompileAssignment(enode->firstChild, &expr); // Must not have unused ambiguous names @@ -4549,8 +4681,11 @@ void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode * } } -void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap) +void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap) { + // The input can be either an object or funcdef, either as handle or reference + asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()); + // If the object already is stored in temporary variable then nothing needs to be done // Note, a type can be temporary without being a variable, in which case it is holding off // on releasing a previously used object. @@ -4579,13 +4714,20 @@ void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ct // Objects stored on the stack are not considered references dt.MakeReference(IsVariableOnHeap(offset)); - asCTypeInfo lvalue; + asCExprValue lvalue; lvalue.Set(dt); lvalue.isExplicitHandle = ctx->type.isExplicitHandle; bool isExplicitHandle = ctx->type.isExplicitHandle; + bool prevIsTemp = ctx->type.isTemporary; + int prevStackOffset = ctx->type.stackOffset; + CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false); + // Release the previous temporary variable if it hasn't already been released + if( prevIsTemp && tempVariables.Exists(prevStackOffset) ) + ReleaseTemporaryVariable(prevStackOffset, &ctx->bc); + // Push the reference to the temporary variable on the stack ctx->bc.InstrSHORT(asBC_PSF, (short)offset); @@ -4618,7 +4760,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc) if( rnode->firstChild ) { // Compile the expression - asSExprContext expr(engine); + asCExprContext expr(engine); int r = CompileAssignment(rnode->firstChild, &expr); if( r < 0 ) return; @@ -4660,7 +4802,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc) // The type must match exactly as we cannot convert // the reference without loosing the original value if( !(v->type.IsEqualExceptConst(expr.type.dataType) || - (expr.type.dataType.IsObject() && + ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) && !expr.type.dataType.IsObjectHandle() && v->type.IsEqualExceptRefAndConst(expr.type.dataType))) || (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) ) @@ -4773,7 +4915,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc) expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset); } } - else if( v->type.IsObject() ) + else if( v->type.IsObject() || v->type.IsFuncdef() ) { // Value types are returned on the stack, in a location // that has been reserved by the calling function. @@ -4803,7 +4945,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc) } else { - asASSERT( v->type.GetObjectType()->flags & asOBJ_REF ); + asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() ); // Prepare the expression to be loaded into the object // register. This will place the reference in local variable @@ -4932,7 +5074,7 @@ void asCCompiler::PrintMatchingFuncs(asCArray &funcs, asCScriptNode *node, } } -int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx) +int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx) { int l = int(reservedVariables.GetLength()); ctx->bc.GetVarsUsed(reservedVariables); @@ -4957,7 +5099,7 @@ int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, boo bool isOnHeap = true; if( t.IsPrimitive() || - (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) ) + (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) ) { // Primitives and value types (unless overridden) are allocated on the stack isOnHeap = false; @@ -5092,6 +5234,7 @@ void asCCompiler::DeallocateVariable(int offset) } } + // Mark the variable slot available for new allocations n = GetVariableSlot(offset); if( n != -1 ) { @@ -5100,13 +5243,13 @@ void asCCompiler::DeallocateVariable(int offset) } // We might get here if the variable was implicitly declared - // because it was use before a formal declaration, in this case + // because it was used before a formal declaration, in this case // the offset is 0x7FFF asASSERT(offset == 0x7FFF); } -void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc) +void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc) { if( t.isTemporary ) { @@ -5137,11 +5280,11 @@ void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc) DeallocateVariable(offset); } -void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode) +void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode) { if( ctx->type.dataType.IsReference() ) { - if( ctx->type.dataType.IsObject() ) + if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() ) { ctx->type.dataType.MakeReference(false); if( generateCode ) @@ -5155,7 +5298,7 @@ void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode) } } -bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node) +bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node) { // No need to check if there is no variable scope if( variables == 0 ) return true; @@ -5175,7 +5318,7 @@ bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node) if( v->isInitialized ) return true; // Complex types don't need this test - if( v->type.IsObject() ) return true; + if( v->type.IsObject() || v->type.IsFuncdef() ) return true; // Mark as initialized so that the user will not be bothered again v->isInitialized = true; @@ -5188,7 +5331,7 @@ bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node) return false; } -void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node) +void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node) { // Check if the variable is initialized (if it indeed is a variable) IsVariableInitialized(&ctx->type, node); @@ -5201,7 +5344,7 @@ void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node) ProcessDeferredParams(ctx); } -void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr) +void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr) { // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too int l = int(reservedVariables.GetLength()); @@ -5249,14 +5392,14 @@ void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx // TODO: ImplicitConversion should know to do this by itself // First convert to a handle which will do a reference cast if( !lvalue->IsObjectHandle() && - (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ) + (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) to.MakeHandle(true); // Don't allow the implicit conversion to create an object ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary); if( !lvalue->IsObjectHandle() && - (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ) + (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) { // Then convert to a reference, which will validate the handle to.MakeHandle(false); @@ -5273,8 +5416,7 @@ void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx else { // If the assignment will be made with the copy behaviour then the rvalue must not be a reference - if( lvalue->IsObject() ) - asASSERT(!rctx->type.dataType.IsReference()); + asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference()); } } @@ -5282,7 +5424,7 @@ void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx reservedVariables.SetLength(l); } -bool asCCompiler::IsLValue(asCTypeInfo &type) +bool asCCompiler::IsLValue(asCExprValue &type) { if( !type.isLValue ) return false; if( type.dataType.IsReadOnly() ) return false; @@ -5290,7 +5432,7 @@ bool asCCompiler::IsLValue(asCTypeInfo &type) return true; } -int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node) +int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node) { if( lvalue->dataType.IsReadOnly() ) { @@ -5333,22 +5475,22 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC } else if( !lvalue->isExplicitHandle ) { - asSExprContext ctx(engine); + asCExprContext ctx(engine); ctx.type = *lvalue; Dereference(&ctx, true); *lvalue = ctx.type; bc->AddCode(&ctx.bc); asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour(); - if( beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy ) + if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy ) { - asSExprContext res(engine); - PerformFunctionCall(beh->copy, &res, false, 0, lvalue->dataType.GetObjectType()); + asCExprContext res(engine); + PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo())); bc->AddCode(&res.bc); *lvalue = res.type; } - else if( beh->copy == engine->scriptTypeBehaviours.beh.copy ) + else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy ) { // Call the default copy operator for script classes // This is done differently because the default copy operator @@ -5363,10 +5505,10 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC { // Default copy operator if( lvalue->dataType.GetSizeInMemoryDWords() == 0 || - !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) ) + !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) ) { asCString msg; - msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf()); + msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf()); Error(msg, node); return -1; } @@ -5385,7 +5527,10 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC return -1; } - bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType()); + if( lvalue->dataType.IsFuncdef() ) + bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo()); // Mark variable as initialized if( variables ) @@ -5398,7 +5543,7 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC return 0; } -bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode) +bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode) { bool conversionDone = false; @@ -5409,15 +5554,15 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo bool isConst = ctx->type.dataType.IsObjectConst(); // Find a suitable opCast or opImplCast method - asCObjectType *ot = ctx->type.dataType.GetObjectType(); - for( n = 0; n < ot->methods.GetLength(); n++ ) + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( n = 0; ot && n < ot->methods.GetLength(); n++ ) { asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; if( (isExplicit && func->name == "opCast") || func->name == "opImplCast" ) { // Is the operator for the output type? - if( func->returnType.GetObjectType() != to.GetObjectType() ) + if( func->returnType.GetTypeInfo() != to.GetTypeInfo() ) continue; // Can't call a non-const function on a const object @@ -5431,9 +5576,22 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo // Filter the list by constness to remove const methods if there are matching non-const methods FilterConst(ops, !isConst); - // It shouldn't be possible to have more than one - // TODO: Should be allowed to have different behaviours for const and non-const references - asASSERT( ops.GetLength() <= 1 ); + // Give an error more than one opCast methods were found + if (ops.GetLength() > 1) + { + if (isExplicit && generateCode) + { + asCString str; + str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, "opCast"); + Error(str, node); + + PrintMatchingFuncs(ops, node, ot); + } + // Return that the conversion was done to avoid further complaints + conversionDone = true; + ctx->type.Set(to); + return conversionDone; + } // Should only have one behaviour for each output type if( ops.GetLength() == 1 ) @@ -5450,13 +5608,13 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo // functions with 1 parameter, even though they should still be // registered with RegisterObjectBehaviour() - if( ctx->type.dataType.GetObjectType()->flags & asOBJ_REF ) + if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE)) { // Add code to avoid calling the cast behaviour if the handle is already null, // because that will raise a null pointer exception due to the cast behaviour // being a class method, and the this pointer cannot be null. - if( !ctx->type.isVariable ) + if (!ctx->type.isVariable) { Dereference(ctx, true); ConvertToVariable(ctx); @@ -5480,8 +5638,8 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo ctx->bc.Instr(asBC_RDSPtr); ctx->type.dataType.MakeReference(false); - asCArray args; - MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node); + asCArray args; + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); ctx->bc.Instr(asBC_PopPtr); int endLabel = nextLabel++; @@ -5498,11 +5656,15 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo } else { - // Value types cannot be null, so there is no need to check for this + // Value types cannot be null, so there is no need to check for this. + + // Likewise for reference types that are registered with asOBJ_NOHANDLE + // as those are only expected as registered global properties that cannot + // be modified anyway. // Call the cast operator - asCArray args; - MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node); + asCArray args; + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); } } else @@ -5511,10 +5673,10 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo ctx->type.Set(func->returnType); } } - else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ) + else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) { // Check for the generic ref cast method: void opCast(?&out) - for( n = 0; n < ot->methods.GetLength(); n++ ) + for( n = 0; ot && n < ot->methods.GetLength(); n++ ) { asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; if( (isExplicit && func->name == "opCast") || @@ -5542,14 +5704,49 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo { asASSERT(to.IsObjectHandle()); + int afterLabel = 0; + bool doNullCheck = false; + asCExprContext tmp(engine); + if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE)) + { + tmp.bc.AddCode(&ctx->bc); + tmp.Merge(ctx); + + // Add code to avoid calling the cast behaviour if the handle is already null, + // because that will raise a null pointer exception due to the cast behaviour + // being a class method, and the this pointer cannot be null. + doNullCheck = true; + if (!ctx->type.isVariable) + { + Dereference(&tmp, true); + ConvertToVariable(&tmp); + } + + // The reference on the stack will not be used + tmp.bc.Instr(asBC_PopPtr); + + // TODO: runtime optimize: should have immediate comparison for null pointer + int offset = AllocateVariable(asCDataType::CreateNullHandle(), true); + // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though) + tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset); + tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset); + DeallocateVariable(offset); + + afterLabel = nextLabel++; + tmp.bc.InstrDWORD(asBC_JZ, afterLabel); + + // Place the object pointer on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset); + } + // Allocate a temporary variable of the requested handle type int stackOffset = AllocateVariableNotIn(to, true, false, ctx); // Pass the reference of that variable to the function as output parameter asCDataType toRef(to); toRef.MakeReference(true); - asCArray args; - asSExprContext arg(engine); + asCArray args; + asCExprContext arg(engine); arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset); // Don't mark the variable as temporary, so it won't be freed too early arg.type.SetVariable(toRef, stackOffset, false); @@ -5558,7 +5755,23 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo args.PushLast(&arg); // Call the behaviour method - MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node); + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + + if (doNullCheck) + { + // Add the call after the null check + tmp.bc.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmp.bc); + + int endLabel = nextLabel++; + + ctx->bc.InstrINT(asBC_JMP, endLabel); + ctx->bc.Label((short)afterLabel); + + // Make a NULL pointer + ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset); + ctx->bc.Label((short)endLabel); + } // Use the reference to the variable as the result of the expression // Now we can mark the variable as temporary @@ -5573,16 +5786,16 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo } } - // If the script object didn't implement a matching opCast or opImplCast + // If the script object didn't implement a matching opCast or opImplCast // then check if the desired type is part of the hierarchy - if( !conversionDone && (ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ) + if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) { // We need it to be a reference if( !ctx->type.dataType.IsReference() ) { - asCDataType to = ctx->type.dataType; - to.MakeReference(true); - ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode); + asCDataType toRef = ctx->type.dataType; + toRef.MakeReference(true); + ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode); } if( isExplicit ) @@ -5616,10 +5829,10 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo } else { - if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) ) + if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) ) { conversionDone = true; - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } } @@ -5631,7 +5844,7 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo return conversionDone; } -asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode) +asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode) { asCDataType to = toOrig; to.MakeReference(false); @@ -5653,7 +5866,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const // Attempt to resolve an ambiguous enum value asCDataType out; asDWORD value; - if( builder->GetEnumValueFromObjectType(to.GetObjectType(), ctx->enumValue.AddressOf(), out, value) ) + if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) ) { ctx->type.SetConstantDW(out, value); ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); @@ -5678,13 +5891,17 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asUINT cost = asCC_NO_CONV; if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) ) cost = asCC_INT_FLOAT_CONV; - else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()) ) + else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType())) cost = asCC_INT_FLOAT_CONV; + else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() ) + cost = asCC_ENUM_SAME_SIZE_CONV; + else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes()) + cost = asCC_ENUM_DIFF_SIZE_CONV; else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() ) cost = asCC_SIGNED_CONV; else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() ) cost = asCC_SIGNED_CONV; - else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() ) + else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() ) cost = asCC_PRIMITIVE_SIZE_CONV; // Start by implicitly converting constant values @@ -5732,7 +5949,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) { ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } else { @@ -5748,7 +5965,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ConvertToTempVariable(ctx); ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset); ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); if( convType != asIC_EXPLICIT_VAL_CAST ) Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); @@ -5766,7 +5983,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const } // Convert to smaller integer if necessary - int s = to.GetSizeInMemoryBytes(); + s = to.GetSizeInMemoryBytes(); if( s < 4 ) { ConvertToTempVariable(ctx); @@ -5784,7 +6001,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) { ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } else { @@ -5814,7 +6031,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ConvertToTempVariable(ctx); ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset); ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); if( convType != asIC_EXPLICIT_VAL_CAST ) Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); @@ -5828,7 +6045,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) { ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } else { @@ -5844,7 +6061,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ConvertToTempVariable(ctx); ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset); ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); if( convType != asIC_EXPLICIT_VAL_CAST ) Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); @@ -5862,7 +6079,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const } // Convert to smaller integer if necessary - int s = to.GetSizeInMemoryBytes(); + s = to.GetSizeInMemoryBytes(); if( s < 4 ) { ConvertToTempVariable(ctx); @@ -5880,7 +6097,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) { ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } else { @@ -5910,7 +6127,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ConvertToTempVariable(ctx); ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset); ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); if( convType != asIC_EXPLICIT_VAL_CAST ) Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); @@ -5923,7 +6140,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ConvertToTempVariable(ctx); ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset); ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) { @@ -5938,7 +6155,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ConvertToTempVariable(ctx); ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset); ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) { @@ -5972,7 +6189,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ConvertToTempVariable(ctx); ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset); ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) { @@ -5987,7 +6204,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ConvertToTempVariable(ctx); ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset); ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } else if( ctx->type.dataType.IsFloatType() ) { @@ -6008,7 +6225,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) ) { ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); } } @@ -6017,9 +6234,9 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const return cost; } -asUINT asCCompiler::ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode) +asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode) { - asASSERT( to.GetFuncDef() && ctx->IsLambda() ); + asASSERT( to.IsFuncdef() && ctx->IsLambda() ); // Check that the lambda has the correct amount of arguments asUINT count = 0; @@ -6031,7 +6248,7 @@ asUINT asCCompiler::ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataT } asASSERT( argNode->nodeType == snStatementBlock ); - asCScriptFunction *funcDef = to.GetFuncDef(); + asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef; if( funcDef->parameterTypes.GetLength() != count ) return asCC_NO_CONV; @@ -6059,14 +6276,25 @@ asUINT asCCompiler::ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataT return asCC_CONST_CONV; } -asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) +asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) { asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken || - ctx->type.dataType.IsNullHandle() ); + ctx->type.dataType.IsNullHandle() || + ctx->IsAnonymousInitList() ); - if( to.GetFuncDef() && ctx->IsLambda() ) - { + if( to.IsFuncdef() && ctx->IsLambda() ) return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode); + + if (ctx->IsAnonymousInitList()) + { + if (to.GetBehaviour() && to.GetBehaviour()->listFactory) + { + if (generateCode) + CompilerAnonymousInitList(ctx->exprNode, ctx, to); + else + ctx->type.dataType = to; + } + return asCC_NO_CONV; } // No conversion from void to any other type @@ -6099,14 +6327,14 @@ asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &t { if( ctx->type.dataType.IsPrimitive() ) return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct); - else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() ) + else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() ) return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct); } return asCC_NO_CONV; } -asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) +asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) { if( ctx->type.isExplicitHandle ) { @@ -6125,7 +6353,7 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC // Find matching value cast behaviours // Here we're only interested in those that convert the type to a primitive type asCArray funcs; - asCObjectType *ot = ctx->type.dataType.GetObjectType(); + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); if( ot == 0 ) { if( convType != asIC_IMPLICIT_CONV && node ) @@ -6281,8 +6509,8 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC asCDataType toRef(to); toRef.MakeReference(true); toRef.MakeReadOnly(false); - asCArray args; - asSExprContext arg(engine); + asCArray args; + asCExprContext arg(engine); // Don't mark the variable as temporary, so it won't be freed too early arg.type.SetVariable(toRef, stackOffset, false); arg.type.isLValue = true; @@ -6290,7 +6518,7 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC args.PushLast(&arg); // Call the behaviour method - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node); + MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); // Use the reference to the variable as the result of the expression // Now we can mark the variable as temporary @@ -6314,7 +6542,7 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC } -asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) +asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) { // Convert null to any object type handle, but not to a non-handle type if( ctx->type.IsNullConstant() && ctx->methodName == "" ) @@ -6327,47 +6555,47 @@ asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType return asCC_NO_CONV; } - asASSERT(ctx->type.dataType.GetObjectType() || ctx->methodName != ""); + asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != ""); // First attempt to convert the base type without instantiating another instance - if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && ctx->methodName == "" ) + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" ) { // If the to type is an interface and the from type implements it, then we can convert it immediately - if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) ) + if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) ) { - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); return asCC_REF_CONV; } // If the to type is a class and the from type derives from it, then we can convert it immediately - else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) ) + else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) ) { - ctx->type.dataType.SetObjectType(to.GetObjectType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); return asCC_REF_CONV; } // If the types are not equal yet, then we may still be able to find a reference cast - else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() ) + else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() ) { // We may still be able to find an implicit ref cast behaviour CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode); // Was the conversion done? - if( ctx->type.dataType.GetObjectType() == to.GetObjectType() ) + if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() ) return asCC_REF_CONV; } } // Convert matching function types - if( to.GetFuncDef() ) + if( to.IsFuncdef() ) { // If the input expression is already a funcdef, check if it can be converted - if( ctx->type.dataType.GetFuncDef() && - to.GetFuncDef() != ctx->type.dataType.GetFuncDef() ) + if( ctx->type.dataType.IsFuncdef() && + to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) { - asCScriptFunction *toFunc = to.GetFuncDef(); - asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef(); + asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef; + asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef; if( toFunc->IsSignatureExceptNameEqual(fromFunc) ) { - ctx->type.dataType.SetFuncDef(toFunc); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); return asCC_REF_CONV; } } @@ -6399,10 +6627,11 @@ asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); // Check if any of the functions have perfect match + asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef; for( asUINT n = 0; n < funcs.GetLength(); n++ ) { asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]); - if( to.GetFuncDef()->IsSignatureExceptNameEqual(func) ) + if( toFunc->IsSignatureExceptNameEqual(func) ) { if( generateCode ) { @@ -6417,7 +6646,7 @@ asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType } } - ctx->type.dataType = asCDataType::CreateFuncDef(to.GetFuncDef()); + ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false); return asCC_REF_CONV; } } @@ -6427,16 +6656,16 @@ asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType return asCC_NO_CONV; } -asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) +asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) { asUINT cost = asCC_NO_CONV; // If the base type is still different, and we are allowed to instance // another object then we can try an implicit value cast - if( to.GetObjectType() != ctx->type.dataType.GetObjectType() ) + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) { // TODO: Implement support for implicit constructor/factory - asCObjectType *ot = ctx->type.dataType.GetObjectType(); + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); if( ot == 0 ) return cost; @@ -6450,7 +6679,7 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy // accept both implicit and explicit cast if( (func->name == "opConv" || func->name == "opImplConv") && - func->returnType.GetObjectType() == to.GetObjectType() && + func->returnType.GetTypeInfo() == to.GetTypeInfo() && func->parameterTypes.GetLength() == 0 ) funcs.PushLast(ot->methods[n]); } @@ -6463,7 +6692,7 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy // accept only implicit cast if( func->name == "opImplConv" && - func->returnType.GetObjectType() == to.GetObjectType() && + func->returnType.GetTypeInfo() == to.GetTypeInfo() && func->parameterTypes.GetLength() == 0 ) funcs.PushLast(ot->methods[n]); } @@ -6538,7 +6767,7 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy // Pass the reference of that variable to the function as output parameter asCDataType toRef(to); toRef.MakeReference(false); - asSExprContext arg(engine); + asCExprContext arg(engine); arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset); // If this an object on the heap, the pointer must be dereferenced @@ -6550,14 +6779,14 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy arg.type.isLValue = true; arg.exprNode = node; - // Mark the argument as clean, so that MakeFunctionCall knows it + // Mark the argument as clean, so that MakeFunctionCall knows it // doesn't have to make a copy of it in order to protect the value arg.isCleanArg = true; // Call the behaviour method - asCArray args; + asCArray args; args.PushLast(&arg); - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node); + MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); // Use the reference to the variable as the result of the expression // Now we can mark the variable as temporary @@ -6576,19 +6805,19 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy return cost; } -asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) +asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) { // First try a ref cast asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode); // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly // construct the object through any of the available constructors - if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct ) + if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct ) { asCArray funcs; - funcs = to.GetObjectType()->beh.constructors; + funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors; - asCArray args; + asCArray args; args.PushLast(ctx); cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false); @@ -6619,7 +6848,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat // TODO: This should really reuse the code from CompileConstructCall // Allocate the new object - asCTypeInfo tempObj; + asCExprValue tempObj; tempObj.dataType = to; tempObj.dataType.MakeReference(false); tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true); @@ -6630,7 +6859,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat bool onHeap = IsVariableOnHeap(tempObj.stackOffset); // Push the address of the object on the stack - asSExprContext e(engine); + asCExprContext e(engine); if( onHeap ) e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); @@ -6649,7 +6878,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat else e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType()); + PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); // Add tag that the object has been initialized e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); @@ -6668,14 +6897,14 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat } else { - ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false)); + ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false)); } } } // If the base type is still different, and we are allowed to instance // another object then we can try an implicit value cast - if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct ) + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct ) { // Attempt implicit value cast cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode); @@ -6683,7 +6912,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat // If we still haven't converted the base type to the correct type, then there is // no need to continue as it is not possible to do the conversion - if( to.GetObjectType() != ctx->type.dataType.GetObjectType() ) + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) return asCC_NO_CONV; @@ -6698,13 +6927,25 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat // reference -> reference to handle // object -> reference to handle - // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype - - // If the rvalue is a handle to a const object, then - // the lvalue must also be a handle to a const object - if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() ) + if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) || + (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) ) { - if( convType != asIC_IMPLICIT_CONV ) + // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const + // TODO: NEWSTRING: Should have an engine property to warn or error on this + if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType)) + { + if (generateCode) + PrepareTemporaryVariable(node, ctx); + else + { + ctx->type.dataType.MakeReadOnly(false); + ctx->type.isConstant = false; + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + else if( convType != asIC_IMPLICIT_CONV ) { asASSERT(node); asCString str; @@ -6755,7 +6996,10 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat if( ctx->type.dataType.IsReference() ) ctx->bc.Instr(asBC_RDSPtr); ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType()); + if (dt.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo()); ctx->bc.Instr(asBC_PopPtr); ctx->bc.InstrSHORT(asBC_PSF, (short)offset); @@ -6806,7 +7050,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat // If the object already is a temporary variable, then the copy // doesn't have to be made as it is already a unique object - PrepareTemporaryObject(node, ctx); + PrepareTemporaryVariable(node, ctx); ctx->type.dataType.MakeReadOnly(typeIsReadOnly); ctx->type.isExplicitHandle = isExplicitHandle; @@ -6862,7 +7106,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat if( generateCode ) { // Make a temporary object with the copy - PrepareTemporaryObject(node, ctx); + PrepareTemporaryVariable(node, ctx); } // In case the object was already in a temporary variable, then the function @@ -6900,7 +7144,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat if( ctx->type.dataType.IsReference() ) { - if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ) + if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) { // ASHANDLE objects are really value types, so explicit handle can be removed ctx->type.isExplicitHandle = false; @@ -6919,7 +7163,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat // A reference to a non-const can be converted to a reference to a const if( to.IsReadOnly() ) ctx->type.dataType.MakeReadOnly(true); - else if( ctx->type.dataType.IsReadOnly() ) + else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct ) { // A reference to a const can be converted to a reference to a // non-const by copying the object to a temporary variable @@ -6929,7 +7173,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat { // If the object already is a temporary variable, then the copy // doesn't have to be made as it is already a unique object - PrepareTemporaryObject(node, ctx); + PrepareTemporaryVariable(node, ctx); } // Add the cost for the copy @@ -6964,7 +7208,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat // A value type allocated on the stack is differentiated // by it not being a reference. But it can be handled as // reference by pushing the pointer on the stack - if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && + if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && (ctx->type.isVariable || ctx->type.isTemporary) && !IsVariableOnHeap(ctx->type.stackOffset) ) { @@ -6983,7 +7227,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat // If the object already is a temporary variable, then the copy // doesn't have to be made as it is already a unique object - PrepareTemporaryObject(node, ctx); + PrepareTemporaryVariable(node, ctx); ctx->type.dataType.MakeReadOnly(typeIsReadOnly); @@ -6997,9 +7241,45 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset)); } - // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made - // Since it is a new temporary variable it doesn't have to be const - ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); + if (to.IsReadOnly()) + { + // This doesn't cost anything + ctx->type.dataType.MakeReadOnly(true); + } + + if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly()) + { + // A const object can be converted to a non-const object through a copy + if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST) + { + ctx->type.dataType.MakeReadOnly(false); + + if (generateCode) + { + // Make a temporary copy of the object in order to make it non-const + PrepareTemporaryVariable(node, ctx); + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + + // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const + // TODO: NEWSTRING: Should have an engine property to warn or error on this + if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType)) + { + if (generateCode) + PrepareTemporaryVariable(node, ctx); + else + { + ctx->type.dataType.MakeReadOnly(false); + ctx->type.isConstant = false; + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + } } } } @@ -7007,12 +7287,12 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat return cost; } -asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/) +asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/) { // Reference types currently don't allow implicit conversion from primitive to object // TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types - asCObjectType *objType = to.GetObjectType(); - asASSERT( objType ); + asCObjectType *objType = CastToObjectType(to.GetTypeInfo()); + asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) ); if( !objType || (objType->flags & asOBJ_REF) ) return asCC_NO_CONV; @@ -7033,10 +7313,10 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asC return asCC_NO_CONV; // Check if it is possible to choose a best match - asSExprContext arg(engine); + asCExprContext arg(engine); arg.type = ctx->type; arg.exprNode = ctx->exprNode; // Use the same node for compiler messages - asCArray args; + asCArray args; args.PushLast(&arg); asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false); if( funcs.GetLength() != 1 ) @@ -7054,7 +7334,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asC ctx->type.SetDummy(); // Value types and script types are allocated through the constructor - asCTypeInfo tempObj; + asCExprValue tempObj; tempObj.dataType = to; tempObj.stackOffset = (short)AllocateVariable(to, true); tempObj.dataType.MakeReference(true); @@ -7085,7 +7365,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asC else ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType()); + PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); // Add tag that the object has been initialized ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); @@ -7111,7 +7391,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asC return cost; } -void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType) +void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType) { asASSERT(from->type.isConstant); @@ -7133,11 +7413,17 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData from->type.dataType.IsUnsignedType() || from->type.dataType.IsIntegerType() ) { + asCDataType targetDt; + if (to.IsEnumType()) + targetDt = to; + else + targetDt = asCDataType::CreatePrimitive(ttInt, true); + // Transform the value // Float constants can be implicitly converted to int if( from->type.dataType.IsFloatType() ) { - float fc = from->type.floatValue; + float fc = from->type.GetConstantF(); int ic = int(fc); if( float(ic) != fc ) @@ -7145,12 +7431,12 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.intValue = ic; + from->type.SetConstantDW(targetDt, ic); } // Double constants can be implicitly converted to int else if( from->type.dataType.IsDoubleType() ) { - double fc = from->type.doubleValue; + double fc = from->type.GetConstantD(); int ic = int(fc); if( double(ic) != fc ) @@ -7158,42 +7444,60 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.intValue = ic; + from->type.SetConstantDW(targetDt, ic); } else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) { // Verify that it is possible to convert to signed without getting negative - if( from->type.intValue < 0 ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); - } + if( from->type.dataType.GetSizeInMemoryBytes() == 4 && + int(from->type.GetConstantDW()) < 0 && + convType != asIC_EXPLICIT_VAL_CAST && + node != 0 ) + Warning(TXT_CHANGE_SIGN, node); // Convert to 32bit if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.intValue = from->type.byteValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.intValue = from->type.wordValue; + from->type.SetConstantDW(targetDt, from->type.GetConstantB()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 2) + from->type.SetConstantDW(targetDt, from->type.GetConstantW()); + else + from->type.dataType = targetDt; } else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) { + if (asQWORD(from->type.GetConstantQW()) >> 31) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + // Convert to 32bit - from->type.intValue = int(from->type.qwordValue); + from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW())); } - else if( from->type.dataType.IsIntegerType() && - from->type.dataType.GetSizeInMemoryBytes() < 4 ) + else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2) + { + if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW())) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + // Convert to 32bit + from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW())); + } + else if (from->type.dataType.IsIntegerType() && + from->type.dataType.GetSizeInMemoryBytes() < 4) { // Convert to 32bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.intValue = (signed char)from->type.byteValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.intValue = (short)from->type.wordValue; + if (from->type.dataType.GetSizeInMemoryBytes() == 1) + from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 2) + from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW()); } - - // Set the resulting type - if( to.IsEnumType() ) - from->type.dataType = to; else - from->type.dataType = asCDataType::CreatePrimitive(ttInt, true); + { + // Only int32 and enums should come here and as these are 32bit + // already nothing needs to be done except set the target type + asASSERT((from->type.dataType.GetTokenType() == ttInt || + from->type.dataType.IsEnumType()) && + from->type.dataType.GetSizeInMemoryBytes() == 4); + + from->type.dataType = targetDt; + } } // Check if a downsize is necessary @@ -7204,20 +7508,18 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData // Verify if it is possible if( to.GetSizeInMemoryBytes() == 1 ) { - if( char(from->type.intValue) != from->type.intValue ) + if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) ) if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - from->type.byteValue = char(from->type.intValue); + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW())); } else if( to.GetSizeInMemoryBytes() == 2 ) { - if( short(from->type.intValue) != from->type.intValue ) + if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) ) if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - from->type.wordValue = short(from->type.intValue); + from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW())); } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); } } else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 ) @@ -7225,7 +7527,7 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData // Float constants can be implicitly converted to int if( from->type.dataType.IsFloatType() ) { - float fc = from->type.floatValue; + float fc = from->type.GetConstantF(); asINT64 ic = asINT64(fc); if( float(ic) != fc ) @@ -7233,13 +7535,12 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); - from->type.qwordValue = ic; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic); } // Double constants can be implicitly converted to int else if( from->type.dataType.IsDoubleType() ) { - double fc = from->type.doubleValue; + double fc = from->type.GetConstantD(); asINT64 ic = asINT64(fc); if( double(ic) != fc ) @@ -7247,46 +7548,42 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); - from->type.qwordValue = ic; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic); } else if( from->type.dataType.IsUnsignedType() ) { // Convert to 64bit if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.qwordValue = from->type.byteValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB()); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.qwordValue = from->type.wordValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW()); else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.qwordValue = from->type.dwordValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW()); else if( from->type.dataType.GetSizeInMemoryBytes() == 8 ) { - if( asINT64(from->type.qwordValue) < 0 ) + if( asINT64(from->type.GetConstantQW()) < 0 ) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); } + from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); } - - from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); } else if( from->type.dataType.IsIntegerType() ) { // Convert to 64bit if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.qwordValue = (signed char)from->type.byteValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB()); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.qwordValue = (short)from->type.wordValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW()); else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.qwordValue = from->type.intValue; - - from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW()); } } else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 ) { if( from->type.dataType.IsFloatType() ) { - float fc = from->type.floatValue; + float fc = from->type.GetConstantF(); // Some compilers set the value to 0 when converting a negative float to unsigned int. // To maintain a consistent behaviour across compilers we convert to int first. asUINT uic = asUINT(int(fc)); @@ -7296,15 +7593,14 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true); - from->type.intValue = uic; + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic); // Try once more, in case of a smaller type ImplicitConversionConstant(from, to, node, convType); } else if( from->type.dataType.IsDoubleType() ) { - double fc = from->type.doubleValue; + double fc = from->type.GetConstantD(); // Some compilers set the value to 0 when converting a negative double to unsigned int. // To maintain a consistent behaviour across compilers we convert to int first. asUINT uic = asUINT(int(fc)); @@ -7314,8 +7610,7 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true); - from->type.intValue = uic; + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic); // Try once more, in case of a smaller type ImplicitConversionConstant(from, to, node, convType); @@ -7323,25 +7618,29 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData else if( from->type.dataType.IsIntegerType() ) { // Verify that it is possible to convert to unsigned without loosing negative - if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.qwordValue) < 0) || - (from->type.dataType.GetSizeInMemoryBytes() <= 4 && from->type.intValue < 0) ) + if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0)) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); } // Check if any data is lost - if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.qwordValue >> 32) != 0 && (from->type.qwordValue >> 32) != 0xFFFFFFFF ) + if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF ) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); } // Convert to 32bit if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.intValue = (signed char)from->type.byteValue; + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB()); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.intValue = (short)from->type.wordValue; - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true); + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW()); + else + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW()); // Try once more, in case of a smaller type ImplicitConversionConstant(from, to, node, convType); @@ -7351,11 +7650,9 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData { // Convert to 32bit if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.dwordValue = from->type.byteValue; + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB()); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.dwordValue = from->type.wordValue; - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true); + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW()); // Try once more, in case of a smaller type ImplicitConversionConstant(from, to, node, convType); @@ -7366,27 +7663,32 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData // Verify if it is possible if( to.GetSizeInMemoryBytes() == 1 ) { - if( asBYTE(from->type.dwordValue) != from->type.dwordValue ) + if( asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW() ) if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - from->type.byteValue = asBYTE(from->type.dwordValue); + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW())); } else if( to.GetSizeInMemoryBytes() == 2 ) { - if( asWORD(from->type.dwordValue) != from->type.dwordValue ) + if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - from->type.wordValue = asWORD(from->type.dwordValue); + from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW())); } + else if (to.GetSizeInMemoryBytes() == 4) + { + if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); + from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW())); + } } } else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 ) { if( from->type.dataType.IsFloatType() ) { - float fc = from->type.floatValue; + float fc = from->type.GetConstantF(); // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers asQWORD uic = asQWORD(asINT64(fc)); @@ -7398,12 +7700,11 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData } #endif - from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); - from->type.qwordValue = uic; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic); } else if( from->type.dataType.IsDoubleType() ) { - double fc = from->type.doubleValue; + double fc = from->type.GetConstantD(); // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers asQWORD uic = asQWORD(asINT64(fc)); @@ -7415,21 +7716,20 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData } #endif - from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); - from->type.qwordValue = uic; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic); } else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) { // Convert to 64bit if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.qwordValue = (asINT64)(signed char)from->type.byteValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB()); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.qwordValue = (asINT64)(short)from->type.wordValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW()); else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.qwordValue = (asINT64)from->type.intValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW()); // Verify that it is possible to convert to unsigned without loosing negative - if( asINT64(from->type.qwordValue) < 0 ) + if( asINT64(from->type.GetConstantQW()) < 0 ) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); } @@ -7439,7 +7739,7 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) { // Verify that it is possible to convert to unsigned without loosing negative - if( asINT64(from->type.qwordValue) < 0 ) + if( asINT64(from->type.GetConstantQW()) < 0 ) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); } @@ -7450,35 +7750,32 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData { // Convert to 64bit if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.qwordValue = from->type.byteValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB()); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.qwordValue = from->type.wordValue; + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW()); else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.qwordValue = from->type.dwordValue; - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW()); } } else if( to.IsFloatType() ) { if( from->type.dataType.IsDoubleType() ) { - double ic = from->type.doubleValue; + double ic = from->type.GetConstantD(); float fc = float(ic); - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = fc; + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) { // Must properly convert value in case the from value is smaller int ic; if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - ic = (signed char)from->type.byteValue; + ic = (asINT8)from->type.GetConstantB(); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - ic = (short)from->type.wordValue; + ic = (asINT16)from->type.GetConstantW(); else - ic = from->type.intValue; + ic = (int)from->type.GetConstantDW(); float fc = float(ic); if( int(fc) != ic ) @@ -7486,30 +7783,28 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = fc; + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) { - float fc = float(asINT64(from->type.qwordValue)); - if( asINT64(fc) != asINT64(from->type.qwordValue) ) + float fc = float(asINT64(from->type.GetConstantQW())); + if( asINT64(fc) != asINT64(from->type.GetConstantQW()) ) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = fc; + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) { // Must properly convert value in case the from value is smaller unsigned int uic; if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - uic = from->type.byteValue; + uic = from->type.GetConstantB(); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - uic = from->type.wordValue; + uic = from->type.GetConstantW(); else - uic = from->type.dwordValue; + uic = from->type.GetConstantDW(); float fc = float(uic); if( (unsigned int)(fc) != uic ) @@ -7517,42 +7812,39 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = fc; + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) { - float fc = float((asINT64)from->type.qwordValue); + float fc = float((asINT64)from->type.GetConstantQW()); - if( asQWORD(fc) != from->type.qwordValue ) + if( asQWORD(fc) != from->type.GetConstantQW()) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = fc; + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } } else if( to.IsDoubleType() ) { if( from->type.dataType.IsFloatType() ) { - float ic = from->type.floatValue; + float ic = from->type.GetConstantF(); double fc = double(ic); - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = fc; + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) { // Must properly convert value in case the from value is smaller int ic; if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - ic = (signed char)from->type.byteValue; + ic = (asINT8)from->type.GetConstantB(); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - ic = (short)from->type.wordValue; + ic = (asINT16)from->type.GetConstantW(); else - ic = from->type.intValue; + ic = (int)from->type.GetConstantDW(); double fc = double(ic); if( int(fc) != ic ) @@ -7560,31 +7852,29 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = fc; + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) { - double fc = double(asINT64(from->type.qwordValue)); + double fc = double(asINT64(from->type.GetConstantQW())); - if( asINT64(fc) != asINT64(from->type.qwordValue) ) + if( asINT64(fc) != asINT64(from->type.GetConstantQW()) ) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = fc; + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) { // Must properly convert value in case the from value is smaller unsigned int uic; if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - uic = from->type.byteValue; + uic = from->type.GetConstantB(); else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - uic = from->type.wordValue; + uic = from->type.GetConstantW(); else - uic = from->type.dwordValue; + uic = from->type.GetConstantDW(); double fc = double(uic); if( (unsigned int)(fc) != uic ) @@ -7592,25 +7882,23 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = fc; + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) { - double fc = double((asINT64)from->type.qwordValue); + double fc = double((asINT64)from->type.GetConstantQW()); - if( asQWORD(fc) != from->type.qwordValue ) + if( asQWORD(fc) != from->type.GetConstantQW()) { if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); } - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = fc; + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); } } } -int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode) +int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode) { // Don't allow any operators on expressions that take address of class method // If methodName is set but the type is not an object, then it is a global function @@ -7621,7 +7909,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr } // Implicit handle types should always be treated as handles in assignments - if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) ) + if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) ) { lctx->type.dataType.MakeHandle(true); lctx->type.isExplicitHandle = true; @@ -7678,7 +7966,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr if( op != ttAssignment ) { // Compute the operator before the assignment - asCTypeInfo lvalue = lctx->type; + asCExprValue lvalue = lctx->type; if( lctx->type.isTemporary && !lctx->type.isVariable ) { @@ -7688,7 +7976,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr lctx->type.isTemporary = false; } - asSExprContext o(engine); + asCExprContext o(engine); CompileOperator(opNode, lctx, rctx, &o); MergeExprBytecode(rctx, &o); rctx->type = o.type; @@ -7733,13 +8021,13 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr return -1; } - if( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ) + if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) { // The object is a value type but that should be treated as a handle // Make sure the right hand value is a handle if( !rctx->type.isExplicitHandle && - !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ) + !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ) { // Function names can be considered handles already if( rctx->methodName == "" ) @@ -7757,9 +8045,14 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr return -1; } } + + // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise + // the code for moving the argument to the stack may not know to correctly handle the argument type + // in case of variable parameter type. + rctx->type.isExplicitHandle = true; } - if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx, true) ) + if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) ) { // An overloaded assignment operator was found (or a compilation error occured) return 0; @@ -7776,7 +8069,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr asCDataType dt = lctx->type.dataType; dt.MakeReference(false); - PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF , true); + PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true); if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) { asCString str; @@ -7816,7 +8109,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr } // Check for overloaded assignment operator - if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) ) + if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) ) { // An overloaded assignment operator was found (or a compilation error occured) return 0; @@ -7844,7 +8137,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr // the application developer is responsible for making the // implementation safe against unwanted destruction of the input // reference before the time. - bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression(); + bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression(); // Implicitly convert the rvalue to the type of the lvalue bool needConversion = false; @@ -7903,13 +8196,15 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr return 0; } -int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx) +int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx) { + asASSERT(expr->nodeType == snAssignment); + asCScriptNode *lexpr = expr->firstChild; if( lexpr->next ) { // Compile the two expression terms - asSExprContext lctx(engine), rctx(engine); + asCExprContext lctx(engine), rctx(engine); int rr = CompileAssignment(lexpr->next->next, &rctx); int lr = CompileCondition(lexpr, &lctx); @@ -7924,9 +8219,9 @@ int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx) return CompileCondition(lexpr, ctx); } -int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) +int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) { - asCTypeInfo ctype; + asCExprValue ctype; // Compile the conditional expression asCScriptNode *cexpr = expr->firstChild; @@ -7934,13 +8229,13 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) { //------------------------------- // Compile the condition - asSExprContext e(engine); + asCExprContext e(engine); int r = CompileExpression(cexpr, &e); if( r < 0 ) e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); // Allow value types to be converted to bool using 'bool opImplConv()' - if( e.type.dataType.GetObjectType() && (e.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) ) + if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV); if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) @@ -7957,13 +8252,17 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) //------------------------------- // Compile the left expression - asSExprContext le(engine); + asCExprContext le(engine); int lr = CompileAssignment(cexpr->next, &le); + // Resolve any function names already + DetermineSingleFunc(&le, cexpr->next); + //------------------------------- // Compile the right expression - asSExprContext re(engine); + asCExprContext re(engine); int rr = CompileAssignment(cexpr->next->next, &re); + DetermineSingleFunc(&re, cexpr->next->next); if( lr >= 0 && rr >= 0 ) { @@ -7980,7 +8279,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) 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.intValue == 0 && le.type.dataType.IsIntegerType() ) + if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() ) { asCDataType to = re.type.dataType; to.MakeReference(false); @@ -8036,6 +8335,24 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) // Set the type of the result ctx->type = le.type; } + else if (le.type.IsNullConstant() && re.type.IsNullConstant()) + { + // Special case for when both results are 'null' + // TODO: Other expressions where both results are identical literal constants can probably also be handled this way + + // Put the code for the condition expression on the output + MergeExprBytecode(ctx, &e); + + // Load the result into the register, but ignore the value since both paths give the same response + ctx->type = e.type; + ConvertToVariable(ctx); + ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + // Return a null constant + ctx->bc.Instr(asBC_PshNull); + ctx->type.SetNullConstant(); + } else { // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference) @@ -8046,12 +8363,12 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) // that would have to be cleaned up after the reference // 3. neither expression can be temporary // - // If either expression is local, the resulting lvalue is not valid - // for return since it is not allowed to return references to local + // If either expression is local, the resulting lvalue is not valid + // for return since it is not allowed to return references to local // variables. // // The reference to the local variable must be loaded into the register, - // the resulting expression must not be considered as a local variable + // the resulting expression must not be considered as a local variable // with a stack offset (i.e. it will not be allowed to use asBC_VAR) if( le.type.isLValue && re.type.isLValue && @@ -8092,7 +8409,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) ctx->bc.Label((short)afterLabel); - // In case the options were to objects, it is necessary to dereference the pointer on + // In case the options were to objects, it is necessary to dereference the pointer on // the stack so it will point to the actual object, instead of the variable if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() ) { @@ -8114,12 +8431,12 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) ctx->type.isTemporary = false; // Must remember if the reference was to a local variable, since it must not be allowed to be returned - ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal; + ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal; } else { // Allocate temporary variable and copy the result to that one - asCTypeInfo temp; + asCExprValue temp; temp = le.type; temp.dataType.MakeReference(false); temp.dataType.MakeReadOnly(false); @@ -8135,7 +8452,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) temp.SetVariable(temp.dataType, offset, true); - // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject() + // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable() CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr); @@ -8151,7 +8468,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) ReleaseTemporaryVariable(ctx->type, &ctx->bc); // Assign the result of the left expression to the temporary variable - asCTypeInfo rtemp; + asCExprValue rtemp; rtemp = temp; if( rtemp.dataType.IsObjectHandle() ) rtemp.isExplicitHandle = true; @@ -8164,7 +8481,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) ctx->bc.InstrSHORT(asBC_PSF, (short)offset); rtemp.dataType.MakeReference(IsVariableOnHeap(offset)); } - asCTypeInfo result; + asCExprValue result; result = rtemp; PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next); if( !result.dataType.IsPrimitive() ) @@ -8228,50 +8545,10 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) return 0; } -int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx) +int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx) { asASSERT(expr->nodeType == snExpression); - // Check if this is an initialization of a temp object with an initialization list - if( expr->firstChild && expr->firstChild->nodeType == snDataType ) - { - // TODO: It should be possible to infer the type of the object from where the - // expression will be used. The compilation of the initialization list - // should be deferred until it is known for what it will be used. It will - // then for example be possible to write expressions like: - // - // @dict = {{'key', 'value'}}; - // funcTakingArrayOfInt({1,2,3,4}); - - // Determine the type of the temporary object - asCDataType dt = builder->CreateDataTypeFromNode(expr->firstChild, script, outFunc->nameSpace); - - // Do not allow constructing non-shared types in shared functions - if( outFunc->IsShared() && - dt.GetObjectType() && !dt.GetObjectType()->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf()); - Error(msg, expr); - } - - // Allocate and initialize the temporary object - int offset = AllocateVariable(dt, true); - CompileInitialization(expr->lastChild, &ctx->bc, dt, expr, offset, 0, 0); - - // Push the reference to the object on the stack - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - ctx->type.SetVariable(dt, offset, true); - ctx->type.isLValue = false; - - // If the variable is allocated on the heap we have a reference, - // otherwise the actual object pointer is pushed on the stack. - if( IsVariableOnHeap(offset) ) - ctx->type.dataType.MakeReference(true); - - return 0; - } - // Convert to polish post fix, i.e: a+b => ab+ asCArray postfix; ConvertToPostFix(expr, postfix); @@ -8317,7 +8594,7 @@ void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray *postfix, asSExprContext *ctx) +int asCCompiler::CompilePostFixExpression(asCArray *postfix, asCExprContext *ctx) { // Shouldn't send any byte code asASSERT(ctx->bc.GetLastInstr() == -1); @@ -8327,26 +8604,26 @@ int asCCompiler::CompilePostFixExpression(asCArray *postfix, as ctx->type.SetDummy(); // Evaluate the operands and operators - asCArray free; - asCArray expr; + asCArray free; + asCArray expr; int ret = 0; for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ ) { asCScriptNode *node = (*postfix)[n]; if( node->nodeType == snExprTerm ) { - asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine); + asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine); expr.PushLast(e); e->exprNode = node; ret = CompileExpressionTerm(node, e); } else { - asSExprContext *r = expr.PopLast(); - asSExprContext *l = expr.PopLast(); + asCExprContext *r = expr.PopLast(); + asCExprContext *l = expr.PopLast(); // Now compile the operator - asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine); + asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine); ret = CompileOperator(node, l, r, e); expr.PushLast(e); @@ -8369,18 +8646,67 @@ int asCCompiler::CompilePostFixExpression(asCArray *postfix, as // Clean up for( asUINT e = 0; e < expr.GetLength(); e++ ) - asDELETE(expr[e], asSExprContext); + asDELETE(expr[e], asCExprContext); for( asUINT f = 0; f < free.GetLength(); f++ ) - asDELETE(free[f], asSExprContext); + asDELETE(free[f], asCExprContext); return ret; } -int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx) +int asCCompiler::CompilerAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt) +{ + asASSERT(node->nodeType == snInitList); + + // Do not allow constructing non-shared types in shared functions + if (outFunc->IsShared() && + dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared()) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + Error(msg, node); + } + + // Allocate and initialize the temporary object + int offset = AllocateVariable(dt, true); + CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0); + + // Push the reference to the object on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + ctx->type.SetVariable(dt, offset, true); + ctx->type.isLValue = false; + + // If the variable is allocated on the heap we have a reference, + // otherwise the actual object pointer is pushed on the stack. + if (IsVariableOnHeap(offset)) + ctx->type.dataType.MakeReference(true); + + return 0; +} + +int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx) { // Shouldn't send any byte code asASSERT(ctx->bc.GetLastInstr() == -1); + // Check if this is an initialization of a temp object with an initialization list + if (node->firstChild ) + { + if (node->firstChild->nodeType == snDataType) + { + // Determine the type of the temporary object + asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); + + return CompilerAnonymousInitList(node->lastChild, ctx, dt); + } + else if (node->firstChild->nodeType == snInitList) + { + // As the type is not yet known, the init list will be compiled at a + // later time when the type can be determined from the destination + ctx->SetAnonymousInitList(node->firstChild); + return 0; + } + } + // Set the type as a dummy by default, in case of any compiler errors ctx->type.SetDummy(); @@ -8389,7 +8715,7 @@ int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx) while( vnode->nodeType != snExprValue ) vnode = vnode->next; - asSExprContext v(engine); + asCExprContext v(engine); int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r; // Compile post fix operators @@ -8414,7 +8740,7 @@ int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx) return 0; } -int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType) +int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType) { bool found = false; @@ -8428,7 +8754,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s found = true; if( v->isPureConstant ) - ctx->type.SetConstantQW(v->type, v->constantValue); + ctx->type.SetConstantData(v->type, v->constantValue); else if( v->type.IsPrimitive() ) { if( v->type.IsReference() ) @@ -8441,7 +8767,9 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s else ctx->type.SetVariable(v->type, v->stackOffset, false); - ctx->type.isLValue = true; + // Set as lvalue unless it is a const variable + if( !v->type.IsReadOnly() ) + ctx->type.isLValue = true; } else { @@ -8456,7 +8784,14 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) ) ctx->bc.Instr(asBC_RDSPtr); - ctx->type.isLValue = true; + // Mark the object as safe for access unless it is a handle, as the + // life time of the object is guaranteed throughout the scope. + if( !v->type.IsObjectHandle() ) + ctx->type.isHandleSafe = true; + + // Set as lvalue unless it is a const variable + if (!v->type.IsReadOnly()) + ctx->type.isLValue = true; } } @@ -8466,7 +8801,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s { if( name == THIS_TOKEN && !objType ) { - asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly); + asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()); // The object pointer is located at stack position 0 ctx->bc.InstrSHORT(asBC_PSF, 0); @@ -8474,23 +8809,26 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s ctx->type.dataType.MakeReference(true); ctx->type.isLValue = true; + // The 'this' handle is always considered safe (i.e. life time guaranteed) + ctx->type.isHandleSafe = true; + found = true; } if( !found ) { // See if there are any matching property accessors - asSExprContext access(engine); + asCExprContext access(engine); if( objType ) - access.type.Set(asCDataType::CreateObject(objType, false)); + access.type.Set(asCDataType::CreateType(objType, false)); else - access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly)); + access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly())); access.type.dataType.MakeReference(true); int r = 0; if( errNode->next && errNode->next->tokenType == ttOpenBracket ) { // This is an index access, check if there is a property accessor that takes an index arg - asSExprContext dummyArg(engine); + asCExprContext dummyArg(engine); r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true); } if( r == 0 ) @@ -8517,9 +8855,9 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s { asCDataType dt; if( objType ) - dt = asCDataType::CreateObject(objType, false); + dt = asCDataType::CreateType(objType, false); else - dt = asCDataType::CreateObject(outFunc->objectType, false); + dt = asCDataType::CreateType(outFunc->objectType, false); asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf()); if( prop ) { @@ -8577,10 +8915,20 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s { // Objects that are members are not references ctx->type.dataType.MakeReference(false); + + // Objects that are members but not handles are safe as long as the parent object is safe + if (!objType || ctx->type.isHandleSafe) + ctx->type.isHandleSafe = true; + } + else if (ctx->type.dataType.IsObjectHandle()) + { + // Objects accessed through handles cannot be considered safe + // as the handle can be cleared at any time + ctx->type.isHandleSafe = false; } // If the object reference is const, the property will also be const - ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly); + ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly()); found = true; } @@ -8613,7 +8961,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s // The object pointer is located at stack position 0 // This is only done when accessing through the implicit this pointer ctx->bc.InstrSHORT(asBC_PSF, 0); - ctx->type.SetVariable(asCDataType::CreateObject(outFunc->objectType, false), 0, false); + ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false); ctx->type.dataType.MakeReference(true); Dereference(ctx, true); } @@ -8638,12 +8986,12 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s if( !found && ns ) { // See if there are any matching global property accessors - asSExprContext access(engine); + asCExprContext access(engine); int r = 0; if( errNode->next && errNode->next->tokenType == ttOpenBracket ) { // This is an index access, check if there is a property accessor that takes an index arg - asSExprContext dummyArg(engine); + asCExprContext dummyArg(engine); r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns); } if( r == 0 ) @@ -8675,7 +9023,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s // Verify that the global property has been compiled already if( isCompiled ) { - if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) ) + if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) ) { ctx->type.dataType.MakeHandle(true); ctx->type.isExplicitHandle = true; @@ -8685,8 +9033,8 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s // we can allow the compiler to optimize it. Pure // constants are global constant variables that were // initialized by literal constants. - if( isPureConstant ) - ctx->type.SetConstantQW(prop->type, constantValue); + if (isPureConstant) + ctx->type.SetConstantData(prop->type, constantValue); else { // A shared type must not access global vars, unless they @@ -8724,7 +9072,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s // This check is not needed for application registered properties, since they // are guaranteed to be valid by the application itself. if( !isAppProp && - ((ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) || + ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) || !ctx->type.dataType.IsObjectHandle()) ) { ctx->bc.Instr(asBC_ChkRefS); @@ -8733,14 +9081,14 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s // If the address pushed on the stack is to a value type or an object // handle, then mark the expression as a reference. Addresses to a reference // type aren't marked as references to get correct behaviour - if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) || + if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) || ctx->type.dataType.IsObjectHandle() ) { ctx->type.dataType.MakeReference(true); } else { - asASSERT( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() ); + asASSERT( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() ); // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object ctx->bc.Instr(asBC_RDSPtr); @@ -8781,27 +9129,17 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s if( !found ) { // The enum type may be declared in a namespace too - asCObjectType *scopeType = 0; + asCTypeInfo *scopeType = 0; if( currScope != "" && currScope != "::" ) { - // Use the last scope name as the enum type - asCString enumType = currScope; - asCString nsScope; - int p = currScope.FindLast("::"); - if( p != -1 ) - { - enumType = currScope.SubString(p+2); - nsScope = currScope.SubString(0, p); - } - - asSNameSpace *ns = engine->FindNameSpace(nsScope.AddressOf()); - if( ns ) - scopeType = builder->GetObjectType(enumType.AddressOf(), ns); + builder->GetNameSpaceByString(currScope, outFunc->objectType ? outFunc->objectType->nameSpace : outFunc->nameSpace, errNode, script, &scopeType, false); + if (CastToEnumType(scopeType) == 0) + scopeType = 0; } asDWORD value = 0; asCDataType dt; - if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) ) + if( scopeType && builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value) ) { // scoped enum value found found = true; @@ -8809,10 +9147,10 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s else if( !engine->ep.requireEnumScope ) { // Look for the enum value without explicitly informing the enum type - asSNameSpace *ns = DetermineNameSpace(currScope); + asSNameSpace *nsEnum = DetermineNameSpace(currScope); int e = 0; - if( ns ) - e = builder->GetEnumValue(name.AddressOf(), dt, value, ns); + if(nsEnum) + e = builder->GetEnumValue(name.AddressOf(), dt, value, nsEnum); if( e ) { found = true; @@ -8895,7 +9233,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true); // Mark the variable as initialized so that the user will not be bother by it again - sVariable *v = variables->GetVariable(name.AddressOf()); + v = variables->GetVariable(name.AddressOf()); asASSERT(v); if( v ) v->isInitialized = true; } @@ -8907,7 +9245,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s return 0; } -int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx) +int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx) { // Shouldn't receive any byte code asASSERT(ctx->bc.GetLastInstr() == -1); @@ -8931,7 +9269,17 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx { asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); - asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0); + bool overflow = false; + asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow); + + // Is the number bigger than a 64bit word? + if (overflow) + { + Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode); + + // Set the value to zero to avoid further warnings + val = 0; + } // Do we need 64 bits? // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid @@ -8952,8 +9300,17 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2 - // TODO: Check for overflow - asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0); + bool overflow = false; + asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow); + + // Is the number bigger than a 64bit word? + if (overflow) + { + Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode); + + // Set the value to zero to avoid further warnings + val = 0; + } // Do we need 64 bits? if( val>>32 ) @@ -9007,7 +9364,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2); asDWORD val = 0; - if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 ) + if( str.GetLength() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 ) { // This is the start of a UTF8 encoded character. We need to decode it val = asStringDecodeUTF8(str.AddressOf(), 0); @@ -9054,8 +9411,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx } // Call the string factory function to create a string object - asCScriptFunction *descr = engine->stringFactory; - if( descr == 0 ) + if(engine->stringFactory == 0 ) { // Error Error(TXT_STRINGS_NOT_RECOGNIZED, vnode); @@ -9066,21 +9422,27 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx } else { - // Register the constant string with the engine - int id = engine->AddConstantString(str.AddressOf(), str.GetLength()); - ctx->bc.InstrWORD(asBC_STR, (asWORD)id); - - bool useVariable = false; - int stackOffset = 0; - - if( descr->DoesReturnOnStack() ) + void *strPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength())); + if (strPtr == 0) { - useVariable = true; - stackOffset = AllocateVariable(descr->returnType, true); - ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset)); + // TODO: A better message is needed + Error(TXT_NULL_POINTER_ACCESS, vnode); + ctx->type.SetDummy(); + return -1; } - PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset); + // Keep the pointer in the list for clean up at exit + usedStringConstants.PushLast(strPtr); + + // Push the pointer on the stack. The string factory already guarantees that the + // string object is valid throughout the lifetime of the script so no need to add + // reference count or make local copy. + ctx->bc.InstrPTR(asBC_PGA, strPtr); + ctx->type.Set(engine->stringType); + + // Mark the string as literal constant so the compiler knows it is allowed + // to treat it differently than an ordinary constant string variable + ctx->type.isConstant = true; } } } @@ -9105,7 +9467,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx } else if( vnode->nodeType == snAssignment ) { - asSExprContext e(engine); + asCExprContext e(engine); int r = CompileAssignment(vnode, &e); if( r < 0 ) { @@ -9127,7 +9489,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx else if( vnode->nodeType == snFunction ) { // This is an anonymous function - // Defer the evaluation of the function until it known where it + // Defer the evaluation of the function until it known where it // will be used, which is where the signature will be defined ctx->SetLambda(vnode); } @@ -9333,11 +9695,14 @@ asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node) { // Remove first line if it only contains whitespace + bool isMultiline = false; int start; for( start = 0; start < (int)str.GetLength(); start++ ) { if( str[start] == '\n' ) { + isMultiline = true; + // Remove the linebreak as well start++; break; @@ -9377,21 +9742,29 @@ void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *no if( end < 0 ) end = 0; asCString tmp; - if( end > start ) - tmp.Assign(&str[start], end-start); + if (end > start || engine->ep.heredocTrimMode != 2 ) + { + // if heredocTrimMode == 0 the string shouldn't be trimmed + // if heredocTrimMode == 1 the string should only be trimmed if it is multiline + // if heredocTrimMode == 2 the string should always be trimmed + if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1)) + tmp.Assign(&str[start], end - start); + else + tmp = str; + } ProcessStringConstant(tmp, node, false); str = tmp; } -int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx) +int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx) { - asSExprContext expr(engine); + asCExprContext expr(engine); asCDataType to; bool anyErrors = false; EImplicitConv convType; - if( node->nodeType == snConstructCall ) + if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall ) { convType = asIC_EXPLICIT_VAL_CAST; @@ -9403,6 +9776,13 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx) expr.type.SetDummy(); anyErrors = true; } + else if (node->lastChild->firstChild && + node->lastChild->firstChild->nodeType == snNamedArgument) + { + Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild); + expr.type.SetDummy(); + anyErrors = true; + } else { // Compile the expression @@ -9445,10 +9825,10 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx) // Do not allow casting to non shared type if we're compiling a shared method if( outFunc->IsShared() && - to.GetObjectType() && !to.GetObjectType()->IsShared() ) + to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() ) { asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf()); + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf()); Error(msg, node); anyErrors = true; } @@ -9456,7 +9836,7 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx) if( anyErrors ) { // Assume that the error can be fixed and allow the compilation to continue - ctx->type.SetConstantDW(to, 0); + ctx->type.Set(to); return -1; } @@ -9537,9 +9917,9 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx) return -1; } -void asCCompiler::AfterFunctionCall(int funcID, asCArray &args, asSExprContext *ctx, bool deferAll) +void asCCompiler::AfterFunctionCall(int funcID, asCArray &args, asCExprContext *ctx, bool deferAll) { - // deferAll is set to true if for example the function returns a reference, since in + // deferAll is set to true if for example the function returns a reference, since in // this case the function might be returning a reference to one of the arguments. asCScriptFunction *descr = builder->GetFunctionDescription(funcID); @@ -9588,7 +9968,7 @@ void asCCompiler::AfterFunctionCall(int funcID, asCArray &args, } } -void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) +void asCCompiler::ProcessDeferredParams(asCExprContext *ctx) { if( isProcessingDeferredParams ) return; @@ -9604,7 +9984,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) } else if( outParam.argInOutFlags == asTM_OUTREF ) { - asSExprContext *expr = outParam.origExpr; + asCExprContext *expr = outParam.origExpr; outParam.origExpr = 0; if( outParam.argType.dataType.IsObjectHandle() ) @@ -9617,7 +9997,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) // Verify that the expression result in a lvalue, or a property accessor if( IsLValue(expr->type) || expr->property_get || expr->property_set ) { - asSExprContext rctx(engine); + asCExprContext rctx(engine); rctx.type = outParam.argType; if( rctx.type.dataType.IsPrimitive() ) rctx.type.dataType.MakeReference(false); @@ -9629,7 +10009,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) rctx.type.isExplicitHandle = true; } - asSExprContext o(engine); + asCExprContext o(engine); DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode); if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr); @@ -9649,7 +10029,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) ctx->bc.Instr(asBC_PopPtr); // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored - if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) ) + if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.GetConstantData() == 0) ) Error(TXT_ARG_NOT_LVALUE, outParam.argNode); ReleaseTemporaryVariable(outParam.argType, &ctx->bc); @@ -9658,7 +10038,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) ReleaseTemporaryVariable(expr->type, &ctx->bc); // Delete the original expression context - asDELETE(expr,asSExprContext); + asDELETE(expr, asCExprContext); } else // &inout { @@ -9669,7 +10049,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) if( outParam.argType.dataType.IsObject() && ((outParam.argType.dataType.GetBehaviour()->addref && outParam.argType.dataType.GetBehaviour()->release) || - (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ) + (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) ) { // Release the object handle that was taken to guarantee the reference ReleaseTemporaryVariable(outParam.argType, &ctx->bc); @@ -9683,11 +10063,11 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) } -int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) +int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx) { // The first node is a datatype node asCString name; - asCTypeInfo tempObj; + asCExprValue tempObj; bool onHeap = true; asCArray funcs; bool error = false; @@ -9701,7 +10081,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) return CompileConversion(node, ctx); } - if( dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) ) + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) ) { // Types declared as implicit handle must not attempt to construct a handle dt.MakeHandle(false); @@ -9717,7 +10097,10 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) return -1; } - if( !dt.CanBeInstantiated() ) + // Make sure the desired type can actually be instantiated + // Delegates are allowed to be created through construct calls, + // even though they cannot be instantiated as variables + if( !dt.CanBeInstantiated() && !dt.IsFuncdef() ) { asCString str; if( dt.IsAbstractClass() ) @@ -9734,37 +10117,43 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) // Do not allow constructing non-shared types in shared functions if( outFunc->IsShared() && - dt.GetObjectType() && !dt.GetObjectType()->IsShared() ) + dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) { asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf()); + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); Error(msg, node); return -1; } // Compile the arguments - asCArray args; + asCArray args; asCArray namedArgs; - asCArray temporaryVariables; + asCArray temporaryVariables; if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) { // Check for a value cast behaviour - if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() ) + if( args.GetLength() == 1 && args[0]->type.dataType.GetTypeInfo() ) { - asSExprContext conv(engine); + asCExprContext conv(engine); conv.type = args[0]->type; asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false); // Don't use this if the cost is 0 because it would mean that nothing - // is done and the scipt wants a new value to be constructed + // is done and the script wants a new value to be constructed if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 ) { + // Make sure the result is a reference, just as if to a local variable + dt.MakeReference(true); + + // Make sure any property accessor is already evaluated + ProcessPropertyGetAccessor(args[0], args[0]->exprNode); + ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST); ctx->bc.AddCode(&args[0]->bc); ctx->type = args[0]->type; - asDELETE(args[0],asSExprContext); + asDELETE(args[0], asCExprContext); return 0; } @@ -9775,7 +10164,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) asSTypeBehaviour *beh = dt.GetBehaviour(); - if( !(dt.GetObjectType()->flags & asOBJ_REF) ) + if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() ) { funcs = beh->constructors; @@ -9792,7 +10181,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) if( onHeap ) ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); } - else + else if( beh ) funcs = beh->factories; // Special case: Allow calling func(void) with a void expression. @@ -9800,7 +10189,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) { // Evaluate the expression before the function call MergeExprBytecode(ctx, args[0]); - asDELETE(args[0],asSExprContext); + asDELETE(args[0], asCExprContext); args.SetLength(0); } @@ -9808,8 +10197,8 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) // If none has been registered, just allocate the variable and push it on the stack. if( args.GetLength() == 0 ) { - asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour(); - if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) ) + beh = tempObj.dataType.GetBehaviour(); + if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) ) { // Call the default constructor ctx->type = tempObj; @@ -9829,7 +10218,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) } // Special case: If this is a construction of a delegate and the expression names an object method - if( dt.GetFuncDef() && args.GetLength() == 1 && args[0]->methodName != "" ) + if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" ) { // TODO: delegate: It is possible that the argument returns a function pointer already, in which // case no object delegate will be created, but instead a delegate for a function pointer @@ -9848,7 +10237,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) else { // Filter the available object methods to find the one that matches the func def - asCObjectType *type = args[0]->type.dataType.GetObjectType(); + asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo()); asCScriptFunction *bestMethod = 0; for( asUINT n = 0; n < type->methods.GetLength(); n++ ) { @@ -9861,7 +10250,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() ) continue; - if( func->IsSignatureExceptNameAndObjectTypeEqual(dt.GetFuncDef()) ) + if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) ) { bestMethod = func; @@ -9880,10 +10269,10 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod); // Call the factory function for the delegate - asCArray funcs; - builder->GetFunctionDescriptions(DELEGATE_FACTORY, funcs, engine->nameSpaces[0]); - asASSERT( funcs.GetLength() == 1 ); - ctx->bc.Call(asBC_CALLSYS , funcs[0], 2*AS_PTR_SIZE); + asCArray delegateFuncs; + builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]); + asASSERT(delegateFuncs.GetLength() == 1 ); + ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE); // Store the returned delegate in a temporary variable int returnOffset = AllocateVariable(dt, true, false); @@ -9900,14 +10289,14 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) else { asCString msg; - msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, dt.GetFuncDef()->GetDeclaration()); + msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration()); Error(msg.AddressOf(), node); error = true; } } // Clean-up arg - asDELETE(args[0],asSExprContext); + asDELETE(args[0], asCExprContext); return error ? -1 : 0; } @@ -9926,7 +10315,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) // TODO: Clean up: Merge this with MakeFunctionCall // Add the default values for arguments not explicitly supplied - int r = CompileDefaultAndNamedArgs(node, args, funcs[0], dt.GetObjectType(), &namedArgs); + int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs); if( r == asSUCCESS ) { @@ -9936,7 +10325,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) MoveArgsToStack(funcs[0], &ctx->bc, args, false); - if( !(dt.GetObjectType()->flags & asOBJ_REF) ) + if( !(dt.GetTypeInfo()->flags & asOBJ_REF) ) { // If the object is allocated on the stack, then call the constructor as a normal function if( onHeap ) @@ -9951,7 +10340,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) else ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType()); + PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); // Add tag that the object has been initialized ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); @@ -9987,25 +10376,25 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) for( asUINT n = 0; n < args.GetLength(); n++ ) if( args[n] ) { - asDELETE(args[n],asSExprContext); + asDELETE(args[n], asCExprContext); } for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) if( namedArgs[n].ctx ) { - asDELETE(namedArgs[n].ctx,asSExprContext); + asDELETE(namedArgs[n].ctx, asCExprContext); } return error ? -1 : 0; } -int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope) +int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope) { - asCTypeInfo tempObj; + asCExprValue tempObj; asCArray funcs; int localVar = -1; bool initializeMembers = false; - asSExprContext funcExpr(engine); + asCExprContext funcExpr(engine); asCScriptNode *nm = node->lastChild->prev; asCString name(&script->code[nm->tokenPos], nm->tokenLength); @@ -10017,12 +10406,12 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a { localVar = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true); if( localVar >= 0 && - !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) && + !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) && funcExpr.methodName == "" ) { // The variable is not a function or object with opCall asCString msg; - msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf()); + msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), funcExpr.type.dataType.Format(outFunc->nameSpace).AddressOf()); Error(msg, node); return -1; } @@ -10079,12 +10468,12 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a { int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true, objectType); if( r >= 0 && - !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) && + !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) && funcExpr.methodName == "" ) { // The variable is not a function asCString msg; - msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf()); + msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), funcExpr.type.dataType.Format(outFunc->nameSpace).AddressOf()); Error(msg, node); return -1; } @@ -10100,7 +10489,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a { objectType = outFunc->objectType; - asCDataType dt = asCDataType::CreateObject(objectType, false); + asCDataType dt = asCDataType::CreateType(objectType, false); // The object pointer is located at stack position 0 ctx->bc.InstrSHORT(asBC_PSF, 0); @@ -10115,26 +10504,26 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a // then look for global functions or global function pointers, // unless this is an expression post op, incase only member // functions are expected - if( objectType == 0 && funcs.GetLength() == 0 && (funcExpr.type.dataType.GetFuncDef() == 0 || funcExpr.type.dataType.IsObject()) ) + if( objectType == 0 && funcs.GetLength() == 0 && (!funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) ) { // The scope is used to define the namespace asSNameSpace *ns = DetermineNameSpace(scope); if( ns ) { // Search recursively in parent namespaces - while( ns && funcs.GetLength() == 0 && funcExpr.type.dataType.GetFuncDef() == 0 ) + while( ns && funcs.GetLength() == 0 && !funcExpr.type.dataType.IsFuncdef() ) { builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); if( funcs.GetLength() == 0 ) { int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true); if( r >= 0 && - !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) && + !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) && funcExpr.methodName == "" ) { // The variable is not a function asCString msg; - msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf()); + msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), funcExpr.type.dataType.Format(outFunc->nameSpace).AddressOf()); Error(msg, node); return -1; } @@ -10155,9 +10544,9 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a if( funcs.GetLength() == 0 ) { - if( funcExpr.type.dataType.GetFuncDef() ) + if( funcExpr.type.dataType.IsFuncdef() ) { - funcs.PushLast(funcExpr.type.dataType.GetFuncDef()->id); + funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id); } else if( funcExpr.type.dataType.IsObject() ) { @@ -10182,7 +10571,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a ProcessPropertyGetAccessor(ctx, node); Dereference(ctx, true); - objectType = funcExpr.type.dataType.GetObjectType(); + objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo()); // Get the opCall methods from the object type if( funcExpr.type.dataType.IsObjectHandle() ) @@ -10190,12 +10579,21 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a else objIsConst = funcExpr.type.dataType.IsReadOnly(); - builder->GetObjectMethodDescriptions("opCall", funcExpr.type.dataType.GetObjectType(), funcs, objIsConst); + builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst); } } + // If at this point no functions have been identified, then this may be a construct call + if (funcs.GetLength() == 0) + { + bool isValid = false; + asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, 0, false, &isValid); + if (isValid) + return CompileConstructCall(node, ctx); + } + // Compile the arguments - asCArray args; + asCArray args; asCArray namedArgs; bool isOK = true; @@ -10206,7 +10604,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a { // Evaluate the expression before the function call MergeExprBytecode(ctx, args[0]); - asDELETE(args[0],asSExprContext); + asDELETE(args[0], asCExprContext); args.SetLength(0); } @@ -10238,7 +10636,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a if( objectType && funcExpr.property_get <= 0 ) { // Dereference the object pointer to access the member - Dereference(ctx, true); + Dereference(ctx, true); } if( funcExpr.property_get > 0 ) @@ -10258,7 +10656,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack funcExpr.bc.Instr(asBC_PopPtr); - asCTypeInfo tmp = ctx->type; + asCExprValue tmp = ctx->type; MergeExprBytecodeAndType(ctx, &funcExpr); ReleaseTemporaryVariable(tmp, &ctx->bc); } @@ -10280,12 +10678,12 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a for( asUINT n = 0; n < args.GetLength(); n++ ) if( args[n] ) { - asDELETE(args[n],asSExprContext); + asDELETE(args[n], asCExprContext); } for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) if( namedArgs[n].ctx ) { - asDELETE(namedArgs[n].ctx,asSExprContext); + asDELETE(namedArgs[n].ctx, asCExprContext); } if( initializeMembers ) @@ -10329,7 +10727,7 @@ asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope) return ns; } -int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx) +int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx) { int op = node->tokenType; @@ -10373,9 +10771,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx if( !ctx->type.IsNullConstant() ) { // Verify that the type allow its handle to be taken - if( !ctx->type.dataType.IsObject() || - !(((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) || - (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ) + if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() ) { Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); return -1; @@ -10384,7 +10780,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx // Objects that are not local variables are not references // Objects allocated on the stack are also not marked as references if( !ctx->type.dataType.IsReference() && - !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) && + !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) && !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) ) { Error(TXT_NOT_VALID_REFERENCE, node); @@ -10392,7 +10788,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx } // Convert the expression to a handle - if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ) + if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) { asCDataType to = ctx->type.dataType; to.MakeHandle(true); @@ -10402,7 +10798,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx asASSERT( ctx->type.dataType.IsObjectHandle() ); } - else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE ) + else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE ) { // For the ASHANDLE type we'll simply set the expression as a handle ctx->type.dataType.MakeHandle(true); @@ -10436,13 +10832,13 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx // Find the correct method bool isConst = ctx->type.dataType.IsObjectConst(); asCArray funcs; - asCObjectType *ot = ctx->type.dataType.GetObjectType(); + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) { asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; if( func->name == opName && func->parameterTypes.GetLength() == 0 && - (!isConst || func->isReadOnly) ) + (!isConst || func->IsReadOnly()) ) { funcs.PushLast(func->id); } @@ -10451,8 +10847,8 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx // Did we find the method? if( funcs.GetLength() == 1 ) { - asCArray args; - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node); + asCArray args; + MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); return 0; } else if( funcs.GetLength() == 0 ) @@ -10551,14 +10947,21 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx { if( op == ttMinus ) { - if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - ctx->type.intValue = -ctx->type.intValue; - else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue; + if (ctx->type.dataType.IsIntegerType()) + { + if (ctx->type.dataType.GetSizeInMemoryBytes() == 4) + ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2) + ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1) + ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8) + ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW()); + } else if( ctx->type.dataType.IsFloatType() ) - ctx->type.floatValue = -ctx->type.floatValue; + ctx->type.SetConstantF(-ctx->type.GetConstantF()); else if( ctx->type.dataType.IsDoubleType() ) - ctx->type.doubleValue = -ctx->type.doubleValue; + ctx->type.SetConstantD(-ctx->type.GetConstantD()); else { Error(TXT_ILLEGAL_OPERATION, node); @@ -10572,14 +10975,18 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx else if( op == ttNot ) { // Allow value types to be converted to bool using 'bool opImplConv()' - if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) ) + if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV); if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) { if( ctx->type.isConstant ) { - ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + #else + ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + #endif return 0; } @@ -10626,7 +11033,14 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx { if( ctx->type.isConstant ) { - ctx->type.qwordValue = ~ctx->type.qwordValue; + if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) + ctx->type.SetConstantB(~ctx->type.GetConstantB()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2) + ctx->type.SetConstantW(~ctx->type.GetConstantW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4) + ctx->type.SetConstantDW(~ctx->type.GetConstantDW()); + else + ctx->type.SetConstantQW(~ctx->type.GetConstantQW()); return 0; } @@ -10741,7 +11155,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx return 0; } -void asCCompiler::ConvertToReference(asSExprContext *ctx) +void asCCompiler::ConvertToReference(asCExprContext *ctx) { if( ctx->type.isVariable && !ctx->type.dataType.IsReference() ) { @@ -10751,12 +11165,12 @@ void asCCompiler::ConvertToReference(asSExprContext *ctx) } } -int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess) +int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess) { return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess); } -int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess) +int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess) { if( engine->ep.propertyAccessorMode == 0 ) { @@ -10775,11 +11189,11 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx // Don't look for property accessors in script classes if the script // property accessors have been disabled by the application - if( !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) || + if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) || engine->ep.propertyAccessorMode == 2 ) { // Check if the object has any methods with the corresponding accessor name(s) - asCObjectType *ot = ctx->type.dataType.GetObjectType(); + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) { asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; @@ -10916,7 +11330,7 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx int idx = (arg?1:0); if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) && !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) && - (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) ) + (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) ) { asCString str; str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf()); @@ -10977,6 +11391,8 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx ctx->property_get = getId; ctx->property_set = setId; + bool isHandleSafe = ctx->type.isHandleSafe; + if( ctx->type.dataType.IsObject() ) { // If the object is read-only then we need to remember that @@ -11008,10 +11424,14 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx ctx->type.isTemporary = isTemp; ctx->exprNode = node; + // Remember if the object is safe, so the invocation of the property + // accessor doesn't needlessly make a safe copy of the handle + ctx->type.isHandleSafe = isHandleSafe; + // Store the argument for later use if( arg ) { - ctx->property_arg = asNEW(asSExprContext)(engine); + ctx->property_arg = asNEW(asCExprContext)(engine); if( ctx->property_arg == 0 ) { // Out of memory @@ -11028,7 +11448,7 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx return 0; } -int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node) +int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node) { // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them? @@ -11043,7 +11463,7 @@ int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext // Make sure the arg match the property asCArray funcs; funcs.PushLast(ctx->property_set); - asCArray args; + asCArray args; if( ctx->property_arg ) args.PushLast(ctx->property_arg); args.PushLast(arg); @@ -11053,7 +11473,7 @@ int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext // MatchFunctions already reported the error if( ctx->property_arg ) { - asDELETE(ctx->property_arg, asSExprContext); + asDELETE(ctx->property_arg, asCExprContext); ctx->property_arg = 0; } return -1; @@ -11062,17 +11482,17 @@ int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext if( func->objectType ) { // Setup the context with the original type so the method call gets built correctly - ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const); + ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const); if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); // Don't allow the call if the object is read-only and the property accessor is not const - if( ctx->property_const && !func->isReadOnly ) + if( ctx->property_const && !func->IsReadOnly() ) { Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); - asCArray funcs; - funcs.PushLast(ctx->property_set); - PrintMatchingFuncs(funcs, node); + asCArray funcCandidates; + funcCandidates.PushLast(ctx->property_set); + PrintMatchingFuncs(funcCandidates, node); } } @@ -11083,17 +11503,17 @@ int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext ctx->property_set = 0; if( ctx->property_arg ) { - asDELETE(ctx->property_arg, asSExprContext); + asDELETE(ctx->property_arg, asCExprContext); ctx->property_arg = 0; } return 0; } -int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, eTokenType op, asCScriptNode *errNode) +int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode) { - // TODO: Perhaps it might be interesting to allow the definition of compound setters for better - // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible + // TODO: Perhaps it might be interesting to allow the definition of compound setters for better + // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible // to support value types, since it would be a single call // Compound assignment for indexed property accessors is not supported yet @@ -11114,7 +11534,7 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte return -1; } - // Property accessors on value types (or scoped references types) are not supported since + // Property accessors on value types (or scoped references types) are not supported since // it is not possible to guarantee that the object will stay alive between the two calls asCScriptFunction *func = engine->scriptFunctions[lctx->property_set]; if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) ) @@ -11134,9 +11554,9 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte case ttDivAssign: op = ttSlash; break; case ttModAssign: op = ttPercent; break; case ttPowAssign: op = ttStarStar; break; - + case ttAndAssign: op = ttAmp; break; - case ttOrAssign: op = ttBitOr; break; + case ttOrAssign: op = ttBitOr; break; case ttXorAssign: op = ttBitXor; break; case ttShiftLeftAssign: op = ttBitShiftLeft; break; @@ -11149,14 +11569,14 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte if( op == ttUnrecognizedToken ) { // Shouldn't happen - asASSERT(false); + asASSERT(false); // Process the property to free the memory ProcessPropertySetAccessor(lctx, rctx, errNode); return -1; } - asSExprContext before(engine); + asCExprContext before(engine); if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF ) { // Keep a reference to the object in a local variable @@ -11202,7 +11622,7 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte } // Keep the original information on the property - asSExprContext llctx(engine); + asCExprContext llctx(engine); llctx.type = lctx->type; llctx.property_arg = lctx->property_arg; llctx.property_const = lctx->property_const; @@ -11212,7 +11632,7 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte llctx.property_set = lctx->property_set; // Compile the dual operator using the get accessor - CompileOperator(errNode, lctx, rctx, ctx, op); + CompileOperator(errNode, lctx, rctx, ctx, op, false); // If we made a local variable to hold the reference it must be reused if( before.type.stackOffset ) @@ -11233,7 +11653,7 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte return 0; } -void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node) +void asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node) { // If no property accessor has been prepared then don't do anything if( !ctx->property_get && !ctx->property_set ) @@ -11247,13 +11667,13 @@ void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode return; } - asCTypeInfo objType = ctx->type; + asCExprValue objType = ctx->type; asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get); // Make sure the arg match the property asCArray funcs; funcs.PushLast(ctx->property_get); - asCArray args; + asCArray args; if( ctx->property_arg ) args.PushLast(ctx->property_arg); MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const); @@ -11262,7 +11682,7 @@ void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode // MatchFunctions already reported the error if( ctx->property_arg ) { - asDELETE(ctx->property_arg, asSExprContext); + asDELETE(ctx->property_arg, asCExprContext); ctx->property_arg = 0; } ctx->type.SetDummy(); @@ -11272,17 +11692,17 @@ void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode if( func->objectType ) { // Setup the context with the original type so the method call gets built correctly - ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const); + ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const); if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); // Don't allow the call if the object is read-only and the property accessor is not const - if( ctx->property_const && !func->isReadOnly ) + if( ctx->property_const && !func->IsReadOnly() ) { Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); - asCArray funcs; - funcs.PushLast(ctx->property_get); - PrintMatchingFuncs(funcs, node); + asCArray funcCandidates; + funcCandidates.PushLast(ctx->property_get); + PrintMatchingFuncs(funcCandidates, node); } } @@ -11294,17 +11714,17 @@ void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode if( isExplicitHandle ) ctx->type.isExplicitHandle = true; - // Clear the property get/set ids + // Clear the property get/set ids ctx->property_get = 0; ctx->property_set = 0; if( ctx->property_arg ) { - asDELETE(ctx->property_arg, asSExprContext); + asDELETE(ctx->property_arg, asCExprContext); ctx->property_arg = 0; } } -int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx) +int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx) { // Don't allow any postfix operators on expressions that take address of class method if( ctx->IsClassMethod() ) @@ -11343,13 +11763,13 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct // Find the correct method bool isConst = ctx->type.dataType.IsObjectConst(); asCArray funcs; - asCObjectType *ot = ctx->type.dataType.GetObjectType(); + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) { asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; if( func->name == opName && func->parameterTypes.GetLength() == 0 && - (!isConst || func->isReadOnly) ) + (!isConst || func->IsReadOnly()) ) { funcs.PushLast(func->id); } @@ -11358,8 +11778,8 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct // Did we find the method? if( funcs.GetLength() == 1 ) { - asCArray args; - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node); + asCArray args; + MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); return 0; } else if( funcs.GetLength() == 0 ) @@ -11478,7 +11898,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct if( node->next && node->next->tokenType == ttOpenBracket ) { // The property accessor should take an index arg - asSExprContext dummyArg(engine); + asCExprContext dummyArg(engine); r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0); } if( r == 0 ) @@ -11507,7 +11927,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct if( prop ) { // Is the property access allowed? - if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) ) + if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) ) { asCString msg; if( prop->isPrivate ) @@ -11517,8 +11937,16 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct Error(msg, node); } + // Adjust the pointer for composite member + // This must always be done even if the offset is 0 because the asCWriter needs the meta data in ADDSi to identify the composite property + if( prop->compositeOffset || prop->isCompositeIndirect ) + ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false))); + if (prop->isCompositeIndirect) + ctx->bc.Instr(asBC_RDSPtr); + // Put the offset on the stack - ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false))); + // This must always be done even if the offset is 0 so the type info is stored + ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false))); if( prop->type.IsReference() ) ctx->bc.Instr(asBC_RDSPtr); @@ -11548,10 +11976,18 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct ctx->type.isVariable = false; ctx->type.isTemporary = false; - if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() ) + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() ) { // Objects that are members are not references ctx->type.dataType.MakeReference(false); + + // The object is safe (life time guaranteed) if the parent object is also safe + } + else if (ctx->type.dataType.IsObjectHandle()) + { + // A object accessed through a handle cannot be considered safe, + // as it can be cleared at any time + ctx->type.isHandleSafe = false; } ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly()); @@ -11561,7 +11997,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct // If the name is not a property, the compiler must check if the name matches // a method, which can be used for constructing delegates asIScriptFunction *func = 0; - asCObjectType *ot = ctx->type.dataType.GetObjectType(); + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) { if( engine->scriptFunctions[ot->methods[n]]->name == name ) @@ -11610,7 +12046,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct ProcessPropertyGetAccessor(ctx, node); // Compile function call - int r = CompileFunctionCall(node->firstChild, ctx, ctx->type.dataType.GetObjectType(), ctx->type.dataType.IsObjectConst()); + int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst()); if( r < 0 ) return r; } } @@ -11638,7 +12074,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct // Set the original type of the expression so we can re-evaluate the property accessor if( func->objectType ) { - ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const); + ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const); if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); } @@ -11653,7 +12089,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct ctx->property_get = ctx->property_set = 0; if( ctx->property_arg ) { - asDELETE(ctx->property_arg, asSExprContext); + asDELETE(ctx->property_arg, asCExprContext); ctx->property_arg = 0; } } @@ -11672,7 +12108,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct // Compile the expression bool isOK = true; - asCArray args; + asCArray args; asCArray namedArgs; asASSERT( node->firstChild->nodeType == snArgList ); if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 ) @@ -11682,7 +12118,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct if( propertyName == "" ) { bool isConst = ctx->type.dataType.IsObjectConst(); - asCObjectType *objectType = ctx->type.dataType.GetObjectType(); + asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo()); asCArray funcs; builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst); @@ -11714,29 +12150,31 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct { if( args.GetLength() != 1 ) { - // TODO: opIndex: Implement this - Error("Property accessor with index only support 1 index argument for now", node); + // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too + Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node); isOK = false; } - - Dereference(ctx, true); - asSExprContext lctx(engine); - MergeExprBytecodeAndType(&lctx, ctx); - - // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name - int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns); - if( r == 0 ) + else { - asCString str; - str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - isOK = false; - } - else if( r < 0 ) - isOK = false; + Dereference(ctx, true); + asCExprContext lctx(engine); + MergeExprBytecodeAndType(&lctx, ctx); - if( isOK ) - MergeExprBytecodeAndType(ctx, &lctx); + // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name + int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns); + if (r == 0) + { + asCString str; + str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + isOK = false; + } + else if (r < 0) + isOK = false; + + if (isOK) + MergeExprBytecodeAndType(ctx, &lctx); + } } } else @@ -11746,7 +12184,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct for( asUINT n = 0; n < args.GetLength(); n++ ) if( args[n] ) { - asDELETE(args[n],asSExprContext); + asDELETE(args[n], asCExprContext); } if( !isOK ) @@ -11757,30 +12195,30 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code? // Make sure the expression is a funcdef or an object that may have opCall methods - if( !ctx->type.dataType.GetFuncDef() && !ctx->type.dataType.IsObject() ) + if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) ) { Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node); return -1; } // Compile arguments - asCArray args; + asCArray args; asCArray namedArgs; if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) { // Match arguments with the funcdef asCArray funcs; - if( ctx->type.dataType.GetFuncDef() ) + if( ctx->type.dataType.IsFuncdef() ) { - funcs.PushLast(ctx->type.dataType.GetFuncDef()->id); - MatchFunctions(funcs, args, node, ctx->type.dataType.GetFuncDef()->name.AddressOf(), &namedArgs); + funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id); + MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs); } else { bool isConst = ctx->type.dataType.IsObjectConst(); - builder->GetObjectMethodDescriptions("opCall", ctx->type.dataType.GetObjectType(), funcs, isConst); - MatchFunctions(funcs, args, node, "opCall", &namedArgs, ctx->type.dataType.GetObjectType(), isConst); + builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst); + MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst); } if( funcs.GetLength() != 1 ) @@ -11793,7 +12231,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct else { // Add the default values for arguments not explicitly supplied - int r = CompileDefaultAndNamedArgs(node, args, funcs[0], ctx->type.dataType.GetObjectType(), &namedArgs); + int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs); // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or // is it enough to make sure it is in a local variable? @@ -11803,7 +12241,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct if( r == asSUCCESS ) { Dereference(ctx, true); - if( ctx->type.dataType.GetFuncDef() ) + if( ctx->type.dataType.IsFuncdef() ) { if( !ctx->type.isVariable ) ConvertToVariable(ctx); @@ -11812,7 +12250,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct ctx->bc.Instr(asBC_PopPtr); } - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetFuncDef() ? 0 : ctx->type.dataType.GetObjectType(), args, node, false, 0, ctx->type.stackOffset); + MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset); } } } @@ -11823,12 +12261,12 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct for( asUINT n = 0; n < args.GetLength(); n++ ) if( args[n] ) { - asDELETE(args[n],asSExprContext); + asDELETE(args[n], asCExprContext); } for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) if( namedArgs[n].ctx ) { - asDELETE(namedArgs[n].ctx,asSExprContext); + asDELETE(namedArgs[n].ctx, asCExprContext); } } @@ -11900,7 +12338,7 @@ int asCCompiler::GetPrecedence(asCScriptNode *op) return 0; } -asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArray &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct) +asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArray &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct) { matches.SetLength(0); @@ -11920,7 +12358,7 @@ asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArrayIsVoidExpression() ) @@ -11930,14 +12368,31 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *ar return -1; } + // Anonymous init lists can only match parameters that can be initialized with a list + if (argExpr->IsAnonymousInitList()) + { + if ((desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] != asTM_INREF) || + desc->parameterTypes[paramNum].GetTypeInfo() == 0 || + desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0) + { + return -1; + } + return 0; + } + // Can we make the match by implicit conversion? - asSExprContext ti(engine); + asCExprContext ti(engine); ti.type = argExpr->type; ti.methodName = argExpr->methodName; ti.enumValue = argExpr->enumValue; ti.exprNode = argExpr->exprNode; if( argExpr->type.dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false); + + // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value + if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF) + allowObjectConstruct = false; + int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct); // If the function parameter is an inout-reference then it must not be possible to call the @@ -11960,7 +12415,7 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *ar // Don't allow an enum to be converted to a reference of another enum type if( desc->parameterTypes[paramNum].IsEnumType() && - desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType() ) + desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() ) { asASSERT( engine->ep.allowUnsafeReferences ); return -1; @@ -11975,8 +12430,8 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *ar } // Don't allow a value type to be converted - if( (desc->parameterTypes[paramNum].GetObjectType() && (desc->parameterTypes[paramNum].GetObjectType()->GetFlags() & asOBJ_VALUE)) && - (desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType()) ) + if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) && + (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) ) { asASSERT( engine->ep.allowUnsafeReferences ); return -1; @@ -11991,14 +12446,14 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *ar return -1; } -void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy) +void asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy) { // Reference parameters whose value won't be used don't evaluate the expression // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg ) { // Store the original bytecode so that it can be reused when processing the deferred output parameter - asSExprContext *orig = asNEW(asSExprContext)(engine); + asCExprContext *orig = asNEW(asCExprContext)(engine); if( orig == 0 ) { // Out of memory @@ -12014,7 +12469,7 @@ void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asC ctx->bc.AddCode(&arg->bc); } -bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool isHandle, eTokenType token) +bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token) { DetermineSingleFunc(lctx, node); DetermineSingleFunc(rctx, node); @@ -12044,11 +12499,11 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont { // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used // Find the matching opEquals method - int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); if( r == 0 ) { // Try again by switching the order of the operands - r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); } if( r == 1 ) @@ -12078,12 +12533,12 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used // Find the matching opCmp method - int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false)); + int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false)); if( r == 0 ) { // Try again by switching the order of the operands swappedOrder = true; - r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false)); + r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false)); } if( r == 1 ) @@ -12121,7 +12576,11 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont else if( r < 0 ) { // Compiler error, don't continue - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); + #endif return true; } } @@ -12150,11 +12609,11 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont { // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used // Find the matching operator method - int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx); + int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx); if( r == 0 ) { // Try again by switching the order of the operands, and using the reversed operator - r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx); + r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx); } if( r == 1 ) @@ -12175,7 +12634,7 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont if( isHandle ) { // Only asOBJ_ASHANDLE types can get here - asASSERT( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ); + asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ); asASSERT( token == ttAssignment ); if( token == ttAssignment ) @@ -12204,7 +12663,7 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont if( op ) { if( builder->engine->ep.disallowValueAssignForRefType && - lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(lctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) ) + lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) ) { if( token == ttAssignment ) Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node); @@ -12219,7 +12678,7 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont // TODO: Shouldn't accept const lvalue with the assignment operators // Find the matching operator method - int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx); + int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx); if( r == 1 ) { // Success, don't continue @@ -12240,12 +12699,12 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont // Returns negative on compile error // zero on no matching operator // one on matching operator -int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType) +int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType) { // Find the matching method if( lctx->type.dataType.IsObject() && (!lctx->type.isExplicitHandle || - lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ) + lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) { asUINT n; @@ -12253,7 +12712,7 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char bool isConst = lctx->type.dataType.IsObjectConst(); asCArray funcs; - asCObjectType *ot = lctx->type.dataType.GetObjectType(); + asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo()); for( n = 0; n < ot->methods.GetLength(); n++ ) { asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; @@ -12261,7 +12720,7 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char if( func && func->name == methodName && (!specificReturn || func->returnType == returnType) && func->parameterTypes.GetLength() == 1 && - (!isConst || func->isReadOnly) ) + (!isConst || func->IsReadOnly()) ) { // Make sure the method is accessible by the module if( builder->module->accessMask & func->accessMask ) @@ -12297,38 +12756,88 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char // Did we find an operator? if( ops.GetLength() == 1 ) { + // Reserve the variables used in the right expression so the new temporary + // variable allocated for the left operand isn't accidentally overwritten. + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + // Process the lctx expression as get accessor ProcessPropertyGetAccessor(lctx, node); - // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue, - // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue. - asCArray usedVars; - lctx->bc.GetVarsUsed(usedVars); - asUINT oldReservedVars = reservedVariables.GetLength(); - for( asUINT n = 0; n < rctx->deferredParams.GetLength(); n++ ) - { - if( rctx->deferredParams[n].argType.isTemporary && - usedVars.Exists(rctx->deferredParams[n].argType.stackOffset) ) - { - if( reservedVariables.GetLength() == oldReservedVars ) - reservedVariables.Concatenate(usedVars); + reservedVariables.SetLength(l); - // Allocate a new variable for the deferred argument - int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx); - int oldVar = rctx->deferredParams[n].argType.stackOffset; - rctx->deferredParams[n].argType.stackOffset = short(offset); - rctx->bc.ExchangeVar(oldVar, offset); - ReleaseTemporaryVariable(oldVar, 0); + asCExprContext tmpCtx(engine); + if (leftToRight) + { + // Make sure lctx is in fact a variable. If it is a reference there is no + // guarantee that the reference will stay alive throughout the evaluation of rctx + if (!lctx->type.isVariable) + { + // Reserve the variables used in the right expression so the new temporary + // variable allocated for the left operand isn't accidentally overwritten. + l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + + if (lctx->type.dataType.SupportHandles()) + lctx->type.dataType.MakeHandle(true); + PrepareTemporaryVariable(node, lctx); + + reservedVariables.SetLength(l); } + + // Move the bytecode for the left operand to a temporary context + // so we can later make sure this is computed first + tmpCtx.bc.AddCode(&lctx->bc); + tmpCtx.bc.Instr(asBC_PopPtr); + + // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer + // This will be placed after rctx by MakeFunctionCall below + lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset); + + // Implicitly dereference handle parameters sent by reference + sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset); + if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle())) + lctx->bc.Instr(asBC_RDSPtr); + } + else + { + // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue, + // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue. + asCArray usedVars; + lctx->bc.GetVarsUsed(usedVars); + asUINT oldReservedVars = reservedVariables.GetLength(); + for (n = 0; n < rctx->deferredParams.GetLength(); n++) + { + if (rctx->deferredParams[n].argType.isTemporary && + usedVars.Exists(rctx->deferredParams[n].argType.stackOffset)) + { + if (reservedVariables.GetLength() == oldReservedVars) + reservedVariables.Concatenate(usedVars); + + // Allocate a new variable for the deferred argument + int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx); + int oldVar = rctx->deferredParams[n].argType.stackOffset; + rctx->deferredParams[n].argType.stackOffset = short(offset); + rctx->bc.ExchangeVar(oldVar, offset); + ReleaseTemporaryVariable(oldVar, 0); + } + } + reservedVariables.SetLength(oldReservedVars); } - reservedVariables.SetLength(oldReservedVars); // Merge the bytecode so that it forms lvalue.methodName(rvalue) - asCArray args; + asCArray args; args.PushLast(rctx); MergeExprBytecode(ctx, lctx); ctx->type = lctx->type; - MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node); + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + + // Rearrange the bytecode so the left argument is computed first + if (leftToRight) + { + tmpCtx.bc.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmpCtx.bc); + } // Found matching operator return 1; @@ -12349,7 +12858,7 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char return 0; } -void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar) +void asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar) { if( objectType ) Dereference(ctx, true); @@ -12410,7 +12919,7 @@ void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectTyp PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar); } -int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op) +int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight) { // Don't allow any operators on expressions that take address of class method, but allow it on global functions if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) ) @@ -12442,7 +12951,7 @@ int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSE else { // Compile an overloaded operator for the two operands - if( CompileOverloadedDualOperator(node, lctx, rctx, ctx, false, op) ) + if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) ) return 0; // If both operands are objects, then we shouldn't continue @@ -12520,7 +13029,7 @@ int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSE return -1; } -void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude) +void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude) { int l = int(reservedVariables.GetLength()); if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); @@ -12528,7 +13037,7 @@ void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext reservedVariables.SetLength(l); } -void asCCompiler::ConvertToTempVariable(asSExprContext *ctx) +void asCCompiler::ConvertToTempVariable(asCExprContext *ctx) { // This is only used for primitive types and null handles asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() ); @@ -12554,7 +13063,7 @@ void asCCompiler::ConvertToTempVariable(asSExprContext *ctx) } } -void asCCompiler::ConvertToVariable(asSExprContext *ctx) +void asCCompiler::ConvertToVariable(asCExprContext *ctx) { // We should never get here while the context is still an unprocessed property accessor asASSERT(ctx->property_get == 0 && ctx->property_set == 0); @@ -12577,7 +13086,10 @@ void asCCompiler::ConvertToVariable(asSExprContext *ctx) // Copy the object handle to a variable ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType()); + if( ctx->type.dataType.IsFuncdef() ) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); ctx->bc.Instr(asBC_PopPtr); } @@ -12596,13 +13108,13 @@ void asCCompiler::ConvertToVariable(asSExprContext *ctx) { offset = AllocateVariable(ctx->type.dataType, true); if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) - ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue); + ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB()); else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) - ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue); + ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW()); else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) - ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue); + ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW()); else - ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue); + ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW()); ctx->type.SetVariable(ctx->type.dataType, offset, true); return; @@ -12631,7 +13143,7 @@ void asCCompiler::ConvertToVariable(asSExprContext *ctx) } } -void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude) +void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude) { int l = int(reservedVariables.GetLength()); if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); @@ -12639,10 +13151,10 @@ void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *ex reservedVariables.SetLength(l); } -void asCCompiler::ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node) +void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node) { asCArray funcs; - asCObjectType *ot = ctx->type.dataType.GetObjectType(); + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); if( ot ) { for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) @@ -12702,7 +13214,7 @@ void asCCompiler::ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScrip } } -void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op) +void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) { // TODO: If a constant is only using 32bits, then a 32bit operation is preferred @@ -12833,9 +13345,13 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, bool isConstant = lctx->type.isConstant && rctx->type.isConstant; // Verify if we are dividing with a constant zero - if( rctx->type.isConstant && rctx->type.qwordValue == 0 && + if( rctx->type.isConstant && (op == ttSlash || op == ttDivAssign || - op == ttPercent || op == ttModAssign) ) + op == ttPercent || op == ttModAssign) && + ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) ) { Error(TXT_DIVIDE_BY_ZERO, node); } @@ -12998,40 +13514,40 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, { int v = 0; if( op == ttPlus ) - v = lctx->type.intValue + rctx->type.intValue; + v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW()); else if( op == ttMinus ) - v = lctx->type.intValue - rctx->type.intValue; + v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW()); else if( op == ttStar ) - v = lctx->type.intValue * rctx->type.intValue; + v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW()); else if( op == ttSlash ) { // TODO: Should probably report an error, rather than silently convert the value to 0 - if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) ) + if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) ) v = 0; else if( lctx->type.dataType.IsIntegerType() ) - v = lctx->type.intValue / rctx->type.intValue; + v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW()); else - v = lctx->type.dwordValue / rctx->type.dwordValue; + v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW(); } else if( op == ttPercent ) { // TODO: Should probably report an error, rather than silently convert the value to 0 - if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) ) + if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) ) v = 0; else if( lctx->type.dataType.IsIntegerType() ) - v = lctx->type.intValue % rctx->type.intValue; + v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW()); else - v = lctx->type.dwordValue % rctx->type.dwordValue; + v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW(); } else if( op == ttStarStar ) { bool isOverflow; if( lctx->type.dataType.IsIntegerType() ) - v = as_powi(lctx->type.intValue, rctx->type.intValue, isOverflow); + v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow); else - v = as_powu(lctx->type.dwordValue, rctx->type.dwordValue, isOverflow); + v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow); if( isOverflow ) Error(TXT_POW_OVERFLOW, node); @@ -13040,47 +13556,47 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, ctx->type.SetConstantDW(lctx->type.dataType, v); // If the right value is greater than the left value in a minus operation, then we need to convert the type to int - if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue ) + if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW()) ctx->type.dataType.SetTokenType(ttInt); } else { asQWORD v = 0; if( op == ttPlus ) - v = lctx->type.qwordValue + rctx->type.qwordValue; + v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW()); else if( op == ttMinus ) - v = lctx->type.qwordValue - rctx->type.qwordValue; + v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW()); else if( op == ttStar ) - v = lctx->type.qwordValue * rctx->type.qwordValue; + v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW()); else if( op == ttSlash ) { // TODO: Should probably report an error, rather than silently convert the value to 0 - if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) ) + if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) ) v = 0; else if( lctx->type.dataType.IsIntegerType() ) - v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue); + v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW()); else - v = lctx->type.qwordValue / rctx->type.qwordValue; + v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW(); } else if( op == ttPercent ) { // TODO: Should probably report an error, rather than silently convert the value to 0 - if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) ) + if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) ) v = 0; else if( lctx->type.dataType.IsIntegerType() ) - v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue); + v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW()); else - v = lctx->type.qwordValue % rctx->type.qwordValue; + v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW(); } else if( op == ttStarStar ) { bool isOverflow; if( lctx->type.dataType.IsIntegerType() ) - v = as_powi64(asINT64(lctx->type.qwordValue), asINT64(rctx->type.qwordValue), isOverflow); + v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow); else - v = as_powu64(lctx->type.qwordValue, rctx->type.qwordValue, isOverflow); + v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow); if( isOverflow ) Error(TXT_POW_OVERFLOW, node); @@ -13089,7 +13605,7 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, ctx->type.SetConstantQW(lctx->type.dataType, v); // If the right value is greater than the left value in a minus operation, then we need to convert the type to int - if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue ) + if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW()) ctx->type.dataType.SetTokenType(ttInt64); } } @@ -13097,28 +13613,28 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, { float v = 0.0f; if( op == ttPlus ) - v = lctx->type.floatValue + rctx->type.floatValue; + v = lctx->type.GetConstantF() + rctx->type.GetConstantF(); else if( op == ttMinus ) - v = lctx->type.floatValue - rctx->type.floatValue; + v = lctx->type.GetConstantF() - rctx->type.GetConstantF(); else if( op == ttStar ) - v = lctx->type.floatValue * rctx->type.floatValue; + v = lctx->type.GetConstantF() * rctx->type.GetConstantF(); else if( op == ttSlash ) { - if( rctx->type.floatValue == 0 ) + if( rctx->type.GetConstantF() == 0 ) v = 0; else - v = lctx->type.floatValue / rctx->type.floatValue; + v = lctx->type.GetConstantF() / rctx->type.GetConstantF(); } else if( op == ttPercent ) { - if( rctx->type.floatValue == 0 ) + if( rctx->type.GetConstantF() == 0 ) v = 0; else - v = fmodf(lctx->type.floatValue, rctx->type.floatValue); + v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF()); } else if( op == ttStarStar ) { - v = pow(lctx->type.floatValue, rctx->type.floatValue); + v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF()); if( v == HUGE_VAL ) Error(TXT_POW_OVERFLOW, node); @@ -13135,7 +13651,7 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, if( op == ttStarStar || op == ttPowAssign ) { - v = pow(lctx->type.doubleValue, rctx->type.intValue); + v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW())); if( v == HUGE_VAL ) Error(TXT_POW_OVERFLOW, node); } @@ -13145,28 +13661,28 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, else { if( op == ttPlus ) - v = lctx->type.doubleValue + rctx->type.doubleValue; + v = lctx->type.GetConstantD() + rctx->type.GetConstantD(); else if( op == ttMinus ) - v = lctx->type.doubleValue - rctx->type.doubleValue; + v = lctx->type.GetConstantD() - rctx->type.GetConstantD(); else if( op == ttStar ) - v = lctx->type.doubleValue * rctx->type.doubleValue; + v = lctx->type.GetConstantD() * rctx->type.GetConstantD(); else if( op == ttSlash ) { - if( rctx->type.doubleValue == 0 ) + if( rctx->type.GetConstantD() == 0 ) v = 0; else - v = lctx->type.doubleValue / rctx->type.doubleValue; + v = lctx->type.GetConstantD() / rctx->type.GetConstantD(); } else if( op == ttPercent ) { - if( rctx->type.doubleValue == 0 ) + if( rctx->type.GetConstantD() == 0 ) v = 0; else - v = fmod(lctx->type.doubleValue, rctx->type.doubleValue); + v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD()); } else if( op == ttStarStar ) { - v = pow(lctx->type.doubleValue, rctx->type.doubleValue); + v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD()); if( v == HUGE_VAL ) Error(TXT_POW_OVERFLOW, node); } @@ -13182,7 +13698,7 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, } } -void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op) +void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) { // TODO: If a constant is only using 32bits, then a 32bit operation is preferred @@ -13291,11 +13807,11 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc { asQWORD v = 0; if( op == ttAmp ) - v = lctx->type.qwordValue & rctx->type.qwordValue; + v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW(); else if( op == ttBitOr ) - v = lctx->type.qwordValue | rctx->type.qwordValue; + v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW(); else if( op == ttBitXor ) - v = lctx->type.qwordValue ^ rctx->type.qwordValue; + v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW(); // Remember the result ctx->type.SetConstantQW(lctx->type.dataType, v); @@ -13304,11 +13820,11 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc { asDWORD v = 0; if( op == ttAmp ) - v = lctx->type.dwordValue & rctx->type.dwordValue; + v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW(); else if( op == ttBitOr ) - v = lctx->type.dwordValue | rctx->type.dwordValue; + v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW(); else if( op == ttBitXor ) - v = lctx->type.dwordValue ^ rctx->type.dwordValue; + v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW(); // Remember the result ctx->type.SetConstantDW(lctx->type.dataType, v); @@ -13336,15 +13852,15 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryBytes() < 4 ) { + // Upgrade to 32bit to = asCDataType::CreatePrimitive(ttUInt, false); } else if( !lctx->type.dataType.IsUnsignedType() ) { - asCDataType to; - if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - to.SetTokenType(ttInt64); + if (lctx->type.dataType.GetSizeInMemoryDWords() == 2) + to = asCDataType::CreatePrimitive(ttInt64, false); else - to.SetTokenType(ttInt); + to = asCDataType::CreatePrimitive(ttInt, false); } // Do the actual conversion @@ -13430,11 +13946,11 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc { asDWORD v = 0; if( op == ttBitShiftLeft ) - v = lctx->type.dwordValue << rctx->type.dwordValue; + v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW(); else if( op == ttBitShiftRight ) - v = lctx->type.dwordValue >> rctx->type.dwordValue; + v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW(); else if( op == ttBitShiftRightArith ) - v = lctx->type.intValue >> rctx->type.dwordValue; + v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW(); ctx->type.SetConstantDW(lctx->type.dataType, v); } @@ -13442,11 +13958,11 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc { asQWORD v = 0; if( op == ttBitShiftLeft ) - v = lctx->type.qwordValue << rctx->type.dwordValue; + v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW(); else if( op == ttBitShiftRight ) - v = lctx->type.qwordValue >> rctx->type.dwordValue; + v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW(); else if( op == ttBitShiftRightArith ) - v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue; + v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW(); ctx->type.SetConstantQW(lctx->type.dataType, v); } @@ -13454,7 +13970,7 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc } } -void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op) +void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) { // Both operands must be of the same type @@ -13516,22 +14032,32 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext bool signMismatch = false; for( int n = 0; !signMismatch && n < 2; n++ ) { - asSExprContext *op = n ? rctx : lctx; + asCExprContext *opCtx = n ? rctx : lctx; - if( op->type.dataType.IsUnsignedType() != to.IsUnsignedType() ) + if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() ) { // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value signMismatch = true; - if( op->type.isConstant ) + if( opCtx->type.isConstant ) { - if( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 ) + if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 ) { - if( !(op->type.qwordValue & (asQWORD(1)<<63)) ) + if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) ) signMismatch = false; } - else + else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() ) { - if( !(op->type.dwordValue & (1<<31)) ) + if( !(opCtx->type.GetConstantDW() & (1<<31)) ) + signMismatch = false; + } + else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16) + { + if (!(opCtx->type.GetConstantW() & (1 << 15))) + signMismatch = false; + } + else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8) + { + if (!(opCtx->type.GetConstantB() & (1 << 7))) signMismatch = false; } @@ -13586,12 +14112,16 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext { // It wasn't possible to get two valid operands, so we just return // a boolean result and let the compiler continue. +#if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); +#else ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); +#endif return; } bool isConstant = lctx->type.isConstant && rctx->type.isConstant; - + if( op == ttUnrecognizedToken ) op = node->tokenType; @@ -13638,7 +14168,11 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext { // TODO: Use TXT_ILLEGAL_OPERATION_ON Error(TXT_ILLEGAL_OPERATION, node); +#if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0); +#else ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0); +#endif } } else @@ -13699,23 +14233,30 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext { if( op == ttEqual || op == ttNotEqual ) { + asDWORD lv, rv; + #if AS_SIZEOF_BOOL == 1 + lv = lctx->type.GetConstantB(); + rv = rctx->type.GetConstantB(); + #else + lv = lctx->type.GetConstantDW(); + rv = rctx->type.GetConstantDW(); + #endif + // Make sure they are equal if not false - if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE; - if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE; + if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE; + if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE; asDWORD v = 0; - if( op == ttEqual ) - { - v = lctx->type.intValue - rctx->type.intValue; - if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; - } - else if( op == ttNotEqual ) - { - v = lctx->type.intValue - rctx->type.intValue; - if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; - } + if (op == ttEqual) + v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0; + else if (op == ttNotEqual) + v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0; - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v); + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v); + #endif } else { @@ -13728,39 +14269,39 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext int i = 0; if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) { - int v = lctx->type.intValue - rctx->type.intValue; + int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW()); if( v < 0 ) i = -1; if( v > 0 ) i = 1; } else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) { - asDWORD v1 = lctx->type.dwordValue; - asDWORD v2 = rctx->type.dwordValue; + asDWORD v1 = lctx->type.GetConstantDW(); + asDWORD v2 = rctx->type.GetConstantDW(); if( v1 < v2 ) i = -1; if( v1 > v2 ) i = 1; } else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) { - asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue); + asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW()); if( v < 0 ) i = -1; if( v > 0 ) i = 1; } else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) { - asQWORD v1 = lctx->type.qwordValue; - asQWORD v2 = rctx->type.qwordValue; + asQWORD v1 = lctx->type.GetConstantQW(); + asQWORD v2 = rctx->type.GetConstantQW(); if( v1 < v2 ) i = -1; if( v1 > v2 ) i = 1; } else if( lctx->type.dataType.IsFloatType() ) { - float v = lctx->type.floatValue - rctx->type.floatValue; + float v = lctx->type.GetConstantF() - rctx->type.GetConstantF(); if( v < 0 ) i = -1; if( v > 0 ) i = 1; } else if( lctx->type.dataType.IsDoubleType() ) { - double v = lctx->type.doubleValue - rctx->type.doubleValue; + double v = lctx->type.GetConstantD() - rctx->type.GetConstantD(); if( v < 0 ) i = -1; if( v > 0 ) i = 1; } @@ -13779,12 +14320,16 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext else if( op == ttGreaterThanOrEqual ) i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i); + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i); + #endif } } } -void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference) +void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference) { // Put the result on the stack if( asReference ) @@ -13801,7 +14346,7 @@ void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference) } } -void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op) +void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) { // Both operands must be booleans asCDataType to; @@ -13813,9 +14358,9 @@ void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lc lctx->bc.GetVarsUsed(reservedVariables); // Allow value types to be converted to bool using 'bool opImplConv()' - if( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) ) + if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); - if( rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) ) + if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV); reservedVariables.SetLength(l); @@ -13875,25 +14420,25 @@ void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lc { // Make sure they are equal if not false #if AS_SIZEOF_BOOL == 1 - if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE; - if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE; + if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE); + if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE); asBYTE v = 0; - v = lctx->type.byteValue - rctx->type.byteValue; + v = lctx->type.GetConstantB() - rctx->type.GetConstantB(); if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; ctx->type.isConstant = true; - ctx->type.byteValue = v; + ctx->type.SetConstantB(v); #else - if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE; - if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE; + if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE); + if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE); asDWORD v = 0; - v = lctx->type.intValue - rctx->type.intValue; + v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW(); if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; ctx->type.isConstant = true; - ctx->type.dwordValue = v; + ctx->type.SetConstantDW(v); #endif } } @@ -13946,29 +14491,29 @@ void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lc #if AS_SIZEOF_BOOL == 1 asBYTE v = 0; if( op == ttAnd ) - v = lctx->type.byteValue && rctx->type.byteValue; + v = lctx->type.GetConstantB() && rctx->type.GetConstantB(); else if( op == ttOr ) - v = lctx->type.byteValue || rctx->type.byteValue; + v = lctx->type.GetConstantB() || rctx->type.GetConstantB(); // Remember the result ctx->type.isConstant = true; - ctx->type.byteValue = v; + ctx->type.SetConstantB(v); #else asDWORD v = 0; if( op == ttAnd ) - v = lctx->type.dwordValue && rctx->type.dwordValue; + v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW(); else if( op == ttOr ) - v = lctx->type.dwordValue || rctx->type.dwordValue; + v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW(); // Remember the result ctx->type.isConstant = true; - ctx->type.dwordValue = v; + ctx->type.SetConstantDW(v); #endif } } } -void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType opToken) +void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken) { // Process the property accessor as get ProcessPropertyGetAccessor(lctx, node); @@ -13992,25 +14537,25 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext * // Warn if not both operands are explicit handles or null handles if( (opToken == ttEqual || opToken == ttNotEqual) && - ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) || - (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) ) + ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) || + (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) ) { Warning(TXT_HANDLE_COMPARISON, node); } // If one of the operands is a value type used as handle, we should look for the opEquals method - if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) || - (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) && + if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) || + (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) && (opToken == ttEqual || opToken == ttIs || opToken == ttNotEqual || opToken == ttNotIs) ) { // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used // Find the matching opEquals method - int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); if( r == 0 ) { // Try again by switching the order of the operands - r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); } if( r == 1 ) @@ -14042,10 +14587,10 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext * else { // Find a common base type - asSExprContext tmp(engine); + asCExprContext tmp(engine); tmp.type = rctx->type; ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false); - if( tmp.type.dataType.GetObjectType() == lctx->type.dataType.GetObjectType() ) + if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() ) to = lctx->type.dataType; else to = rctx->type.dataType; @@ -14068,7 +14613,11 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext * { // Compiler error, don't continue Error(TXT_OPERANDS_MUST_BE_HANDLES, node); +#if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); +#else ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); +#endif return; } @@ -14103,7 +14652,7 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext * if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs ) { - // Make sure handles received as parameters by reference are copied to a local variable before the + // Make sure handles received as parameters by reference are copied to a local variable before the // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 ) lctx->type.isVariable = false; @@ -14148,7 +14697,7 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext * } -void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar) +void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar) { asCScriptFunction *descr = builder->GetFunctionDescription(funcId); @@ -14161,14 +14710,14 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo } // Check if the function is private or protected - if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() ) + if( descr->IsPrivate() && descr->GetObjectType() != outFunc->GetObjectType() ) { asCString msg; msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf()); Error(msg, ctx->exprNode); } - else if( descr->isProtected && - !(descr->GetObjectType() == outFunc->GetObjectType() || + else if( descr->IsProtected() && + !(descr->GetObjectType() == outFunc->GetObjectType() || (outFunc->GetObjectType() && outFunc->GetObjectType()->DerivesFrom(descr->GetObjectType()))) ) { asCString msg; @@ -14182,25 +14731,24 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo // alive throughout the call by holding on to a reference in a local variable. This must // be done for any methods that return references, and any calls on script objects. // Application registered objects are assumed to know to keep themselves alive even - // if the method doesn't return a refernce. - if( descr->objectType && + // if the method doesn't return a reference. + if( !ctx->type.isHandleSafe && + descr->objectType && (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) && - (descr->returnType.IsReference() || (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCRIPT_OBJECT)) && + (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) && !(ctx->type.isVariable || ctx->type.isTemporary) && - !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) && - !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) ) + !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) && + !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) ) { - // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a + // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a // local variable and then refer to the same for each call. An alias for the global variable - // should be stored in the variable scope so that the compiler can find it. For loops and - // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the + // should be stored in the variable scope so that the compiler can find it. For loops and + // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the // higher scope to increase the probability of re-use. - // TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time - int tempRef = AllocateVariable(ctx->type.dataType, true); ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef); - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType()); + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); // Add the release of this reference as a deferred expression asSDeferredParam deferred; @@ -14302,11 +14850,11 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo else if( descr->funcType == asFUNC_SYSTEM ) { // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of - // type &obj::func(int) + // type &obj::func(int) // type &obj::func(uint) - if( descr->GetObjectType() && descr->returnType.IsReference() && - descr->parameterTypes.GetLength() == 1 && - (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) && + if( descr->GetObjectType() && descr->returnType.IsReference() && + descr->parameterTypes.GetLength() == 1 && + (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) && descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 && !descr->parameterTypes[0].IsReference() ) ctx->bc.Call(asBC_Thiscall1, descr->id, argSize); @@ -14317,11 +14865,11 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize); } - if( descr->returnType.IsObject() && !descr->returnType.IsReference() ) + if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() ) { int returnOffset = 0; - asCTypeInfo tmpExpr = ctx->type; + asCExprValue tmpExpr = ctx->type; if( descr->DoesReturnOnStack() ) { @@ -14413,7 +14961,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo { asASSERT(useVariable == false); - asCTypeInfo tmpExpr = ctx->type; + asCExprValue tmpExpr = ctx->type; if( descr->returnType.GetSizeInMemoryBytes() ) { @@ -14422,7 +14970,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo int l = int(reservedVariables.GetLength()); for( asUINT n = 0; args && n < args->GetLength(); n++ ) { - asSExprContext *expr = (*args)[n]->origExpr; + asCExprContext *expr = (*args)[n]->origExpr; if( expr ) expr->bc.GetVarsUsed(reservedVariables); } @@ -14453,7 +15001,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo } // This only merges the bytecode, but doesn't modify the type of the final context -void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after) +void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after) { before->bc.AddCode(&after->bc); @@ -14467,7 +15015,7 @@ void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *afte } // This merges both bytecode and the type of the final context -void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after) +void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after) { MergeExprBytecode(before, after); @@ -14488,7 +15036,7 @@ void asCCompiler::FilterConst(asCArray &funcs, bool removeConst) for( n = 0; n < funcs.GetLength(); n++ ) { desc = builder->GetFunctionDescription(funcs[n]); - if( desc->isReadOnly != removeConst ) + if( desc->IsReadOnly() != removeConst ) { foundNonConst = true; break; @@ -14501,7 +15049,7 @@ void asCCompiler::FilterConst(asCArray &funcs, bool removeConst) for( n = 0; n < funcs.GetLength(); n++ ) { desc = builder->GetFunctionDescription(funcs[n]); - if( desc->isReadOnly == removeConst ) + if( desc->IsReadOnly() == removeConst ) { if( n == funcs.GetLength() - 1 ) funcs.PopLast(); @@ -14514,6 +15062,389 @@ void asCCompiler::FilterConst(asCArray &funcs, bool removeConst) } } +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +asCExprValue::asCExprValue() +{ + isTemporary = false; + stackOffset = 0; + isConstant = false; + isVariable = false; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; + isRefToLocal = false; + isHandleSafe = false; +} + +void asCExprValue::Set(const asCDataType &dt) +{ + dataType = dt; + + isTemporary = false; + stackOffset = 0; + isConstant = false; + isVariable = false; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; + isRefToLocal = false; + isHandleSafe = false; +} + +void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary) +{ + Set(in_dt); + + this->isVariable = true; + this->isTemporary = in_isTemporary; + this->stackOffset = (short)in_stackOffset; +} + +void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value) +{ + Set(dt); + + isConstant = true; + SetConstantQW(value); +} + +void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value) +{ + Set(dt); + + isConstant = true; + SetConstantDW(value); +} + +void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value) +{ + Set(dt); + + isConstant = true; + SetConstantB(value); +} + +void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value) +{ + Set(dt); + + isConstant = true; + SetConstantW(value); +} + +void asCExprValue::SetConstantF(const asCDataType &dt, float value) +{ + Set(dt); + + isConstant = true; + SetConstantF(value); +} + +void asCExprValue::SetConstantD(const asCDataType &dt, double value) +{ + Set(dt); + + isConstant = true; + SetConstantD(value); +} + +void asCExprValue::SetConstantQW(asQWORD value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + qwordValue = value; +} + +void asCExprValue::SetConstantDW(asDWORD value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + dwordValue = value; +} + +void asCExprValue::SetConstantW(asWORD value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 2); + wordValue = value; +} + +void asCExprValue::SetConstantB(asBYTE value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 1); + byteValue = value; +} + +void asCExprValue::SetConstantF(float value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + floatValue = value; +} + +void asCExprValue::SetConstantD(double value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + doubleValue = value; +} + +asQWORD asCExprValue::GetConstantQW() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + return qwordValue; +} + +asDWORD asCExprValue::GetConstantDW() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + return dwordValue; +} + +asWORD asCExprValue::GetConstantW() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 2); + return wordValue; +} + +asBYTE asCExprValue::GetConstantB() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 1); + return byteValue; +} + +float asCExprValue::GetConstantF() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + return floatValue; +} + +double asCExprValue::GetConstantD() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + return doubleValue; +} + +void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw) +{ + Set(dt); + + isConstant = true; + + // This code is necessary to guarantee that the code + // works on both big endian and little endian CPUs. + if (dataType.GetSizeInMemoryBytes() == 1) + byteValue = (asBYTE)qw; + if (dataType.GetSizeInMemoryBytes() == 2) + wordValue = (asWORD)qw; + if (dataType.GetSizeInMemoryBytes() == 4) + dwordValue = (asDWORD)qw; + else + qwordValue = qw; +} + +asQWORD asCExprValue::GetConstantData() +{ + asQWORD qw = 0; + // This code is necessary to guarantee that the code + // works on both big endian and little endian CPUs. + if (dataType.GetSizeInMemoryBytes() == 1) + qw = byteValue; + if (dataType.GetSizeInMemoryBytes() == 2) + qw = wordValue; + if (dataType.GetSizeInMemoryBytes() == 4) + qw = dwordValue; + else + qw = qwordValue; + return qw; +} + +void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine) +{ + // This is used for when the expression evaluates to a + // function, but it is not yet known exactly which. The + // owner expression will hold the name of the function + // to determine the exact function when the signature is + // known. + Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true)); + isConstant = true; + isExplicitHandle = false; + qwordValue = 1; // Set to a different value than 0 to differentiate from null constant + isLValue = false; +} + +bool asCExprValue::IsUndefinedFuncHandle() const +{ + if (isConstant == false) return false; + if (qwordValue == 0) return false; + if (isLValue) return false; + if (dataType.GetTypeInfo() == 0) return false; + if (dataType.GetTypeInfo()->name != "$func") return false; + if (dataType.IsFuncdef()) return false; + + return true; +} + +void asCExprValue::SetNullConstant() +{ + Set(asCDataType::CreateNullHandle()); + isConstant = true; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; +} + +bool asCExprValue::IsNullConstant() const +{ + // We can't check the actual object type, because the null constant may have been cast to another type + if (isConstant && dataType.IsObjectHandle() && qwordValue == 0) + return true; + + return false; +} + +void asCExprValue::SetVoid() +{ + Set(asCDataType::CreatePrimitive(ttVoid, false)); + isLValue = false; + isConstant = true; +} + +bool asCExprValue::IsVoid() const +{ + if (dataType.GetTokenType() == ttVoid) + return true; + + return false; +} + +void asCExprValue::SetDummy() +{ + SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine) +{ + property_arg = 0; + + Clear(); +} + +asCExprContext::~asCExprContext() +{ + if (property_arg) + asDELETE(property_arg, asCExprContext); +} + +void asCExprContext::Clear() +{ + bc.ClearAll(); + type.Set(asCDataType()); + deferredParams.SetLength(0); + if (property_arg) + asDELETE(property_arg, asCExprContext); + property_arg = 0; + exprNode = 0; + origExpr = 0; + property_get = 0; + property_set = 0; + property_const = false; + property_handle = false; + property_ref = false; + methodName = ""; + enumValue = ""; + isVoidExpression = false; + isCleanArg = false; + isAnonymousInitList = false; +} + +bool asCExprContext::IsClassMethod() const +{ + if (type.dataType.GetTypeInfo() == 0) return false; + if (methodName == "") return false; + if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false; + if (isAnonymousInitList) return false; + return true; +} + +bool asCExprContext::IsGlobalFunc() const +{ + if (type.dataType.GetTypeInfo() == 0) return false; + if (methodName == "") return false; + if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false; + if (isAnonymousInitList) return false; + return true; +} + +void asCExprContext::SetLambda(asCScriptNode *funcDecl) +{ + asASSERT(funcDecl && funcDecl->nodeType == snFunction); + asASSERT(bc.GetLastInstr() == -1); + + Clear(); + type.SetUndefinedFuncHandle(bc.GetEngine()); + exprNode = funcDecl; +} + +bool asCExprContext::IsLambda() const +{ + if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction) + return true; + + return false; +} + +void asCExprContext::SetVoidExpression() +{ + Clear(); + type.SetVoid(); + isVoidExpression = true; +} + +bool asCExprContext::IsVoidExpression() const +{ + if (isVoidExpression && type.IsVoid() && exprNode == 0) + return true; + + return false; +} + +void asCExprContext::SetAnonymousInitList(asCScriptNode *initList) +{ + Clear(); + exprNode = initList; + isAnonymousInitList = true; +} + +bool asCExprContext::IsAnonymousInitList() const +{ + if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList) + return true; + + return false; +} + +void asCExprContext::Merge(asCExprContext *after) +{ + type = after->type; + property_get = after->property_get; + property_set = after->property_set; + property_const = after->property_const; + property_handle = after->property_handle; + property_ref = after->property_ref; + property_arg = after->property_arg; + exprNode = after->exprNode; + methodName = after->methodName; + enumValue = after->enumValue; + isVoidExpression = after->isVoidExpression; + isCleanArg = after->isCleanArg; + isAnonymousInitList = after->isAnonymousInitList; + + after->property_arg = 0; + + // Do not copy the origExpr member +} + + + END_AS_NAMESPACE #endif // AS_NO_COMPILER diff --git a/lib/angelscript/source/as_compiler.h b/lib/angelscript/source/as_compiler.h index f9de7e475..61e9f3490 100644 --- a/lib/angelscript/source/as_compiler.h +++ b/lib/angelscript/source/as_compiler.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -50,123 +50,110 @@ #include "as_bytecode.h" #include "as_array.h" #include "as_datatype.h" -#include "as_typeinfo.h" BEGIN_AS_NAMESPACE -struct asSExprContext; +// This class represents the value of an expression as evaluated by the compiler. +// It holds information such as the type of the value, stack offset for a local +// variable, value of constants, whether the value can be modified (i.e. lvalue), etc. +struct asCExprValue +{ + asCExprValue(); + void Set(const asCDataType &dataType); + void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary); + void SetConstantB(const asCDataType &dataType, asBYTE value); + void SetConstantQW(const asCDataType &dataType, asQWORD value); + void SetConstantDW(const asCDataType &dataType, asDWORD value); + void SetConstantW(const asCDataType &dataType, asWORD value); + void SetConstantF(const asCDataType &dataType, float value); + void SetConstantD(const asCDataType &dataType, double value); + void SetConstantB(asBYTE value); + void SetConstantW(asWORD value); + void SetConstantQW(asQWORD value); + void SetConstantDW(asDWORD value); + void SetConstantF(float value); + void SetConstantD(double value); + asBYTE GetConstantB(); + asWORD GetConstantW(); + asQWORD GetConstantQW(); + asDWORD GetConstantDW(); + float GetConstantF(); + double GetConstantD(); + + void SetConstantData(const asCDataType &dataType, asQWORD value); + asQWORD GetConstantData(); + + void SetNullConstant(); + void SetUndefinedFuncHandle(asCScriptEngine *engine); + void SetVoid(); + void SetDummy(); + + bool IsUndefinedFuncHandle() const; + bool IsNullConstant() const; + bool IsVoid() const; + + asCDataType dataType; + bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc + bool isTemporary : 1; + bool isConstant : 1; + bool isVariable : 1; + bool isExplicitHandle : 1; + bool isRefToLocal : 1; // The reference may be to a local variable + bool isHandleSafe : 1; // the life-time of the handle is guaranteed for the duration of the access + short dummy : 9; + short stackOffset; + +private: + // These values must not be accessed directly in order to avoid problems with endianess. + // Use the appropriate accessor methods instead + union + { + asQWORD qwordValue; + double doubleValue; + asDWORD dwordValue; + float floatValue; + asWORD wordValue; + asBYTE byteValue; + }; +}; + +struct asCExprContext; + +// This class holds information for arguments that needs to be +// cleaned up after the result of a function has been evaluated. struct asSDeferredParam { asSDeferredParam() {argNode = 0; origExpr = 0;} asCScriptNode *argNode; - asCTypeInfo argType; + asCExprValue argType; int argInOutFlags; - asSExprContext *origExpr; + asCExprContext *origExpr; }; -// TODO: refactor: asSExprContext should have indicators to inform where the value is, +// TODO: refactor: asCExprContext should have indicators to inform where the value is, // i.e. if the reference to an object is pushed on the stack or not, etc -struct asSExprContext +// This class holds information about an expression that is being evaluated, e.g. +// the current bytecode, ambiguous symbol names, property accessors, etc. +struct asCExprContext { - asSExprContext(asCScriptEngine *engine) : bc(engine) - { - property_arg = 0; - - Clear(); - } - ~asSExprContext() - { - if( property_arg ) - asDELETE(property_arg, asSExprContext); - } - void Clear() - { - bc.ClearAll(); - type.Set(asCDataType()); - deferredParams.SetLength(0); - if( property_arg ) - asDELETE(property_arg, asSExprContext); - property_arg = 0; - exprNode = 0; - origExpr = 0; - property_get = 0; - property_set = 0; - property_const = false; - property_handle = false; - property_ref = false; - methodName = ""; - enumValue = ""; - isVoidExpression = false; - isCleanArg = false; - } - bool IsClassMethod() const - { - if( type.dataType.GetObjectType() == 0 ) return false; - if( methodName == "" ) return false; - if( type.dataType.GetObjectType() == &type.dataType.GetObjectType()->engine->functionBehaviours ) return false; - return true; - } - bool IsGlobalFunc() const - { - if( type.dataType.GetObjectType() == 0 ) return false; - if( methodName == "" ) return false; - if( type.dataType.GetObjectType() != &type.dataType.GetObjectType()->engine->functionBehaviours ) return false; - return true; - } - void SetLambda(asCScriptNode *funcDecl) - { - asASSERT( funcDecl && funcDecl->nodeType == snFunction ); - asASSERT( bc.GetLastInstr() == -1 ); - - Clear(); - type.SetUndefinedFuncHandle(bc.GetEngine()); - exprNode = funcDecl; - } - bool IsLambda() const - { - if( type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction ) - return true; - - return false; - } - void SetVoidExpression() - { - Clear(); - type.SetVoid(); - isVoidExpression = true; - } - bool IsVoidExpression() const - { - if( isVoidExpression && type.IsVoid() && exprNode == 0 ) - return true; - - return false; - } - void Merge(asSExprContext *after) - { - type = after->type; - property_get = after->property_get; - property_set = after->property_set; - property_const = after->property_const; - property_handle = after->property_handle; - property_ref = after->property_ref; - property_arg = after->property_arg; - exprNode = after->exprNode; - methodName = after->methodName; - enumValue = after->enumValue; - isVoidExpression = after->isVoidExpression; - isCleanArg = after->isCleanArg; - - after->property_arg = 0; - - // Do not copy the origExpr member - } + asCExprContext(asCScriptEngine *engine); + ~asCExprContext(); + void Clear(); + bool IsClassMethod() const; + bool IsGlobalFunc() const; + void SetLambda(asCScriptNode *funcDecl); + bool IsLambda() const; + void SetVoidExpression(); + bool IsVoidExpression() const; + void Merge(asCExprContext *after); + void SetAnonymousInitList(asCScriptNode *initList); + bool IsAnonymousInitList() const; asCByteCode bc; - asCTypeInfo type; + asCExprValue type; int property_get; int property_set; bool property_const; // If the object that is being accessed through property accessor is read-only @@ -174,19 +161,20 @@ struct asSExprContext bool property_ref; // If the property accessor is called on a reference bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls bool isCleanArg; // Set to true if the expression has only been initialized with default constructor - asSExprContext *property_arg; + asCExprContext *property_arg; asCArray deferredParams; asCScriptNode *exprNode; - asSExprContext *origExpr; + asCExprContext *origExpr; // TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value asCString methodName; asCString enumValue; + bool isAnonymousInitList; // Set to true if the expression is an init list for which the type has not yet been determined }; struct asSOverloadCandidate { asSOverloadCandidate() : funcId(0), cost(0) {} - asSOverloadCandidate(int _id, asUINT _cost ) : funcId(_id), cost(_cost) {} + asSOverloadCandidate(int _id, asUINT _cost) : funcId(_id), cost(_cost) {} int funcId; asUINT cost; }; @@ -194,7 +182,7 @@ struct asSOverloadCandidate struct asSNamedArgument { asCString name; - asSExprContext *ctx; + asCExprContext *ctx; asUINT match; }; @@ -209,13 +197,15 @@ enum EConvCost { asCC_NO_CONV = 0, asCC_CONST_CONV = 1, - asCC_PRIMITIVE_SIZE_CONV = 2, - asCC_SIGNED_CONV = 3, - asCC_INT_FLOAT_CONV = 4, - asCC_REF_CONV = 5, - asCC_OBJ_TO_PRIMITIVE_CONV = 6, - asCC_TO_OBJECT_CONV = 7, - asCC_VARIABLE_CONV = 8 + asCC_ENUM_SAME_SIZE_CONV = 2, + asCC_ENUM_DIFF_SIZE_CONV = 3, + asCC_PRIMITIVE_SIZE_CONV = 4, + asCC_SIGNED_CONV = 5, + asCC_INT_FLOAT_CONV = 6, + asCC_REF_CONV = 7, + asCC_OBJ_TO_PRIMITIVE_CONV = 8, + asCC_TO_OBJECT_CONV = 9, + asCC_VARIABLE_CONV = 10 }; class asCCompiler @@ -250,93 +240,94 @@ protected: void CompileExpressionStatement(asCScriptNode *node, asCByteCode *bc); // Expressions - int CompileAssignment(asCScriptNode *expr, asSExprContext *out); - int CompileCondition(asCScriptNode *expr, asSExprContext *out); - int CompileExpression(asCScriptNode *expr, asSExprContext *out); - int CompilePostFixExpression(asCArray *postfix, asSExprContext *out); - int CompileExpressionTerm(asCScriptNode *node, asSExprContext *out); - int CompileExpressionPreOp(asCScriptNode *node, asSExprContext *out); - int CompileExpressionPostOp(asCScriptNode *node, asSExprContext *out); - int CompileExpressionValue(asCScriptNode *node, asSExprContext *out); - int CompileFunctionCall(asCScriptNode *node, asSExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = ""); - int CompileConstructCall(asCScriptNode *node, asSExprContext *out); - int CompileConversion(asCScriptNode *node, asSExprContext *out); - int CompileOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileMathOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileBitwiseOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileComparisonOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileBooleanOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken); - bool CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken); - int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *l, asSExprContext *r, asSExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false)); + int CompileAssignment(asCScriptNode *expr, asCExprContext *out); + int CompileCondition(asCScriptNode *expr, asCExprContext *out); + int CompileExpression(asCScriptNode *expr, asCExprContext *out); + int CompilePostFixExpression(asCArray *postfix, asCExprContext *out); + int CompileExpressionTerm(asCScriptNode *node, asCExprContext *out); + int CompileExpressionPreOp(asCScriptNode *node, asCExprContext *out); + int CompileExpressionPostOp(asCScriptNode *node, asCExprContext *out); + int CompileExpressionValue(asCScriptNode *node, asCExprContext *out); + int CompileFunctionCall(asCScriptNode *node, asCExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = ""); + int CompileConstructCall(asCScriptNode *node, asCExprContext *out); + int CompileConversion(asCScriptNode *node, asCExprContext *out); + int CompileOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken, bool leftToRight = true); + void CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileMathOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileBitwiseOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileComparisonOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileBooleanOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + bool CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken); + int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false)); - void CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem); + void CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem); int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList); + int CompilerAnonymousInitList(asCScriptNode *listNode, asCExprContext *ctx, const asCDataType &dt); int CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false); - int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false); + int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false); void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc); - int CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs); - int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *type, asCArray *namedArgs = 0); - asUINT MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs = NULL, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = ""); - int CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, bool noFunction = false, bool noGlobal = false, asCObjectType *objType = 0); + int CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs); + int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *type, asCArray *namedArgs = 0); + asUINT MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs = NULL, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = ""); + int CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, bool noFunction = false, bool noGlobal = false, asCObjectType *objType = 0); void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults); - bool CompileAutoType(asCDataType &autoType, asSExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode); - bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asSExprContext *preCompiled = 0); - void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination); + bool CompileAutoType(asCDataType &autoType, asCExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode); + bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled = 0); + void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination); // Helper functions void ConvertToPostFix(asCScriptNode *expr, asCArray &postfix); - void ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node); - int ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node); - int ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, eTokenType op, asCScriptNode *errNode); - int FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); - int FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); - void PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap = false); - void PrepareOperand(asSExprContext *ctx, asCScriptNode *node); - void PrepareForAssignment(asCDataType *lvalue, asSExprContext *rvalue, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr = 0); - int PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node); - bool IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node); - void Dereference(asSExprContext *ctx, bool generateCode); - bool CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true); - asUINT MatchArgument(asCArray &funcs, asCArray &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); - int MatchArgument(asCScriptFunction *desc, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); - void PerformFunctionCall(int funcId, asSExprContext *out, bool isConstructor = false, asCArray *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0); - void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset); - void MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0); - void PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args); - void AfterFunctionCall(int funcId, asCArray &args, asSExprContext *ctx, bool deferAll); - void ProcessDeferredParams(asSExprContext *ctx); - int PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false); - void PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false); - bool IsLValue(asCTypeInfo &type); - int DoAssignment(asSExprContext *out, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode); - void MergeExprBytecode(asSExprContext *before, asSExprContext *after); - void MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after); + void ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node); + int ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node); + int ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode); + int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); + int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); + void PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap = false); + void PrepareOperand(asCExprContext *ctx, asCScriptNode *node); + void PrepareForAssignment(asCDataType *lvalue, asCExprContext *rvalue, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr = 0); + int PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node); + bool IsVariableInitialized(asCExprValue *type, asCScriptNode *node); + void Dereference(asCExprContext *ctx, bool generateCode); + bool CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true); + asUINT MatchArgument(asCArray &funcs, asCArray &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); + int MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); + void PerformFunctionCall(int funcId, asCExprContext *out, bool isConstructor = false, asCArray *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0); + void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset); + void MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0); + void PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args); + void AfterFunctionCall(int funcId, asCArray &args, asCExprContext *ctx, bool deferAll); + void ProcessDeferredParams(asCExprContext *ctx); + int PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false); + void PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false); + bool IsLValue(asCExprValue &type); + int DoAssignment(asCExprContext *out, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode); + void MergeExprBytecode(asCExprContext *before, asCExprContext *after); + void MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after); void FilterConst(asCArray &funcs, bool removeConst = true); - void ConvertToVariable(asSExprContext *ctx); - void ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude); - void ConvertToTempVariable(asSExprContext *ctx); - void ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude); - void ConvertToReference(asSExprContext *ctx); - void PushVariableOnStack(asSExprContext *ctx, bool asReference); + void ConvertToVariable(asCExprContext *ctx); + void ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); + void ConvertToTempVariable(asCExprContext *ctx); + void ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); + void ConvertToReference(asCExprContext *ctx); + void PushVariableOnStack(asCExprContext *ctx, bool asReference); void DestroyVariables(asCByteCode *bc); asSNameSpace *DetermineNameSpace(const asCString &scope); int SetupParametersAndReturnVariable(asCArray ¶meterNames, asCScriptNode *func); - void DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node); + void DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node); // Returns the cost of the conversion (the sum of the EConvCost performed) - asUINT ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); - asUINT ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); - asUINT ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); - asUINT ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); - void ImplicitConversionConstant(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType); - void ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node); - asUINT ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + asUINT ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + asUINT ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + asUINT ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); + asUINT ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); + void ImplicitConversionConstant(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType); + void ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node); + asUINT ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); void LineInstr(asCByteCode *bc, size_t pos); @@ -373,11 +364,11 @@ protected: asCArray continueLabels; int AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap = false); - int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx); + int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx); int GetVariableOffset(int varIndex); int GetVariableSlot(int varOffset); void DeallocateVariable(int pos); - void ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc); + void ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc); void ReleaseTemporaryVariable(int offset, asCByteCode *bc); bool IsVariableOnHeap(int offset); @@ -402,6 +393,10 @@ protected: // This array holds the indices of variables that must not be used in an allocation asCArray reservedVariables; + // This array holds the string constants that were allocated during the compilation, + // so they can be released upon completion, whether the compilation was successful or not. + asCArray usedStringConstants; + bool isCompilingDefaultArg; bool isProcessingDeferredParams; int noCodeOutput; diff --git a/lib/angelscript/source/as_config.h b/lib/angelscript/source/as_config.h index 525ebed25..8542c186a 100644 --- a/lib/angelscript/source/as_config.h +++ b/lib/angelscript/source/as_config.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -155,6 +155,7 @@ // // How to identify different compilers //----------------------------------------- +// Ref: http://nadeausoftware.com/articles/2012/10/c_c_tip_how_detect_compiler_name_and_version_using_compiler_predefined_macros // MS Visual C++ // _MSC_VER is defined @@ -167,10 +168,13 @@ // GNU C based compilers // __GNUC__ is defined +// CLang/LLVM +// __clang__ is defined + // Embarcadero C++Builder // __BORLANDC__ is defined -// Sun CC compiler +// Oracle Solaris Studio (previously known as Sun CC compiler) // __SUNPRO_CC is defined @@ -602,7 +606,8 @@ // GNU C (and MinGW or Cygwin on Windows) // Use the following command to determine predefined macros: echo . | g++ -dM -E - -#if (defined(__GNUC__) && !defined(__SNC__)) || defined(EPPC) || defined(__CYGWIN__) // JWC -- use this instead for Wii +// MSVC2015 can now use CLang too, but it shouldn't go in here +#if (defined(__GNUC__) && !defined(__SNC__) && !defined(_MSC_VER)) || defined(EPPC) || defined(__CYGWIN__) // JWC -- use this instead for Wii #define GNU_STYLE_VIRTUAL_METHOD #define MULTI_BASE_OFFSET(x) (*((asPWORD*)(&x)+1)) #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) @@ -836,6 +841,7 @@ #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + // x86 32bit #define THISCALL_RETURN_SIMPLE_IN_MEMORY #define CDECL_RETURN_SIMPLE_IN_MEMORY #define STDCALL_RETURN_SIMPLE_IN_MEMORY @@ -845,6 +851,7 @@ #define AS_X86 #undef AS_NO_THISCALL_FUNCTOR_METHOD #elif defined(__x86_64__) + // x86 64bit #define AS_X64_GCC #undef AS_NO_THISCALL_FUNCTOR_METHOD #define HAS_128_BIT_PRIMITIVES @@ -854,49 +861,56 @@ // STDCALL is not available on 64bit Linux #undef STDCALL #define STDCALL - #elif (defined(__ARMEL__) || defined(__arm__)) && !(defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)) - #define AS_ARM + #elif defined(__ARMEL__) || defined(__arm__) || defined(__aarch64__) || defined(__AARCH64EL__) + // arm - // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S - #define AS_NO_EXCEPTIONS + // The assembler code currently doesn't support arm v4, nor 64bit (v8) + #if !defined(__ARM_ARCH_4__) && !defined(__ARM_ARCH_4T__) && !defined(__LP64__) + #define AS_ARM - #undef STDCALL - #define STDCALL + // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S + #define AS_NO_EXCEPTIONS - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #undef STDCALL + #define STDCALL - #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 CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #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 + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #ifndef AS_MAX_PORTABILITY - // Make a few checks against incompatible ABI combinations - #if defined(__FAST_MATH__) && __FAST_MATH__ == 1 - #error -ffast-math is not supported with native calling conventions + #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 + + #ifndef AS_MAX_PORTABILITY + // Make a few checks against incompatible ABI combinations + #if defined(__FAST_MATH__) && __FAST_MATH__ == 1 + #error -ffast-math is not supported with native calling conventions + #endif + #endif + + // Verify if soft-float or hard-float ABI is used + #if defined(__SOFTFP__) && __SOFTFP__ == 1 + // -ffloat-abi=softfp or -ffloat-abi=soft + #define AS_SOFTFP + #endif + + // Tested with both hard float and soft float abi + #undef AS_NO_THISCALL_FUNCTOR_METHOD #endif - #endif - - // Verify if soft-float or hard-float ABI is used - #if defined(__SOFTFP__) && __SOFTFP__ == 1 - // -ffloat-abi=softfp or -ffloat-abi=soft - #define AS_SOFTFP - #endif - - // Tested with both hard float and soft float abi - #undef AS_NO_THISCALL_FUNCTOR_METHOD #elif defined(__mips__) + // mips #define AS_MIPS #undef STDCALL #define STDCALL #ifdef _ABIO32 + // 32bit O32 ABI #define AS_MIPS // All structures are returned in memory regardless of size or complexity @@ -911,6 +925,13 @@ // For other ABIs the native calling convention is not available (yet) #define AS_MAX_PORTABILITY #endif + #elif defined(__PPC64__) + // PPC 64bit + + // The code in as_callfunc_ppc_64.cpp was built for PS3 and XBox 360, that + // although use 64bit PPC only uses 32bit pointers. + // TODO: Add support for native calling conventions on Linux with PPC 64bit + #define AS_MAX_PORTABILITY #else #define AS_MAX_PORTABILITY #endif @@ -923,7 +944,7 @@ #endif // Free BSD - #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__) + #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) #define AS_BSD #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) #undef COMPLEX_MASK @@ -1153,23 +1174,20 @@ // Detect target hardware //------------------------------------------------ -// X86, Intel, AMD, etc, i.e. most PCs -#if defined(__i386__) || defined(_M_IX86) - // Nothing special here +// Big endian CPU target? +// see: http://sourceforge.net/p/predef/wiki/Endianness/ +#if !defined(AS_BIG_ENDIAN) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ + defined(__BIG_ENDIAN__) || \ + defined(__ARMEB__) || \ + defined(__THUMBEB__) || \ + defined(__AARCH64EB__) || \ + defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) + #define AS_BIG_ENDIAN #endif -// PowerPC, e.g. Mac, GameCube, PS3, XBox 360, Wii -#if defined(__PPC__) || defined(__ppc__) || defined(_PPC_) || defined(EPPC) - #define AS_BIG_ENDIAN - - // Gamecube - #if defined(_GC) - #define AS_USE_DOUBLE_AS_FLOAT - #endif -#endif - -// Dreamcast console -#ifdef __SH4_SINGLE_ONLY__ +// Dreamcast and Gamecube use only 32bit floats, so treat doubles as floats +#if defined(__SH4_SINGLE_ONLY__) || defined(_GC) #define AS_USE_DOUBLE_AS_FLOAT // use 32bit floats instead of doubles #endif diff --git a/lib/angelscript/source/as_configgroup.cpp b/lib/angelscript/source/as_configgroup.cpp index 882fc4645..36a6b11d7 100644 --- a/lib/angelscript/source/as_configgroup.cpp +++ b/lib/angelscript/source/as_configgroup.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -66,11 +66,11 @@ int asCConfigGroup::Release() return refCount; } -asCObjectType *asCConfigGroup::FindType(const char *obj) +asCTypeInfo *asCConfigGroup::FindType(const char *obj) { - for( asUINT n = 0; n < objTypes.GetLength(); n++ ) - if( objTypes[n]->name == obj ) - return objTypes[n]; + for( asUINT n = 0; n < types.GetLength(); n++ ) + if( types[n]->name == obj ) + return types[n]; return 0; } @@ -90,27 +90,27 @@ void asCConfigGroup::RefConfigGroup(asCConfigGroup *group) void asCConfigGroup::AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func) { - AddReferencesForType(engine, func->returnType.GetObjectType()); + AddReferencesForType(engine, func->returnType.GetTypeInfo()); for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - AddReferencesForType(engine, func->parameterTypes[n].GetObjectType()); + AddReferencesForType(engine, func->parameterTypes[n].GetTypeInfo()); } -void asCConfigGroup::AddReferencesForType(asCScriptEngine *engine, asCObjectType *type) +void asCConfigGroup::AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type) { if( type == 0 ) return; // Keep reference to other groups - RefConfigGroup(engine->FindConfigGroupForObjectType(type)); + RefConfigGroup(engine->FindConfigGroupForTypeInfo(type)); // Keep track of which generated template instances the config group uses - if( type->flags & asOBJ_TEMPLATE && engine->generatedTemplateTypes.Exists(type) && !generatedTemplateInstances.Exists(type) ) - generatedTemplateInstances.PushLast(type); + if( type->flags & asOBJ_TEMPLATE && engine->generatedTemplateTypes.Exists(CastToObjectType(type)) && !generatedTemplateInstances.Exists(CastToObjectType(type)) ) + generatedTemplateInstances.PushLast(CastToObjectType(type)); } bool asCConfigGroup::HasLiveObjects() { - for( asUINT n = 0; n < objTypes.GetLength(); n++ ) - if( objTypes[n]->externalRefCount.get() != 0 ) + for( asUINT n = 0; n < types.GetLength(); n++ ) + if( types[n]->externalRefCount.get() != 0 ) return true; return false; @@ -143,36 +143,24 @@ void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed) if( index >= 0 ) engine->registeredGlobalFuncs.Erase(index); scriptFunctions[n]->ReleaseInternal(); - if( engine->stringFactory == scriptFunctions[n] ) - engine->stringFactory = 0; } scriptFunctions.SetLength(0); // Remove behaviours and members of object types - for( n = 0; n < objTypes.GetLength(); n++ ) + for( n = 0; n < types.GetLength(); n++ ) { - asCObjectType *obj = objTypes[n]; - - obj->ReleaseAllFunctions(); + asCObjectType *obj = CastToObjectType(types[n]); + if( obj ) + obj->ReleaseAllFunctions(); } - // Remove function definitions - for( n = 0; n < funcDefs.GetLength(); n++ ) - { - engine->registeredFuncDefs.RemoveValue(funcDefs[n]); - funcDefs[n]->ReleaseInternal(); - engine->RemoveFuncdef(funcDefs[n]); - funcDefs[n]->ReleaseInternal(); - } - funcDefs.SetLength(0); - // Remove object types (skip this if it is possible other groups are still using the types) if( !notUsed ) { - for( n = asUINT(objTypes.GetLength()); n-- > 0; ) + for( n = asUINT(types.GetLength()); n-- > 0; ) { - asCObjectType *t = objTypes[n]; - asSMapNode *cursor; + asCTypeInfo *t = types[n]; + asSMapNode *cursor; if( engine->allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(t->nameSpace, t->name)) && cursor->value == t ) { @@ -182,29 +170,35 @@ void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed) engine->defaultArrayObjectType = 0; if( t->flags & asOBJ_TYPEDEF ) - engine->registeredTypeDefs.RemoveValue(t); + engine->registeredTypeDefs.RemoveValue(CastToTypedefType(t)); else if( t->flags & asOBJ_ENUM ) - engine->registeredEnums.RemoveValue(t); - else if( t->flags & asOBJ_TEMPLATE ) - engine->registeredTemplateTypes.RemoveValue(t); + engine->registeredEnums.RemoveValue(CastToEnumType(t)); + else if (t->flags & asOBJ_TEMPLATE) + engine->registeredTemplateTypes.RemoveValue(CastToObjectType(t)); + else if (t->flags & asOBJ_FUNCDEF) + { + engine->registeredFuncDefs.RemoveValue(CastToFuncdefType(t)); + engine->RemoveFuncdef(CastToFuncdefType(t)); + } else - engine->registeredObjTypes.RemoveValue(t); + engine->registeredObjTypes.RemoveValue(CastToObjectType(t)); t->DestroyInternal(); t->ReleaseInternal(); } else { - int idx = engine->templateInstanceTypes.IndexOf(t); + int idx = engine->templateInstanceTypes.IndexOf(CastToObjectType(t)); if( idx >= 0 ) { engine->templateInstanceTypes.RemoveIndexUnordered(idx); - t->DestroyInternal(); - t->ReleaseInternal(); + asCObjectType *ot = CastToObjectType(t); + ot->DestroyInternal(); + ot->ReleaseInternal(); } } } - objTypes.SetLength(0); + types.SetLength(0); } // Release other config groups diff --git a/lib/angelscript/source/as_configgroup.h b/lib/angelscript/source/as_configgroup.h index ccf785e6c..48720301e 100644 --- a/lib/angelscript/source/as_configgroup.h +++ b/lib/angelscript/source/as_configgroup.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -57,23 +57,22 @@ public: int AddRef(); int Release(); - asCObjectType *FindType(const char *obj); + asCTypeInfo *FindType(const char *name); void RefConfigGroup(asCConfigGroup *group); bool HasLiveObjects(); void RemoveConfiguration(asCScriptEngine *engine, bool notUsed = false); void AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func); - void AddReferencesForType(asCScriptEngine *engine, asCObjectType *type); + void AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type); asCString groupName; int refCount; - asCArray objTypes; + asCArray types; asCArray scriptFunctions; asCArray globalProps; asCArray referencedConfigGroups; - asCArray funcDefs; // This array holds the generated template instances that are used // by the config group as part of function signature or property diff --git a/lib/angelscript/source/as_context.cpp b/lib/angelscript/source/as_context.cpp index 9096a1045..e10f85766 100644 --- a/lib/angelscript/source/as_context.cpp +++ b/lib/angelscript/source/as_context.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -153,7 +153,6 @@ AS_API asIScriptContext *asGetActiveContext() } // internal -// Note: There is no asPopActiveContext(), just call tld->activeContexts.PopLast() instead asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx) { asCThreadLocalData *tld = asCThreadManager::GetLocalData(); @@ -164,6 +163,15 @@ asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx) return tld; } +// internal +void asPopActiveContext(asCThreadLocalData *tld, asIScriptContext *ctx) +{ + UNUSED_VAR(ctx); + asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength() - 1] == ctx); + if (tld) + tld->activeContexts.PopLast(); +} + asCContext::asCContext(asCScriptEngine *engine, bool holdRef) { m_refCount.set(1); @@ -501,6 +509,11 @@ int asCContext::Unprepare() if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED ) return asCONTEXT_ACTIVE; + // Set the context as active so that any clean up code can use access it if desired + asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this); + asDWORD count = m_refCount.get(); + UNUSED_VAR(count); + // Only clean the stack if the context was prepared but not executed until the end if( m_status != asEXECUTION_UNINITIALIZED && m_status != asEXECUTION_FINISHED ) @@ -511,6 +524,11 @@ int asCContext::Unprepare() // Release the returned object (if any) CleanReturnObject(); + // TODO: Unprepare is called during destruction, so nobody + // must be allowed to keep an extra reference + asASSERT(m_refCount.get() == count); + asPopActiveContext(tld, this); + // Release the object if it is a script object if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) { @@ -552,7 +570,7 @@ asBYTE asCContext::GetReturnByte() asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; return *(asBYTE*)&m_regs.valueRegister; } @@ -563,7 +581,7 @@ asWORD asCContext::GetReturnWord() asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; return *(asWORD*)&m_regs.valueRegister; } @@ -574,7 +592,7 @@ asDWORD asCContext::GetReturnDWord() asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; return *(asDWORD*)&m_regs.valueRegister; } @@ -585,7 +603,7 @@ asQWORD asCContext::GetReturnQWord() asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; return m_regs.valueRegister; } @@ -596,7 +614,7 @@ float asCContext::GetReturnFloat() asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; return *(float*)&m_regs.valueRegister; } @@ -607,7 +625,7 @@ double asCContext::GetReturnDouble() asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; return *(double*)&m_regs.valueRegister; } @@ -620,7 +638,7 @@ void *asCContext::GetReturnAddress() if( dt->IsReference() ) return *(void**)&m_regs.valueRegister; - else if( dt->IsObject() ) + else if( dt->IsObject() || dt->IsFuncdef() ) { if( m_initialFunction->DoesReturnOnStack() ) { @@ -644,7 +662,7 @@ void *asCContext::GetReturnObject() asCDataType *dt = &m_initialFunction->returnType; - if( !dt->IsObject() ) return 0; + if( !dt->IsObject() && !dt->IsFuncdef() ) return 0; if( dt->IsReference() ) return *(void**)(asPWORD)m_regs.valueRegister; @@ -671,7 +689,7 @@ void *asCContext::GetAddressOfReturnValue() asCDataType *dt = &m_initialFunction->returnType; // An object is stored in the objectRegister - if( !dt->IsReference() && dt->IsObject() ) + if( !dt->IsReference() && (dt->IsObject() || dt->IsFuncdef()) ) { // Need to dereference objects if( !dt->IsObjectHandle() ) @@ -731,7 +749,7 @@ int asCContext::SetArgByte(asUINT arg, asBYTE value) // Verify the type of the argument asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) { m_status = asEXECUTION_ERROR; return asINVALID_TYPE; @@ -774,7 +792,7 @@ int asCContext::SetArgWord(asUINT arg, asWORD value) // Verify the type of the argument asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) { m_status = asEXECUTION_ERROR; return asINVALID_TYPE; @@ -817,7 +835,7 @@ int asCContext::SetArgDWord(asUINT arg, asDWORD value) // Verify the type of the argument asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) { m_status = asEXECUTION_ERROR; return asINVALID_TYPE; @@ -860,7 +878,7 @@ int asCContext::SetArgQWord(asUINT arg, asQWORD value) // Verify the type of the argument asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) { m_status = asEXECUTION_ERROR; return asINVALID_TYPE; @@ -903,7 +921,7 @@ int asCContext::SetArgFloat(asUINT arg, float value) // Verify the type of the argument asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) { m_status = asEXECUTION_ERROR; return asINVALID_TYPE; @@ -946,7 +964,7 @@ int asCContext::SetArgDouble(asUINT arg, double value) // Verify the type of the argument asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) { m_status = asEXECUTION_ERROR; return asINVALID_TYPE; @@ -1026,7 +1044,7 @@ int asCContext::SetArgObject(asUINT arg, void *obj) // Verify the type of the argument asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( !dt->IsObject() ) + if( !dt->IsObject() && !dt->IsFuncdef() ) { m_status = asEXECUTION_ERROR; return asINVALID_TYPE; @@ -1038,13 +1056,18 @@ int asCContext::SetArgObject(asUINT arg, void *obj) if( dt->IsObjectHandle() ) { // Increase the reference counter - asSTypeBehaviour *beh = &dt->GetObjectType()->beh; - if( obj && beh->addref ) - m_engine->CallObjectMethod(obj, beh->addref); + if (obj && dt->IsFuncdef()) + ((asIScriptFunction*)obj)->AddRef(); + else + { + asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh; + if (obj && beh->addref) + m_engine->CallObjectMethod(obj, beh->addref); + } } else { - obj = m_engine->CreateScriptObjectCopy(obj, dt->GetObjectType()); + obj = m_engine->CreateScriptObjectCopy(obj, dt->GetTypeInfo()); } } @@ -1186,7 +1209,11 @@ int asCContext::Execute() asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this); - if( m_regs.programPointer == 0 ) + // Make sure there are not too many nested calls, as it could crash the application + // by filling up the thread call stack + if (tld->activeContexts.GetLength() > m_engine->ep.maxNestedCalls) + SetInternalException(TXT_TOO_MANY_NESTED_CALLS); + else if( m_regs.programPointer == 0 ) { if( m_currentFunction->funcType == asFUNC_DELEGATE ) { @@ -1319,13 +1346,11 @@ int asCContext::Execute() } // Pop the active context - asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength()-1] == this); - if( tld ) - tld->activeContexts.PopLast(); + asPopActiveContext(tld, this); if( m_status == asEXECUTION_FINISHED ) { - m_regs.objectType = m_initialFunction->returnType.GetObjectType(); + m_regs.objectType = m_initialFunction->returnType.GetTypeInfo(); return asEXECUTION_FINISHED; } @@ -1426,7 +1451,7 @@ int asCContext::PopState() m_regs.valueRegister = asQWORD(asDWORD(tmp[5])); m_regs.valueRegister |= asQWORD(tmp[6])<<32; m_regs.objectRegister = (void*)tmp[7]; - m_regs.objectType = (asIObjectType*)tmp[8]; + m_regs.objectType = (asITypeInfo*)tmp[8]; // Calculate the returnValueSize if( m_initialFunction->DoesReturnOnStack() ) @@ -2481,18 +2506,9 @@ void asCContext::ExecuteNext() break; case asBC_STR: - { - // Get the string id from the argument - asWORD w = asBC_WORDARG0(l_bc); - // Push the string pointer on the stack - const asCString &b = m_engine->GetConstantString(w); - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = (asPWORD)b.AddressOf(); - // Push the string length on the stack - --l_sp; - *l_sp = (asDWORD)b.GetLength(); - l_bc++; - } + // TODO: NEWSTRING: Deprecate this instruction + asASSERT(false); + l_bc++; break; case asBC_CALLSYS: @@ -2803,7 +2819,7 @@ void asCContext::ExecuteNext() { // Read variable index from location on stack asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); - asDWORD offset = *(asDWORD*)a; + asPWORD offset = *a; // Move pointer from variable to the same location on the stack asPWORD *v = (asPWORD*)(l_fp - offset); *a = *v; @@ -4339,17 +4355,24 @@ void asCContext::ExecuteNext() // Pop the thispointer from the stack void *obj = *(void**)l_sp; - l_sp += AS_PTR_SIZE; + if (obj == 0) + SetInternalException(TXT_NULL_POINTER_ACCESS); + else + { + // Only update the stack pointer if all is OK so the + // exception handler can properly clean up the stack + l_sp += AS_PTR_SIZE; - // Pop the int arg from the stack - int arg = *(int*)l_sp; - l_sp++; + // Pop the int arg from the stack + int arg = *(int*)l_sp; + l_sp++; - // Call the method - m_callingSystemFunction = m_engine->scriptFunctions[i]; - void *ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction); - m_callingSystemFunction = 0; - *(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr; + // Call the method + m_callingSystemFunction = m_engine->scriptFunctions[i]; + void *ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction); + m_callingSystemFunction = 0; + *(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr; + } // Update the program position after the call so that line number is correct l_bc += 2; @@ -4510,8 +4533,8 @@ void asCContext::CleanReturnObject() if( m_initialFunction && m_initialFunction->DoesReturnOnStack() && m_status == asEXECUTION_FINISHED ) { // If function returns on stack we need to call the destructor on the returned object - if( m_initialFunction->returnType.GetObjectType()->beh.destruct ) - m_engine->CallObjectMethod(GetReturnObject(), m_initialFunction->returnType.GetObjectType()->beh.destruct); + if(CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct ) + m_engine->CallObjectMethod(GetReturnObject(), CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct); return; } @@ -4522,25 +4545,34 @@ void asCContext::CleanReturnObject() if( m_regs.objectType ) { - // Call the destructor on the object - asSTypeBehaviour *beh = &((asCObjectType*)m_regs.objectType)->beh; - if( m_regs.objectType->GetFlags() & asOBJ_REF ) + if (m_regs.objectType->GetFlags() & asOBJ_FUNCDEF) { - asASSERT( beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT) ); - - if( beh->release ) - m_engine->CallObjectMethod(m_regs.objectRegister, beh->release); - + // Release the function pointer + reinterpret_cast(m_regs.objectRegister)->Release(); m_regs.objectRegister = 0; } else { - if( beh->destruct ) - m_engine->CallObjectMethod(m_regs.objectRegister, beh->destruct); + // Call the destructor on the object + asSTypeBehaviour *beh = &(CastToObjectType(reinterpret_cast(m_regs.objectType))->beh); + if (m_regs.objectType->GetFlags() & asOBJ_REF) + { + asASSERT(beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT)); - // Free the memory - m_engine->CallFree(m_regs.objectRegister); - m_regs.objectRegister = 0; + if (beh->release) + m_engine->CallObjectMethod(m_regs.objectRegister, beh->release); + + m_regs.objectRegister = 0; + } + else + { + if (beh->destruct) + m_engine->CallObjectMethod(m_regs.objectRegister, beh->destruct); + + // Free the memory + m_engine->CallFree(m_regs.objectRegister); + m_regs.objectRegister = 0; + } } } } @@ -4779,7 +4811,7 @@ void asCContext::CleanArgsOnStack() for( v = 0; v < m_currentFunction->scriptData->objVariablePos.GetLength(); v++ ) if( m_currentFunction->scriptData->objVariablePos[v] == var ) { - func = m_currentFunction->scriptData->funcVariableTypes[v]; + func = CastToFuncdefType(m_currentFunction->scriptData->objVariableTypes[v])->funcdef; break; } @@ -4795,7 +4827,8 @@ void asCContext::CleanArgsOnStack() { if( var == paramPos ) { - func = m_currentFunction->parameterTypes[v].GetFuncDef(); + if (m_currentFunction->parameterTypes[v].IsFuncdef()) + func = CastToFuncdefType(m_currentFunction->parameterTypes[v].GetTypeInfo())->funcdef; break; } paramPos -= m_currentFunction->parameterTypes[v].GetSizeOnStackDWords(); @@ -4815,19 +4848,23 @@ void asCContext::CleanArgsOnStack() offset += AS_PTR_SIZE; for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) { - if( func->parameterTypes[n].IsObject() && !func->parameterTypes[n].IsReference() ) + if( (func->parameterTypes[n].IsObject() || func->parameterTypes[n].IsFuncdef()) && !func->parameterTypes[n].IsReference() ) { + // TODO: cleanup: This logic is repeated twice in CleanStackFrame too. Should create a common function to share the code if( *(asPWORD*)&m_regs.stackPointer[offset] ) { // Call the object's destructor asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour(); - if( func->parameterTypes[n].GetObjectType()->flags & asOBJ_REF ) + if (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF) { - asASSERT( (func->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release ); + (*(asCScriptFunction**)&m_regs.stackPointer[offset])->Release(); + } + else if( func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF ) + { + asASSERT( (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); if( beh->release ) m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release); - *(asPWORD*)&m_regs.stackPointer[offset] = 0; } else { @@ -4836,8 +4873,8 @@ void asCContext::CleanArgsOnStack() // Free the memory m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackPointer[offset]); - *(asPWORD*)&m_regs.stackPointer[offset] = 0; } + *(asPWORD*)&m_regs.stackPointer[offset] = 0; } } @@ -4875,25 +4912,29 @@ void asCContext::CleanStackFrame() if( *(asPWORD*)&m_regs.stackFramePointer[-pos] ) { // Call the object's destructor - asSTypeBehaviour *beh = &m_currentFunction->scriptData->objVariableTypes[n]->beh; - if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_REF ) + if (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_FUNCDEF) { + (*(asCScriptFunction**)&m_regs.stackFramePointer[-pos])->Release(); + } + else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_REF ) + { + asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; asASSERT( (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_NOCOUNT) || beh->release ); if( beh->release ) m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->release); - *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0; } else { + asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; if( beh->destruct ) m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_LIST_PATTERN ) - m_engine->DestroyList((asBYTE*)*(asPWORD*)&m_regs.stackFramePointer[-pos], m_currentFunction->scriptData->objVariableTypes[n]); + m_engine->DestroyList((asBYTE*)*(asPWORD*)&m_regs.stackFramePointer[-pos], CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])); // Free the memory m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos]); - *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0; } + *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0; } } else @@ -4903,7 +4944,7 @@ void asCContext::CleanStackFrame() // Only destroy the object if it is truly alive if( liveObjects[n] > 0 ) { - asSTypeBehaviour *beh = &m_currentFunction->scriptData->objVariableTypes[n]->beh; + asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; if( beh->destruct ) m_engine->CallObjectMethod((void*)(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); } @@ -4925,19 +4966,22 @@ void asCContext::CleanStackFrame() offset += AS_PTR_SIZE; for( asUINT n = 0; n < m_currentFunction->parameterTypes.GetLength(); n++ ) { - if( m_currentFunction->parameterTypes[n].IsObject() && !m_currentFunction->parameterTypes[n].IsReference() ) + if( (m_currentFunction->parameterTypes[n].IsObject() ||m_currentFunction->parameterTypes[n].IsFuncdef()) && !m_currentFunction->parameterTypes[n].IsReference() ) { if( *(asPWORD*)&m_regs.stackFramePointer[offset] ) { // Call the object's destructor asSTypeBehaviour *beh = m_currentFunction->parameterTypes[n].GetBehaviour(); - if( m_currentFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_REF ) + if (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF) { - asASSERT( (m_currentFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release ); + (*(asCScriptFunction**)&m_regs.stackFramePointer[offset])->Release(); + } + else if( m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF ) + { + asASSERT( (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); if( beh->release ) m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->release); - *(asPWORD*)&m_regs.stackFramePointer[offset] = 0; } else { @@ -4946,8 +4990,8 @@ void asCContext::CleanStackFrame() // Free the memory m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[offset]); - *(asPWORD*)&m_regs.stackFramePointer[offset] = 0; } + *(asPWORD*)&m_regs.stackFramePointer[offset] = 0; } } @@ -5122,12 +5166,27 @@ int asCContext::CallGeneric(asCScriptFunction *descr) asCGeneric gen(m_engine, descr, currentObject, args); m_callingSystemFunction = descr; +#ifdef AS_NO_EXCEPTIONS func(&gen); +#else + // This try/catch block is to catch potential exception that may + // be thrown by the registered function. + try + { + func(&gen); + } + catch (...) + { + // Convert the exception to a script exception so the VM can + // properly report the error to the application and then clean up + SetException(TXT_EXCEPTION_CAUGHT); + } +#endif m_callingSystemFunction = 0; m_regs.valueRegister = gen.returnVal; m_regs.objectRegister = gen.objectRegister; - m_regs.objectType = descr->returnType.GetObjectType(); + m_regs.objectType = descr->returnType.GetTypeInfo(); // Clean up arguments const asUINT cleanCount = sysFunc->cleanArgs.GetLength(); @@ -5244,7 +5303,7 @@ void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel) !func->scriptData->variables[varIndex]->type.IsObjectHandle() ) { onHeap = true; - if( func->scriptData->variables[varIndex]->type.GetObjectType()->GetFlags() & asOBJ_VALUE ) + if( func->scriptData->variables[varIndex]->type.GetTypeInfo()->GetFlags() & asOBJ_VALUE ) { for( asUINT n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ ) { @@ -5312,7 +5371,7 @@ int asCContext::GetThisTypeId(asUINT stackLevel) return 0; // not in a method // create a datatype - asCDataType dt = asCDataType::CreateObject((asCObjectType*)func->GetObjectType(), false); + asCDataType dt = asCDataType::CreateType((asCObjectType*)func->GetObjectType(), false); // return a typeId from the data type return m_engine->GetTypeIdFromDataType(dt); diff --git a/lib/angelscript/source/as_criticalsection.h b/lib/angelscript/source/as_criticalsection.h index 0a5084a1f..2e15288a5 100644 --- a/lib/angelscript/source/as_criticalsection.h +++ b/lib/angelscript/source/as_criticalsection.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -45,18 +45,18 @@ BEGIN_AS_NAMESPACE #ifdef AS_NO_THREADS -#define DECLARECRITICALSECTION(x) -#define ENTERCRITICALSECTION(x) -#define LEAVECRITICALSECTION(x) +#define DECLARECRITICALSECTION(x) +#define ENTERCRITICALSECTION(x) +#define LEAVECRITICALSECTION(x) inline bool tryEnter() { return true; } #define TRYENTERCRITICALSECTION(x) tryEnter() -#define DECLAREREADWRITELOCK(x) -#define ACQUIREEXCLUSIVE(x) -#define RELEASEEXCLUSIVE(x) -#define ACQUIRESHARED(x) -#define RELEASESHARED(x) +#define DECLAREREADWRITELOCK(x) +#define ACQUIREEXCLUSIVE(x) +#define RELEASEEXCLUSIVE(x) +#define ACQUIRESHARED(x) +#define RELEASESHARED(x) #else @@ -115,7 +115,9 @@ END_AS_NAMESPACE #ifdef AS_XBOX360 #include #else -#define WIN32_LEAN_AND_MEAN +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0600 // We need this to get the declaration for Windows Phone compatible Ex functions #endif @@ -154,11 +156,11 @@ public: void ReleaseShared(); protected: - // The Slim Read Write Lock object, SRWLOCK, is more efficient + // The Slim Read Write Lock object, SRWLOCK, is more efficient // but it is only available from Windows Vista so we cannot use it and // maintain compatibility with olders versions of Windows. - // Critical sections and semaphores are available on Windows XP and onwards. + // Critical sections and semaphores are available on Windows XP and onwards. // Windows XP is oldest version we support with multithreading. // The implementation is based on the following article, that shows diff --git a/lib/angelscript/source/as_datatype.cpp b/lib/angelscript/source/as_datatype.cpp index 88d0067eb..0fcd75ca6 100644 --- a/lib/angelscript/source/as_datatype.cpp +++ b/lib/angelscript/source/as_datatype.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -38,6 +38,7 @@ #include "as_config.h" #include "as_datatype.h" #include "as_tokendef.h" +#include "as_typeinfo.h" #include "as_objecttype.h" #include "as_scriptengine.h" #include "as_tokenizer.h" @@ -47,27 +48,27 @@ BEGIN_AS_NAMESPACE asCDataType::asCDataType() { tokenType = ttUnrecognizedToken; - objectType = 0; + typeInfo = 0; isReference = false; isReadOnly = false; isAuto = false; isObjectHandle = false; isConstHandle = false; - funcDef = 0; isHandleToAsHandleType = false; + ifHandleThenConst = false; } asCDataType::asCDataType(const asCDataType &dt) { tokenType = dt.tokenType; - objectType = dt.objectType; + typeInfo = dt.typeInfo; isReference = dt.isReference; isReadOnly = dt.isReadOnly; isAuto = dt.isAuto; isObjectHandle = dt.isObjectHandle; isConstHandle = dt.isConstHandle; - funcDef = dt.funcDef; isHandleToAsHandleType = dt.isHandleToAsHandleType; + ifHandleThenConst = dt.ifHandleThenConst; } asCDataType::~asCDataType() @@ -83,12 +84,12 @@ bool asCDataType::IsValid() const return true; } -asCDataType asCDataType::CreateObject(asCObjectType *ot, bool isConst) +asCDataType asCDataType::CreateType(asCTypeInfo *ti, bool isConst) { asCDataType dt; dt.tokenType = ttIdentifier; - dt.objectType = ot; + dt.typeInfo = ti; dt.isReadOnly = isConst; return dt; @@ -105,28 +106,20 @@ asCDataType asCDataType::CreateAuto(bool isConst) return dt; } -asCDataType asCDataType::CreateObjectHandle(asCObjectType *ot, bool isConst) +asCDataType asCDataType::CreateObjectHandle(asCTypeInfo *ot, bool isConst) { asCDataType dt; + asASSERT(CastToObjectType(ot)); + dt.tokenType = ttIdentifier; - dt.objectType = ot; + dt.typeInfo = ot; dt.isObjectHandle = true; dt.isConstHandle = isConst; return dt; } -asCDataType asCDataType::CreateFuncDef(asCScriptFunction *func) -{ - asCDataType dt; - dt.tokenType = ttIdentifier; - dt.funcDef = func; - dt.objectType = &func->engine->functionBehaviours; - - return dt; -} - asCDataType asCDataType::CreatePrimitive(eTokenType tt, bool isConst) { asCDataType dt; @@ -152,7 +145,7 @@ asCDataType asCDataType::CreateNullHandle() bool asCDataType::IsNullHandle() const { if( tokenType == ttUnrecognizedToken && - objectType == 0 && + typeInfo == 0 && isObjectHandle ) return true; @@ -171,38 +164,40 @@ asCString asCDataType::Format(asSNameSpace *currNs, bool includeNamespace) const // If the type is not declared in the current namespace, then the namespace // must always be informed to guarantee that the correct type is informed - if( includeNamespace || (objectType && objectType->nameSpace != currNs) || (funcDef && funcDef->nameSpace != currNs) ) + if (includeNamespace || (typeInfo && typeInfo->nameSpace != currNs)) { - if( objectType && objectType->nameSpace->name != "" ) - str += objectType->nameSpace->name + "::"; - else if( funcDef && funcDef->nameSpace->name != "" ) - str += funcDef->nameSpace->name + "::"; + if (typeInfo && typeInfo->nameSpace && typeInfo->nameSpace->name != "") + str += typeInfo->nameSpace->name + "::"; + } + if (typeInfo && typeInfo->nameSpace == 0) + { + // If funcDef->nameSpace is null it means the funcDef was declared as member of + // another type, in which case the scope should be built with the name of that type + str += CastToFuncdefType(typeInfo)->parentClass->name + "::"; } if( tokenType != ttIdentifier ) { str += asCTokenizer::GetDefinition(tokenType); } - else if( IsArrayType() && objectType && !objectType->engine->ep.expandDefaultArrayToTemplate ) + else if( IsArrayType() && typeInfo && !typeInfo->engine->ep.expandDefaultArrayToTemplate ) { - asASSERT( objectType->templateSubTypes.GetLength() == 1 ); - str += objectType->templateSubTypes[0].Format(currNs, includeNamespace); + asCObjectType *ot = CastToObjectType(typeInfo); + asASSERT( ot && ot->templateSubTypes.GetLength() == 1 ); + str += ot->templateSubTypes[0].Format(currNs, includeNamespace); str += "[]"; } - else if( funcDef ) + else if(typeInfo) { - str += funcDef->name; - } - else if( objectType ) - { - str += objectType->name; - if( objectType->templateSubTypes.GetLength() > 0 ) + str += typeInfo->name; + asCObjectType *ot = CastToObjectType(typeInfo); + if( ot && ot->templateSubTypes.GetLength() > 0 ) { str += "<"; - for( asUINT subtypeIndex = 0; subtypeIndex < objectType->templateSubTypes.GetLength(); subtypeIndex++ ) + for( asUINT subtypeIndex = 0; subtypeIndex < ot->templateSubTypes.GetLength(); subtypeIndex++ ) { - str += objectType->templateSubTypes[subtypeIndex].Format(currNs, includeNamespace); - if( subtypeIndex != objectType->templateSubTypes.GetLength()-1 ) + str += ot->templateSubTypes[subtypeIndex].Format(currNs, includeNamespace); + if( subtypeIndex != ot->templateSubTypes.GetLength()-1 ) str += ","; } str += ">"; @@ -210,10 +205,7 @@ asCString asCDataType::Format(asSNameSpace *currNs, bool includeNamespace) const } else if( isAuto ) { - if( isObjectHandle ) - str += ""; - else - str += ""; + str += ""; } else { @@ -237,13 +229,13 @@ asCDataType &asCDataType::operator =(const asCDataType &dt) { tokenType = dt.tokenType; isReference = dt.isReference; - objectType = dt.objectType; + typeInfo = dt.typeInfo; isReadOnly = dt.isReadOnly; isObjectHandle = dt.isObjectHandle; isConstHandle = dt.isConstHandle; isAuto = dt.isAuto; - funcDef = dt.funcDef; isHandleToAsHandleType = dt.isHandleToAsHandleType; + ifHandleThenConst = dt.ifHandleThenConst; return (asCDataType &)*this; } @@ -269,18 +261,17 @@ int asCDataType::MakeHandle(bool b, bool acceptHandleForScope) // (except when returned from registered function) // funcdefs are special reference types and support handles // value types with asOBJ_ASHANDLE are treated as a handle - if( !funcDef && - (!objectType || - !((objectType->flags & asOBJ_REF) || (objectType->flags & asOBJ_TEMPLATE_SUBTYPE) || (objectType->flags & asOBJ_ASHANDLE)) || - (objectType->flags & asOBJ_NOHANDLE) || - ((objectType->flags & asOBJ_SCOPED) && !acceptHandleForScope)) ) + if( (!typeInfo || + !((typeInfo->flags & asOBJ_REF) || (typeInfo->flags & asOBJ_TEMPLATE_SUBTYPE) || (typeInfo->flags & asOBJ_ASHANDLE) || (typeInfo->flags & asOBJ_FUNCDEF)) || + (typeInfo->flags & asOBJ_NOHANDLE) || + ((typeInfo->flags & asOBJ_SCOPED) && !acceptHandleForScope)) ) return -1; isObjectHandle = b; isConstHandle = false; // ASHANDLE supports being handle, but as it really is a value type it will not be marked as a handle - if( (objectType->flags & asOBJ_ASHANDLE) ) + if( (typeInfo->flags & asOBJ_ASHANDLE) ) { isObjectHandle = false; isHandleToAsHandleType = true; @@ -306,7 +297,7 @@ int asCDataType::MakeArray(asCScriptEngine *engine, asCModule *module) isObjectHandle = false; isConstHandle = false; - objectType = at; + typeInfo = at; tokenType = ttIdentifier; return 0; @@ -341,9 +332,9 @@ int asCDataType::MakeHandleToConst(bool b) bool asCDataType::SupportHandles() const { - if( objectType && - (objectType->flags & (asOBJ_REF | asOBJ_ASHANDLE)) && - !(objectType->flags & asOBJ_NOHANDLE) && + if( typeInfo && + (typeInfo->flags & (asOBJ_REF | asOBJ_ASHANDLE | asOBJ_FUNCDEF)) && + !(typeInfo->flags & asOBJ_NOHANDLE) && !isObjectHandle ) return true; @@ -355,19 +346,25 @@ bool asCDataType::CanBeInstantiated() const if( GetSizeOnStackDWords() == 0 ) // Void return false; - if( !IsObject() ) // Primitives + if( !IsObject() && !IsFuncdef() ) // Primitives return true; - if( IsObjectHandle() && !(objectType->flags & asOBJ_NOHANDLE) ) // Handles - return true; - - if( funcDef ) // Funcdefs can be instantiated as delegates - return true; - - if( (objectType->flags & asOBJ_REF) && objectType->beh.factories.GetLength() == 0 ) // ref types without factories + if (IsNullHandle()) // null return false; - if( (objectType->flags & asOBJ_ABSTRACT) && !IsObjectHandle() ) // Can't instantiate abstract classes + if( IsObjectHandle() && !(typeInfo->flags & asOBJ_NOHANDLE) ) // Handles + return true; + + // Funcdefs cannot be instantiated without being handles + // The exception being delegates, but these can only be created as temporary objects + if (IsFuncdef()) + return false; + + asCObjectType *ot = CastToObjectType(typeInfo); + if( ot && (ot->flags & asOBJ_REF) && ot->beh.factories.GetLength() == 0 ) // ref types without factories + return false; + + if( ot && (ot->flags & asOBJ_ABSTRACT) && !IsObjectHandle() ) // Can't instantiate abstract classes return false; return true; @@ -375,12 +372,16 @@ bool asCDataType::CanBeInstantiated() const bool asCDataType::IsAbstractClass() const { - return objectType && (objectType->flags & asOBJ_ABSTRACT) ? true : false; + return typeInfo && (typeInfo->flags & asOBJ_ABSTRACT) ? true : false; } bool asCDataType::IsInterface() const { - return objectType && objectType->IsInterface(); + if (typeInfo == 0) + return false; + + asCObjectType *ot = CastToObjectType(typeInfo); + return ot && ot->IsInterface(); } bool asCDataType::CanBeCopied() const @@ -389,19 +390,19 @@ bool asCDataType::CanBeCopied() const if( IsPrimitive() ) return true; // Plain-old-data structures can always be copied - if( objectType->flags & asOBJ_POD ) return true; + if( typeInfo->flags & asOBJ_POD ) return true; // It must be possible to instantiate the type if( !CanBeInstantiated() ) return false; - // It must have a default constructor or factory - if( objectType->beh.construct == 0 && - objectType->beh.factory == 0 ) return false; + // It must have a default constructor or factory and the opAssign + // Alternatively it must have the copy constructor + asCObjectType *ot = CastToObjectType(typeInfo); + if (ot && (((ot->beh.construct != 0 || ot->beh.factory != 0) && ot->beh.copy != 0) || + (ot->beh.copyconstruct != 0 || ot->beh.copyfactory != 0)) ) + return true; - // It must be possible to copy the type - if( objectType->beh.copy == 0 ) return false; - - return true; + return false; } bool asCDataType::IsReadOnly() const @@ -430,15 +431,15 @@ bool asCDataType::IsObjectConst() const bool asCDataType::IsArrayType() const { // This is only true if the type used is the default array type, i.e. the one used for the [] syntax form - if( objectType && objectType->engine->defaultArrayObjectType ) - return objectType->name == objectType->engine->defaultArrayObjectType->name; + if( typeInfo && typeInfo->engine->defaultArrayObjectType ) + return typeInfo->name == typeInfo->engine->defaultArrayObjectType->name; return false; } bool asCDataType::IsTemplate() const { - if( objectType && (objectType->flags & asOBJ_TEMPLATE) ) + if( typeInfo && (typeInfo->flags & asOBJ_TEMPLATE) ) return true; return false; @@ -446,7 +447,7 @@ bool asCDataType::IsTemplate() const bool asCDataType::IsScriptObject() const { - if( objectType && (objectType->flags & asOBJ_SCRIPT_OBJECT) ) + if( typeInfo && (typeInfo->flags & asOBJ_SCRIPT_OBJECT) ) return true; return false; @@ -454,8 +455,9 @@ bool asCDataType::IsScriptObject() const asCDataType asCDataType::GetSubType(asUINT subtypeIndex) const { - asASSERT(objectType); - return objectType->templateSubTypes[subtypeIndex]; + asASSERT(typeInfo); + asCObjectType *ot = CastToObjectType(typeInfo); + return ot->templateSubTypes[subtypeIndex]; } @@ -487,11 +489,10 @@ bool asCDataType::IsEqualExceptRefAndConst(const asCDataType &dt) const { // Check base type if( tokenType != dt.tokenType ) return false; - if( objectType != dt.objectType ) return false; + if( typeInfo != dt.typeInfo ) return false; if( isObjectHandle != dt.isObjectHandle ) return false; if( isObjectHandle ) if( isReadOnly != dt.isReadOnly ) return false; - if( funcDef != dt.funcDef ) return false; return true; } @@ -510,11 +511,11 @@ bool asCDataType::IsPrimitive() const if( IsEnumType() ) return true; - // A registered object is never a primitive neither is a pointer, nor an array - if( objectType || funcDef ) + // A registered object is never a primitive neither is a pointer nor an array + if( typeInfo ) return false; - // Null handle doesn't have an objectType, but it is not a primitive + // Null handle doesn't have a typeInfo, but it is not a primitive if( tokenType == ttUnrecognizedToken ) return false; @@ -584,16 +585,25 @@ bool asCDataType::IsObject() const return false; // Null handle doesn't have an object type but should still be considered an object - if( objectType == 0 ) + if( typeInfo == 0 ) return IsNullHandle(); - return true; + // Template subtypes shouldn't be considered objects + return CastToObjectType(typeInfo) ? true : false; +} + +bool asCDataType::IsFuncdef() const +{ + if (typeInfo && (typeInfo->flags & asOBJ_FUNCDEF)) + return true; + + return false; } int asCDataType::GetSizeInMemoryBytes() const { - if( objectType != 0 ) - return objectType->size; + if( typeInfo != 0 ) + return typeInfo->size; if( tokenType == ttVoid ) return 0; @@ -640,7 +650,7 @@ int asCDataType::GetSizeOnStackDWords() const int size = tokenType == ttQuestion ? 1 : 0; if( isReference ) return AS_PTR_SIZE + size; - if( objectType && !IsEnumType() ) return AS_PTR_SIZE + size; + if( typeInfo && !IsEnumType() ) return AS_PTR_SIZE + size; return GetSizeInMemoryDWords() + size; } @@ -648,27 +658,29 @@ int asCDataType::GetSizeOnStackDWords() const #ifdef WIP_16BYTE_ALIGN int asCDataType::GetAlignment() const { - if( objectType == NULL ) + if( typeInfo == NULL ) { // TODO: Small primitives should not be aligned to 4 byte boundaries return 4; //Default alignment } - return objectType->alignment; + return typeInfo->alignment; } #endif asSTypeBehaviour *asCDataType::GetBehaviour() const -{ - return objectType ? &objectType->beh : 0; +{ + if (!typeInfo) return 0; + asCObjectType *ot = CastToObjectType(typeInfo); + return ot ? &ot->beh : 0; } bool asCDataType::IsEnumType() const { // Do a sanity check on the objectType, to verify that we aren't trying to access memory after it has been released - asASSERT( objectType == 0 || objectType->name.GetLength() < 100 ); + asASSERT(typeInfo == 0 || typeInfo->name.GetLength() < 100); - if( objectType && (objectType->flags & asOBJ_ENUM) ) + if (typeInfo && (typeInfo->flags & asOBJ_ENUM)) return true; return false; diff --git a/lib/angelscript/source/as_datatype.h b/lib/angelscript/source/as_datatype.h index b079e447c..665f83a42 100644 --- a/lib/angelscript/source/as_datatype.h +++ b/lib/angelscript/source/as_datatype.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -47,12 +47,14 @@ BEGIN_AS_NAMESPACE struct asSTypeBehaviour; class asCScriptEngine; -class asCObjectType; +class asCTypeInfo; class asCScriptFunction; class asCModule; +class asCObjectType; +class asCEnumType; struct asSNameSpace; -// TODO: refactor: Reference should not be part of the datatype. This should be stored separately, e.g. in asCTypeInfo +// TODO: refactor: Reference should not be part of the datatype. This should be stored separately, e.g. in asCExprValue // MakeReference, MakeReadOnly, IsReference, IsReadOnly should be removed class asCDataType @@ -67,10 +69,9 @@ public: asCString Format(asSNameSpace *currNs, bool includeNamespace = false) const; static asCDataType CreatePrimitive(eTokenType tt, bool isConst); - static asCDataType CreateObject(asCObjectType *ot, bool isConst); + static asCDataType CreateType(asCTypeInfo *ti, bool isConst); static asCDataType CreateAuto(bool isConst); - static asCDataType CreateObjectHandle(asCObjectType *ot, bool isConst); - static asCDataType CreateFuncDef(asCScriptFunction *ot); + static asCDataType CreateObjectHandle(asCTypeInfo *ot, bool isConst); static asCDataType CreateNullHandle(); int MakeHandle(bool b, bool acceptHandleForScope = false); @@ -78,6 +79,8 @@ public: int MakeReference(bool b); int MakeReadOnly(bool b); int MakeHandleToConst(bool b); + void SetIfHandleThenConst(bool b) { ifHandleThenConst = b; } + bool HasIfHandleThenConst() const { return ifHandleThenConst; } bool IsTemplate() const; bool IsScriptObject() const; @@ -101,6 +104,7 @@ public: bool IsHandleToAsHandleType() const {return isHandleToAsHandleType;} bool IsAbstractClass() const; bool IsInterface() const; + bool IsFuncdef() const; bool IsObjectConst() const; @@ -118,8 +122,7 @@ public: asCDataType GetSubType(asUINT subtypeIndex = 0) const; eTokenType GetTokenType() const {return tokenType;} - asCObjectType *GetObjectType() const {return objectType;} - asCScriptFunction *GetFuncDef() const {return funcDef;} + asCTypeInfo *GetTypeInfo() const { return typeInfo; } int GetSizeOnStackDWords() const; int GetSizeInMemoryBytes() const; @@ -129,8 +132,7 @@ public: #endif void SetTokenType(eTokenType tt) {tokenType = tt;} - void SetObjectType(asCObjectType *obj) {objectType = obj;} - void SetFuncDef(asCScriptFunction *func) {asASSERT(funcDef); funcDef = func; } + void SetTypeInfo(asCTypeInfo *ti) {typeInfo = ti;} asCDataType &operator =(const asCDataType &); @@ -141,8 +143,7 @@ protected: eTokenType tokenType; // Behaviour type - asCObjectType *objectType; - asCScriptFunction *funcDef; + asCTypeInfo *typeInfo; // Top level bool isReference:1; @@ -151,7 +152,8 @@ protected: bool isConstHandle:1; bool isAuto:1; bool isHandleToAsHandleType:1; // Used by the compiler to know how to initialize the object - char dummy:2; + bool ifHandleThenConst:1; // Used when creating template instances to determine if a handle should be const or not + char dummy:1; }; END_AS_NAMESPACE diff --git a/lib/angelscript/source/as_debug.h b/lib/angelscript/source/as_debug.h index 197887401..e67d8b3ae 100644 --- a/lib/angelscript/source/as_debug.h +++ b/lib/angelscript/source/as_debug.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -49,7 +49,7 @@ #ifndef AS_PSVITA // Possible on PSVita, but requires SDK access -#if defined(__GNUC__) || defined( AS_MARMALADE ) +#if !defined(_MSC_VER) && (defined(__GNUC__) || defined(AS_MARMALADE)) #ifdef __ghs__ // WIIU defines __GNUC__ but types are not defined here in 'conventional' way diff --git a/lib/angelscript/source/as_gc.cpp b/lib/angelscript/source/as_gc.cpp index f488a5053..38a527f00 100644 --- a/lib/angelscript/source/as_gc.cpp +++ b/lib/angelscript/source/as_gc.cpp @@ -130,7 +130,7 @@ int asCGarbageCollector::AddScriptObjectToGC(void *obj, asCObjectType *objType) return ot.seqNbr; } -int asCGarbageCollector::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asIObjectType **type) +int asCGarbageCollector::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type) { if( seqNbr ) *seqNbr = 0; if( obj ) *obj = 0; diff --git a/lib/angelscript/source/as_gc.h b/lib/angelscript/source/as_gc.h index 3609ec42b..db8da0e40 100644 --- a/lib/angelscript/source/as_gc.h +++ b/lib/angelscript/source/as_gc.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -60,7 +60,7 @@ public: void GetStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const; void GCEnumCallback(void *reference); int AddScriptObjectToGC(void *obj, asCObjectType *objType); - int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asIObjectType **type); + int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type); int ReportAndReleaseUndestroyedObjects(); diff --git a/lib/angelscript/source/as_generic.cpp b/lib/angelscript/source/as_generic.cpp index 7510a6d05..14dd9cb6f 100644 --- a/lib/angelscript/source/as_generic.cpp +++ b/lib/angelscript/source/as_generic.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -62,6 +62,12 @@ asCGeneric::~asCGeneric() { } +// interface +void *asCGeneric::GetAuxiliary() const +{ + return sysFunction->GetAuxiliary(); +} + // interface asIScriptEngine *asCGeneric::GetEngine() const { @@ -83,7 +89,7 @@ void *asCGeneric::GetObject() // interface int asCGeneric::GetObjectTypeId() const { - asCDataType dt = asCDataType::CreateObject(sysFunction->objectType, false); + asCDataType dt = asCDataType::CreateType(sysFunction->objectType, false); return engine->GetTypeIdFromDataType(dt); } @@ -101,7 +107,7 @@ asBYTE asCGeneric::GetArgByte(asUINT arg) // Verify that the type is correct asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) return 0; if( dt->GetSizeInMemoryBytes() != 1 ) @@ -124,7 +130,7 @@ asWORD asCGeneric::GetArgWord(asUINT arg) // Verify that the type is correct asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) return 0; if( dt->GetSizeInMemoryBytes() != 2 ) @@ -147,7 +153,7 @@ asDWORD asCGeneric::GetArgDWord(asUINT arg) // Verify that the type is correct asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) return 0; if( dt->GetSizeInMemoryBytes() != 4 ) @@ -170,7 +176,7 @@ asQWORD asCGeneric::GetArgQWord(asUINT arg) // Verify that the type is correct asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) return 0; if( dt->GetSizeInMemoryBytes() != 8 ) @@ -193,7 +199,7 @@ float asCGeneric::GetArgFloat(asUINT arg) // Verify that the type is correct asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) return 0; if( dt->GetSizeInMemoryBytes() != 4 ) @@ -216,7 +222,7 @@ double asCGeneric::GetArgDouble(asUINT arg) // Verify that the type is correct asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) return 0; if( dt->GetSizeInMemoryBytes() != 8 ) @@ -259,7 +265,7 @@ void *asCGeneric::GetArgObject(asUINT arg) // Verify that the type is correct asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( !dt->IsObject() ) + if( !dt->IsObject() && !dt->IsFuncdef() ) return 0; // Determine the position of the argument @@ -325,14 +331,14 @@ int asCGeneric::GetArgTypeId(asUINT arg, asDWORD *flags) const int asCGeneric::SetReturnByte(asBYTE val) { // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) return asINVALID_TYPE; if( sysFunction->returnType.GetSizeInMemoryBytes() != 1 ) return asINVALID_TYPE; - // Store the value - *(asBYTE*)&returnVal = val; + // Store the value + *(asBYTE*)&returnVal = val; return 0; } @@ -341,14 +347,14 @@ int asCGeneric::SetReturnByte(asBYTE val) int asCGeneric::SetReturnWord(asWORD val) { // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) return asINVALID_TYPE; if( sysFunction->returnType.GetSizeInMemoryBytes() != 2 ) return asINVALID_TYPE; - // Store the value - *(asWORD*)&returnVal = val; + // Store the value + *(asWORD*)&returnVal = val; return 0; } @@ -357,14 +363,14 @@ int asCGeneric::SetReturnWord(asWORD val) int asCGeneric::SetReturnDWord(asDWORD val) { // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) return asINVALID_TYPE; if( sysFunction->returnType.GetSizeInMemoryBytes() != 4 ) return asINVALID_TYPE; - // Store the value - *(asDWORD*)&returnVal = val; + // Store the value + *(asDWORD*)&returnVal = val; return 0; } @@ -373,7 +379,7 @@ int asCGeneric::SetReturnDWord(asDWORD val) int asCGeneric::SetReturnQWord(asQWORD val) { // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) return asINVALID_TYPE; if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) @@ -389,7 +395,7 @@ int asCGeneric::SetReturnQWord(asQWORD val) int asCGeneric::SetReturnFloat(float val) { // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) return asINVALID_TYPE; if( sysFunction->returnType.GetSizeOnStackDWords() != 1 ) @@ -405,7 +411,7 @@ int asCGeneric::SetReturnFloat(float val) int asCGeneric::SetReturnDouble(double val) { // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) return asINVALID_TYPE; if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) @@ -441,7 +447,7 @@ int asCGeneric::SetReturnAddress(void *val) int asCGeneric::SetReturnObject(void *obj) { asCDataType *dt = &sysFunction->returnType; - if( !dt->IsObject() ) + if( !dt->IsObject() && !dt->IsFuncdef() ) return asINVALID_TYPE; if( dt->IsReference() ) @@ -453,9 +459,17 @@ int asCGeneric::SetReturnObject(void *obj) if( dt->IsObjectHandle() ) { // Increase the reference counter - asSTypeBehaviour *beh = &dt->GetObjectType()->beh; - if( obj && beh->addref ) - engine->CallObjectMethod(obj, beh->addref); + if (dt->IsFuncdef()) + { + if (obj) + reinterpret_cast(obj)->AddRef(); + } + else + { + asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh; + if (obj && beh && beh->addref) + engine->CallObjectMethod(obj, beh->addref); + } } else { @@ -463,7 +477,7 @@ int asCGeneric::SetReturnObject(void *obj) // Here we should just initialize that memory by calling the copy constructor // or the default constructor followed by the assignment operator void *mem = (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE]; - engine->ConstructScriptObjectCopy(mem, obj, dt->GetObjectType()); + engine->ConstructScriptObjectCopy(mem, obj, CastToObjectType(dt->GetTypeInfo())); return 0; } @@ -477,7 +491,7 @@ void *asCGeneric::GetReturnPointer() { asCDataType &dt = sysFunction->returnType; - if( dt.IsObject() && !dt.IsReference() ) + if( (dt.IsObject() ||dt.IsFuncdef()) && !dt.IsReference() ) { // This function doesn't support returning on the stack but the use of // the function doesn't require it so we don't need to implement it here. @@ -494,7 +508,7 @@ void *asCGeneric::GetAddressOfReturnLocation() { asCDataType &dt = sysFunction->returnType; - if( dt.IsObject() && !dt.IsReference() ) + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() ) { if( sysFunction->DoesReturnOnStack() ) { diff --git a/lib/angelscript/source/as_generic.h b/lib/angelscript/source/as_generic.h index dd122be13..158d8f9c7 100644 --- a/lib/angelscript/source/as_generic.h +++ b/lib/angelscript/source/as_generic.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -55,6 +55,7 @@ public: // Miscellaneous asIScriptEngine *GetEngine() const; asIScriptFunction *GetFunction() const; + void *GetAuxiliary() const; // Object void *GetObject(); diff --git a/lib/angelscript/source/as_globalproperty.cpp b/lib/angelscript/source/as_globalproperty.cpp index df2e51557..3fe4627fb 100644 --- a/lib/angelscript/source/as_globalproperty.cpp +++ b/lib/angelscript/source/as_globalproperty.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -120,13 +120,13 @@ void *asCGlobalProperty::GetRegisteredAddress() const return realAddress; } -void asCGlobalProperty::SetInitFunc(asCScriptFunction *initFunc) +void asCGlobalProperty::SetInitFunc(asCScriptFunction *in_initFunc) { // This should only be done once - asASSERT( this->initFunc == 0 ); + asASSERT( initFunc == 0 ); - this->initFunc = initFunc; - this->initFunc->AddRefInternal(); + initFunc = in_initFunc; + initFunc->AddRefInternal(); } asCScriptFunction *asCGlobalProperty::GetInitFunc() diff --git a/lib/angelscript/source/as_memory.cpp b/lib/angelscript/source/as_memory.cpp index a2a357b4d..db3b06f94 100644 --- a/lib/angelscript/source/as_memory.cpp +++ b/lib/angelscript/source/as_memory.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -38,8 +38,7 @@ #include -#if !defined(__APPLE__) && !defined( __SNC__ ) && !defined( __ghs__ ) \ - && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +#if !defined(__APPLE__) && !defined(__SNC__) && !defined(__ghs__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #include #endif diff --git a/lib/angelscript/source/as_module.cpp b/lib/angelscript/source/as_module.cpp index 2c81e0762..870a66932 100644 --- a/lib/angelscript/source/as_module.cpp +++ b/lib/angelscript/source/as_module.cpp @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -67,7 +67,7 @@ asCModule::~asCModule() { InternalReset(); - // The builder is not removed by InternalReset because it holds the script + // The builder is not removed by InternalReset because it holds the script // sections that will be built, so we need to explictly remove it now if it exists if( builder ) { @@ -111,7 +111,7 @@ void asCModule::Discard() asCScriptEngine *lEngine = engine; // Instead of deleting the module immediately, move it to the discarded pile - // This will turn it invisible to the application, yet keep it alive until all + // This will turn it invisible to the application, yet keep it alive until all // external references to its entities have been released. ACQUIREEXCLUSIVE(engine->engineRWLock); if( lEngine->lastModule == this ) @@ -195,9 +195,9 @@ asIScriptEngine *asCModule::GetEngine() const } // interface -void asCModule::SetName(const char *name) +void asCModule::SetName(const char *in_name) { - this->name = name; + name = in_name; } // interface @@ -248,13 +248,13 @@ int asCModule::SetDefaultNamespace(const char *nameSpace) } // interface -int asCModule::AddScriptSection(const char *name, const char *code, size_t codeLength, int lineOffset) +int asCModule::AddScriptSection(const char *in_name, const char *in_code, size_t in_codeLength, int in_lineOffset) { #ifdef AS_NO_COMPILER - UNUSED_VAR(name); - UNUSED_VAR(code); - UNUSED_VAR(codeLength); - UNUSED_VAR(lineOffset); + UNUSED_VAR(in_name); + UNUSED_VAR(in_code); + UNUSED_VAR(in_codeLength); + UNUSED_VAR(in_lineOffset); return asNOT_SUPPORTED; #else if( !builder ) @@ -264,7 +264,7 @@ int asCModule::AddScriptSection(const char *name, const char *code, size_t codeL return asOUT_OF_MEMORY; } - return builder->AddCode(name, code, (int)codeLength, lineOffset, (int)engine->GetScriptSectionNameIndex(name ? name : ""), engine->ep.copyScriptSections); + return builder->AddCode(in_name, in_code, (int)in_codeLength, in_lineOffset, (int)engine->GetScriptSectionNameIndex(in_name ? in_name : ""), engine->ep.copyScriptSections); #endif } @@ -287,7 +287,7 @@ int asCModule::Build() #else TimeIt("asCModule::Build"); - // Don't allow the module to be rebuilt if there are still + // Don't allow the module to be rebuilt if there are still // external references that will need the previous code // TODO: interface: The asIScriptModule must have a method for querying if the module is used if( HasExternalReferences(false) ) @@ -322,7 +322,7 @@ int asCModule::Build() r = builder->Build(); asDELETE(builder,asCBuilder); builder = 0; - + if( r < 0 ) { // Reset module again @@ -359,7 +359,7 @@ int asCModule::Build() // interface int asCModule::ResetGlobalVars(asIScriptContext *ctx) { - if( isGlobalVarInitialized ) + if( isGlobalVarInitialized ) CallExit(); return CallInit(ctx); @@ -374,7 +374,7 @@ asIScriptFunction *asCModule::GetFunctionByIndex(asUINT index) const // internal int asCModule::CallInit(asIScriptContext *myCtx) { - if( isGlobalVarInitialized ) + if( isGlobalVarInitialized ) return asERROR; // Each global variable needs to be cleared individually @@ -414,19 +414,19 @@ int asCModule::CallInit(asIScriptContext *myCtx) asCScriptFunction *func = desc->GetInitFunc(); engine->WriteMessage(func->scriptData->scriptSectionIdx >= 0 ? engine->scriptSectionNames[func->scriptData->scriptSectionIdx]->AddressOf() : "", - func->GetLineNumber(0, 0) & 0xFFFFF, + func->GetLineNumber(0, 0) & 0xFFFFF, func->GetLineNumber(0, 0) >> 20, asMSGTYPE_ERROR, msg.AddressOf()); - + if( r == asEXECUTION_EXCEPTION ) { const asIScriptFunction *function = ctx->GetExceptionFunction(); msg.Format(TXT_EXCEPTION_s_IN_s, ctx->GetExceptionString(), function->GetDeclaration()); - engine->WriteMessage(function->GetScriptSectionName(), - ctx->GetExceptionLineNumber(), + engine->WriteMessage(function->GetScriptSectionName(), + ctx->GetExceptionLineNumber(), 0, asMSGTYPE_INFORMATION, msg.AddressOf()); @@ -442,9 +442,9 @@ int asCModule::CallInit(asIScriptContext *myCtx) ctx = 0; } - // Even if the initialization failed we need to set the + // Even if the initialization failed we need to set the // flag that the variables have been initialized, otherwise - // the module won't free those variables that really were + // the module won't free those variables that really were // initialized. isGlobalVarInitialized = true; @@ -454,6 +454,48 @@ int asCModule::CallInit(asIScriptContext *myCtx) return asSUCCESS; } +// internal +void asCModule::UninitializeGlobalProp(asCGlobalProperty *prop) +{ + if (prop == 0) + return; + + if (prop->type.IsObject()) + { + void **obj = (void**)prop->GetAddressOfValue(); + if (*obj) + { + asCObjectType *ot = CastToObjectType(prop->type.GetTypeInfo()); + + if (ot->flags & asOBJ_REF) + { + asASSERT((ot->flags & asOBJ_NOCOUNT) || ot->beh.release); + if (ot->beh.release) + engine->CallObjectMethod(*obj, ot->beh.release); + } + else + { + if (ot->beh.destruct) + engine->CallObjectMethod(*obj, ot->beh.destruct); + + engine->CallFree(*obj); + } + + // Set the address to 0 as someone might try to access the variable afterwards + *obj = 0; + } + } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **func = (asCScriptFunction**)prop->GetAddressOfValue(); + if (*func) + { + (*func)->Release(); + *func = 0; + } + } +} + // internal void asCModule::CallExit() { @@ -462,31 +504,7 @@ void asCModule::CallExit() asCSymbolTableIterator it = scriptGlobals.List(); while( it ) { - if( (*it)->type.IsObject() ) - { - void **obj = (void**)(*it)->GetAddressOfValue(); - if( *obj ) - { - asCObjectType *ot = (*it)->type.GetObjectType(); - - if( ot->flags & asOBJ_REF ) - { - asASSERT( (ot->flags & asOBJ_NOCOUNT) || ot->beh.release ); - if( ot->beh.release ) - engine->CallObjectMethod(*obj, ot->beh.release); - } - else - { - if( ot->beh.destruct ) - engine->CallObjectMethod(*obj, ot->beh.destruct); - - engine->CallFree(*obj); - } - - // Set the address to 0 as someone might try to access the variable afterwards - *obj = 0; - } - } + UninitializeGlobalProp(*it); it++; } @@ -498,7 +516,30 @@ bool asCModule::HasExternalReferences(bool shuttingDown) { // Check all entiteis in the module for any external references. // If there are any external references the module cannot be deleted yet. - + + asCSymbolTableIterator it = scriptGlobals.List(); + while (it) + { + asCGlobalProperty *desc = *it; + if (desc->GetInitFunc() && desc->GetInitFunc()->externalRefCount.get()) + { + if( !shuttingDown ) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + // TODO: Use a better error message + asCString tmpName = "init " + desc->name; + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, tmpName.AddressOf(), desc->GetInitFunc()->GetFuncType()); + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + it++; + } + for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ ) if( scriptFunctions[n] && scriptFunctions[n]->externalRefCount.get() ) { @@ -542,7 +583,7 @@ bool asCModule::HasExternalReferences(bool shuttingDown) msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, name.AddressOf()); engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); - msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, funcDefs[n]->GetName(), funcDefs[n]->GetFuncType()); + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, funcDefs[n]->GetName(), funcDefs[n]->funcdef->GetFuncType()); engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); } } @@ -576,7 +617,7 @@ void asCModule::InternalReset() // Remove all global functions globalFunctions.Clear(); - // Destroy the internals of the global properties here, but do not yet remove them from the + // Destroy the internals of the global properties here, but do not yet remove them from the // engine, because functions need the engine's varAddressMap to get to the property. If the // property is removed already, it may leak as the refCount doesn't reach 0. asCSymbolTableIterator globIt = scriptGlobals.List(); @@ -650,7 +691,7 @@ void asCModule::InternalReset() classTypes.SetLength(0); for( n = 0; n < enumTypes.GetLength(); n++ ) { - asCObjectType *type = enumTypes[n]; + asCEnumType *type = enumTypes[n]; if( type->IsShared() ) { // The type is shared, so transfer ownership to another module that also uses it @@ -662,9 +703,6 @@ void asCModule::InternalReset() } } - // The type should be destroyed now - type->DestroyInternal(); - // Remove the type from the engine if( type->IsShared() ) { @@ -679,7 +717,7 @@ void asCModule::InternalReset() enumTypes.SetLength(0); for( n = 0; n < typeDefs.GetLength(); n++ ) { - asCObjectType *type = typeDefs[n]; + asCTypedefType *type = typeDefs[n]; // The type should be destroyed now type->DestroyInternal(); @@ -693,13 +731,14 @@ void asCModule::InternalReset() // Free funcdefs for( n = 0; n < funcDefs.GetLength(); n++ ) { - asCScriptFunction *func = funcDefs[n]; - if( func->IsShared() ) + asCFuncdefType *func = funcDefs[n]; + asASSERT(func); + if( func->funcdef && func->funcdef->IsShared() ) { - // The func is shared, so transfer ownership to another module that also uses it - if( engine->FindNewOwnerForSharedFunc(func, this) != this ) + // The funcdef is shared, so transfer ownership to another module that also uses it + if( engine->FindNewOwnerForSharedType(func, this) != this ) { - // The func is owned by another module, just release our reference + // The funcdef is owned by another module, just release our reference func->ReleaseInternal(); continue; } @@ -748,12 +787,12 @@ void asCModule::InternalReset() } // interface -asIScriptFunction *asCModule::GetFunctionByName(const char *name) const +asIScriptFunction *asCModule::GetFunctionByName(const char *in_name) const { asSNameSpace *ns = defaultNamespace; while( ns ) { - const asCArray &idxs = globalFunctions.GetIndexes(ns, name); + const asCArray &idxs = globalFunctions.GetIndexes(ns, in_name); if( idxs.GetLength() != 1 ) return 0; @@ -790,7 +829,7 @@ int asCModule::GetImportedFunctionIndexByDecl(const char *decl) const int id = -1; for( asUINT n = 0; n < bindInformations.GetLength(); ++n ) { - if( func.name == bindInformations[n]->importedFunctionSignature->name && + if( func.name == bindInformations[n]->importedFunctionSignature->name && func.returnType == bindInformations[n]->importedFunctionSignature->returnType && func.parameterTypes.GetLength() == bindInformations[n]->importedFunctionSignature->parameterTypes.GetLength() ) { @@ -898,14 +937,14 @@ asUINT asCModule::GetGlobalVarCount() const } // interface -int asCModule::GetGlobalVarIndexByName(const char *name) const +int asCModule::GetGlobalVarIndexByName(const char *in_name) const { asSNameSpace *ns = defaultNamespace; // Find the global var id while( ns ) { - int id = scriptGlobals.GetFirstIndex(ns, name); + int id = scriptGlobals.GetFirstIndex(ns, in_name); if( id >= 0 ) return id; // Recursively search parent namespaces @@ -922,17 +961,22 @@ int asCModule::RemoveGlobalVar(asUINT index) if( !prop ) return asINVALID_ARG; + // If the global variables have already been initialized + // then uninitialize the variable before it is removed + if (isGlobalVarInitialized) + UninitializeGlobalProp(prop); + // Destroy the internal of the global variable (removes the initialization function) prop->DestroyInternal(); - // Check if the module is the only one referring to the module, if so remove it from the engine too + // Check if the module is the only one referring to the property, if so remove it from the engine too // If the property is not removed now, it will be removed later when the module is discarded if( prop->refCount.get() == 2 ) engine->RemoveGlobalProperty(prop); // Remove the global variable from the module - prop->Release(); scriptGlobals.Erase(index); + prop->Release(); return 0; } @@ -945,17 +989,17 @@ int asCModule::GetGlobalVarIndexByDecl(const char *decl) const // Don't write parser errors to the message callback bld.silent = true; - asCString name; + asCString declName; asSNameSpace *nameSpace; asCDataType dt; - int r = bld.ParseVariableDeclaration(decl, defaultNamespace, name, nameSpace, dt); + int r = bld.ParseVariableDeclaration(decl, defaultNamespace, declName, nameSpace, dt); if( r < 0 ) return r; // Search global variables for a match while( nameSpace ) { - int id = scriptGlobals.GetFirstIndex(nameSpace, name, asCCompGlobPropType(dt)); + int id = scriptGlobals.GetFirstIndex(nameSpace, declName, asCCompGlobPropType(dt)); if( id != -1 ) return id; @@ -970,7 +1014,7 @@ int asCModule::GetGlobalVarIndexByDecl(const char *decl) const void *asCModule::GetAddressOfGlobalVar(asUINT index) { asCGlobalProperty *prop = scriptGlobals.Get(index); - if( !prop ) + if( !prop ) return 0; // For object variables it's necessary to dereference the pointer to get the address of the value @@ -998,19 +1042,19 @@ const char *asCModule::GetGlobalVarDeclaration(asUINT index, bool includeNamespa } // interface -int asCModule::GetGlobalVar(asUINT index, const char **name, const char **nameSpace, int *typeId, bool *isConst) const +int asCModule::GetGlobalVar(asUINT index, const char **out_name, const char **out_nameSpace, int *out_typeId, bool *out_isConst) const { const asCGlobalProperty *prop = scriptGlobals.Get(index); if (!prop) return 0; - if( name ) - *name = prop->name.AddressOf(); - if( nameSpace ) - *nameSpace = prop->nameSpace->name.AddressOf(); - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(prop->type); - if( isConst ) - *isConst = prop->type.IsReadOnly(); + if( out_name ) + *out_name = prop->name.AddressOf(); + if( out_nameSpace ) + *out_nameSpace = prop->nameSpace->name.AddressOf(); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(prop->type); + if( out_isConst ) + *out_isConst = prop->type.IsReadOnly(); return asSUCCESS; } @@ -1021,29 +1065,45 @@ asUINT asCModule::GetObjectTypeCount() const return (asUINT)classTypes.GetLength(); } -// interface -asIObjectType *asCModule::GetObjectTypeByIndex(asUINT index) const +// interface +asITypeInfo *asCModule::GetObjectTypeByIndex(asUINT index) const { - if( index >= classTypes.GetLength() ) + if( index >= classTypes.GetLength() ) return 0; return classTypes[index]; } // interface -asIObjectType *asCModule::GetObjectTypeByName(const char *name) const +asITypeInfo *asCModule::GetTypeInfoByName(const char *in_name) const { asSNameSpace *ns = defaultNamespace; - while( ns ) + while (ns) { - for( asUINT n = 0; n < classTypes.GetLength(); n++ ) + for (asUINT n = 0; n < classTypes.GetLength(); n++) { - if( classTypes[n] && - classTypes[n]->name == name && - classTypes[n]->nameSpace == ns ) + if (classTypes[n] && + classTypes[n]->name == in_name && + classTypes[n]->nameSpace == ns) return classTypes[n]; } + for (asUINT n = 0; n < enumTypes.GetLength(); n++) + { + if (enumTypes[n] && + enumTypes[n]->name == in_name && + enumTypes[n]->nameSpace == ns) + return enumTypes[n]; + } + + for (asUINT n = 0; n < typeDefs.GetLength(); n++) + { + if (typeDefs[n] && + typeDefs[n]->name == in_name && + typeDefs[n]->nameSpace == ns) + return typeDefs[n]; + } + // Recursively search parent namespace ns = engine->GetParentNameSpace(ns); } @@ -1070,7 +1130,7 @@ int asCModule::GetTypeIdByDecl(const char *decl) const } // interface -asIObjectType *asCModule::GetObjectTypeByDecl(const char *decl) const +asITypeInfo *asCModule::GetTypeInfoByDecl(const char *decl) const { asCDataType dt; @@ -1081,59 +1141,25 @@ asIObjectType *asCModule::GetObjectTypeByDecl(const char *decl) const bld.silent = true; int r = bld.ParseDataType(decl, &dt, defaultNamespace); - if( r < 0 ) + if (r < 0) return 0; - return dt.GetObjectType(); + return dt.GetTypeInfo(); } // interface asUINT asCModule::GetEnumCount() const { - return (asUINT)enumTypes.GetLength(); + return enumTypes.GetLength(); } // interface -const char *asCModule::GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace) const +asITypeInfo *asCModule::GetEnumByIndex(asUINT index) const { if( index >= enumTypes.GetLength() ) return 0; - if( enumTypeId ) - *enumTypeId = engine->GetTypeIdFromDataType(asCDataType::CreateObject(enumTypes[index], false)); - - if( nameSpace ) - *nameSpace = enumTypes[index]->nameSpace->name.AddressOf(); - - return enumTypes[index]->name.AddressOf(); -} - -// interface -int asCModule::GetEnumValueCount(int enumTypeId) const -{ - asCDataType dt = engine->GetDataTypeFromTypeId(enumTypeId); - asCObjectType *t = dt.GetObjectType(); - if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) ) - return asINVALID_TYPE; - - return (int)t->enumValues.GetLength(); -} - -// interface -const char *asCModule::GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const -{ - asCDataType dt = engine->GetDataTypeFromTypeId(enumTypeId); - asCObjectType *t = dt.GetObjectType(); - if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) ) - return 0; - - if( index >= t->enumValues.GetLength() ) - return 0; - - if( outValue ) - *outValue = t->enumValues[index]->value; - - return t->enumValues[index]->name.AddressOf(); + return enumTypes[index]; } // interface @@ -1143,21 +1169,14 @@ asUINT asCModule::GetTypedefCount() const } // interface -const char *asCModule::GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace) const +asITypeInfo *asCModule::GetTypedefByIndex(asUINT index) const { if( index >= typeDefs.GetLength() ) return 0; - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(typeDefs[index]->templateSubTypes[0]); - - if( nameSpace ) - *nameSpace = typeDefs[index]->nameSpace->name.AddressOf(); - - return typeDefs[index]->name.AddressOf(); + return typeDefs[index]; } - // internal int asCModule::GetNextImportedFunctionId() { @@ -1170,7 +1189,7 @@ int asCModule::GetNextImportedFunctionId() #ifndef AS_NO_COMPILER // internal -int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType, bool isConstMethod, bool isGlobalFunction, bool isPrivate, bool isProtected, bool isFinal, bool isOverride, bool isShared, asSNameSpace *ns) +int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &funcName, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType, bool isGlobalFunction, asSFunctionTraits funcTraits, asSNameSpace *ns) { asASSERT(id >= 0); @@ -1191,9 +1210,9 @@ int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const a // All methods of shared objects are also shared if( objType && objType->IsShared() ) - isShared = true; + funcTraits.SetTrait(asTRAIT_SHARED, true); - func->name = name; + func->name = funcName; func->nameSpace = ns; func->id = id; func->returnType = returnType; @@ -1209,18 +1228,13 @@ int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const a func->objectType = objType; if( objType ) objType->AddRefInternal(); - func->isReadOnly = isConstMethod; - func->isPrivate = isPrivate; - func->isProtected = isProtected; - func->isFinal = isFinal; - func->isOverride = isOverride; - func->isShared = isShared; + func->traits = funcTraits; asASSERT( params.GetLength() == inOutFlags.GetLength() && params.GetLength() == defaultArgs.GetLength() ); // Verify that we are not assigning either the final or override specifier(s) if we are registering a non-member function - asASSERT( !(!objType && isFinal) ); - asASSERT( !(!objType && isOverride) ); + asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_FINAL)) ); + asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_OVERRIDE)) ); // The internal ref count was already set by the constructor scriptFunctions.PushLast(func); @@ -1237,7 +1251,7 @@ int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const a return 0; } -// internal +// internal int asCModule::AddScriptFunction(asCScriptFunction *func) { scriptFunctions.PushLast(func); @@ -1247,9 +1261,9 @@ int asCModule::AddScriptFunction(asCScriptFunction *func) // If the function that is being added is an already compiled shared function // then it is necessary to look for anonymous functions that may be declared // within it and add those as well - if( func->isShared && func->funcType == asFUNC_SCRIPT ) + if( func->IsShared() && func->funcType == asFUNC_SCRIPT ) { - // Loop through the byte code and check all the + // Loop through the byte code and check all the // asBC_FuncPtr instructions for anonymous functions asDWORD *bc = func->scriptData->byteCode.AddressOf(); asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength(); @@ -1275,7 +1289,7 @@ int asCModule::AddScriptFunction(asCScriptFunction *func) } // internal -int asCModule::AddImportedFunction(int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSNameSpace *ns, const asCString &moduleName) +int asCModule::AddImportedFunction(int id, const asCString &funcName, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSNameSpace *ns, const asCString &moduleName) { asASSERT(id >= 0); @@ -1291,7 +1305,7 @@ int asCModule::AddImportedFunction(int id, const asCString &name, const asCDataT return asOUT_OF_MEMORY; } - func->name = name; + func->name = funcName; func->id = id; func->returnType = returnType; func->nameSpace = ns; @@ -1343,7 +1357,7 @@ int asCModule::BindImportedFunction(asUINT index, asIScriptFunction *func) return asINVALID_ARG; asCScriptFunction *src = engine->GetScriptFunction(func->GetId()); - if( src == 0 ) + if( src == 0 ) return asNO_FUNCTION; // Verify return type @@ -1454,6 +1468,35 @@ int asCModule::UnbindAllImportedFunctions() return asSUCCESS; } +// internal +asCTypeInfo *asCModule::GetType(const char *type, asSNameSpace *ns) +{ + asUINT n; + + // TODO: optimize: Improve linear search + for (n = 0; n < classTypes.GetLength(); n++) + if (classTypes[n]->name == type && + classTypes[n]->nameSpace == ns) + return classTypes[n]; + + for (n = 0; n < enumTypes.GetLength(); n++) + if (enumTypes[n]->name == type && + enumTypes[n]->nameSpace == ns) + return enumTypes[n]; + + for (n = 0; n < typeDefs.GetLength(); n++) + if (typeDefs[n]->name == type && + typeDefs[n]->nameSpace == ns) + return typeDefs[n]; + + for (n = 0; n < funcDefs.GetLength(); n++) + if (funcDefs[n]->name == type && + funcDefs[n]->nameSpace == ns) + return funcDefs[n]; + + return 0; +} + // internal asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) { @@ -1465,24 +1508,14 @@ asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) classTypes[n]->nameSpace == ns ) return classTypes[n]; - for( n = 0; n < enumTypes.GetLength(); n++ ) - if( enumTypes[n]->name == type && - enumTypes[n]->nameSpace == ns ) - return enumTypes[n]; - - for( n = 0; n < typeDefs.GetLength(); n++ ) - if( typeDefs[n]->name == type && - typeDefs[n]->nameSpace == ns ) - return typeDefs[n]; - return 0; } // internal -asCGlobalProperty *asCModule::AllocateGlobalProperty(const char *name, const asCDataType &dt, asSNameSpace *ns) +asCGlobalProperty *asCModule::AllocateGlobalProperty(const char *propName, const asCDataType &dt, asSNameSpace *ns) { asCGlobalProperty *prop = engine->AllocateGlobalProperty(); - prop->name = name; + prop->name = propName; prop->nameSpace = ns; // Allocate the memory for this property based on its type @@ -1538,7 +1571,7 @@ int asCModule::LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped) { if( in == 0 ) return asINVALID_ARG; - // Don't allow the module to be rebuilt if there are still + // Don't allow the module to be rebuilt if there are still // external references that will need the previous code if( HasExternalReferences(false) ) { @@ -1554,6 +1587,11 @@ int asCModule::LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped) asCReader read(this, in, engine); r = read.Read(wasDebugInfoStripped); + if (r < 0) + { + engine->BuildCompleted(); + return r; + } JITCompile(); @@ -1601,33 +1639,33 @@ int asCModule::CompileGlobalVar(const char *sectionName, const char *code, int l } // Compile the global variable and add it to the module scope - asCBuilder builder(engine, this); + asCBuilder varBuilder(engine, this); asCString str = code; - r = builder.CompileGlobalVar(sectionName, str.AddressOf(), lineOffset); + r = varBuilder.CompileGlobalVar(sectionName, str.AddressOf(), lineOffset); engine->BuildCompleted(); // Initialize the variable if( r >= 0 && engine->ep.initGlobalVarsAfterBuild ) { - // Clear the memory + // Clear the memory asCGlobalProperty *prop = scriptGlobals.GetLast(); if( prop ) { memset(prop->GetAddressOfValue(), 0, sizeof(asDWORD)*prop->type.GetSizeOnStackDWords()); - + if( prop->GetInitFunc() ) { // Call the init function for the global variable asIScriptContext *ctx = 0; - int r = engine->CreateContext(&ctx, true); + r = engine->CreateContext(&ctx, true); if( r < 0 ) return r; - + r = ctx->Prepare(prop->GetInitFunc()); if( r >= 0 ) r = ctx->Execute(); - + ctx->Release(); } } @@ -1640,7 +1678,7 @@ int asCModule::CompileGlobalVar(const char *sectionName, const char *code, int l // interface 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 if( outFunc ) *outFunc = 0; @@ -1653,7 +1691,7 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li return asNOT_SUPPORTED; #else // Validate arguments - if( code == 0 || + if( code == 0 || (compileFlags != 0 && compileFlags != asCOMP_ADD_TO_MODULE) ) return asINVALID_ARG; @@ -1673,10 +1711,10 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li } // Compile the single function - asCBuilder builder(engine, this); + asCBuilder funcBuilder(engine, this); asCString str = code; asCScriptFunction *func = 0; - r = builder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func); + r = funcBuilder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func); engine->BuildCompleted(); @@ -1714,22 +1752,32 @@ int asCModule::RemoveFunction(asIScriptFunction *func) #ifndef AS_NO_COMPILER // internal -int asCModule::AddFuncDef(const asCString &name, asSNameSpace *ns) +int asCModule::AddFuncDef(const asCString &funcName, asSNameSpace *ns, asCObjectType *parent) { + // namespace and parent are mutually exclusive + asASSERT((ns == 0 && parent) || (ns && parent == 0)); + asCScriptFunction *func = asNEW(asCScriptFunction)(engine, 0, asFUNC_FUNCDEF); - if( func == 0 ) + if (func == 0) return asOUT_OF_MEMORY; - func->name = name; + func->name = funcName; func->nameSpace = ns; func->module = this; - funcDefs.PushLast(func); + asCFuncdefType *fdt = asNEW(asCFuncdefType)(engine, func); + funcDefs.PushLast(fdt); // The constructor set the refcount to 1 - engine->funcDefs.PushLast(func); + engine->funcDefs.PushLast(fdt); // doesn't increase refcount func->id = engine->GetNextScriptFunctionId(); engine->AddScriptFunction(func); + if (parent) + { + parent->childFuncDefs.PushLast(fdt); + fdt->parentClass = parent; + } + return (int)funcDefs.GetLength()-1; } #endif diff --git a/lib/angelscript/source/as_module.h b/lib/angelscript/source/as_module.h index 22ad598d4..6915fe40e 100644 --- a/lib/angelscript/source/as_module.h +++ b/lib/angelscript/source/as_module.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -58,12 +58,14 @@ class asCCompiler; class asCBuilder; class asCContext; class asCConfigGroup; +class asCTypedefType; +class asCFuncdefType; struct asSNameSpace; struct sBindInfo { asCScriptFunction *importedFunctionSignature; - asCString importFromModule; + asCString importFromModule; int boundFunctionId; }; @@ -74,17 +76,17 @@ struct sObjectTypePair }; -// TODO: import: Remove function imports. When I have implemented function +// TODO: import: Remove function imports. When I have implemented function // pointers the function imports should be deprecated. // TODO: Need a separate interface for compiling scripts. The asIScriptCompiler // will have a target module, and will allow the compilation of an entire // script or just individual functions within the scope of the module -// +// // With this separation it will be possible to compile the library without // the compiler, thus giving a much smaller binary executable. -// TODO: There should be an special compile option that will let the application +// TODO: There should be a special compile option that will let the application // recompile an already compiled script. The compiler should check if no // destructive changes have been made (changing function signatures, etc) // then it should simply replace the bytecode within the functions without @@ -130,20 +132,18 @@ public: // Type identification virtual asUINT GetObjectTypeCount() const; - virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const; - virtual asIObjectType *GetObjectTypeByName(const char *name) const; - virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const; virtual int GetTypeIdByDecl(const char *decl) const; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const; // Enums - virtual asUINT GetEnumCount() const; - virtual const char *GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace) const; - virtual int GetEnumValueCount(int enumTypeId) const; - virtual const char *GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const; + virtual asUINT GetEnumCount() const; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const; // Typedefs - virtual asUINT GetTypedefCount() const; - virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace) const; + virtual asUINT GetTypedefCount() const; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) const; // Dynamic binding between modules virtual asUINT GetImportedFunctionCount() const; @@ -186,16 +186,18 @@ public: void JITCompile(); #ifndef AS_NO_COMPILER - int AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType = 0, bool isConstMethod = false, bool isGlobalFunction = false, bool isPrivate = false, bool isProtected = false, bool isFinal = false, bool isOverride = false, bool isShared = false, asSNameSpace *ns = 0); + int AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType = 0, bool isGlobalFunction = false, asSFunctionTraits funcTraits = asSFunctionTraits(), asSNameSpace *ns = 0); int AddScriptFunction(asCScriptFunction *func); int AddImportedFunction(int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSNameSpace *ns, const asCString &moduleName); - int AddFuncDef(const asCString &name, asSNameSpace *ns); + int AddFuncDef(const asCString &name, asSNameSpace *ns, asCObjectType *parent); #endif int GetNextImportedFunctionId(); asCScriptFunction *GetImportedFunction(int funcId) const; + asCTypeInfo *GetType(const char *type, asSNameSpace *ns); asCObjectType *GetObjectType(const char *type, asSNameSpace *ns); asCGlobalProperty *AllocateGlobalProperty(const char *name, const asCDataType &dt, asSNameSpace *ns); + void UninitializeGlobalProp(asCGlobalProperty *prop); asCString name; @@ -208,7 +210,7 @@ public: // This array holds all functions, class members, factories, etc that were compiled with the module. // These references hold an internal reference to the function object. asCArray scriptFunctions; // increases ref count - // This array holds global functions declared in the module. These references are not counted, + // This array holds global functions declared in the module. These references are not counted, // as the same pointer is always present in the scriptFunctions array too. asCSymbolTable globalFunctions; // doesn't increase ref count // This array holds imported functions in the module. @@ -223,11 +225,16 @@ public: // This array holds class and interface types asCArray classTypes; // increases ref count // This array holds enum types - asCArray enumTypes; // increases ref count + asCArray enumTypes; // increases ref count // This array holds typedefs - asCArray typeDefs; // increases ref count + asCArray typeDefs; // increases ref count // This array holds the funcdefs declared in the module - asCArray funcDefs; // increases ref count + asCArray funcDefs; // increases ref count + + // This array holds types that have been explicitly declared with 'external' + asCArray externalTypes; // doesn't increase ref count + // This array holds functions that have been explicitly declared with 'external' + asCArray externalFunctions; // doesn't increase ref count }; END_AS_NAMESPACE diff --git a/lib/angelscript/source/as_objecttype.cpp b/lib/angelscript/source/as_objecttype.cpp index 8bded269d..626cb11b1 100644 --- a/lib/angelscript/source/as_objecttype.cpp +++ b/lib/angelscript/source/as_objecttype.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -45,155 +45,46 @@ BEGIN_AS_NAMESPACE -asCObjectType::asCObjectType() +asCObjectType::asCObjectType() : asCTypeInfo() { - externalRefCount.set(0); - internalRefCount.set(1); // start with one internal ref-count - engine = 0; - module = 0; derivedFrom = 0; - size = 0; - typeId = -1; // start as -1 to signal that it hasn't been defined acceptValueSubType = true; acceptRefSubType = true; - scriptSectionIdx = -1; - declaredAt = 0; - - accessMask = 0xFFFFFFFF; - nameSpace = 0; #ifdef WIP_16BYTE_ALIGN alignment = 4; #endif } -asCObjectType::asCObjectType(asCScriptEngine *engine) +asCObjectType::asCObjectType(asCScriptEngine *in_engine) : asCTypeInfo(in_engine) { - externalRefCount.set(0); - internalRefCount.set(1); // start with one internal ref count - this->engine = engine; - module = 0; derivedFrom = 0; - typeId = -1; // start as -1 to signal that it hasn't been defined acceptValueSubType = true; - acceptRefSubType = true; + acceptRefSubType = true; - scriptSectionIdx = -1; - declaredAt = 0; - - accessMask = 0xFFFFFFFF; - nameSpace = engine->nameSpaces[0]; #ifdef WIP_16BYTE_ALIGN alignment = 4; #endif } -int asCObjectType::AddRef() const -{ - return externalRefCount.atomicInc(); -} - -int asCObjectType::Release() const -{ - int r = externalRefCount.atomicDec(); - - if( r == 0 ) - { - // There are no more external references, if there are also no - // internal references then it is time to delete the object type - if( internalRefCount.get() == 0 ) - { - // If the engine is no longer set, then it has already been - // released and we must take care of the deletion ourselves - asDELETE(const_cast(this), asCObjectType); - } - } - - return r; -} - -int asCObjectType::AddRefInternal() -{ - return internalRefCount.atomicInc(); -} - -int asCObjectType::ReleaseInternal() -{ - int r = internalRefCount.atomicDec(); - - if( r == 0 ) - { - // There are no more internal references, if there are also no - // external references then it is time to delete the object type - if( externalRefCount.get() == 0 ) - { - // If the engine is no longer set, then it has already been - // released and we must take care of the deletion ourselves - asDELETE(const_cast(this), asCObjectType); - } - } - - return r; -} - // interface -asIScriptModule *asCObjectType::GetModule() const +asUINT asCObjectType::GetChildFuncdefCount() const { - return module; + return childFuncDefs.GetLength(); } -void *asCObjectType::SetUserData(void *data, asPWORD type) +// interface +asITypeInfo *asCObjectType::GetChildFuncdef(asUINT index) const { - // As a thread might add a new new user data at the same time as another - // it is necessary to protect both read and write access to the userData member - ACQUIREEXCLUSIVE(engine->engineRWLock); + if (index >= childFuncDefs.GetLength()) + return 0; - // It is not intended to store a lot of different types of userdata, - // so a more complex structure like a associative map would just have - // more overhead than a simple array. - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - void *oldData = reinterpret_cast(userData[n+1]); - userData[n+1] = reinterpret_cast(data); - - RELEASEEXCLUSIVE(engine->engineRWLock); - - return oldData; - } - } - - userData.PushLast(type); - userData.PushLast(reinterpret_cast(data)); - - RELEASEEXCLUSIVE(engine->engineRWLock); - - return 0; -} - -void *asCObjectType::GetUserData(asPWORD type) const -{ - // There may be multiple threads reading, but when - // setting the user data nobody must be reading. - ACQUIRESHARED(engine->engineRWLock); - - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - RELEASESHARED(engine->engineRWLock); - return reinterpret_cast(userData[n+1]); - } - } - - RELEASESHARED(engine->engineRWLock); - - return 0; + return childFuncDefs[index]; } +// internal void asCObjectType::DestroyInternal() { if( engine == 0 ) return; @@ -207,13 +98,38 @@ void asCObjectType::DestroyInternal() } // Release the object types held by the templateSubTypes + bool isTemplateInstance = templateSubTypes.GetLength() > 0; for( asUINT subtypeIndex = 0; subtypeIndex < templateSubTypes.GetLength(); subtypeIndex++ ) { - if( templateSubTypes[subtypeIndex].GetObjectType() ) - templateSubTypes[subtypeIndex].GetObjectType()->ReleaseInternal(); + if( templateSubTypes[subtypeIndex].GetTypeInfo() ) + templateSubTypes[subtypeIndex].GetTypeInfo()->ReleaseInternal(); } templateSubTypes.SetLength(0); + // Clear the child types + for (asUINT n = 0; n < childFuncDefs.GetLength(); n++) + { + asCFuncdefType *func = childFuncDefs[n]; + if (func) + { + func->parentClass = 0; + if (isTemplateInstance) + { + // Any child funcdefs that have been created as part of the template + // instantiation must be destroyed too + // TODO: Before destroying the funcdef, make sure no external references to it is held + if (func->externalRefCount.get() == 0) + { + func->DestroyInternal(); + engine->RemoveFuncdef(func); + func->module = 0; + func->ReleaseInternal(); + } + } + } + } + childFuncDefs.SetLength(0); + if( derivedFrom ) derivedFrom->ReleaseInternal(); derivedFrom = 0; @@ -222,25 +138,7 @@ void asCObjectType::DestroyInternal() ReleaseAllFunctions(); - asUINT n; - for( n = 0; n < enumValues.GetLength(); n++ ) - { - if( enumValues[n] ) - asDELETE(enumValues[n],asSEnumValue); - } - enumValues.SetLength(0); - - // Clean the user data - for( n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n+1] ) - { - for( asUINT c = 0; c < engine->cleanObjectTypeFuncs.GetLength(); c++ ) - if( engine->cleanObjectTypeFuncs[c].type == userData[n] ) - engine->cleanObjectTypeFuncs[c].cleanFunc(this); - } - } - userData.SetLength(0); + CleanUserData(); // Remove the type from the engine if( typeId != -1 ) @@ -252,14 +150,11 @@ void asCObjectType::DestroyInternal() asCObjectType::~asCObjectType() { - if( engine == 0 ) - return; - DestroyInternal(); } // interface -bool asCObjectType::Implements(const asIObjectType *objType) const +bool asCObjectType::Implements(const asITypeInfo *objType) const { if( this == objType ) return true; @@ -271,7 +166,7 @@ bool asCObjectType::Implements(const asIObjectType *objType) const } // interface -bool asCObjectType::DerivesFrom(const asIObjectType *objType) const +bool asCObjectType::DerivesFrom(const asITypeInfo *objType) const { if( this == objType ) return true; @@ -288,56 +183,6 @@ bool asCObjectType::DerivesFrom(const asIObjectType *objType) const return false; } -bool asCObjectType::IsShared() const -{ - // Objects that can be declared by scripts need to have the explicit flag asOBJ_SHARED - if( flags & (asOBJ_SCRIPT_OBJECT|asOBJ_ENUM) ) return flags & asOBJ_SHARED ? true : false; - - // Otherwise we assume the object to be shared - return true; -} - -// interface -const char *asCObjectType::GetName() const -{ - return name.AddressOf(); -} - -// interface -const char *asCObjectType::GetNamespace() const -{ - return nameSpace->name.AddressOf(); -} - -// interface -asDWORD asCObjectType::GetFlags() const -{ - return flags; -} - -// interface -asUINT asCObjectType::GetSize() const -{ - return size; -} - -// interface -int asCObjectType::GetTypeId() const -{ - if( typeId == -1 ) - { - // We need a non const pointer to create the asCDataType object. - // We're not breaking anything here because this function is not - // modifying the object, so this const cast is safe. - asCObjectType *ot = const_cast(this); - - // The engine will define the typeId for this object type - engine->GetTypeIdFromDataType(asCDataType::CreateObject(ot, false)); - } - - return typeId; -} - // interface int asCObjectType::GetSubTypeId(asUINT subtypeIndex) const { @@ -352,12 +197,12 @@ int asCObjectType::GetSubTypeId(asUINT subtypeIndex) const } // interface -asIObjectType *asCObjectType::GetSubType(asUINT subtypeIndex) const +asITypeInfo *asCObjectType::GetSubType(asUINT subtypeIndex) const { if( subtypeIndex >= templateSubTypes.GetLength() ) return 0; - return templateSubTypes[subtypeIndex].GetObjectType(); + return templateSubTypes[subtypeIndex].GetTypeInfo(); } asUINT asCObjectType::GetSubTypeCount() const @@ -370,7 +215,7 @@ asUINT asCObjectType::GetInterfaceCount() const return asUINT(interfaces.GetLength()); } -asIObjectType *asCObjectType::GetInterface(asUINT index) const +asITypeInfo *asCObjectType::GetInterface(asUINT index) const { return interfaces[index]; } @@ -384,11 +229,6 @@ bool asCObjectType::IsInterface() const return false; } -asIScriptEngine *asCObjectType::GetEngine() const -{ - return engine; -} - // interface asUINT asCObjectType::GetFactoryCount() const { @@ -437,12 +277,12 @@ asIScriptFunction *asCObjectType::GetMethodByIndex(asUINT index, bool getVirtual } // interface -asIScriptFunction *asCObjectType::GetMethodByName(const char *name, bool getVirtual) const +asIScriptFunction *asCObjectType::GetMethodByName(const char *in_name, bool in_getVirtual) const { int id = -1; for( asUINT n = 0; n < methods.GetLength(); n++ ) { - if( engine->scriptFunctions[methods[n]]->name == name ) + if( engine->scriptFunctions[methods[n]]->name == in_name ) { if( id == -1 ) id = methods[n]; @@ -454,7 +294,7 @@ asIScriptFunction *asCObjectType::GetMethodByName(const char *name, bool getVirt if( id == -1 ) return 0; asCScriptFunction *func = engine->scriptFunctions[id]; - if( !getVirtual ) + if( !in_getVirtual ) { if( func && func->funcType == asFUNC_VIRTUAL ) return virtualFunctionTable[func->vfTableIdx]; @@ -497,26 +337,30 @@ asUINT asCObjectType::GetPropertyCount() const } // interface -int asCObjectType::GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask) const +int asCObjectType::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const { if( index >= properties.GetLength() ) return asINVALID_ARG; asCObjectProperty *prop = properties[index]; - if( name ) - *name = prop->name.AddressOf(); - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(prop->type); - if( isPrivate ) - *isPrivate = prop->isPrivate; - if( isProtected ) - *isProtected = prop->isProtected; - if( offset ) - *offset = prop->byteOffset; - if( isReference ) - *isReference = prop->type.IsReference(); - if( accessMask ) - *accessMask = prop->accessMask; + if( out_name ) + *out_name = prop->name.AddressOf(); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(prop->type); + if( out_isPrivate ) + *out_isPrivate = prop->isPrivate; + if( out_isProtected ) + *out_isProtected = prop->isProtected; + if( out_offset ) + *out_offset = prop->byteOffset; + if( out_isReference ) + *out_isReference = prop->type.IsReference(); + if( out_accessMask ) + *out_accessMask = prop->accessMask; + if (out_compositeOffset) + *out_compositeOffset = prop->compositeOffset; + if (out_isCompositeIndirect) + *out_isCompositeIndirect = prop->isCompositeIndirect; return 0; } @@ -541,7 +385,7 @@ const char *asCObjectType::GetPropertyDeclaration(asUINT index, bool includeName return tempString->AddressOf(); } -asIObjectType *asCObjectType::GetBaseType() const +asITypeInfo *asCObjectType::GetBaseType() const { return derivedFrom; } @@ -661,24 +505,8 @@ asIScriptFunction *asCObjectType::GetBehaviourByIndex(asUINT index, asEBehaviour return 0; } -// interface -const char *asCObjectType::GetConfigGroup() const -{ - asCConfigGroup *group = engine->FindConfigGroupForObjectType(this); - if( group == 0 ) - return 0; - - return group->groupName.AddressOf(); -} - -// interface -asDWORD asCObjectType::GetAccessMask() const -{ - return accessMask; -} - // internal -asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited) +asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &propName, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited) { asASSERT( flags & asOBJ_SCRIPT_OBJECT ); asASSERT( dt.CanBeInstantiated() ); @@ -692,7 +520,7 @@ asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, cons return 0; } - prop->name = name; + prop->name = propName; prop->type = dt; prop->isPrivate = isPrivate; prop->isProtected = isProtected; @@ -705,7 +533,7 @@ asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, cons // because there is a risk that the script might // try to access the content without knowing that // it hasn't been initialized yet. - if( dt.GetObjectType()->flags & asOBJ_POD ) + if( dt.GetTypeInfo()->flags & asOBJ_POD ) propSize = dt.GetSizeInMemoryBytes(); else { @@ -714,6 +542,12 @@ asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, cons prop->type.MakeReference(true); } } + else if (dt.IsFuncdef()) + { + // Funcdefs don't have a size, as they must always be stored as handles + asASSERT(dt.IsObjectHandle()); + propSize = AS_PTR_SIZE * 4; + } else propSize = dt.GetSizeInMemoryBytes(); @@ -738,11 +572,11 @@ asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, cons properties.PushLast(prop); // Make sure the struct holds a reference to the config group where the object is registered - asCConfigGroup *group = engine->FindConfigGroupForObjectType(prop->type.GetObjectType()); + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(prop->type.GetTypeInfo()); if( group != 0 ) group->AddRef(); // Add reference to object types - asCObjectType *type = prop->type.GetObjectType(); + asCTypeInfo *type = prop->type.GetTypeInfo(); if( type ) type->AddRefInternal(); @@ -759,18 +593,18 @@ void asCObjectType::ReleaseAllProperties() if( flags & asOBJ_SCRIPT_OBJECT ) { // Release the config group for script classes that are being destroyed - asCConfigGroup *group = engine->FindConfigGroupForObjectType(properties[n]->type.GetObjectType()); + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(properties[n]->type.GetTypeInfo()); if( group != 0 ) group->Release(); // Release references to objects types - asCObjectType *type = properties[n]->type.GetObjectType(); + asCTypeInfo *type = properties[n]->type.GetTypeInfo(); if( type ) type->ReleaseInternal(); } else { // Release template instance types (ref increased by RegisterObjectProperty) - asCObjectType *type = properties[n]->type.GetObjectType(); + asCTypeInfo *type = properties[n]->type.GetTypeInfo(); if( type ) type->ReleaseInternal(); } diff --git a/lib/angelscript/source/as_objecttype.h b/lib/angelscript/source/as_objecttype.h index 7c84b7831..4b7bd5d0f 100644 --- a/lib/angelscript/source/as_objecttype.h +++ b/lib/angelscript/source/as_objecttype.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -41,17 +41,13 @@ #ifndef AS_OBJECTTYPE_H #define AS_OBJECTTYPE_H -#include "as_atomic.h" -#include "as_string.h" #include "as_property.h" #include "as_array.h" #include "as_scriptfunction.h" +#include "as_typeinfo.h" BEGIN_AS_NAMESPACE -// TODO: memory: Need to minimize used memory here, because not all types use all properties of the class - - struct asSTypeBehaviour { asSTypeBehaviour() @@ -99,134 +95,75 @@ struct asSTypeBehaviour asCArray constructors; }; -struct asSEnumValue -{ - asCString name; - int value; -}; - class asCScriptEngine; struct asSNameSpace; -class asCObjectType : public asIObjectType +class asCObjectType : public asCTypeInfo { public: -//===================================== -// From asIObjectType -//===================================== - asIScriptEngine *GetEngine() const; - const char *GetConfigGroup() const; - asDWORD GetAccessMask() const; - asIScriptModule *GetModule() const; - - // Memory management - int AddRef() const; - int Release() const; - - // Type info - const char *GetName() const; - const char *GetNamespace() const; - asIObjectType *GetBaseType() const; - bool DerivesFrom(const asIObjectType *objType) const; - asDWORD GetFlags() const; - asUINT GetSize() const; - int GetTypeId() const; - int GetSubTypeId(asUINT subtypeIndex = 0) const; - asIObjectType *GetSubType(asUINT subtypeIndex = 0) const; - asUINT GetSubTypeCount() const; - - // Interfaces - asUINT GetInterfaceCount() const; - asIObjectType *GetInterface(asUINT index) const; - bool Implements(const asIObjectType *objType) const; - - // Factories + asITypeInfo *GetBaseType() const; + bool DerivesFrom(const asITypeInfo *objType) const; + int GetSubTypeId(asUINT subtypeIndex = 0) const; + asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const; + asUINT GetSubTypeCount() const; + asUINT GetInterfaceCount() const; + asITypeInfo *GetInterface(asUINT index) const; + bool Implements(const asITypeInfo *objType) const; asUINT GetFactoryCount() const; asIScriptFunction *GetFactoryByIndex(asUINT index) const; asIScriptFunction *GetFactoryByDecl(const char *decl) const; - - // Methods asUINT GetMethodCount() const; asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const; asIScriptFunction *GetMethodByName(const char *name, bool getVirtual) const; asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const; - - // Properties - asUINT GetPropertyCount() const; - int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask) const; - const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const; - - // Behaviours + asUINT GetPropertyCount() const; + int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const; + const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const; asUINT GetBehaviourCount() const; asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const; + asUINT GetChildFuncdefCount() const; + asITypeInfo *GetChildFuncdef(asUINT index) const; - // User data - void *SetUserData(void *data, asPWORD type); - void *GetUserData(asPWORD type) const; - -//=========================================== -// Internal -//=========================================== public: asCObjectType(asCScriptEngine *engine); ~asCObjectType(); void DestroyInternal(); - // Keep an internal reference counter to separate references coming from - // application or script objects and references coming from the script code - int AddRefInternal(); - int ReleaseInternal(); - void ReleaseAllFunctions(); bool IsInterface() const; - bool IsShared() const; asCObjectProperty *AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited); void ReleaseAllProperties(); - asCString name; - asSNameSpace *nameSpace; - int size; #ifdef WIP_16BYTE_ALIGN int alignment; #endif - mutable int typeId; asCArray properties; asCArray methods; + + // TODO: These are not used by template types. Should perhaps create a derived class to save memory on ordinary object types asCArray interfaces; asCArray interfaceVFTOffsets; - asCArray enumValues; asCObjectType * derivedFrom; asCArray virtualFunctionTable; - asDWORD flags; - asDWORD accessMask; + // Used for funcdefs declared as members of class. + // TODO: child funcdef: Should be possible to enumerate these from application + asCArray childFuncDefs; asSTypeBehaviour beh; // Used for template types - asCArray templateSubTypes; + asCArray templateSubTypes; // increases refCount for typeinfo held in datatype bool acceptValueSubType; bool acceptRefSubType; - // Store the script section where the code was declared - int scriptSectionIdx; - // Store the location where the function was declared (row in the lower 20 bits, and column in the upper 12) - int declaredAt; - - asCScriptEngine *engine; - asCModule *module; - asCArray userData; - protected: friend class asCScriptEngine; friend class asCConfigGroup; friend class asCModule; asCObjectType(); - - mutable asCAtomic externalRefCount; - asCAtomic internalRefCount; }; END_AS_NAMESPACE diff --git a/lib/angelscript/source/as_parser.cpp b/lib/angelscript/source/as_parser.cpp index fca02fe68..1f21bd7d1 100644 --- a/lib/angelscript/source/as_parser.cpp +++ b/lib/angelscript/source/as_parser.cpp @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -35,7 +35,7 @@ // This class parses the script code and builds a tree for compilation // // -// I've documented the syntax in Extended BNF. You'll find it by doing a search in +// I've documented the syntax in Extended BNF. You'll find it by doing a search in // this file by "BNF:". The starting point for the script language is SCRIPT ::=. // // Ref: http://matt.might.net/articles/grammars-bnf-ebnf/ @@ -103,18 +103,18 @@ asCScriptNode *asCParser::GetScriptNode() return scriptNode; } -int asCParser::ParseFunctionDefinition(asCScriptCode *script, bool expectListPattern) +int asCParser::ParseFunctionDefinition(asCScriptCode *in_script, bool in_expectListPattern) { Reset(); // Set flag that permits ? as datatype for parameters isParsingAppInterface = true; - this->script = script; + this->script = in_script; scriptNode = ParseFunctionDefinition(); - if( expectListPattern ) + if( in_expectListPattern ) scriptNode->AddChildLast(ParseListPattern()); // The declaration should end after the definition @@ -149,19 +149,19 @@ asCScriptNode *asCParser::CreateNode(eScriptNode type) return new(ptr) asCScriptNode(type); } -int asCParser::ParseDataType(asCScriptCode *script, bool isReturnType) +int asCParser::ParseDataType(asCScriptCode *in_script, bool in_isReturnType) { Reset(); - this->script = script; + this->script = in_script; scriptNode = CreateNode(snDataType); if( scriptNode == 0 ) return -1; - + scriptNode->AddChildLast(ParseType(true)); if( isSyntaxError ) return -1; - if( isReturnType ) + if( in_isReturnType ) { scriptNode->AddChildLast(ParseTypeMod(false)); if( isSyntaxError ) return -1; @@ -185,11 +185,11 @@ int asCParser::ParseDataType(asCScriptCode *script, bool isReturnType) // Parse a template declaration: IDENTIFIER '<' 'class'? IDENTIFIER '>' -int asCParser::ParseTemplateDecl(asCScriptCode *script) +int asCParser::ParseTemplateDecl(asCScriptCode *in_script) { Reset(); - this->script = script; + this->script = in_script; scriptNode = CreateNode(snUndefined); if( scriptNode == 0 ) return -1; @@ -249,11 +249,11 @@ int asCParser::ParseTemplateDecl(asCScriptCode *script) return 0; } -int asCParser::ParsePropertyDeclaration(asCScriptCode *script) +int asCParser::ParsePropertyDeclaration(asCScriptCode *in_script) { Reset(); - this->script = script; + this->script = in_script; scriptNode = CreateNode(snDeclaration); if( scriptNode == 0 ) return -1; @@ -287,28 +287,79 @@ int asCParser::ParsePropertyDeclaration(asCScriptCode *script) return 0; } -// BNF: SCOPE ::= [[IDENTIFIER] '::' {IDENTIFIER '::'}] +// BNF: SCOPE ::= ['::'] {IDENTIFIER '::'} [IDENTIFIER ['<' TYPE {',' TYPE} '>'] '::'] void asCParser::ParseOptionalScope(asCScriptNode *node) { + asCScriptNode *scope = CreateNode(snScope); + sToken t1, t2; GetToken(&t1); GetToken(&t2); if( t1.type == ttScope ) { RewindTo(&t1); - node->AddChildLast(ParseToken(ttScope)); + scope->AddChildLast(ParseToken(ttScope)); GetToken(&t1); GetToken(&t2); } while( t1.type == ttIdentifier && t2.type == ttScope ) { RewindTo(&t1); - node->AddChildLast(ParseIdentifier()); - node->AddChildLast(ParseToken(ttScope)); + scope->AddChildLast(ParseIdentifier()); + scope->AddChildLast(ParseToken(ttScope)); GetToken(&t1); GetToken(&t2); } + + // The innermost scope may be a template type + if( t1.type == ttIdentifier && t2.type == ttLessThan ) + { + tempString.Assign(&script->code[t1.pos], t1.length); + if (engine->IsTemplateType(tempString.AddressOf())) + { + RewindTo(&t1); + asCScriptNode *restore = scope->lastChild; + scope->AddChildLast(ParseIdentifier()); + if (ParseTemplTypeList(scope, false)) + { + GetToken(&t2); + if (t2.type == ttScope) + { + // Template type is part of the scope + // Nothing more needs to be done + node->AddChildLast(scope); + return; + } + else + { + // The template type is not part of the scope + // Rewind to the template type and end the scope + RewindTo(&t1); + + // Restore the previously parsed node + while (scope->lastChild != restore) + { + asCScriptNode *last = scope->lastChild; + last->DisconnectParent(); + last->Destroy(engine); + } + if( scope->lastChild ) + node->AddChildLast(scope); + else + scope->Destroy(engine); + return; + } + } + } + } + + // The identifier is not part of the scope RewindTo(&t1); + + if (scope->lastChild) + node->AddChildLast(scope); + else + scope->Destroy(engine); } asCScriptNode *asCParser::ParseFunctionDefinition() @@ -369,7 +420,7 @@ asCScriptNode *asCParser::ParseTypeMod(bool isParam) } } - // Parse possible + token + // Parse possible + token GetToken(&t); RewindTo(&t); if( t.type == ttPlus ) @@ -378,6 +429,15 @@ asCScriptNode *asCParser::ParseTypeMod(bool isParam) if( isSyntaxError ) return node; } + // Parse possible if_handle_then_const token + GetToken(&t); + RewindTo(&t); + if (IdentifierIs(t, IF_HANDLE_TOKEN)) + { + node->AddChildLast(ParseToken(ttIdentifier)); + if (isSyntaxError) return node; + } + return node; } @@ -414,41 +474,8 @@ asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType, boo tempString.Assign(&script->code[type->tokenPos], type->tokenLength); if( engine->IsTemplateType(tempString.AddressOf()) && t.type == ttLessThan ) { - GetToken(&t); - if( t.type != ttLessThan ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseType(true, false)); - if( isSyntaxError ) return node; - - GetToken(&t); - - // Parse template types by list separator - while(t.type == ttListSeparator) - { - node->AddChildLast(ParseType(true, false)); - - if( isSyntaxError ) return node; - GetToken(&t); - } - - // Accept >> and >>> tokens too. But then force the tokenizer to move - // only 1 character ahead (thus splitting the token in two). - if( script->code[t.pos] != '>' ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t); - Error(InsteadFound(t), &t); - return node; - } - else - { - // Break the token so that only the first > is parsed - SetPos(t.pos + 1); - } + ParseTemplTypeList(node); + if (isSyntaxError) return node; } // Parse [] and @ @@ -482,6 +509,82 @@ asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType, boo return node; } +// This parses a template type list, e.g. +// If 'required' is false, and the template type list is not valid, +// then no change will be done and the function returns false. This +// can be used as do an optional parsing +bool asCParser::ParseTemplTypeList(asCScriptNode *node, bool required) +{ + sToken t; + bool isValid = true; + + // Remember the last child, so we can restore the state if needed + asCScriptNode *last = node->lastChild; + + // Starts with '<' + GetToken(&t); + if (t.type != ttLessThan) + { + if (required) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t); + Error(InsteadFound(t), &t); + } + return false; + } + + // At least one type + // TODO: child funcdef: Make this work with !required + node->AddChildLast(ParseType(true, false)); + if (isSyntaxError) return false; + + GetToken(&t); + + // Parse template types by list separator + while (t.type == ttListSeparator) + { + // TODO: child funcdef: Make this work with !required + node->AddChildLast(ParseType(true, false)); + if (isSyntaxError) return false; + GetToken(&t); + } + + // End with '>' + // Accept >> and >>> tokens too. But then force the tokenizer to move + // only 1 character ahead (thus splitting the token in two). + if (script->code[t.pos] != '>') + { + if (required) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t); + Error(InsteadFound(t), &t); + } + else + isValid = false; + } + else + { + // Break the token so that only the first > is parsed + SetPos(t.pos + 1); + } + + if (!required && !isValid) + { + // Restore the original state before returning + while (node->lastChild != last) + { + asCScriptNode *n = node->lastChild; + n->DisconnectParent(); + n->Destroy(engine); + } + + return false; + } + + // The template type list was parsed OK + return true; +} + asCScriptNode *asCParser::ParseToken(int token) { asCScriptNode *node = CreateNode(snUndefined); @@ -708,7 +811,7 @@ asCScriptNode *asCParser::SuperficiallyParseExpression() asCScriptNode *node = CreateNode(snExpression); if( node == 0 ) return 0; - // Simply parse everything until the first , or ), whichever comes first. + // Simply parse everything until the first , or ), whichever comes first. // Keeping in mind that () and {} can group expressions. sToken start; @@ -839,7 +942,7 @@ void asCParser::GetToken(sToken *token) sourcePos += token->length; } // Filter out whitespace and comments - while( token->type == ttWhiteSpace || + while( token->type == ttWhiteSpace || token->type == ttOnelineComment || token->type == ttMultilineComment ); } @@ -852,8 +955,8 @@ void asCParser::SetPos(size_t pos) void asCParser::RewindTo(const sToken *token) { - // TODO: optimize: Perhaps we can optimize this further by having the parser - // set an explicit return point, after which each token will + // TODO: optimize: Perhaps we can optimize this further by having the parser + // set an explicit return point, after which each token will // be stored. That way not just one token will be reused but // no token will have to be tokenized more than once. @@ -995,10 +1098,13 @@ asCString asCParser::InsteadFound(sToken &t) if( t.type == ttIdentifier ) { asCString id(&script->code[t.pos], t.length); - str.Format(TXT_INSTEAD_FOUND_s, id.AddressOf()); + str.Format(TXT_INSTEAD_FOUND_IDENTIFIER_s, id.AddressOf()); } + else if( t.type >= ttIf ) + str.Format(TXT_INSTEAD_FOUND_KEYWORD_s, asCTokenizer::GetDefinition(t.type)); else str.Format(TXT_INSTEAD_FOUND_s, asCTokenizer::GetDefinition(t.type)); + return str; } @@ -1095,7 +1201,7 @@ asCScriptNode *asCParser::ParseListPattern() bool asCParser::IdentifierIs(const sToken &t, const char *str) { - if( t.type != ttIdentifier ) + if( t.type != ttIdentifier ) return false; return script->TokenEquals(t.pos, t.length, str); @@ -1103,79 +1209,80 @@ bool asCParser::IdentifierIs(const sToken &t, const char *str) #ifndef AS_NO_COMPILER -// This function will return true if the current token is not a template, or if it is and -// the following has a valid syntax for a template type. The source position will be left +// This function will return true if the current token is not a template, or if it is and +// the following has a valid syntax for a template type. The source position will be left // at the first token after the type in case of success -bool asCParser::CheckTemplateType(sToken &t) +bool asCParser::CheckTemplateType(const sToken &t) { // Is this a template type? tempString.Assign(&script->code[t.pos], t.length); if( engine->IsTemplateType(tempString.AddressOf()) ) { // If the next token is a < then parse the sub-type too - GetToken(&t); - if( t.type != ttLessThan ) + sToken t1; + GetToken(&t1); + if( t1.type != ttLessThan ) { - RewindTo(&t); + RewindTo(&t1); return true; } for(;;) { // There might optionally be a 'const' - GetToken(&t); - if( t.type == ttConst ) - GetToken(&t); + GetToken(&t1); + if( t1.type == ttConst ) + GetToken(&t1); // The type may be initiated with the scope operator - if( t.type == ttScope ) - GetToken(&t); + if( t1.type == ttScope ) + GetToken(&t1); // There may be multiple levels of scope operators sToken t2; GetToken(&t2); - while( t.type == ttIdentifier && t2.type == ttScope ) + while( t1.type == ttIdentifier && t2.type == ttScope ) { - GetToken(&t); + GetToken(&t1); GetToken(&t2); } RewindTo(&t2); // Now there must be a data type - if( !IsDataType(t) ) + if( !IsDataType(t1) ) return false; - if( !CheckTemplateType(t) ) + if( !CheckTemplateType(t1) ) return false; - GetToken(&t); + GetToken(&t1); // Is it a handle or array? - while( t.type == ttHandle || t.type == ttOpenBracket ) + while( t1.type == ttHandle || t1.type == ttOpenBracket ) { - if( t.type == ttOpenBracket ) + if( t1.type == ttOpenBracket ) { - GetToken(&t); - if( t.type != ttCloseBracket ) + GetToken(&t1); + if( t1.type != ttCloseBracket ) return false; } - GetToken(&t); + GetToken(&t1); } // Was this the last template subtype? - if( t.type != ttListSeparator ) + if( t1.type != ttListSeparator ) break; } - // Accept >> and >>> tokens too. But then force the tokenizer to move + // Accept >> and >>> tokens too. But then force the tokenizer to move // only 1 character ahead (thus splitting the token in two). - if( script->code[t.pos] != '>' ) + if( script->code[t1.pos] != '>' ) return false; - else if( t.length != 1 ) + else if( t1.length != 1 ) { // We need to break the token, so that only the first character is parsed - SetPos(t.pos + 1); + SetPos(t1.pos + 1); } } @@ -1279,7 +1386,7 @@ asCScriptNode *asCParser::ParseExprValue() GetToken(&t); if( t.type == ttScope ) GetToken(&t); - else + else break; } @@ -1294,13 +1401,14 @@ asCScriptNode *asCParser::ParseExprValue() } GetToken(&t2); - + // Rewind so the real parsing can be done, after deciding what to parse RewindTo(&t1); // Check if this is a construct call - if( isDataType && (t.type == ttOpenParanthesis || // type() - (t.type == ttOpenBracket && t2.type == ttCloseBracket)) ) // type[]() + // Just 'type()' isn't considered a construct call, because type may just be a function/method name. + // The compiler will have to sort this out, since the parser doesn't have enough information. + if( isDataType && (t.type == ttOpenBracket && t2.type == ttCloseBracket) ) // type[]() node->AddChildLast(ParseConstructCall()); else if( isTemplateType && t.type == ttLessThan ) // type() node->AddChildLast(ParseConstructCall()); @@ -1446,7 +1554,7 @@ asCScriptNode *asCParser::ParseLambda() return node; } - // We should just find the end of the statement block here. The statements + // We should just find the end of the statement block here. The statements // will be parsed on request by the compiler once it starts the compilation. node->AddChildLast(SuperficiallyParseStatementBlock()); @@ -1613,7 +1721,7 @@ asCScriptNode *asCParser::ParseArgList(bool withParenthesis) Error(InsteadFound(t1), &t1); } } - else + else RewindTo(&t1); return node; @@ -1642,7 +1750,11 @@ bool asCParser::IsFunctionCall() } // A function call starts with an identifier followed by an argument list - if( t1.type != ttIdentifier || IsDataType(t1) ) + // The parser doesn't have enough information about scope to determine if the + // identifier is a datatype, so even if it happens to be the parser will + // identify the expression as a function call rather than a construct call. + // The compiler will sort this out later + if( t1.type != ttIdentifier ) { RewindTo(&s); return false; @@ -1716,35 +1828,12 @@ asCScriptNode *asCParser::ParseCondition() return node; } -// BNF: EXPR ::= (TYPE '=' INITLIST) | (EXPRTERM {EXPROP EXPRTERM}) +// BNF: EXPR ::= EXPRTERM {EXPROP EXPRTERM} asCScriptNode *asCParser::ParseExpression() { asCScriptNode *node = CreateNode(snExpression); if( node == 0 ) return 0; - // Check if the expression is a initialization of a temp object with init list, i.e. type = {...} - sToken t; - GetToken(&t); - sToken t2 = t, t3; - if( IsDataType(t2) && CheckTemplateType(t2) ) - { - // The next token must be a = followed by a { - GetToken(&t2); - GetToken(&t3); - if( t2.type == ttAssignment && t3.type == ttStartStatementBlock ) - { - // It is an initialization, now parse it for real - RewindTo(&t); - node->AddChildLast(ParseType(false)); - GetToken(&t2); - node->AddChildLast(ParseInitList()); - return node; - } - } - - // It wasn't an initialization, so it must be an ordinary expression - RewindTo(&t); - node->AddChildLast(ParseExprTerm()); if( isSyntaxError ) return node; @@ -1766,15 +1855,44 @@ asCScriptNode *asCParser::ParseExpression() UNREACHABLE_RETURN; } -// BNF: EXPRTERM ::= {EXPRPREOP} EXPRVALUE {EXPRPOSTOP} +// BNF: EXPRTERM ::= ([TYPE '='] INITLIST) | ({EXPRPREOP} EXPRVALUE {EXPRPOSTOP}) asCScriptNode *asCParser::ParseExprTerm() { asCScriptNode *node = CreateNode(snExprTerm); if( node == 0 ) return 0; + // Check if the expression term is an initialization of a temp object with init list, i.e. type = {...} + sToken t; + GetToken(&t); + sToken t2 = t, t3; + if (IsDataType(t2) && CheckTemplateType(t2)) + { + // The next token must be a = followed by a { + GetToken(&t2); + GetToken(&t3); + if (t2.type == ttAssignment && t3.type == ttStartStatementBlock) + { + // It is an initialization, now parse it for real + RewindTo(&t); + node->AddChildLast(ParseType(false)); + GetToken(&t2); + node->AddChildLast(ParseInitList()); + return node; + } + } + // Or an anonymous init list, i.e. {...} + else if( t.type == ttStartStatementBlock ) + { + RewindTo(&t); + node->AddChildLast(ParseInitList()); + return node; + } + + // It wasn't an initialization, so it must be an ordinary expression term + RewindTo(&t); + for(;;) { - sToken t; GetToken(&t); RewindTo(&t); if( !IsPreOperator(t.type) ) @@ -1787,10 +1905,9 @@ asCScriptNode *asCParser::ParseExprTerm() node->AddChildLast(ParseExprValue()); if( isSyntaxError ) return node; - + for(;;) { - sToken t; GetToken(&t); RewindTo(&t); if( !IsPostOperator(t.type) ) @@ -1900,7 +2017,7 @@ asCScriptNode *asCParser::ParseExprOperator() return node; } -// BNF: ASSIGNOP ::= '=' | '+=' | '-=' | '*=' | '/=' | '|=' | '&=' | '^=' | '%=' | '**=' | '<<=' | '>>=' | '>>>=' +// BNF: ASSIGNOP ::= '=' | '+=' | '-=' | '*=' | '/=' | '|=' | '&=' | '^=' | '%=' | '**=' | '<<=' | '>>=' | '>>>=' asCScriptNode *asCParser::ParseAssignOperator() { asCScriptNode *node = CreateNode(snExprOperator); @@ -2012,18 +2129,18 @@ bool asCParser::IsConstant(int tokenType) return false; } -int asCParser::ParseScript(asCScriptCode *script) +int asCParser::ParseScript(asCScriptCode *in_script) { Reset(); - this->script = script; + this->script = in_script; scriptNode = ParseScript(false); if( errorWhileParsing ) return -1; - // TODO: Should allow application to request this warning to be generated. + // TODO: Should allow application to request this warning to be generated. // It should be off by default, since pre-processor may remove all // code from a section while still being meant as valid code /* @@ -2037,11 +2154,11 @@ int asCParser::ParseScript(asCScriptCode *script) return 0; } -int asCParser::ParseExpression(asCScriptCode *script) +int asCParser::ParseExpression(asCScriptCode *in_script) { Reset(); - this->script = script; + this->script = in_script; checkValidTypes = true; @@ -2127,29 +2244,33 @@ asCScriptNode *asCParser::ParseScript(bool inBlock) if( node == 0 ) return 0; // Determine type of node - sToken t1, t2; - for(;;) { while( !isSyntaxError ) { - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); + sToken tStart; + GetToken(&tStart); + + // Optimize by skipping tokens 'shared', 'external', 'final', 'abstract' so they don't have to be checked in every condition + sToken t1 = tStart; + while (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN) || + IdentifierIs(t1, FINAL_TOKEN) || + IdentifierIs(t1, ABSTRACT_TOKEN)) + GetToken(&t1); + RewindTo(&tStart); if( t1.type == ttImport ) node->AddChildLast(ParseImport()); - else if( t1.type == ttEnum || (IdentifierIs(t1, SHARED_TOKEN) && t2.type == ttEnum) ) + else if( t1.type == ttEnum ) node->AddChildLast(ParseEnumeration()); // Handle enumerations else if( t1.type == ttTypedef ) node->AddChildLast(ParseTypedef()); // Handle primitive typedefs - else if( t1.type == ttClass || - ((IdentifierIs(t1, SHARED_TOKEN) || IdentifierIs(t1, FINAL_TOKEN) || IdentifierIs(t1, ABSTRACT_TOKEN)) && t2.type == ttClass) || - (IdentifierIs(t1, SHARED_TOKEN) && (IdentifierIs(t2, FINAL_TOKEN) || IdentifierIs(t2, ABSTRACT_TOKEN))) ) + else if( t1.type == ttClass ) node->AddChildLast(ParseClass()); else if( t1.type == ttMixin ) node->AddChildLast(ParseMixin()); - else if( t1.type == ttInterface || (t1.type == ttIdentifier && t2.type == ttInterface) ) + else if( t1.type == ttInterface ) node->AddChildLast(ParseInterface()); else if( t1.type == ttFuncDef ) node->AddChildLast(ParseFuncDef()); @@ -2188,6 +2309,7 @@ asCScriptNode *asCParser::ParseScript(bool inBlock) if( isSyntaxError ) { // Search for either ';' or '{' or end + sToken t1; GetToken(&t1); while( t1.type != ttEndStatement && t1.type != ttEnd && t1.type != ttStartStatementBlock ) @@ -2269,7 +2391,7 @@ asCScriptNode *asCParser::ParseNamespace() return node; } -int asCParser::ParseStatementBlock(asCScriptCode *script, asCScriptNode *block) +int asCParser::ParseStatementBlock(asCScriptCode *in_script, asCScriptNode *in_block) { TimeIt("asCParser::ParseStatementBlock"); @@ -2278,8 +2400,8 @@ int asCParser::ParseStatementBlock(asCScriptCode *script, asCScriptNode *block) // Tell the parser to validate the identifiers as valid types checkValidTypes = true; - this->script = script; - sourcePos = block->tokenPos; + this->script = in_script; + sourcePos = in_block->tokenPos; scriptNode = ParseStatementBlock(); @@ -2289,7 +2411,7 @@ int asCParser::ParseStatementBlock(asCScriptCode *script, asCScriptNode *block) return 0; } -// BNF: ENUM ::= ['shared'] 'enum' IDENTIFIER '{' IDENTIFIER ['=' EXPR] {',' IDENTIFIER ['=' EXPR]} '}' +// BNF: ENUM ::= {'shared' | 'external'} 'enum' IDENTIFIER (';' | ('{' IDENTIFIER ['=' EXPR] {',' IDENTIFIER ['=' EXPR]} '}')) asCScriptNode *asCParser::ParseEnumeration() { asCScriptNode *ident; @@ -2298,12 +2420,13 @@ asCScriptNode *asCParser::ParseEnumeration() asCScriptNode *node = CreateNode(snEnum); if( node == 0 ) return 0; - sToken token; + sToken token; - // Optional 'shared' token + // Optional 'shared' and 'external' token GetToken(&token); - if( IdentifierIs(token, SHARED_TOKEN) ) - { + while( IdentifierIs(token, SHARED_TOKEN) || + IdentifierIs(token, EXTERNAL_TOKEN) ) + { RewindTo(&token); node->AddChildLast(ParseIdentifier()); if( isSyntaxError ) return node; @@ -2324,7 +2447,7 @@ asCScriptNode *asCParser::ParseEnumeration() // Get the identifier GetToken(&token); - if(ttIdentifier != token.type) + if(ttIdentifier != token.type) { Error(TXT_EXPECTED_IDENTIFIER, &token); Error(InsteadFound(token), &token); @@ -2332,47 +2455,56 @@ asCScriptNode *asCParser::ParseEnumeration() } dataType = CreateNode(snDataType); - if( dataType == 0 ) return 0; + if( dataType == 0 ) return node; node->AddChildLast(dataType); ident = CreateNode(snIdentifier); - if( ident == 0 ) return 0; + if( ident == 0 ) return node; ident->SetToken(&token); ident->UpdateSourcePos(token.pos, token.length); dataType->AddChildLast(ident); - // check for the start of the declaration block + // External shared declarations are ended with ';' GetToken(&token); - if( token.type != ttStartStatementBlock ) + if (token.type == ttEndStatement) { RewindTo(&token); - Error(ExpectedToken(asCTokenizer::GetDefinition(token.type)), &token); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // check for the start of the declaration block + if( token.type != ttStartStatementBlock ) + { + RewindTo(&token); + int tokens[] = { ttStartStatementBlock, ttEndStatement }; + Error(ExpectedOneOf(tokens, 2), &token); Error(InsteadFound(token), &token); return node; } - while(ttEnd != token.type) + while(ttEnd != token.type) { GetToken(&token); - if( ttEndStatementBlock == token.type ) + if( ttEndStatementBlock == token.type ) { RewindTo(&token); break; } - if(ttIdentifier != token.type) + if(ttIdentifier != token.type) { Error(TXT_EXPECTED_IDENTIFIER, &token); Error(InsteadFound(token), &token); return node; } - // Add the enum element + // Add the enum element ident = CreateNode(snIdentifier); - if( ident == 0 ) return 0; + if( ident == 0 ) return node; ident->SetToken(&token); ident->UpdateSourcePos(token.pos, token.length); @@ -2393,16 +2525,16 @@ asCScriptNode *asCParser::ParseEnumeration() GetToken(&token); } - if(ttListSeparator != token.type) + if(ttListSeparator != token.type) { RewindTo(&token); break; } } - // check for the end of the declaration block + // check for the end of the declaration block GetToken(&token); - if( token.type != ttEndStatementBlock ) + if( token.type != ttEndStatementBlock ) { RewindTo(&token); Error(ExpectedToken("}"), &token); @@ -2410,7 +2542,6 @@ asCScriptNode *asCParser::ParseEnumeration() return node; } - // Parse the declarations return node; } @@ -2441,10 +2572,32 @@ bool asCParser::IsVarDecl() // The type may be preceeded with a multilevel scope GetToken(&t2); - while( t1.type == ttIdentifier && t2.type == ttScope ) + while( t1.type == ttIdentifier ) { - GetToken(&t1); - GetToken(&t2); + if (t2.type == ttScope) + { + GetToken(&t1); + GetToken(&t2); + continue; + } + else if(t2.type == ttLessThan) + { + // Template types can also be used as scope identifiers + RewindTo(&t2); + if (CheckTemplateType(t1)) + { + sToken t3; + GetToken(&t3); + if (t3.type == ttScope) + { + GetToken(&t1); + GetToken(&t2); + continue; + } + } + } + + break; } RewindTo(&t2); } @@ -2466,7 +2619,7 @@ bool asCParser::IsVarDecl() } // Object handles can be interleaved with the array brackets - // Even though declaring variables with & is invalid we'll accept + // Even though declaring variables with & is invalid we'll accept // it here to give an appropriate error message later GetToken(&t2); while( t2.type == ttHandle || t2.type == ttAmp || t2.type == ttOpenBracket ) @@ -2496,9 +2649,9 @@ bool asCParser::IsVarDecl() RewindTo(&t); return true; } - if( t2.type == ttOpenParanthesis ) - { - // If the closing paranthesis is followed by a statement + if( t2.type == ttOpenParanthesis ) + { + // If the closing paranthesis is followed by a statement // block or end-of-file, then treat it as a function. A // function decl may have nested paranthesis so we need to // check for this too. @@ -2516,8 +2669,11 @@ bool asCParser::IsVarDecl() GetToken(&t2); } - if( t2.type == ttEnd ) + if (t2.type == ttEnd) + { + RewindTo(&t); return false; + } else { GetToken(&t1); @@ -2527,7 +2683,6 @@ bool asCParser::IsVarDecl() } RewindTo(&t); - return true; } @@ -2713,10 +2868,10 @@ bool asCParser::IsFuncDecl(bool isMethod) } GetToken(&t2); - if( t2.type == ttOpenParanthesis ) - { - // If the closing parenthesis is not followed by a - // statement block then it is not a function. + if( t2.type == ttOpenParanthesis ) + { + // If the closing parenthesis is not followed by a + // statement block then it is not a function. // It's possible that there are nested parenthesis due to default // arguments so this should be checked for. int nest = 0; @@ -2741,7 +2896,7 @@ bool asCParser::IsFuncDecl(bool isMethod) GetToken(&t1); if( t1.type != ttConst ) RewindTo(&t1); - + // A class method may also have any number of additional inheritance behavior specifiers for( ; ; ) { @@ -2768,14 +2923,25 @@ bool asCParser::IsFuncDecl(bool isMethod) return false; } -// BNF: FUNCDEF ::= 'funcdef' TYPE ['&'] IDENTIFIER PARAMLIST ';' +// BNF: FUNCDEF ::= {'external' | 'shared'} 'funcdef' TYPE ['&'] IDENTIFIER PARAMLIST ';' asCScriptNode *asCParser::ParseFuncDef() { asCScriptNode *node = CreateNode(snFuncDef); if( node == 0 ) return 0; + // Allow keywords 'external' and 'shared' before 'interface' sToken t1; GetToken(&t1); + while (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN)) + { + RewindTo(&t1); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + + GetToken(&t1); + } + if( t1.type != ttFuncDef ) { Error(asCTokenizer::GetDefinition(ttFuncDef), &t1); @@ -2809,32 +2975,52 @@ asCScriptNode *asCParser::ParseFuncDef() return node; } -// BNF: FUNC ::= ['private' | 'protected' | 'shared'] [((TYPE ['&']) | '~')] IDENTIFIER PARAMLIST ['const'] {'override' | 'final'} STATBLOCK +// BNF: FUNC ::= {'shared' | 'external'} ['private' | 'protected'] [((TYPE ['&']) | '~')] IDENTIFIER PARAMLIST ['const'] {'override' | 'final'} (';' | STATBLOCK) asCScriptNode *asCParser::ParseFunction(bool isMethod) { asCScriptNode *node = CreateNode(snFunction); if( node == 0 ) return 0; - sToken t1,t2; + sToken t1; GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); - - // A class method can start with 'private' or 'protected' - if( isMethod && t1.type == ttPrivate ) - node->AddChildLast(ParseToken(ttPrivate)); - else if( isMethod && t1.type == ttProtected ) - node->AddChildLast(ParseToken(ttProtected)); - if( isSyntaxError ) return node; - - // A global function can be marked as shared - if( !isMethod && IdentifierIs(t1, SHARED_TOKEN) ) + if (!isMethod) { - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; + // A global function can be marked as shared and external + while (t1.type == ttIdentifier) + { + if (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN)) + { + RewindTo(&t1); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + } + else + break; + + GetToken(&t1); + } } + // A class method can start with 'private' or 'protected' + if (isMethod && t1.type == ttPrivate) + { + RewindTo(&t1); + node->AddChildLast(ParseToken(ttPrivate)); + GetToken(&t1); + } + else if (isMethod && t1.type == ttProtected) + { + RewindTo(&t1); + node->AddChildLast(ParseToken(ttProtected)); + GetToken(&t1); + } + if( isSyntaxError ) return node; + // If it is a global function, or a method, except constructor and destructor, then the return type is parsed + sToken t2; + GetToken(&t2); + RewindTo(&t1); if( !isMethod || (t1.type != ttBitNot && t2.type != ttOpenParanthesis) ) { node->AddChildLast(ParseType(true)); @@ -2871,7 +3057,16 @@ asCScriptNode *asCParser::ParseFunction(bool isMethod) if( isSyntaxError ) return node; } - // We should just find the end of the statement block here. The statements + // External shared functions must be ended with ';' + GetToken(&t1); + RewindTo(&t1); + if (t1.type == ttEndStatement) + { + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // We should just find the end of the statement block here. The statements // will be parsed on request by the compiler once it starts the compilation. node->AddChildLast(SuperficiallyParseStatementBlock()); @@ -2965,7 +3160,7 @@ asCScriptNode *asCParser::ParseVirtualPropertyDecl(bool isMethod, bool isInterfa RewindTo(&t1); accessorNode->AddChildLast(ParseIdentifier()); - + if( isMethod ) { GetToken(&t1); @@ -3021,28 +3216,23 @@ asCScriptNode *asCParser::ParseVirtualPropertyDecl(bool isMethod, bool isInterfa return node; } -// BNF: INTERFACE ::= ['shared'] 'interface' IDENTIFIER [':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | INTFMTHD} '}' +// BNF: INTERFACE ::= {'external' | 'shared'} 'interface' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | INTFMTHD} '}')) asCScriptNode *asCParser::ParseInterface() { asCScriptNode *node = CreateNode(snInterface); if( node == 0 ) return 0; sToken t; + + // Allow keywords 'external' and 'shared' before 'interface' GetToken(&t); - - // Allow keyword 'shared' before 'interface' - if( t.type == ttIdentifier ) + while( IdentifierIs(t, SHARED_TOKEN) || + IdentifierIs(t, EXTERNAL_TOKEN) ) { - tempString.Assign(&script->code[t.pos], t.length); - if( tempString != SHARED_TOKEN ) - { - Error(ExpectedToken(SHARED_TOKEN), &t); - Error(InsteadFound(t), &t); - return node; - } - RewindTo(&t); node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + GetToken(&t); } @@ -3054,11 +3244,18 @@ asCScriptNode *asCParser::ParseInterface() } node->SetToken(&t); - node->AddChildLast(ParseIdentifier()); - // Can optionally have a list of interfaces that are inherited + // External shared declarations are ended with ';' GetToken(&t); + if (t.type == ttEndStatement) + { + RewindTo(&t); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // Can optionally have a list of interfaces that are inherited if( t.type == ttColon ) { asCScriptNode *inherit = CreateNode(snIdentifier); @@ -3100,7 +3297,7 @@ asCScriptNode *asCParser::ParseInterface() node->AddChildLast(ParseInterfaceMethod()); if( isSyntaxError ) return node; - + GetToken(&t); RewindTo(&t); } @@ -3142,7 +3339,7 @@ asCScriptNode *asCParser::ParseMixin() return node; } -// BNF: CLASS ::= {'shared' | 'abstract' | 'final'} 'class' IDENTIFIER [':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | FUNC | VAR} '}' +// BNF: CLASS ::= {'shared' | 'abstract' | 'final' | 'external'} 'class' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | FUNC | VAR | FUNCDEF} '}')) asCScriptNode *asCParser::ParseClass() { asCScriptNode *node = CreateNode(snClass); @@ -3151,10 +3348,11 @@ asCScriptNode *asCParser::ParseClass() sToken t; GetToken(&t); - // Allow the keywords 'shared', 'abstract', and 'final' before 'class' + // Allow the keywords 'shared', 'abstract', 'final', and 'external' before 'class' while( IdentifierIs(t, SHARED_TOKEN) || IdentifierIs(t, ABSTRACT_TOKEN) || - IdentifierIs(t, FINAL_TOKEN) ) + IdentifierIs(t, FINAL_TOKEN) || + IdentifierIs(t, EXTERNAL_TOKEN) ) { RewindTo(&t); node->AddChildLast(ParseIdentifier()); @@ -3174,7 +3372,7 @@ asCScriptNode *asCParser::ParseClass() { // Parse 'implicit handle class' construct GetToken(&t); - + if ( t.type == ttHandle ) node->SetToken(&t); else @@ -3183,7 +3381,14 @@ asCScriptNode *asCParser::ParseClass() node->AddChildLast(ParseIdentifier()); + // External shared declarations are ended with ';' GetToken(&t); + if (t.type == ttEndStatement) + { + RewindTo(&t); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } // Optional list of interfaces that are being implemented and classes that are being inherited if( t.type == ttColon ) @@ -3218,7 +3423,9 @@ asCScriptNode *asCParser::ParseClass() while( t.type != ttEndStatementBlock && t.type != ttEnd ) { // Is it a property or a method? - if( IsFuncDecl(true) ) + if (t.type == ttFuncDef) + node->AddChildLast(ParseFuncDef()); + else if( IsFuncDecl(true) ) node->AddChildLast(ParseFunction(true)); else if( IsVirtualPropertyDecl() ) node->AddChildLast(ParseVirtualPropertyDecl(true, false)); @@ -3227,7 +3434,7 @@ asCScriptNode *asCParser::ParseClass() else if( t.type == ttEndStatement ) // Skip empty declarations GetToken(&t); - else + else { Error(TXT_EXPECTED_METHOD_OR_PROPERTY, &t); Error(InsteadFound(t), &t); @@ -3253,15 +3460,15 @@ asCScriptNode *asCParser::ParseClass() return node; } -int asCParser::ParseVarInit(asCScriptCode *script, asCScriptNode *init) +int asCParser::ParseVarInit(asCScriptCode *in_script, asCScriptNode *in_init) { Reset(); // Tell the parser to validate the identifiers as valid types checkValidTypes = true; - this->script = script; - sourcePos = init->tokenPos; + this->script = in_script; + sourcePos = in_init->tokenPos; // If next token is assignment, parse expression sToken t; @@ -3275,7 +3482,7 @@ int asCParser::ParseVarInit(asCScriptCode *script, asCScriptNode *init) else scriptNode = ParseAssignment(); } - else if( t.type == ttOpenParanthesis ) + else if( t.type == ttOpenParanthesis ) { RewindTo(&t); scriptNode = ParseArgList(); @@ -3545,10 +3752,10 @@ asCScriptNode *asCParser::ParseInitList() GetToken(&t1); if( t1.type == ttListSeparator ) { - // No expression + // No expression node->AddChildLast(CreateNode(snUndefined)); node->lastChild->UpdateSourcePos(t1.pos, 1); - + GetToken(&t1); if( t1.type == ttEndStatementBlock ) { @@ -3562,7 +3769,7 @@ asCScriptNode *asCParser::ParseInitList() } else if( t1.type == ttEndStatementBlock ) { - // No expression + // No expression node->AddChildLast(CreateNode(snUndefined)); node->lastChild->UpdateSourcePos(t1.pos, 1); node->UpdateSourcePos(t1.pos, t1.length); @@ -3637,7 +3844,7 @@ asCScriptNode *asCParser::ParseDeclaration(bool isClassProp, bool isGlobalVar) node->AddChildLast(ParseToken(ttPrivate)); else if( t.type == ttProtected && isClassProp ) node->AddChildLast(ParseToken(ttProtected)); - + // Parse data type node->AddChildLast(ParseType(true, false, !isClassProp)); if( isSyntaxError ) return node; @@ -3821,11 +4028,11 @@ asCScriptNode *asCParser::ParseSwitch() Error(InsteadFound(t), &t); return node; } - + while( !isSyntaxError ) { GetToken(&t); - + if( t.type == ttEndStatementBlock ) break; @@ -3886,9 +4093,9 @@ asCScriptNode *asCParser::ParseCase() // Parse statements until we find either of }, case, default, and break GetToken(&t); RewindTo(&t); - while( t.type != ttCase && - t.type != ttDefault && - t.type != ttEndStatementBlock && + while( t.type != ttCase && + t.type != ttDefault && + t.type != ttEndStatementBlock && t.type != ttBreak ) { if( IsVarDecl() ) @@ -4025,7 +4232,7 @@ asCScriptNode *asCParser::ParseFor() } node->AddChildLast(ParseStatement()); - + return node; } @@ -4246,7 +4453,7 @@ asCScriptNode *asCParser::ParseTypedef() Error(InsteadFound(token), &token); return node; } - + node->SetToken(&token); node->UpdateSourcePos(token.pos, token.length); @@ -4268,7 +4475,7 @@ asCScriptNode *asCParser::ParseTypedef() // Check for the end of the typedef GetToken(&token); - if( token.type != ttEndStatement ) + if( token.type != ttEndStatement ) { RewindTo(&token); Error(ExpectedToken(asCTokenizer::GetDefinition(token.type)), &token); diff --git a/lib/angelscript/source/as_parser.h b/lib/angelscript/source/as_parser.h index 06fd93ff8..0f08368b2 100644 --- a/lib/angelscript/source/as_parser.h +++ b/lib/angelscript/source/as_parser.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -66,7 +66,7 @@ public: int ParseVarInit(asCScriptCode *script, asCScriptNode *init); int ParseExpression(asCScriptCode *script); #endif - + asCScriptNode *GetScriptNode(); protected: @@ -90,6 +90,7 @@ protected: asCScriptNode *ParseRealType(); asCScriptNode *ParseDataType(bool allowVariableType = false, bool allowAuto = false); asCScriptNode *ParseIdentifier(); + bool ParseTemplTypeList(asCScriptNode *node, bool required = true); asCScriptNode *ParseListPattern(); @@ -161,7 +162,7 @@ protected: bool IsPostOperator(int tokenType); bool IsAssignOperator(int tokenType); - bool CheckTemplateType(sToken &t); + bool CheckTemplateType(const sToken &t); #endif asCScriptNode *ParseToken(int token); diff --git a/lib/angelscript/source/as_property.h b/lib/angelscript/source/as_property.h index 983ee644f..c318ec4a3 100644 --- a/lib/angelscript/source/as_property.h +++ b/lib/angelscript/source/as_property.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -53,12 +53,14 @@ struct asSNameSpace; class asCObjectProperty { public: - asCObjectProperty() {accessMask = 0xFFFFFFFF;} - asCObjectProperty(const asCObjectProperty &o) : name(o.name), type(o.type), byteOffset(o.byteOffset), accessMask(o.accessMask), isPrivate(o.isPrivate), isProtected(o.isProtected), isInherited(o.isInherited) {} + asCObjectProperty() : byteOffset(0), accessMask(0xFFFFFFFF), compositeOffset(0), isCompositeIndirect(false), isPrivate(false), isProtected(false), isInherited(false) {} + asCObjectProperty(const asCObjectProperty &o) : name(o.name), type(o.type), byteOffset(o.byteOffset), accessMask(o.accessMask), compositeOffset(o.compositeOffset), isCompositeIndirect(o.isCompositeIndirect), isPrivate(o.isPrivate), isProtected(o.isProtected), isInherited(o.isInherited) {} asCString name; asCDataType type; int byteOffset; asDWORD accessMask; + int compositeOffset; + bool isCompositeIndirect; bool isPrivate; bool isProtected; bool isInherited; diff --git a/lib/angelscript/source/as_restore.cpp b/lib/angelscript/source/as_restore.cpp index 4e13157b8..6beda7cec 100644 --- a/lib/angelscript/source/as_restore.cpp +++ b/lib/angelscript/source/as_restore.cpp @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -44,6 +44,10 @@ BEGIN_AS_NAMESPACE +// Macros for doing endianess agnostic bitmask serialization +#define SAVE_TO_BIT(dst, val, bit) ((dst) |= ((val) << (bit))) +#define LOAD_FROM_BIT(dst, val, bit) ((dst) = ((val) >> (bit)) & 1) + asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine) : module(_module), stream(_stream), engine(_engine) { @@ -51,24 +55,28 @@ asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngi bytesRead = 0; } -void asCReader::ReadData(void *data, asUINT size) +int asCReader::ReadData(void *data, asUINT size) { asASSERT(size == 1 || size == 2 || size == 4 || size == 8); + int ret = 0; #if defined(AS_BIG_ENDIAN) - for( asUINT n = 0; n < size; n++ ) - stream->Read(((asBYTE*)data)+n, 1); + for( asUINT n = 0; ret >= 0 && n < size; n++ ) + ret = stream->Read(((asBYTE*)data)+n, 1); #else - for( int n = size-1; n >= 0; n-- ) - stream->Read(((asBYTE*)data)+n, 1); + for( int n = size-1; ret >= 0 && n >= 0; n-- ) + ret = stream->Read(((asBYTE*)data)+n, 1); #endif + if (ret < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); bytesRead += size; + return ret; } int asCReader::Read(bool *wasDebugInfoStripped) { TimeIt("asCReader::Read"); - // Before starting the load, make sure that + // Before starting the load, make sure that // any existing resources have been freed module->InternalReset(); @@ -108,6 +116,11 @@ int asCReader::Read(bool *wasDebugInfoStripped) *wasDebugInfoStripped = noDebugInfo; } + // Clean up the loaded string constants + for (asUINT n = 0; n < usedStringConstants.GetLength(); n++) + engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]); + usedStringConstants.SetLength(0); + return r; } @@ -125,12 +138,12 @@ int asCReader::Error(const char *msg) return asERROR; } -int asCReader::ReadInner() +int asCReader::ReadInner() { TimeIt("asCReader::ReadInner"); // This function will load each entity one by one from the stream. - // If any error occurs, it will return to the caller who is + // If any error occurs, it will return to the caller who is // responsible for cleaning up the partially loaded entities. engine->deferValidationOfTemplateTypes = true; @@ -138,61 +151,77 @@ int asCReader::ReadInner() unsigned long i, count; asCScriptFunction* func; - ReadData(&noDebugInfo, 1); + // Read the flag as 1 byte even on platforms with 4byte booleans + noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0; // Read enums count = ReadEncodedUInt(); module->enumTypes.Allocate(count, false); for( i = 0; i < count && !error; i++ ) { - asCObjectType *ot = asNEW(asCObjectType)(engine); - if( ot == 0 ) + asCEnumType *et = asNEW(asCEnumType)(engine); + if( et == 0 ) { error = true; return asOUT_OF_MEMORY; } - ReadObjectTypeDeclaration(ot, 1); + bool isExternal = false; + ReadTypeDeclaration(et, 1, &isExternal); // If the type is shared then we should use the original if it exists bool sharedExists = false; - if( ot->IsShared() ) + if( et->IsShared() ) { for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) { - asCObjectType *t = engine->sharedScriptTypes[n]; - if( t && + asCTypeInfo *t = engine->sharedScriptTypes[n]; + if( t && t->IsShared() && - t->name == ot->name && - t->nameSpace == ot->nameSpace && + t->name == et->name && + t->nameSpace == et->nameSpace && (t->flags & asOBJ_ENUM) ) { - asDELETE(ot, asCObjectType); - ot = t; + asDELETE(et, asCEnumType); + et = CastToEnumType(t); sharedExists = true; break; } } } + if (isExternal && !sharedExists) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, et->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + asDELETE(et, asCEnumType); + error = true; + return asERROR; + } + if( sharedExists ) { - existingShared.Insert(ot, true); - ot->AddRefInternal(); + existingShared.Insert(et, true); + et->AddRefInternal(); } else { - if( ot->IsShared() ) + if( et->IsShared() ) { - engine->sharedScriptTypes.PushLast(ot); - ot->AddRefInternal(); + engine->sharedScriptTypes.PushLast(et); + et->AddRefInternal(); } // Set this module as the owner - ot->module = module; + et->module = module; } - module->enumTypes.PushLast(ot); - ReadObjectTypeDeclaration(ot, 2); + module->enumTypes.PushLast(et); + + if (isExternal) + module->externalTypes.PushLast(et); + + ReadTypeDeclaration(et, 2); } if( error ) return asERROR; @@ -210,7 +239,8 @@ int asCReader::ReadInner() return asOUT_OF_MEMORY; } - ReadObjectTypeDeclaration(ot, 1); + bool isExternal = false; + ReadTypeDeclaration(ot, 1, &isExternal); // If the type is shared, then we should use the original if it exists bool sharedExists = false; @@ -218,7 +248,8 @@ int asCReader::ReadInner() { for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) { - asCObjectType *t = engine->sharedScriptTypes[n]; + asCTypeInfo *ti = engine->sharedScriptTypes[n]; + asCObjectType *t = CastToObjectType(ti); if( t && t->IsShared() && t->name == ot->name && @@ -226,13 +257,23 @@ int asCReader::ReadInner() t->IsInterface() == ot->IsInterface() ) { asDELETE(ot, asCObjectType); - ot = t; + ot = CastToObjectType(t); sharedExists = true; break; } } } + if (isExternal && !sharedExists) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, ot->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + asDELETE(ot, asCObjectType); + error = true; + return asERROR; + } + if( sharedExists ) { existingShared.Insert(ot, true); @@ -250,6 +291,9 @@ int asCReader::ReadInner() ot->module = module; } module->classTypes.PushLast(ot); + + if (isExternal) + module->externalTypes.PushLast(ot); } if( error ) return asERROR; @@ -259,44 +303,75 @@ int asCReader::ReadInner() module->funcDefs.Allocate(count, false); for( i = 0; i < count && !error; i++ ) { - bool isNew; - asCScriptFunction *func = ReadFunction(isNew, false, true); - if( func ) + bool isNew, isExternal; + asCScriptFunction *funcDef = ReadFunction(isNew, false, true, true, &isExternal); + if(funcDef) { - func->module = module; - module->funcDefs.PushLast(func); - engine->funcDefs.PushLast(func); + funcDef->module = module; + + asCFuncdefType *fdt = funcDef->funcdefType; + fdt->module = module; + + module->funcDefs.PushLast(fdt); + engine->funcDefs.PushLast(fdt); // TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module // Check if there is another identical funcdef from another module and if so reuse that instead - if( func->isShared ) + if(funcDef->IsShared()) { for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) { - asCScriptFunction *f2 = engine->funcDefs[n]; - if( f2 == 0 || func == f2 ) + asCFuncdefType *f2 = engine->funcDefs[n]; + if( f2 == 0 || fdt == f2 ) continue; - if( !f2->isShared ) + if( !f2->funcdef->IsShared() ) continue; - if( f2->name == func->name && - f2->nameSpace == func->nameSpace && - f2->IsSignatureExceptNameEqual(func) ) + if( f2->name == fdt->name && + f2->nameSpace == fdt->nameSpace && + f2->parentClass == fdt->parentClass && + f2->funcdef->IsSignatureExceptNameEqual(funcDef) ) { // Replace our funcdef for the existing one - module->funcDefs[module->funcDefs.IndexOf(func)] = f2; + module->funcDefs[module->funcDefs.IndexOf(fdt)] = f2; f2->AddRefInternal(); - engine->funcDefs.RemoveValue(func); + if (isExternal) + module->externalTypes.PushLast(f2); - savedFunctions[savedFunctions.IndexOf(func)] = f2; + engine->funcDefs.RemoveValue(fdt); - func->ReleaseInternal(); + savedFunctions[savedFunctions.IndexOf(funcDef)] = f2->funcdef; + + if (fdt->parentClass) + { + // The real funcdef should already be in the object + asASSERT(fdt->parentClass->childFuncDefs.IndexOf(f2) >= 0); + + fdt->parentClass = 0; + } + + fdt->ReleaseInternal(); + funcDef = 0; break; } } } + + // Add the funcdef to the parentClass if this is a child funcdef + if (funcDef && fdt->parentClass) + fdt->parentClass->childFuncDefs.PushLast(fdt); + + // Check if an external shared funcdef was really found + if (isExternal && funcDef) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + error = true; + return asERROR; + } } else Error(TXT_INVALID_BYTECODE_d); @@ -306,21 +381,21 @@ int asCReader::ReadInner() for( i = 0; i < module->classTypes.GetLength() && !error; i++ ) { if( module->classTypes[i]->IsInterface() ) - ReadObjectTypeDeclaration(module->classTypes[i], 2); + ReadTypeDeclaration(module->classTypes[i], 2); } // Read class methods and behaviours for( i = 0; i < module->classTypes.GetLength() && !error; ++i ) { if( !module->classTypes[i]->IsInterface() ) - ReadObjectTypeDeclaration(module->classTypes[i], 2); + ReadTypeDeclaration(module->classTypes[i], 2); } // Read class properties for( i = 0; i < module->classTypes.GetLength() && !error; ++i ) { if( !module->classTypes[i]->IsInterface() ) - ReadObjectTypeDeclaration(module->classTypes[i], 3); + ReadTypeDeclaration(module->classTypes[i], 3); } if( error ) return asERROR; @@ -330,17 +405,18 @@ int asCReader::ReadInner() module->typeDefs.Allocate(count, false); for( i = 0; i < count && !error; i++ ) { - asCObjectType *ot = asNEW(asCObjectType)(engine); - if( ot == 0 ) + asCTypedefType *td = asNEW(asCTypedefType)(engine); + if( td == 0 ) { error = true; return asOUT_OF_MEMORY; } - ReadObjectTypeDeclaration(ot, 1); - ot->module = module; - module->typeDefs.PushLast(ot); - ReadObjectTypeDeclaration(ot, 2); + bool isExternal = false; + ReadTypeDeclaration(td, 1, &isExternal); + td->module = module; + module->typeDefs.PushLast(td); + ReadTypeDeclaration(td, 2); } if( error ) return asERROR; @@ -353,26 +429,26 @@ int asCReader::ReadInner() Error(TXT_INVALID_BYTECODE_d); } module->scriptGlobals.Allocate(count, false); - for( i = 0; i < count && !error; ++i ) + for( i = 0; i < count && !error; ++i ) { ReadGlobalProperty(); } // scriptFunctions[] count = ReadEncodedUInt(); - for( i = 0; i < count && !error; ++i ) + for( i = 0; i < count && !error; ++i ) { size_t len = module->scriptFunctions.GetLength(); - bool isNew; - func = ReadFunction(isNew); + bool isNew, isExternal; + func = ReadFunction(isNew, true, true, true, &isExternal); if( func == 0 ) { Error(TXT_INVALID_BYTECODE_d); break; } - + // Is the function shared and was it created now? - if( func->isShared && len != module->scriptFunctions.GetLength() ) + if( func->IsShared() && len != module->scriptFunctions.GetLength() ) { // If the function already existed in another module, then // we need to replace it with previously existing one @@ -393,14 +469,29 @@ int asCReader::ReadInner() // Insert the function in the dontTranslate array dontTranslate.Insert(realFunc, true); + if (isExternal) + module->externalFunctions.PushLast(realFunc); + // Release the function, but make sure nothing else is released func->id = 0; - func->scriptData->byteCode.SetLength(0); + if( func->scriptData ) + func->scriptData->byteCode.SetLength(0); func->ReleaseInternal(); + func = 0; break; } } } + + // Check if an external shared func was really found + if (isExternal && func) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, func->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + error = true; + return asERROR; + } } // globalFunctions[] @@ -466,8 +557,8 @@ int asCReader::ReadInner() usedTypes.Allocate(count, false); for( i = 0; i < count && !error; ++i ) { - asCObjectType *ot = ReadObjectType(); - usedTypes.PushLast(ot); + asCTypeInfo *ti = ReadTypeInfo(); + usedTypes.PushLast(ti); } // usedTypeIds[] @@ -483,7 +574,7 @@ int asCReader::ReadInner() ReadUsedGlobalProps(); // usedStringConstants[] - if( !error ) + if( !error ) ReadUsedStringConstants(); // usedObjectProperties @@ -495,22 +586,24 @@ int asCReader::ReadInner() { for( i = 0; i < usedTypes.GetLength() && !error; i++ ) { - if( !(usedTypes[i]->flags & asOBJ_TEMPLATE) || - !usedTypes[i]->beh.templateCallback ) + asCObjectType *ot = CastToObjectType(usedTypes[i]); + if( !ot || + !(ot->flags & asOBJ_TEMPLATE) || + !ot->beh.templateCallback ) continue; - + bool dontGarbageCollect = false; - asCScriptFunction *callback = engine->scriptFunctions[usedTypes[i]->beh.templateCallback]; - if( !engine->CallGlobalFunctionRetBool(usedTypes[i], &dontGarbageCollect, callback->sysFuncIntf, callback) ) + asCScriptFunction *callback = engine->scriptFunctions[ot->beh.templateCallback]; + if( !engine->CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) ) { - asCString sub = usedTypes[i]->templateSubTypes[0].Format(usedTypes[i]->nameSpace); - for( asUINT n = 1; n < usedTypes[i]->templateSubTypes.GetLength(); n++ ) + asCString sub = ot->templateSubTypes[0].Format(ot->nameSpace); + for( asUINT n = 1; n < ot->templateSubTypes.GetLength(); n++ ) { sub += ","; - sub += usedTypes[i]->templateSubTypes[n].Format(usedTypes[i]->nameSpace); + sub += ot->templateSubTypes[n].Format(ot->nameSpace); } asCString str; - str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, usedTypes[i]->name.AddressOf(), sub.AddressOf()); + str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } @@ -518,7 +611,7 @@ int asCReader::ReadInner() { // If the callback said this template instance won't be garbage collected then remove the flag if( dontGarbageCollect ) - usedTypes[i]->flags &= ~asOBJ_GC; + ot->flags &= ~asOBJ_GC; } } } @@ -567,11 +660,18 @@ void asCReader::ReadUsedStringConstants() asUINT count; count = ReadEncodedUInt(); + + if (count > 0 && engine->stringFactory == 0) + { + Error(TXT_STRINGS_NOT_RECOGNIZED); + return; + } + usedStringConstants.Allocate(count, false); - for( asUINT i = 0; i < count; ++i ) + for( asUINT i = 0; i < count; ++i ) { ReadString(&str); - usedStringConstants.PushLast(engine->AddConstantString(str.AddressOf(), str.GetLength())); + usedStringConstants.PushLast(const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()))); } } @@ -607,7 +707,8 @@ void asCReader::ReadUsedFunctions() else { asCScriptFunction func(engine, c == 'm' ? module : 0, asFUNC_DUMMY); - ReadFunctionSignature(&func); + asCObjectType *parentClass = 0; + ReadFunctionSignature(&func, &parentClass); if( error ) { func.funcType = asFUNC_DUMMY; @@ -623,7 +724,7 @@ void asCReader::ReadUsedFunctions() { asCScriptFunction *f = module->bindInformations[i]->importedFunctionSignature; if( func.objectType != f->objectType || - func.funcType != f->funcType || + func.funcType != f->funcType || func.nameSpace != f->nameSpace || !func.IsSignatureEqual(f) ) continue; @@ -634,14 +735,16 @@ void asCReader::ReadUsedFunctions() } else if( func.funcType == asFUNC_FUNCDEF ) { - const asCArray &funcs = module->funcDefs; + const asCArray &funcs = module->funcDefs; for( asUINT i = 0; i < funcs.GetLength(); i++ ) { - asCScriptFunction *f = funcs[i]; - if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + asCScriptFunction *f = funcs[i]->funcdef; + if( f == 0 || + func.name != f->name || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) || + funcs[i]->parentClass != parentClass ) continue; - // Funcdefs are always global so there is no need to compare object type asASSERT( f->objectType == 0 ); usedFunctions[n] = f; @@ -657,7 +760,7 @@ void asCReader::ReadUsedFunctions() { asCScriptFunction *f = module->scriptFunctions[i]; if( func.objectType != f->objectType || - func.funcType != f->funcType || + func.funcType != f->funcType || func.nameSpace != f->nameSpace || !func.IsSignatureEqual(f) ) continue; @@ -667,19 +770,59 @@ void asCReader::ReadUsedFunctions() } } } + else if (c == 's') + { + // Look for shared entities in the engine, as they may not necessarily be part + // of the scope of the module if they have been inhereted from other modules. + if (func.funcType == asFUNC_FUNCDEF) + { + const asCArray &funcs = engine->funcDefs; + for (asUINT i = 0; i < funcs.GetLength(); i++) + { + asCScriptFunction *f = funcs[i]->funcdef; + if (f == 0 || + func.name != f->name || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) || + funcs[i]->parentClass != parentClass) + continue; + + asASSERT(f->objectType == 0); + + usedFunctions[n] = f; + break; + } + } + else + { + for (asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++) + { + asCScriptFunction *f = engine->scriptFunctions[i]; + if (f == 0 || !f->IsShared() || + func.objectType != f->objectType || + func.funcType != f->funcType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f)) + continue; + + usedFunctions[n] = f; + break; + } + } + } else { + asASSERT(c == 'a'); + if( func.funcType == asFUNC_FUNCDEF ) { // This is a funcdef (registered or shared) - const asCArray &funcs = engine->funcDefs; + const asCArray &funcs = engine->funcDefs; for( asUINT i = 0; i < funcs.GetLength(); i++ ) { - asCScriptFunction *f = funcs[i]; - if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + asCScriptFunction *f = funcs[i]->funcdef; + if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) || funcs[i]->parentClass != parentClass ) continue; - // Funcdefs are always global so there is no need to compare object type asASSERT( f->objectType == 0 ); usedFunctions[n] = f; @@ -690,11 +833,7 @@ void asCReader::ReadUsedFunctions() { // This is a special function - // Check for string factory - if( func.name == "$str" && engine->stringFactory && - func.IsSignatureExceptNameAndObjectTypeEqual(engine->stringFactory) ) - usedFunctions[n] = engine->stringFactory; - else if( func.name == "$beh0" && func.objectType ) + if( func.name == "$beh0" && func.objectType ) { // This is a class constructor, so we can search directly in the object type's constructors for( asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++ ) @@ -711,7 +850,7 @@ void asCReader::ReadUsedFunctions() else if( func.name == "$fact" || func.name == "$beh3" ) { // This is a factory (or stub), so look for the function in the return type's factories - asCObjectType *objType = func.returnType.GetObjectType(); + asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo()); if( objType ) { for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ ) @@ -729,7 +868,7 @@ void asCReader::ReadUsedFunctions() else if( func.name == "$list" ) { // listFactory is used for both factory is global and returns a handle and constructor that is a method - asCObjectType *objType = func.objectType ? func.objectType : func.returnType.GetObjectType(); + asCObjectType *objType = func.objectType ? func.objectType : CastToObjectType(func.returnType.GetTypeInfo()); if( objType ) { asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory]; @@ -751,7 +890,7 @@ void asCReader::ReadUsedFunctions() else if( func.name == "$beh4" ) { // This is a list factory, so check the return type's list factory - asCObjectType *objType = func.returnType.GetObjectType(); + asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo()); if( objType ) { asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory]; @@ -800,10 +939,10 @@ void asCReader::ReadUsedFunctions() if( usedFunctions[n] == 0 ) { - // TODO: clean up: This part of the code should never happen. All functions should - // be found in the above logic. The only valid reason to come here + // TODO: clean up: This part of the code should never happen. All functions should + // be found in the above logic. The only valid reason to come here // is if the bytecode is wrong and the function doesn't exist anyway. - // This loop is kept temporarily until we can be certain all scenarios + // This loop is kept temporarily until we can be certain all scenarios // are covered. for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ ) { @@ -835,7 +974,7 @@ void asCReader::ReadUsedFunctions() } } -void asCReader::ReadFunctionSignature(asCScriptFunction *func) +void asCReader::ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass) { asUINT i, count; asCDataType dt; @@ -844,7 +983,7 @@ void asCReader::ReadFunctionSignature(asCScriptFunction *func) ReadString(&func->name); if( func->name == DELEGATE_FACTORY ) { - // It's not necessary to read anymore, everything is known + // It's not necessary to read anymore, everything is known asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY); asASSERT( f ); func->returnType = f->returnType; @@ -866,7 +1005,7 @@ void asCReader::ReadFunctionSignature(asCScriptFunction *func) return; } func->parameterTypes.Allocate(count, false); - for( i = 0; i < count; ++i ) + for( i = 0; i < count; ++i ) { ReadDataType(&dt); func->parameterTypes.PushLast(dt); @@ -926,30 +1065,55 @@ void asCReader::ReadFunctionSignature(asCScriptFunction *func) ReadString(str); } } - - func->objectType = ReadObjectType(); + + func->objectType = CastToObjectType(ReadTypeInfo()); if( func->objectType ) { func->objectType->AddRefInternal(); asBYTE b; ReadData(&b, 1); - func->isReadOnly = (b & 1) ? true : false; - func->isPrivate = (b & 2) ? true : false; - func->isProtected = (b & 4) ? true : false; + func->SetReadOnly((b & 1) ? true : false); + func->SetPrivate((b & 2) ? true : false); + func->SetProtected((b & 4) ? true : false); func->nameSpace = engine->nameSpaces[0]; } else { - asCString ns; - ReadString(&ns); - func->nameSpace = engine->AddNameSpace(ns.AddressOf()); + if (func->funcType == asFUNC_FUNCDEF) + { + asBYTE b; + ReadData(&b, 1); + if (b == 'n') + { + asCString ns; + ReadString(&ns); + func->nameSpace = engine->AddNameSpace(ns.AddressOf()); + } + else if (b == 'o') + { + func->nameSpace = 0; + if (parentClass) + *parentClass = CastToObjectType(ReadTypeInfo()); + else + error = true; + } + else + error = true; + } + else + { + asCString ns; + ReadString(&ns); + func->nameSpace = engine->AddNameSpace(ns.AddressOf()); + } } } -asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC) +asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC, bool *isExternal) { isNew = false; + if (isExternal) *isExternal = false; if( error ) return 0; char c; @@ -989,7 +1153,8 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a asCDataType dt; int num; - ReadFunctionSignature(func); + asCObjectType *parentClass = 0; + ReadFunctionSignature(func, &parentClass); if( error ) { func->DestroyHalfCreated(); @@ -998,150 +1163,160 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a if( func->funcType == asFUNC_SCRIPT ) { - func->AllocateScriptFunctionData(); - if( func->scriptData == 0 ) + char bits; + ReadData(&bits, 1); + func->SetShared((bits & 1) ? true : false); + func->dontCleanUpOnException = (bits & 2) ? true : false; + if ((bits & 4) && isExternal) + *isExternal = true; + + // for external shared functions the rest is not needed + if (!(bits & 4)) { - // Out of memory - error = true; - func->DestroyHalfCreated(); - return 0; - } - - if( addToGC && !addToModule ) - engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours); - - ReadByteCode(func); - - func->scriptData->variableSpace = ReadEncodedUInt(); - - count = ReadEncodedUInt(); - func->scriptData->objVariablePos.Allocate(count, false); - func->scriptData->objVariableTypes.Allocate(count, false); - func->scriptData->funcVariableTypes.Allocate(count, false); - for( i = 0; i < count; ++i ) - { - func->scriptData->objVariableTypes.PushLast(ReadObjectType()); - asUINT idx = ReadEncodedUInt(); - func->scriptData->funcVariableTypes.PushLast((asCScriptFunction*)(asPWORD)idx); - num = ReadEncodedUInt(); - func->scriptData->objVariablePos.PushLast(num); - - if( error ) - { - // No need to continue (the error has already been reported before) - func->DestroyHalfCreated(); - return 0; - } - } - if( count > 0 ) - func->scriptData->objVariablesOnHeap = ReadEncodedUInt(); - else - func->scriptData->objVariablesOnHeap = 0; - - int length = ReadEncodedUInt(); - func->scriptData->objVariableInfo.SetLength(length); - for( i = 0; i < length; ++i ) - { - func->scriptData->objVariableInfo[i].programPos = ReadEncodedUInt(); - func->scriptData->objVariableInfo[i].variableOffset = ReadEncodedUInt(); - func->scriptData->objVariableInfo[i].option = ReadEncodedUInt(); - } - - if( !noDebugInfo ) - { - length = ReadEncodedUInt(); - func->scriptData->lineNumbers.SetLength(length); - if( int(func->scriptData->lineNumbers.GetLength()) != length ) + func->AllocateScriptFunctionData(); + if (func->scriptData == 0) { // Out of memory error = true; func->DestroyHalfCreated(); return 0; } - for( i = 0; i < length; ++i ) - func->scriptData->lineNumbers[i] = ReadEncodedUInt(); - // Read the array of script sections - length = ReadEncodedUInt(); - func->scriptData->sectionIdxs.SetLength(length); - if( int(func->scriptData->sectionIdxs.GetLength()) != length ) + if (addToGC && !addToModule) + engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours); + + ReadByteCode(func); + + func->scriptData->variableSpace = ReadEncodedUInt(); + + count = ReadEncodedUInt(); + func->scriptData->objVariablePos.Allocate(count, false); + func->scriptData->objVariableTypes.Allocate(count, false); + for (i = 0; i < count; ++i) { - // Out of memory - error = true; - func->DestroyHalfCreated(); - return 0; - } - for( i = 0; i < length; ++i ) - { - if( (i & 1) == 0 ) - func->scriptData->sectionIdxs[i] = ReadEncodedUInt(); - else - { - asCString str; - ReadString(&str); - func->scriptData->sectionIdxs[i] = engine->GetScriptSectionNameIndex(str.AddressOf()); - } - } - } + func->scriptData->objVariableTypes.PushLast(ReadTypeInfo()); + num = ReadEncodedUInt(); + func->scriptData->objVariablePos.PushLast(num); - // Read the variable information - if( !noDebugInfo ) - { - length = ReadEncodedUInt(); - func->scriptData->variables.Allocate(length, false); - for( i = 0; i < length; i++ ) - { - asSScriptVariable *var = asNEW(asSScriptVariable); - if( var == 0 ) - { - // Out of memory - error = true; - func->DestroyHalfCreated(); - return 0; - } - func->scriptData->variables.PushLast(var); - - var->declaredAtProgramPos = ReadEncodedUInt(); - var->stackOffset = ReadEncodedUInt(); - ReadString(&var->name); - ReadDataType(&var->type); - - if( error ) + if (error) { // No need to continue (the error has already been reported before) func->DestroyHalfCreated(); return 0; } } - } + if (count > 0) + func->scriptData->objVariablesOnHeap = ReadEncodedUInt(); + else + func->scriptData->objVariablesOnHeap = 0; - char bits; - ReadData(&bits, 1); - func->isShared = bits & 1 ? true : false; - func->dontCleanUpOnException = bits & 2 ? true : false; - - // Read script section name - if( !noDebugInfo ) - { - asCString name; - ReadString(&name); - func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf()); - func->scriptData->declaredAt = ReadEncodedUInt(); - } - - // Read parameter names - if( !noDebugInfo ) - { - asUINT count = asUINT(ReadEncodedUInt64()); - if( count > func->parameterTypes.GetLength() ) + int length = ReadEncodedUInt(); + func->scriptData->objVariableInfo.SetLength(length); + for (i = 0; i < length; ++i) { - error = true; - func->DestroyHalfCreated(); - return 0; + func->scriptData->objVariableInfo[i].programPos = ReadEncodedUInt(); + func->scriptData->objVariableInfo[i].variableOffset = ReadEncodedUInt(); + asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt(); + func->scriptData->objVariableInfo[i].option = option; + if (option != asOBJ_INIT && option != asOBJ_UNINIT && option != asBLOCK_BEGIN && option != asBLOCK_END) + { + error = true; + func->DestroyHalfCreated(); + return 0; + } + } + + if (!noDebugInfo) + { + length = ReadEncodedUInt(); + func->scriptData->lineNumbers.SetLength(length); + if (int(func->scriptData->lineNumbers.GetLength()) != length) + { + // Out of memory + error = true; + func->DestroyHalfCreated(); + return 0; + } + for (i = 0; i < length; ++i) + func->scriptData->lineNumbers[i] = ReadEncodedUInt(); + + // Read the array of script sections + length = ReadEncodedUInt(); + func->scriptData->sectionIdxs.SetLength(length); + if (int(func->scriptData->sectionIdxs.GetLength()) != length) + { + // Out of memory + error = true; + func->DestroyHalfCreated(); + return 0; + } + for (i = 0; i < length; ++i) + { + if ((i & 1) == 0) + func->scriptData->sectionIdxs[i] = ReadEncodedUInt(); + else + { + asCString str; + ReadString(&str); + func->scriptData->sectionIdxs[i] = engine->GetScriptSectionNameIndex(str.AddressOf()); + } + } + } + + // Read the variable information + if (!noDebugInfo) + { + length = ReadEncodedUInt(); + func->scriptData->variables.Allocate(length, false); + for (i = 0; i < length; i++) + { + asSScriptVariable *var = asNEW(asSScriptVariable); + if (var == 0) + { + // Out of memory + error = true; + func->DestroyHalfCreated(); + return 0; + } + func->scriptData->variables.PushLast(var); + + var->declaredAtProgramPos = ReadEncodedUInt(); + var->stackOffset = ReadEncodedUInt(); + ReadString(&var->name); + ReadDataType(&var->type); + + if (error) + { + // No need to continue (the error has already been reported before) + func->DestroyHalfCreated(); + return 0; + } + } + } + + // Read script section name + if (!noDebugInfo) + { + asCString name; + ReadString(&name); + func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf()); + func->scriptData->declaredAt = ReadEncodedUInt(); + } + + // Read parameter names + if (!noDebugInfo) + { + asUINT countParam = asUINT(ReadEncodedUInt64()); + if (countParam > func->parameterTypes.GetLength()) + { + error = true; + func->DestroyHalfCreated(); + return 0; + } + func->parameterNames.SetLength(countParam); + for (asUINT n = 0; n < countParam; n++) + ReadString(&func->parameterNames[n]); } - func->parameterNames.SetLength(count); - for( asUINT n = 0; n < count; n++ ) - ReadString(&func->parameterNames[n]); } } else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) @@ -1152,8 +1327,14 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a { asBYTE bits; ReadData(&bits, 1); - if( bits ) - func->isShared = true; + if( bits & 1 ) + func->SetShared(true); + if ((bits & 2) && isExternal) + *isExternal = true; + + // The asCFuncdefType constructor adds itself to the func->funcdefType member + asCFuncdefType *fdt = asNEW(asCFuncdefType)(engine, func); + fdt->parentClass = parentClass; } if( addToModule ) @@ -1173,48 +1354,84 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a return func; } -void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) +void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExternal) { if( phase == 1 ) { + asASSERT(isExternal); + if (isExternal) + *isExternal = false; + // Read the initial attributes - ReadString(&ot->name); - ReadData(&ot->flags, 4); - ot->size = ReadEncodedUInt(); + ReadString(&type->name); + ReadData(&type->flags, 4); + type->size = ReadEncodedUInt(); asCString ns; ReadString(&ns); - ot->nameSpace = engine->AddNameSpace(ns.AddressOf()); + type->nameSpace = engine->AddNameSpace(ns.AddressOf()); + + // Verify that the flags match the asCTypeInfo + if ((CastToEnumType(type) && !(type->flags & asOBJ_ENUM)) || + (CastToFuncdefType(type) && !(type->flags & asOBJ_FUNCDEF)) || + (CastToObjectType(type) && !(type->flags & (asOBJ_REF | asOBJ_VALUE)))) + { + error = true; + return; + } // Reset the size of script classes, since it will be recalculated as properties are added - if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size != 0 ) - ot->size = sizeof(asCScriptObject); + if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size != 0 ) + type->size = sizeof(asCScriptObject); - // Use the default script class behaviours - ot->beh = engine->scriptTypeBehaviours.beh; - ot->beh.construct = 0; - ot->beh.factory = 0; - ot->beh.constructors.PopLast(); // These will be read from the file - ot->beh.factories.PopLast(); // These will be read from the file - engine->scriptFunctions[ot->beh.addref]->AddRefInternal(); - engine->scriptFunctions[ot->beh.release]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal(); - engine->scriptFunctions[ot->beh.copy]->AddRefInternal(); - // TODO: weak: Should not do this if the class has been declared with 'noweak' - engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); + asCObjectType *ot = CastToObjectType(type); + if (ot) + { + // Use the default script class behaviours + ot->beh = engine->scriptTypeBehaviours.beh; + ot->beh.construct = 0; + ot->beh.factory = 0; + ot->beh.constructors.PopLast(); // These will be read from the file + ot->beh.factories.PopLast(); // These will be read from the file + engine->scriptFunctions[ot->beh.addref]->AddRefInternal(); + engine->scriptFunctions[ot->beh.release]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal(); + engine->scriptFunctions[ot->beh.copy]->AddRefInternal(); + // TODO: weak: Should not do this if the class has been declared with 'noweak' + engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); + } + + // external shared flag + if (type->flags & asOBJ_SHARED) + { + char c; + ReadData(&c, 1); + if (c == 'e') + *isExternal = true; + else if (c != ' ') + { + error = true; + return; + } + } } else if( phase == 2 ) { - if( ot->flags & asOBJ_ENUM ) + // external shared types doesn't store this + if ((type->flags & asOBJ_SHARED) && module->externalTypes.IndexOf(type) >= 0) + return; + + if( type->flags & asOBJ_ENUM ) { + asCEnumType *t = CastToEnumType(type); int count = ReadEncodedUInt(); - bool sharedExists = existingShared.MoveTo(0, ot); + bool sharedExists = existingShared.MoveTo(0, type); if( !sharedExists ) { - ot->enumValues.Allocate(count, false); + t->enumValues.Allocate(count, false); for( int n = 0; n < count; n++ ) { asSEnumValue *e = asNEW(asSEnumValue); @@ -1226,7 +1443,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) } ReadString(&e->name); ReadData(&e->value, 4); // TODO: Should be encoded - ot->enumValues.PushLast(e); + t->enumValues.PushLast(e); } } else @@ -1239,10 +1456,10 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) ReadString(&name); ReadData(&value, 4); // TODO: Should be encoded bool found = false; - for( asUINT e = 0; e < ot->enumValues.GetLength(); e++ ) + for( asUINT e = 0; e < t->enumValues.GetLength(); e++ ) { - if( ot->enumValues[e]->name == name && - ot->enumValues[e]->value == value ) + if( t->enumValues[e]->name == name && + t->enumValues[e]->value == value ) { found = true; break; @@ -1251,37 +1468,42 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) if( !found ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } } } } - else if( ot->flags & asOBJ_TYPEDEF ) + else if( type->flags & asOBJ_TYPEDEF ) { + asCTypedefType *td = CastToTypedefType(type); + asASSERT(td); eTokenType t = (eTokenType)ReadEncodedUInt(); - ot->templateSubTypes.PushLast(asCDataType::CreatePrimitive(t, false)); + td->aliasForType = asCDataType::CreatePrimitive(t, false); } else { - // If the type is shared and pre-existing, we should just - // validate that the loaded methods match the original - bool sharedExists = existingShared.MoveTo(0, ot); + asCObjectType *ot = CastToObjectType(type); + asASSERT(ot); + + // If the type is shared and pre-existing, we should just + // validate that the loaded methods match the original + bool sharedExists = existingShared.MoveTo(0, type); if( sharedExists ) { - asCObjectType *dt = ReadObjectType(); + asCObjectType *dt = CastToObjectType(ReadTypeInfo()); if( ot->derivedFrom != dt ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } } else { - ot->derivedFrom = ReadObjectType(); + ot->derivedFrom = CastToObjectType(ReadTypeInfo()); if( ot->derivedFrom ) ot->derivedFrom->AddRefInternal(); } @@ -1292,13 +1514,13 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) { for( int n = 0; n < size; n++ ) { - asCObjectType *intf = ReadObjectType(); + asCObjectType *intf = CastToObjectType(ReadTypeInfo()); ReadEncodedUInt(); - if( !ot->Implements(intf) ) + if( !type->Implements(intf) ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } @@ -1310,7 +1532,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) ot->interfaceVFTOffsets.Allocate(size, false); for( int n = 0; n < size; n++ ) { - asCObjectType *intf = ReadObjectType(); + asCObjectType *intf = CastToObjectType(ReadTypeInfo()); ot->interfaces.PushLast(intf); asUINT offset = ReadEncodedUInt(); @@ -1319,7 +1541,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) } // behaviours - if( !ot->IsInterface() && ot->flags != asOBJ_TYPEDEF && ot->flags != asOBJ_ENUM ) + if( !ot->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM ) { bool isNew; asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); @@ -1336,7 +1558,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) else { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } @@ -1368,17 +1590,16 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) size = ReadEncodedUInt(); for( int n = 0; n < size; n++ ) { - bool isNew; - asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); + func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); if( func ) { if( sharedExists ) { // Find the real function in the object, and update the savedFunctions array bool found = false; - for( asUINT n = 0; n < ot->beh.constructors.GetLength(); n++ ) + for( asUINT f = 0; f < ot->beh.constructors.GetLength(); f++ ) { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[n]); + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[f]); if( realFunc->IsSignatureEqual(func) ) { // If the function is not the last, then the substitution has already occurred before @@ -1394,7 +1615,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) if( !found ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } @@ -1427,9 +1648,9 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) { // Find the real function in the object, and update the savedFunctions array bool found = false; - for( asUINT n = 0; n < ot->beh.factories.GetLength(); n++ ) + for( asUINT f = 0; f < ot->beh.factories.GetLength(); f++ ) { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[n]); + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[f]); if( realFunc->IsSignatureEqual(func) ) { // If the function is not the last, then the substitution has already occurred before @@ -1445,7 +1666,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) if( !found ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } @@ -1476,7 +1697,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) // methods[] size = ReadEncodedUInt(); int n; - for( n = 0; n < size; n++ ) + for( n = 0; n < size; n++ ) { bool isNew; asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); @@ -1486,9 +1707,9 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) { // Find the real function in the object, and update the savedFunctions array bool found = false; - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + for( asUINT f = 0; f < ot->methods.GetLength(); f++ ) { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[n]); + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[f]); if( realFunc->IsSignatureEqual(func) ) { // If the function is not the last, then the substitution has already occurred before @@ -1504,7 +1725,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) if( !found ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } @@ -1521,14 +1742,14 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) { // If the method is the assignment operator we need to replace the default implementation if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && - func->parameterTypes[0].GetObjectType() == func->objectType && + func->parameterTypes[0].GetTypeInfo() == func->objectType && (func->inOutFlags[0] & asTM_INREF) ) { engine->scriptFunctions[ot->beh.copy]->ReleaseInternal(); ot->beh.copy = func->id; func->AddRefInternal(); } - + ot->methods.PushLast(func->id); func->AddRefInternal(); } @@ -1551,9 +1772,9 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) { // Find the real function in the object, and update the savedFunctions array bool found = false; - for( asUINT n = 0; n < ot->virtualFunctionTable.GetLength(); n++ ) + for( asUINT f = 0; f < ot->virtualFunctionTable.GetLength(); f++ ) { - asCScriptFunction *realFunc = ot->virtualFunctionTable[n]; + asCScriptFunction *realFunc = ot->virtualFunctionTable[f]; if( realFunc->IsSignatureEqual(func) ) { // If the function is not the last, then the substitution has already occurred before @@ -1569,7 +1790,7 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) if( !found ) { asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); Error(TXT_INVALID_BYTECODE_d); } @@ -1597,6 +1818,15 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) } else if( phase == 3 ) { + // external shared types doesn't store this + if ((type->flags & asOBJ_SHARED) && module->externalTypes.IndexOf(type) >= 0) + return; + + asCObjectType *ot = CastToObjectType(type); + + // This is only done for object types + asASSERT(ot); + // properties[] asUINT size = ReadEncodedUInt(); for( asUINT n = 0; n < size; n++ ) @@ -1633,7 +1863,7 @@ asQWORD asCReader::ReadEncodedUInt64() ReadData(&b, 1); bool isNegative = ( b & 0x80 ) ? true : false; b &= 0x7F; - + if( (b & 0x7F) == 0x7F ) { ReadData(&b, 1); i = asQWORD(b) << 56; @@ -1654,7 +1884,7 @@ asQWORD asCReader::ReadEncodedUInt64() ReadData(&b, 1); i += asUINT(b) << 16; ReadData(&b, 1); i += asUINT(b) << 8; ReadData(&b, 1); i += b; - } + } else if( (b & 0x7C) == 0x7C ) { i = asQWORD(b & 0x03) << 40; @@ -1663,7 +1893,7 @@ asQWORD asCReader::ReadEncodedUInt64() ReadData(&b, 1); i += asUINT(b) << 16; ReadData(&b, 1); i += asUINT(b) << 8; ReadData(&b, 1); i += b; - } + } else if( (b & 0x78) == 0x78 ) { i = asQWORD(b & 0x07) << 32; @@ -1671,7 +1901,7 @@ asQWORD asCReader::ReadEncodedUInt64() ReadData(&b, 1); i += asUINT(b) << 16; ReadData(&b, 1); i += asUINT(b) << 8; ReadData(&b, 1); i += b; - } + } else if( (b & 0x70) == 0x70 ) { i = asUINT(b & 0x0F) << 24; @@ -1700,7 +1930,7 @@ asQWORD asCReader::ReadEncodedUInt64() return i; } -void asCReader::ReadString(asCString* str) +void asCReader::ReadString(asCString* str) { asUINT len = ReadEncodedUInt(); if( len & 1 ) @@ -1715,7 +1945,9 @@ void asCReader::ReadString(asCString* str) { len /= 2; str->SetLength(len); - stream->Read(str->AddressOf(), len); + int r = stream->Read(str->AddressOf(), len); + if (r < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); savedStrings.PushLast(*str); } @@ -1723,7 +1955,7 @@ void asCReader::ReadString(asCString* str) str->SetLength(0); } -void asCReader::ReadGlobalProperty() +void asCReader::ReadGlobalProperty() { asCString name; asCDataType type; @@ -1740,7 +1972,7 @@ void asCReader::ReadGlobalProperty() // Read the initialization function bool isNew; - // Do not add the function to the GC at this time. It will + // Do not add the function to the GC at this time. It will // only be added to the GC when the module releases the property asCScriptFunction *func = ReadFunction(isNew, false, true, false); if( func ) @@ -1753,7 +1985,7 @@ void asCReader::ReadGlobalProperty() } } -void asCReader::ReadObjectProperty(asCObjectType *ot) +void asCReader::ReadObjectProperty(asCObjectType *ot) { asCString name; ReadString(&name); @@ -1764,20 +1996,20 @@ void asCReader::ReadObjectProperty(asCObjectType *ot) bool isProtected = (flags & 2) ? true : false; bool isInherited = (flags & 4) ? true : false; - // TODO: shared: If the type is shared and pre-existing, we should just - // validate that the loaded methods match the original + // TODO: shared: If the type is shared and pre-existing, we should just + // validate that the loaded methods match the original if( !existingShared.MoveTo(0, ot) ) ot->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); } -void asCReader::ReadDataType(asCDataType *dt) +void asCReader::ReadDataType(asCDataType *dt) { // Check if this is a previously used type - asUINT n = ReadEncodedUInt(); - if( n != 0 ) + asUINT idx = ReadEncodedUInt(); + if( idx != 0 ) { // Get the datatype from the cache - *dt = savedDataTypes[n-1]; + *dt = savedDataTypes[idx-1]; return; } @@ -1789,78 +2021,42 @@ void asCReader::ReadDataType(asCDataType *dt) savedDataTypes.PushLast(asCDataType()); // Read the datatype for the first time - asCObjectType *objType = 0; + asCTypeInfo *ti = 0; if( tokenType == ttIdentifier ) - objType = ReadObjectType(); + ti = ReadTypeInfo(); - struct - { - char isObjectHandle :1; - char isHandleToConst:1; - char isReference :1; - char isReadOnly :1; - } bits = {0}; - asASSERT( sizeof(bits) == 1 ); - ReadData(&bits, 1); + // Read type flags as a bitmask + // Endian-safe code + bool isObjectHandle, isHandleToConst, isReference, isReadOnly; + char b = 0; + ReadData(&b, 1); + LOAD_FROM_BIT(isObjectHandle, b, 0); + LOAD_FROM_BIT(isHandleToConst, b, 1); + LOAD_FROM_BIT(isReference, b, 2); + LOAD_FROM_BIT(isReadOnly, b, 3); - asCScriptFunction *funcDef = 0; - if( tokenType == ttIdentifier && objType && objType->name == "$func" ) - { - asCScriptFunction func(engine, module, asFUNC_DUMMY); - ReadFunctionSignature(&func); - if( error ) return; - for( asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++ ) - { - // TODO: access: Only return the definitions that the module has access to - if( engine->registeredFuncDefs[n]->name == func.name && - engine->registeredFuncDefs[n]->nameSpace == func.nameSpace ) - { - funcDef = engine->registeredFuncDefs[n]; - break; - } - } - - if( !funcDef && module ) - { - for( asUINT n = 0; n < module->funcDefs.GetLength(); n++ ) - { - if( module->funcDefs[n]->name == func.name && - module->funcDefs[n]->nameSpace == func.nameSpace ) - { - funcDef = module->funcDefs[n]; - break; - } - } - } - - // Set to dummy to avoid unwanted release of resources - func.funcType = asFUNC_DUMMY; - } - - if( funcDef ) - *dt = asCDataType::CreateFuncDef(funcDef); - else if( tokenType == ttIdentifier ) - *dt = asCDataType::CreateObject(objType, false); + if( tokenType == ttIdentifier ) + *dt = asCDataType::CreateType(ti, false); else *dt = asCDataType::CreatePrimitive(tokenType, false); - if( bits.isObjectHandle ) + if( isObjectHandle ) { - dt->MakeReadOnly(bits.isHandleToConst ? true : false); - - // Here we must allow a scoped type to be a handle + dt->MakeReadOnly(isHandleToConst ? true : false); + + // Here we must allow a scoped type to be a handle // e.g. if the datatype is for a system function dt->MakeHandle(true, true); } - dt->MakeReadOnly(bits.isReadOnly ? true : false); - dt->MakeReference(bits.isReference ? true : false); + dt->MakeReadOnly(isReadOnly ? true : false); + dt->MakeReference(isReference ? true : false); // Update the previously saved slot savedDataTypes[saveSlot] = *dt; } -asCObjectType* asCReader::ReadObjectType() +asCTypeInfo* asCReader::ReadTypeInfo() { - asCObjectType *ot = 0; + asCTypeInfo *ot = 0; char ch; ReadData(&ch, 1); if( ch == 'a' ) @@ -1871,7 +2067,8 @@ asCObjectType* asCReader::ReadObjectType() ReadString(&ns); asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); - asCObjectType *tmpl = engine->GetRegisteredObjectType(typeName.AddressOf(), nameSpace); + asCTypeInfo *tmp = engine->GetRegisteredType(typeName.AddressOf(), nameSpace); + asCObjectType *tmpl = CastToObjectType(tmp); if( tmpl == 0 ) { asCString str; @@ -1927,7 +2124,7 @@ asCObjectType* asCReader::ReadObjectType() } else if( ch == 'l' ) { - asCObjectType *st = ReadObjectType(); + asCObjectType *st = CastToObjectType(ReadTypeInfo()); if( st == 0 || st->beh.listFactory == 0 ) { Error(TXT_INVALID_BYTECODE_d); @@ -1972,10 +2169,10 @@ asCObjectType* asCReader::ReadObjectType() if( typeName.GetLength() && typeName != "$obj" && typeName != "$func" ) { // Find the object type - ot = module->GetObjectType(typeName.AddressOf(), nameSpace); - if( !ot ) - ot = engine->GetRegisteredObjectType(typeName.AddressOf(), nameSpace); - + ot = module->GetType(typeName.AddressOf(), nameSpace); + if (!ot) + ot = engine->GetRegisteredType(typeName.AddressOf(), nameSpace); + if( ot == 0 ) { asCString str; @@ -1996,6 +2193,36 @@ asCObjectType* asCReader::ReadObjectType() else asASSERT( false ); } + else if (ch == 'c') + { + // Read the object type name + asCString typeName, ns; + ReadString(&typeName); + + // Read the parent class + asCObjectType *parentClass = CastToObjectType(ReadTypeInfo()); + if (parentClass == 0) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + // Find the child type in the parentClass + for (asUINT n = 0; n < parentClass->childFuncDefs.GetLength(); n++) + { + if (parentClass->childFuncDefs[n]->name == typeName) + ot = parentClass->childFuncDefs[n]; + } + + if (ot == 0) + { + asCString str; + str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + } else { // No object type @@ -2151,7 +2378,7 @@ void asCReader::ReadByteCode(asCScriptFunction *func) w = ReadEncodedUInt16(); *(asWORD*)bc = w; bc++; - + // Read the third argument asDWORD dw = ReadEncodedUInt(); *bc++ = dw; @@ -2314,7 +2541,7 @@ void asCReader::ReadUsedObjectProps() usedObjectProperties.SetLength(c); for( asUINT n = 0; n < c; n++ ) { - asCObjectType *objType = ReadObjectType(); + asCObjectType *objType = CastToObjectType(ReadTypeInfo()); if( objType == 0 ) { Error(TXT_INVALID_BYTECODE_d); @@ -2324,14 +2551,14 @@ void asCReader::ReadUsedObjectProps() asCString name; ReadString(&name); - // Find the property offset + // Find the property bool found = false; for( asUINT p = 0; p < objType->properties.GetLength(); p++ ) { if( objType->properties[p]->name == name ) { usedObjectProperties[n].objType = objType; - usedObjectProperties[n].offset = objType->properties[p]->byteOffset; + usedObjectProperties[n].prop = objType->properties[p]; found = true; break; } @@ -2347,13 +2574,32 @@ void asCReader::ReadUsedObjectProps() short asCReader::FindObjectPropOffset(asWORD index) { + static asCObjectProperty *lastCompositeProp = 0; + if (lastCompositeProp) + { + if (index != 0) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + short offset = (short)lastCompositeProp->byteOffset; + lastCompositeProp = 0; + return offset; + } + if( index >= usedObjectProperties.GetLength() ) { Error(TXT_INVALID_BYTECODE_d); return 0; } - return (short)usedObjectProperties[index].offset; + if (usedObjectProperties[index].prop->compositeOffset || usedObjectProperties[index].prop->isCompositeIndirect) + { + lastCompositeProp = usedObjectProperties[index].prop; + return (short)lastCompositeProp->compositeOffset; + } + return (short)usedObjectProperties[index].prop->byteOffset; } asCScriptFunction *asCReader::FindFunction(int idx) @@ -2398,13 +2644,13 @@ void asCReader::TranslateFunction(asCScriptFunction *func) for( n = 0; n < bcLength; bcNum++ ) { int c = *(asBYTE*)&bc[n]; - if( c == asBC_REFCPY || + if( c == asBC_REFCPY || c == asBC_RefCpyV || c == asBC_OBJTYPE ) { // Translate the index to the true object type asPWORD *ot = (asPWORD*)&bc[n+1]; - *(asCObjectType**)ot = FindObjectType(*(int*)ot); + *(asCObjectType**)ot = CastToObjectType(FindType(int(*ot))); } else if( c == asBC_TYPEID || c == asBC_Cast ) @@ -2449,7 +2695,7 @@ void asCReader::TranslateFunction(asCScriptFunction *func) int *tid = (int*)&bc[n+1]; *tid = FindTypeId(*tid); - // COPY is used to copy POD types that don't have the opAssign method. It is + // COPY is used to copy POD types that don't have the opAssign method. It is // also used to copy references to scoped types during variable initializations. // Update the number of dwords to copy as it may be different on the target platform if( (*tid) & asTYPEID_OBJHANDLE ) @@ -2496,13 +2742,13 @@ void asCReader::TranslateFunction(asCScriptFunction *func) { // Translate the index to the func pointer asPWORD *fid = (asPWORD*)&bc[n+1]; - *fid = (asPWORD)FindFunction((int)*fid); + *fid = (asPWORD)FindFunction(int(*fid)); } else if( c == asBC_ALLOC ) { // Translate the index to the true object type asPWORD *arg = (asPWORD*)&bc[n+1]; - *(asCObjectType**)arg = FindObjectType(*(int*)arg); + *(asCObjectType**)arg = CastToObjectType(FindType(int(*arg))); // The constructor function id must be translated, unless it is zero int *fid = (int*)&bc[n+1+AS_PTR_SIZE]; @@ -2521,16 +2767,8 @@ void asCReader::TranslateFunction(asCScriptFunction *func) } else if( c == asBC_STR ) { - // Translate the index to the true string id - asWORD *arg = ((asWORD*)&bc[n])+1; - - if( *arg < usedStringConstants.GetLength() ) - *arg = (asWORD)usedStringConstants[*arg]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } + Error(TXT_INVALID_BYTECODE_d); + return; } else if( c == asBC_CALLBND ) { @@ -2562,14 +2800,30 @@ void asCReader::TranslateFunction(asCScriptFunction *func) c == asBC_CpyVtoG4 || c == asBC_SetG4 ) { - // Translate the global var index to pointer - asPWORD *index = (asPWORD*)&bc[n+1]; - if( *(asUINT*)index < usedGlobalProperties.GetLength() ) - *(void**)index = usedGlobalProperties[*(asUINT*)index]; + // Translate the index to pointer + asPWORD *index = (asPWORD*)&bc[n + 1]; + if ((*index & 1)) + { + if ((asUINT(*index)>>1) < usedGlobalProperties.GetLength()) + *(void**)index = usedGlobalProperties[asUINT(*index)>>1]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } else { - Error(TXT_INVALID_BYTECODE_d); - return; + // Only PGA and PshGPtr can hold string constants + asASSERT(c == asBC_PGA || c == asBC_PshGPtr); + + if ((asUINT(*index)>>1) < usedStringConstants.GetLength()) + *(void**)index = usedStringConstants[asUINT(*index)>>1]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } } } else if( c == asBC_JMP || @@ -2582,7 +2836,7 @@ void asCReader::TranslateFunction(asCScriptFunction *func) c == asBC_JP || c == asBC_JNP ) // The JMPP instruction doesn't need modification { - // Get the offset + // Get the offset int offset = int(bc[n+1]); // Count the instruction sizes to the destination instruction @@ -2596,24 +2850,24 @@ void asCReader::TranslateFunction(asCScriptFunction *func) for( asUINT num = bcNum; offset++ < 0; num-- ) size -= bcSizes[num]; - // The size is dword offset + // The size is dword offset bc[n+1] = size; } else if( c == asBC_AllocMem ) { // The size of the allocated memory is only known after all the elements has been seen. - // This helper class will collect this information and adjust the size when the + // This helper class will collect this information and adjust the size when the // corresponding asBC_FREE is encountered // The adjuster also needs to know the list type so it can know the type of the elements - asCObjectType *ot = func->GetObjectTypeOfLocalVar(asBC_SWORDARG0(&bc[n])); + asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(asBC_SWORDARG0(&bc[n]))); listAdjusters.PushLast(asNEW(SListAdjuster)(this, &bc[n], ot)); } else if( c == asBC_FREE ) { // Translate the index to the true object type asPWORD *pot = (asPWORD*)&bc[n+1]; - *(asCObjectType**)pot = FindObjectType(*(int*)pot); + *(asCObjectType**)pot = CastToObjectType(FindType(int(*pot))); asCObjectType *ot = *(asCObjectType**)pot; if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) @@ -2722,17 +2976,14 @@ void asCReader::TranslateFunction(asCScriptFunction *func) // objVariablePos for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ ) - { func->scriptData->objVariablePos[n] = AdjustStackPosition(func->scriptData->objVariablePos[n]); - func->scriptData->funcVariableTypes[n] = FindFunction((int)(asPWORD)func->scriptData->funcVariableTypes[n]); - } // Adjust the get offsets. This must be done in the second iteration because - // it relies on the function ids and variable position already being correct in the + // it relies on the function ids and variable position already being correct in the // bytecodes that come after the GET instructions. // TODO: optimize: Instead of doing a full extra loop. We can push the GET instructions // on a stack, and then when a call instruction is found update all of them. - // This will also make the AdjustGetOffset() function quicker as it can + // This will also make the AdjustGetOffset() function quicker as it can // receive the called function directly instead of having to search for it. bc = func->scriptData->byteCode.AddressOf(); for( n = 0; n < bcLength; ) @@ -2741,7 +2992,8 @@ void asCReader::TranslateFunction(asCScriptFunction *func) if( c == asBC_GETREF || c == asBC_GETOBJ || - c == asBC_GETOBJREF ) + c == asBC_GETOBJREF || + c == asBC_ChkNullS ) { asBC_WORDARG0(&bc[n]) = (asWORD)AdjustGetOffset(asBC_WORDARG0(&bc[n]), func, n); } @@ -2757,7 +3009,7 @@ void asCReader::TranslateFunction(asCScriptFunction *func) } // The program position (every even number) needs to be adjusted - // for the line numbers to be in number of dwords instead of number of instructions + // for the line numbers to be in number of dwords instead of number of instructions for( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 ) func->scriptData->lineNumbers[n] = instructionNbrToPos[func->scriptData->lineNumbers[n]]; for( n = 0; n < func->scriptData->sectionIdxs.GetLength(); n += 2 ) @@ -2766,7 +3018,7 @@ void asCReader::TranslateFunction(asCScriptFunction *func) CalculateStackNeeded(func); } -asCReader::SListAdjuster::SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *listType) : +asCReader::SListAdjuster::SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *listType) : reader(rd), allocMemBC(bc), maxOffset(0), patternType(listType), repeatCount(0), lastOffset(-1), nextOffset(0), nextTypeId(-1) { asASSERT( patternType && (patternType->flags & asOBJ_LIST_PATTERN) ); @@ -2817,12 +3069,12 @@ int asCReader::SListAdjuster::AdjustOffset(int offset) if( repeatCount > 0 ) repeatCount--; - asCDataType dt = patternType->engine->GetDataTypeFromTypeId(nextTypeId); + asCDataType nextdt = patternType->engine->GetDataTypeFromTypeId(nextTypeId); asUINT size; - if( dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_REF)) ) + if(nextdt.IsObjectHandle() || (nextdt.GetTypeInfo() && (nextdt.GetTypeInfo()->flags & asOBJ_REF)) ) size = AS_PTR_SIZE*4; else - size = dt.GetSizeInMemoryBytes(); + size = nextdt.GetSizeInMemoryBytes(); // Align the offset to 4 bytes boundary if( size >= 4 && (maxOffset & 0x3) ) @@ -2860,8 +3112,7 @@ int asCReader::SListAdjuster::AdjustOffset(int offset) { // Determine the size of the element asUINT size; - asCDataType dt = reinterpret_cast(patternNode)->dataType; - if( dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_REF)) ) + if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) ) size = AS_PTR_SIZE*4; else size = dt.GetSizeInMemoryBytes(); @@ -2964,7 +3215,7 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func) stackSize.SetLength(func->scriptData->byteCode.GetLength()); memset(&stackSize[0], -1, stackSize.GetLength()*4); - // Add the first instruction to the list of unchecked code + // Add the first instruction to the list of unchecked code // paths and set the stack size at that instruction to variableSpace asCArray paths; paths.PushLast(0); @@ -2975,7 +3226,7 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func) { asUINT pos = paths[p]; int currStackSize = stackSize[pos]; - + asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[pos]; if( bc == asBC_RET ) continue; @@ -3010,7 +3261,7 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func) } } } - + currStackSize += stackInc; asASSERT( currStackSize >= 0 ); @@ -3040,7 +3291,7 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func) { // Find the label that is being jumped to int offset = asBC_INTARG(&func->scriptData->byteCode[pos]); - + // Add both paths to the code paths pos += 2; if( stackSize[pos] == -1 ) @@ -3065,7 +3316,7 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func) else if( bc == asBC_JMPP ) { pos++; - + // Add all subsequent JMP instructions to the path while( *(asBYTE*)&func->scriptData->byteCode[pos] == asBC_JMP ) { @@ -3077,8 +3328,8 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func) else asASSERT(stackSize[pos] == currStackSize); pos += 2; - } - continue; + } + continue; } else { @@ -3101,7 +3352,7 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func) void asCReader::CalculateAdjustmentByPos(asCScriptFunction *func) { - // Adjust the offset of all negative variables (parameters) as + // Adjust the offset of all negative variables (parameters) as // all pointers have been stored as having a size of 1 dword asUINT n; asCArray adjustments; @@ -3146,35 +3397,35 @@ void asCReader::CalculateAdjustmentByPos(asCScriptFunction *func) adjustNegativeStackByPos[i] += adjust; } - // The bytecode has been stored as if all object variables take up only 1 dword. + // The bytecode has been stored as if all object variables take up only 1 dword. // It is necessary to adjust to the size according to the current platform. adjustments.SetLength(0); int highestPos = 0; for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ ) { - if( func->scriptData->objVariableTypes[n] ) + // Determine the size the variable currently occupies on the stack + int size = AS_PTR_SIZE; + + // objVariableTypes is null if the type is a null pointer + if( func->scriptData->objVariableTypes[n] && + (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && + n >= func->scriptData->objVariablesOnHeap ) { - // Determine the size the variable currently occupies on the stack - int size = AS_PTR_SIZE; - if( (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && - n >= func->scriptData->objVariablesOnHeap ) - { - size = func->scriptData->objVariableTypes[n]->GetSize(); - if( size < 4 ) - size = 1; - else - size /= 4; - } + size = func->scriptData->objVariableTypes[n]->GetSize(); + if( size < 4 ) + size = 1; + else + size /= 4; + } - // Check if type has a different size than stored - if( size > 1 ) - { - if( func->scriptData->objVariablePos[n] > highestPos ) - highestPos = func->scriptData->objVariablePos[n]; + // Check if type has a different size than stored + if( size > 1 ) + { + if( func->scriptData->objVariablePos[n] > highestPos ) + highestPos = func->scriptData->objVariablePos[n]; - adjustments.PushLast(func->scriptData->objVariablePos[n]); - adjustments.PushLast(size-1); - } + adjustments.PushLast(func->scriptData->objVariablePos[n]); + adjustments.PushLast(size-1); } } @@ -3201,7 +3452,7 @@ int asCReader::AdjustStackPosition(int pos) if( adjustByPos.GetLength() ) pos += (short)adjustByPos[adjustByPos.GetLength()-1]; } - else if( pos >= 0 ) + else if( pos >= 0 ) pos += (short)adjustByPos[pos]; else if( -pos >= (int)adjustNegativeStackByPos.GetLength() ) Error(TXT_INVALID_BYTECODE_d); @@ -3244,7 +3495,7 @@ asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD // Find the funcdef from the local variable for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) if( func->scriptData->objVariablePos[v] == var ) - return func->scriptData->funcVariableTypes[v]; + return CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef; // Look in parameters int paramPos = 0; @@ -3254,8 +3505,16 @@ asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD paramPos -= AS_PTR_SIZE; for( v = 0; v < func->parameterTypes.GetLength(); v++ ) { - if( var == paramPos ) - return func->parameterTypes[v].GetFuncDef(); + if (var == paramPos) + { + if (func->parameterTypes[v].IsFuncdef()) + return CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef; + else + { + error = true; + return 0; + } + } paramPos -= func->parameterTypes[v].GetSizeOnStackDWords(); } } @@ -3271,6 +3530,8 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog // Get offset 0 doesn't need adjustment if( offset == 0 ) return 0; + bool bcAlloc = false; + // Find out which function that will be called asCScriptFunction *calledFunc = 0; int stackDelta = 0; @@ -3280,11 +3541,16 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog if( bc == asBC_CALL || bc == asBC_CALLSYS || bc == asBC_Thiscall1 || - bc == asBC_CALLINTF || + bc == asBC_CALLINTF || bc == asBC_ALLOC || bc == asBC_CALLBND || bc == asBC_CallPtr ) { + // The alloc instruction allocates the object memory + // so it doesn't take the this pointer as input + if (bc == asBC_ALLOC) + bcAlloc = true; + calledFunc = GetCalledFunction(func, n); break; } @@ -3296,7 +3562,7 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog return offset - (1 - AS_PTR_SIZE); } - // Keep track of the stack size between the + // Keep track of the stack size between the // instruction that needs to be adjusted and the call stackDelta += asBCInfo[bc].stackInc; @@ -3309,17 +3575,17 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog return offset; } - // Count the number of pointers pushed on the stack above the + // Count the number of pointers pushed on the stack above the // current offset, and then adjust the offset accordingly asUINT numPtrs = 0; int currOffset = -stackDelta; - if( offset > currOffset && calledFunc->GetObjectType() ) + if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc ) { currOffset++; if( currOffset > 0 ) numPtrs++; #if AS_PTR_SIZE == 2 - // For 64bit platforms it is necessary to increment the currOffset by one more + // For 64bit platforms it is necessary to increment the currOffset by one more // DWORD since the stackDelta was counting the full 64bit size of the pointer else if( stackDelta ) currOffset++; @@ -3331,7 +3597,7 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog if( currOffset > 0 ) numPtrs++; #if AS_PTR_SIZE == 2 - // For 64bit platforms it is necessary to increment the currOffset by one more + // For 64bit platforms it is necessary to increment the currOffset by one more // DWORD since the stackDelta was counting the full 64bit size of the pointer else if( stackDelta ) currOffset++; @@ -3348,7 +3614,7 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog if( currOffset > 0 ) numPtrs++; #if AS_PTR_SIZE == 2 - // For 64bit platforms it is necessary to increment the currOffset by one more + // For 64bit platforms it is necessary to increment the currOffset by one more // DWORD since the stackDelta was counting the full 64bit size of the pointer else if( stackDelta ) currOffset++; @@ -3380,7 +3646,7 @@ int asCReader::FindTypeId(int idx) } } -asCObjectType *asCReader::FindObjectType(int idx) +asCTypeInfo *asCReader::FindType(int idx) { if( idx < 0 || idx >= (int)usedTypes.GetLength() ) { @@ -3394,23 +3660,42 @@ asCObjectType *asCReader::FindObjectType(int idx) #ifndef AS_NO_COMPILER asCWriter::asCWriter(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine, bool _stripDebug) - : module(_module), stream(_stream), engine(_engine), stripDebugInfo(_stripDebug) + : module(_module), stream(_stream), engine(_engine), stripDebugInfo(_stripDebug), error(false), bytesWritten(0) { } -void asCWriter::WriteData(const void *data, asUINT size) +int asCWriter::Error(const char *msg) +{ + // Don't write if it has already been reported an error earlier + if (!error) + { + asCString str; + str.Format(msg, bytesWritten); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + error = true; + } + + return asERROR; +} + +int asCWriter::WriteData(const void *data, asUINT size) { asASSERT(size == 1 || size == 2 || size == 4 || size == 8); + int ret = 0; #if defined(AS_BIG_ENDIAN) - for( asUINT n = 0; n < size; n++ ) - stream->Write(((asBYTE*)data)+n, 1); + for( asUINT n = 0; ret >= 0 && n < size; n++ ) + ret = stream->Write(((asBYTE*)data)+n, 1); #else - for( int n = size-1; n >= 0; n-- ) - stream->Write(((asBYTE*)data)+n, 1); + for( int n = size-1; ret >= 0 && n >= 0; n-- ) + ret = stream->Write(((asBYTE*)data)+n, 1); #endif + if (ret < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); + bytesWritten += size; + return ret; } -int asCWriter::Write() +int asCWriter::Write() { TimeIt("asCWriter::Write"); @@ -3421,7 +3706,9 @@ int asCWriter::Write() // TODO: Should be possible to skip saving the enum values. They are usually not needed after the script is compiled anyway // TODO: Should be possible to skip saving the typedefs. They are usually not needed after the script is compiled anyway // TODO: Should be possible to skip saving constants. They are usually not needed after the script is compiled anyway - WriteData(&stripDebugInfo, sizeof(stripDebugInfo)); + + // Write the flag as 1byte even on platforms with 4byte booleans + WriteEncodedInt64(stripDebugInfo ? 1 : 0); // Store enums { @@ -3431,8 +3718,8 @@ int asCWriter::Write() WriteEncodedInt64(count); for( i = 0; i < count; i++ ) { - WriteObjectTypeDeclaration(module->enumTypes[i], 1); - WriteObjectTypeDeclaration(module->enumTypes[i], 2); + WriteTypeDeclaration(module->enumTypes[i], 1); + WriteTypeDeclaration(module->enumTypes[i], 2); } } @@ -3445,7 +3732,7 @@ int asCWriter::Write() for( i = 0; i < count; i++ ) { // Store only the name of the class/interface types - WriteObjectTypeDeclaration(module->classTypes[i], 1); + WriteTypeDeclaration(module->classTypes[i], 1); } } @@ -3456,7 +3743,7 @@ int asCWriter::Write() count = (asUINT)module->funcDefs.GetLength(); WriteEncodedInt64(count); for( i = 0; i < count; i++ ) - WriteFunction(module->funcDefs[i]); + WriteFunction(module->funcDefs[i]->funcdef); } // Now store all interface methods @@ -3467,7 +3754,7 @@ int asCWriter::Write() for( i = 0; i < count; i++ ) { if( module->classTypes[i]->IsInterface() ) - WriteObjectTypeDeclaration(module->classTypes[i], 2); + WriteTypeDeclaration(module->classTypes[i], 2); } } @@ -3478,7 +3765,7 @@ int asCWriter::Write() for( i = 0; i < count; ++i ) { if( !module->classTypes[i]->IsInterface() ) - WriteObjectTypeDeclaration(module->classTypes[i], 2); + WriteTypeDeclaration(module->classTypes[i], 2); } } @@ -3489,7 +3776,7 @@ int asCWriter::Write() for( i = 0; i < count; ++i ) { if( !module->classTypes[i]->IsInterface() ) - WriteObjectTypeDeclaration(module->classTypes[i], 3); + WriteTypeDeclaration(module->classTypes[i], 3); } } @@ -3501,8 +3788,8 @@ int asCWriter::Write() WriteEncodedInt64(count); for( i = 0; i < count; i++ ) { - WriteObjectTypeDeclaration(module->typeDefs[i], 1); - WriteObjectTypeDeclaration(module->typeDefs[i], 2); + WriteTypeDeclaration(module->typeDefs[i], 1); + WriteTypeDeclaration(module->typeDefs[i], 2); } } @@ -3565,7 +3852,7 @@ int asCWriter::Write() count = (asUINT)usedTypes.GetLength(); WriteEncodedInt64(count); for( i = 0; i < count; ++i ) - WriteObjectType(usedTypes[i]); + WriteTypeInfo(usedTypes[i]); } // usedTypeIds[] @@ -3583,18 +3870,18 @@ int asCWriter::Write() // usedObjectProperties[] WriteUsedObjectProps(); - return asSUCCESS; + return error ? asERROR : asSUCCESS; } -int asCWriter::FindStringConstantIndex(int id) +int asCWriter::FindStringConstantIndex(void *str) { - asSMapNode *cursor = 0; - if (stringIdToIndexMap.MoveTo(&cursor, id)) + asSMapNode *cursor = 0; + if (stringToIndexMap.MoveTo(&cursor, str)) return cursor->value; - usedStringConstants.PushLast(id); + usedStringConstants.PushLast(str); int index = int(usedStringConstants.GetLength() - 1); - stringIdToIndexMap.Insert(id, index); + stringToIndexMap.Insert(str, index); return index; } @@ -3604,8 +3891,16 @@ void asCWriter::WriteUsedStringConstants() asUINT count = (asUINT)usedStringConstants.GetLength(); WriteEncodedInt64(count); - for( asUINT i = 0; i < count; ++i ) - WriteString(engine->stringConstants[usedStringConstants[i]]); + + asCString str; + for (asUINT i = 0; i < count; ++i) + { + asUINT length; + engine->stringFactory->GetRawStringData(usedStringConstants[i], 0, &length); + str.SetLength(length); + engine->stringFactory->GetRawStringData(usedStringConstants[i], str.AddressOf(), &length); + WriteString(&str); + } } void asCWriter::WriteUsedFunctions() @@ -3620,18 +3915,24 @@ void asCWriter::WriteUsedFunctions() char c; // Write enough data to be able to uniquely identify the function upon load - - if( usedFunctions[n] ) + asCScriptFunction *func = usedFunctions[n]; + if(func) { // Is the function from the module or the application? - c = usedFunctions[n]->module ? 'm' : 'a'; + c = func->module ? 'm' : 'a'; + + // Functions and methods that are shared and not owned by the module can be + // stored as 's' to tell the reader that these are received from other modules. + if (c == 'm' && func->IsShared() && module->scriptFunctions.IndexOf(func) < 0 ) + c = 's'; + WriteData(&c, 1); - WriteFunctionSignature(usedFunctions[n]); + WriteFunctionSignature(func); } else { // null function pointer - c = 'n'; + c = 'n'; WriteData(&c, 1); } } @@ -3652,9 +3953,9 @@ void asCWriter::WriteFunctionSignature(asCScriptFunction *func) count = (asUINT)func->parameterTypes.GetLength(); WriteEncodedInt64(count); - for( i = 0; i < count; ++i ) + for( i = 0; i < count; ++i ) WriteDataType(&func->parameterTypes[i]); - + // Only write the inout flags if any of them are set count = 0; for( i = asUINT(func->inOutFlags.GetLength()); i > 0; i-- ) @@ -3679,23 +3980,41 @@ void asCWriter::WriteFunctionSignature(asCScriptFunction *func) if( func->defaultArgs[i] ) WriteString(func->defaultArgs[i]); - WriteObjectType(func->objectType); + WriteTypeInfo(func->objectType); if( func->objectType ) { asBYTE b = 0; - b += func->isReadOnly ? 1 : 0; - b += func->isPrivate ? 2 : 0; - b += func->isProtected ? 4 : 0; + b += func->IsReadOnly() ? 1 : 0; + b += func->IsPrivate() ? 2 : 0; + b += func->IsProtected() ? 4 : 0; WriteData(&b, 1); } else { - WriteString(&func->nameSpace->name); + if (func->funcType == asFUNC_FUNCDEF) + { + if (func->nameSpace) + { + // This funcdef was declared as global entity + asBYTE b = 'n'; + WriteData(&b, 1); + WriteString(&func->nameSpace->name); + } + else + { + // This funcdef was declared as class member + asBYTE b = 'o'; + WriteData(&b, 1); + WriteTypeInfo(func->funcdefType->parentClass); + } + } + else + WriteString(&func->nameSpace->name); } } -void asCWriter::WriteFunction(asCScriptFunction* func) +void asCWriter::WriteFunction(asCScriptFunction* func) { char c; @@ -3731,6 +4050,17 @@ void asCWriter::WriteFunction(asCScriptFunction* func) if( func->funcType == asFUNC_SCRIPT ) { + char bits = 0; + bits += func->IsShared() ? 1 : 0; + bits += func->dontCleanUpOnException ? 2 : 0; + if (module->externalFunctions.IndexOf(func) >= 0) + bits += 4; + WriteData(&bits, 1); + + // For external shared functions the rest is not needed + if (bits & 4) + return; + // Calculate the adjustment by position lookup table CalculateAdjustmentByPos(func); @@ -3743,9 +4073,7 @@ void asCWriter::WriteFunction(asCScriptFunction* func) WriteEncodedInt64(count); for( i = 0; i < count; ++i ) { - WriteObjectType(func->scriptData->objVariableTypes[i]); - // TODO: Only write this if the object type is the builtin function type - WriteEncodedInt64(FindFunctionIndex(func->scriptData->funcVariableTypes[i])); + WriteTypeInfo(func->scriptData->objVariableTypes[i]); WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i])); } if( count > 0 ) @@ -3787,7 +4115,7 @@ void asCWriter::WriteFunction(asCScriptFunction* func) WriteString(engine->scriptSectionNames[func->scriptData->sectionIdxs[i]]); else { - char c = 0; + c = 0; WriteData(&c, 1); } } @@ -3809,11 +4137,6 @@ void asCWriter::WriteFunction(asCScriptFunction* func) } } - char bits = 0; - bits += func->isShared ? 1 : 0; - bits += func->dontCleanUpOnException ? 2 : 0; - WriteData(&bits,1); - // Store script section name if( !stripDebugInfo ) { @@ -3821,7 +4144,7 @@ void asCWriter::WriteFunction(asCScriptFunction* func) WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]); else { - char c = 0; + c = 0; WriteData(&c, 1); } WriteEncodedInt64(func->scriptData->declaredAt); @@ -3830,7 +4153,7 @@ void asCWriter::WriteFunction(asCScriptFunction* func) // Store the parameter names if( !stripDebugInfo ) { - asUINT count = asUINT(func->parameterNames.GetLength()); + count = asUINT(func->parameterNames.GetLength()); WriteEncodedInt64(count); for( asUINT n = 0; n < count; n++ ) WriteString(&func->parameterNames[n]); @@ -3844,117 +4167,144 @@ void asCWriter::WriteFunction(asCScriptFunction* func) else if( func->funcType == asFUNC_FUNCDEF ) { char bits = 0; - bits += func->isShared ? 1 : 0; + bits += func->IsShared() ? 1 : 0; + if (module->externalTypes.IndexOf(func->funcdefType) >= 0) + bits += 2; WriteData(&bits,1); } } -void asCWriter::WriteObjectTypeDeclaration(asCObjectType *ot, int phase) +void asCWriter::WriteTypeDeclaration(asCTypeInfo *type, int phase) { if( phase == 1 ) { // name - WriteString(&ot->name); + WriteString(&type->name); // flags - WriteData(&ot->flags, 4); + WriteData(&type->flags, 4); // size - // TODO: Do we really need to store this? The reader should be able to + // TODO: Do we really need to store this? The reader should be able to // determine the correct size from the object type's flags - if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size > 0 ) + if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size > 0 ) { - // The size for script objects may vary from platform to platform so + // The size for script objects may vary from platform to platform so // only store 1 to diferentiate from interfaces that have size 0. - WriteEncodedInt64(1); + WriteEncodedInt64(1); } else { // Enums, typedefs, and interfaces have fixed sizes independently // of platform so it is safe to serialize the size directly. - WriteEncodedInt64(ot->size); + WriteEncodedInt64(type->size); } // namespace - WriteString(&ot->nameSpace->name); + WriteString(&type->nameSpace->name); + + // external shared flag + if ((type->flags & asOBJ_SHARED)) + { + char c = ' '; + if (module->externalTypes.IndexOf(type) >= 0) + c = 'e'; + WriteData(&c, 1); + } } else if( phase == 2 ) { - if( ot->flags & asOBJ_ENUM ) + // external shared types doesn't need to save this + if ((type->flags & asOBJ_SHARED) && module->externalTypes.IndexOf(type) >= 0) + return; + + if(type->flags & asOBJ_ENUM ) { // enumValues[] - int size = (int)ot->enumValues.GetLength(); + asCEnumType *t = CastToEnumType(type); + int size = (int)t->enumValues.GetLength(); WriteEncodedInt64(size); for( int n = 0; n < size; n++ ) { - WriteString(&ot->enumValues[n]->name); - WriteData(&ot->enumValues[n]->value, 4); + WriteString(&t->enumValues[n]->name); + WriteData(&t->enumValues[n]->value, 4); } } - else if( ot->flags & asOBJ_TYPEDEF ) + else if(type->flags & asOBJ_TYPEDEF ) { - eTokenType t = ot->templateSubTypes[0].GetTokenType(); + asCTypedefType *td = CastToTypedefType(type); + eTokenType t = td->aliasForType.GetTokenType(); WriteEncodedInt64(t); } else { - WriteObjectType(ot->derivedFrom); + asCObjectType *t = CastToObjectType(type); + WriteTypeInfo(t->derivedFrom); // interfaces[] / interfaceVFTOffsets[] // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those? - int size = (asUINT)ot->interfaces.GetLength(); + int size = (asUINT)t->interfaces.GetLength(); WriteEncodedInt64(size); asUINT n; - asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() ); - for( n = 0; n < ot->interfaces.GetLength(); n++ ) + asASSERT( t->interfaces.GetLength() == t->interfaceVFTOffsets.GetLength() ); + for( n = 0; n < t->interfaces.GetLength(); n++ ) { - WriteObjectType(ot->interfaces[n]); - WriteEncodedInt64(ot->interfaceVFTOffsets[n]); + WriteTypeInfo(t->interfaces[n]); + WriteEncodedInt64(t->interfaceVFTOffsets[n]); } // behaviours - // TODO: Default behaviours should just be stored as a indicator + // TODO: Default behaviours should just be stored as a indicator // to avoid storing the actual function object - if( !ot->IsInterface() && ot->flags != asOBJ_TYPEDEF && ot->flags != asOBJ_ENUM ) + if( !t->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM ) { - WriteFunction(engine->scriptFunctions[ot->beh.destruct]); - size = (int)ot->beh.constructors.GetLength(); + WriteFunction(engine->scriptFunctions[t->beh.destruct]); + size = (int)t->beh.constructors.GetLength(); WriteEncodedInt64(size); - for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) + for( n = 0; n < t->beh.constructors.GetLength(); n++ ) { - WriteFunction(engine->scriptFunctions[ot->beh.constructors[n]]); - WriteFunction(engine->scriptFunctions[ot->beh.factories[n]]); + WriteFunction(engine->scriptFunctions[t->beh.constructors[n]]); + WriteFunction(engine->scriptFunctions[t->beh.factories[n]]); } } // methods[] // TODO: Avoid storing inherited methods in interfaces, as the reader // can add those directly from the base interface - size = (int)ot->methods.GetLength(); + size = (int)t->methods.GetLength(); WriteEncodedInt64(size); - for( n = 0; n < ot->methods.GetLength(); n++ ) + for( n = 0; n < t->methods.GetLength(); n++ ) { - WriteFunction(engine->scriptFunctions[ot->methods[n]]); + WriteFunction(engine->scriptFunctions[t->methods[n]]); } // virtualFunctionTable[] // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader - size = (int)ot->virtualFunctionTable.GetLength(); + size = (int)t->virtualFunctionTable.GetLength(); WriteEncodedInt64(size); for( n = 0; n < (asUINT)size; n++ ) { - WriteFunction(ot->virtualFunctionTable[n]); + WriteFunction(t->virtualFunctionTable[n]); } } } else if( phase == 3 ) { + // external shared types doesn't need to save this + if ((type->flags & asOBJ_SHARED) && module->externalTypes.IndexOf(type) >= 0) + return; + // properties[] - asUINT size = (asUINT)ot->properties.GetLength(); + asCObjectType *t = CastToObjectType(type); + + // This is only done for object types + asASSERT(t); + + asUINT size = (asUINT)t->properties.GetLength(); WriteEncodedInt64(size); - for( asUINT n = 0; n < ot->properties.GetLength(); n++ ) + for (asUINT n = 0; n < t->properties.GetLength(); n++) { - WriteObjectProperty(ot->properties[n]); + WriteObjectProperty(t->properties[n]); } } } @@ -4014,7 +4364,7 @@ void asCWriter::WriteEncodedInt64(asINT64 i) b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); b = asBYTE(i & 0xFF); WriteData(&b, 1); } - else + else { b = asBYTE(0x7F + signBit); WriteData(&b, 1); b = asBYTE((i >> 56) & 0xFF); WriteData(&b, 1); @@ -4028,11 +4378,11 @@ void asCWriter::WriteEncodedInt64(asINT64 i) } } -void asCWriter::WriteString(asCString* str) +void asCWriter::WriteString(asCString* str) { // First check if the string hasn't been saved already - asSMapNode *cursor = 0; - if (stringToIdMap.MoveTo(&cursor, asCStringPointer(str))) + asSMapNode *cursor = 0; + if (stringToIdMap.MoveTo(&cursor, *str)) { // Save a reference to the existing string // The lowest bit is set to 1 to indicate a reference @@ -4048,16 +4398,17 @@ void asCWriter::WriteString(asCString* str) if( len > 0 ) { stream->Write(str->AddressOf(), (asUINT)len); + bytesWritten += len; savedStrings.PushLast(*str); - stringToIdMap.Insert(asCStringPointer(str), int(savedStrings.GetLength()) - 1); + stringToIdMap.Insert(*str, int(savedStrings.GetLength()) - 1); } } -void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop) +void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop) { - // TODO: We might be able to avoid storing the name and type of the global - // properties twice if we merge this with the WriteUsedGlobalProperties. + // TODO: We might be able to avoid storing the name and type of the global + // properties twice if we merge this with the WriteUsedGlobalProperties. WriteString(&prop->name); WriteString(&prop->nameSpace->name); WriteDataType(&prop->type); @@ -4066,7 +4417,7 @@ void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop) WriteFunction(prop->GetInitFunc()); } -void asCWriter::WriteObjectProperty(asCObjectProperty* prop) +void asCWriter::WriteObjectProperty(asCObjectProperty* prop) { WriteString(&prop->name); WriteDataType(&prop->type); @@ -4077,7 +4428,7 @@ void asCWriter::WriteObjectProperty(asCObjectProperty* prop) WriteEncodedInt64(flags); } -void asCWriter::WriteDataType(const asCDataType *dt) +void asCWriter::WriteDataType(const asCDataType *dt) { // First check if the datatype has already been saved for( asUINT n = 0; n < savedDataTypes.GetLength(); n++ ) @@ -4099,47 +4450,37 @@ void asCWriter::WriteDataType(const asCDataType *dt) int t = dt->GetTokenType(); WriteEncodedInt64(t); if( t == ttIdentifier ) - WriteObjectType(dt->GetObjectType()); + WriteTypeInfo(dt->GetTypeInfo()); - struct - { - char isObjectHandle :1; - char isHandleToConst:1; - char isReference :1; - char isReadOnly :1; - } bits = {0}; - - bits.isObjectHandle = dt->IsObjectHandle(); - bits.isHandleToConst = dt->IsHandleToConst(); - bits.isReference = dt->IsReference(); - bits.isReadOnly = dt->IsReadOnly(); + // Endianess safe bitmask + char bits = 0; + SAVE_TO_BIT(bits, dt->IsObjectHandle(), 0); + SAVE_TO_BIT(bits, dt->IsHandleToConst(), 1); + SAVE_TO_BIT(bits, dt->IsReference(), 2); + SAVE_TO_BIT(bits, dt->IsReadOnly(), 3); WriteData(&bits, 1); - - if( t == ttIdentifier && dt->GetObjectType()->name == "$func" ) - { - WriteFunctionSignature(dt->GetFuncDef()); - } } -void asCWriter::WriteObjectType(asCObjectType* ot) +void asCWriter::WriteTypeInfo(asCTypeInfo* ti) { char ch; - if( ot ) + if( ti ) { // Check for template instances/specializations - if( ot->templateSubTypes.GetLength() ) + asCObjectType *ot = CastToObjectType(ti); + if( ot && ot->templateSubTypes.GetLength() ) { // Check for list pattern type or template type if( ot->flags & asOBJ_LIST_PATTERN ) { - ch = 'l'; + ch = 'l'; // list WriteData(&ch, 1); - WriteObjectType(ot->templateSubTypes[0].GetObjectType()); + WriteTypeInfo(ot->templateSubTypes[0].GetTypeInfo()); } else { - ch = 'a'; + ch = 'a'; // array WriteData(&ch, 1); WriteString(&ot->name); WriteString(&ot->nameSpace->name); @@ -4147,15 +4488,15 @@ void asCWriter::WriteObjectType(asCObjectType* ot) WriteEncodedInt64(ot->templateSubTypes.GetLength()); for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) { - if( ot->templateSubTypes[n].IsObject() || ot->templateSubTypes[n].IsEnumType() ) + if( !ot->templateSubTypes[n].IsPrimitive() || ot->templateSubTypes[n].IsEnumType() ) { - ch = 's'; + ch = 's'; // sub type WriteData(&ch, 1); WriteDataType(&ot->templateSubTypes[n]); } else { - ch = 't'; + ch = 't'; // token WriteData(&ch, 1); eTokenType t = ot->templateSubTypes[n].GetTokenType(); WriteEncodedInt64(t); @@ -4163,18 +4504,27 @@ void asCWriter::WriteObjectType(asCObjectType* ot) } } } - else if( ot->flags & asOBJ_TEMPLATE_SUBTYPE ) + else if( ti->flags & asOBJ_TEMPLATE_SUBTYPE ) { - ch = 's'; + ch = 's'; // sub type WriteData(&ch, 1); - WriteString(&ot->name); + WriteString(&ti->name); + } + else if( !ti->GetParentType() ) + { + ch = 'o'; // object + WriteData(&ch, 1); + WriteString(&ti->name); + WriteString(&ti->nameSpace->name); } else { - ch = 'o'; + asASSERT(ti->flags & asOBJ_FUNCDEF); + + ch = 'c'; // child type WriteData(&ch, 1); - WriteString(&ot->name); - WriteString(&ot->nameSpace->name); + WriteString(&ti->name); + WriteTypeInfo(CastToFuncdefType(ti)->parentClass); } } else @@ -4235,27 +4585,27 @@ void asCWriter::CalculateAdjustmentByPos(asCScriptFunction *func) adjustments.SetLength(0); for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ ) { - if( func->scriptData->objVariableTypes[n] ) - { - // Determine the size the variable currently occupies on the stack - int size = AS_PTR_SIZE; - if( (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && - n >= func->scriptData->objVariablesOnHeap ) - { - size = func->scriptData->objVariableTypes[n]->GetSize(); - if( size < 4 ) - size = 1; - else - size /= 4; - } + // Determine the size the variable currently occupies on the stack + int size = AS_PTR_SIZE; - // If larger than 1 dword, adjust the offsets accordingly - if( size > 1 ) - { - // How much needs to be adjusted? - adjustments.PushLast(func->scriptData->objVariablePos[n]); - adjustments.PushLast(-(size-1)); - } + // objVariableTypes is null if the variable type is a null pointer + if( func->scriptData->objVariableTypes[n] && + (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && + n >= func->scriptData->objVariablesOnHeap ) + { + size = func->scriptData->objVariableTypes[n]->GetSize(); + if( size < 4 ) + size = 1; + else + size /= 4; + } + + // If larger than 1 dword, adjust the offsets accordingly + if (size > 1) + { + // How much needs to be adjusted? + adjustments.PushLast(func->scriptData->objVariablePos[n]); + adjustments.PushLast(-(size - 1)); } } @@ -4282,7 +4632,7 @@ void asCWriter::CalculateAdjustmentByPos(asCScriptFunction *func) offset += asBCTypeSize[asBCInfo[*(asBYTE*)(bc+offset)].type]; num++; } - // The last instruction is always a BC_RET. This make it possible to query + // The last instruction is always a BC_RET. This make it possible to query // the number of instructions by checking the last entry in bytecodeNbrByPos asASSERT(*(asBYTE*)(bc+length-1) == asBC_RET); } @@ -4315,6 +4665,8 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog // Get offset 0 doesn't need adjustment if( offset == 0 ) return 0; + bool bcAlloc = false; + // Find out which function that will be called asCScriptFunction *calledFunc = 0; int stackDelta = 0; @@ -4333,6 +4685,10 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog } else if( bc == asBC_ALLOC ) { + // The alloc instruction doesn't take the object pointer on the stack, + // as the memory will be allocated by the instruction itself + bcAlloc = true; + // Find the function from the function id in the bytecode int funcId = asBC_INTARG(&func->scriptData->byteCode[n+AS_PTR_SIZE]); calledFunc = engine->scriptFunctions[funcId]; @@ -4354,7 +4710,7 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog { if( func->scriptData->objVariablePos[v] == var ) { - calledFunc = func->scriptData->funcVariableTypes[v]; + calledFunc = CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef; break; } } @@ -4370,7 +4726,7 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog { if( var == paramPos ) { - calledFunc = func->parameterTypes[v].GetFuncDef(); + calledFunc = CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef; break; } paramPos -= func->parameterTypes[v].GetSizeOnStackDWords(); @@ -4386,7 +4742,7 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog return offset + (1 - AS_PTR_SIZE); } - // Keep track of the stack size between the + // Keep track of the stack size between the // instruction that needs to be adjusted and the call stackDelta += asBCInfo[bc].stackInc; @@ -4395,11 +4751,11 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog asASSERT( calledFunc ); - // Count the number of pointers pushed on the stack above the + // Count the number of pointers pushed on the stack above the // current offset, and then adjust the offset accordingly asUINT numPtrs = 0; int currOffset = -stackDelta; - if( offset > currOffset && calledFunc->GetObjectType() ) + if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc ) { currOffset += AS_PTR_SIZE; if( currOffset > 0 ) @@ -4437,7 +4793,7 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog // The get offset must match one of the parameter offsets asASSERT( offset == currOffset ); - + return offset + numPtrs * (1 - AS_PTR_SIZE); } @@ -4446,7 +4802,7 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) asDWORD *bc = func->scriptData->byteCode.AddressOf(); size_t length = func->scriptData->byteCode.GetLength(); - // The length cannot be stored, because it is platform dependent, + // The length cannot be stored, because it is platform dependent, // instead we store the number of instructions asUINT count = bytecodeNbrByPos[bytecodeNbrByPos.GetLength()-1] + 1; WriteEncodedInt64(count); @@ -4454,23 +4810,23 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) asDWORD *startBC = bc; while( length ) { - asDWORD tmp[4]; // The biggest instructions take up 4 DWORDs + asDWORD tmpBC[4]; // The biggest instructions take up 4 DWORDs asDWORD c = *(asBYTE*)bc; // Copy the instruction to a temp buffer so we can work on it before saving - memcpy(tmp, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD)); + memcpy(tmpBC, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD)); if( c == asBC_ALLOC ) // PTR_DW_ARG { - // Translate the object type - asCObjectType *ot = *(asCObjectType**)(tmp+1); - *(asPWORD*)(tmp+1) = FindObjectTypeIdx(ot); + // Translate the object type + asCObjectType *ot = *(asCObjectType**)(tmpBC+1); + *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot); // Translate the constructor func id, unless it is 0 - if( *(int*)&tmp[1+AS_PTR_SIZE] != 0 ) + if( *(int*)&tmpBC[1+AS_PTR_SIZE] != 0 ) { // Increment 1 to the translated function id, as 0 will be reserved for no function - *(int*)&tmp[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmp[1+AS_PTR_SIZE]]); + *(int*)&tmpBC[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmpBC[1+AS_PTR_SIZE]]); } } else if( c == asBC_REFCPY || // PTR_ARG @@ -4478,60 +4834,59 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) c == asBC_OBJTYPE ) // PTR_ARG { // Translate object type pointers into indices - *(asPWORD*)(tmp+1) = FindObjectTypeIdx(*(asCObjectType**)(tmp+1)); + *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(*(asCObjectType**)(tmpBC+1)); } else if( c == asBC_JitEntry ) // PTR_ARG { // We don't store the JIT argument - *(asPWORD*)(tmp+1) = 0; + *(asPWORD*)(tmpBC+1) = 0; } else if( c == asBC_TYPEID || // DW_ARG c == asBC_Cast ) // DW_ARG { // Translate type ids into indices - *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1)); + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); } else if( c == asBC_ADDSi || // W_DW_ARG c == asBC_LoadThisR ) // W_DW_ARG { // Translate property offsets into indices - *(((short*)tmp)+1) = (short)FindObjectPropIndex(*(((short*)tmp)+1), *(int*)(tmp+1)); + *(((short*)tmpBC)+1) = (short)FindObjectPropIndex(*(((short*)tmpBC)+1), *(int*)(tmpBC+1), bc); // Translate type ids into indices - *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1)); + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); } else if( c == asBC_LoadRObjR || // rW_W_DW_ARG c == asBC_LoadVObjR ) // rW_W_DW_ARG { - asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmp+2)); + asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmpBC+2)); if( ot->flags & asOBJ_LIST_PATTERN ) { // List patterns have a different way of translating the offsets SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - *(((short*)tmp)+2) = (short)listAdj->AdjustOffset(*(((short*)tmp)+2), ot); + *(((short*)tmpBC)+2) = (short)listAdj->AdjustOffset(*(((short*)tmpBC)+2), ot); } else { // Translate property offsets into indices - // TODO: optimize: Pass the object type directly to the method instead of the type id - *(((short*)tmp)+2) = (short)FindObjectPropIndex(*(((short*)tmp)+2), *(int*)(tmp+2)); + *(((short*)tmpBC)+2) = (short)FindObjectPropIndex(*(((short*)tmpBC)+2), *(int*)(tmpBC+2), bc); } // Translate type ids into indices - *(int*)(tmp+2) = FindTypeIdIdx(*(int*)(tmp+2)); + *(int*)(tmpBC+2) = FindTypeIdIdx(*(int*)(tmpBC+2)); } else if( c == asBC_COPY ) // W_DW_ARG { // Translate type ids into indices - *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1)); + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); // Update the WORDARG0 to 0, as this will be recalculated on the target platform - asBC_WORDARG0(tmp) = 0; + asBC_WORDARG0(tmpBC) = 0; } else if( c == asBC_RET ) // W_ARG { // Save with arg 0, as this will be recalculated on the target platform - asBC_WORDARG0(tmp) = 0; + asBC_WORDARG0(tmpBC) = 0; } else if( c == asBC_CALL || // DW_ARG c == asBC_CALLINTF || // DW_ARG @@ -4539,23 +4894,17 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) c == asBC_Thiscall1 ) // DW_ARG { // Translate the function id - *(int*)(tmp+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmp+1)]); + *(int*)(tmpBC+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmpBC+1)]); } else if( c == asBC_FuncPtr ) // PTR_ARG { // Translate the function pointer - *(asPWORD*)(tmp+1) = FindFunctionIndex(*(asCScriptFunction**)(tmp+1)); - } - else if( c == asBC_STR ) // W_ARG - { - // Translate the string constant id - asWORD *arg = ((asWORD*)tmp)+1; - *arg = (asWORD)FindStringConstantIndex(*arg); + *(asPWORD*)(tmpBC+1) = FindFunctionIndex(*(asCScriptFunction**)(tmpBC+1)); } else if( c == asBC_CALLBND ) // DW_ARG { // Translate the function id - int funcId = tmp[1]; + int funcId = tmpBC[1]; for( asUINT n = 0; n < module->bindInformations.GetLength(); n++ ) if( module->bindInformations[n]->importedFunctionSignature->id == funcId ) { @@ -4563,10 +4912,10 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) break; } - tmp[1] = funcId; + tmpBC[1] = funcId; } else if( c == asBC_PGA || // PTR_ARG - c == asBC_PshGPtr || // PTR_ARG + c == asBC_PshGPtr || // PTR_ARG c == asBC_LDG || // PTR_ARG c == asBC_PshG4 || // PTR_ARG c == asBC_LdGRdR4 || // wW_PTR_ARG @@ -4574,8 +4923,23 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) c == asBC_CpyVtoG4 || // rW_PTR_ARG c == asBC_SetG4 ) // PTR_DW_ARG { - // Translate global variable pointers into indices - *(asPWORD*)(tmp+1) = FindGlobalPropPtrIndex(*(void**)(tmp+1)); + // Check if the address is a global property or a string constant + void *ptr = *(void**)(tmpBC + 1); + if (engine->varAddressMap.MoveTo(0, ptr)) + { + // Translate global variable pointers into indices + // Flag the first bit to signal global property + *(asPWORD*)(tmpBC + 1) = (FindGlobalPropPtrIndex(*(void**)(tmpBC + 1)) << 1) + 1; + } + else + { + // Only PGA and PshGPtr can hold string constants + asASSERT(c == asBC_PGA || c == asBC_PshGPtr); + + // Translate string constants into indices + // Leave the first bit clear to signal string constant + *(asPWORD*)(tmpBC + 1) = FindStringConstantIndex(*(void**)(tmpBC + 1)) << 1; + } } else if( c == asBC_JMP || // DW_ARG c == asBC_JZ || @@ -4588,7 +4952,7 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) c == asBC_JNP ) // The JMPP instruction doesn't need modification { // Get the DWORD offset from arg - int offset = *(int*)(tmp+1); + int offset = *(int*)(tmpBC+1); // Determine instruction number for next instruction and destination int bcSeqNum = bytecodeNbrByPos[asUINT(bc - startBC)] + 1; @@ -4596,23 +4960,24 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) int targetBcSeqNum = bytecodeNbrByPos[asUINT(targetBC - startBC)]; // Set the offset in number of instructions - *(int*)(tmp+1) = targetBcSeqNum - bcSeqNum; + *(int*)(tmpBC+1) = targetBcSeqNum - bcSeqNum; } else if( c == asBC_GETOBJ || // W_ARG c == asBC_GETOBJREF || - c == asBC_GETREF ) + c == asBC_GETREF || + c == asBC_ChkNullS ) { // Adjust the offset according to the function call that comes after - asBC_WORDARG0(tmp) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmp), func, asDWORD(bc - startBC)); + asBC_WORDARG0(tmpBC) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmpBC), func, asDWORD(bc - startBC)); } else if( c == asBC_AllocMem ) { // It's not necessary to store the size of the list buffer, as it will be recalculated in the reader - asBC_DWORDARG(tmp) = 0; + asBC_DWORDARG(tmpBC) = 0; // Determine the type of the list pattern from the variable - short var = asBC_WORDARG0(tmp); - asCObjectType *ot = func->GetObjectTypeOfLocalVar(var); + short var = asBC_WORDARG0(tmpBC); + asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(var)); // Create this helper object to adjust the offset of the elements accessed in the buffer listAdjusters.PushLast(asNEW(SListAdjuster)(ot)); @@ -4620,8 +4985,8 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) else if( c == asBC_FREE ) // wW_PTR_ARG { // Translate object type pointers into indices - asCObjectType *ot = *(asCObjectType**)(tmp+1); - *(asPWORD*)(tmp+1) = FindObjectTypeIdx(ot); + asCObjectType *ot = *(asCObjectType**)(tmpBC+1); + *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot); // Pop and destroy the list adjuster helper that was created with asBC_AllocMem if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) @@ -4634,28 +4999,28 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) { // Adjust the offset in the initialization list SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType); + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); // Tell the adjuster how many repeated values there are - listAdj->SetRepeatCount(tmp[2]); + listAdj->SetRepeatCount(tmpBC[2]); } else if( c == asBC_PshListElmnt ) // W_DW_ARG { // Adjust the offset in the initialization list SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType); + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); } else if( c == asBC_SetListType ) { // Adjust the offset in the initialization list SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType); + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); // Inform the adjuster of the type id of the next element - listAdj->SetNextType(tmp[2]); + listAdj->SetNextType(tmpBC[2]); // Translate the type id - tmp[2] = FindTypeIdIdx(tmp[2]); + tmpBC[2] = FindTypeIdIdx(tmpBC[2]); } // Adjust the variable offsets switch( asBCInfo[c].type ) @@ -4670,7 +5035,7 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) case asBCTYPE_rW_W_DW_ARG: case asBCTYPE_rW_DW_DW_ARG: { - asBC_SWORDARG0(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp)); + asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); } break; @@ -4678,16 +5043,16 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) case asBCTYPE_wW_rW_DW_ARG: case asBCTYPE_rW_rW_ARG: { - asBC_SWORDARG0(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp)); - asBC_SWORDARG1(tmp) = (short)AdjustStackPosition(asBC_SWORDARG1(tmp)); + asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); + asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC)); } break; case asBCTYPE_wW_rW_rW_ARG: { - asBC_SWORDARG0(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp)); - asBC_SWORDARG1(tmp) = (short)AdjustStackPosition(asBC_SWORDARG1(tmp)); - asBC_SWORDARG2(tmp) = (short)AdjustStackPosition(asBC_SWORDARG2(tmp)); + asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); + asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC)); + asBC_SWORDARG2(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG2(tmpBC)); } break; @@ -4696,9 +5061,9 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) break; } - // TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform. + // TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform. // Some platforms may not use the IEEE 754 standard, in which case it is necessary to encode the values - + // Now store the instruction in the smallest possible way switch( asBCInfo[c].type ) { @@ -4716,9 +5081,9 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) // Write the instruction code asBYTE b = (asBYTE)c; WriteData(&b, 1); - + // Write the argument - short w = *(((short*)tmp)+1); + short w = *(((short*)tmpBC)+1); WriteEncodedInt64(w); } break; @@ -4731,11 +5096,11 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the word argument - short w = *(((short*)tmp)+1); + short w = *(((short*)tmpBC)+1); WriteEncodedInt64(w); // Write the dword argument - WriteEncodedInt64((int)tmp[1]); + WriteEncodedInt64((int)tmpBC[1]); } break; case asBCTYPE_DW_ARG: @@ -4745,7 +5110,7 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the argument - WriteEncodedInt64((int)tmp[1]); + WriteEncodedInt64((int)tmpBC[1]); } break; case asBCTYPE_DW_DW_ARG: @@ -4755,10 +5120,10 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the dword argument - WriteEncodedInt64((int)tmp[1]); + WriteEncodedInt64((int)tmpBC[1]); // Write the dword argument - WriteEncodedInt64((int)tmp[2]); + WriteEncodedInt64((int)tmpBC[2]); } break; case asBCTYPE_wW_rW_rW_ARG: @@ -4768,15 +5133,15 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the first argument - short w = *(((short*)tmp)+1); + short w = *(((short*)tmpBC)+1); WriteEncodedInt64(w); // Write the second argument - w = *(((short*)tmp)+2); + w = *(((short*)tmpBC)+2); WriteEncodedInt64(w); // Write the third argument - w = *(((short*)tmp)+3); + w = *(((short*)tmpBC)+3); WriteEncodedInt64(w); } break; @@ -4789,11 +5154,11 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the first argument - short w = *(((short*)tmp)+1); + short w = *(((short*)tmpBC)+1); WriteEncodedInt64(w); // Write the second argument - w = *(((short*)tmp)+2); + w = *(((short*)tmpBC)+2); WriteEncodedInt64(w); } break; @@ -4805,15 +5170,15 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the first argument - short w = *(((short*)tmp)+1); + short w = *(((short*)tmpBC)+1); WriteEncodedInt64(w); // Write the second argument - w = *(((short*)tmp)+2); + w = *(((short*)tmpBC)+2); WriteEncodedInt64(w); // Write the third argument - int dw = tmp[2]; + int dw = tmpBC[2]; WriteEncodedInt64(dw); } break; @@ -4824,7 +5189,7 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the argument - asQWORD qw = *(asQWORD*)&tmp[1]; + asQWORD qw = *(asQWORD*)&tmpBC[1]; WriteEncodedInt64(qw); } break; @@ -4835,11 +5200,11 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the argument - asQWORD qw = *(asQWORD*)&tmp[1]; + asQWORD qw = *(asQWORD*)&tmpBC[1]; WriteEncodedInt64(qw); // Write the second argument - int dw = tmp[3]; + int dw = tmpBC[3]; WriteEncodedInt64(dw); } break; @@ -4851,11 +5216,11 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the first argument - short w = *(((short*)tmp)+1); + short w = *(((short*)tmpBC)+1); WriteEncodedInt64(w); // Write the argument - asQWORD qw = *(asQWORD*)&tmp[1]; + asQWORD qw = *(asQWORD*)&tmpBC[1]; WriteEncodedInt64(qw); } break; @@ -4866,14 +5231,14 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) WriteData(&b, 1); // Write the short argument - short w = *(((short*)tmp)+1); + short w = *(((short*)tmpBC)+1); WriteEncodedInt64(w); // Write the dword argument - WriteEncodedInt64((int)tmp[1]); + WriteEncodedInt64((int)tmpBC[1]); // Write the dword argument - WriteEncodedInt64((int)tmp[2]); + WriteEncodedInt64((int)tmpBC[2]); } break; default: @@ -4883,7 +5248,7 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) // Store the bc as is for( int n = 0; n < asBCTypeSize[asBCInfo[c].type]; n++ ) - WriteData(&tmp[n], 4); + WriteData(&tmpBC[n], 4); } } @@ -4894,8 +5259,8 @@ void asCWriter::WriteByteCode(asCScriptFunction *func) } asCWriter::SListAdjuster::SListAdjuster(asCObjectType *ot) : patternType(ot), repeatCount(0), entries(0), lastOffset(-1), nextOffset(0), nextTypeId(-1) -{ - asASSERT( ot && (ot->flags & asOBJ_LIST_PATTERN) ); +{ + asASSERT( ot && (ot->flags & asOBJ_LIST_PATTERN) ); // Find the first expected value in the list asSListPatternNode *node = ot->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; @@ -4908,7 +5273,7 @@ int asCWriter::SListAdjuster::AdjustOffset(int offset, asCObjectType *listPatter // TODO: cleanup: The listPatternType parameter is not needed asASSERT( patternType == listPatternType ); UNUSED_VAR(listPatternType); - + asASSERT( offset >= lastOffset ); // If it is the same offset being accessed again, just return the same adjusted value @@ -4932,8 +5297,8 @@ int asCWriter::SListAdjuster::AdjustOffset(int offset, asCObjectType *listPatter const asCDataType &dt = reinterpret_cast(patternNode)->dataType; if( dt.GetTokenType() == ttQuestion ) { - // The bytecode need to inform the type that will - // come next and then adjust that position too before + // The bytecode need to inform the type that will + // come next and then adjust that position too before // we can move to the next node if( nextTypeId != -1 ) { @@ -4949,13 +5314,13 @@ int asCWriter::SListAdjuster::AdjustOffset(int offset, asCObjectType *listPatter nextTypeId = -1; } } - else + else { if( repeatCount > 0 ) { // Was any value skipped? asUINT size; - if( dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_REF)) ) + if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) ) size = AS_PTR_SIZE*4; else size = dt.GetSizeInMemoryBytes(); @@ -5037,10 +5402,10 @@ void asCWriter::SListAdjuster::SetRepeatCount(asUINT rc) void asCWriter::SListAdjuster::SetNextType(int typeId) { // Make sure the list is expecting a type at this location - asASSERT( patternNode->type == asLPT_TYPE && + asASSERT( patternNode->type == asLPT_TYPE && reinterpret_cast(patternNode)->dataType.GetTokenType() == ttQuestion ); - // Inform the type id for the next adjustment + // Inform the type id for the next adjustment nextTypeId = typeId; } @@ -5069,14 +5434,14 @@ int asCWriter::FindGlobalPropPtrIndex(void *ptr) void asCWriter::WriteUsedGlobalProps() { TimeIt("asCWriter::WriteUsedGlobalProps"); - + int c = (int)usedGlobalProperties.GetLength(); WriteEncodedInt64(c); for( int n = 0; n < c; n++ ) { asPWORD *p = (asPWORD*)usedGlobalProperties[n]; - + // Find the property descriptor from the address asCGlobalProperty *prop = 0; asSMapNode *cursor; @@ -5109,32 +5474,86 @@ void asCWriter::WriteUsedObjectProps() for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) { - asCObjectType *objType = usedObjectProperties[n].objType; - WriteObjectType(objType); - - // Find the property name - for( asUINT p = 0; p < objType->properties.GetLength(); p++ ) - { - if( objType->properties[p]->byteOffset == usedObjectProperties[n].offset ) - { - WriteString(&objType->properties[p]->name); - break; - } - } + WriteTypeInfo(usedObjectProperties[n].objType); + WriteString(&usedObjectProperties[n].prop->name); } } -int asCWriter::FindObjectPropIndex(short offset, int typeId) +int asCWriter::FindObjectPropIndex(short offset, int typeId, asDWORD *bc) { + // If the last property was a composite property, then just return 0, because it won't be translated + static bool lastWasComposite = false; + if (lastWasComposite) + { + lastWasComposite = false; + return 0; + } + asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId); + asCObjectProperty *objProp = 0; + + // Look for composite properties first + for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++) + { + // TODO: Composite: Perhaps it would be better to add metadata to the bytecode instruction to give the exact property. + // That would also allow me to remove the typeId from the bytecode instruction itself + // Or perhaps a new bytecode instruction all together for accessing composite properties + // One that would do both offsets and indirection in a single go. + // TODO: Composite: Need to be able to handle instructions replaced in bytecode optimizations too + if (objType->properties[n]->compositeOffset == offset) + { + // This is a potential composite property. Need to check the following instructions to be sure + objProp = objType->properties[n]; + asDWORD *bcTemp = bc; + bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type]; + if (objProp->isCompositeIndirect) + { + // The next instruction would be a asBC_RDSPtr + if ((*(asBYTE*)bcTemp) != asBC_RDSPtr) + { + objProp = 0; + continue; + } + bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type]; + } + // The next instruction would be asBC_ADDSi + if ((*(asBYTE*)bcTemp) != asBC_ADDSi) + { + objProp = 0; + continue; + } + // Make sure the offset is the expected one + if (*(((short*)bcTemp) + 1) != objProp->byteOffset) + { + objProp = 0; + continue; + } + } + } + + // If none of the composite properties matched, then look for ordinary property + for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++) + { + if (objType->properties[n]->byteOffset == offset && !(objType->properties[n]->compositeOffset || objType->properties[n]->isCompositeIndirect)) + objProp = objType->properties[n]; + } + + asASSERT(objProp); + + // Remember if this is a composite property as the next call will then be for the same property + if (objProp->compositeOffset || objProp->isCompositeIndirect) + lastWasComposite = true; + + // Now check if the same property has already been accessed for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) { if( usedObjectProperties[n].objType == objType && - usedObjectProperties[n].offset == offset ) + usedObjectProperties[n].prop == objProp ) return n; } - SObjProp prop = {objType, offset}; + // Insert the new property + SObjProp prop = {objType, objProp}; usedObjectProperties.PushLast(prop); return (int)usedObjectProperties.GetLength() - 1; } @@ -5164,7 +5583,7 @@ int asCWriter::FindTypeIdIdx(int typeId) return (int)usedTypeIds.GetLength() - 1; } -int asCWriter::FindObjectTypeIdx(asCObjectType *obj) +int asCWriter::FindTypeInfoIdx(asCTypeInfo *obj) { asUINT n; for( n = 0; n < usedTypes.GetLength(); n++ ) diff --git a/lib/angelscript/source/as_restore.h b/lib/angelscript/source/as_restore.h index bfd2725bc..462c2ae5e 100644 --- a/lib/angelscript/source/as_restore.h +++ b/lib/angelscript/source/as_restore.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -64,15 +64,15 @@ protected: int ReadInner(); - void ReadData(void *data, asUINT size); + int ReadData(void *data, asUINT size); void ReadString(asCString *str); - asCScriptFunction *ReadFunction(bool &isNew, bool addToModule = true, bool addToEngine = true, bool addToGC = true); - void ReadFunctionSignature(asCScriptFunction *func); + asCScriptFunction *ReadFunction(bool &isNew, bool addToModule = true, bool addToEngine = true, bool addToGC = true, bool *isExternal = 0); + void ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass = 0); void ReadGlobalProperty(); void ReadObjectProperty(asCObjectType *ot); void ReadDataType(asCDataType *dt); - asCObjectType * ReadObjectType(); - void ReadObjectTypeDeclaration(asCObjectType *ot, int phase); + asCTypeInfo *ReadTypeInfo(); + void ReadTypeDeclaration(asCTypeInfo *ot, int phase, bool *isExternal = 0); void ReadByteCode(asCScriptFunction *func); asWORD ReadEncodedUInt16(); asUINT ReadEncodedUInt(); @@ -84,7 +84,7 @@ protected: void ReadUsedStringConstants(); void ReadUsedObjectProps(); - asCObjectType * FindObjectType(int idx); + asCTypeInfo * FindType(int idx); int FindTypeId(int idx); short FindObjectPropOffset(asWORD index); asCScriptFunction *FindFunction(int idx); @@ -99,10 +99,10 @@ protected: // Temporary storage for persisting variable data asCArray usedTypeIds; - asCArray usedTypes; + asCArray usedTypes; asCArray usedFunctions; asCArray usedGlobalProperties; - asCArray usedStringConstants; + asCArray usedStringConstants; asCArray savedFunctions; asCArray savedDataTypes; @@ -113,8 +113,8 @@ protected: struct SObjProp { - asCObjectType *objType; - int offset; + asCObjectType *objType; + asCObjectProperty *prop; }; asCArray usedObjectProperties; @@ -165,8 +165,12 @@ protected: asIBinaryStream *stream; asCScriptEngine *engine; bool stripDebugInfo; + bool error; + asUINT bytesWritten; - void WriteData(const void *data, asUINT size); + int Error(const char *msg); + + int WriteData(const void *data, asUINT size); void WriteString(asCString *str); void WriteFunction(asCScriptFunction *func); @@ -174,18 +178,18 @@ protected: void WriteGlobalProperty(asCGlobalProperty *prop); void WriteObjectProperty(asCObjectProperty *prop); void WriteDataType(const asCDataType *dt); - void WriteObjectType(asCObjectType *ot); - void WriteObjectTypeDeclaration(asCObjectType *ot, int phase); + void WriteTypeInfo(asCTypeInfo *ot); + void WriteTypeDeclaration(asCTypeInfo *ot, int phase); void WriteByteCode(asCScriptFunction *func); void WriteEncodedInt64(asINT64 i); // Helper functions for storing variable data - int FindObjectTypeIdx(asCObjectType*); + int FindTypeInfoIdx(asCTypeInfo *ti); int FindTypeIdIdx(int typeId); int FindFunctionIndex(asCScriptFunction *func); int FindGlobalPropPtrIndex(void *); - int FindStringConstantIndex(int id); - int FindObjectPropIndex(short offset, int typeId); + int FindStringConstantIndex(void *str); + int FindObjectPropIndex(short offset, int typeId, asDWORD *bc); void CalculateAdjustmentByPos(asCScriptFunction *func); int AdjustStackPosition(int pos); @@ -201,24 +205,24 @@ protected: // Temporary storage for persisting variable data asCArray usedTypeIds; - asCArray usedTypes; + asCArray usedTypes; asCArray usedFunctions; asCArray usedGlobalProperties; - asCArray usedStringConstants; - asCMap stringIdToIndexMap; + asCArray usedStringConstants; + asCMap stringToIndexMap; asCArray savedFunctions; asCArray savedDataTypes; asCArray savedStrings; - asCMap stringToIdMap; + asCMap stringToIdMap; asCArray adjustStackByPos; asCArray adjustNegativeStackByPos; asCArray bytecodeNbrByPos; struct SObjProp { - asCObjectType *objType; - int offset; + asCObjectType *objType; + asCObjectProperty *prop; }; asCArray usedObjectProperties; diff --git a/lib/angelscript/source/as_scriptcode.cpp b/lib/angelscript/source/as_scriptcode.cpp index ef576c64c..833b401b6 100644 --- a/lib/angelscript/source/as_scriptcode.cpp +++ b/lib/angelscript/source/as_scriptcode.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -58,41 +58,41 @@ asCScriptCode::~asCScriptCode() } } -int asCScriptCode::SetCode(const char *name, const char *code, bool makeCopy) +int asCScriptCode::SetCode(const char *in_name, const char *in_code, bool in_makeCopy) { - return SetCode(name, code, 0, makeCopy); + return SetCode(in_name, in_code, 0, in_makeCopy); } -int asCScriptCode::SetCode(const char *name, const char *code, size_t length, bool makeCopy) +int asCScriptCode::SetCode(const char *in_name, const char *in_code, size_t in_length, bool in_makeCopy) { - if( !code ) return asINVALID_ARG; - this->name = name ? name : ""; - if( !sharedCode && this->code ) - asDELETEARRAY(this->code); + if( !in_code) return asINVALID_ARG; + this->name = in_name ? in_name : ""; + if( !sharedCode && code ) + asDELETEARRAY(code); - if( length == 0 ) - length = strlen(code); - if( makeCopy ) + if( in_length == 0 ) + in_length = strlen(in_code); + if( in_makeCopy ) { - codeLength = length; + codeLength = in_length; sharedCode = false; - this->code = asNEWARRAY(char,length); - if( this->code == 0 ) + code = asNEWARRAY(char, in_length); + if( code == 0 ) return asOUT_OF_MEMORY; - memcpy((char*)this->code, code, length); + memcpy(code, in_code, in_length); } else { - codeLength = length; - this->code = const_cast(code); + codeLength = in_length; + code = const_cast(in_code); sharedCode = true; } // Find the positions of each line linePositions.PushLast(0); - for( size_t n = 0; n < length; n++ ) - if( code[n] == '\n' ) linePositions.PushLast(n+1); - linePositions.PushLast(length); + for( size_t n = 0; n < in_length; n++ ) + if( in_code[n] == '\n' ) linePositions.PushLast(n+1); + linePositions.PushLast(in_length); return asSUCCESS; } diff --git a/lib/angelscript/source/as_scriptengine.cpp b/lib/angelscript/source/as_scriptengine.cpp index ecc489840..3f8507a12 100644 --- a/lib/angelscript/source/as_scriptengine.cpp +++ b/lib/angelscript/source/as_scriptengine.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -401,6 +401,24 @@ int asCScriptEngine::SetEngineProperty(asEEngineProp property, asPWORD value) ep.privatePropAsProtected = value ? true : false; break; + case asEP_ALLOW_UNICODE_IDENTIFIERS: + ep.allowUnicodeIdentifiers = value ? true : false; + break; + + case asEP_HEREDOC_TRIM_MODE: + if (value <= 2) + ep.heredocTrimMode = (int)value; + else + return asINVALID_ARG; + break; + + case asEP_MAX_NESTED_CALLS: + if (value > 0xFFFFFFFF) + ep.maxNestedCalls = 0xFFFFFFFF; + else + ep.maxNestedCalls = (asUINT)value; + break; + default: return asINVALID_ARG; } @@ -485,6 +503,15 @@ asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const case asEP_PRIVATE_PROP_AS_PROTECTED: return ep.privatePropAsProtected; + case asEP_ALLOW_UNICODE_IDENTIFIERS: + return ep.allowUnicodeIdentifiers; + + case asEP_HEREDOC_TRIM_MODE: + return ep.heredocTrimMode; + + case asEP_MAX_NESTED_CALLS: + return ep.maxNestedCalls; + default: return 0; } @@ -499,7 +526,7 @@ asIScriptFunction *asCScriptEngine::CreateDelegate(asIScriptFunction *func, void return 0; // The function must be a class method - asIObjectType *type = func->GetObjectType(); + asITypeInfo *type = func->GetObjectType(); if( type == 0 ) return 0; @@ -547,6 +574,9 @@ asCScriptEngine::asCScriptEngine() ep.disableIntegerDivision = false; ep.disallowEmptyListElements = false; ep.privatePropAsProtected = false; + ep.allowUnicodeIdentifiers = false; + ep.heredocTrimMode = 1; // 0 = never trim, 1 = don't trim on single line, 2 = trim initial and final empty line + ep.maxNestedCalls = 100; } gc.engine = this; @@ -566,7 +596,7 @@ asCScriptEngine::asCScriptEngine() typeIdSeqNbr = 0; currentGroup = &defaultGroup; - defaultAccessMask = 1; + defaultAccessMask = 0xFFFFFFFF; // All bits set so that built-in functions/types will be available to all modules msgCallback = 0; jitCompiler = 0; @@ -612,7 +642,7 @@ asCScriptEngine::asCScriptEngine() void asCScriptEngine::DeleteDiscardedModules() { - // TODO: redesign: Prevent more than one thread from entering this function at the same time. + // TODO: redesign: Prevent more than one thread from entering this function at the same time. // If a thread is already doing the work for the clean-up the other thread should // simply return, as the first thread will continue. @@ -652,7 +682,6 @@ asCScriptEngine::~asCScriptEngine() { // TODO: clean-up: Clean up redundant code - asUINT n = 0; inDestructor = true; asASSERT(refCount.get() == 0); @@ -672,13 +701,13 @@ asCScriptEngine::~asCScriptEngine() } // Delete the functions for generated template types that may references object types - for( n = 0; n < templateInstanceTypes.GetLength(); n++ ) + for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ ) { asCObjectType *templateType = templateInstanceTypes[n]; if( templateInstanceTypes[n] ) templateType->DestroyInternal(); } - for( n = 0; n < listPatternTypes.GetLength(); n++ ) + for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) { asCObjectType *type = listPatternTypes[n]; if( type ) @@ -694,8 +723,7 @@ asCScriptEngine::~asCScriptEngine() if( refCount.get() > 0 ) WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN); - mapTypeIdToObjectType.EraseAll(); - mapTypeIdToFunction.EraseAll(); + mapTypeIdToTypeInfo.EraseAll(); // First remove what is not used, so that other groups can be deleted safely defaultGroup.RemoveConfiguration(this, true); @@ -713,7 +741,7 @@ asCScriptEngine::~asCScriptEngine() defaultGroup.RemoveConfiguration(this); // Any remaining objects in templateInstanceTypes is from generated template instances - for( n = 0; n < templateInstanceTypes.GetLength(); n++ ) + for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ ) { asCObjectType *templateType = templateInstanceTypes[n]; if( templateInstanceTypes[n] ) @@ -729,7 +757,7 @@ asCScriptEngine::~asCScriptEngine() } registeredGlobalProps.Clear(); - for( n = 0; n < templateSubTypes.GetLength(); n++ ) + for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ ) { if( templateSubTypes[n] ) { @@ -750,7 +778,7 @@ asCScriptEngine::~asCScriptEngine() scriptTypeBehaviours.ReleaseAllFunctions(); functionBehaviours.ReleaseAllFunctions(); - for( n = 0; n < scriptFunctions.GetLength(); n++ ) + for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ ) if( scriptFunctions[n] ) { scriptFunctions[n]->DestroyInternal(); @@ -766,7 +794,7 @@ asCScriptEngine::~asCScriptEngine() // Destroy the funcdefs // As funcdefs are shared between modules it shouldn't be a problem to keep the objects until the engine is released - for( n = 0; n < funcDefs.GetLength(); n++ ) + for( asUINT n = 0; n < funcDefs.GetLength(); n++ ) if( funcDefs[n] ) { funcDefs[n]->DestroyInternal(); @@ -785,19 +813,13 @@ asCScriptEngine::~asCScriptEngine() } } - // Free string constants - for( n = 0; n < stringConstants.GetLength(); n++ ) - asDELETE(stringConstants[n],asCString); - stringConstants.SetLength(0); - stringToIdMap.EraseAll(); - // Free the script section names - for( n = 0; n < scriptSectionNames.GetLength(); n++ ) + for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ ) asDELETE(scriptSectionNames[n],asCString); scriptSectionNames.SetLength(0); // Clean the user data - for( n = 0; n < userData.GetLength(); n += 2 ) + for( asUINT n = 0; n < userData.GetLength(); n += 2 ) { if( userData[n+1] ) { @@ -808,7 +830,7 @@ asCScriptEngine::~asCScriptEngine() } // Free namespaces - for( n = 0; n < nameSpaces.GetLength(); n++ ) + for( asUINT n = 0; n < nameSpaces.GetLength(); n++ ) asDELETE(nameSpaces[n], asSNameSpace); nameSpaces.SetLength(0); @@ -846,63 +868,63 @@ asIScriptContext *asCScriptEngine::RequestContext() } // internal -asCModule *asCScriptEngine::FindNewOwnerForSharedType(asCObjectType *type, asCModule *mod) +asCModule *asCScriptEngine::FindNewOwnerForSharedType(asCTypeInfo *in_type, asCModule *in_mod) { - asASSERT( type->IsShared() ); + asASSERT( in_type->IsShared() ); - if( type->module != mod ) - return type->module; + if( in_type->module != in_mod) + return in_type->module; for( asUINT n = 0; n < scriptModules.GetLength(); n++ ) { // TODO: optimize: If the modules already stored the shared types separately, this would be quicker int foundIdx = -1; asCModule *mod = scriptModules[n]; - if( mod == type->module ) continue; - if( type->flags & asOBJ_ENUM ) - foundIdx = mod->enumTypes.IndexOf(type); - else if( type->flags & asOBJ_TYPEDEF ) - foundIdx = mod->typeDefs.IndexOf(type); + if( mod == in_type->module ) continue; + if( in_type->flags & asOBJ_ENUM ) + foundIdx = mod->enumTypes.IndexOf(CastToEnumType(in_type)); + else if (in_type->flags & asOBJ_TYPEDEF) + foundIdx = mod->typeDefs.IndexOf(CastToTypedefType(in_type)); + else if (in_type->flags & asOBJ_FUNCDEF) + foundIdx = mod->funcDefs.IndexOf(CastToFuncdefType(in_type)); else - foundIdx = mod->classTypes.IndexOf(type); - + foundIdx = mod->classTypes.IndexOf(CastToObjectType(in_type)); + if( foundIdx >= 0 ) { - type->module = mod; + in_type->module = mod; break; } } - return type->module; + return in_type->module; } // internal -asCModule *asCScriptEngine::FindNewOwnerForSharedFunc(asCScriptFunction *func, asCModule *mod) +asCModule *asCScriptEngine::FindNewOwnerForSharedFunc(asCScriptFunction *in_func, asCModule *in_mod) { - asASSERT( func->IsShared() ); + asASSERT( in_func->IsShared() ); + asASSERT(!(in_func->funcType & asFUNC_FUNCDEF)); - if( func->module != mod ) - return func->module; + if( in_func->module != in_mod) + return in_func->module; for( asUINT n = 0; n < scriptModules.GetLength(); n++ ) { // TODO: optimize: If the modules already stored the shared types separately, this would be quicker int foundIdx = -1; asCModule *mod = scriptModules[n]; - if( mod == func->module ) continue; - if( func->funcType == asFUNC_FUNCDEF ) - foundIdx = mod->funcDefs.IndexOf(func); - else - foundIdx = mod->scriptFunctions.IndexOf(func); - + if( mod == in_func->module ) continue; + foundIdx = mod->scriptFunctions.IndexOf(in_func); + if( foundIdx >= 0 ) { - func->module = mod; + in_func->module = mod; break; } } - return func->module; + return in_func->module; } // interface @@ -1041,6 +1063,10 @@ int asCScriptEngine::SetDefaultNamespace(const char *nameSpace) if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) ) return ConfigError(asINVALID_DECLARATION, "SetDefaultNamespace", nameSpace, 0); + // Make sure parent namespaces are registred in case of nested namespaces + if (expectIdentifier) + AddNameSpace(ns.SubString(0, pos + len).AddressOf()); + expectIdentifier = !expectIdentifier; } @@ -1261,31 +1287,6 @@ asIScriptModule *asCScriptEngine::GetModuleByIndex(asUINT index) const return mod; } -// Internal -void asCScriptEngine::RemoveTypeAndRelatedFromList(asCMap &types, asCObjectType *ot) -{ - // Remove the type from the list - asSMapNode* node; - if( !types.MoveTo(&node, ot) ) - return; - - types.Erase(node); - - // If the type is an template type then remove all sub types as well - for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) - { - if( ot->templateSubTypes[n].GetObjectType() ) - RemoveTypeAndRelatedFromList(types, ot->templateSubTypes[n].GetObjectType()); - } - - // If the type is a class then remove all properties types as well - if( ot->properties.GetLength() ) - { - for( asUINT n = 0; n < ot->properties.GetLength(); n++ ) - RemoveTypeAndRelatedFromList(types, ot->properties[n]->type.GetObjectType()); - } -} - // internal int asCScriptEngine::GetFactoryIdByDecl(const asCObjectType *ot, const char *decl) { @@ -1405,7 +1406,7 @@ int asCScriptEngine::CreateContext(asIScriptContext **context, bool isInternal) } // interface -int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset) +int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset, bool isCompositeIndirect) { int r; asCDataType dt; @@ -1414,12 +1415,15 @@ int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declara if( r < 0 ) return ConfigError(r, "RegisterObjectProperty", obj, declaration); + if (dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE))) + return ConfigError(asINVALID_OBJECT, "RegisterObjectProperty", obj, declaration); + // Don't allow modifying generated template instances - if( dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(dt.GetObjectType()) ) + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) return ConfigError(asINVALID_TYPE, "RegisterObjectProperty", obj, declaration); // Verify that the correct config group is used - if( currentGroup->FindType(dt.GetObjectType()->name.AddressOf()) == 0 ) + if( currentGroup->FindType(dt.GetTypeInfo()->name.AddressOf()) == 0 ) return ConfigError(asWRONG_CONFIG_GROUP, "RegisterObjectProperty", obj, declaration); asCDataType type; @@ -1428,10 +1432,6 @@ int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declara if( (r = bld.VerifyProperty(&dt, declaration, name, type, 0)) < 0 ) return ConfigError(r, "RegisterObjectProperty", obj, declaration); - // Store the property info - if( dt.GetObjectType() == 0 || dt.IsObjectHandle() ) - return ConfigError(asINVALID_OBJECT, "RegisterObjectProperty", obj, declaration); - // The VM currently only supports 16bit offsets // TODO: The VM needs to have support for 32bit offsets. Probably with a second ADDSi instruction // However, when implementing this it is necessary for the bytecode serialization to support @@ -1439,31 +1439,36 @@ int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declara // same on all platforms if( byteOffset > 32767 || byteOffset < -32768 ) return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration); + // The composite offset must also obey the ADDSi restriction + if (compositeOffset > 32767 || compositeOffset < -32768) + return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration); asCObjectProperty *prop = asNEW(asCObjectProperty); if( prop == 0 ) return ConfigError(asOUT_OF_MEMORY, "RegisterObjectProperty", obj, declaration); - prop->name = name; - prop->type = type; - prop->byteOffset = byteOffset; - prop->isPrivate = false; - prop->isProtected = false; - prop->accessMask = defaultAccessMask; + prop->name = name; + prop->type = type; + prop->byteOffset = byteOffset; + prop->isPrivate = false; + prop->isProtected = false; + prop->compositeOffset = compositeOffset; + prop->isCompositeIndirect = isCompositeIndirect; + prop->accessMask = defaultAccessMask; - dt.GetObjectType()->properties.PushLast(prop); + CastToObjectType(dt.GetTypeInfo())->properties.PushLast(prop); // Add references to types so they are not released too early - if( type.GetObjectType() ) + if( type.GetTypeInfo() ) { - type.GetObjectType()->AddRefInternal(); + type.GetTypeInfo()->AddRefInternal(); // Add template instances to the config group - if( (type.GetObjectType()->flags & asOBJ_TEMPLATE) && !currentGroup->objTypes.Exists(type.GetObjectType()) ) - currentGroup->objTypes.PushLast(type.GetObjectType()); + if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && !currentGroup->types.Exists(type.GetTypeInfo()) ) + currentGroup->types.PushLast(type.GetTypeInfo()); } - currentGroup->AddReferencesForType(this, type.GetObjectType()); + currentGroup->AddReferencesForType(this, type.GetTypeInfo()); return asSUCCESS; } @@ -1474,7 +1479,7 @@ int asCScriptEngine::RegisterInterface(const char *name) if( name == 0 ) return ConfigError(asINVALID_NAME, "RegisterInterface", 0, 0); // Verify if the name has been registered as a type already - if( GetRegisteredObjectType(name, defaultNamespace) ) + if( GetRegisteredType(name, defaultNamespace) ) return asALREADY_REGISTERED; // Use builder to parse the datatype @@ -1487,7 +1492,7 @@ int asCScriptEngine::RegisterInterface(const char *name) { // If it is not in the defaultNamespace then the type was successfully parsed because // it is declared in a parent namespace which shouldn't be treated as an error - if( dt.GetObjectType() && dt.GetObjectType()->nameSpace == defaultNamespace ) + if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace ) return ConfigError(asERROR, "RegisterInterface", name, 0); } @@ -1525,9 +1530,9 @@ int asCScriptEngine::RegisterInterface(const char *name) allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); registeredObjTypes.PushLast(st); - currentGroup->objTypes.PushLast(st); + currentGroup->types.PushLast(st); - return asSUCCESS; + return GetTypeIdByDecl(name); } // interface @@ -1547,7 +1552,7 @@ int asCScriptEngine::RegisterInterfaceMethod(const char *intf, const char *decla if( func == 0 ) return ConfigError(asOUT_OF_MEMORY, "RegisterInterfaceMethod", intf, declaration); - func->objectType = dt.GetObjectType(); + func->objectType = CastToObjectType(dt.GetTypeInfo()); func->objectType->AddRefInternal(); r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, false); @@ -1559,7 +1564,7 @@ int asCScriptEngine::RegisterInterfaceMethod(const char *intf, const char *decla } // Check name conflicts - r = bld.CheckNameConflictMember(dt.GetObjectType(), func->name.AddressOf(), 0, 0, false); + r = bld.CheckNameConflictMember(dt.GetTypeInfo(), func->name.AddressOf(), 0, 0, false); if( r < 0 ) { func->funcType = asFUNC_DUMMY; @@ -1697,7 +1702,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD return ConfigError(r, "RegisterObjectType", name, 0); // Verify that the template name hasn't been registered as a type already - if( GetRegisteredObjectType(typeName, defaultNamespace) ) + if( GetRegisteredType(typeName, defaultNamespace) ) // This is not an irrepairable error, as it may just be that the same type is registered twice return asALREADY_REGISTERED; @@ -1717,14 +1722,14 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD // Store it in the object types allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); - currentGroup->objTypes.PushLast(type); + currentGroup->types.PushLast(type); registeredObjTypes.PushLast(type); registeredTemplateTypes.PushLast(type); // Define the template subtypes for( asUINT subTypeIdx = 0; subTypeIdx < subtypeNames.GetLength(); subTypeIdx++ ) { - asCObjectType *subtype = 0; + asCTypeInfo *subtype = 0; for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ ) { if( templateSubTypes[n]->name == subtypeNames[subTypeIdx] ) @@ -1736,19 +1741,16 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD if( subtype == 0 ) { // Create the new subtype if not already existing - subtype = asNEW(asCObjectType)(this); + subtype = asNEW(asCTypeInfo)(this); if( subtype == 0 ) return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); subtype->name = subtypeNames[subTypeIdx]; subtype->size = 0; -#ifdef WIP_16BYTE_ALIGN - type->alignment = 0; // template subtypes cannot be instantiated and don't need alignment -#endif subtype->flags = asOBJ_TEMPLATE_SUBTYPE; templateSubTypes.PushLast(subtype); } - type->templateSubTypes.PushLast(asCDataType::CreateObject(subtype, false)); + type->templateSubTypes.PushLast(asCDataType::CreateType(subtype, false)); subtype->AddRefInternal(); } } @@ -1757,7 +1759,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD typeName = name; // Verify if the name has been registered as a type already - if( GetRegisteredObjectType(typeName, defaultNamespace) ) + if( GetRegisteredType(typeName, defaultNamespace) ) // This is not an irrepairable error, as it may just be that the same type is registered twice return asALREADY_REGISTERED; @@ -1785,7 +1787,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD // If the builder fails or the namespace is different than the default // namespace, then the type name is new and it should be registered - if( r < 0 || dt.GetObjectType()->nameSpace != defaultNamespace ) + if( r < 0 || dt.GetTypeInfo()->nameSpace != defaultNamespace ) { // Make sure the name is not a reserved keyword size_t tokenLen; @@ -1793,7 +1795,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD if( token != ttIdentifier || typeName.GetLength() != tokenLen ) return ConfigError(asINVALID_NAME, "RegisterObjectType", name, 0); - int r = bld.CheckNameConflict(name, 0, 0, defaultNamespace); + r = bld.CheckNameConflict(name, 0, 0, defaultNamespace); if( r < 0 ) return ConfigError(asNAME_TAKEN, "RegisterObjectType", name, 0); @@ -1818,7 +1820,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); registeredObjTypes.PushLast(type); - currentGroup->objTypes.PushLast(type); + currentGroup->types.PushLast(type); } else { @@ -1836,7 +1838,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD return ConfigError(asINVALID_TYPE, "RegisterObjectType", name, 0); // Was the template instance type generated before? - if( generatedTemplateTypes.Exists(dt.GetObjectType()) && + if( generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) && generatedTemplateTypes[generatedTemplateTypes.GetLength()-1] == mostRecentTemplateInstanceType ) { asCString str; @@ -1847,12 +1849,12 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD // If this is not a generated template instance type, then it means it is an // already registered template specialization - if( !generatedTemplateTypes.Exists(dt.GetObjectType()) ) + if( !generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) return ConfigError(asALREADY_REGISTERED, "RegisterObjectType", name, 0); // TODO: Add this again. The type is used by the factory stubs so we need to discount that // Is the template instance type already being used? -// if( dt.GetObjectType()->GetRefCount() > 1 ) +// if( dt.GetTypeInfo()->GetRefCount() > 1 ) // return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0); // Put the data type in the list @@ -1860,13 +1862,13 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD if( type == 0 ) return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); - type->name = dt.GetObjectType()->name; + type->name = dt.GetTypeInfo()->name; // The namespace will be the same as the original template type - type->nameSpace = dt.GetObjectType()->nameSpace; + type->nameSpace = dt.GetTypeInfo()->nameSpace; type->templateSubTypes.PushLast(dt.GetSubType()); for( asUINT s = 0; s < type->templateSubTypes.GetLength(); s++ ) - if( type->templateSubTypes[s].GetObjectType() ) - type->templateSubTypes[s].GetObjectType()->AddRefInternal(); + if( type->templateSubTypes[s].GetTypeInfo() ) + type->templateSubTypes[s].GetTypeInfo()->AddRefInternal(); type->size = byteSize; #ifdef WIP_16BYTE_ALIGN // TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries @@ -1877,7 +1879,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD templateInstanceTypes.PushLast(type); - currentGroup->objTypes.PushLast(type); + currentGroup->types.PushLast(type); // Remove the template instance type, which will no longer be used. // It is possible that multiple template instances are generated if @@ -1895,7 +1897,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD } // interface -int asCScriptEngine::RegisterObjectBehaviour(const char *datatype, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) +int asCScriptEngine::RegisterObjectBehaviour(const char *datatype, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) { if( datatype == 0 ) return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", datatype, decl); @@ -1906,26 +1908,26 @@ int asCScriptEngine::RegisterObjectBehaviour(const char *datatype, asEBehaviours if( r < 0 ) return ConfigError(r, "RegisterObjectBehaviour", datatype, decl); - if( type.GetObjectType() == 0 || type.IsObjectHandle() ) + if( type.GetTypeInfo() == 0 || (type.IsObjectHandle() && !(type.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE)) ) return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); // Don't allow application to modify built-in types - if( type.GetObjectType() == &functionBehaviours || - type.GetObjectType() == &scriptTypeBehaviours ) + if( type.GetTypeInfo() == &functionBehaviours || + type.GetTypeInfo() == &scriptTypeBehaviours ) return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); if( type.IsReadOnly() || type.IsReference() ) return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); // Don't allow modifying generated template instances - if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(type.GetObjectType()) ) + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(type.GetTypeInfo())) ) return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); - return RegisterBehaviourToObjectType(type.GetObjectType(), behaviour, decl, funcPointer, callConv, objForThiscall); + return RegisterBehaviourToObjectType(CastToObjectType(type.GetTypeInfo()), behaviour, decl, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect); } // internal -int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) +int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) { #ifdef AS_MAX_PORTABILITY if( callConv != asCALL_GENERIC ) @@ -1936,10 +1938,15 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as bool isMethod = !(behaviour == asBEHAVE_FACTORY || behaviour == asBEHAVE_LIST_FACTORY || behaviour == asBEHAVE_TEMPLATE_CALLBACK); - int r = DetectCallingConvention(isMethod, funcPointer, callConv, objForThiscall, &internal); + int r = DetectCallingConvention(isMethod, funcPointer, callConv, auxiliary, &internal); if( r < 0 ) return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + internal.compositeOffset = compositeOffset; + internal.isCompositeIndirect = isCompositeIndirect; + if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL ) + return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType // If the object type is a template, make sure there are no generated instances already if( objectType->flags & asOBJ_TEMPLATE ) @@ -1949,10 +1956,10 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as asCObjectType *tmpl = generatedTemplateTypes[n]; if( tmpl->name == objectType->name && tmpl->nameSpace == objectType->nameSpace && - !(tmpl->templateSubTypes[0].GetObjectType() && (tmpl->templateSubTypes[0].GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) + !(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) { asCString msg; - msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateObject(tmpl, false).Format(tmpl->nameSpace).AddressOf()); + msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf()); WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf()); return ConfigError(asERROR, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); } @@ -1984,40 +1991,12 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as func.objectType->AddRefInternal(); } - // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType // Check if the method restricts that use of the template to value types or reference types if( objectType->flags & asOBJ_TEMPLATE ) { - for( asUINT subTypeIdx = 0; subTypeIdx < objectType->templateSubTypes.GetLength(); subTypeIdx++ ) - { - if( func.returnType.GetObjectType() == objectType->templateSubTypes[subTypeIdx].GetObjectType() ) - { - if( func.returnType.IsObjectHandle() ) - objectType->acceptValueSubType = false; - else if( !func.returnType.IsReference() ) - objectType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if( !func.returnType.IsObjectHandle() && !func.returnType.IsReference() ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), decl); - } - - for( asUINT n = 0; n < func.parameterTypes.GetLength(); n++ ) - { - if( func.parameterTypes[n].GetObjectType() == objectType->templateSubTypes[subTypeIdx].GetObjectType() ) - { - // TODO: If unsafe references are allowed, then inout references allow value types - if( func.parameterTypes[n].IsObjectHandle() || (func.parameterTypes[n].IsReference() && func.inOutFlags[n] == asTM_INOUTREF) ) - objectType->acceptValueSubType = false; - else if( !func.parameterTypes[n].IsReference() ) - objectType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if( !func.parameterTypes[n].IsObjectHandle() && !func.parameterTypes[n].IsReference() ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), decl); - } - } - } + r = SetTemplateRestrictions(objectType, &func, "RegisterObjectBehaviour", decl); + if (r < 0) + return r; } if( behaviour == asBEHAVE_CONSTRUCT ) @@ -2074,7 +2053,7 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as // If the parameter is object, and const reference for input or inout, // and same type as this class, then this is a copy constructor. if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() && - (func.inOutFlags[0] & asTM_INREF) && paramType.GetObjectType() == objectType ) + (func.inOutFlags[0] & asTM_INREF) && paramType.GetTypeInfo() == objectType ) beh->copyconstruct = func.id; } } @@ -2148,7 +2127,7 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as beh->listFactory = func.id; // Store the list pattern for this function - int r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern); + r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern); if( listPattern ) listPattern->Destroy(this); @@ -2245,7 +2224,7 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as beh->listFactory = func.id; // Store the list pattern for this function - int r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern); + r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern); if( listPattern ) listPattern->Destroy(this); @@ -2260,7 +2239,7 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as // If the parameter is object, and const reference for input, // and same type as this class, then this is a copy constructor. - if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() && func.inOutFlags[func.parameterTypes.GetLength()-1] == asTM_INREF && paramType.GetObjectType() == objectType ) + if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() && func.inOutFlags[func.parameterTypes.GetLength()-1] == asTM_INREF && paramType.GetTypeInfo() == objectType ) beh->copyfactory = func.id; } } @@ -2389,58 +2368,6 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as else if( behaviour == asBEHAVE_RELEASEREFS ) func.id = beh->gcReleaseAllReferences = AddBehaviourFunction(func, internal); } -#ifdef AS_DEPRECATED - // Deprecated since 2.30.0. 2014-10-24 - else if( behaviour == asBEHAVE_IMPLICIT_VALUE_CAST || - behaviour == asBEHAVE_VALUE_CAST ) - { - // There are two allowed signatures - // 1. type f() - // 2. void f(?&out) - - if( !(func.parameterTypes.GetLength() == 1 && func.parameterTypes[0].GetTokenType() == ttQuestion && func.inOutFlags[0] == asTM_OUTREF && func.returnType.GetTokenType() == ttVoid) && - !(func.parameterTypes.GetLength() == 0 && func.returnType.GetTokenType() != ttVoid) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // It is not allowed to implement a value cast to bool - if( func.returnType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, false)) ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - asCString decl; - decl += func.returnType.Format(defaultNamespace); - decl += behaviour == asBEHAVE_VALUE_CAST ? " opConv(" : " opImplConv("; - if( func.parameterTypes.GetLength() ) - decl += "?&out"; - decl += ")"; - func.id = RegisterMethodToObjectType(objectType, decl.AddressOf(), funcPointer, callConv, objForThiscall); - } - // Deprecated since 2.30.0, 2014-12-30 - else if( behaviour == asBEHAVE_REF_CAST || - behaviour == asBEHAVE_IMPLICIT_REF_CAST ) - { - // There are two allowed signatures - // 1. obj @f() - // 2. void f(?&out) - - if( !(func.parameterTypes.GetLength() == 0 && func.returnType.IsObjectHandle()) && - !(func.parameterTypes.GetLength() == 1 && func.parameterTypes[0].GetTokenType() == ttQuestion && func.inOutFlags[0] == asTM_OUTREF && func.returnType.GetTokenType() == ttVoid) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Currently it is not supported to register const overloads for the ref cast behaviour - if( func.IsReadOnly() ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - asCString decl; - decl += func.returnType.Format(defaultNamespace); - if( internal.returnAutoHandle ) - decl += "+"; - decl += behaviour == asBEHAVE_REF_CAST ? " opCast(" : " opImplCast("; - if( func.parameterTypes.GetLength() ) - decl += "?&out"; - decl += ")"; - func.id = RegisterMethodToObjectType(objectType, decl.AddressOf(), funcPointer, callConv, objForThiscall); - } -#endif else if ( behaviour == asBEHAVE_GET_WEAKREF_FLAG ) { // This behaviour is only allowed for reference types @@ -2484,6 +2411,43 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as return func.id; } +int asCScriptEngine::SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl) +{ + asASSERT(templateType->flags & asOBJ_TEMPLATE); + + for (asUINT subTypeIdx = 0; subTypeIdx < templateType->templateSubTypes.GetLength(); subTypeIdx++) + { + if (func->returnType.GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo()) + { + if (func->returnType.IsObjectHandle()) + templateType->acceptValueSubType = false; + else if (!func->returnType.IsReference()) + templateType->acceptRefSubType = false; + + // Can't support template subtypes by value, since each type is treated differently in the ABI + if (!func->returnType.IsObjectHandle() && !func->returnType.IsReference()) + return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl); + } + + for (asUINT n = 0; n < func->parameterTypes.GetLength(); n++) + { + if (func->parameterTypes[n].GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo()) + { + // TODO: If unsafe references are allowed, then inout references allow value types + if (func->parameterTypes[n].IsObjectHandle() || (func->parameterTypes[n].IsReference() && func->inOutFlags[n] == asTM_INOUTREF)) + templateType->acceptValueSubType = false; + else if (!func->parameterTypes[n].IsReference()) + templateType->acceptRefSubType = false; + + // Can't support template subtypes by value, since each type is treated differently in the ABI + if (!func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference()) + return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl); + } + } + } + + return asSUCCESS; +} int asCScriptEngine::VerifyVarTypeNotInFunction(asCScriptFunction *func) { @@ -2523,9 +2487,10 @@ int asCScriptEngine::AddBehaviourFunction(asCScriptFunction &func, asSSystemFunc if( f->objectType ) f->objectType->AddRefInternal(); f->id = id; - f->isReadOnly = func.isReadOnly; + f->SetReadOnly(func.IsReadOnly()); f->accessMask = defaultAccessMask; f->parameterTypes = func.parameterTypes; + f->parameterNames = func.parameterNames; f->inOutFlags = func.inOutFlags; for( n = 0; n < func.defaultArgs.GetLength(); n++ ) if( func.defaultArgs[n] ) @@ -2574,7 +2539,7 @@ int asCScriptEngine::RegisterGlobalProperty(const char *declaration, void *point prop->AddRef(); currentGroup->globalProps.PushLast(prop); - currentGroup->AddReferencesForType(this, type.GetObjectType()); + currentGroup->AddReferencesForType(this, type.GetTypeInfo()); return asSUCCESS; } @@ -2663,7 +2628,7 @@ int asCScriptEngine::GetGlobalPropertyIndexByName(const char *name) const while( ns ) { int id = registeredGlobalProps.GetFirstIndex(ns, name); - if( id >= 0 ) + if( id >= 0 ) return id; // Recursively search parent namespace @@ -2703,7 +2668,7 @@ int asCScriptEngine::GetGlobalPropertyIndexByDecl(const char *decl) const } // interface -int asCScriptEngine::RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) +int asCScriptEngine::RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) { if( obj == 0 ) return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); @@ -2715,23 +2680,25 @@ int asCScriptEngine::RegisterObjectMethod(const char *obj, const char *declarati if( r < 0 ) return ConfigError(r, "RegisterObjectMethod", obj, declaration); - if( dt.GetObjectType() == 0 || dt.IsObjectHandle() ) + // Don't allow application to modify primitives or handles + if( dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE))) return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); - // Don't allow application to modify built-in types - if( dt.GetObjectType() == &functionBehaviours || - dt.GetObjectType() == &scriptTypeBehaviours ) + // Don't allow application to modify built-in types or funcdefs + if( dt.GetTypeInfo() == &functionBehaviours || + dt.GetTypeInfo() == &scriptTypeBehaviours || + CastToFuncdefType(dt.GetTypeInfo()) ) return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); // Don't allow modifying generated template instances - if( dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(dt.GetObjectType()) ) + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) return ConfigError(asINVALID_TYPE, "RegisterObjectMethod", obj, declaration); - return RegisterMethodToObjectType(dt.GetObjectType(), declaration, funcPointer, callConv, objForThiscall); + return RegisterMethodToObjectType(CastToObjectType(dt.GetTypeInfo()), declaration, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect); } // internal -int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) +int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) { #ifdef AS_MAX_PORTABILITY if( callConv != asCALL_GENERIC ) @@ -2739,10 +2706,15 @@ int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const #endif asSSystemFunctionInterface internal; - int r = DetectCallingConvention(true, funcPointer, callConv, objForThiscall, &internal); + int r = DetectCallingConvention(true, funcPointer, callConv, auxiliary, &internal); if( r < 0 ) return ConfigError(r, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + internal.compositeOffset = compositeOffset; + internal.isCompositeIndirect = isCompositeIndirect; + if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL ) + return ConfigError(asINVALID_ARG, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType // If the object type is a template, make sure there are no generated instances already if( objectType->flags & asOBJ_TEMPLATE ) @@ -2752,10 +2724,10 @@ int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const asCObjectType *tmpl = generatedTemplateTypes[n]; if( tmpl->name == objectType->name && tmpl->nameSpace == objectType->nameSpace && - !(tmpl->templateSubTypes[0].GetObjectType() && (tmpl->templateSubTypes[0].GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) + !(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) { asCString msg; - msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateObject(tmpl, false).Format(tmpl->nameSpace).AddressOf()); + msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf()); WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf()); return ConfigError(asERROR, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); } @@ -2800,11 +2772,10 @@ int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const } // Check against duplicate methods - asUINT n; if( func->name == "opConv" || func->name == "opImplConv" || func->name == "opCast" || func->name == "opImplCast" ) { // opConv and opCast are special methods that the compiler differentiates between by the return type - for( n = 0; n < func->objectType->methods.GetLength(); n++ ) + for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ ) { asCScriptFunction *f = scriptFunctions[func->objectType->methods[n]]; if( f->name == func->name && @@ -2818,7 +2789,7 @@ int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const } else { - for( n = 0; n < func->objectType->methods.GetLength(); n++ ) + for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ ) { asCScriptFunction *f = scriptFunctions[func->objectType->methods[n]]; if( f->name == func->name && @@ -2842,42 +2813,15 @@ int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const // Check if the method restricts that use of the template to value types or reference types if( func->objectType->flags & asOBJ_TEMPLATE ) { - for( asUINT subTypeIdx = 0; subTypeIdx < func->objectType->templateSubTypes.GetLength(); subTypeIdx++ ) - { - if( func->returnType.GetObjectType() == func->objectType->templateSubTypes[subTypeIdx].GetObjectType() ) - { - if( func->returnType.IsObjectHandle() ) - func->objectType->acceptValueSubType = false; - else if( !func->returnType.IsReference() ) - func->objectType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if( !func->returnType.IsObjectHandle() && !func->returnType.IsReference() ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - - for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( func->parameterTypes[n].GetObjectType() == func->objectType->templateSubTypes[subTypeIdx].GetObjectType() ) - { - // TODO: If unsafe references are allowed, then inout references allow value types - if( func->parameterTypes[n].IsObjectHandle() || (func->parameterTypes[n].IsReference() && func->inOutFlags[n] == asTM_INOUTREF) ) - func->objectType->acceptValueSubType = false; - else if( !func->parameterTypes[n].IsReference() ) - func->objectType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if( !func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference() ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - } - } + r = SetTemplateRestrictions(func->objectType, func, "RegisterObjectMethod", declaration); + if (r < 0) + return r; } // TODO: beh.copy member will be removed, so this is not necessary // Is this the default copy behaviour? - if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && func->isReadOnly == false && - ((objectType->flags & asOBJ_SCRIPT_OBJECT) || func->parameterTypes[0].IsEqualExceptRefAndConst(asCDataType::CreateObject(func->objectType, false))) ) + if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && !func->IsReadOnly() && + ((objectType->flags & asOBJ_SCRIPT_OBJECT) || func->parameterTypes[0].IsEqualExceptRefAndConst(asCDataType::CreateType(func->objectType, false))) ) { if( func->objectType->beh.copy != 0 ) return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); @@ -2891,7 +2835,7 @@ int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const } // interface -int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) +int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary) { #ifdef AS_MAX_PORTABILITY if( callConv != asCALL_GENERIC ) @@ -2899,7 +2843,7 @@ int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFu #endif asSSystemFunctionInterface internal; - int r = DetectCallingConvention(false, funcPointer, callConv, objForThiscall, &internal); + int r = DetectCallingConvention(false, funcPointer, callConv, auxiliary, &internal); if( r < 0 ) return ConfigError(r, "RegisterGlobalFunction", declaration, 0); @@ -3048,9 +2992,9 @@ asIScriptFunction *asCScriptEngine::GetGlobalFunctionByDecl(const char *decl) co } -asCObjectType *asCScriptEngine::GetRegisteredObjectType(const asCString &type, asSNameSpace *ns) const +asCTypeInfo *asCScriptEngine::GetRegisteredType(const asCString &type, asSNameSpace *ns) const { - asSMapNode *cursor; + asSMapNode *cursor; if( allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(ns, type)) ) return cursor->value; @@ -3128,7 +3072,7 @@ void asCScriptEngine::PrepareEngine() else if( (type->flags & asOBJ_VALUE) && !(type->flags & asOBJ_POD) ) { - if( type->beh.construct == 0 || + if( type->beh.constructors.GetLength() == 0 || type->beh.destruct == 0 ) { infoMsg = TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR; @@ -3179,11 +3123,11 @@ int asCScriptEngine::RegisterDefaultArrayType(const char *type) int r = bld.ParseDataType(type, &dt, defaultNamespace); if( r < 0 ) return r; - if( dt.GetObjectType() == 0 || - !(dt.GetObjectType()->GetFlags() & asOBJ_TEMPLATE) ) + if( dt.GetTypeInfo() == 0 || + !(dt.GetTypeInfo()->GetFlags() & asOBJ_TEMPLATE) ) return asINVALID_TYPE; - defaultArrayObjectType = dt.GetObjectType(); + defaultArrayObjectType = CastToObjectType(dt.GetTypeInfo()); defaultArrayObjectType->AddRefInternal(); return 0; @@ -3193,78 +3137,35 @@ int asCScriptEngine::RegisterDefaultArrayType(const char *type) int asCScriptEngine::GetDefaultArrayTypeId() const { if( defaultArrayObjectType ) - return GetTypeIdFromDataType(asCDataType::CreateObject(defaultArrayObjectType, false)); + return GetTypeIdFromDataType(asCDataType::CreateType(defaultArrayObjectType, false)); return asINVALID_TYPE; } // interface -int asCScriptEngine::RegisterStringFactory(const char *datatype, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) +int asCScriptEngine::RegisterStringFactory(const char *datatype, asIStringFactory *factory) { - asSSystemFunctionInterface internal; - int r = DetectCallingConvention(false, funcPointer, callConv, objForThiscall, &internal); - if( r < 0 ) - return ConfigError(r, "RegisterStringFactory", datatype, 0); - -#ifdef AS_MAX_PORTABILITY - if( callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterStringFactory", datatype, 0); -#else - if( callConv != asCALL_CDECL && - callConv != asCALL_STDCALL && - callConv != asCALL_THISCALL_ASGLOBAL && - callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterStringFactory", datatype, 0); -#endif - - // Put the system function in the list of system functions - asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal); - if( newInterface == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterStringFactory", datatype, 0); - - asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM); - if( func == 0 ) - { - asDELETE(newInterface, asSSystemFunctionInterface); - return ConfigError(asOUT_OF_MEMORY, "RegisterStringFactory", datatype, 0); - } - - func->name = "$str"; - func->sysFuncIntf = newInterface; + if (factory == 0) + return ConfigError(asINVALID_ARG, "RegisterStringFactory", datatype, 0); + // Parse the data type asCBuilder bld(this, 0); - asCDataType dt; - r = bld.ParseDataType(datatype, &dt, defaultNamespace, true); - if( r < 0 ) - { - // Set as dummy before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); + int r = bld.ParseDataType(datatype, &dt, defaultNamespace, true); + if (r < 0) return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); - } - func->returnType = dt; - func->parameterTypes.PushLast(asCDataType::CreatePrimitive(ttInt, true)); - func->inOutFlags.PushLast(asTM_NONE); - asCDataType parm1 = asCDataType::CreatePrimitive(ttUInt8, true); - parm1.MakeReference(true); - func->parameterTypes.PushLast(parm1); - func->inOutFlags.PushLast(asTM_INREF); - func->id = GetNextScriptFunctionId(); - AddScriptFunction(func); + // Validate the type. It must not be reference or handle + if (dt.IsReference() || dt.IsObjectHandle()) + return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); - stringFactory = func; + // All string literals will be treated as const + dt.MakeReadOnly(true); - if( func->returnType.GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType()); - if( group == 0 ) group = &defaultGroup; - group->scriptFunctions.PushLast(func); - } + stringType = dt; + stringFactory = factory; - // Register function id as success - return func->id; + return asSUCCESS; } // interface @@ -3273,7 +3174,9 @@ int asCScriptEngine::GetStringFactoryReturnTypeId(asDWORD *flags) const if( stringFactory == 0 ) return asNO_FUNCTION; - return stringFactory->GetReturnTypeId(flags); + if( flags ) + *flags = 0; + return GetTypeIdFromDataType(stringType); } // internal @@ -3403,7 +3306,7 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT if( type->module == 0 ) { // Set the ownership of this template type - // It may be without ownership if it was previously created from application with for example GetObjectTypeByDecl + // It may be without ownership if it was previously created from application with for example GetTypeInfoByDecl type->module = requestingModule; } if( !requestingModule->templateInstances.Exists(type) ) @@ -3422,10 +3325,10 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT // Make sure this template supports the subtype for( n = 0; n < subTypes.GetLength(); n++ ) { - if( !templateType->acceptValueSubType && (subTypes[n].IsPrimitive() || (subTypes[n].GetObjectType()->flags & asOBJ_VALUE)) ) + if( !templateType->acceptValueSubType && (subTypes[n].IsPrimitive() || (subTypes[n].GetTypeInfo()->flags & asOBJ_VALUE)) ) return 0; - if( !templateType->acceptRefSubType && (subTypes[n].IsObject() && (subTypes[n].GetObjectType()->flags & asOBJ_REF)) ) + if( !templateType->acceptRefSubType && (subTypes[n].IsObject() && (subTypes[n].GetTypeInfo()->flags & asOBJ_REF)) ) return 0; } @@ -3459,9 +3362,9 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT // engine at any time (unless the application holds an external reference). for( n = 0; n < subTypes.GetLength(); n++ ) { - if( subTypes[n].GetObjectType() ) + if( subTypes[n].GetTypeInfo() ) { - ot->module = subTypes[n].GetObjectType()->module; + ot->module = subTypes[n].GetTypeInfo()->module; if( ot->module ) { ot->module->templateInstances.PushLast(ot); @@ -3534,6 +3437,15 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT // The object types in templateInstanceTypes that are not also in generatedTemplateTypes are registered template specializations generatedTemplateTypes.PushLast(ot); + // Any child funcdefs must be copied to the template instance (with adjustments in case of template subtypes) + // This must be done before resolving other methods, to make sure the other methods that may refer to the + // templated funcdef will resolve to the new funcdef + for (n = 0; n < templateType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcdef = GenerateNewTemplateFuncdef(templateType, ot, templateType->childFuncDefs[n]); + funcdef->parentClass = ot; + ot->childFuncDefs.PushLast(funcdef); + } // As the new template type is instantiated the engine should // generate new functions to substitute the ones with the template subtype. @@ -3590,7 +3502,7 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT if( templateType->beh.listFactory ) { asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, templateType->beh.listFactory); - + // Rename the function to easily identify it in LoadByteCode func->name = "$list"; @@ -3635,23 +3547,23 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT // Increase ref counter for sub type if it is an object type for( n = 0; n < ot->templateSubTypes.GetLength(); n++ ) - if( ot->templateSubTypes[n].GetObjectType() ) - ot->templateSubTypes[n].GetObjectType()->AddRefInternal(); + if( ot->templateSubTypes[n].GetTypeInfo() ) + ot->templateSubTypes[n].GetTypeInfo()->AddRefInternal(); // Copy the properties to the template instance for( n = 0; n < templateType->properties.GetLength(); n++ ) { asCObjectProperty *prop = templateType->properties[n]; ot->properties.PushLast(asNEW(asCObjectProperty)(*prop)); - if( prop->type.GetObjectType() ) - prop->type.GetObjectType()->AddRefInternal(); + if( prop->type.GetTypeInfo() ) + prop->type.GetTypeInfo()->AddRefInternal(); } return ot; } // interface -asILockableSharedBool *asCScriptEngine::GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const +asILockableSharedBool *asCScriptEngine::GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const { // Make sure it is not a null pointer if( obj == 0 || type == 0 ) return 0; @@ -3667,21 +3579,25 @@ asILockableSharedBool *asCScriptEngine::GetWeakRefFlagOfScriptObject(void *obj, } // internal +// orig is the parameter type that is to be replaced +// tmpl is the registered template. Used to find which subtype is being replaced +// ot is the new template instance that is being created. Used to find the target type asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot) { asCDataType dt; - if( orig.GetObjectType() && (orig.GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE) ) + if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) { bool found = false; for( asUINT n = 0; n < tmpl->templateSubTypes.GetLength(); n++ ) { - if( orig.GetObjectType() == tmpl->templateSubTypes[n].GetObjectType() ) + if( orig.GetTypeInfo() == tmpl->templateSubTypes[n].GetTypeInfo() ) { found = true; dt = ot->templateSubTypes[n]; if( orig.IsObjectHandle() && !ot->templateSubTypes[n].IsObjectHandle() ) { dt.MakeHandle(true, true); + asASSERT(dt.IsObjectHandle()); if( orig.IsHandleToConst() ) dt.MakeHandleToConst(true); dt.MakeReference(orig.IsReference()); @@ -3689,6 +3605,12 @@ asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, a } else { + // The target type is a handle, then check if the application + // wants this handle to be to a const object. This is done by + // flagging the type with 'if_handle_then_const' in the declaration. + if (dt.IsObjectHandle() && orig.HasIfHandleThenConst()) + dt.MakeHandleToConst(true); + dt.MakeReference(orig.IsReference()); dt.MakeReadOnly(ot->templateSubTypes[n].IsReadOnly() || orig.IsReadOnly()); } @@ -3698,28 +3620,28 @@ asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, a asASSERT( found ); UNUSED_VAR( found ); } - else if( orig.GetObjectType() == tmpl ) + else if( orig.GetTypeInfo() == tmpl ) { if( orig.IsObjectHandle() ) dt = asCDataType::CreateObjectHandle(ot, false); else - dt = asCDataType::CreateObject(ot, false); + dt = asCDataType::CreateType(ot, false); dt.MakeReference(orig.IsReference()); dt.MakeReadOnly(orig.IsReadOnly()); } - else if( orig.GetObjectType() && (orig.GetObjectType()->flags & asOBJ_TEMPLATE) ) + else if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) { // The type is itself a template, so it is necessary to find the correct template instance type asCArray tmplSubTypes; - asCObjectType *origType = orig.GetObjectType(); + asCObjectType *origType = CastToObjectType(orig.GetTypeInfo()); bool needInstance = true; // Find the matching replacements for the subtypes for( asUINT n = 0; n < origType->templateSubTypes.GetLength(); n++ ) { - if( origType->templateSubTypes[n].GetObjectType() == 0 || - !(origType->templateSubTypes[n].GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE) ) + if( origType->templateSubTypes[n].GetTypeInfo() == 0 || + !(origType->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) { // The template is already an instance so we shouldn't attempt to create another instance needInstance = false; @@ -3727,7 +3649,7 @@ asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, a } for( asUINT m = 0; m < tmpl->templateSubTypes.GetLength(); m++ ) - if( origType->templateSubTypes[n].GetObjectType() == tmpl->templateSubTypes[m].GetObjectType() ) + if( origType->templateSubTypes[n].GetTypeInfo() == tmpl->templateSubTypes[m].GetTypeInfo() ) tmplSubTypes.PushLast(ot->templateSubTypes[m]); if( tmplSubTypes.GetLength() != n+1 ) @@ -3761,11 +3683,23 @@ asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, a if( orig.IsObjectHandle() ) dt = asCDataType::CreateObjectHandle(ntype, false); else - dt = asCDataType::CreateObject(ntype, false); + dt = asCDataType::CreateType(ntype, false); dt.MakeReference(orig.IsReference()); dt.MakeReadOnly(orig.IsReadOnly()); } + else if (orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(orig.GetTypeInfo())->parentClass == tmpl) + { + // The type is a child funcdef. Find the corresponding child funcdef in the template instance + for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++) + { + if (ot->childFuncDefs[n]->name == orig.GetTypeInfo()->name) + { + dt = orig; + dt.SetTypeInfo(ot->childFuncDefs[n]); + } + } + } else dt = orig; @@ -3788,34 +3722,39 @@ asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *t return 0; } - func->funcType = asFUNC_SCRIPT; + func->funcType = asFUNC_SCRIPT; func->AllocateScriptFunctionData(); - func->name = "$fact"; - func->id = GetNextScriptFunctionId(); + func->id = GetNextScriptFunctionId(); AddScriptFunction(func); - func->isShared = true; + func->SetShared(true); if( templateType->flags & asOBJ_REF ) { - func->returnType = asCDataType::CreateObjectHandle(ot, false); + func->name = "$fact"; + func->returnType = asCDataType::CreateObjectHandle(ot, false); } else { - func->returnType = factory->returnType; // constructors return nothing - func->objectType = ot; + func->name = "$beh0"; + func->returnType = factory->returnType; // constructors return nothing + func->objectType = ot; func->objectType->AddRefInternal(); } // Skip the first parameter as this is the object type pointer that the stub will add func->parameterTypes.SetLength(factory->parameterTypes.GetLength()-1); + func->parameterNames.SetLength(factory->parameterNames.GetLength()-1); func->inOutFlags.SetLength(factory->inOutFlags.GetLength()-1); + func->defaultArgs.SetLength(factory->defaultArgs.GetLength()-1); for( asUINT p = 1; p < factory->parameterTypes.GetLength(); p++ ) { func->parameterTypes[p-1] = factory->parameterTypes[p]; + func->parameterNames[p-1] = factory->parameterNames[p]; func->inOutFlags[p-1] = factory->inOutFlags[p]; + func->defaultArgs[p-1] = factory->defaultArgs[p] ? asNEW(asCString)(*factory->defaultArgs[p]) : 0; } func->scriptData->objVariablesOnHeap = 0; - + // Generate the bytecode for the factory stub asUINT bcLength = asBCTypeSize[asBCInfo[asBC_OBJTYPE].type] + asBCTypeSize[asBCInfo[asBC_CALLSYS].type] + @@ -3889,15 +3828,18 @@ asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *t bool asCScriptEngine::RequireTypeReplacement(asCDataType &type, asCObjectType *templateType) { - if( type.GetObjectType() == templateType ) return true; - if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE) ) return true; - if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_TEMPLATE) ) + if( type.GetTypeInfo() == templateType ) return true; + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) return true; + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) { - for( asUINT n = 0; n < type.GetObjectType()->templateSubTypes.GetLength(); n++ ) - if( type.GetObjectType()->templateSubTypes[n].GetObjectType() && - type.GetObjectType()->templateSubTypes[n].GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE ) + asCObjectType *ot = CastToObjectType(type.GetTypeInfo()); + for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) + if( ot->templateSubTypes[n].GetTypeInfo() && + ot->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE ) return true; } + if (type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(type.GetTypeInfo())->parentClass == templateType) + return true; return false; } @@ -3933,16 +3875,23 @@ bool asCScriptEngine::GenerateNewTemplateFunction(asCObjectType *templateType, a func2->returnType = DetermineTypeForTemplate(func->returnType, templateType, ot); func2->parameterTypes.SetLength(func->parameterTypes.GetLength()); - for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ ) + for (asUINT p = 0; p < func->parameterTypes.GetLength(); p++) func2->parameterTypes[p] = DetermineTypeForTemplate(func->parameterTypes[p], templateType, ot); + for (asUINT n = 0; n < func->defaultArgs.GetLength(); n++) + if (func->defaultArgs[n]) + func2->defaultArgs.PushLast(asNEW(asCString)(*func->defaultArgs[n])); + else + func2->defaultArgs.PushLast(0); + // TODO: template: Must be careful when instantiating templates for garbage collected types // If the template hasn't been registered with the behaviours, it shouldn't // permit instantiation of garbage collected types that in turn may refer to // this instance. + func2->parameterNames = func->parameterNames; func2->inOutFlags = func->inOutFlags; - func2->isReadOnly = func->isReadOnly; + func2->SetReadOnly(func->IsReadOnly()); func2->objectType = ot; func2->objectType->AddRefInternal(); func2->sysFuncIntf = asNEW(asSSystemFunctionInterface)(*func->sysFuncIntf); @@ -3963,6 +3912,48 @@ bool asCScriptEngine::GenerateNewTemplateFunction(asCObjectType *templateType, a return true; } +asCFuncdefType *asCScriptEngine::GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *ot, asCFuncdefType *func) +{ + // TODO: Only generate the new funcdef if it used the template subtypes. + // Remember to also update the clean up in asCObjectType::DestroyInternal so it doesn't delete + // child funcdefs that have not been created specificially for the template instance. + // Perhaps a new funcdef is always needed, since the funcdef will have a reference to the + // parent class (in this case the template instance). + + asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcdef->funcType); + if (func2 == 0) + { + // Out of memory + return 0; + } + + func2->name = func->name; + + func2->returnType = DetermineTypeForTemplate(func->funcdef->returnType, templateType, ot); + func2->parameterTypes.SetLength(func->funcdef->parameterTypes.GetLength()); + for (asUINT p = 0; p < func->funcdef->parameterTypes.GetLength(); p++) + func2->parameterTypes[p] = DetermineTypeForTemplate(func->funcdef->parameterTypes[p], templateType, ot); + + // TODO: template: Must be careful when instantiating templates for garbage collected types + // If the template hasn't been registered with the behaviours, it shouldn't + // permit instantiation of garbage collected types that in turn may refer to + // this instance. + + func2->inOutFlags = func->funcdef->inOutFlags; + func2->SetReadOnly(func->funcdef->IsReadOnly()); + asASSERT(func->funcdef->objectType == 0); + asASSERT(func->funcdef->sysFuncIntf == 0); + + func2->id = GetNextScriptFunctionId(); + AddScriptFunction(func2); + + asCFuncdefType *fdt2 = asNEW(asCFuncdefType)(this, func2); + funcDefs.PushLast(fdt2); // don't increase refCount as the constructor already set it to 1 + + // Return the new function + return fdt2; +} + void asCScriptEngine::CallObjectMethod(void *obj, int func) const { asCScriptFunction *s = scriptFunctions[func]; @@ -3992,6 +3983,11 @@ void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, asPWORD baseOffset; // Same size as the pointer } f; } p; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + p.f.func = (asFUNCTION_t)(i->func); p.f.baseOffset = asPWORD(i->baseOffset); void (asCSimpleDummy::*f)() = p.mthd; @@ -4013,6 +4009,11 @@ void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, } p; p.func = (asFUNCTION_t)(i->func); void (asCSimpleDummy::*f)() = p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + obj = (void*)(asPWORD(obj) + i->baseOffset); (((asCSimpleDummy*)obj)->*f)(); } @@ -4058,6 +4059,11 @@ bool asCScriptEngine::CallObjectMethodRetBool(void *obj, int func) const asPWORD baseOffset; } f; } p; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + p.f.func = (asFUNCTION_t)(i->func); p.f.baseOffset = asPWORD(i->baseOffset); bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())(p.mthd); @@ -4079,6 +4085,11 @@ bool asCScriptEngine::CallObjectMethodRetBool(void *obj, int func) const } p; p.func = (asFUNCTION_t)(i->func); bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + obj = (void*)(asPWORD(obj) + i->baseOffset); return (((asCSimpleDummy*)obj)->*f)(); } @@ -4127,6 +4138,11 @@ int asCScriptEngine::CallObjectMethodRetInt(void *obj, int func) const } p; p.f.func = (asFUNCTION_t)(i->func); p.f.baseOffset = asPWORD(i->baseOffset); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())(p.mthd); return (((asCSimpleDummy*)obj)->*f)(); } @@ -4146,6 +4162,11 @@ int asCScriptEngine::CallObjectMethodRetInt(void *obj, int func) const } p; p.func = (asFUNCTION_t)(i->func); int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + obj = (void*)(asPWORD(obj) + i->baseOffset); return (((asCSimpleDummy*)obj)->*f)(); } @@ -4194,6 +4215,11 @@ void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int func) const } p; p.f.func = (asFUNCTION_t)(i->func); p.f.baseOffset = asPWORD(i->baseOffset); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + void *(asCSimpleDummy::*f)() = (void *(asCSimpleDummy::*)())(p.mthd); return (((asCSimpleDummy*)obj)->*f)(); } @@ -4213,6 +4239,11 @@ void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int func) const } p; p.func = (asFUNCTION_t)(i->func); void *(asCSimpleDummy::*f)() = (void *(asCSimpleDummy::*)())p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + obj = (void*)(asPWORD(obj) + i->baseOffset); return (((asCSimpleDummy*)obj)->*f)(); } @@ -4235,6 +4266,7 @@ void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int func) const void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const { + asASSERT( obj != 0 ); asASSERT( func != 0 ); asSSystemFunctionInterface *i = func->sysFuncIntf; @@ -4254,6 +4286,11 @@ void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int param1, asCScriptFu } p; p.f.func = (asFUNCTION_t)(i->func); p.f.baseOffset = asPWORD(i->baseOffset); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))(p.mthd); return (((asCSimpleDummy*)obj)->*f)(param1); #else @@ -4264,6 +4301,11 @@ void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int param1, asCScriptFu } p; p.func = (asFUNCTION_t)(i->func); void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + obj = (void*)(asPWORD(obj) + i->baseOffset); return (((asCSimpleDummy*)obj)->*f)(param1); #endif @@ -4383,6 +4425,11 @@ void asCScriptEngine::CallObjectMethod(void *obj, void *param, asSSystemFunction } p; p.f.func = (asFUNCTION_t)(i->func); p.f.baseOffset = asPWORD(i->baseOffset); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + void (asCSimpleDummy::*f)(void*) = (void (asCSimpleDummy::*)(void*))(p.mthd); (((asCSimpleDummy*)obj)->*f)(param); } @@ -4402,6 +4449,11 @@ void asCScriptEngine::CallObjectMethod(void *obj, void *param, asSSystemFunction } p; p.func = (asFUNCTION_t)(i->func); void (asCSimpleDummy::*f)(void *) = (void (asCSimpleDummy::*)(void *))(p.mthd); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + obj = (void*)(asPWORD(obj) + i->baseOffset); (((asCSimpleDummy*)obj)->*f)(param); } @@ -4516,13 +4568,13 @@ void asCScriptEngine::CallFree(void *obj) const } // interface -int asCScriptEngine::NotifyGarbageCollectorOfNewObject(void *obj, asIObjectType *type) +int asCScriptEngine::NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type) { return gc.AddScriptObjectToGC(obj, static_cast(type)); } // interface -int asCScriptEngine::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asIObjectType **type) +int asCScriptEngine::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type) { return gc.GetObjectInGC(idx, seqNbr, obj, type); } @@ -4559,7 +4611,7 @@ int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const { if( dtIn.IsNullHandle() ) return asTYPEID_VOID; - if( dtIn.GetObjectType() == 0 ) + if( dtIn.GetTypeInfo() == 0 ) { // Primitives have pre-fixed typeIds switch( dtIn.GetTokenType() ) @@ -4584,68 +4636,32 @@ int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const } int typeId = -1; - asCObjectType *ot = dtIn.GetObjectType(); - if( ot != &functionBehaviours ) + asCTypeInfo *ot = dtIn.GetTypeInfo(); + asASSERT(ot != &functionBehaviours); + // Object's hold the typeId themselves + typeId = ot->typeId; + + if( typeId == -1 ) { - // Object's hold the typeId themselves - typeId = ot->typeId; - - if( typeId == -1 ) - { - ACQUIREEXCLUSIVE(engineRWLock); - // Make sure another thread didn't determine the typeId while we were waiting for the lock - if( ot->typeId == -1 ) - { - typeId = typeIdSeqNbr++; - if( ot->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT; - else if( ot->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE; - else if( ot->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this? - else typeId |= asTYPEID_APPOBJECT; - - ot->typeId = typeId; - - mapTypeIdToObjectType.Insert(typeId, ot); - } - RELEASEEXCLUSIVE(engineRWLock); - } - } - else - { - // This a funcdef, so we'll need to look in the map for the funcdef - - // TODO: optimize: It shouldn't be necessary to exclusive lock when the typeId already exists ACQUIREEXCLUSIVE(engineRWLock); - - // Find the existing type id - asCScriptFunction *func = dtIn.GetFuncDef(); - asASSERT(func); - asSMapNode *cursor = 0; - mapTypeIdToFunction.MoveFirst(&cursor); - while( cursor ) + // Make sure another thread didn't determine the typeId while we were waiting for the lock + if( ot->typeId == -1 ) { - if( mapTypeIdToFunction.GetValue(cursor) == func ) - { - typeId = mapTypeIdToFunction.GetKey(cursor); - break; - } - - mapTypeIdToFunction.MoveNext(&cursor, cursor); - } - - // The type id doesn't exist, create it - if( typeId == -1 ) - { - // Setup the type id for the funcdef typeId = typeIdSeqNbr++; - typeId |= asTYPEID_APPOBJECT; - mapTypeIdToFunction.Insert(typeId, func); - } + if( ot->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT; + else if( ot->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE; + else if( ot->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this? + else typeId |= asTYPEID_APPOBJECT; + ot->typeId = typeId; + + mapTypeIdToTypeInfo.Insert(typeId, ot); + } RELEASEEXCLUSIVE(engineRWLock); } // Add flags according to the requested type - if( dtIn.GetObjectType() && !(dtIn.GetObjectType()->flags & asOBJ_ASHANDLE) ) + if( dtIn.GetTypeInfo() && !(dtIn.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) { // The ASHANDLE types behave like handles, but are really // value types so the typeId is never returned as a handle @@ -4669,35 +4685,16 @@ asCDataType asCScriptEngine::GetDataTypeFromTypeId(int typeId) const } // First check if the typeId is an object type - asCObjectType *ot = 0; + asCTypeInfo *ot = 0; ACQUIRESHARED(engineRWLock); - asSMapNode *cursor = 0; - if( mapTypeIdToObjectType.MoveTo(&cursor, baseId) ) - ot = mapTypeIdToObjectType.GetValue(cursor); + asSMapNode *cursor = 0; + if( mapTypeIdToTypeInfo.MoveTo(&cursor, baseId) ) + ot = mapTypeIdToTypeInfo.GetValue(cursor); RELEASESHARED(engineRWLock); if( ot ) { - asCDataType dt = asCDataType::CreateObject(ot, false); - if( typeId & asTYPEID_OBJHANDLE ) - dt.MakeHandle(true, true); - if( typeId & asTYPEID_HANDLETOCONST ) - dt.MakeHandleToConst(true); - - return dt; - } - - // Then check if it is a funcdef - asCScriptFunction *func = 0; - ACQUIRESHARED(engineRWLock); - asSMapNode *cursor2 = 0; - if( mapTypeIdToFunction.MoveTo(&cursor2, baseId) ) - func = mapTypeIdToFunction.GetValue(cursor2); - RELEASESHARED(engineRWLock); - - if( func ) - { - asCDataType dt = asCDataType::CreateFuncDef(func); + asCDataType dt = asCDataType::CreateType(ot, false); if( typeId & asTYPEID_OBJHANDLE ) dt.MakeHandle(true, true); if( typeId & asTYPEID_HANDLETOCONST ) @@ -4712,28 +4709,28 @@ asCDataType asCScriptEngine::GetDataTypeFromTypeId(int typeId) const asCObjectType *asCScriptEngine::GetObjectTypeFromTypeId(int typeId) const { asCDataType dt = GetDataTypeFromTypeId(typeId); - return dt.GetObjectType(); + return CastToObjectType(dt.GetTypeInfo()); } -void asCScriptEngine::RemoveFromTypeIdMap(asCObjectType *type) +void asCScriptEngine::RemoveFromTypeIdMap(asCTypeInfo *type) { ACQUIREEXCLUSIVE(engineRWLock); - asSMapNode *cursor = 0; - mapTypeIdToObjectType.MoveFirst(&cursor); + asSMapNode *cursor = 0; + mapTypeIdToTypeInfo.MoveFirst(&cursor); while( cursor ) { - if( mapTypeIdToObjectType.GetValue(cursor) == type ) + if(mapTypeIdToTypeInfo.GetValue(cursor) == type ) { - mapTypeIdToObjectType.Erase(cursor); + mapTypeIdToTypeInfo.Erase(cursor); break; } - mapTypeIdToObjectType.MoveNext(&cursor, cursor); + mapTypeIdToTypeInfo.MoveNext(&cursor, cursor); } RELEASEEXCLUSIVE(engineRWLock); } // interface -asIObjectType *asCScriptEngine::GetObjectTypeByDecl(const char *decl) const +asITypeInfo *asCScriptEngine::GetTypeInfoByDecl(const char *decl) const { asCDataType dt; // This cast is ok, because we are not changing anything in the engine @@ -4743,10 +4740,10 @@ asIObjectType *asCScriptEngine::GetObjectTypeByDecl(const char *decl) const bld.silent = true; int r = bld.ParseDataType(decl, &dt, defaultNamespace); - if( r < 0 ) + if (r < 0) return 0; - return dt.GetObjectType(); + return dt.GetTypeInfo(); } // interface @@ -4787,7 +4784,7 @@ int asCScriptEngine::GetSizeOfPrimitiveType(int typeId) const } // interface -int asCScriptEngine::RefCastObject(void *obj, asIObjectType *fromType, asIObjectType *toType, void **newPtr, bool useOnlyImplicitCast) +int asCScriptEngine::RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast) { if( newPtr == 0 ) return asINVALID_ARG; *newPtr = 0; @@ -4798,10 +4795,6 @@ int asCScriptEngine::RefCastObject(void *obj, asIObjectType *fromType, asIObject if( obj == 0 ) return asSUCCESS; - // This method doesn't support casting function pointers, since they cannot be described with just an object type - if( fromType->GetFlags() & asOBJ_SCRIPT_FUNCTION ) - return asNOT_SUPPORTED; - if( fromType == toType ) { *newPtr = obj; @@ -4809,6 +4802,22 @@ int asCScriptEngine::RefCastObject(void *obj, asIObjectType *fromType, asIObject return asSUCCESS; } + // Check for funcdefs + if ((fromType->GetFlags() & asOBJ_FUNCDEF) && (toType->GetFlags() & asOBJ_FUNCDEF)) + { + asCFuncdefType *fromFunc = CastToFuncdefType(reinterpret_cast(fromType)); + asCFuncdefType *toFunc = CastToFuncdefType(reinterpret_cast(toType)); + + if (fromFunc && toFunc && fromFunc->funcdef->IsSignatureExceptNameEqual(toFunc->funcdef)) + { + *newPtr = obj; + AddRefScriptObject(*newPtr, toType); + return asSUCCESS; + } + + return asSUCCESS; + } + // Look for ref cast behaviours asCScriptFunction *universalCastFunc = 0; asCObjectType *from = reinterpret_cast(fromType); @@ -4818,7 +4827,7 @@ int asCScriptEngine::RefCastObject(void *obj, asIObjectType *fromType, asIObject if( func->name == "opImplCast" || (!useOnlyImplicitCast && func->name == "opCast") ) { - if( func->returnType.GetObjectType() == toType ) + if( func->returnType.GetTypeInfo() == toType ) { *newPtr = CallObjectMethodRetPtr(obj, func->id); // The ref cast behaviour returns a handle with incremented @@ -4830,8 +4839,8 @@ int asCScriptEngine::RefCastObject(void *obj, asIObjectType *fromType, asIObject } else { - asASSERT( func->returnType.GetTokenType() == ttVoid && - func->parameterTypes.GetLength() == 1 && + asASSERT( func->returnType.GetTokenType() == ttVoid && + func->parameterTypes.GetLength() == 1 && func->parameterTypes[0].GetTokenType() == ttQuestion ); universalCastFunc = func; } @@ -4875,18 +4884,10 @@ int asCScriptEngine::RefCastObject(void *obj, asIObjectType *fromType, asIObject // Down casts to derived class or from interface can only be done explicitly if( !useOnlyImplicitCast ) { - if( toType->Implements(fromType) || - toType->DerivesFrom(fromType) ) - { - *newPtr = obj; - reinterpret_cast(*newPtr)->AddRef(); - return asSUCCESS; - } - // Get the true type of the object so the explicit cast can evaluate all possibilities - asIObjectType *from = reinterpret_cast(obj)->GetObjectType(); - if( from->DerivesFrom(toType) || - from->Implements(toType) ) + asITypeInfo *trueType = reinterpret_cast(obj)->GetObjectType(); + if (trueType->DerivesFrom(toType) || + trueType->Implements(toType)) { *newPtr = obj; reinterpret_cast(*newPtr)->AddRef(); @@ -4900,7 +4901,7 @@ int asCScriptEngine::RefCastObject(void *obj, asIObjectType *fromType, asIObject } // interface -void *asCScriptEngine::CreateScriptObject(const asIObjectType *type) +void *asCScriptEngine::CreateScriptObject(const asITypeInfo *type) { if( type == 0 ) return 0; @@ -4922,7 +4923,7 @@ void *asCScriptEngine::CreateScriptObject(const asIObjectType *type) // Call the script class' default factory with a context ptr = ScriptObjectFactory(objType, this); } - else if( objType->flags & asOBJ_TEMPLATE ) + else if( (objType->flags & asOBJ_TEMPLATE) && (objType->flags & asOBJ_REF) ) { // The registered factory that takes the object type is moved // to the construct behaviour when the type is instantiated @@ -4933,10 +4934,10 @@ void *asCScriptEngine::CreateScriptObject(const asIObjectType *type) { ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType); } - catch(...) + catch (...) { asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) + if (ctx) ctx->SetException(TXT_EXCEPTION_CAUGHT); } #endif @@ -4973,34 +4974,127 @@ void *asCScriptEngine::CreateScriptObject(const asIObjectType *type) // Manually allocate the memory, then call the default constructor ptr = CallAlloc(objType); int funcIndex = objType->beh.construct; - if( funcIndex ) + if (funcIndex) { + if (objType->flags & asOBJ_TEMPLATE) + { + // Templates of value types create script functions as the constructors + CallScriptObjectMethod(ptr, funcIndex); + } + else + { #ifdef AS_NO_EXCEPTIONS - CallObjectMethod(ptr, funcIndex); -#else - try - { CallObjectMethod(ptr, funcIndex); - } - catch(...) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException(TXT_EXCEPTION_CAUGHT); +#else + try + { + CallObjectMethod(ptr, funcIndex); + } + catch (...) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException(TXT_EXCEPTION_CAUGHT); - // Free the memory - CallFree(ptr); - ptr = 0; - } + // Free the memory + CallFree(ptr); + ptr = 0; + } #endif + } } } return ptr; } +// internal +int asCScriptEngine::CallScriptObjectMethod(void *obj, int funcId) +{ + asIScriptContext *ctx = 0; + int r = 0; + bool isNested = false; + + // Use nested call in the context if there is an active context + ctx = asGetActiveContext(); + if (ctx) + { + // It may not always be possible to reuse the current context, + // in which case we'll have to create a new one any way. + if (ctx->GetEngine() == this && ctx->PushState() == asSUCCESS) + isNested = true; + else + ctx = 0; + } + + if (ctx == 0) + { + // Request a context from the engine + ctx = RequestContext(); + if (ctx == 0) + { + // TODO: How to best report this failure? + return asERROR; + } + } + + r = ctx->Prepare(scriptFunctions[funcId]); + if (r < 0) + { + if (isNested) + ctx->PopState(); + else + ReturnContext(ctx); + // TODO: How to best report this failure? + return asERROR; + } + + // Set the object + ctx->SetObject(obj); + + for (;;) + { + r = ctx->Execute(); + + // We can't allow this execution to be suspended + // so resume the execution immediately + if (r != asEXECUTION_SUSPENDED) + break; + } + + if (r != asEXECUTION_FINISHED) + { + if (isNested) + { + ctx->PopState(); + + // If the execution was aborted or an exception occurred, + // then we should forward that to the outer execution. + if (r == asEXECUTION_EXCEPTION) + { + // TODO: How to improve this exception + ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); + } + else if (r == asEXECUTION_ABORTED) + ctx->Abort(); + } + else + ReturnContext(ctx); + + // TODO: How to best report the error? + return asERROR; + } + + if (isNested) + ctx->PopState(); + else + ReturnContext(ctx); + + return asSUCCESS; +} + // interface -void *asCScriptEngine::CreateUninitializedScriptObject(const asIObjectType *type) +void *asCScriptEngine::CreateUninitializedScriptObject(const asITypeInfo *type) { // This function only works for script classes. Registered types cannot be created this way. if( type == 0 || !(type->GetFlags() & asOBJ_SCRIPT_OBJECT) ) @@ -5019,7 +5113,7 @@ void *asCScriptEngine::CreateUninitializedScriptObject(const asIObjectType *type } // interface -void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asIObjectType *type) +void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asITypeInfo *type) { if( origObj == 0 || type == 0 ) return 0; @@ -5087,7 +5181,7 @@ void asCScriptEngine::ConstructScriptObjectCopy(void *mem, void *obj, asCObjectT } // interface -int asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asIObjectType *type) +int asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type) { // TODO: Warn about invalid call in message stream // TODO: Should a script exception be set in case a context is active? @@ -5121,88 +5215,66 @@ int asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asIObj } // interface -void asCScriptEngine::AddRefScriptObject(void *obj, const asIObjectType *type) +void asCScriptEngine::AddRefScriptObject(void *obj, const asITypeInfo *type) { // Make sure it is not a null pointer if( obj == 0 || type == 0 ) return; - const asCObjectType *objType = static_cast(type); - if( objType->beh.addref ) + const asCTypeInfo *ti = static_cast(type); + if (ti->flags & asOBJ_FUNCDEF) { - // Call the addref behaviour - CallObjectMethod(obj, objType->beh.addref); - } -} - -// interface -void asCScriptEngine::ReleaseScriptObject(void *obj, const asIObjectType *type) -{ - // Make sure it is not a null pointer - if( obj == 0 || type == 0 ) return; - - const asCObjectType *objType = static_cast(type); - if( objType->flags & asOBJ_REF ) - { - asASSERT( (objType->flags & asOBJ_NOCOUNT) || objType->beh.release ); - if( objType->beh.release ) - { - // Call the release behaviour - CallObjectMethod(obj, objType->beh.release); - } + CallObjectMethod(obj, functionBehaviours.beh.addref); } else { - // Call the destructor - if( objType->beh.destruct ) - CallObjectMethod(obj, objType->beh.destruct); - else if( objType->flags & asOBJ_LIST_PATTERN ) - DestroyList((asBYTE*)obj, objType); - - // We'll have to trust that the memory for the object was allocated with CallAlloc. - // This is true if the object was created in the context, or with CreateScriptObject. - - // Then free the memory - CallFree(obj); + asCObjectType *objType = CastToObjectType(const_cast(ti)); + if (objType && objType->beh.addref) + { + // Call the addref behaviour + CallObjectMethod(obj, objType->beh.addref); + } } } -#ifdef AS_DEPRECATED -// Deprecated since 2.30.0, 2014-11-04 // interface -bool asCScriptEngine::IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const +void asCScriptEngine::ReleaseScriptObject(void *obj, const asITypeInfo *type) { - // if equal, then it is obvious they are compatible - if( objTypeId == handleTypeId ) - return true; + // Make sure it is not a null pointer + if( obj == 0 || type == 0 ) return; - // Get the actual data types from the type ids - asCDataType objDt = GetDataTypeFromTypeId(objTypeId); - asCDataType hdlDt = GetDataTypeFromTypeId(handleTypeId); - - // A handle to const cannot be passed to a handle that is not referencing a const object - if( objDt.IsHandleToConst() && !hdlDt.IsHandleToConst() ) - return false; - - if( objDt.GetObjectType() == hdlDt.GetObjectType() ) + const asCTypeInfo *ti = static_cast(type); + if (ti->flags & asOBJ_FUNCDEF) { - // The object type is equal - return true; + CallObjectMethod(obj, functionBehaviours.beh.release); } - else if( objDt.IsScriptObject() && obj ) + else { - // Get the true type from the object instance - asCObjectType *objType = ((asCScriptObject*)obj)->objType; + asCObjectType *objType = CastToObjectType(const_cast(ti)); + if (objType && objType->flags & asOBJ_REF) + { + asASSERT((objType->flags & asOBJ_NOCOUNT) || objType->beh.release); + if (objType->beh.release) + { + // Call the release behaviour + CallObjectMethod(obj, objType->beh.release); + } + } + else if( objType ) + { + // Call the destructor + if (objType->beh.destruct) + CallObjectMethod(obj, objType->beh.destruct); + else if (objType->flags & asOBJ_LIST_PATTERN) + DestroyList((asBYTE*)obj, objType); - // Check if the object implements the interface, or derives from the base class - // This will also return true, if the requested handle type is an exact match for the object type - if( objType->Implements(hdlDt.GetObjectType()) || - objType->DerivesFrom(hdlDt.GetObjectType()) ) - return true; + // We'll have to trust that the memory for the object was allocated with CallAlloc. + // This is true if the object was created in the context, or with CreateScriptObject. + + // Then free the memory + CallFree(obj); + } } - - return false; } -#endif // interface int asCScriptEngine::BeginConfigGroup(const char *groupName) @@ -5259,7 +5331,7 @@ int asCScriptEngine::RemoveConfigGroup(const char *groupName) { asCConfigGroup *group = configGroups[n]; - // Remove any unused generated template instances + // Remove any unused generated template instances // before verifying if the config group is still in use. // RemoveTemplateInstanceType() checks if the instance is in use for( asUINT g = generatedTemplateTypes.GetLength(); g-- > 0; ) @@ -5320,13 +5392,13 @@ asCConfigGroup *asCScriptEngine::FindConfigGroupForGlobalVar(int gvarId) const return 0; } -asCConfigGroup *asCScriptEngine::FindConfigGroupForObjectType(const asCObjectType *objType) const +asCConfigGroup *asCScriptEngine::FindConfigGroupForTypeInfo(const asCTypeInfo *objType) const { for( asUINT n = 0; n < configGroups.GetLength(); n++ ) { - for( asUINT m = 0; m < configGroups[n]->objTypes.GetLength(); m++ ) + for( asUINT m = 0; m < configGroups[n]->types.GetLength(); m++ ) { - if( configGroups[n]->objTypes[m] == objType ) + if( configGroups[n]->types[m] == objType ) return configGroups[n]; } } @@ -5334,12 +5406,12 @@ asCConfigGroup *asCScriptEngine::FindConfigGroupForObjectType(const asCObjectTyp return 0; } -asCConfigGroup *asCScriptEngine::FindConfigGroupForFuncDef(const asCScriptFunction *funcDef) const +asCConfigGroup *asCScriptEngine::FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const { for( asUINT n = 0; n < configGroups.GetLength(); n++ ) { - asCScriptFunction *f = const_cast(funcDef); - if( configGroups[n]->funcDefs.Exists(f) ) + asCFuncdefType *f = const_cast(funcDef); + if( configGroups[n]->types.Exists(f) ) return configGroups[n]; } @@ -5447,7 +5519,7 @@ void asCScriptEngine::RemoveScriptFunction(asCScriptFunction *func) } // internal -void asCScriptEngine::RemoveFuncdef(asCScriptFunction *funcdef) +void asCScriptEngine::RemoveFuncdef(asCFuncdefType *funcdef) { funcDefs.RemoveValue(funcdef); } @@ -5463,7 +5535,8 @@ int asCScriptEngine::RegisterFuncdef(const char *decl) return ConfigError(asOUT_OF_MEMORY, "RegisterFuncdef", decl, 0); asCBuilder bld(this, 0); - int r = bld.ParseFunctionDeclaration(0, decl, func, false, 0, 0, defaultNamespace); + asCObjectType *parentClass = 0; + int r = bld.ParseFunctionDeclaration(0, decl, func, false, 0, 0, defaultNamespace, 0, &parentClass); if( r < 0 ) { // Set as dummy function before deleting @@ -5483,16 +5556,31 @@ int asCScriptEngine::RegisterFuncdef(const char *decl) func->id = GetNextScriptFunctionId(); AddScriptFunction(func); - funcDefs.PushLast(func); - func->AddRefInternal(); - registeredFuncDefs.PushLast(func); - currentGroup->funcDefs.PushLast(func); + asCFuncdefType *fdt = asNEW(asCFuncdefType)(this, func); + funcDefs.PushLast(fdt); // doesn't increase refcount + registeredFuncDefs.PushLast(fdt); // doesn't increase refcount + allRegisteredTypes.Insert(asSNameSpaceNamePair(fdt->nameSpace, fdt->name), fdt); // constructor already set the ref count to 1 + + currentGroup->types.PushLast(fdt); + if (parentClass) + { + parentClass->childFuncDefs.PushLast(fdt); + fdt->parentClass = parentClass; + + // Check if the method restricts that use of the template to value types or reference types + if (parentClass->flags & asOBJ_TEMPLATE) + { + r = SetTemplateRestrictions(parentClass, func, "RegisterFuncdef", decl); + if (r < 0) + return r; + } + } // If parameter type from other groups are used, add references currentGroup->AddReferencesForFunc(this, func); - // Return the function id as success - return func->id; + // Return the type id as success + return GetTypeIdFromDataType(asCDataType::CreateType(fdt, false)); } // interface @@ -5502,7 +5590,7 @@ asUINT asCScriptEngine::GetFuncdefCount() const } // interface -asIScriptFunction *asCScriptEngine::GetFuncdefByIndex(asUINT index) const +asITypeInfo *asCScriptEngine::GetFuncdefByIndex(asUINT index) const { if( index >= registeredFuncDefs.GetLength() ) return 0; @@ -5510,6 +5598,75 @@ asIScriptFunction *asCScriptEngine::GetFuncdefByIndex(asUINT index) const return registeredFuncDefs[index]; } +// internal +asCFuncdefType *asCScriptEngine::FindMatchingFuncdef(asCScriptFunction *func, asCModule *module) +{ + asCFuncdefType *funcDef = func->funcdefType; + + if (funcDef == 0) + { + // Check if there is any matching funcdefs already in the engine that can be reused + for (asUINT n = 0; n < funcDefs.GetLength(); n++) + { + if (funcDefs[n]->funcdef->IsSignatureExceptNameEqual(func)) + { + if (func->IsShared() && !funcDefs[n]->funcdef->IsShared()) + continue; + funcDef = funcDefs[n]; + break; + } + } + } + + if (funcDef == 0) + { + // Create a matching funcdef + asCScriptFunction *fd = asNEW(asCScriptFunction)(this, 0, asFUNC_FUNCDEF); + fd->name = func->name; + fd->nameSpace = func->nameSpace; + fd->SetShared(func->IsShared()); + + fd->returnType = func->returnType; + fd->parameterTypes = func->parameterTypes; + fd->inOutFlags = func->inOutFlags; + + funcDef = asNEW(asCFuncdefType)(this, fd); + funcDefs.PushLast(funcDef); // doesn't increase the refCount + + fd->id = GetNextScriptFunctionId(); + AddScriptFunction(fd); + + if (module) + { + // Add the new funcdef to the module so it will + // be available when saving the bytecode + funcDef->module = module; + module->funcDefs.PushLast(funcDef); // the refCount was already accounted for in the constructor + } + + // Observe, if the funcdef is created without informing a module a reference will be stored in the + // engine's funcDefs array, but it will not be owned by any module. This means that it will live on + // until the engine is released. + } + + if (funcDef && module && funcDef->module && funcDef->module != module) + { + // Unless this is a registered funcDef the returned funcDef must + // be stored as part of the module for saving/loading bytecode + if (!module->funcDefs.Exists(funcDef)) + { + module->funcDefs.PushLast(funcDef); + funcDef->AddRefInternal(); + } + else + { + asASSERT(funcDef->IsShared()); + } + } + + return funcDef; +} + // interface // TODO: typedef: Accept complex types for the typedefs int asCScriptEngine::RegisterTypedef(const char *type, const char *decl) @@ -5518,7 +5675,7 @@ int asCScriptEngine::RegisterTypedef(const char *type, const char *decl) // Verify if the name has been registered as a type already // TODO: Must check against registered funcdefs too - if( GetRegisteredObjectType(type, defaultNamespace) ) + if( GetRegisteredType(type, defaultNamespace) ) // Let the application recover from this error, for example if the same typedef is registered twice return asALREADY_REGISTERED; @@ -5568,22 +5725,22 @@ int asCScriptEngine::RegisterTypedef(const char *type, const char *decl) // types as they are allowed to use the names // Put the data type in the list - asCObjectType *object = asNEW(asCObjectType)(this); - if( object == 0 ) + asCTypedefType *td = asNEW(asCTypedefType)(this); + if( td == 0 ) return ConfigError(asOUT_OF_MEMORY, "RegisterTypedef", type, decl); - object->flags = asOBJ_TYPEDEF; - object->size = dataType.GetSizeInMemoryBytes(); - object->name = type; - object->nameSpace = defaultNamespace; - object->templateSubTypes.PushLast(dataType); + td->flags = asOBJ_TYPEDEF; + td->size = dataType.GetSizeInMemoryBytes(); + td->name = type; + td->nameSpace = defaultNamespace; + td->aliasForType = dataType; - allRegisteredTypes.Insert(asSNameSpaceNamePair(object->nameSpace, object->name), object); - registeredTypeDefs.PushLast(object); + allRegisteredTypes.Insert(asSNameSpaceNamePair(td->nameSpace, td->name), td); + registeredTypeDefs.PushLast(td); - currentGroup->objTypes.PushLast(object); + currentGroup->types.PushLast(td); - return asSUCCESS; + return GetTypeIdByDecl(type); } // interface @@ -5593,30 +5750,12 @@ asUINT asCScriptEngine::GetTypedefCount() const } // interface -const char *asCScriptEngine::GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace, const char **configGroup, asDWORD *accessMask) const +asITypeInfo *asCScriptEngine::GetTypedefByIndex(asUINT index) const { if( index >= registeredTypeDefs.GetLength() ) return 0; - if( typeId ) - *typeId = GetTypeIdFromDataType(registeredTypeDefs[index]->templateSubTypes[0]); - - if( configGroup ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(registeredTypeDefs[index]); - if( group ) - *configGroup = group->groupName.AddressOf(); - else - *configGroup = 0; - } - - if( accessMask ) - *accessMask = registeredTypeDefs[index]->accessMask; - - if( nameSpace ) - *nameSpace = registeredTypeDefs[index]->nameSpace->name.AddressOf(); - - return registeredTypeDefs[index]->name.AddressOf(); + return registeredTypeDefs[index]; } // interface @@ -5627,7 +5766,7 @@ int asCScriptEngine::RegisterEnum(const char *name) return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0); // Verify if the name has been registered as a type already - if( GetRegisteredObjectType(name, defaultNamespace) ) + if( GetRegisteredType(name, defaultNamespace) ) return asALREADY_REGISTERED; // Use builder to parse the datatype @@ -5640,7 +5779,7 @@ int asCScriptEngine::RegisterEnum(const char *name) { // If it is not in the defaultNamespace then the type was successfully parsed because // it is declared in a parent namespace which shouldn't be treated as an error - if( dt.GetObjectType() && dt.GetObjectType()->nameSpace == defaultNamespace ) + if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace ) return ConfigError(asERROR, "RegisterEnum", name, 0); } @@ -5654,7 +5793,7 @@ int asCScriptEngine::RegisterEnum(const char *name) if( r < 0 ) return ConfigError(asNAME_TAKEN, "RegisterEnum", name, 0); - asCObjectType *st = asNEW(asCObjectType)(this); + asCEnumType *st = asNEW(asCEnumType)(this); if( st == 0 ) return ConfigError(asOUT_OF_MEMORY, "RegisterEnum", name, 0); @@ -5669,9 +5808,9 @@ int asCScriptEngine::RegisterEnum(const char *name) allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); registeredEnums.PushLast(st); - currentGroup->objTypes.PushLast(st); + currentGroup->types.PushLast(st); - return asSUCCESS; + return GetTypeIdByDecl(name); } // interface @@ -5689,8 +5828,8 @@ int asCScriptEngine::RegisterEnumValue(const char *typeName, const char *valueNa return ConfigError(r, "RegisterEnumValue", typeName, valueName); // Store the enum value - asCObjectType *ot = dt.GetObjectType(); - if( ot == 0 || !(ot->flags & asOBJ_ENUM) ) + asCEnumType *ot = CastToEnumType(dt.GetTypeInfo()); + if( ot == 0 ) return ConfigError(asINVALID_TYPE, "RegisterEnumValue", typeName, valueName); if( NULL == valueName ) @@ -5722,63 +5861,16 @@ int asCScriptEngine::RegisterEnumValue(const char *typeName, const char *valueNa // interface asUINT asCScriptEngine::GetEnumCount() const { - return asUINT(registeredEnums.GetLength()); + return registeredEnums.GetLength(); } // interface -const char *asCScriptEngine::GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace, const char **configGroup, asDWORD *accessMask) const +asITypeInfo *asCScriptEngine::GetEnumByIndex(asUINT index) const { if( index >= registeredEnums.GetLength() ) return 0; - if( configGroup ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(registeredEnums[index]); - if( group ) - *configGroup = group->groupName.AddressOf(); - else - *configGroup = 0; - } - - if( accessMask ) - *accessMask = registeredEnums[index]->accessMask; - - if( enumTypeId ) - *enumTypeId = GetTypeIdFromDataType(asCDataType::CreateObject(registeredEnums[index], false)); - - if( nameSpace ) - *nameSpace = registeredEnums[index]->nameSpace->name.AddressOf(); - - return registeredEnums[index]->name.AddressOf(); -} - -// interface -int asCScriptEngine::GetEnumValueCount(int enumTypeId) const -{ - asCDataType dt = GetDataTypeFromTypeId(enumTypeId); - asCObjectType *t = dt.GetObjectType(); - if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) ) - return asINVALID_TYPE; - - return (int)t->enumValues.GetLength(); -} - -// interface -const char *asCScriptEngine::GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const -{ - // TODO: This same function is implemented in as_module.cpp as well. Perhaps it should be moved to asCObjectType? - asCDataType dt = GetDataTypeFromTypeId(enumTypeId); - asCObjectType *t = dt.GetObjectType(); - if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) ) - return 0; - - if( index >= t->enumValues.GetLength() ) - return 0; - - if( outValue ) - *outValue = t->enumValues[index]->value; - - return t->enumValues[index]->name.AddressOf(); + return registeredEnums[index]; } // interface @@ -5788,7 +5880,7 @@ asUINT asCScriptEngine::GetObjectTypeCount() const } // interface -asIObjectType *asCScriptEngine::GetObjectTypeByIndex(asUINT index) const +asITypeInfo *asCScriptEngine::GetObjectTypeByIndex(asUINT index) const { if( index >= registeredObjTypes.GetLength() ) return 0; @@ -5797,28 +5889,44 @@ asIObjectType *asCScriptEngine::GetObjectTypeByIndex(asUINT index) const } // interface -asIObjectType *asCScriptEngine::GetObjectTypeByName(const char *name) const +asITypeInfo *asCScriptEngine::GetTypeInfoByName(const char *name) const { asSNameSpace *ns = defaultNamespace; - while( ns ) + while (ns) { // Check the object types - for( asUINT n = 0; n < registeredObjTypes.GetLength(); n++ ) + for (asUINT n = 0; n < registeredObjTypes.GetLength(); n++) { - if( registeredObjTypes[n]->name == name && - registeredObjTypes[n]->nameSpace == ns ) + if (registeredObjTypes[n]->name == name && + registeredObjTypes[n]->nameSpace == ns) return registeredObjTypes[n]; } // Perhaps it is a template type? In this case // the returned type will be the generic type - for( asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++ ) + for (asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++) { - if( registeredTemplateTypes[n]->name == name && - registeredTemplateTypes[n]->nameSpace == ns ) + if (registeredTemplateTypes[n]->name == name && + registeredTemplateTypes[n]->nameSpace == ns) return registeredTemplateTypes[n]; } + // Check the enum types + for (asUINT n = 0; n < registeredEnums.GetLength(); n++) + { + if (registeredEnums[n]->name == name && + registeredEnums[n]->nameSpace == ns) + return registeredEnums[n]; + } + + // Check the typedefs + for (asUINT n = 0; n < registeredTypeDefs.GetLength();n++) + { + if (registeredTypeDefs[n]->name == name && + registeredTypeDefs[n]->nameSpace == ns) + return registeredTypeDefs[n]; + } + // Recursively search parent namespace ns = GetParentNameSpace(ns); } @@ -5827,18 +5935,14 @@ asIObjectType *asCScriptEngine::GetObjectTypeByName(const char *name) const } // interface -asIObjectType *asCScriptEngine::GetObjectTypeById(int typeId) const +asITypeInfo *asCScriptEngine::GetTypeInfoById(int typeId) const { asCDataType dt = GetDataTypeFromTypeId(typeId); // Is the type id valid? - if( !dt.IsValid() ) return 0; + if (!dt.IsValid()) return 0; - // Enum types are not objects, so we shouldn't return an object type for them - if( dt.GetObjectType() && dt.GetObjectType()->GetFlags() & asOBJ_ENUM ) - return 0; - - return dt.GetObjectType(); + return dt.GetTypeInfo(); } // interface @@ -5847,12 +5951,6 @@ asIScriptFunction *asCScriptEngine::GetFunctionById(int funcId) const return GetScriptFunction(funcId); } -// interface -asIScriptFunction *asCScriptEngine::GetFuncDefFromTypeId(int typeId) const -{ - return GetDataTypeFromTypeId(typeId).GetFuncDef(); -} - // internal bool asCScriptEngine::IsTemplateType(const char *name) const { @@ -5867,43 +5965,6 @@ bool asCScriptEngine::IsTemplateType(const char *name) const return false; } -// internal -int asCScriptEngine::AddConstantString(const char *str, size_t len) -{ - // This is only called when build a script module, so it is - // known that only one thread can enter the function at a time. - asASSERT( isBuilding ); - - // The str may contain null chars, so we cannot use strlen, or strcmp, or strcpy - - // Has the string been registered before? - asSMapNode *cursor = 0; - if (stringToIdMap.MoveTo(&cursor, asCStringPointer(str, len))) - return cursor->value; - - // No match was found, add the string - asCString *cstr = asNEW(asCString)(str, len); - if( cstr ) - { - stringConstants.PushLast(cstr); - int index = (int)stringConstants.GetLength() - 1; - stringToIdMap.Insert(asCStringPointer(cstr), index); - - // The VM currently doesn't handle string ids larger than 65535 - asASSERT(stringConstants.GetLength() <= 65536); - - return index; - } - - return 0; -} - -// internal -const asCString &asCScriptEngine::GetConstantString(int id) -{ - return *stringConstants[id]; -} - // internal int asCScriptEngine::GetScriptSectionNameIndex(const char *name) { @@ -6022,23 +6083,23 @@ void asCScriptEngine::SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t c } // interface -void asCScriptEngine::SetObjectTypeUserDataCleanupCallback(asCLEANOBJECTTYPEFUNC_t callback, asPWORD type) +void asCScriptEngine::SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type) { ACQUIREEXCLUSIVE(engineRWLock); - for( asUINT n = 0; n < cleanObjectTypeFuncs.GetLength(); n++ ) + for( asUINT n = 0; n < cleanTypeInfoFuncs.GetLength(); n++ ) { - if( cleanObjectTypeFuncs[n].type == type ) + if( cleanTypeInfoFuncs[n].type == type ) { - cleanObjectTypeFuncs[n].cleanFunc = callback; + cleanTypeInfoFuncs[n].cleanFunc = callback; RELEASEEXCLUSIVE(engineRWLock); return; } } - SObjTypeClean otc = {type, callback}; - cleanObjectTypeFuncs.PushLast(otc); + STypeInfoClean otc = {type, callback}; + cleanTypeInfoFuncs.PushLast(otc); RELEASEEXCLUSIVE(engineRWLock); } @@ -6072,19 +6133,19 @@ asCObjectType *asCScriptEngine::GetListPatternType(int listPatternFuncId) // or from the factory's return type for reference types asCObjectType *ot = scriptFunctions[listPatternFuncId]->objectType; if( ot == 0 ) - ot = scriptFunctions[listPatternFuncId]->returnType.GetObjectType(); + ot = CastToObjectType(scriptFunctions[listPatternFuncId]->returnType.GetTypeInfo()); asASSERT( ot ); // Check if this object type already has a list pattern type for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) { - if( listPatternTypes[n]->templateSubTypes[0].GetObjectType() == ot ) + if( listPatternTypes[n]->templateSubTypes[0].GetTypeInfo() == ot ) return listPatternTypes[n]; } // Create a new list pattern type for the given object type asCObjectType *lpt = asNEW(asCObjectType)(this); - lpt->templateSubTypes.PushLast(asCDataType::CreateObject(ot, false)); + lpt->templateSubTypes.PushLast(asCDataType::CreateType(ot, false)); lpt->flags = asOBJ_LIST_PATTERN; listPatternTypes.PushLast(lpt); @@ -6099,7 +6160,7 @@ void asCScriptEngine::DestroyList(asBYTE *buffer, const asCObjectType *listPatte // Get the list pattern from the listFactory function // TODO: runtime optimize: Store the used list factory in the listPatternType itself // TODO: runtime optimize: Keep a flag to indicate if there is really a need to free anything - asCObjectType *ot = listPatternType->templateSubTypes[0].GetObjectType(); + asCObjectType *ot = CastToObjectType(listPatternType->templateSubTypes[0].GetTypeInfo()); asCScriptFunction *listFactory = scriptFunctions[ot->beh.listFactory]; asASSERT( listFactory ); @@ -6171,19 +6232,20 @@ void asCScriptEngine::DestroySubList(asBYTE *&buffer, asSListPatternNode *&node) dt = GetDataTypeFromTypeId(typeId); } - asCObjectType *ot = dt.GetObjectType(); - if( ot && (ot->flags & asOBJ_ENUM) == 0 ) + asCTypeInfo *ti = dt.GetTypeInfo(); + if( ti && (ti->flags & asOBJ_ENUM) == 0 ) { // Free all instances of this type - if( ot->flags & asOBJ_VALUE ) + if( ti->flags & asOBJ_VALUE ) { - asUINT size = ot->GetSize(); + asUINT size = ti->GetSize(); // Align the offset to 4 bytes boundary if( size >= 4 && (asPWORD(buffer) & 0x3) ) buffer += 4 - (asPWORD(buffer) & 0x3); - if( ot->beh.destruct ) + asCObjectType *ot = CastToObjectType(ti); + if( ot && ot->beh.destruct ) { // Only call the destructor if the object has been created // We'll assume the object has been created if any byte in @@ -6217,7 +6279,7 @@ void asCScriptEngine::DestroySubList(asBYTE *&buffer, asSListPatternNode *&node) // Call the release behaviour void *ptr = *(void**)buffer; if( ptr ) - ReleaseScriptObject(ptr, ot); + ReleaseScriptObject(ptr, ti); buffer += AS_PTR_SIZE*4; } } diff --git a/lib/angelscript/source/as_scriptengine.h b/lib/angelscript/source/as_scriptengine.h index c9a2a487f..ad82858d4 100644 --- a/lib/angelscript/source/as_scriptengine.h +++ b/lib/angelscript/source/as_scriptengine.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -86,7 +86,7 @@ public: virtual asIJITCompiler *GetJITCompiler() const; // Global functions - virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0); + virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0); virtual asUINT GetGlobalFunctionCount() const; virtual asIScriptFunction *GetGlobalFunctionByIndex(asUINT index) const; virtual asIScriptFunction *GetGlobalFunctionByDecl(const char *declaration) const; @@ -100,18 +100,16 @@ public: // Type registration virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags); - virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset); - virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0); - virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0); + virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset = 0, bool isCompositeIndirect = false); + virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); virtual int RegisterInterface(const char *name); virtual int RegisterInterfaceMethod(const char *intf, const char *declaration); virtual asUINT GetObjectTypeCount() const; - virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const; - virtual asIObjectType *GetObjectTypeByName(const char *name) const; - virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const; // String factory - virtual int RegisterStringFactory(const char *datatype, const asSFuncPtr &factoryFunc, asDWORD callConv, void *objForThiscall = 0); + virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory); virtual int GetStringFactoryReturnTypeId(asDWORD *flags) const; // Default array type @@ -119,23 +117,21 @@ public: virtual int GetDefaultArrayTypeId() const; // Enums - virtual int RegisterEnum(const char *type); - virtual int RegisterEnumValue(const char *type, const char *name, int value); - virtual asUINT GetEnumCount() const; - virtual const char *GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace, const char **configGroup = 0, asDWORD *accessMask = 0) const; - virtual int GetEnumValueCount(int enumTypeId) const; - virtual const char *GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const; + virtual int RegisterEnum(const char *type); + virtual int RegisterEnumValue(const char *type, const char *name, int value); + virtual asUINT GetEnumCount() const; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const; // Funcdefs - virtual int RegisterFuncdef(const char *decl); - virtual asUINT GetFuncdefCount() const; - virtual asIScriptFunction *GetFuncdefByIndex(asUINT index) const; + virtual int RegisterFuncdef(const char *decl); + virtual asUINT GetFuncdefCount() const; + virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const; // Typedefs // TODO: interface: Should perhaps rename this to Alias, since it doesn't really create a new type - virtual int RegisterTypedef(const char *type, const char *decl); - virtual asUINT GetTypedefCount() const; - virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace, const char **configGroup = 0, asDWORD *accessMask = 0) const; + virtual int RegisterTypedef(const char *type, const char *decl); + virtual asUINT GetTypedefCount() const; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) const; // Configuration groups virtual int BeginConfigGroup(const char *groupName); @@ -153,29 +149,26 @@ public: // Script functions virtual asIScriptFunction *GetFunctionById(int funcId) const; - virtual asIScriptFunction *GetFuncDefFromTypeId(int typeId) const; // Type identification - virtual asIObjectType *GetObjectTypeById(int typeId) const; virtual int GetTypeIdByDecl(const char *decl) const; virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const; virtual int GetSizeOfPrimitiveType(int typeId) const; + virtual asITypeInfo *GetTypeInfoById(int typeId) const; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const; // Script execution virtual asIScriptContext *CreateContext(); - virtual void *CreateScriptObject(const asIObjectType *type); - virtual void *CreateScriptObjectCopy(void *obj, const asIObjectType *type); - virtual void *CreateUninitializedScriptObject(const asIObjectType *type); + virtual void *CreateScriptObject(const asITypeInfo *type); + virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type); + virtual void *CreateUninitializedScriptObject(const asITypeInfo *type); virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj); - virtual int AssignScriptObject(void *dstObj, void *srcObj, const asIObjectType *type); - virtual void ReleaseScriptObject(void *obj, const asIObjectType *type); - virtual void AddRefScriptObject(void *obj, const asIObjectType *type); - virtual int RefCastObject(void *obj, asIObjectType *fromType, asIObjectType *toType, void **newPtr, bool useOnlyImplicitCast = false); -#ifdef AS_DEPRECATED - // Deprecated since 2.30.0, 2014-11-04 - virtual bool IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const; -#endif - virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const; + virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type); + virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type); + virtual void AddRefScriptObject(void *obj, const asITypeInfo *type); + virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false); + virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const; // Context pooling virtual asIScriptContext *RequestContext(); @@ -188,8 +181,8 @@ public: // Garbage collection virtual int GarbageCollect(asDWORD flags = asGC_FULL_CYCLE, asUINT numIterations = 1); virtual void GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const; - virtual int NotifyGarbageCollectorOfNewObject(void *obj, asIObjectType *type); - virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj = 0, asIObjectType **type = 0); + virtual int NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type); + virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj = 0, asITypeInfo **type = 0); virtual void GCEnumCallback(void *reference); // User data @@ -199,7 +192,7 @@ public: virtual void SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type); virtual void SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type); virtual void SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type); - virtual void SetObjectTypeUserDataCleanupCallback(asCLEANOBJECTTYPEFUNC_t callback, asPWORD type); + virtual void SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type); virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type); //=========================================================== @@ -219,8 +212,8 @@ public: friend class asCByteCode; friend int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine); - int RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0); - int RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall); + int RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + int RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); int VerifyVarTypeNotInFunction(asCScriptFunction *func); @@ -241,18 +234,18 @@ public: void *CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const; void CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; bool CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; + int CallScriptObjectMethod(void *obj, int func); void ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type); void DeleteDiscardedModules(); void RemoveTemplateInstanceType(asCObjectType *t); - void RemoveTypeAndRelatedFromList(asCMap &types, asCObjectType *ot); asCConfigGroup *FindConfigGroupForFunction(int funcId) const; asCConfigGroup *FindConfigGroupForGlobalVar(int gvarId) const; - asCConfigGroup *FindConfigGroupForObjectType(const asCObjectType *type) const; - asCConfigGroup *FindConfigGroupForFuncDef(const asCScriptFunction *funcDef) const; + asCConfigGroup *FindConfigGroupForTypeInfo(const asCTypeInfo *type) const; + asCConfigGroup *FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const; int RequestBuild(); void BuildCompleted(); @@ -262,7 +255,7 @@ public: int CreateContext(asIScriptContext **context, bool isInternal); - asCObjectType *GetRegisteredObjectType(const asCString &name, asSNameSpace *ns) const; + asCTypeInfo *GetRegisteredType(const asCString &name, asSNameSpace *ns) const; asCObjectType *GetListPatternType(int listPatternFuncId); void DestroyList(asBYTE *buffer, const asCObjectType *listPatternType); @@ -283,29 +276,28 @@ public: int GetNextScriptFunctionId(); void AddScriptFunction(asCScriptFunction *func); void RemoveScriptFunction(asCScriptFunction *func); - void RemoveFuncdef(asCScriptFunction *func); + void RemoveFuncdef(asCFuncdefType *func); int ConfigError(int err, const char *funcName, const char *arg1, const char *arg2); int GetTypeIdFromDataType(const asCDataType &dt) const; asCDataType GetDataTypeFromTypeId(int typeId) const; asCObjectType *GetObjectTypeFromTypeId(int typeId) const; - void RemoveFromTypeIdMap(asCObjectType *type); + void RemoveFromTypeIdMap(asCTypeInfo *type); bool IsTemplateType(const char *name) const; + int SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl); asCObjectType *GetTemplateInstanceType(asCObjectType *templateType, asCArray &subTypes, asCModule *requestingModule); asCScriptFunction *GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *templateInstanceType, int origFactoryId); bool GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *templateInstanceType, asCScriptFunction *templateFunc, asCScriptFunction **newFunc); + asCFuncdefType *GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *templateInstanceType, asCFuncdefType *templateFuncdef); asCDataType DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot); bool RequireTypeReplacement(asCDataType &type, asCObjectType *templateType); - asCModule *FindNewOwnerForSharedType(asCObjectType *type, asCModule *mod); + asCModule *FindNewOwnerForSharedType(asCTypeInfo *type, asCModule *mod); asCModule *FindNewOwnerForSharedFunc(asCScriptFunction *func, asCModule *mod); - // String constants - // TODO: Must free unused string constants, thus the ref count for each must be tracked - int AddConstantString(const char *str, size_t length); - const asCString &GetConstantString(int id); + asCFuncdefType *FindMatchingFuncdef(asCScriptFunction *func, asCModule *mod); // Global property management asCGlobalProperty *AllocateGlobalProperty(); @@ -330,24 +322,26 @@ public: asCObjectType functionBehaviours; // Registered interface - asCArray registeredObjTypes; - asCArray registeredTypeDefs; - asCArray registeredEnums; - asCSymbolTable registeredGlobalProps; // increases ref count // TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used + asCArray registeredObjTypes; // doesn't increase ref count + asCArray registeredTypeDefs; // doesn't increase ref count + asCArray registeredEnums; // doesn't increase ref count + // TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used for global props + asCSymbolTable registeredGlobalProps; // increases ref count asCSymbolTable registeredGlobalFuncs; - asCArray registeredFuncDefs; - asCArray registeredTemplateTypes; - asCScriptFunction *stringFactory; + asCArray registeredFuncDefs; // doesn't increase ref count + asCArray registeredTemplateTypes; // doesn't increase ref count + asIStringFactory *stringFactory; + asCDataType stringType; bool configFailed; - // Stores all registered types except funcdefs - asCMap allRegisteredTypes; // increases ref count + // Stores all registered types + asCMap allRegisteredTypes; // increases ref count - // Dummy types used to name the subtypes in the template objects - asCArray templateSubTypes; + // Dummy types used to name the subtypes in the template objects + asCArray templateSubTypes; // Store information about template types - // This list will contain all instances of templates, both registered specialized + // This list will contain all instances of templates, both registered specialized // types and those automacially instantiated from scripts asCArray templateInstanceTypes; // increases ref count @@ -378,7 +372,7 @@ public: // This array holds all live script modules asCArray scriptModules; // Synchronized with engineRWLock - // This is a pointer to the last module that was requested. It is used for performance + // This is a pointer to the last module that was requested. It is used for performance // improvement, since it is common that the same module is accessed many times in a row asCModule *lastModule; // Synchronized with engineRWLock @@ -389,29 +383,28 @@ public: // This array holds modules that have been discard (thus are no longer visible to the application) // but cannot yet be deleted due to having external references to some of the entities in them asCArray discardedModules; - // This flag is set to true during compilations of scripts (or loading pre-compiled scripts) - // to delay the validation of template types until the subtypes have been fully declared + // This flag is set to true during compilations of scripts (or loading pre-compiled scripts) + // to delay the validation of template types until the subtypes have been fully declared bool deferValidationOfTemplateTypes; // Tokenizer is instantiated once to share resources asCTokenizer tok; // Stores shared script declared types (classes, interfaces, enums) - asCArray sharedScriptTypes; // increases ref count + asCArray sharedScriptTypes; // increases ref count // This array stores the template instances types that have been automatically generated from template types asCArray generatedTemplateTypes; // Stores the funcdefs // TODO: redesign: Only shared funcdefs should be stored here // a funcdef becomes shared if all arguments and the return type are shared (or application registered) - asCArray funcDefs; // doesn't increase ref count + asCArray funcDefs; // doesn't increases ref count // Stores the names of the script sections for debugging purposes asCArray scriptSectionNames; // Type identifiers mutable int typeIdSeqNbr; - mutable asCMap mapTypeIdToObjectType; - mutable asCMap mapTypeIdToFunction; + mutable asCMap mapTypeIdToTypeInfo; // Garbage collector asCGarbageCollector gc; @@ -441,16 +434,10 @@ public: asIJITCompiler *jitCompiler; // Namespaces - // These are shared between all entities and are + // These are shared between all entities and are // only deleted once the engine is destroyed asCArray nameSpaces; - // String constants - // These are shared between all scripts and are - // only deleted once the engine is destroyed - asCArray stringConstants; - asCMap stringToIdMap; - // Callbacks for context pooling asREQUESTCONTEXTFUNC_t requestCtxFunc; asRETURNCONTEXTFUNC_t returnCtxFunc; @@ -459,16 +446,16 @@ public: // User data asCArray userData; - struct SEngineClean { asPWORD type; asCLEANENGINEFUNC_t cleanFunc; }; + struct SEngineClean { asPWORD type; asCLEANENGINEFUNC_t cleanFunc; }; asCArray cleanEngineFuncs; - struct SModuleClean { asPWORD type; asCLEANMODULEFUNC_t cleanFunc; }; + struct SModuleClean { asPWORD type; asCLEANMODULEFUNC_t cleanFunc; }; asCArray cleanModuleFuncs; - struct SContextClean { asPWORD type; asCLEANCONTEXTFUNC_t cleanFunc; }; + struct SContextClean { asPWORD type; asCLEANCONTEXTFUNC_t cleanFunc; }; asCArray cleanContextFuncs; - struct SFunctionClean { asPWORD type; asCLEANFUNCTIONFUNC_t cleanFunc; }; + struct SFunctionClean { asPWORD type; asCLEANFUNCTIONFUNC_t cleanFunc; }; asCArray cleanFunctionFuncs; - struct SObjTypeClean { asPWORD type; asCLEANOBJECTTYPEFUNC_t cleanFunc; }; - asCArray cleanObjectTypeFuncs; + struct STypeInfoClean { asPWORD type; asCLEANTYPEINFOFUNC_t cleanFunc; }; + asCArray cleanTypeInfoFuncs; struct SScriptObjClean { asPWORD type; asCLEANSCRIPTOBJECTFUNC_t cleanFunc; }; asCArray cleanScriptObjectFuncs; @@ -504,12 +491,15 @@ public: bool disallowEmptyListElements; // TODO: 3.0.0: Remove the privatePropAsProtected bool privatePropAsProtected; + bool allowUnicodeIdentifiers; + int heredocTrimMode; + asUINT maxNestedCalls; } ep; // This flag is to allow a quicker shutdown when releasing the engine bool shuttingDown; - // This flag is set when the engine's destructor is called, this is to + // This flag is set when the engine's destructor is called, this is to // avoid recursive calls if an object happens to increment/decrement // the ref counter during shutdown bool inDestructor; diff --git a/lib/angelscript/source/as_scriptfunction.cpp b/lib/angelscript/source/as_scriptfunction.cpp index efb4a5c07..d007a477b 100644 --- a/lib/angelscript/source/as_scriptfunction.cpp +++ b/lib/angelscript/source/as_scriptfunction.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -123,7 +123,7 @@ void RegisterScriptFunction(asCScriptEngine *engine) int r = 0; UNUSED_VAR(r); // It is only used in debug mode engine->functionBehaviours.engine = engine; - engine->functionBehaviours.flags = asOBJ_REF | asOBJ_GC | asOBJ_SCRIPT_FUNCTION; + engine->functionBehaviours.flags = asOBJ_REF | asOBJ_GC; engine->functionBehaviours.name = "$func"; #ifndef AS_MAX_PORTABILITY r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptFunction,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 ); @@ -163,7 +163,7 @@ void RegisterScriptFunction(asCScriptEngine *engine) engine->registeredGlobalFuncs.Put(engine->scriptFunctions[r]); // Change the return type so the VM will know the function really returns a handle - engine->scriptFunctions[r]->returnType = asCDataType::CreateObject(&engine->functionBehaviours, false); + engine->scriptFunctions[r]->returnType = asCDataType::CreateType(&engine->functionBehaviours, false); engine->scriptFunctions[r]->returnType.MakeHandle(true); } @@ -205,6 +205,15 @@ void asCScriptFunction::MakeDelegate(asCScriptFunction *func, void *obj) dontCleanUpOnException = true; } +// interface +void *asCScriptFunction::GetAuxiliary() const +{ + if (sysFuncIntf) + return sysFuncIntf->auxiliary; + + return 0; +} + // interface void *asCScriptFunction::GetDelegateObject() const { @@ -212,7 +221,7 @@ void *asCScriptFunction::GetDelegateObject() const } // interface -asIObjectType *asCScriptFunction::GetDelegateObjectType() const +asITypeInfo *asCScriptFunction::GetDelegateObjectType() const { if( objForDelegate == 0 || funcForDelegate == 0 ) return 0; @@ -297,7 +306,7 @@ int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char asCBuilder builder(engine, 0); asCScriptCode code; code.SetCode("", decl, 0, false); - dt = builder.CreateDataTypeFromNode(listNodes, &code, engine->defaultNamespace, false, returnType.GetObjectType()); + dt = builder.CreateDataTypeFromNode(listNodes, &code, engine->defaultNamespace, false, CastToObjectType(returnType.GetTypeInfo())); node->next = asNEW(asSListPatternDataTypeNode)(dt); node = node->next; @@ -350,11 +359,6 @@ asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, as module = mod; objectType = 0; name = ""; - isReadOnly = false; - isPrivate = false; - isProtected = false; - isFinal = false; - isOverride = false; sysFuncIntf = 0; signatureId = 0; dontCleanUpOnException = false; @@ -363,11 +367,11 @@ asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, as userData = 0; id = 0; accessMask = 0xFFFFFFFF; - isShared = false; nameSpace = engine->nameSpaces[0]; objForDelegate = 0; funcForDelegate = 0; listPattern = 0; + funcdefType = 0; if( funcType == asFUNC_SCRIPT ) AllocateScriptFunctionData(); @@ -552,7 +556,7 @@ int asCScriptFunction::ReleaseInternal() int asCScriptFunction::GetTypeId() const { // This const cast is ok, the object won't be modified - asCDataType dt = asCDataType::CreateFuncDef(const_cast(this)); + asCDataType dt = asCDataType::CreateType(engine->FindMatchingFuncdef(const_cast(this), 0), false); return engine->GetTypeIdFromDataType(dt); } @@ -562,10 +566,10 @@ bool asCScriptFunction::IsCompatibleWithTypeId(int typeId) const asCDataType dt = engine->GetDataTypeFromTypeId(typeId); // Make sure the type is a function - asCScriptFunction *func = dt.GetFuncDef(); - if( func == 0 ) + if (!dt.IsFuncdef()) return false; + asCScriptFunction *func = CastToFuncdefType(dt.GetTypeInfo())->funcdef; if( !IsSignatureExceptNameEqual(func) ) return false; @@ -594,7 +598,7 @@ asIScriptModule *asCScriptFunction::GetModule() const } // interface -asIObjectType *asCScriptFunction::GetObjectType() const +asITypeInfo *asCScriptFunction::GetObjectType() const { return objectType; } @@ -617,25 +621,28 @@ const char *asCScriptFunction::GetName() const // interface const char *asCScriptFunction::GetNamespace() const { - return nameSpace->name.AddressOf(); + if (nameSpace) + return nameSpace->name.AddressOf(); + + return 0; } // interface bool asCScriptFunction::IsReadOnly() const { - return isReadOnly; + return traits.GetTrait(asTRAIT_CONST); } // interface bool asCScriptFunction::IsPrivate() const { - return isPrivate; + return traits.GetTrait(asTRAIT_PRIVATE); } // interface bool asCScriptFunction::IsProtected() const { - return isProtected; + return traits.GetTrait(asTRAIT_PROTECTED); } // internal @@ -658,8 +665,8 @@ int asCScriptFunction::GetSpaceNeededForReturnValue() // internal bool asCScriptFunction::DoesReturnOnStack() const { - if( returnType.GetObjectType() && - (returnType.GetObjectType()->flags & asOBJ_VALUE) && + if( returnType.GetTypeInfo() && + (returnType.GetTypeInfo()->flags & asOBJ_VALUE) && !returnType.IsReference() ) return true; @@ -692,6 +699,16 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl else str += "_unnamed_type_::"; } + else if (funcdefType && funcdefType->parentClass && includeObjectName) + { + if (includeNamespace && funcdefType->parentClass->nameSpace->name != "") + str += funcdefType->parentClass->nameSpace->name + "::"; + + if (funcdefType->parentClass->name != "") + str += funcdefType->parentClass->name + "::"; + else + str += "_unnamed_type_::"; + } else if( includeNamespace && nameSpace->name != "" ) { str += nameSpace->name + "::"; @@ -703,7 +720,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl if( name[4] == '0' + asBEHAVE_CONSTRUCT ) str += objectType->name + "("; else if( name[4] == '0' + asBEHAVE_FACTORY ) - str += returnType.GetObjectType()->name + "("; + str += returnType.GetTypeInfo()->name + "("; else if( name[4] == '0' + asBEHAVE_DESTRUCT ) str += "~" + objectType->name + "("; else @@ -766,7 +783,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl str += ")"; - if( isReadOnly ) + if( IsReadOnly() ) str += " const"; // Add the declaration of the list pattern @@ -923,17 +940,17 @@ asUINT asCScriptFunction::GetVarCount() const } // interface -int asCScriptFunction::GetVar(asUINT index, const char **name, int *typeId) const +int asCScriptFunction::GetVar(asUINT index, const char **out_name, int *out_typeId) const { if( scriptData == 0 ) return asNOT_SUPPORTED; if( index >= scriptData->variables.GetLength() ) return asINVALID_ARG; - if( name ) - *name = scriptData->variables[index]->name.AddressOf(); - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(scriptData->variables[index]->type); + if( out_name ) + *out_name = scriptData->variables[index]->name.AddressOf(); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(scriptData->variables[index]->type); return asSUCCESS; } @@ -952,7 +969,7 @@ const char *asCScriptFunction::GetVarDecl(asUINT index, bool includeNamespace) c } // internal -void asCScriptFunction::AddVariable(asCString &name, asCDataType &type, int stackOffset) +void asCScriptFunction::AddVariable(asCString &in_name, asCDataType &in_type, int in_stackOffset) { asASSERT( scriptData ); asSScriptVariable *var = asNEW(asSScriptVariable); @@ -961,15 +978,15 @@ void asCScriptFunction::AddVariable(asCString &name, asCDataType &type, int stac // Out of memory return; } - var->name = name; - var->type = type; - var->stackOffset = stackOffset; + var->name = in_name; + var->type = in_type; + var->stackOffset = in_stackOffset; var->declaredAtProgramPos = 0; scriptData->variables.PushLast(var); } // internal -asCObjectType *asCScriptFunction::GetObjectTypeOfLocalVar(short varOffset) +asCTypeInfo *asCScriptFunction::GetTypeInfoOfLocalVar(short varOffset) { asASSERT( scriptData ); @@ -1015,7 +1032,7 @@ bool asCScriptFunction::IsSignatureEqual(const asCScriptFunction *func) const // internal bool asCScriptFunction::IsSignatureExceptNameEqual(const asCScriptFunction *func) const { - return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, func->objectType, func->isReadOnly); + return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, func->objectType, func->IsReadOnly()); } // internal @@ -1029,19 +1046,19 @@ bool asCScriptFunction::IsSignatureExceptNameEqual(const asCDataType &retType, c // internal bool asCScriptFunction::IsSignatureExceptNameAndObjectTypeEqual(const asCScriptFunction *func) const { - return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, objectType, isReadOnly); + return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, objectType, IsReadOnly()); } // internal bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCScriptFunction *func) const { - return IsSignatureExceptNameAndReturnTypeEqual(func->parameterTypes, func->inOutFlags, func->objectType, func->isReadOnly); + return IsSignatureExceptNameAndReturnTypeEqual(func->parameterTypes, func->inOutFlags, func->objectType, func->IsReadOnly()); } // internal bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCArray ¶mTypes, const asCArray ¶mInOut, const asCObjectType *objType, bool readOnly) const { - if( this->isReadOnly != readOnly ) return false; + if( this->IsReadOnly() != readOnly ) return false; if( (this->objectType != 0) != (objType != 0) ) return false; if( this->inOutFlags != paramInOut ) return false; if( this->parameterTypes != paramTypes ) return false; @@ -1062,20 +1079,20 @@ void asCScriptFunction::AddReferences() // Only count references if there is any bytecode if( scriptData && scriptData->byteCode.GetLength() ) { - if( returnType.GetObjectType() ) + if( returnType.GetTypeInfo() ) { - returnType.GetObjectType()->AddRefInternal(); + returnType.GetTypeInfo()->AddRefInternal(); - asCConfigGroup *group = engine->FindConfigGroupForObjectType(returnType.GetObjectType()); + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(returnType.GetTypeInfo()); if( group != 0 ) group->AddRef(); } for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) - if( parameterTypes[p].GetObjectType() ) + if( parameterTypes[p].GetTypeInfo() ) { - parameterTypes[p].GetObjectType()->AddRefInternal(); + parameterTypes[p].GetTypeInfo()->AddRefInternal(); - asCConfigGroup *group = engine->FindConfigGroupForObjectType(parameterTypes[p].GetObjectType()); + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(parameterTypes[p].GetTypeInfo()); if( group != 0 ) group->AddRef(); } @@ -1084,7 +1101,7 @@ void asCScriptFunction::AddReferences() { scriptData->objVariableTypes[v]->AddRefInternal(); - asCConfigGroup *group = engine->FindConfigGroupForObjectType(scriptData->objVariableTypes[v]); + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(scriptData->objVariableTypes[v]); if( group != 0 ) group->AddRef(); } @@ -1135,7 +1152,31 @@ void asCScriptFunction::AddReferences() void *gvarPtr = (void*)asBC_PTRARG(&bc[n]); if( !gvarPtr ) break; asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr); - if( !prop ) break; + + if (!prop) + { + // The pointer is a string constant. In order to make sure the correct resource + // management is maintained we request a new string constant here, so the compiler + // or bytecode loader can release its copy afterwards. + asCString str; + asUINT length; + int r = engine->stringFactory->GetRawStringData(gvarPtr, 0, &length); + if (r >= 0) + { + str.SetLength(length); + engine->stringFactory->GetRawStringData(gvarPtr, str.AddressOf(), &length); + + // Get a new pointer (depending on the string factory implementation it may actually be the same) + gvarPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), length)); + asBC_PTRARG(&bc[n]) = (asPWORD)gvarPtr; + } + + // If we get an error from the string factory there is not + // anything we can do about it, except report a message. + // TODO: NEWSTRING: Write a message and then exit gracefully + asASSERT(r >= 0); + break; + } // Only addref the properties once if( !ptrs.Exists(gvarPtr) ) @@ -1195,20 +1236,20 @@ void asCScriptFunction::ReleaseReferences() // Only count references if there is any bytecode if( scriptData && scriptData->byteCode.GetLength() ) { - if( returnType.GetObjectType() ) + if( returnType.GetTypeInfo() ) { - returnType.GetObjectType()->ReleaseInternal(); + returnType.GetTypeInfo()->ReleaseInternal(); - asCConfigGroup *group = engine->FindConfigGroupForObjectType(returnType.GetObjectType()); + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(returnType.GetTypeInfo()); if( group != 0 ) group->Release(); } for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) - if( parameterTypes[p].GetObjectType() ) + if( parameterTypes[p].GetTypeInfo() ) { - parameterTypes[p].GetObjectType()->ReleaseInternal(); + parameterTypes[p].GetTypeInfo()->ReleaseInternal(); - asCConfigGroup *group = engine->FindConfigGroupForObjectType(parameterTypes[p].GetObjectType()); + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(parameterTypes[p].GetTypeInfo()); if( group != 0 ) group->Release(); } @@ -1217,7 +1258,7 @@ void asCScriptFunction::ReleaseReferences() { scriptData->objVariableTypes[v]->ReleaseInternal(); - asCConfigGroup *group = engine->FindConfigGroupForObjectType(scriptData->objVariableTypes[v]); + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(scriptData->objVariableTypes[v]); if( group != 0 ) group->Release(); } @@ -1276,7 +1317,21 @@ void asCScriptFunction::ReleaseReferences() void *gvarPtr = (void*)asBC_PTRARG(&bc[n]); if( !gvarPtr ) break; asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr); - if( !prop ) break; + + if (!prop) + { + // The pointer is a string constant, so it needs to be released by the string factory + int r = engine->stringFactory->ReleaseStringConstant(gvarPtr); + UNUSED_VAR(r); + + // If we get an error from the string factory there is not + // anything we can do about it, except report a message. + // TODO: Write a message showing that the string couldn't be + // released. Include the first 10 characters and the length + // to make it easier to identify which string it was + asASSERT(r >= 0); + break; + } // Only release the properties once if( !ptrs.Exists(gvarPtr) ) @@ -1376,57 +1431,40 @@ asUINT asCScriptFunction::GetParamCount() const } // interface -int asCScriptFunction::GetParam(asUINT index, int *typeId, asDWORD *flags, const char **name, const char **defaultArg) const +int asCScriptFunction::GetParam(asUINT index, int *out_typeId, asDWORD *out_flags, const char **out_name, const char **out_defaultArg) const { if( index >= parameterTypes.GetLength() ) return asINVALID_ARG; - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(parameterTypes[index]); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(parameterTypes[index]); - if( flags ) + if( out_flags ) { - *flags = inOutFlags[index]; - *flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0; + *out_flags = inOutFlags[index]; + *out_flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0; } - if( name ) + if( out_name ) { // The parameter names are not stored if loading from bytecode without debug information if( index < parameterNames.GetLength() ) - *name = parameterNames[index].AddressOf(); + *out_name = parameterNames[index].AddressOf(); else - *name = 0; + *out_name = 0; } - if( defaultArg ) + if( out_defaultArg ) { if( index < defaultArgs.GetLength() && defaultArgs[index] ) - *defaultArg = defaultArgs[index]->AddressOf(); + *out_defaultArg = defaultArgs[index]->AddressOf(); else - *defaultArg = 0; + *out_defaultArg = 0; } return asSUCCESS; } -#ifdef AS_DEPRECATED -// Deprecated since 2014-04-06, 2.29.0 -int asCScriptFunction::GetParamTypeId(asUINT index, asDWORD *flags) const -{ - if( index >= parameterTypes.GetLength() ) - return asINVALID_ARG; - - if( flags ) - { - *flags = inOutFlags[index]; - *flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0; - } - - return engine->GetTypeIdFromDataType(parameterTypes[index]); -} -#endif - // interface asIScriptEngine *asCScriptFunction::GetEngine() const { @@ -1457,7 +1495,7 @@ const char *asCScriptFunction::GetConfigGroup() const if( funcType != asFUNC_FUNCDEF ) group = engine->FindConfigGroupForFunction(id); else - group = engine->FindConfigGroupForFuncDef(this); + group = engine->FindConfigGroupForFuncDef(this->funcdefType); if( group == 0 ) return 0; @@ -1655,20 +1693,23 @@ bool asCScriptFunction::IsShared() const asASSERT( objectType == 0 || objectType->engine == engine || objectType->engine == 0 ); if( objectType && (objectType->flags & asOBJ_SHARED) ) return true; + // funcdefs that are registered by the application are shared + if (funcType == asFUNC_FUNCDEF && module == 0) return true; + // Functions that have been specifically marked as shared are shared - return isShared; + return traits.GetTrait(asTRAIT_SHARED); } // internal bool asCScriptFunction::IsFinal() const { - return isFinal; + return traits.GetTrait(asTRAIT_FINAL); } // internal bool asCScriptFunction::IsOverride() const { - return isOverride; + return traits.GetTrait(asTRAIT_OVERRIDE); } END_AS_NAMESPACE diff --git a/lib/angelscript/source/as_scriptfunction.h b/lib/angelscript/source/as_scriptfunction.h index 1ab9a75e3..167af4de9 100644 --- a/lib/angelscript/source/as_scriptfunction.h +++ b/lib/angelscript/source/as_scriptfunction.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -53,6 +53,7 @@ class asCModule; class asCConfigGroup; class asCGlobalProperty; class asCScriptNode; +class asCFuncdefType; struct asSNameSpace; struct asSScriptVariable @@ -96,17 +97,39 @@ enum asEObjVarInfoOption asBLOCK_END }; +enum asEFuncTrait +{ + asTRAIT_CONSTRUCTOR = 1, + asTRAIT_DESTRUCTOR = 2, + asTRAIT_CONST = 4, + asTRAIT_PRIVATE = 8, + asTRAIT_PROTECTED = 16, + asTRAIT_FINAL = 32, + asTRAIT_OVERRIDE = 64, + asTRAIT_SHARED = 128, + asTRAIT_EXTERNAL = 256 +}; + +struct asSFunctionTraits +{ + asSFunctionTraits() : traits(0) {} + void SetTrait(asEFuncTrait trait, bool set) { if (set) traits |= trait; else traits &= ~trait; } + bool GetTrait(asEFuncTrait trait) const { return (traits & trait) ? true : false; } +protected: + asDWORD traits; +}; + struct asSObjectVariableInfo { - asUINT programPos; - int variableOffset; - asUINT option; + asUINT programPos; + int variableOffset; + asEObjVarInfoOption option; }; struct asSSystemFunctionInterface; -// TODO: Might be interesting to allow enumeration of accessed global variables, and -// also functions/methods that are being called. This could be used to build a +// TODO: Might be interesting to allow enumeration of accessed global variables, and +// also functions/methods that are being called. This could be used to build a // code database with call graphs, etc. void RegisterScriptFunction(asCScriptEngine *engine); @@ -129,9 +152,10 @@ public: const char *GetScriptSectionName() const; const char *GetConfigGroup() const; asDWORD GetAccessMask() const; + void *GetAuxiliary() const; // Function signature - asIObjectType *GetObjectType() const; + asITypeInfo *GetObjectType() const; const char *GetObjectName() const; const char *GetName() const; const char *GetNamespace() const; @@ -144,19 +168,15 @@ public: bool IsShared() const; asUINT GetParamCount() const; int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const; -#ifdef AS_DEPRECATED - // Deprecated, since 2.29.0, 2014-04-06 - int GetParamTypeId(asUINT index, asDWORD *flags = 0) const; -#endif int GetReturnTypeId(asDWORD *flags = 0) const; - // Type id for function pointers + // Type id for function pointers int GetTypeId() const; bool IsCompatibleWithTypeId(int typeId) const; // Delegates void *GetDelegateObject() const; - asIObjectType *GetDelegateObjectType() const; + asITypeInfo *GetDelegateObjectType() const; asIScriptFunction *GetDelegateFunction() const; // Debug information @@ -176,10 +196,17 @@ public: //----------------------------------- // Internal methods + void SetShared(bool set) {traits.SetTrait(asTRAIT_SHARED, set);} + void SetReadOnly(bool set) { traits.SetTrait(asTRAIT_CONST, set); } + void SetFinal(bool set) { traits.SetTrait(asTRAIT_FINAL, set); } + void SetOverride(bool set) { traits.SetTrait(asTRAIT_OVERRIDE, set); } + void SetProtected(bool set) { traits.SetTrait(asTRAIT_PROTECTED, set); } + void SetPrivate(bool set) { traits.SetTrait(asTRAIT_PRIVATE, set); } + asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType funcType); ~asCScriptFunction(); - // Keep an internal reference counter to separate references coming from + // Keep an internal reference counter to separate references coming from // application or script objects and references coming from the script code int AddRefInternal(); int ReleaseInternal(); @@ -210,7 +237,7 @@ public: bool IsSignatureExceptNameAndReturnTypeEqual(const asCArray ¶mTypes, const asCArray &inOutFlags, const asCObjectType *type, bool isReadOnly) const; bool IsSignatureExceptNameAndObjectTypeEqual(const asCScriptFunction *func) const; - asCObjectType *GetObjectTypeOfLocalVar(short varOffset); + asCTypeInfo *GetTypeInfoOfLocalVar(short varOffset); void MakeDelegate(asCScriptFunction *func, void *obj); @@ -255,11 +282,7 @@ public: asCArray parameterNames; asCArray inOutFlags; asCArray defaultArgs; - bool isReadOnly; - bool isPrivate; - bool isProtected; - bool isFinal; - bool isOverride; + asSFunctionTraits traits; asCObjectType *objectType; int signatureId; @@ -267,10 +290,14 @@ public: asEFuncType funcType; asDWORD accessMask; - bool isShared; + // Namespace will be null for funcdefs that are declared as child funcdefs + // of a class. In this case the namespace shall be taken from the parentClass + // in the funcdefType asSNameSpace *nameSpace; + asCFuncdefType *funcdefType; // Doesn't increase refCount + // Used by asFUNC_DELEGATE void *objForDelegate; asCScriptFunction *funcForDelegate; @@ -289,8 +316,7 @@ public: // These hold information on objects and function pointers, including temporary // variables used by exception handler and when saving bytecode - asCArray objVariableTypes; - asCArray funcVariableTypes; + asCArray objVariableTypes; asCArray objVariablePos; // The first variables in above array are allocated on the heap, the rest on the stack. diff --git a/lib/angelscript/source/as_scriptnode.cpp b/lib/angelscript/source/as_scriptnode.cpp index 8ab4454d1..9bd9cfd2b 100644 --- a/lib/angelscript/source/as_scriptnode.cpp +++ b/lib/angelscript/source/as_scriptnode.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2012 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -60,13 +60,13 @@ void asCScriptNode::Destroy(asCScriptEngine *engine) { // Destroy all children asCScriptNode *node = firstChild; - asCScriptNode *next; + asCScriptNode *nxt; while( node ) { - next = node->next; + nxt = node->next; node->Destroy(engine); - node = next; + node = nxt; } // Return the memory to the memory manager diff --git a/lib/angelscript/source/as_scriptnode.h b/lib/angelscript/source/as_scriptnode.h index 66f7bac03..4f32c92d2 100644 --- a/lib/angelscript/source/as_scriptnode.h +++ b/lib/angelscript/source/as_scriptnode.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -89,7 +89,8 @@ enum eScriptNode snNamespace, snMixin, snListPattern, - snNamedArgument + snNamedArgument, + snScope }; struct sToken diff --git a/lib/angelscript/source/as_scriptobject.cpp b/lib/angelscript/source/as_scriptobject.cpp index 80af81e83..21c8cc8c6 100644 --- a/lib/angelscript/source/as_scriptobject.cpp +++ b/lib/angelscript/source/as_scriptobject.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -271,13 +271,13 @@ asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize) asCObjectProperty *prop = objType->properties[n]; if( prop->type.IsObject() && !prop->type.IsObjectHandle() ) { - if( prop->type.IsReference() || prop->type.GetObjectType()->flags & asOBJ_REF ) + if( prop->type.IsReference() || prop->type.GetTypeInfo()->flags & asOBJ_REF ) { asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); - if( prop->type.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT ) - *ptr = (asPWORD)ScriptObjectFactory(prop->type.GetObjectType(), ot->engine); + if( prop->type.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT ) + *ptr = (asPWORD)ScriptObjectFactory(prop->type.GetTypeInfo(), ot->engine); else - *ptr = (asPWORD)AllocateUninitializedObject(prop->type.GetObjectType(), ot->engine); + *ptr = (asPWORD)AllocateUninitializedObject(prop->type.GetTypeInfo(), ot->engine); } } } @@ -292,10 +292,10 @@ asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize) asCObjectProperty *prop = objType->properties[n]; if( prop->type.IsObject() && !prop->type.IsObjectHandle() ) { - if( prop->type.IsReference() || (prop->type.GetObjectType()->flags & asOBJ_REF) ) + if( prop->type.IsReference() || (prop->type.GetTypeInfo()->flags & asOBJ_REF) ) { asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); - *ptr = (asPWORD)AllocateUninitializedObject(prop->type.GetObjectType(), engine); + *ptr = (asPWORD)AllocateUninitializedObject(CastToObjectType(prop->type.GetTypeInfo()), engine); } } } @@ -359,7 +359,7 @@ asCScriptObject::~asCScriptObject() if( prop->type.IsObject() ) { // Destroy the object - asCObjectType *propType = prop->type.GetObjectType(); + asCObjectType *propType = CastToObjectType(prop->type.GetTypeInfo()); if( prop->type.IsReference() || propType->flags & asOBJ_REF ) { void **ptr = (void**)(((char*)this) + prop->byteOffset); @@ -381,6 +381,16 @@ asCScriptObject::~asCScriptObject() engine->CallObjectMethod(ptr, propType->beh.destruct); } } + else if( prop->type.IsFuncdef() ) + { + // Release the function descriptor + asCScriptFunction **ptr = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + if (*ptr) + { + (*ptr)->Release(); + *ptr = 0; + } + } } objType->Release(); @@ -647,7 +657,7 @@ void asCScriptObject::CallDestructor() } } -asIObjectType *asCScriptObject::GetObjectType() const +asITypeInfo *asCScriptObject::GetObjectType() const { return objType; } @@ -670,7 +680,7 @@ bool asCScriptObject::GetFlag() // interface int asCScriptObject::GetTypeId() const { - asCDataType dt = asCDataType::CreateObject(objType, false); + asCDataType dt = asCDataType::CreateType(objType, false); return objType->engine->GetTypeIdFromDataType(dt); } @@ -703,7 +713,7 @@ void *asCScriptObject::GetAddressOfProperty(asUINT prop) // Objects are stored by reference, so this must be dereferenced asCDataType *dt = &objType->properties[prop]->type; if( dt->IsObject() && !dt->IsObjectHandle() && - (dt->IsReference() || dt->GetObjectType()->flags & asOBJ_REF) ) + (dt->IsReference() || dt->GetTypeInfo()->flags & asOBJ_REF) ) return *(void**)(((char*)this) + objType->properties[prop]->byteOffset); return (void*)(((char*)this) + objType->properties[prop]->byteOffset); @@ -715,19 +725,21 @@ void asCScriptObject::EnumReferences(asIScriptEngine *engine) for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) { asCObjectProperty *prop = objType->properties[n]; + void *ptr = 0; if( prop->type.IsObject() ) { // TODO: gc: The members of the value type needs to be enumerated // too, since the value type may be holding a reference. - void *ptr; - if( prop->type.IsReference() || (prop->type.GetObjectType()->flags & asOBJ_REF) ) + if( prop->type.IsReference() || (prop->type.GetTypeInfo()->flags & asOBJ_REF) ) ptr = *(void**)(((char*)this) + prop->byteOffset); else ptr = (void*)(((char*)this) + prop->byteOffset); - - if( ptr ) - ((asCScriptEngine*)engine)->GCEnumCallback(ptr); } + else if (prop->type.IsFuncdef()) + ptr = *(void**)(((char*)this) + prop->byteOffset); + + if (ptr) + ((asCScriptEngine*)engine)->GCEnumCallback(ptr); } } @@ -745,12 +757,21 @@ void asCScriptObject::ReleaseAllHandles(asIScriptEngine *engine) void **ptr = (void**)(((char*)this) + prop->byteOffset); if( *ptr ) { - asASSERT( (prop->type.GetObjectType()->flags & asOBJ_NOCOUNT) || prop->type.GetBehaviour()->release ); + asASSERT( (prop->type.GetTypeInfo()->flags & asOBJ_NOCOUNT) || prop->type.GetBehaviour()->release ); if( prop->type.GetBehaviour()->release ) ((asCScriptEngine*)engine)->CallObjectMethod(*ptr, prop->type.GetBehaviour()->release); *ptr = 0; } } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **ptr = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + if (*ptr) + { + (*ptr)->Release(); + *ptr = 0; + } + } } } @@ -787,13 +808,23 @@ asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other) void **src = (void**)(((char*)&other) + prop->byteOffset); if( !prop->type.IsObjectHandle() ) { - if( prop->type.IsReference() || (prop->type.GetObjectType()->flags & asOBJ_REF) ) - CopyObject(*src, *dst, prop->type.GetObjectType(), engine); + if( prop->type.IsReference() || (prop->type.GetTypeInfo()->flags & asOBJ_REF) ) + CopyObject(*src, *dst, CastToObjectType(prop->type.GetTypeInfo()), engine); else - CopyObject(src, dst, prop->type.GetObjectType(), engine); + CopyObject(src, dst, CastToObjectType(prop->type.GetTypeInfo()), engine); } else - CopyHandle((asPWORD*)src, (asPWORD*)dst, prop->type.GetObjectType(), engine); + CopyHandle((asPWORD*)src, (asPWORD*)dst, CastToObjectType(prop->type.GetTypeInfo()), engine); + } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **dst = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + asCScriptFunction **src = (asCScriptFunction**)(((char*)&other) + prop->byteOffset); + if (*dst) + (*dst)->Release(); + *dst = *src; + if (*dst) + (*dst)->AddRef(); } else { @@ -905,29 +936,29 @@ int asCScriptObject::CopyFrom(asIScriptObject *other) return 0; } -void *asCScriptObject::AllocateUninitializedObject(asCObjectType *objType, asCScriptEngine *engine) +void *asCScriptObject::AllocateUninitializedObject(asCObjectType *in_objType, asCScriptEngine *engine) { void *ptr = 0; - if( objType->flags & asOBJ_SCRIPT_OBJECT ) + if( in_objType->flags & asOBJ_SCRIPT_OBJECT ) { - ptr = engine->CallAlloc(objType); - ScriptObject_ConstructUnitialized(objType, reinterpret_cast(ptr)); + ptr = engine->CallAlloc(in_objType); + ScriptObject_ConstructUnitialized(in_objType, reinterpret_cast(ptr)); } - else if( objType->flags & asOBJ_TEMPLATE ) + else if( in_objType->flags & asOBJ_TEMPLATE ) { // Templates store the original factory that takes the object // type as a hidden parameter in the construct behaviour - ptr = engine->CallGlobalFunctionRetPtr(objType->beh.construct, objType); + ptr = engine->CallGlobalFunctionRetPtr(in_objType->beh.construct, in_objType); } - else if( objType->flags & asOBJ_REF ) + else if( in_objType->flags & asOBJ_REF ) { - ptr = engine->CallGlobalFunctionRetPtr(objType->beh.factory); + ptr = engine->CallGlobalFunctionRetPtr(in_objType->beh.factory); } else { - ptr = engine->CallAlloc(objType); - int funcIndex = objType->beh.construct; + ptr = engine->CallAlloc(in_objType); + int funcIndex = in_objType->beh.construct; if( funcIndex ) engine->CallObjectMethod(ptr, funcIndex); } @@ -935,52 +966,52 @@ void *asCScriptObject::AllocateUninitializedObject(asCObjectType *objType, asCSc return ptr; } -void asCScriptObject::FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine) +void asCScriptObject::FreeObject(void *ptr, asCObjectType *in_objType, asCScriptEngine *engine) { - if( objType->flags & asOBJ_REF ) + if( in_objType->flags & asOBJ_REF ) { - asASSERT( (objType->flags & asOBJ_NOCOUNT) || objType->beh.release ); - if( objType->beh.release ) - engine->CallObjectMethod(ptr, objType->beh.release); + asASSERT( (in_objType->flags & asOBJ_NOCOUNT) || in_objType->beh.release ); + if(in_objType->beh.release ) + engine->CallObjectMethod(ptr, in_objType->beh.release); } else { - if( objType->beh.destruct ) - engine->CallObjectMethod(ptr, objType->beh.destruct); + if( in_objType->beh.destruct ) + engine->CallObjectMethod(ptr, in_objType->beh.destruct); engine->CallFree(ptr); } } -void asCScriptObject::CopyObject(void *src, void *dst, asCObjectType *objType, asCScriptEngine *engine) +void asCScriptObject::CopyObject(void *src, void *dst, asCObjectType *in_objType, asCScriptEngine *engine) { - int funcIndex = objType->beh.copy; + int funcIndex = in_objType->beh.copy; if( funcIndex ) { - asCScriptFunction *func = engine->scriptFunctions[objType->beh.copy]; + asCScriptFunction *func = engine->scriptFunctions[in_objType->beh.copy]; if( func->funcType == asFUNC_SYSTEM ) engine->CallObjectMethod(dst, src, funcIndex); else { // Call the script class' opAssign method - asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT ); + asASSERT(in_objType->flags & asOBJ_SCRIPT_OBJECT ); reinterpret_cast(dst)->CopyFrom(reinterpret_cast(src)); } } - else if( objType->size && (objType->flags & asOBJ_POD) ) - memcpy(dst, src, objType->size); + else if( in_objType->size && (in_objType->flags & asOBJ_POD) ) + memcpy(dst, src, in_objType->size); } -void asCScriptObject::CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine) +void asCScriptObject::CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *in_objType, asCScriptEngine *engine) { // asOBJ_NOCOUNT doesn't have addref or release behaviours - asASSERT( (objType->flags & asOBJ_NOCOUNT) || (objType->beh.release && objType->beh.addref) ); + asASSERT( (in_objType->flags & asOBJ_NOCOUNT) || (in_objType->beh.release && in_objType->beh.addref) ); - if( *dst && objType->beh.release ) - engine->CallObjectMethod(*(void**)dst, objType->beh.release); + if( *dst && in_objType->beh.release ) + engine->CallObjectMethod(*(void**)dst, in_objType->beh.release); *dst = *src; - if( *dst && objType->beh.addref ) - engine->CallObjectMethod(*(void**)dst, objType->beh.addref); + if( *dst && in_objType->beh.addref ) + engine->CallObjectMethod(*(void**)dst, in_objType->beh.addref); } // TODO: weak: Should move to its own file diff --git a/lib/angelscript/source/as_scriptobject.h b/lib/angelscript/source/as_scriptobject.h index dcdc5f371..7d357ec46 100644 --- a/lib/angelscript/source/as_scriptobject.h +++ b/lib/angelscript/source/as_scriptobject.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -60,14 +60,14 @@ public: bool Get() const; void Set(bool); - + void Lock() const; void Unlock() const; protected: mutable asCAtomic refCount; bool value; - DECLARECRITICALSECTION(mutable lock); + DECLARECRITICALSECTION(mutable lock) }; class asCScriptObject : public asIScriptObject @@ -84,7 +84,7 @@ public: // Type info int GetTypeId() const; - asIObjectType *GetObjectType() const; + asITypeInfo *GetObjectType() const; // Class properties asUINT GetPropertyCount() const; @@ -137,7 +137,7 @@ protected: bool isDestructCalled; // Most script classes instances won't have neither the weakRefFlags nor - // userData so we only allocate this if requested. Even when used it is + // userData so we only allocate this if requested. Even when used it is // not something that will be accessed all the time so having the extra // indirection will not affect the performance significantly. struct SExtra diff --git a/lib/angelscript/source/as_string.cpp b/lib/angelscript/source/as_string.cpp index aaa280c23..8bd3edfe3 100644 --- a/lib/angelscript/source/as_string.cpp +++ b/lib/angelscript/source/as_string.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -283,20 +283,24 @@ size_t asCString::Format(const char *format, ...) va_list args; va_start(args, format); - char tmp[256]; - int r = asVSNPRINTF(tmp, 255, format, args); + const size_t startSize = 1024; + char tmp[startSize]; + int r = asVSNPRINTF(tmp, startSize-1, format, args); - if( r > 0 ) + if( r > 0 && r < int(startSize) ) { Assign(tmp, r); } else { - size_t n = 512; + // TODO: For some reason this doesn't work properly on Linux. Perhaps the + // problem is related to vsnprintf not keeping the state of va_arg. + // Perhaps I need to rewrite this in some way to keep the state + size_t n = startSize*2; asCString str; // Use temporary string in case the current buffer is a parameter str.Allocate(n, false); - while( (r = asVSNPRINTF(str.AddressOf(), n, format, args)) < 0 ) + while( (r = asVSNPRINTF(str.AddressOf(), n, format, args)) < 0 || r >= int(n) ) { n *= 2; str.Allocate(n, false); @@ -324,15 +328,15 @@ const char &asCString::operator [](size_t index) const return AddressOf()[index]; } -asCString asCString::SubString(size_t start, size_t length) const +asCString asCString::SubString(size_t in_start, size_t in_length) const { - if( start >= GetLength() || length == 0 ) + if( in_start >= GetLength() || in_length == 0 ) return asCString(""); - if( length == (size_t)(-1) ) length = GetLength() - start; + if( in_length == (size_t)(-1) ) in_length = GetLength() - in_start; asCString tmp; - tmp.Assign(AddressOf() + start, length); + tmp.Assign(AddressOf() + in_start, in_length); return tmp; } diff --git a/lib/angelscript/source/as_string_util.cpp b/lib/angelscript/source/as_string_util.cpp index 8ee210dc5..32edbedb0 100644 --- a/lib/angelscript/source/as_string_util.cpp +++ b/lib/angelscript/source/as_string_util.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -171,17 +171,24 @@ static int asCharToNbr(char ch, int radix) } // If base is 0 the string should be prefixed by 0x, 0d, 0o, or 0b to allow the function to automatically determine the radix -asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned) +asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned, bool *overflow) { asASSERT(base == 10 || base == 16 || base == 0); + if (overflow) + *overflow = false; + const char *end = string; + static const asQWORD QWORD_MAX = (~asQWORD(0)); + asQWORD res = 0; if( base == 10 ) { while( *end >= '0' && *end <= '9' ) { + if( overflow && ((res > QWORD_MAX / 10) || ((asUINT(*end - '0') > (QWORD_MAX - (QWORD_MAX / 10) * 10)) && res == QWORD_MAX / 10)) ) + *overflow = true; res *= 10; res += *end++ - '0'; } @@ -205,8 +212,13 @@ asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned) if( base ) { - for( int nbr; (nbr = asCharToNbr(*end, base)) >= 0; end++ ) + for (int nbr; (nbr = asCharToNbr(*end, base)) >= 0; end++) + { + if (overflow && ((res > QWORD_MAX / base) || ((asUINT(nbr) > (QWORD_MAX - (QWORD_MAX / base) * base)) && res == QWORD_MAX / base)) ) + *overflow = true; + res = res * base + nbr; + } } } diff --git a/lib/angelscript/source/as_string_util.h b/lib/angelscript/source/as_string_util.h index 788e3d4b2..29174dfb8 100644 --- a/lib/angelscript/source/as_string_util.h +++ b/lib/angelscript/source/as_string_util.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2011 Andreas Jonsson + Copyright (c) 2003-2016 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -39,7 +39,7 @@ BEGIN_AS_NAMESPACE int asCompareStrings(const char *str1, size_t len1, const char *str2, size_t len2); double asStringScanDouble(const char *string, size_t *numScanned); -asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned); +asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned, bool *overflow); int asStringEncodeUTF8(unsigned int value, char *outEncodedBuffer); int asStringDecodeUTF8(const char *encodedBuffer, unsigned int *outLength); diff --git a/lib/angelscript/source/as_texts.h b/lib/angelscript/source/as_texts.h index b43648b16..6814ae0f3 100644 --- a/lib/angelscript/source/as_texts.h +++ b/lib/angelscript/source/as_texts.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -105,6 +105,8 @@ #define TXT_EXPECTED_STRING "Expected string" #define TXT_EXPR_DOESNT_EVAL_TO_FUNC "Expression doesn't evaluate to a function" #define TXT_EXPR_MUST_BE_BOOL "Expression must be of boolean type" +#define TXT_EXTERNAL_SHARED_s_NOT_FOUND "External shared entity '%s' not found" +#define TXT_EXTERNAL_SHARED_s_CANNOT_REDEF "External shared entity '%s' cannot redefine the original entity" #define TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s "Failed while compiling default arg for parameter %d in function '%s'" #define TXT_FAILED_TO_CREATE_TEMP_OBJ "Previous error occurred while attempting to create a temporary copy of object" @@ -135,6 +137,8 @@ #define TXT_INIT_LIST_CANNOT_BE_USED_WITH_s "Initialization lists cannot be used with '%s'" #define TXT_INSTANCING_INVLD_TMPL_TYPE_s_s "Attempting to instantiate invalid template type '%s<%s>'" #define TXT_INSTEAD_FOUND_s "Instead found '%s'" +#define TXT_INSTEAD_FOUND_IDENTIFIER_s "Instead found identifier '%s'" +#define TXT_INSTEAD_FOUND_KEYWORD_s "Instead found reserved keyword '%s'" #define TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED "Interface '%s' cannot be instantiated" #define TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE "Interfaces can only implement other interfaces" #define TXT_INVALID_BREAK "Invalid 'break'" @@ -150,15 +154,18 @@ #define TXT_INVALID_UNICODE_FORMAT_EXPECTED_d "Invalid unicode escape sequence, expected %d hex digits" #define TXT_INVALID_UNICODE_VALUE "Invalid unicode code point" #define TXT_INVALID_UNICODE_SEQUENCE_IN_SRC "Invalid unicode sequence in source" +#define TXT_INVALID_USE_OF_NAMED_ARGS "Invalid use of named arguments" #define TXT_METHOD_CANNOT_OVERRIDE_s "Method '%s' declared as final and cannot be overridden" #define TXT_METHOD_CANT_HAVE_NAME_OF_CLASS "The method cannot be named with the class name" #define TXT_METHOD_s_DOES_NOT_OVERRIDE "Method '%s' marked as override but does not replace any base class or interface method" #define TXT_METHOD_s_s_HAS_NO_RETURN_TYPE "Method '%s::%s' is missing the return type, nor is it the same name as object to be a constructor" #define TXT_MISSING_IMPLEMENTATION_OF_s "Missing implementation of '%s'" +#define TXT_MISSING_DEFINITION_OF_s "Missing definition of '%s'" #define TXT_MIXIN_CANNOT_BE_DECLARED_AS_s "Mixin class cannot be declared as '%s'" #define TXT_MIXIN_CANNOT_HAVE_CONSTRUCTOR "Mixin classes cannot have constructors or destructors" #define TXT_MIXIN_CLASS_CANNOT_INHERIT "Mixin class cannot inherit from classes" +#define TXT_MIXIN_CANNOT_HAVE_CHILD_TYPES "Mixin classes cannot have child types" #define TXT_MORE_THAN_ONE_MATCHING_OP "Found more than one matching operator" #define TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s "Multiple matching signatures to '%s'" #define TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s "Found multiple get accessors for property '%s'" @@ -192,7 +199,7 @@ #define TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s "No matching operator that takes the types '%s' and '%s' found" #define TXT_NON_CONST_METHOD_ON_CONST_OBJ "Non-const method call on read-only object reference" #define TXT_NONTERMINATED_STRING "Non-terminated string literal" -#define TXT_NOT_A_FUNC_s_IS_VAR "Expression doesn't form a function call. '%s' is a variable of a non-function type" +#define TXT_NOT_A_FUNC_s_IS_TYPE_s "Expression doesn't form a function call. '%s' evaluates to the non-function type '%s'" #define TXT_NOT_ALL_PATHS_RETURN "Not all paths return a value" #define TXT_NOT_ENOUGH_VALUES_FOR_LIST "Not enough values to match pattern" #define TXT_s_NOT_DECLARED "'%s' is not declared" @@ -216,10 +223,12 @@ #define TXT_PARAMETER_ALREADY_DECLARED "Parameter already declared" #define TXT_PARAMETER_CANT_BE_s "Parameter type can't be '%s', because the type cannot be instantiated." #define TXT_POS_ARG_AFTER_NAMED_ARG "Positional arguments cannot be passed after named arguments" +#define TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s "Previous error occurred while attempting to compile initialization list for type '%s'" #define TXT_PRIVATE_METHOD_CALL_s "Illegal call to private method '%s'" #define TXT_PRIVATE_PROP_ACCESS_s "Illegal access to private property '%s'" #define TXT_PROTECTED_METHOD_CALL_s "Illegal call to protected method '%s'" #define TXT_PROTECTED_PROP_ACCESS_s "Illegal access to protected property '%s'" +#define TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG "Property accessor with index must have 1 and only 1 index argument" #define TXT_PROPERTY_ACCESSOR_DISABLED "Property accessors have been disabled by the application" #define TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED "Property accessor must be implemented" #define TXT_PROPERTY_CANT_BE_CONST "Class properties cannot be declared as const" @@ -252,6 +261,7 @@ #define TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY "Template subtype must not be read-only" #define TXT_TOO_MANY_JUMP_LABELS "The function has too many jump labels to handle. Split the function into smaller ones." #define TXT_TOO_MANY_VALUES_FOR_LIST "Too many values to match pattern" +#define TXT_TYPE_s_CANNOT_BE_REFERENCE "Type '%s' cannot be a reference" #define TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE "Type '%s' is not available for this module" #define TXT_TYPE_s_NOT_TEMPLATE "Type '%s' is not a template type" @@ -291,7 +301,7 @@ #define TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR "A garbage collected type must have the addref, release, and all gc behaviours" #define TXT_SCOPE_REQUIRE_REL_BEHAVIOUR "A scoped reference type must have the release behaviour" #define TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR "A reference type must have the addref and release behaviours" -#define TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR "A non-pod value type must have the default constructor and destructor behaviours" +#define TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR "A non-pod value type must have at least one constructor and the destructor behaviours" #define TXT_CANNOT_PASS_TYPE_s_BY_VAL "Can't pass type '%s' by value unless the application type is informed in the registration" #define TXT_CANNOT_RET_TYPE_s_BY_VAL "Can't return type '%s' by value unless the application type is informed in the registration" // TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to pass by value to application in native calling convention" @@ -341,5 +351,6 @@ #define TXT_OUT_OF_BOUNDS "Out of range" #define TXT_EXCEPTION_CAUGHT "Caught an exception from the application" #define TXT_MISMATCH_IN_VALUE_ASSIGN "Mismatching types in value assignment" +#define TXT_TOO_MANY_NESTED_CALLS "Too many nested calls" #endif diff --git a/lib/angelscript/source/as_thread.h b/lib/angelscript/source/as_thread.h index f4abf88a1..813d4c0f0 100644 --- a/lib/angelscript/source/as_thread.h +++ b/lib/angelscript/source/as_thread.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -80,7 +80,7 @@ protected: #else asDWORD tlsKey; #endif - DECLARECRITICALSECTION(criticalSection); + DECLARECRITICALSECTION(criticalSection) #else asCThreadLocalData *tld; #endif diff --git a/lib/angelscript/source/as_tokendef.h b/lib/angelscript/source/as_tokendef.h index a88d2605a..0ad6d4a4d 100644 --- a/lib/angelscript/source/as_tokendef.h +++ b/lib/angelscript/source/as_tokendef.h @@ -1,24 +1,24 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -244,7 +244,7 @@ sTokenWord const tokenWords[] = asTokenDef("auto" , ttAuto), asTokenDef("bool" , ttBool), asTokenDef("break" , ttBreak), - asTokenDef("case" , ttCase), + asTokenDef("case" , ttCase), asTokenDef("cast" , ttCast), asTokenDef("class" , ttClass), asTokenDef("const" , ttConst), @@ -269,7 +269,7 @@ sTokenWord const tokenWords[] = asTokenDef("int" , ttInt), asTokenDef("int8" , ttInt8), asTokenDef("int16" , ttInt16), - asTokenDef("int32" , ttInt), + asTokenDef("int32" , ttInt), asTokenDef("int64" , ttInt64), asTokenDef("interface" , ttInterface), asTokenDef("is" , ttIs), @@ -302,16 +302,18 @@ const char * const whiteSpace = " \t\r\n"; // Some keywords that are not considered tokens by the parser // These only have meaning in specific situations. Outside these // situations they are treated as normal identifiers. -const char * const THIS_TOKEN = "this"; -const char * const FROM_TOKEN = "from"; -const char * const SUPER_TOKEN = "super"; -const char * const SHARED_TOKEN = "shared"; -const char * const FINAL_TOKEN = "final"; -const char * const OVERRIDE_TOKEN = "override"; -const char * const GET_TOKEN = "get"; -const char * const SET_TOKEN = "set"; -const char * const ABSTRACT_TOKEN = "abstract"; -const char * const FUNCTION_TOKEN = "function"; +const char * const THIS_TOKEN = "this"; +const char * const FROM_TOKEN = "from"; +const char * const SUPER_TOKEN = "super"; +const char * const SHARED_TOKEN = "shared"; +const char * const FINAL_TOKEN = "final"; +const char * const OVERRIDE_TOKEN = "override"; +const char * const GET_TOKEN = "get"; +const char * const SET_TOKEN = "set"; +const char * const ABSTRACT_TOKEN = "abstract"; +const char * const FUNCTION_TOKEN = "function"; +const char * const IF_HANDLE_TOKEN = "if_handle_then_const"; +const char * const EXTERNAL_TOKEN = "external"; END_AS_NAMESPACE diff --git a/lib/angelscript/source/as_tokenizer.cpp b/lib/angelscript/source/as_tokenizer.cpp index 82c1b80e0..2017a12ec 100644 --- a/lib/angelscript/source/as_tokenizer.cpp +++ b/lib/angelscript/source/as_tokenizer.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson + Copyright (c) 2003-2015 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -395,20 +395,27 @@ bool asCTokenizer::IsConstant(const char *source, size_t sourceLength, size_t &t bool asCTokenizer::IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const { + // char is unsigned by default on some architectures, e.g. ppc and arm + // Make sure the value is always treated as signed in the below comparisons + signed char c = source[0]; + // Starting with letter or underscore - if( (source[0] >= 'a' && source[0] <= 'z') || - (source[0] >= 'A' && source[0] <= 'Z') || - source[0] == '_' ) + if( (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c == '_' || + (c < 0 && engine->ep.allowUnicodeIdentifiers) ) { tokenType = ttIdentifier; tokenLength = 1; for( size_t n = 1; n < sourceLength; n++ ) { - if( (source[n] >= 'a' && source[n] <= 'z') || - (source[n] >= 'A' && source[n] <= 'Z') || - (source[n] >= '0' && source[n] <= '9') || - source[n] == '_' ) + c = source[n]; + if( (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_' || + (c < 0 && engine->ep.allowUnicodeIdentifiers) ) tokenLength++; else break; diff --git a/lib/angelscript/source/as_typeinfo.cpp b/lib/angelscript/source/as_typeinfo.cpp index 230aff05f..f407ecc73 100644 --- a/lib/angelscript/source/as_typeinfo.cpp +++ b/lib/angelscript/source/as_typeinfo.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -32,13 +32,9 @@ // // as_typeinfo.cpp // -// This class holds extra type info for the compiler -// + #include "as_config.h" - -#ifndef AS_NO_COMPILER - #include "as_typeinfo.h" #include "as_scriptengine.h" @@ -46,144 +42,434 @@ BEGIN_AS_NAMESPACE asCTypeInfo::asCTypeInfo() { - isTemporary = false; - stackOffset = 0; - isConstant = false; - isVariable = false; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; - isRefToLocal = false; + externalRefCount.set(0); + internalRefCount.set(1); // start with one internal ref-count + engine = 0; + module = 0; + size = 0; + flags = 0; + typeId = -1; // start as -1 to signal that it hasn't been defined + + scriptSectionIdx = -1; + declaredAt = 0; + + accessMask = 0xFFFFFFFF; + nameSpace = 0; } -void asCTypeInfo::Set(const asCDataType &dt) +asCTypeInfo::asCTypeInfo(asCScriptEngine *in_engine) { - dataType = dt; + externalRefCount.set(0); + internalRefCount.set(1); // start with one internal ref count + engine = in_engine; + module = 0; + size = 0; + flags = 0; + typeId = -1; // start as -1 to signal that it hasn't been defined - isTemporary = false; - stackOffset = 0; - isConstant = false; - isVariable = false; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; - isRefToLocal = false; + scriptSectionIdx = -1; + declaredAt = 0; + + accessMask = 0xFFFFFFFF; + nameSpace = engine->nameSpaces[0]; } -void asCTypeInfo::SetVariable(const asCDataType &dt, int stackOffset, bool isTemporary) +asCTypeInfo::~asCTypeInfo() { - Set(dt); - - this->isVariable = true; - this->isTemporary = isTemporary; - this->stackOffset = (short)stackOffset; } -void asCTypeInfo::SetConstantQW(const asCDataType &dt, asQWORD value) +// interface +int asCTypeInfo::AddRef() const { - Set(dt); - - isConstant = true; - qwordValue = value; + return externalRefCount.atomicInc(); } -void asCTypeInfo::SetConstantDW(const asCDataType &dt, asDWORD value) +// interface +int asCTypeInfo::Release() const { - Set(dt); + int r = externalRefCount.atomicDec(); - isConstant = true; - dwordValue = value; + if (r == 0) + { + // There are no more external references, if there are also no + // internal references then it is time to delete the object type + if (internalRefCount.get() == 0) + { + // If the engine is no longer set, then it has already been + // released and we must take care of the deletion ourselves + asDELETE(const_cast(this), asCTypeInfo); + } + } + + return r; } -void asCTypeInfo::SetConstantB(const asCDataType &dt, asBYTE value) +int asCTypeInfo::AddRefInternal() { - Set(dt); - - isConstant = true; - byteValue = value; + return internalRefCount.atomicInc(); } -void asCTypeInfo::SetConstantF(const asCDataType &dt, float value) +int asCTypeInfo::ReleaseInternal() { - Set(dt); + int r = internalRefCount.atomicDec(); - isConstant = true; - floatValue = value; + if (r == 0) + { + // There are no more internal references, if there are also no + // external references then it is time to delete the object type + if (externalRefCount.get() == 0) + { + // If the engine is no longer set, then it has already been + // released and we must take care of the deletion ourselves + asDELETE(const_cast(this), asCTypeInfo); + } + } + + return r; } -void asCTypeInfo::SetConstantD(const asCDataType &dt, double value) +// interface +asIScriptModule *asCTypeInfo::GetModule() const { - Set(dt); - - isConstant = true; - doubleValue = value; + return module; } -void asCTypeInfo::SetUndefinedFuncHandle(asCScriptEngine *engine) +void *asCTypeInfo::SetUserData(void *data, asPWORD type) { - // This is used for when the expression evaluates to a - // function, but it is not yet known exactly which. The - // owner expression will hold the name of the function - // to determine the exact function when the signature is - // known. - Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true)); - isConstant = true; - isExplicitHandle = false; - qwordValue = 1; // Set to a different value than 0 to differentiate from null constant - isLValue = false; + // As a thread might add a new new user data at the same time as another + // it is necessary to protect both read and write access to the userData member + ACQUIREEXCLUSIVE(engine->engineRWLock); + + // It is not intended to store a lot of different types of userdata, + // so a more complex structure like a associative map would just have + // more overhead than a simple array. + for (asUINT n = 0; n < userData.GetLength(); n += 2) + { + if (userData[n] == type) + { + void *oldData = reinterpret_cast(userData[n + 1]); + userData[n + 1] = reinterpret_cast(data); + + RELEASEEXCLUSIVE(engine->engineRWLock); + + return oldData; + } + } + + userData.PushLast(type); + userData.PushLast(reinterpret_cast(data)); + + RELEASEEXCLUSIVE(engine->engineRWLock); + + return 0; } -bool asCTypeInfo::IsUndefinedFuncHandle() const +void *asCTypeInfo::GetUserData(asPWORD type) const { - if( isConstant == false ) return false; - if( qwordValue == 0 ) return false; - if( isLValue ) return false; - if( dataType.GetObjectType() == 0 ) return false; - if( dataType.GetObjectType()->name != "$func" ) return false; - if( dataType.GetFuncDef() ) return false; + // There may be multiple threads reading, but when + // setting the user data nobody must be reading. + ACQUIRESHARED(engine->engineRWLock); + for (asUINT n = 0; n < userData.GetLength(); n += 2) + { + if (userData[n] == type) + { + RELEASESHARED(engine->engineRWLock); + return reinterpret_cast(userData[n + 1]); + } + } + + RELEASESHARED(engine->engineRWLock); + + return 0; +} + +// interface +const char *asCTypeInfo::GetName() const +{ + return name.AddressOf(); +} + +// interface +const char *asCTypeInfo::GetNamespace() const +{ + if( nameSpace ) + return nameSpace->name.AddressOf(); + + return 0; +} + +// interface +asDWORD asCTypeInfo::GetFlags() const +{ + return flags; +} + +// interface +asUINT asCTypeInfo::GetSize() const +{ + return size; +} + +// interface +int asCTypeInfo::GetTypeId() const +{ + if (typeId == -1) + { + // We need a non const pointer to create the asCDataType object. + // We're not breaking anything here because this function is not + // modifying the object, so this const cast is safe. + asCTypeInfo *ot = const_cast(this); + + // The engine will define the typeId for this object type + engine->GetTypeIdFromDataType(asCDataType::CreateType(ot, false)); + } + + return typeId; +} + +// interface +asIScriptEngine *asCTypeInfo::GetEngine() const +{ + return engine; +} + +// interface +const char *asCTypeInfo::GetConfigGroup() const +{ + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(this); + if (group == 0) + return 0; + + return group->groupName.AddressOf(); +} + +// interface +asDWORD asCTypeInfo::GetAccessMask() const +{ + return accessMask; +} + +// interface +int asCTypeInfo::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const +{ + UNUSED_VAR(index); + if (out_name) *out_name = 0; + if (out_typeId) *out_typeId = 0; + if (out_isPrivate) *out_isPrivate = false; + if (out_isProtected) *out_isProtected = false; + if (out_offset) *out_offset = 0; + if (out_isReference) *out_isReference = false; + if (out_accessMask) *out_accessMask = 0; + if (out_compositeOffset) *out_compositeOffset = 0; + if (out_isCompositeIndirect) *out_isCompositeIndirect = false; + return -1; +} + +// internal +asCObjectType *CastToObjectType(asCTypeInfo *ti) +{ + // Allow call on null pointer + if (ti == 0) return 0; + + // TODO: type: Should List pattern have its own type class? + if ((ti->flags & (asOBJ_VALUE | asOBJ_REF | asOBJ_LIST_PATTERN)) && !(ti->flags & asOBJ_FUNCDEF)) + return reinterpret_cast(ti); + + return 0; +} + +// internal +asCEnumType *CastToEnumType(asCTypeInfo *ti) +{ + // Allow call on null pointer + if (ti == 0) return 0; + + if (ti->flags & (asOBJ_ENUM)) + return reinterpret_cast(ti); + + return 0; +} + +// internal +asCTypedefType *CastToTypedefType(asCTypeInfo *ti) +{ + // Allow call on null pointer + if (ti == 0) return 0; + + if (ti->flags & (asOBJ_TYPEDEF)) + return reinterpret_cast(ti); + + return 0; +} + +// internal +asCFuncdefType *CastToFuncdefType(asCTypeInfo *ti) +{ + // Allow call on null pointer + if (ti == 0) return 0; + + if (ti->flags & (asOBJ_FUNCDEF)) + return reinterpret_cast(ti); + + return 0; +} + +// internal +void asCTypeInfo::CleanUserData() +{ + asASSERT(engine); + for (asUINT n = 0; n < userData.GetLength(); n += 2) + { + if (userData[n + 1]) + { + for (asUINT c = 0; c < engine->cleanTypeInfoFuncs.GetLength(); c++) + if (engine->cleanTypeInfoFuncs[c].type == userData[n]) + engine->cleanTypeInfoFuncs[c].cleanFunc(this); + } + } + userData.SetLength(0); +} + +// internal +bool asCTypeInfo::IsShared() const +{ + // Types that can be declared by scripts need to have the explicit flag asOBJ_SHARED + if (flags & (asOBJ_SCRIPT_OBJECT | asOBJ_ENUM)) return flags & asOBJ_SHARED ? true : false; + + // Otherwise we assume the type to be shared return true; } -void asCTypeInfo::SetNullConstant() +//////////////////////////////////////////////////////////////////////////////////////// + +asCEnumType::~asCEnumType() { - Set(asCDataType::CreateNullHandle()); - isConstant = true; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; + asUINT n; + for (n = 0; n < enumValues.GetLength(); n++) + { + if (enumValues[n]) + asDELETE(enumValues[n], asSEnumValue); + } + enumValues.SetLength(0); } -bool asCTypeInfo::IsNullConstant() const +// interface +asUINT asCEnumType::GetEnumValueCount() const { - // We can't check the actual object type, because the null constant may have been cast to another type - if( isConstant && dataType.IsObjectHandle() && qwordValue == 0 ) - return true; - - return false; + return enumValues.GetLength(); } -void asCTypeInfo::SetVoid() +// interface +const char *asCEnumType::GetEnumValueByIndex(asUINT index, int *outValue) const { - Set(asCDataType::CreatePrimitive(ttVoid, false)); - isLValue = false; - isConstant = true; + if (outValue) + *outValue = 0; + + if (index >= enumValues.GetLength()) + return 0; + + if (outValue) + *outValue = enumValues[index]->value; + + return enumValues[index]->name.AddressOf(); } -bool asCTypeInfo::IsVoid() const -{ - if( dataType.GetTokenType() == ttVoid ) - return true; +////////////////////////////////////////////////////////////////////////////////////////// - return false; +asCTypedefType::~asCTypedefType() +{ + DestroyInternal(); } -void asCTypeInfo::SetDummy() +void asCTypedefType::DestroyInternal() { - SetConstantQW(asCDataType::CreatePrimitive(ttInt, true), 0); + if (engine == 0) return; + + // Release the object types held by the alias + if (aliasForType.GetTypeInfo()) + aliasForType.GetTypeInfo()->ReleaseInternal(); + + aliasForType = asCDataType::CreatePrimitive(ttVoid, false); + + CleanUserData(); + + // Remove the type from the engine + if (typeId != -1) + engine->RemoveFromTypeIdMap(this); + + // Clear the engine pointer to mark the object type as invalid + engine = 0; } +// interface +int asCTypedefType::GetTypedefTypeId() const +{ + return engine->GetTypeIdFromDataType(aliasForType); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +asCFuncdefType::asCFuncdefType(asCScriptEngine *en, asCScriptFunction *func) : asCTypeInfo(en) +{ + asASSERT(func->funcType == asFUNC_FUNCDEF); + asASSERT(func->funcdefType == 0); + + // A function pointer is special kind of reference type + flags = asOBJ_REF | asOBJ_FUNCDEF | (func->IsShared() ? asOBJ_SHARED : 0); + name = func->name; + nameSpace = func->nameSpace; + module = func->module; + accessMask = func->accessMask; + funcdef = func; // reference already counted by the asCScriptFunction constructor + parentClass = 0; + + func->funcdefType = this; +} + +asCFuncdefType::~asCFuncdefType() +{ + DestroyInternal(); +} + +void asCFuncdefType::DestroyInternal() +{ + if (engine == 0) return; + + // Release the funcdef + if( funcdef ) + funcdef->ReleaseInternal(); + funcdef = 0; + + // Detach from parent class + if (parentClass) + { + parentClass->childFuncDefs.RemoveValue(this); + parentClass = 0; + } + + CleanUserData(); + + // Remove the type from the engine + if (typeId != -1) + engine->RemoveFromTypeIdMap(this); + + // Clear the engine pointer to mark the object type as invalid + engine = 0; +} + +// interface +asIScriptFunction *asCFuncdefType::GetFuncdefSignature() const +{ + return funcdef; +} + +// interface +asITypeInfo *asCFuncdefType::GetParentType() const +{ + return parentClass; +} END_AS_NAMESPACE -#endif // AS_NO_COMPILER + diff --git a/lib/angelscript/source/as_typeinfo.h b/lib/angelscript/source/as_typeinfo.h index 724411e82..a5643dda5 100644 --- a/lib/angelscript/source/as_typeinfo.h +++ b/lib/angelscript/source/as_typeinfo.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2015 Andreas Jonsson + Copyright (c) 2003-2017 Andreas Jonsson This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -32,8 +32,6 @@ // // as_typeinfo.h // -// This class holds extra type info for the compiler -// @@ -41,56 +39,204 @@ #define AS_TYPEINFO_H #include "as_config.h" - -#ifndef AS_NO_COMPILER - +#include "as_string.h" +#include "as_atomic.h" #include "as_datatype.h" BEGIN_AS_NAMESPACE -struct asCTypeInfo +class asCScriptEngine; +class asCModule; +class asCObjectType; +class asCEnumType; +class asCTypedefType; +class asCFuncdefType; +struct asSNameSpace; + +// TODO: type: asCPrimitiveType shall be implemented to represent primitives (void, int, double, etc) + +// TODO: type: asCTypeInfo should have an internal virtual method GetBehaviours. For asCObjectType it +// should return the beh member. For asCFuncdefType it should return the beh member of +// engine->functionBehaviours. This will allow the code that needs the behaviour to handle +// both object types and funcdefs the same way + +class asCTypeInfo : public asITypeInfo { +public: + //===================================== + // From asITypeInfo + //===================================== + asIScriptEngine *GetEngine() const; + const char *GetConfigGroup() const; + asDWORD GetAccessMask() const; + asIScriptModule *GetModule() const; + + // Memory management + int AddRef() const; + int Release() const; + + // Type info + const char *GetName() const; + const char *GetNamespace() const; + asITypeInfo *GetBaseType() const { return 0; } + bool DerivesFrom(const asITypeInfo *objType) const { UNUSED_VAR(objType); return 0; } + asDWORD GetFlags() const; + asUINT GetSize() const; + int GetTypeId() const; + int GetSubTypeId(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return -1; } + asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return 0; } + asUINT GetSubTypeCount() const { return 0; } + + // Interfaces + asUINT GetInterfaceCount() const { return 0; } + asITypeInfo *GetInterface(asUINT index) const { UNUSED_VAR(index); return 0; } + bool Implements(const asITypeInfo *objType) const { UNUSED_VAR(objType); return false; } + + // Factories + asUINT GetFactoryCount() const { return 0; } + asIScriptFunction *GetFactoryByIndex(asUINT index) const { UNUSED_VAR(index); return 0; } + asIScriptFunction *GetFactoryByDecl(const char *decl) const { UNUSED_VAR(decl); return 0; } + + // Methods + asUINT GetMethodCount() const { return 0; } + asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const { UNUSED_VAR(index); UNUSED_VAR(getVirtual); return 0; } + asIScriptFunction *GetMethodByName(const char *in_name, bool getVirtual) const { UNUSED_VAR(in_name); UNUSED_VAR(getVirtual); return 0; } + asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const { UNUSED_VAR(decl); UNUSED_VAR(getVirtual); return 0; } + + // Properties + asUINT GetPropertyCount() const { return 0; } + int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const; + const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const { UNUSED_VAR(index); UNUSED_VAR(includeNamespace); return 0; } + + // Behaviours + asUINT GetBehaviourCount() const { return 0; } + asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const { UNUSED_VAR(index); UNUSED_VAR(outBehaviour); return 0; } + + // Child types + asUINT GetChildFuncdefCount() const { return 0; } + asITypeInfo *GetChildFuncdef(asUINT index) const { UNUSED_VAR(index); return 0; } + asITypeInfo *GetParentType() const { return 0; } + + // Enums + virtual asUINT GetEnumValueCount() const { return 0; } + virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const { UNUSED_VAR(index); if (outValue) *outValue = 0; return 0; } + + // Typedef + virtual int GetTypedefTypeId() const { return asERROR; } + + // Funcdef + virtual asIScriptFunction *GetFuncdefSignature() const { return 0; } + + // User data + void *SetUserData(void *data, asPWORD type); + void *GetUserData(asPWORD type) const; + + //=========================================== + // Internal + //=========================================== +public: + asCTypeInfo(asCScriptEngine *engine); + virtual ~asCTypeInfo(); + + // Keep an internal reference counter to separate references coming from + // application or script objects and references coming from the script code + virtual int AddRefInternal(); + virtual int ReleaseInternal(); + + virtual void DestroyInternal() {} + + void CleanUserData(); + + bool IsShared() const; + + // These can be safely used on null pointers (which will return null) + friend asCObjectType *CastToObjectType(asCTypeInfo *); + friend asCEnumType *CastToEnumType(asCTypeInfo *); + friend asCTypedefType *CastToTypedefType(asCTypeInfo *); + friend asCFuncdefType *CastToFuncdefType(asCTypeInfo *); + + + asCString name; + asSNameSpace *nameSpace; + int size; + mutable int typeId; + asDWORD flags; + asDWORD accessMask; + + // Store the script section where the code was declared + int scriptSectionIdx; + // Store the location where the function was declared (row in the lower 20 bits, and column in the upper 12) + int declaredAt; + + asCScriptEngine *engine; + asCModule *module; + asCArray userData; + +protected: + friend class asCScriptEngine; + friend class asCConfigGroup; + friend class asCModule; + friend class asCObjectType; asCTypeInfo(); - void Set(const asCDataType &dataType); - void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary); - void SetConstantB(const asCDataType &dataType, asBYTE value); - void SetConstantQW(const asCDataType &dataType, asQWORD value); - void SetConstantDW(const asCDataType &dataType, asDWORD value); - void SetConstantF(const asCDataType &dataType, float value); - void SetConstantD(const asCDataType &dataType, double value); - void SetNullConstant(); - void SetUndefinedFuncHandle(asCScriptEngine *engine); - void SetVoid(); - void SetDummy(); + mutable asCAtomic externalRefCount; + asCAtomic internalRefCount; +}; - bool IsUndefinedFuncHandle() const; - bool IsNullConstant() const; - bool IsVoid() const; +struct asSEnumValue +{ + asCString name; + int value; +}; - asCDataType dataType; - bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc - bool isTemporary : 1; - bool isConstant : 1; - bool isVariable : 1; - bool isExplicitHandle : 1; - bool isRefToLocal : 1; // The reference may be to a local variable - short dummy : 10; - short stackOffset; - union - { - asQWORD qwordValue; - double doubleValue; - asDWORD dwordValue; - float floatValue; - int intValue; - asWORD wordValue; - asBYTE byteValue; - }; +class asCEnumType : public asCTypeInfo +{ +public: + asCEnumType(asCScriptEngine *engine) : asCTypeInfo(engine) {} + ~asCEnumType(); + + asCArray enumValues; + + asUINT GetEnumValueCount() const; + const char *GetEnumValueByIndex(asUINT index, int *outValue) const; + +protected: + asCEnumType() : asCTypeInfo() {} +}; + +class asCTypedefType : public asCTypeInfo +{ +public: + asCTypedefType(asCScriptEngine *engine) : asCTypeInfo(engine) {} + ~asCTypedefType(); + + void DestroyInternal(); + + asCDataType aliasForType; // increase refCount for typeinfo inside datatype + + int GetTypedefTypeId() const; + +protected: + asCTypedefType() : asCTypeInfo() {} +}; + +class asCFuncdefType : public asCTypeInfo +{ +public: + asCFuncdefType(asCScriptEngine *engine, asCScriptFunction *func); + ~asCFuncdefType(); + + asIScriptFunction *GetFuncdefSignature() const; + asITypeInfo *GetParentType() const; + + void DestroyInternal(); + asCScriptFunction *funcdef; // increases refCount + asCObjectType *parentClass; // doesn't increase refCount + +protected: + asCFuncdefType() : asCTypeInfo(), funcdef(0), parentClass(0) {} }; END_AS_NAMESPACE -#endif // AS_NO_COMPILER - #endif diff --git a/src/scriptengine/script_engine.cpp b/src/scriptengine/script_engine.cpp index 47458c93d..2c1ccbf3e 100644 --- a/src/scriptengine/script_engine.cpp +++ b/src/scriptengine/script_engine.cpp @@ -222,7 +222,7 @@ namespace Scripting /* void ScriptEngine::runMethod(asIScriptObject* obj, std::string methodName) { - asIObjectType* type = obj->GetObjectType(); + asITypeInfo* type = obj->GetObjectType(); asIScriptFunction* method = type->GetMethodByName(methodName.c_str()); if (method == NULL) Log::error("Scripting", ("runMethod: object does not implement method " + methodName).c_str()); diff --git a/src/scriptengine/scriptarray.cpp b/src/scriptengine/scriptarray.cpp index 322cdfa17..8557c8cb9 100644 --- a/src/scriptengine/scriptarray.cpp +++ b/src/scriptengine/scriptarray.cpp @@ -1,38 +1,9 @@ -/* -AngelCode Scripting Library -Copyright (c) 2003-2015 Andreas Jonsson - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you -must not claim that you wrote the original software. If you use -this software in a product, an acknowledgment in the product -documentation would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. - -The original version of this library can be located at: -http://www.angelcode.com/angelscript/ - -Andreas Jonsson -andreas@angelcode.com -*/ - #include #include #include #include #include // sprintf +#include #include "scriptarray.hpp" @@ -79,7 +50,7 @@ struct SArrayCache // through 1999 for this purpose, so we should be fine. const asPWORD ARRAY_CACHE = 1000; -static void CleanupObjectTypeArrayCache(asIObjectType *type) +static void CleanupTypeInfoArrayCache(asITypeInfo *type) { SArrayCache *cache = reinterpret_cast(type->GetUserData(ARRAY_CACHE)); if( cache ) @@ -89,14 +60,13 @@ static void CleanupObjectTypeArrayCache(asIObjectType *type) } } -CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length) +CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length) { - asIScriptContext *ctx = asGetActiveContext(); - // Allocate the memory void *mem = userAlloc(sizeof(CScriptArray)); if( mem == 0 ) { + asIScriptContext *ctx = asGetActiveContext(); if( ctx ) ctx->SetException("Out of memory"); @@ -104,27 +74,18 @@ CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length) } // Initialize the object - CScriptArray *a = new(mem) CScriptArray(length, ot); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } + CScriptArray *a = new(mem) CScriptArray(length, ti); return a; } -CScriptArray* CScriptArray::Create(asIObjectType *ot, void *initList) +CScriptArray* CScriptArray::Create(asITypeInfo *ti, void *initList) { - asIScriptContext *ctx = asGetActiveContext(); - // Allocate the memory void *mem = userAlloc(sizeof(CScriptArray)); if( mem == 0 ) { + asIScriptContext *ctx = asGetActiveContext(); if( ctx ) ctx->SetException("Out of memory"); @@ -132,27 +93,18 @@ CScriptArray* CScriptArray::Create(asIObjectType *ot, void *initList) } // Initialize the object - CScriptArray *a = new(mem) CScriptArray(ot, initList); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } + CScriptArray *a = new(mem) CScriptArray(ti, initList); return a; } -CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length, void *defVal) +CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length, void *defVal) { - asIScriptContext *ctx = asGetActiveContext(); - // Allocate the memory void *mem = userAlloc(sizeof(CScriptArray)); if( mem == 0 ) { + asIScriptContext *ctx = asGetActiveContext(); if( ctx ) ctx->SetException("Out of memory"); @@ -160,22 +112,14 @@ CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length, void *defVa } // Initialize the object - CScriptArray *a = new(mem) CScriptArray(length, defVal, ot); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } + CScriptArray *a = new(mem) CScriptArray(length, defVal, ti); return a; } -CScriptArray* CScriptArray::Create(asIObjectType *ot) +CScriptArray* CScriptArray::Create(asITypeInfo *ti) { - return CScriptArray::Create(ot, asUINT(0)); + return CScriptArray::Create(ti, asUINT(0)); } // This optional callback is called when the template type is first used by the compiler. @@ -183,16 +127,16 @@ CScriptArray* CScriptArray::Create(asIObjectType *ot) // subtype at compile time, instead of at runtime. The output argument dontGarbageCollect // allow the callback to tell the engine if the template instance type shouldn't be garbage collected, // i.e. no asOBJ_GC flag. -static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageCollect) +static bool ScriptArrayTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect) { // Make sure the subtype can be instantiated with a default factory/constructor, // otherwise we won't be able to instantiate the elements. - int typeId = ot->GetSubTypeId(); + int typeId = ti->GetSubTypeId(); if( typeId == asTYPEID_VOID ) return false; if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) { - asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId); + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); asDWORD flags = subtype->GetFlags(); if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) ) { @@ -215,7 +159,8 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl if( !found ) { // There is no default constructor - ot->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); + // TODO: Should format the message to give the name of the subtype for better understanding + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); return false; } } @@ -225,7 +170,7 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl // If value assignment for ref type has been disabled then the array // can be created if the type has a default factory function - if( !ot->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) + if( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) { // Verify that there is a default factory for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) @@ -243,7 +188,8 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl if( !found ) { // No default factory - ot->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); + // TODO: Should format the message to give the name of the subtype for better understanding + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); return false; } } @@ -266,7 +212,7 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl // If it is possible to determine that the handle cannot refer to an object type // that can potentially form a circular reference with the array then it is not // necessary to make the array garbage collected. - asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId); + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); asDWORD flags = subtype->GetFlags(); if( !(flags & asOBJ_GC) ) { @@ -317,7 +263,7 @@ static void RegisterScriptArray_Native(asIScriptEngine *engine) UNUSED_VAR(r); // Register the object type user data clean up - engine->SetObjectTypeUserDataCleanupCallback(CleanupObjectTypeArrayCache, ARRAY_CACHE); + engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); // Register the array type as a template r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); @@ -326,45 +272,54 @@ static void RegisterScriptArray_Native(asIScriptEngine *engine) r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL); assert( r >= 0 ); // Templates receive the object type as the first parameter. To the script writer this is hidden - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint, const T &in)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); // Register the factory that will be used for initialization lists - r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); // The memory management methods r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL); assert( r >= 0 ); // The index operator returns the template subtype - r = engine->RegisterObjectMethod("array", "T &opIndex(uint)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "const T &opIndex(uint) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); // The assignment operator r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL); assert( r >= 0 ); // Other methods - r = engine->RegisterObjectMethod("array", "void insertAt(uint, const T&in)", asMETHOD(CScriptArray, InsertAt), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeAt(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertLast(const T&in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert(r >= 0); r = engine->RegisterObjectMethod("array", "void removeLast()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asMETHOD(CScriptArray, RemoveRange), asCALL_THISCALL); assert(r >= 0); // TODO: Should length() and resize() be deprecated as the property accessors do the same thing? r = engine->RegisterObjectMethod("array", "uint length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void reserve(uint)", asMETHOD(CScriptArray, Reserve), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void resize(uint)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asMETHOD(CScriptArray, Reserve), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void resize(uint length)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void sortAsc()", asMETHODPR(CScriptArray, SortAsc, (), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc(uint, uint)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void sortDesc()", asMETHODPR(CScriptArray, SortDesc, (), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc(uint, uint)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void reverse()", asMETHOD(CScriptArray, Reverse), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(const T&in) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(uint, const T&in) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(const T&in) const", asMETHODPR(CScriptArray, FindByRef, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(uint, const T&in) const", asMETHODPR(CScriptArray, FindByRef, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // The token 'if_handle_then_const' tells the engine that if the type T is a handle, then it should refer to a read-only object + r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // TODO: It should be "int find(const T&in value, uint startAt = 0) const" + r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // TODO: It should be "int findByRef(const T&in value, uint startAt = 0) const" + r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asMETHOD(CScriptArray, operator==), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + // Sort with callback for comparison + r = engine->RegisterFuncdef("bool array::less(const T&in a, const T&in b)"); + r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asMETHODPR(CScriptArray, Sort, (asIScriptFunction*, asUINT, asUINT), void), asCALL_THISCALL); assert(r >= 0); + // Register virtual properties r = engine->RegisterObjectMethod("array", "uint get_length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void set_length(uint)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); @@ -386,7 +341,8 @@ static void RegisterScriptArray_Native(asIScriptEngine *engine) // Same as removeLast r = engine->RegisterObjectMethod("array", "void pop_back()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); // Same as insertAt - r = engine->RegisterObjectMethod("array", "void insert(uint, const T&in)", asMETHOD(CScriptArray, InsertAt), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insert(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insert(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); // Same as removeAt r = engine->RegisterObjectMethod("array", "void erase(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 ); #endif @@ -408,17 +364,20 @@ CScriptArray &CScriptArray::operator=(const CScriptArray &other) return *this; } -CScriptArray::CScriptArray(asIObjectType *ot, void *buf) +CScriptArray::CScriptArray(asITypeInfo *ti, void *buf) { + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + refCount = 1; gcFlag = false; - objType = ot; + objType = ti; objType->AddRef(); buffer = 0; Precache(); - asIScriptEngine *engine = ot->GetEngine(); + asIScriptEngine *engine = ti->GetEngine(); // Determine element size if( subTypeId & asTYPEID_MASK_OBJECT ) @@ -437,7 +396,7 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) } // Copy the values of the array elements from the buffer - if( (ot->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) + if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) { CreateBuffer(&buffer, length); @@ -445,7 +404,7 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) if( length > 0 ) memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); } - else if( ot->GetSubTypeId() & asTYPEID_OBJHANDLE ) + else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) { CreateBuffer(&buffer, length); @@ -459,7 +418,7 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) // its references too memset((((asUINT*)buf)+1), 0, length * elementSize); } - else if( ot->GetSubType()->GetFlags() & asOBJ_REF ) + else if( ti->GetSubType()->GetFlags() & asOBJ_REF ) { // Only allocate the buffer, but not the objects subTypeId |= asTYPEID_OBJHANDLE; @@ -488,8 +447,8 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) { void *obj = At(n); asBYTE *srcObj = (asBYTE*)buf; - srcObj += 4 + n*ot->GetSubType()->GetSize(); - engine->AssignScriptObject(obj, srcObj, ot->GetSubType()); + srcObj += 4 + n*ti->GetSubType()->GetSize(); + engine->AssignScriptObject(obj, srcObj, ti->GetSubType()); } } @@ -498,11 +457,14 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); } -CScriptArray::CScriptArray(asUINT length, asIObjectType *ot) +CScriptArray::CScriptArray(asUINT length, asITypeInfo *ti) { + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + refCount = 1; gcFlag = false; - objType = ot; + objType = ti; objType->AddRef(); buffer = 0; @@ -549,11 +511,14 @@ CScriptArray::CScriptArray(const CScriptArray &other) *this = other; } -CScriptArray::CScriptArray(asUINT length, void *defVal, asIObjectType *ot) +CScriptArray::CScriptArray(asUINT length, void *defVal, asITypeInfo *ti) { + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + refCount = 1; gcFlag = false; - objType = ot; + objType = ti; objType->AddRef(); buffer = 0; @@ -662,9 +627,8 @@ void CScriptArray::Reserve(asUINT maxElements) return; } - // TODO: memcpy assumes the objects in the array doesn't hold pointers to themselves - // This should really be using the objects copy/move constructor to copy each object - // to the new location. It would most likely be a hit on the performance though. + // As objects in arrays of objects are not stored inline, it is safe to use memcpy here + // since we're just copying the pointers to objects and not the actual objects. memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize); // Release the old buffer @@ -681,6 +645,34 @@ void CScriptArray::Resize(asUINT numElements) Resize((int)numElements - (int)buffer->numElements, (asUINT)-1); } +void CScriptArray::RemoveRange(asUINT start, asUINT count) +{ + if (count == 0) + return; + + if( buffer == 0 || start > buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Index out of bounds"); + return; + } + + // Cap count to the end of the array + if (start + count > buffer->numElements) + count = buffer->numElements - start; + + // Destroy the elements that are being removed + Destruct(buffer, start, start + count); + + // Compact the elements + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + start*elementSize, buffer->data + (start + count)*elementSize, (buffer->numElements - start - count)*elementSize); + buffer->numElements -= count; +} + // Internal void CScriptArray::Resize(int delta, asUINT at) { @@ -721,9 +713,8 @@ void CScriptArray::Resize(int delta, asUINT at) return; } - // TODO: memcpy assumes the objects in the array doesn't hold pointers to themselves - // This should really be using the objects copy/move constructor to copy each object - // to the new location. It would most likely be a hit on the performance though. + // As objects in arrays of objects are not stored inline, it is safe to use memcpy here + // since we're just copying the pointers to objects and not the actual objects. memcpy(newBuffer->data, buffer->data, at*elementSize); if( at < buffer->numElements ) memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize); @@ -739,17 +730,15 @@ void CScriptArray::Resize(int delta, asUINT at) else if( delta < 0 ) { Destruct(buffer, at, at-delta); - // TODO: memmove assumes the objects in the array doesn't hold pointers to themselves - // This should really be using the objects copy/move constructor to copy each object - // to the new location. It would most likely be a hit on the performance though. + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. memmove(buffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements - (at-delta))*elementSize); buffer->numElements += delta; } else { - // TODO: memmove assumes the objects in the array doesn't hold pointers to themselves - // This should really be using the objects copy/move constructor to copy each object - // to the new location. It would most likely be a hit on the performance though. + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. memmove(buffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements - at)*elementSize); Construct(buffer, at, at+delta); buffer->numElements += delta; @@ -779,7 +768,7 @@ bool CScriptArray::CheckMaxSize(asUINT numElements) return true; } -asIObjectType *CScriptArray::GetArrayObjectType() const +asITypeInfo *CScriptArray::GetArrayObjectType() const { return objType; } @@ -812,6 +801,61 @@ void CScriptArray::InsertAt(asUINT index, void *value) SetValue(index, value); } +void CScriptArray::InsertAt(asUINT index, const CScriptArray &arr) +{ + if (index > buffer->numElements) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Index out of bounds"); + return; + } + + if (objType != arr.objType) + { + // This shouldn't really be possible to happen when + // called from a script, but let's check for it anyway + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Mismatching array types"); + return; + } + + asUINT elements = arr.GetSize(); + Resize(elements, index); + if (&arr != this) + { + for (asUINT n = 0; n < arr.GetSize(); n++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + n, value); + } + } + else + { + // The array that is being inserted is the same as this one. + // So we should iterate over the elements before the index, + // and then the elements after + for (asUINT n = 0; n < index; n++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + n, value); + } + + for (asUINT n = index + elements, m = 0; n < arr.GetSize(); n++, m++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + index + m, value); + } + } +} + void CScriptArray::InsertLast(void *value) { InsertAt(buffer->numElements, value); @@ -859,6 +903,11 @@ void *CScriptArray::At(asUINT index) return const_cast(const_cast(this)->At(index)); } +void *CScriptArray::GetBuffer() +{ + return buffer->data; +} + // internal void CScriptArray::CreateBuffer(SArrayBuffer **buf, asUINT numElements) @@ -899,7 +948,7 @@ void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end) void **d = (void**)(buf->data + start * sizeof(void*)); asIScriptEngine *engine = objType->GetEngine(); - asIObjectType *subType = objType->GetSubType(); + asITypeInfo *subType = objType->GetSubType(); for( ; d < max; d++ ) { @@ -975,6 +1024,8 @@ bool CScriptArray::Less(const void *a, const void *b, bool asc, asIScriptContext } else { + int r = 0; + if( subTypeId & asTYPEID_OBJHANDLE ) { // Allow sort to work even if the array contains null handles @@ -986,7 +1037,7 @@ bool CScriptArray::Less(const void *a, const void *b, bool asc, asIScriptContext if( cache && cache->cmpFunc ) { // TODO: Add proper error handling - int r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); + r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); if( subTypeId & asTYPEID_OBJHANDLE ) { @@ -1219,7 +1270,7 @@ int CScriptArray::Find(asUINT startAt, void *value) const if( !cache || (cache->cmpFunc == 0 && cache->eqFunc == 0) ) { asIScriptContext *ctx = asGetActiveContext(); - asIObjectType* subType = objType->GetEngine()->GetObjectTypeById(subTypeId); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); // Throw an exception if( ctx ) @@ -1302,6 +1353,8 @@ int CScriptArray::Find(asUINT startAt, void *value) const // internal // Copy object handle or primitive value +// Even in arrays of objects the objects are allocated on +// the heap and the array stores the pointers to the objects void CScriptArray::Copy(void *dst, void *src) { memcpy(dst, src, elementSize); @@ -1317,17 +1370,17 @@ void *CScriptArray::GetArrayItemPointer(int index) // internal // Return pointer to data in buffer (object or primitive) -void *CScriptArray::GetDataPointer(void *buffer) +void *CScriptArray::GetDataPointer(void *buf) { if ((subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) { // Real address of object - return reinterpret_cast(*(size_t*)buffer); + return reinterpret_cast(*(size_t*)buf); } else { // Primitive is just a raw data - return buffer; + return buf; } } @@ -1367,7 +1420,7 @@ void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) if( !cache || cache->cmpFunc == 0 ) { asIScriptContext *ctx = asGetActiveContext(); - asIObjectType* subType = objType->GetEngine()->GetObjectTypeById(subTypeId); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); // Throw an exception if( ctx ) @@ -1434,10 +1487,7 @@ void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) } if( cmpContext == 0 ) { - // TODO: Ideally this context would be retrieved from a pool, so we don't have to - // create a new one everytime. We could keep a context with the array object - // but that would consume a lot of resources as each context is quite heavy. - cmpContext = objType->GetEngine()->CreateContext(); + cmpContext = objType->GetEngine()->RequestContext(); } } @@ -1467,7 +1517,88 @@ void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) cmpContext->Abort(); } else - cmpContext->Release(); + objType->GetEngine()->ReturnContext(cmpContext); + } +} + +// Sort with script callback for comparing elements +void CScriptArray::Sort(asIScriptFunction *func, asUINT startAt, asUINT count) +{ + // No need to sort + if (count < 2) + return; + + // Check if we could access invalid item while sorting + asUINT start = startAt; + asUINT end = asQWORD(startAt) + asQWORD(count) >= (asQWORD(1)<<32) ? 0xFFFFFFFF : startAt + count; + if (end > buffer->numElements) + end = buffer->numElements; + + if (start >= buffer->numElements) + { + asIScriptContext *ctx = asGetActiveContext(); + + // Throw an exception + if (ctx) + ctx->SetException("Index out of bounds"); + + return; + } + + asBYTE tmp[16]; + asIScriptContext *cmpContext = 0; + bool isNested = false; + + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if (cmpContext) + { + if (cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0) + isNested = true; + else + cmpContext = 0; + } + if (cmpContext == 0) + cmpContext = objType->GetEngine()->RequestContext(); + + // Insertion sort + for (asUINT i = start + 1; i < end; i++) + { + Copy(tmp, GetArrayItemPointer(i)); + + asUINT j = i - 1; + + while (j != 0xFFFFFFFF && j >= start ) + { + cmpContext->Prepare(func); + cmpContext->SetArgAddress(0, GetDataPointer(tmp)); + cmpContext->SetArgAddress(1, At(j)); + int r = cmpContext->Execute(); + if (r != asEXECUTION_FINISHED) + break; + if (*(bool*)(cmpContext->GetAddressOfReturnValue())) + { + Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); + j--; + } + else + break; + } + + Copy(GetArrayItemPointer(j + 1), tmp); + } + + if (cmpContext) + { + if (isNested) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if (state == asEXECUTION_ABORTED) + cmpContext->Abort(); + } + else + objType->GetEngine()->ReturnContext(cmpContext); } } @@ -1510,7 +1641,7 @@ void CScriptArray::CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src) void **d = (void**)dst->data; void **s = (void**)src->data; - asIObjectType *subType = objType->GetSubType(); + asITypeInfo *subType = objType->GetSubType(); for( ; d < max; d++, s++ ) engine->AssignScriptObject(*d, *s, subType); } @@ -1561,7 +1692,7 @@ void CScriptArray::Precache() // If the sub type is a handle to const, then the methods must be const too bool mustBeConst = (subTypeId & asTYPEID_HANDLETOCONST) ? true : false; - asIObjectType *subType = objType->GetEngine()->GetObjectTypeById(subTypeId); + asITypeInfo *subType = objType->GetEngine()->GetTypeInfoById(subTypeId); if( subType ) { for( asUINT i = 0; i < subType->GetMethodCount(); i++ ) @@ -1710,41 +1841,41 @@ bool CScriptArray::GetFlag() static void ScriptArrayFactory_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti); } static void ScriptArrayFactory2_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); asUINT length = gen->GetArgDWord(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, length); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length); } static void ScriptArrayListFactory_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); void *buf = gen->GetArgAddress(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, buf); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, buf); } static void ScriptArrayFactoryDefVal_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); asUINT length = gen->GetArgDWord(1); void *defVal = gen->GetArgAddress(2); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, length, defVal); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length, defVal); } static void ScriptArrayTemplateCallback_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ot, *dontGarbageCollect); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ti, *dontGarbageCollect); } static void ScriptArrayAssignment_Generic(asIScriptGeneric *gen) @@ -1808,6 +1939,14 @@ static void ScriptArrayInsertAt_Generic(asIScriptGeneric *gen) self->InsertAt(index, value); } +static void ScriptArrayInsertAtArray_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + CScriptArray *array = (CScriptArray*)gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertAt(index, *array); +} + static void ScriptArrayRemoveAt_Generic(asIScriptGeneric *gen) { asUINT index = gen->GetArgDWord(0); @@ -1815,6 +1954,14 @@ static void ScriptArrayRemoveAt_Generic(asIScriptGeneric *gen) self->RemoveAt(index); } +static void ScriptArrayRemoveRange_Generic(asIScriptGeneric *gen) +{ + asUINT start = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveRange(start, count); +} + static void ScriptArrayInsertLast_Generic(asIScriptGeneric *gen) { void *value = gen->GetArgAddress(0); @@ -1890,6 +2037,15 @@ static void ScriptArraySortDesc2_Generic(asIScriptGeneric *gen) self->SortDesc(index, count); } +static void ScriptArraySortCallback_Generic(asIScriptGeneric *gen) +{ + asIScriptFunction *callback = (asIScriptFunction*)gen->GetArgAddress(0); + asUINT startAt = gen->GetArgDWord(1); + asUINT count = gen->GetArgDWord(2); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Sort(callback, startAt, count); +} + static void ScriptArrayAddRef_Generic(asIScriptGeneric *gen) { CScriptArray *self = (CScriptArray*)gen->GetObject(); @@ -1939,39 +2095,43 @@ static void RegisterScriptArray_Generic(asIScriptEngine *engine) int r = 0; UNUSED_VAR(r); - engine->SetObjectTypeUserDataCleanupCallback(CleanupObjectTypeArrayCache, ARRAY_CACHE); + engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTION(ScriptArrayFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint)", asFUNCTION(ScriptArrayFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint, const T &in)", asFUNCTION(ScriptArrayFactoryDefVal_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length)", asFUNCTION(ScriptArrayFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTION(ScriptArrayFactoryDefVal_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in, int&in) {repeat T}", asFUNCTION(ScriptArrayListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptArrayAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptArrayRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "T &opIndex(uint)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "const T &opIndex(uint) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asFUNCTION(ScriptArrayAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertAt(uint, const T&in)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeAt(uint)", asFUNCTION(ScriptArrayRemoveAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertLast(const T&in)", asFUNCTION(ScriptArrayInsertLast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asFUNCTION(ScriptArrayInsertAtArray_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asFUNCTION(ScriptArrayInsertLast_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asFUNCTION(ScriptArrayRemoveAt_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void removeLast()", asFUNCTION(ScriptArrayRemoveLast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asFUNCTION(ScriptArrayRemoveRange_Generic), asCALL_GENERIC); assert(r >= 0); r = engine->RegisterObjectMethod("array", "uint length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void reserve(uint)", asFUNCTION(ScriptArrayReserve_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void resize(uint)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asFUNCTION(ScriptArrayReserve_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void resize(uint length)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void sortAsc()", asFUNCTION(ScriptArraySortAsc_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc(uint, uint)", asFUNCTION(ScriptArraySortAsc2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asFUNCTION(ScriptArraySortAsc2_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void sortDesc()", asFUNCTION(ScriptArraySortDesc_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc(uint, uint)", asFUNCTION(ScriptArraySortDesc2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asFUNCTION(ScriptArraySortDesc2_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void reverse()", asFUNCTION(ScriptArrayReverse_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(const T&in) const", asFUNCTION(ScriptArrayFind_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(uint, const T&in) const", asFUNCTION(ScriptArrayFind2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(const T&in) const", asFUNCTION(ScriptArrayFindByRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(uint, const T&in) const", asFUNCTION(ScriptArrayFindByRef2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "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", "bool opEquals(const array&in) const", asFUNCTION(ScriptArrayEquals_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asFUNCTION(ScriptArrayIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterFuncdef("bool array::less(const T&in a, const T&in b)"); + r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asFUNCTION(ScriptArraySortCallback_Generic), asCALL_GENERIC); assert(r >= 0); r = engine->RegisterObjectMethod("array", "uint get_length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void set_length(uint)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptArrayGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); diff --git a/src/scriptengine/scriptarray.hpp b/src/scriptengine/scriptarray.hpp index a1c0a0a1d..e6eb2783a 100644 --- a/src/scriptengine/scriptarray.hpp +++ b/src/scriptengine/scriptarray.hpp @@ -29,19 +29,19 @@ public: static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); // Factory functions - static CScriptArray *Create(asIObjectType *ot); - static CScriptArray *Create(asIObjectType *ot, asUINT length); - static CScriptArray *Create(asIObjectType *ot, asUINT length, void *defaultValue); - static CScriptArray *Create(asIObjectType *ot, void *listBuffer); + static CScriptArray *Create(asITypeInfo *ot); + static CScriptArray *Create(asITypeInfo *ot, asUINT length); + static CScriptArray *Create(asITypeInfo *ot, asUINT length, void *defaultValue); + static CScriptArray *Create(asITypeInfo *ot, void *listBuffer); // Memory management void AddRef() const; void Release() const; // Type information - asIObjectType *GetArrayObjectType() const; - int GetArrayTypeId() const; - int GetElementTypeId() const; + asITypeInfo *GetArrayObjectType() const; + int GetArrayTypeId() const; + int GetElementTypeId() const; // Get the current size asUINT GetSize() const; @@ -73,20 +73,26 @@ public: // Array manipulation void InsertAt(asUINT index, void *value); - void RemoveAt(asUINT index); + void InsertAt(asUINT index, const CScriptArray &arr); void InsertLast(void *value); + void RemoveAt(asUINT index); void RemoveLast(); + void RemoveRange(asUINT start, asUINT count); void SortAsc(); void SortDesc(); void SortAsc(asUINT startAt, asUINT count); void SortDesc(asUINT startAt, asUINT count); void Sort(asUINT startAt, asUINT count, bool asc); + void Sort(asIScriptFunction *less, asUINT startAt, asUINT count); void Reverse(); int Find(void *value) const; int Find(asUINT startAt, void *value) const; int FindByRef(void *ref) const; int FindByRef(asUINT startAt, void *ref) const; + // Return the address of internal buffer for direct manipulation of elements + void *GetBuffer(); + // GC methods int GetRefCount(); void SetFlag(); @@ -95,17 +101,17 @@ public: void ReleaseAllHandles(asIScriptEngine *engine); protected: - mutable int refCount; - mutable bool gcFlag; - asIObjectType *objType; - SArrayBuffer *buffer; - int elementSize; - int subTypeId; + mutable int refCount; + mutable bool gcFlag; + asITypeInfo *objType; + SArrayBuffer *buffer; + int elementSize; + int subTypeId; // Constructors - CScriptArray(asIObjectType *ot, void *initBuf); // Called from script when initialized with list - CScriptArray(asUINT length, asIObjectType *ot); - CScriptArray(asUINT length, void *defVal, asIObjectType *ot); + CScriptArray(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list + CScriptArray(asUINT length, asITypeInfo *ot); + CScriptArray(asUINT length, void *defVal, asITypeInfo *ot); CScriptArray(const CScriptArray &other); virtual ~CScriptArray(); diff --git a/src/scriptengine/scriptstdstring.cpp b/src/scriptengine/scriptstdstring.cpp index 381a78cc1..4da068109 100644 --- a/src/scriptengine/scriptstdstring.cpp +++ b/src/scriptengine/scriptstdstring.cpp @@ -1,33 +1,3 @@ -/* -AngelCode Scripting Library -Copyright (c) 2003-2015 Andreas Jonsson - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you -must not claim that you wrote the original software. If you use -this software in a product, an acknowledgment in the product -documentation would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. - -The original version of this library can be located at: -http://www.angelcode.com/angelscript/ - -Andreas Jonsson -andreas@angelcode.com -*/ - #include "scriptstdstring.hpp" #include // assert() #include // std::stringstream @@ -37,120 +7,86 @@ andreas@angelcode.com #ifndef __psp2__ #include // setlocale() #endif -#include // std::map using namespace std; -BEGIN_AS_NAMESPACE - // This macro is used to avoid warnings about unused variables. // Usually where the variables are only used in debug mode. #define UNUSED_VAR(x) (void)(x) -#if AS_USE_STRINGPOOL == 1 - -// By keeping the literal strings in a pool the application -// performance is improved as there are less string copies created. - -// The string pool will be kept as user data in the engine. We'll -// need a specific type to identify the string pool user data. -// We just define a number here that we assume nobody else is using for -// object type user data. The add-ons have reserved the numbers 1000 -// through 1999 for this purpose, so we should be fine. -const asPWORD STRING_POOL = 1001; - -// This global static variable is placed here rather than locally within the -// StringFactory, due to memory leak detectors that don't see the deallocation -// of global variables. By placing the variable globally it will be initialized -// before the memory leak detector starts, thus it won't report the missing -// deallocation. An example of this the Marmalade leak detector initialized with -// IwGxInit() and finished with IwGxTerminate(). -static const string emptyString; - -static const string &StringFactory(asUINT length, const char *s) -{ - // Each engine instance has its own string pool - asIScriptContext *ctx = asGetActiveContext(); - if( ctx == 0 ) - { - // The string factory can only be called from a script - assert( ctx ); - return emptyString; - } - asIScriptEngine *engine = ctx->GetEngine(); - - // TODO: runtime optimize: Use unordered_map if C++11 is supported, i.e. MSVC10+, gcc 4.?+ - map *pool = reinterpret_cast< map* >(engine->GetUserData(STRING_POOL)); - - if( !pool ) - { - // The string pool hasn't been created yet, so we'll create it now - asAcquireExclusiveLock(); - - // Make sure the string pool wasn't created while we were waiting for the lock - pool = reinterpret_cast< map* >(engine->GetUserData(STRING_POOL)); - if( !pool ) - { - #if defined(__S3E__) - pool = new map; - #else - pool = new (nothrow) map; - #endif - if( pool == 0 ) - { - ctx->SetException("Out of memory"); - asReleaseExclusiveLock(); - return emptyString; - } - engine->SetUserData(pool, STRING_POOL); - } - - asReleaseExclusiveLock(); - } - - // We can't let other threads modify the pool while we query it - asAcquireSharedLock(); - - // First check if a string object hasn't been created already - map::iterator it; - it = pool->find(s); - if( it != pool->end() ) - { - asReleaseSharedLock(); - return it->second; - } - - asReleaseSharedLock(); - - // Acquire an exclusive lock so we can add the new string to the pool - asAcquireExclusiveLock(); - - // Make sure the string wasn't created while we were waiting for the exclusive lock - it = pool->find(s); - if( it == pool->end() ) - { - // Create a new string object - it = pool->insert(map::value_type(s, string(s, length))).first; - } - - asReleaseExclusiveLock(); - return it->second; -} - -static void CleanupEngineStringPool(asIScriptEngine *engine) -{ - map *pool = reinterpret_cast< map* >(engine->GetUserData(STRING_POOL)); - if( pool ) - delete pool; -} - +#ifdef AS_CAN_USE_CPP11 +// The string factory doesn't need to keep a specific order in the +// cache, so the unordered_map is faster than the ordinary map +#include // std::unordered_map +BEGIN_AS_NAMESPACE +typedef unordered_map map_t; +END_AS_NAMESPACE #else -static string StringFactory(asUINT length, const char *s) -{ - return string(s, length); -} +#include // std::map +BEGIN_AS_NAMESPACE +typedef map map_t; +END_AS_NAMESPACE #endif +class CStdStringFactory : public asIStringFactory +{ +public: + CStdStringFactory() {} + ~CStdStringFactory() + { + // The script engine must release each string + // constant that it has requested + assert(stringCache.size() == 0); + } + + const void *GetStringConstant(const char *data, asUINT length) + { + string str(data, length); + map_t::iterator it = stringCache.find(str); + if (it != stringCache.end()) + it->second++; + else + it = stringCache.insert(map_t::value_type(str, 1)).first; + + return reinterpret_cast(&it->first); + } + + int ReleaseStringConstant(const void *str) + { + if (str == 0) + return asERROR; + + map_t::iterator it = stringCache.find(*reinterpret_cast(str)); + if (it == stringCache.end()) + return asERROR; + + it->second--; + if (it->second == 0) + stringCache.erase(it); + return asSUCCESS; + } + + int GetRawStringData(const void *str, char *data, asUINT *length) const + { + if (str == 0) + return asERROR; + + if (length) + *length = (asUINT)reinterpret_cast(str)->length(); + + if (data) + memcpy(data, reinterpret_cast(str)->c_str(), reinterpret_cast(str)->length()); + + return asSUCCESS; + } + + // TODO: Make sure the access to the string cache is thread safe + map_t stringCache; +}; + +static CStdStringFactory stringFactory; + + static void ConstructString(string *thisPointer) { new(thisPointer) string(); @@ -371,7 +307,53 @@ static int StringCmp(const string &a, const string &b) static int StringFindFirst(const string &sub, asUINT start, const string &str) { // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find(sub, start); + return (int)str.find(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the first position where the one of the bytes in substring +// exists in the input string. If the characters in the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findFirstOf(const string &in sub, uint start = 0) const +static int StringFindFirstOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_first_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the last position where the one of the bytes in substring +// exists in the input string. If the characters in the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findLastOf(const string &in sub, uint start = -1) const +static int StringFindLastOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_last_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the first position where a byte other than those in substring +// exists in the input string. If none is found -1 is returned. +// +// AngelScript signature: +// int string::findFirstNotOf(const string &in sub, uint start = 0) const +static int StringFindFirstNotOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_first_not_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the last position where a byte other than those in substring +// exists in the input string. If none is found -1 is returned. +// +// AngelScript signature: +// int string::findLastNotOf(const string &in sub, uint start = -1) const +static int StringFindLastNotOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_last_of(sub, (size_t)(start < 0 ? string::npos : start)); } // This function returns the index of the last position where the substring @@ -383,9 +365,26 @@ static int StringFindFirst(const string &sub, asUINT start, const string &str) static int StringFindLast(const string &sub, int start, const string &str) { // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.rfind(sub, (size_t)start); + return (int)str.rfind(sub, (size_t)(start < 0 ? string::npos : start)); } +// AngelScript signature: +// void string::insert(uint pos, const string &in other) +static void StringInsert(unsigned int pos, const string &other, string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.insert(pos, other); +} + +// AngelScript signature: +// void string::erase(uint pos, int count = -1) +static void StringErase(unsigned int pos, int count, string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.erase(pos, (size_t)(count < 0 ? string::npos : count)); +} + + // AngelScript signature: // uint string::length() const static asUINT StringLength(const string &str) @@ -447,6 +446,50 @@ static string formatInt(asINT64 value, const string &options, asUINT width) return buf; } +// AngelScript signature: +// string formatUInt(uint64 val, const string &in options, uint width) +static string formatUInt(asQWORD value, const string &options, asUINT width) +{ + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool hexSmall = options.find("h") != string::npos; + bool hexLarge = options.find("H") != string::npos; + + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; + +#ifdef _WIN32 + fmt += "*I64"; +#else +#ifdef _LP64 + fmt += "*l"; +#else + fmt += "*ll"; +#endif +#endif + + if( hexSmall ) fmt += "x"; + else if( hexLarge ) fmt += "X"; + else fmt += "u"; + + string buf; + buf.resize(width+30); +#if _MSC_VER >= 1400 && !defined(__S3E__) + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); +#else + sprintf(&buf[0], fmt.c_str(), width, value); +#endif + buf.resize(strlen(&buf[0])); + + return buf; +} + // AngelScript signature: // string formatFloat(double val, const string &in options, uint width, uint precision) static string formatFloat(double value, const string &options, asUINT width, asUINT precision) @@ -540,15 +583,59 @@ static asINT64 parseInt(const string &val, asUINT base, asUINT *byteCount) return res; } +// AngelScript signature: +// uint64 parseUInt(const string &in val, uint base = 10, uint &out byteCount = 0) +static asQWORD parseUInt(const string &val, asUINT base, asUINT *byteCount) +{ + // Only accept base 10 and 16 + if (base != 10 && base != 16) + { + if (byteCount) *byteCount = 0; + return 0; + } + + const char *end = &val[0]; + + asQWORD res = 0; + if (base == 10) + { + while (*end >= '0' && *end <= '9') + { + res *= 10; + res += *end++ - '0'; + } + } + else if (base == 16) + { + while ((*end >= '0' && *end <= '9') || + (*end >= 'a' && *end <= 'f') || + (*end >= 'A' && *end <= 'F')) + { + res *= 16; + if (*end >= '0' && *end <= '9') + res += *end++ - '0'; + else if (*end >= 'a' && *end <= 'f') + res += *end++ - 'a' + 10; + else if (*end >= 'A' && *end <= 'F') + res += *end++ - 'A' + 10; + } + } + + if (byteCount) + *byteCount = asUINT(size_t(end - val.c_str())); + + return res; +} + // AngelScript signature: // double parseFloat(const string &in val, uint &out byteCount = 0) double parseFloat(const string &val, asUINT *byteCount) { char *end; - // WinCE doesn't have setlocale. Some quick testing on my current platform - // still manages to parse the numbers such as "3.14" even if the decimal for the - // locale is ",". + // WinCE doesn't have setlocale. Some quick testing on my current platform + // still manages to parse the numbers such as "3.14" even if the decimal for the + // locale is ",". #if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) // Set the locale to C so that we are guaranteed to parse the float value correctly char *orig = setlocale(LC_NUMERIC, 0); @@ -578,7 +665,7 @@ static string StringSubString(asUINT start, int count, const string &str) // Check for out-of-bounds string ret; if( start < str.length() && count != 0 ) - ret = str.substr(start, count); + ret = str.substr(start, (size_t)(count < 0 ? string::npos : count)); return ret; } @@ -591,7 +678,7 @@ static string StringSubString(asUINT start, int count, const string &str) // makro, so this wrapper was introduced as work around. static bool StringEquals(const std::string& lhs, const std::string& rhs) { - return lhs == rhs; + return lhs == rhs; } void RegisterStdString_Native(asIScriptEngine *engine) @@ -607,16 +694,7 @@ void RegisterStdString_Native(asIScriptEngine *engine) r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); #endif -#if AS_USE_STRINGPOOL == 1 - // Register the string factory - r = engine->RegisterStringFactory("const string &", asFUNCTION(StringFactory), asCALL_CDECL); assert( r >= 0 ); - - // Register the cleanup callback for the string pool - engine->SetEngineUserDataCleanupCallback(CleanupEngineStringPool, STRING_POOL); -#else - // Register the string factory - r = engine->RegisterStringFactory("string", asFUNCTION(StringFactory), asCALL_CDECL); assert( r >= 0 ); -#endif + r = engine->RegisterStringFactory("string", &stringFactory); // Register the object operator overloads r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); @@ -675,11 +753,20 @@ void RegisterStdString_Native(asIScriptEngine *engine) // Utilities r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options, uint width = 0)", asFUNCTION(formatInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options, uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); assert(r >= 0); + + r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); assert(r >= 0); r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt), asCALL_CDECL); assert(r >= 0); r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat), asCALL_CDECL); assert(r >= 0); #if AS_USE_STLNAMES == 1 @@ -694,112 +781,103 @@ void RegisterStdString_Native(asIScriptEngine *engine) #endif // TODO: Implement the following - // findFirstOf - // findLastOf - // findFirstNotOf - // findLastNotOf // findAndReplace - replaces a text found in the string // replaceRange - replaces a range of bytes in the string - // trim/trimLeft/trimRight // multiply/times/opMul/opMul_r - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----" } -#if AS_USE_STRINGPOOL == 1 -static void StringFactoryGeneric(asIScriptGeneric *gen) -{ - asUINT length = gen->GetArgDWord(0); - const char *s = (const char*)gen->GetArgAddress(1); - - // Return a reference to a string - gen->SetReturnAddress(const_cast(&StringFactory(length, s))); -} -#else -static void StringFactoryGeneric(asIScriptGeneric *gen) -{ - asUINT length = gen->GetArgDWord(0); - const char *s = (const char*)gen->GetArgAddress(1); - - // Return a string value - new (gen->GetAddressOfReturnLocation()) string(StringFactory(length, s)); -} -#endif - static void ConstructStringGeneric(asIScriptGeneric * gen) { - new (gen->GetObject()) string(); + new (gen->GetObject()) string(); } static void CopyConstructStringGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetArgObject(0)); - new (gen->GetObject()) string(*a); + string * a = static_cast(gen->GetArgObject(0)); + new (gen->GetObject()) string(*a); } static void DestructStringGeneric(asIScriptGeneric * gen) { - string * ptr = static_cast(gen->GetObject()); - ptr->~string(); + string * ptr = static_cast(gen->GetObject()); + ptr->~string(); } static void AssignStringGeneric(asIScriptGeneric *gen) { - string * a = static_cast(gen->GetArgObject(0)); - string * self = static_cast(gen->GetObject()); - *self = *a; - gen->SetReturnAddress(self); + string * a = static_cast(gen->GetArgObject(0)); + string * self = static_cast(gen->GetObject()); + *self = *a; + gen->SetReturnAddress(self); } static void AddAssignStringGeneric(asIScriptGeneric *gen) { - string * a = static_cast(gen->GetArgObject(0)); - string * self = static_cast(gen->GetObject()); - *self += *a; - gen->SetReturnAddress(self); + string * a = static_cast(gen->GetArgObject(0)); + string * self = static_cast(gen->GetObject()); + *self += *a; + gen->SetReturnAddress(self); } static void StringEqualsGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); - *(bool*)gen->GetAddressOfReturnLocation() = (*a == *b); + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + *(bool*)gen->GetAddressOfReturnLocation() = (*a == *b); } static void StringCmpGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); - int cmp = 0; - if( *a < *b ) cmp = -1; - else if( *a > *b ) cmp = 1; + int cmp = 0; + if( *a < *b ) cmp = -1; + else if( *a > *b ) cmp = 1; - *(int*)gen->GetAddressOfReturnLocation() = cmp; + *(int*)gen->GetAddressOfReturnLocation() = cmp; } static void StringAddGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); - string ret_val = *a + *b; - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + string ret_val = *a + *b; + gen->SetReturnObject(&ret_val); } static void StringLengthGeneric(asIScriptGeneric * gen) { - string * self = static_cast(gen->GetObject()); - *static_cast(gen->GetAddressOfReturnLocation()) = (asUINT)self->length(); + string * self = static_cast(gen->GetObject()); + *static_cast(gen->GetAddressOfReturnLocation()) = (asUINT)self->length(); } static void StringIsEmptyGeneric(asIScriptGeneric * gen) { - string * self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringIsEmpty(*self); + string * self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringIsEmpty(*self); } static void StringResizeGeneric(asIScriptGeneric * gen) { - string * self = static_cast(gen->GetObject()); - self->resize(*static_cast(gen->GetAddressOfArg(0))); + string * self = static_cast(gen->GetObject()); + self->resize(*static_cast(gen->GetAddressOfArg(0))); +} + +static void StringInsert_Generic(asIScriptGeneric *gen) +{ + string * self = static_cast(gen->GetObject()); + asUINT pos = gen->GetArgDWord(0); + string *other = reinterpret_cast(gen->GetArgAddress(1)); + StringInsert(pos, *other, *self); +} + +static void StringErase_Generic(asIScriptGeneric *gen) +{ + string * self = static_cast(gen->GetObject()); + asUINT pos = gen->GetArgDWord(0); + int count = int(gen->GetArgDWord(1)); + StringErase(pos, count, *self); } static void StringFindFirst_Generic(asIScriptGeneric * gen) @@ -818,6 +896,38 @@ static void StringFindLast_Generic(asIScriptGeneric * gen) *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLast(*find, start, *self); } +static void StringFindFirstOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstOf(*find, start, *self); +} + +static void StringFindLastOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastOf(*find, start, *self); +} + +static void StringFindFirstNotOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstNotOf(*find, start, *self); +} + +static void StringFindLastNotOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastNotOf(*find, start, *self); +} + static void formatInt_Generic(asIScriptGeneric * gen) { asINT64 val = gen->GetArgQWord(0); @@ -826,6 +936,14 @@ static void formatInt_Generic(asIScriptGeneric * gen) new(gen->GetAddressOfReturnLocation()) string(formatInt(val, *options, width)); } +static void formatUInt_Generic(asIScriptGeneric * gen) +{ + asQWORD val = gen->GetArgQWord(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + new(gen->GetAddressOfReturnLocation()) string(formatUInt(val, *options, width)); +} + static void formatFloat_Generic(asIScriptGeneric *gen) { double val = gen->GetArgDouble(0); @@ -843,6 +961,14 @@ static void parseInt_Generic(asIScriptGeneric *gen) gen->SetReturnQWord(parseInt(*str,base,byteCount)); } +static void parseUInt_Generic(asIScriptGeneric *gen) +{ + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT base = gen->GetArgDWord(1); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); + gen->SetReturnQWord(parseUInt(*str, base, byteCount)); +} + static void parseFloat_Generic(asIScriptGeneric *gen) { string *str = reinterpret_cast(gen->GetArgAddress(0)); @@ -852,21 +978,21 @@ static void parseFloat_Generic(asIScriptGeneric *gen) static void StringCharAtGeneric(asIScriptGeneric * gen) { - unsigned int index = gen->GetArgDWord(0); - string * self = static_cast(gen->GetObject()); + unsigned int index = gen->GetArgDWord(0); + string * self = static_cast(gen->GetObject()); - if (index >= self->size()) - { - // Set a script exception - asIScriptContext *ctx = asGetActiveContext(); - ctx->SetException("Out of range"); + if (index >= self->size()) + { + // Set a script exception + asIScriptContext *ctx = asGetActiveContext(); + ctx->SetException("Out of range"); - gen->SetReturnAddress(0); - } - else - { - gen->SetReturnAddress(&(self->operator [](index))); - } + gen->SetReturnAddress(0); + } + else + { + gen->SetReturnAddress(&(self->operator [](index))); + } } static void AssignInt2StringGeneric(asIScriptGeneric *gen) @@ -921,163 +1047,163 @@ static void AssignBool2StringGeneric(asIScriptGeneric *gen) static void AddAssignDouble2StringGeneric(asIScriptGeneric * gen) { - double * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); + double * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignFloat2StringGeneric(asIScriptGeneric * gen) { - float * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); + float * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignInt2StringGeneric(asIScriptGeneric * gen) { - asINT64 * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); + asINT64 * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignUInt2StringGeneric(asIScriptGeneric * gen) { - asQWORD * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); + asQWORD * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignBool2StringGeneric(asIScriptGeneric * gen) { - bool * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << (*a ? "true" : "false"); - *self += sstr.str(); - gen->SetReturnAddress(self); + bool * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false"); + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddString2DoubleGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - double * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + double * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddString2FloatGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - float * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + float * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddString2IntGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - asINT64 * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + asINT64 * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddString2UIntGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - asQWORD * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + asQWORD * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddString2BoolGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - bool * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << (*b ? "true" : "false"); - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + bool * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << (*b ? "true" : "false"); + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddDouble2StringGeneric(asIScriptGeneric * gen) { - double* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + double* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddFloat2StringGeneric(asIScriptGeneric * gen) { - float* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + float* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddInt2StringGeneric(asIScriptGeneric * gen) { - asINT64* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + asINT64* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddUInt2StringGeneric(asIScriptGeneric * gen) { - asQWORD* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + asQWORD* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddBool2StringGeneric(asIScriptGeneric * gen) { - bool* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << (*a ? "true" : "false") << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + bool* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false") << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void StringSubString_Generic(asIScriptGeneric *gen) { - // Get the arguments - string *str = (string*)gen->GetObject(); - asUINT start = *(int*)gen->GetAddressOfArg(0); - int count = *(int*)gen->GetAddressOfArg(1); + // Get the arguments + string *str = (string*)gen->GetObject(); + asUINT start = *(int*)gen->GetAddressOfArg(0); + int count = *(int*)gen->GetAddressOfArg(1); // Return the substring - new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str)); + new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str)); } void RegisterStdString_Generic(asIScriptEngine *engine) @@ -1088,16 +1214,7 @@ void RegisterStdString_Generic(asIScriptEngine *engine) // Register the string type r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); -#if AS_USE_STRINGPOOL == 1 - // Register the string factory - r = engine->RegisterStringFactory("const string &", asFUNCTION(StringFactoryGeneric), asCALL_GENERIC); assert( r >= 0 ); - - // Register the cleanup callback for the string pool - engine->SetEngineUserDataCleanupCallback(CleanupEngineStringPool, STRING_POOL); -#else - // Register the string factory - r = engine->RegisterStringFactory("string", asFUNCTION(StringFactoryGeneric), asCALL_GENERIC); assert( r >= 0 ); -#endif + r = engine->RegisterStringFactory("string", &stringFactory); // Register the object operator overloads r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); @@ -1147,13 +1264,22 @@ void RegisterStdString_Generic(asIScriptEngine *engine) r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddString2BoolGeneric), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options, uint width = 0)", asFUNCTION(formatInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options, uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_Generic), asCALL_GENERIC); assert(r >= 0); + + r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_Generic), asCALL_GENERIC); assert(r >= 0); r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt_Generic), asCALL_GENERIC); assert(r >= 0); r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat_Generic), asCALL_GENERIC); assert(r >= 0); } diff --git a/src/scriptengine/scriptstdstring.hpp b/src/scriptengine/scriptstdstring.hpp index d7e3a49c6..9d8ac53cf 100644 --- a/src/scriptengine/scriptstdstring.hpp +++ b/src/scriptengine/scriptstdstring.hpp @@ -11,29 +11,17 @@ #ifndef SCRIPTSTDSTRING_H #define SCRIPTSTDSTRING_H -// String must be included before angelscript.h to avoid some errors during -// compilation with GetObject function -#include - #ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif +#include + //--------------------------- // Compilation settings // -// The use of the string pool can improve performance quite drastically -// for scripts that work with a lot of literal string constants. -// -// 1 = on -// 0 = off - -#ifndef AS_USE_STRINGPOOL -#define AS_USE_STRINGPOOL 1 -#endif - // Sometimes it may be desired to use the same method names as used by C++ STL. // This may for example reduce time when converting code from script to C++ or // back. diff --git a/src/scriptengine/scriptstdstring_utils.cpp b/src/scriptengine/scriptstdstring_utils.cpp index d46fea751..3abd02896 100644 --- a/src/scriptengine/scriptstdstring_utils.cpp +++ b/src/scriptengine/scriptstdstring_utils.cpp @@ -28,7 +28,7 @@ static CScriptArray *StringSplit(const string &delim, const string &str) // TODO: This should only be done once // TODO: This assumes that CScriptArray was already registered - asIObjectType *arrayType = engine->GetObjectTypeByDecl("array"); + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); // Create the array object CScriptArray *array = CScriptArray::Create(arrayType);