Browse Source

Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer

Arnis Lielturks 6 years ago
parent
commit
7bcd6beaaf
41 changed files with 1491 additions and 613 deletions
  1. 8 11
      .travis.yml
  2. 1 1
      CMake/Modules/UrhoCommon.cmake
  3. 2 1
      Docs/Urho3D.dox
  4. 2 1
      README.md
  5. 3 3
      Rakefile
  6. 10 4
      Source/ThirdParty/AngelScript/include/angelscript.h
  7. 178 39
      Source/ThirdParty/AngelScript/source/as_builder.cpp
  8. 4 2
      Source/ThirdParty/AngelScript/source/as_builder.h
  9. 72 5
      Source/ThirdParty/AngelScript/source/as_bytecode.cpp
  10. 4 1
      Source/ThirdParty/AngelScript/source/as_bytecode.h
  11. 0 18
      Source/ThirdParty/AngelScript/source/as_callfunc_x86.cpp
  12. 332 100
      Source/ThirdParty/AngelScript/source/as_compiler.cpp
  13. 5 3
      Source/ThirdParty/AngelScript/source/as_compiler.h
  14. 259 100
      Source/ThirdParty/AngelScript/source/as_context.cpp
  15. 8 5
      Source/ThirdParty/AngelScript/source/as_context.h
  16. 170 126
      Source/ThirdParty/AngelScript/source/as_parser.cpp
  17. 3 2
      Source/ThirdParty/AngelScript/source/as_parser.h
  18. 87 41
      Source/ThirdParty/AngelScript/source/as_restore.cpp
  19. 64 30
      Source/ThirdParty/AngelScript/source/as_scriptengine.cpp
  20. 3 2
      Source/ThirdParty/AngelScript/source/as_scriptengine.h
  21. 11 5
      Source/ThirdParty/AngelScript/source/as_scriptfunction.cpp
  22. 21 8
      Source/ThirdParty/AngelScript/source/as_scriptfunction.h
  23. 3 2
      Source/ThirdParty/AngelScript/source/as_scriptnode.h
  24. 2 1
      Source/ThirdParty/AngelScript/source/as_scriptobject.cpp
  25. 2 0
      Source/ThirdParty/AngelScript/source/as_texts.h
  26. 7 2
      Source/ThirdParty/AngelScript/source/as_tokendef.h
  27. 2 32
      Source/Urho3D/IO/MemoryBuffer.cpp
  28. 2 32
      Source/Urho3D/IO/VectorBuffer.cpp
  29. 12 0
      Source/Urho3D/Math/MathDefs.h
  30. 10 4
      android/launcher-app/build.gradle.kts
  31. 92 23
      android/urho3d-lib/build.gradle.kts
  32. 2 1
      bin/Data/Scripts/Editor/AttributeEditor.as
  33. 2 1
      bin/Data/Scripts/Editor/EditorView.as
  34. 60 1
      build.gradle.kts
  35. 6 3
      buildSrc/src/main/kotlin/UrhoCommon.kt
  36. BIN
      gradle/wrapper/gradle-wrapper.jar
  37. 1 1
      gradle/wrapper/gradle-wrapper.properties
  38. 17 1
      gradlew
  39. 17 1
      gradlew.bat
  40. 4 0
      script/.env-file
  41. 3 0
      settings.gradle.kts

+ 8 - 11
.travis.yml

@@ -234,27 +234,24 @@ env:
   global:
     - secure: SLJCjkjDsTMbCIV9Wecz5JATnhk0fuzlnLMeZdvvFDv+8NL8cXyutkU0VfyRSLf3HSD1Js79a6fRMROyVGWj/w/BRrjqGnZzsB6+ZeJNnadiVIF5Gh+w90We5ccvSp2G4DyYgwkNnkKlJK7zNEWGu/K+bHL1EOCA+EIVrFMyA44=
     - secure: ecj/PwpbHkH9AYFsc2TMeRuNm5E3xMM8A0x4AcGhzpwDuZWdFx3R1T4G9u45Z5aUyTJWGqOeX1JPaEVVFZuYnNBKRy0kmiUrM9EE0j7WsT57K48tP1ysn2ynyvHgbYkKOfYR0t8XAMWTBbulT9DVVk3DS69//2WgiXGDVUEJTyI=
+    - secure: S6Vb3QUW8mDLkLrsIRSullTjwHM1ZIeG4rUT1Nwqx4XSovTZDvq9OThrzAvnuA6sYzeyDI2WHCeBUgmiKFyVBiB2NZwZZjRlTTAC2GVyRZKph9ErhJH3O0DfbPErICQAxL+RI6uCU6nSRPzq4L64UbZi5t04n6f95JXWmfeX2oY=
     - ANDROID=1
     - ORG_GRADLE_PROJECT_URHO3D_LUAJIT=1
+    - HOT=$HOME/urho3d_home_dir/.ccache/.hot
   matrix:
-    - ORG_GRADLE_PROJECT_ANDROID_ABI=x86 ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=STATIC
-    - ORG_GRADLE_PROJECT_ANDROID_ABI=x86 ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=SHARED
-    - ORG_GRADLE_PROJECT_ANDROID_ABI=x86_64 ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=STATIC
-    - ORG_GRADLE_PROJECT_ANDROID_ABI=x86_64 ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=SHARED
-    - ORG_GRADLE_PROJECT_ANDROID_ABI=armeabi-v7a ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=STATIC
-    - ORG_GRADLE_PROJECT_ANDROID_ABI=armeabi-v7a ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=SHARED
-    - ORG_GRADLE_PROJECT_ANDROID_ABI=arm64-v8a ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=STATIC
-    - ORG_GRADLE_PROJECT_ANDROID_ABI=arm64-v8a ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=SHARED
-stage: split ABI build configuration
+    - ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=STATIC
+    - ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE=SHARED
+stage: universal build configuration
 before_script:
   - rake ci_timer
   - export TRAVIS_COMMIT=$TRAVIS_COMMIT~
   - export COMMIT_MESSAGE=$(git log --format=%B -n1 $TRAVIS_COMMIT)
   - export TAG=$(git describe --exact-match $TRAVIS_COMMIT 2>/dev/null); if [[ $TAG =~ [[:digit:]]+\.[[:digit:]]+ ]]; then export RELEASE_TAG=$TAG; fi
-  - if [[ $RELEASE_TAG ]] || (! [[ $TRAVIS_BRANCH =~ [^-]+-[^-]+-CI ]] && echo $COMMIT_MESSAGE |grep -cq '\[ci package\]'); then export PACKAGE_UPLOAD=1; fi
+  - if [[ $RELEASE_TAG ]] || (! [[ $TRAVIS_BRANCH =~ [^-]+-[^-]+-CI ]] && echo $COMMIT_MESSAGE |grep -cq '\[ci package\]'); then export bintrayUpload=bintrayUpload; fi
+  - if (echo $COMMIT_MESSAGE |grep -cq '\[cache clear\]' || [[ ! -e $HOT ]]); then export ORG_GRADLE_PROJECT_ANDROID_ABI=arm64-v8a,armeabi-v7a; unset bintrayUpload; fi; touch $HOT
   - if [[ "$ORG_GRADLE_PROJECT_URHO3D_LIB_TYPE" == "STATIC" ]]; then export ORG_GRADLE_PROJECT_URHO3D_SAMPLES=0; fi
   - rake ci_setup_cache
-script: script/dockerized.sh android ./gradlew build publishToMavenLocal --console plain && if [[ $PACKAGE_UPLOAD ]]; then script/dockerized.sh android rake ci_package_upload; fi && rake ci_timer
+script: script/dockerized.sh android ./gradlew build $bintrayUpload --console plain && rake ci_timer
 matrix:
   fast_finish: true
   include: [stage: housekeep]

+ 1 - 1
CMake/Modules/UrhoCommon.cmake

@@ -730,7 +730,7 @@ else ()
             set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics")
             set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
         endif ()
-        if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0.1 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0.1)
+        if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.1 AND NOT APPLE)
             # Workaround for Clang 7.0.1 and above until the Bullet upstream has fixed the Clang 7 diagnostic checks issue (see https://github.com/bulletphysics/bullet3/issues/2114)
             set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-argument-outside-range")
             set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-argument-outside-range")

+ 2 - 1
Docs/Urho3D.dox

@@ -67,6 +67,7 @@ Urho3D development, contributions and bugfixes by:
 - Wei Tjong Yao
 - Aster Jian
 - Ricardo Abreu
+- Eli Aloni
 - Vivienne Anthony
 - Christopher Augustus
 - Colin Barrett
@@ -224,7 +225,7 @@ Urho3D is greatly inspired by OGRE (http://www.ogre3d.org/) and Horde3D (http://
 
 Urho3D uses the following third-party libraries:
 
-- AngelScript 2.33.0 WIP (http://www.angelcode.com/angelscript)
+- AngelScript 2.33.0+ (http://www.angelcode.com/angelscript)
 - Boost 1.64.0 (http://www.boost.org) - only used for AngelScript generic bindings
 - Box2D 2.3.2 WIP (http://box2d.org)
 - Bullet 2.86.1 (http://www.bulletphysics.org)

+ 2 - 1
README.md

@@ -21,6 +21,7 @@ Urho3D development, contributions and bugfixes by:
 - Wei Tjong Yao
 - Aster Jian
 - Ricardo Abreu
+- Eli Aloni
 - Vivienne Anthony
 - Christopher Augustus
 - Colin Barrett
@@ -188,7 +189,7 @@ Urho3D is greatly inspired by OGRE (http://www.ogre3d.org) and Horde3D
   http://warp.povusers.org/SortComparison/
 
 Urho3D uses the following third-party libraries:
-- AngelScript 2.33.0 WIP (http://www.angelcode.com/angelscript)
+- AngelScript 2.33.0+ (http://www.angelcode.com/angelscript)
 - Boost 1.64.0 (http://www.boost.org) - only used for AngelScript generic bindings
 - Box2D 2.3.2 WIP (http://box2d.org)
 - Bullet 2.86.1 (http://www.bulletphysics.org)

+ 3 - 3
Rakefile

@@ -323,9 +323,9 @@ task :ci do
   # When not explicitly specified then use generic generator
   generator = ENV['XCODE'] ? 'xcode' : (ENV['APPVEYOR'] ? (ENV['MINGW'] ? 'mingw' : 'vs2017') : '')
   # Cache the initial build tree for next run on platform that is slow to generate the build tree
-  system "mkdir -p #{ENV['build_tree']} && cp -rp #{ENV['HOME']}/initial-build-tree/* #{ENV['build_tree']}" if (ENV['OSX'] || ENV['WEB']) && ENV['CI'] && File.exist?("#{ENV['HOME']}/initial-build-tree/CMakeCache.txt")
+  system "mkdir -p #{ENV['build_tree']} && cp -rp #{ENV['HOME']}/initial-build-tree/* #{ENV['build_tree']} && git diff $(cat #{ENV['HOME']}/initial-build-tree/.sha1) $TRAVIS_COMMIT --name-only |grep -i cmake |xargs -r touch" if (ENV['OSX'] || ENV['WEB']) && ENV['CI'] && File.exist?("#{ENV['HOME']}/initial-build-tree/.sha1")
   system "rake cmake #{generator} URHO3D_DATABASE_SQLITE=1 URHO3D_EXTRAS=1" or abort 'Failed to configure Urho3D library build'
-  system "bash -c 'cp -rp #{ENV['build_tree']}/* #{ENV['HOME']}/initial-build-tree 2>/dev/null && rm -rf #{ENV['HOME']}/initial-build-tree/{bin,include} 2>/dev/null'" if (ENV['OSX'] || ENV['WEB']) && ENV['CI']
+  system "bash -c 'cp -rp #{ENV['build_tree']}/* #{ENV['HOME']}/initial-build-tree 2>/dev/null && rm -rf #{ENV['HOME']}/initial-build-tree/{bin,include} 2>/dev/null && echo $TRAVIS_COMMIT >#{ENV['HOME']}/initial-build-tree/.sha1'" if (ENV['OSX'] || ENV['WEB']) && ENV['CI']
   next if timeup    # Measure the CMake configuration overhead
   # Temporarily put the logic here for clang-tools migration until everything else are in their places
   if ENV['URHO3D_BINDINGS']
@@ -411,7 +411,7 @@ task :ci_setup_cache do
   # This is a hack as it relies on docker volume internal directory structure
   system 'docker volume create $(id -u).urho3d_home_dir && sudo rm -rf /var/lib/docker/volumes/$(id -u).urho3d_home_dir/_data && sudo ln -s $HOME/urho3d_home_dir /var/lib/docker/volumes/$(id -u).urho3d_home_dir/_data' or abort 'Failed to setup build cache'
   # Ensure '.build-options' and '.env-file' are up-to-date
-  system 'bash', '-c', %q(perl -ne 'undef $/; print $1 if /(Build Option.*?(?=\n\n))/s' Docs/GettingStarted.dox |tail -n +3 |cut -d'|' -f2 |tr -d [:blank:] >script/.build-options && cat script/.build-options <(perl -ne 'while (/(\w+)=.+?/g) {print "$1\n"}' .travis.yml) <(perl -ne 'while (/ENV\[\x27(\w+)\x27\]/g) {print "$1\n"}' Rakefile) |sort |uniq |grep -Ev '^(HOME|PATH)$' >script/.env-file) or abort 'Failed to update .build-options and .env-file'
+  system 'bash', '-c', %q(perl -ne 'undef $/; print $1 if /(Build Option.*?(?=\n\n))/s' Docs/GettingStarted.dox |tail -n +3 |cut -d'|' -f2 |tr -d [:blank:] >script/.build-options && cat script/.build-options <(perl -ne 'while (/(\w+)=.+?/g) {print "$1\n"}' .travis.yml) <(perl -ne 'while (/ENV\[\x27(\w+)\x27\]/g) {print "$1\n"}' Rakefile) <(perl -ne 'while (/System.getenv\\("(\w+)"\\)/g) {print "$1\n"}' android/urho3d-lib/build.gradle.kts) |sort |uniq |grep -Ev '^(HOME|PATH)$' >script/.env-file) or abort 'Failed to update .build-options and .env-file'
 end
 
 # Usage: NOT intended to be used manually

+ 10 - 4
Source/ThirdParty/AngelScript/include/angelscript.h

@@ -65,7 +65,7 @@ BEGIN_AS_NAMESPACE
 // AngelScript version
 
 #define ANGELSCRIPT_VERSION        23300
-#define ANGELSCRIPT_VERSION_STRING "2.33.0 WIP"
+#define ANGELSCRIPT_VERSION_STRING "2.33.0"
 
 // Data types
 
@@ -149,6 +149,9 @@ enum asEEngineProp
 	asEP_HEREDOC_TRIM_MODE                  = 26,
 	asEP_MAX_NESTED_CALLS                   = 27,
 	asEP_GENERIC_CALL_MODE                  = 28,
+	asEP_INIT_STACK_SIZE                    = 29,
+	asEP_INIT_CALL_STACK_SIZE               = 30,
+	asEP_MAX_CALL_STACK_SIZE                = 31,
 
 	asEP_LAST_PROPERTY
 };
@@ -421,7 +424,7 @@ typedef void (*asCIRCULARREFFUNC_t)(asITypeInfo *, const void *, void *);
 
 // This macro does basically the same thing as offsetof defined in stddef.h, but
 // GNUC should not complain about the usage as I'm not using 0 as the base pointer.
-#define asOFFSET(s,m) ((size_t)(&reinterpret_cast<s*>(100000)->m)-100000)
+#define asOFFSET(s,m) ((int)(size_t)(&reinterpret_cast<s*>(100000)->m)-100000)
 
 #define asFUNCTION(f) asFunctionPtr(f)
 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || (defined(__BORLANDC__) && __BORLANDC__ < 0x590)
@@ -926,10 +929,11 @@ public:
 	virtual void   *GetAddressOfReturnValue() = 0;
 
 	// Exception handling
-	virtual int                SetException(const char *string) = 0;
+	virtual int                SetException(const char *info, bool allowCatch = true) = 0;
 	virtual int                GetExceptionLineNumber(int *column = 0, const char **sectionName = 0) = 0;
 	virtual asIScriptFunction *GetExceptionFunction() = 0;
 	virtual const char *       GetExceptionString() = 0;
+	virtual bool               WillExceptionBeCaught() = 0;
 	virtual int                SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv) = 0;
 	virtual void               ClearExceptionCallback() = 0;
 
@@ -1132,6 +1136,7 @@ public:
 	virtual bool             IsFinal() const = 0;
 	virtual bool             IsOverride() const = 0;
 	virtual bool             IsShared() const = 0;
+	virtual bool             IsExplicit() 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;
 	virtual int              GetReturnTypeId(asDWORD *flags = 0) const = 0;
@@ -1588,6 +1593,7 @@ enum asEBCInstr
 	asBC_MAXBYTECODE	= 201,
 
 	// Temporary tokens. Can't be output to the final program
+	asBC_TryBlock		= 250,
 	asBC_VarDecl		= 251,
 	asBC_Block			= 252,
 	asBC_ObjInfo		= 253,
@@ -1930,8 +1936,8 @@ const asSBCInfo asBCInfo[256] =
 	asBCINFO_DUMMY(247),
 	asBCINFO_DUMMY(248),
 	asBCINFO_DUMMY(249),
-	asBCINFO_DUMMY(250),
 
+	asBCINFO(TryBlock,		DW_ARG,			0),
 	asBCINFO(VarDecl,		W_ARG,			0),
 	asBCINFO(Block,			INFO,			0),
 	asBCINFO(ObjInfo,		rW_DW_ARG,		0),

+ 178 - 39
Source/ThirdParty/AngelScript/source/as_builder.cpp

@@ -108,6 +108,7 @@ asCBuilder::~asCBuilder()
 	}
 
 	// Free all global variables
+	CleanupEnumValues();
 	asCSymbolTable<sGlobalVariableDescription>::iterator it = globVariables.List();
 	while( it )
 	{
@@ -227,6 +228,28 @@ int asCBuilder::AddCode(const char *name, const char *code, int codeLength, int
 	return 0;
 }
 
+asCScriptCode *asCBuilder::FindOrAddCode(const char *name, const char *code, asUINT length)
+{
+	for (asUINT n = 0; n < scripts.GetLength(); n++)
+		if( scripts[n]->name == name && scripts[n]->codeLength == length && memcmp(scripts[n]->code, code, length) == 0 )
+			return scripts[n];
+
+	asCScriptCode *script = asNEW(asCScriptCode);
+	if (script == 0)
+		return 0;
+
+	int r = script->SetCode(name, code, 0, true);
+	if (r < 0)
+	{
+		asDELETE(script, asCScriptCode);
+		return 0;
+	}
+
+	script->idx = engine->GetScriptSectionNameIndex(name);
+	scripts.PushLast(script);
+	return script;
+}
+
 void asCBuilder::EvaluateTemplateInstances(asUINT startIdx, bool keepSilent)
 {
 	// Backup the original message stream
@@ -289,6 +312,8 @@ int asCBuilder::Build()
 	asUINT numTempl = (asUINT)engine->templateInstanceTypes.GetLength();
 
 	ParseScripts();
+	if (numErrors > 0)
+		return asERROR;
 
 	// Compile the types first
 	CompileInterfaces();
@@ -298,6 +323,8 @@ int asCBuilder::Build()
 	// all classes have been fully built and it is known which ones will need garbage collection.
 	EvaluateTemplateInstances(numTempl, false);
 	engine->deferValidationOfTemplateTypes = false;
+	if (numErrors > 0)
+		return asERROR;
 
 	// Then the global variables. Here the variables declared with auto
 	// will be resolved, so they can be accessed properly in the functions
@@ -545,7 +572,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 )
 	{
-		r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->defaultNamespace);
+		r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->defaultNamespace, false);
 		if( r < 0 )
 		{
 			func->ReleaseInternal();
@@ -656,6 +683,14 @@ void asCBuilder::ParseScripts()
 		for( n = 0; n < funcDefs.GetLength(); n++ )
 			CompleteFuncDef(funcDefs[n]);
 
+		// Find other global nodes
+		for (n = 0; n < scripts.GetLength(); n++)
+		{
+			// Find other global nodes
+			asCScriptNode *node = parsers[n]->GetScriptNode();
+			RegisterNonTypesFromScript(node, scripts[n], engine->nameSpaces[0]);
+		}
+
 		// Register script methods found in the interfaces
 		for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
 		{
@@ -744,14 +779,6 @@ void asCBuilder::ParseScripts()
 				}
 			}
 		}
-
-		// Find other global nodes
-		for( n = 0; n < scripts.GetLength(); n++ )
-		{
-			// Find other global nodes
-			asCScriptNode *node = parsers[n]->GetScriptNode();
-			RegisterNonTypesFromScript(node, scripts[n], engine->nameSpaces[0]);
-		}
 	}
 
 	for( n = 0; n < parsers.GetLength(); n++ )
@@ -1049,7 +1076,7 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam
 	}
 	else
 	{
-		if( CheckNameConflict(name.AddressOf(), nameNode, &source, ns) < 0 )
+		if( CheckNameConflict(name.AddressOf(), nameNode, &source, ns, true) < 0 )
 			return asNAME_TAKEN;
 	}
 
@@ -1305,6 +1332,15 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec
 	else
 		func->SetReadOnly(false);
 
+	// Check for additional function traits
+	while (n && n->nodeType == snIdentifier)
+	{
+		if (source.TokenEquals(n->tokenPos, n->tokenLength, EXPLICIT_TOKEN))
+			func->SetExplicit(true);
+
+		n = n->next;
+	}
+
 	// If the caller expects a list pattern, check for the existence, else report an error if not
 	if( listPattern )
 	{
@@ -1365,6 +1401,7 @@ int asCBuilder::ParseVariableDeclaration(const char *decl, asSNameSpace *implici
 	return 0;
 }
 
+// TODO: This should use SymbolLookupMember, which should be available in the TypeInfo class
 int asCBuilder::CheckNameConflictMember(asCTypeInfo *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty)
 {
 	// It's not necessary to check against object types
@@ -1426,19 +1463,37 @@ int asCBuilder::CheckNameConflictMember(asCTypeInfo *t, const char *name, asCScr
 		}
 	}
 
+	// If there is a namespace at the same level with the same name as the class, then need to check for conflicts with symbols in that namespace too
+	// TODO: When classes can have static members, the code should change so that class name cannot be the same as a namespace
+	asCString scope;
+	if (ot->nameSpace->name != "")
+		scope = ot->nameSpace->name + "::" + ot->name;
+	else
+		scope = ot->name;
+	asSNameSpace *ns = engine->FindNameSpace(scope.AddressOf());
+	if (ns)
+	{
+		// Check as if not a function as it doesn't matter the function signature
+		return CheckNameConflict(name, node, code, ns, true);
+	}
+	
 	return 0;
 }
 
-int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns)
+// TODO: This should use SymbolLookup
+int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns, bool isProperty)
 {
 	// Check against registered object types
-	// TODO: Must check against registered funcdefs too
 	if( engine->GetRegisteredType(name, ns) != 0 )
 	{
 		if( code )
 		{
 			asCString str;
-			str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, name);
+			if (ns->name != "")
+				str = ns->name + "::" + name;
+			else
+				str = name;
+			str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, str.AddressOf());
 			WriteError(str, code, node);
 		}
 
@@ -1451,14 +1506,40 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
 		if( code )
 		{
 			asCString str;
-			str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, name);
+			if (ns->name != "")
+				str = ns->name + "::" + name;
+			else
+				str = name;
+			str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, str.AddressOf());
 			WriteError(str, code, node);
 		}
 
 		return -1;
 	}
 
-	// TODO: Property names must be checked against function names
+	// Property names must be checked against function names
+	if (isProperty)
+	{
+		for (asUINT n = 0; n < engine->registeredGlobalFuncs.GetSize(); n++)
+		{
+			if (engine->registeredGlobalFuncs.Get(n)->name == name &&
+				engine->registeredGlobalFuncs.Get(n)->nameSpace == ns)
+			{
+				if (code)
+				{
+					asCString str;
+					if (ns->name != "")
+						str = ns->name + "::" + name;
+					else
+						str = name;
+					str.Format(TXT_NAME_CONFLICT_s_IS_FUNCTION, str.AddressOf());
+					WriteError(str, code, node);
+				}
+
+				return -1;
+			}
+		}
+	}
 
 #ifndef AS_NO_COMPILER
 	// Check against class types
@@ -1471,7 +1552,11 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
 			if( code )
 			{
 				asCString str;
-				str.Format(TXT_NAME_CONFLICT_s_STRUCT, name);
+				if (ns->name != "")
+					str = ns->name + "::" + name;
+				else
+					str = name;
+				str.Format(TXT_NAME_CONFLICT_s_STRUCT, str.AddressOf());
 				WriteError(str, code, node);
 			}
 
@@ -1488,7 +1573,11 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
 			if( code )
 			{
 				asCString str;
-				str.Format(TXT_NAME_CONFLICT_s_IS_NAMED_TYPE, name);
+				if (ns->name != "")
+					str = ns->name + "::" + name;
+				else
+					str = name;
+				str.Format(TXT_NAME_CONFLICT_s_IS_NAMED_TYPE, str.AddressOf());
 				WriteError(str, code, node);
 			}
 
@@ -1505,7 +1594,11 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
 			if( code )
 			{
 				asCString str;
-				str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name);
+				if (ns->name != "")
+					str = ns->name + "::" + name;
+				else
+					str = name;
+				str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, str.AddressOf());
 				WriteError(str, code, node);
 			}
 
@@ -1519,12 +1612,42 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
 		if( code )
 		{
 			asCString str;
-			str.Format(TXT_NAME_CONFLICT_s_IS_MIXIN, name);
+			if (ns->name != "")
+				str = ns->name + "::" + name;
+			else
+				str = name;
+			str.Format(TXT_NAME_CONFLICT_s_IS_MIXIN, str.AddressOf());
 			WriteError(str, code, node);
 		}
 
 		return -1;
 	}
+
+	// Property names must be checked against function names
+	if (isProperty)
+	{
+		for (n = 0; n < functions.GetLength(); n++)
+		{
+			if (functions[n] && 
+				functions[n]->objType == 0 && 
+				functions[n]->name == name &&
+				engine->scriptFunctions[functions[n]->funcId]->nameSpace == ns )
+			{
+				if (code)
+				{
+					asCString str;
+					if (ns->name != "")
+						str = ns->name + "::" + name;
+					else
+						str = name;
+					str.Format(TXT_NAME_CONFLICT_s_IS_FUNCTION, str.AddressOf());
+					WriteError(str, code, node);
+				}
+
+				return -1;
+			}
+		}
+	}
 #endif
 
 	return 0;
@@ -1561,7 +1684,7 @@ int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNam
 	// Check for name conflict with other types
 	if (ns)
 	{
-		int r = CheckNameConflict(name.AddressOf(), node, file, ns);
+		int r = CheckNameConflict(name.AddressOf(), node, file, ns, true);
 		if (asSUCCESS != r)
 		{
 			node->Destroy(engine);
@@ -1718,7 +1841,7 @@ int asCBuilder::RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSN
 	{
 		// Verify that the name isn't taken
 		asCString name(&file->code[n->tokenPos], n->tokenLength);
-		CheckNameConflict(name.AddressOf(), n, file, ns);
+		CheckNameConflict(name.AddressOf(), n, file, ns, true);
 
 		// Register the global variable
 		sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription);
@@ -1795,7 +1918,7 @@ int asCBuilder::RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asS
 	int r, c;
 	file->ConvertPosToRowCol(n->tokenPos, &r, &c);
 
-	CheckNameConflict(name.AddressOf(), n, file, ns);
+	CheckNameConflict(name.AddressOf(), n, file, ns, true);
 
 	sMixinClass *decl = asNEW(sMixinClass);
 	if( decl == 0 )
@@ -1905,7 +2028,7 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS
 	int r, c;
 	file->ConvertPosToRowCol(n->tokenPos, &r, &c);
 
-	CheckNameConflict(name.AddressOf(), n, file, ns);
+	CheckNameConflict(name.AddressOf(), n, file, ns, true);
 
 	sClassDeclaration *decl = asNEW(sClassDeclaration);
 	if( decl == 0 )
@@ -2076,7 +2199,7 @@ int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSN
 
 	asCString name;
 	name.Assign(&file->code[n->tokenPos], n->tokenLength);
-	CheckNameConflict(name.AddressOf(), n, file, ns);
+	CheckNameConflict(name.AddressOf(), n, file, ns, true);
 
 	sClassDeclaration *decl = asNEW(sClassDeclaration);
 	if( decl == 0 )
@@ -2447,28 +2570,33 @@ void asCBuilder::CompileGlobalVariables()
 			module->scriptGlobals.SwapWith(initOrder);
 	}
 
+	CleanupEnumValues();
+}
+
+void asCBuilder::CleanupEnumValues()
+{
 	// Delete the enum expressions
 	asCSymbolTableIterator<sGlobalVariableDescription> it = globVariables.List();
-	while( it )
+	while (it)
 	{
 		sGlobalVariableDescription *gvar = *it;
-		if( gvar->isEnumValue )
+		if (gvar->isEnumValue)
 		{
 			// Remove from symboltable. This has to be done prior to freeing the memeory
 			globVariables.Erase(it.GetIndex());
 
 			// Destroy the gvar property
-			if( gvar->declaredAtNode )
+			if (gvar->declaredAtNode)
 			{
 				gvar->declaredAtNode->Destroy(engine);
 				gvar->declaredAtNode = 0;
 			}
-			if( gvar->initializationNode )
+			if (gvar->initializationNode)
 			{
 				gvar->initializationNode->Destroy(engine);
 				gvar->initializationNode = 0;
 			}
-			if( gvar->property )
+			if (gvar->property)
 			{
 				asDELETE(gvar->property, asCGlobalProperty);
 				gvar->property = 0;
@@ -2624,6 +2752,14 @@ void asCBuilder::CompileInterfaces()
 	for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
 	{
 		sClassDeclaration *intfDecl = interfaceDeclarations[n];
+		if( intfDecl->isExistingShared )
+		{
+			// Set the declaration as validated already, so that other
+			// types that contain this will accept this type
+			intfDecl->validState = 1;
+			continue;
+		}
+		
 		asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo);
 
 		// TODO: Is this really at the correct place? Hasn't the vfTableIdx already been set here?
@@ -2916,7 +3052,6 @@ void asCBuilder::CompileClasses(asUINT numTempl)
 	asUINT n;
 	asCArray<sClassDeclaration*> 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++ )
@@ -4006,7 +4141,7 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp
 		module->externalTypes.PushLast(existingSharedType);
 
 	// Check the name and add the enum
-	int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file, ns);
+	int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file, ns, true);
 	if( asSUCCESS == r )
 	{
 		asCEnumType *st;
@@ -4176,7 +4311,7 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam
 	name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength);
 
 	// If the name is not already in use add it
- 	int r = CheckNameConflict(name.AddressOf(), tmp, file, ns);
+ 	int r = CheckNameConflict(name.AddressOf(), tmp, file, ns, true);
 
 	asCTypedefType *st = 0;
 	if( asSUCCESS == r )
@@ -4291,6 +4426,7 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi
 	funcTraits.SetTrait(asTRAIT_CONST, false);
 	funcTraits.SetTrait(asTRAIT_FINAL, false);
 	funcTraits.SetTrait(asTRAIT_OVERRIDE, false);
+	funcTraits.SetTrait(asTRAIT_EXPLICIT, false);
 
 	if( objType && n->next->next )
 	{
@@ -4305,10 +4441,12 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi
 
 		while( decorator )
 		{
-			if( decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, FINAL_TOKEN) )
+			if (decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, FINAL_TOKEN))
 				funcTraits.SetTrait(asTRAIT_FINAL, true);
-			else if( decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, OVERRIDE_TOKEN) )
+			else if (decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, OVERRIDE_TOKEN))
 				funcTraits.SetTrait(asTRAIT_OVERRIDE, true);
+			else if (decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, EXPLICIT_TOKEN))
+				funcTraits.SetTrait(asTRAIT_EXPLICIT, true);
 
 			decorator = decorator->next;
 		}
@@ -4530,7 +4668,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
 				WriteError(TXT_METHOD_CANT_HAVE_NAME_OF_CLASS, file, node);
 		}
 		else
-			CheckNameConflict(name.AddressOf(), node, file, ns);
+			CheckNameConflict(name.AddressOf(), node, file, ns, false);
 	}
 	else
 	{
@@ -5017,7 +5155,7 @@ int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCS
 		ns = engine->nameSpaces[0];
 
 	GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns);
-	CheckNameConflict(name.AddressOf(), node, file, ns);
+	CheckNameConflict(name.AddressOf(), node, file, ns, false);
 
 	// Check that the same function hasn't been registered already in the namespace
 	asCArray<int> funcs;
@@ -5153,9 +5291,10 @@ void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *ob
 				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 *f = engine->scriptFunctions[objectType->methods[n]];
+				if( f && f->funcType == asFUNC_VIRTUAL )
+					f = objectType->virtualFunctionTable[f->vfTableIdx];
+				methods.PushLast(f->id);
 			}
 		}
 	}

+ 4 - 2
Source/ThirdParty/AngelScript/source/as_builder.h

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2017 Andreas Jonsson
+   Copyright (c) 2003-2019 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
@@ -142,11 +142,12 @@ public:
 	int ParseTemplateDecl(const char *decl, asCString *name, asCArray<asCString> &subtypeNames);
 	int ParseFunctionDeclaration(asCObjectType *type, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray<bool> *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 CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns, bool isNotFunction);
 	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);
+	asCScriptCode *FindOrAddCode(const char *name, const char *code, asUINT length);
 	int Build();
 
 	int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asCScriptFunction **outFunc);
@@ -238,6 +239,7 @@ protected:
 	void               GetFunctionDescriptions(const char *name, asCArray<int> &funcs, asSNameSpace *ns);
 	void               GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray<int> &methods, bool objIsConst, const asCString &scope = "", asCScriptNode *errNode = 0, asCScriptCode *script = 0);
 	void               EvaluateTemplateInstances(asUINT startIdx, bool keepSilent);
+	void               CleanupEnumValues();
 
 	asCArray<asCScriptCode *>                  scripts;
 	asCArray<sFunctionDescription *>           functions;

+ 72 - 5
Source/ThirdParty/AngelScript/source/as_bytecode.cpp

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2018 Andreas Jonsson
+   Copyright (c) 2003-2019 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
@@ -1549,7 +1549,20 @@ void asCByteCode::ExtractObjectVariableInfo(asCScriptFunction *outFunc)
 		}
 		else if( instr->op == asBC_VarDecl )
 		{
+			// Record the position for debug info
 			outFunc->scriptData->variables[instr->wArg[0]]->declaredAtProgramPos = pos;
+			
+			// Record declaration of object variables for try/catch handling
+			// This is used for identifying if handles and objects on the heap should be cleared upon catching an exception
+			// Only extract this info if there is a try/catch block in the function, so we don't use up unnecessary space
+			if( outFunc->scriptData->tryCatchInfo.GetLength() && outFunc->scriptData->variables[instr->wArg[0]]->type.GetTypeInfo() )
+			{
+				asSObjectVariableInfo info;
+				info.programPos     = pos;
+				info.variableOffset = outFunc->scriptData->variables[instr->wArg[0]]->stackOffset;
+				info.option         = asOBJ_VARDECL;
+				outFunc->scriptData->objVariableInfo.PushLast(info);
+			}
 		}
 		else
 			pos += instr->size;
@@ -1559,6 +1572,27 @@ void asCByteCode::ExtractObjectVariableInfo(asCScriptFunction *outFunc)
 	asASSERT( blockLevel == 0 );
 }
 
+void asCByteCode::ExtractTryCatchInfo(asCScriptFunction *outFunc)
+{
+	asASSERT(outFunc->scriptData);
+
+	unsigned int pos = 0;
+	asCByteInstruction *instr = first;
+	while (instr)
+	{
+		if (instr->op == asBC_TryBlock)
+		{
+			asSTryCatchInfo info;
+			info.tryPos    = pos;
+			info.catchPos  = *ARG_DW(instr->arg);
+			outFunc->scriptData->tryCatchInfo.PushLast(info);
+		}
+
+		pos += instr->size;
+		instr = instr->next;
+	}
+}
+
 int asCByteCode::GetSize()
 {
 	int size = 0;
@@ -1776,6 +1810,17 @@ void asCByteCode::Block(bool start)
 	last->wArg[0]  = start ? 1 : 0;
 }
 
+void asCByteCode::TryBlock(short catchLabel)
+{
+	if (AddInstruction() < 0)
+		return;
+
+	last->op = asBC_TryBlock;
+	last->size = 0;
+	last->stackInc = 0;
+	*ARG_DW(last->arg) = catchLabel;
+}
+
 void asCByteCode::VarDecl(int varDeclIdx)
 {
 	if( AddInstruction() < 0 )
@@ -1843,6 +1888,8 @@ int asCByteCode::ResolveJumpAddresses()
 {
 	TimeIt("asCByteCode::ResolveJumpAddresses");
 
+	asUINT currPos = 0;
+
 	asCByteInstruction *instr = first;
 	while( instr )
 	{
@@ -1860,7 +1907,21 @@ int asCByteCode::ResolveJumpAddresses()
 			else
 				return -1;
 		}
+		else if (instr->op == asBC_TryBlock)
+		{
+			int label = *((int*)ARG_DW(instr->arg));
+			int labelPosOffset;
+			int r = FindLabel(label, instr, 0, &labelPosOffset);
+			if (r == 0)
+			{
+				// Should store the absolute address so the exception handler doesn't need to figure it out
+				*((int*)ARG_DW(instr->arg)) = currPos + labelPosOffset;
+			}
+			else
+				return -1;
+		}
 
+		currPos += instr->GetSize();
 		instr = instr->next;
 	}
 
@@ -2006,10 +2067,11 @@ void asCByteCode::PostProcess()
 				AddPath(paths, dest, stackSize);
 				break;
 			}
-			else if( instr->op == asBC_JZ    || instr->op == asBC_JNZ ||
+			else if( instr->op == asBC_JZ    || instr->op == asBC_JNZ    ||
 					 instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ ||
-					 instr->op == asBC_JS    || instr->op == asBC_JNS ||
-					 instr->op == asBC_JP    || instr->op == asBC_JNP )
+					 instr->op == asBC_JS    || instr->op == asBC_JNS    ||
+					 instr->op == asBC_JP    || instr->op == asBC_JNP    ||
+					 instr->op == asBC_TryBlock )
 			{
 				// Find the label that is being jumped to
 				int label = *((int*) ARG_DW(instr->arg));
@@ -2074,7 +2136,10 @@ void asCByteCode::PostProcess()
 #ifdef AS_DEBUG
 void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func)
 {
+#ifndef __MINGW32__
+	// _mkdir is broken on mingw
 	_mkdir("AS_DEBUG");
+#endif
 
 	asCString path = "AS_DEBUG/";
 	path += name;
@@ -2091,7 +2156,9 @@ void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func)
 	FILE *file = fopen(path.AddressOf(), "w");
 #endif
 
-#if !defined(AS_XENON) // XBox 360: When running in DVD Emu, no write is allowed
+#if !defined(AS_XENON) && !defined(__MINGW32__)
+	// XBox 360: When running in DVD Emu, no write is allowed
+	// MinGW: As _mkdir is broken, don't assert on file not created if the AS_DEBUG directory doesn't exist
 	asASSERT( file );
 #endif
 

+ 4 - 1
Source/ThirdParty/AngelScript/source/as_bytecode.h

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2015 Andreas Jonsson
+   Copyright (c) 2003-2018 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 
@@ -72,6 +72,7 @@ public:
 	void OptimizeLocally(const asCArray<int> &tempVariableOffsets);
 	void ExtractLineNumbers();
 	void ExtractObjectVariableInfo(asCScriptFunction *outFunc);
+	void ExtractTryCatchInfo(asCScriptFunction *outFunc);
 	int  ResolveJumpAddresses();
 	int  FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta);
 
@@ -100,6 +101,8 @@ public:
 	void Line(int line, int column, int scriptIdx);
 	void ObjInfo(int offset, int info);
 	void Block(bool start);
+	void TryBlock(short catchLabel);
+
 	void VarDecl(int varDeclIdx);
 	void Call(asEBCInstr bc, int funcID, int pop);
 	void CallPtr(asEBCInstr bc, int funcPtrVar, int pop);

+ 0 - 18
Source/ThirdParty/AngelScript/source/as_callfunc_x86.cpp

@@ -354,7 +354,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -401,7 +400,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable
@@ -478,7 +476,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -526,7 +523,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable
@@ -603,7 +599,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -651,7 +646,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable
@@ -737,7 +731,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -789,7 +782,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable
@@ -871,7 +863,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -920,7 +911,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable
@@ -1004,7 +994,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -1056,7 +1045,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable
@@ -1128,7 +1116,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -1173,7 +1160,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable
@@ -1261,7 +1247,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -1315,7 +1300,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable
@@ -1410,7 +1394,6 @@ endcopy:
 		// 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_startproc            \n"
 		".cfi_adjust_cfa_offset 4  \n"
 		".cfi_rel_offset ebp, 0    \n"
 		"movl %%esp, %%ebp         \n"
@@ -1477,7 +1460,6 @@ endcopy:
 		"popl %%ebp                \n"
 		".cfi_adjust_cfa_offset -4 \n"
 		".cfi_restore ebp          \n"
-		".cfi_endproc              \n"
 #endif
 		// Copy EAX:EDX to retQW. As the stack pointer has been
 		// restored it is now safe to access the local variable

+ 332 - 100
Source/ThirdParty/AngelScript/source/as_compiler.cpp

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2018 Andreas Jonsson
+   Copyright (c) 2003-2019 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
@@ -98,7 +98,7 @@ asCCompiler::~asCCompiler()
 		asDELETE(var,asCVariableScope);
 	}
 
-	// Clean up all the string constants that were allocated. By now the script 
+	// 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]);
@@ -270,6 +270,10 @@ void asCCompiler::FinalizeFunction()
 	// Finalize the bytecode
 	byteCode.Finalize(tempVariableOffsets);
 
+	// extract the try/catch info before object variable info, as 
+	// some variable info is not needed if there are no try/catch blocks
+	byteCode.ExtractTryCatchInfo(outFunc);
+
 	byteCode.ExtractObjectVariableInfo(outFunc);
 
 	// Compile the list of object variables for the exception handler
@@ -1713,7 +1717,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, as
 			}
 			else
 			{
-				// Null handles and void expressions must be marked as explicit 
+				// Null handles and void expressions must be marked as explicit
 				// handles for correct treatement in MoveArgsToStack
 				if (dt.IsNullHandle())
 					ctx->type.isExplicitHandle = true;
@@ -1773,7 +1777,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, as
 			}
 
 			// Literal constants cannot be passed to inout ref arguments
-			if( !ctx->type.isVariable && 
+			if( !ctx->type.isVariable &&
 				ctx->type.isConstant &&
 				!ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) )
 			{
@@ -1937,7 +1941,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, as
 	return 0;
 }
 
-void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args)
+int asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args)
 {
 	// When a match has been found, compile the final byte code using correct parameter types
 	asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
@@ -1963,11 +1967,16 @@ void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCE
 		for( int m = n; m >= 0; m-- )
 			args[m]->bc.GetVarsUsed(reservedVariables);
 
-		PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
+		int r = PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
 		reservedVariables.SetLength(l);
+
+		if (r < 0)
+			return r;
 	}
 
 	bc->AddCode(&e.bc);
+
+	return 0;
 }
 
 void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset)
@@ -2234,9 +2243,8 @@ int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExp
 
 		// Parse the default arg string
 		asCParser parser(builder);
-		asCScriptCode code;
-		code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
-		int r = parser.ParseExpression(&code);
+		asCScriptCode *code = builder->FindOrAddCode("default arg", func->defaultArgs[n]->AddressOf(), func->defaultArgs[n]->GetLength());
+		int r = parser.ParseExpression(code);
 		if( r < 0 )
 		{
 			asCString msg;
@@ -2250,7 +2258,7 @@ int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExp
 
 		// Temporarily set the script code to the default arg expression
 		asCScriptCode *origScript = script;
-		script = &code;
+		script = code;
 
 		// Don't allow the expression to access local variables
 		isCompilingDefaultArg = true;
@@ -2663,9 +2671,15 @@ bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx
 			}
 
 			// Implicit handle types should always be handles
-			if (newType.GetTypeInfo() && 
+			if (newType.GetTypeInfo() &&
 				(newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))
 				newType.MakeHandle(true);
+				
+			// For types that support handles auto should prefer handle 
+			// as it is more efficient than making a copy
+			// TODO: 'auto a = ...;' and 'auto @a = ...;' works the same in this case. Is this what we want?
+			if( newType.SupportHandles() )
+				newType.MakeHandle(true);
 
 			type = newType;
 			return true;
@@ -3244,11 +3258,11 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, co
 							useHndlAssign = true;
 
 							// Make sure the right hand expression is treated as a handle
-							if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant())
+							if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant() )
 							{
 								// TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function
 								// Convert the expression to a handle
-								if (!expr->type.dataType.IsObjectHandle() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))
+								if (!expr->type.dataType.IsObjectHandle() && expr->type.dataType.GetTypeInfo() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))
 								{
 									asCDataType to = expr->type.dataType;
 									to.MakeHandle(true);
@@ -3258,11 +3272,16 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, co
 
 									asASSERT(expr->type.dataType.IsObjectHandle());
 								}
-								else if (expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)
+								else if (expr->type.dataType.GetTypeInfo() && expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)
 								{
 									// For the ASHANDLE type we'll simply set the expression as a handle
 									expr->type.dataType.MakeHandle(true);
 								}
+
+								if( !expr->type.dataType.IsObjectHandle() && !expr->type.dataType.SupportHandles())
+								{
+									Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
+								}
 								expr->type.isExplicitHandle = true;
 							}
 						}
@@ -3915,25 +3934,27 @@ void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, as
 	if( statement->nodeType != snExpressionStatement || statement->firstChild )
 		*hasReturn = false;
 
-	if( statement->nodeType == snStatementBlock )
+	if (statement->nodeType == snStatementBlock)
 		CompileStatementBlock(statement, true, hasReturn, bc);
-	else if( statement->nodeType == snIf )
+	else if (statement->nodeType == snIf)
 		CompileIfStatement(statement, hasReturn, bc);
-	else if( statement->nodeType == snFor )
+	else if (statement->nodeType == snFor)
 		CompileForStatement(statement, bc);
-	else if( statement->nodeType == snWhile )
+	else if (statement->nodeType == snWhile)
 		CompileWhileStatement(statement, bc);
-	else if( statement->nodeType == snDoWhile )
+	else if (statement->nodeType == snDoWhile)
 		CompileDoWhileStatement(statement, bc);
-	else if( statement->nodeType == snExpressionStatement )
+	else if (statement->nodeType == snExpressionStatement)
 		CompileExpressionStatement(statement, bc);
-	else if( statement->nodeType == snBreak )
+	else if (statement->nodeType == snBreak)
 		CompileBreakStatement(statement, bc);
-	else if( statement->nodeType == snContinue )
+	else if (statement->nodeType == snContinue)
 		CompileContinueStatement(statement, bc);
-	else if( statement->nodeType == snSwitch )
+	else if (statement->nodeType == snSwitch)
 		CompileSwitchStatement(statement, hasReturn, bc);
-	else if( statement->nodeType == snReturn )
+	else if (statement->nodeType == snTryCatch)
+		CompileTryCatch(statement, hasReturn, bc);
+	else if (statement->nodeType == snReturn)
 	{
 		CompileReturnStatement(statement, bc);
 		*hasReturn = true;
@@ -4269,6 +4290,48 @@ void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
 	}
 }
 
+void asCCompiler::CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc)
+{
+	// We will use one label before and another after the catch statement
+	int beforeCatchLabel = nextLabel++;
+	int afterCatchLabel = nextLabel++;
+
+	// Compile the try block
+	bool hasReturnTry;
+	asCByteCode tryBC(engine);
+	CompileStatement(node->firstChild, &hasReturnTry, &tryBC);
+
+	// Add marker to unwind exception until here, then jump to catch block
+	bc->TryBlock((short)beforeCatchLabel);
+
+	// Add the byte code
+	LineInstr(bc, node->firstChild->tokenPos);
+	bc->AddCode(&tryBC);
+
+	// Add jump to after catch
+	bc->InstrINT(asBC_JMP, afterCatchLabel);
+
+	// Compile the catch block
+	bool hasReturnCatch;
+	asCByteCode catchBC(engine);
+	CompileStatement(node->firstChild->next, &hasReturnCatch, &catchBC);
+
+	// Add marker to tell bytecode optimizer that this is a catch
+	// block so the code is not removed as unreachable code
+	bc->Label((short)beforeCatchLabel);
+
+	// Add the byte code
+	LineInstr(bc, node->firstChild->next->tokenPos);
+	bc->AddCode(&catchBC);
+
+	// Add the label after catch
+	bc->Label((short)afterCatchLabel);
+
+	// The try/catch statement only has return (i.e. no code after
+	// the try/catch block will be executed) if both blocks have
+	*hasReturn = hasReturnTry && hasReturnCatch;
+}
+
 void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
 {
 	// We will use one label for the if statement
@@ -4288,14 +4351,11 @@ void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCB
 			Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
 		else
 		{
-			if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
-			ProcessDeferredParams(&expr);
-
 			if( !expr.type.isConstant )
 			{
 				ProcessPropertyGetAccessor(&expr, inode);
-
 				ConvertToVariable(&expr);
+				ProcessDeferredParams(&expr);
 
 				// Add a test
 				expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
@@ -4445,13 +4505,11 @@ void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
 				Error(TXT_EXPR_MUST_BE_BOOL, second);
 			else
 			{
-				if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
-				ProcessDeferredParams(&expr);
-
 				ProcessPropertyGetAccessor(&expr, second);
+				ConvertToVariable(&expr);
+				ProcessDeferredParams(&expr);
 
 				// If expression is false exit the loop
-				ConvertToVariable(&expr);
 				expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
 				expr.bc.Instr(asBC_ClrHi);
 				expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
@@ -4559,13 +4617,9 @@ void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
 			Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
 		else
 		{
-			if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
-			ProcessDeferredParams(&expr);
-
 			ProcessPropertyGetAccessor(&expr, wnode);
-
-			// Add byte code for the expression
 			ConvertToVariable(&expr);
+			ProcessDeferredParams(&expr);
 
 			// Jump to end of statement if expression is false
 			expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
@@ -4652,14 +4706,10 @@ void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
 		Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
 	else
 	{
-		if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
-		ProcessDeferredParams(&expr);
-
 		ProcessPropertyGetAccessor(&expr, wnode);
-
-		// Add byte code for the expression
 		ConvertToVariable(&expr);
-
+		ProcessDeferredParams(&expr);
+		
 		// Jump to next iteration if expression is true
 		expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
 		expr.bc.Instr(asBC_ClrHi);
@@ -5153,6 +5203,23 @@ void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node,
 			func = inType->virtualFunctionTable[func->vfTableIdx];
 
 		builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
+
+		if (func->objectType && (func->objectType->flags & asOBJ_TEMPLATE))
+		{
+			// Check for funcdefs in the arguments that may have been generated by the template instance, so these can be shown to user
+			for (unsigned int p = 0; p < func->GetParamCount(); p++)
+			{
+				int typeId = 0;
+				func->GetParam(p, &typeId);
+				asITypeInfo *ti = engine->GetTypeInfoById(typeId);
+				if (ti && (ti->GetFlags() & asOBJ_FUNCDEF))
+				{
+					asCString msg;
+					msg.Format(TXT_WHERE_s_IS_s, ti->GetName(), ti->GetFuncdefSignature()->GetDeclaration());
+					builder->WriteInfo(script->name, msg.AddressOf(), r, c, false);
+				}
+			}
+		}
 	}
 }
 
@@ -5660,7 +5727,7 @@ bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, boo
 	// If there is multiple matches, then pick the most appropriate one
 	if (ops.GetLength() > 1)
 	{
-		// This should only happen if an explicit cast is compiled 
+		// This should only happen if an explicit cast is compiled
 		// and the type has both the opCast and opImplCast
 		asASSERT(isExplicit);
 		asASSERT(ops.GetLength() == 2);
@@ -5783,7 +5850,7 @@ bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, boo
 		// If there is multiple matches, then pick the most appropriate one
 		if (ops.GetLength() > 1)
 		{
-			// This should only happen if an explicit cast is compiled 
+			// This should only happen if an explicit cast is compiled
 			// and the type has both the opCast and opImplCast
 			asASSERT(isExplicit);
 			asASSERT(ops.GetLength() == 2);
@@ -5875,7 +5942,7 @@ bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, boo
 					ctx->bc.Label((short)endLabel);
 				}
 
-				// If a temporary variable was allocated in the tmp to convert 
+				// If a temporary variable was allocated in the tmp to convert
 				// the input expression to a variable, it must be released here
 				if (releaseTempVariable && tmp.type.isTemporary)
 					ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc);
@@ -6359,8 +6426,8 @@ asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataT
 			asETypeModifiers inOutFlag;
 			dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0);
 
-			if (count >= funcDef->parameterTypes.GetLength() || 
-				funcDef->parameterTypes[count] != dt || 
+			if (count >= funcDef->parameterTypes.GetLength() ||
+				funcDef->parameterTypes[count] != dt ||
 				funcDef->inOutFlags[count] != inOutFlag)
 				return asCC_NO_CONV;
 
@@ -6624,7 +6691,7 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asC
 	// If there are multiple valid value casts, then we must choose the most appropriate one
 	if (funcs.GetLength() > 1)
 	{
-		// This should only happen in case of explicit value cast and 
+		// This should only happen in case of explicit value cast and
 		// the application has registered both opImplConv and opConv
 		asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
 		asASSERT(funcs.GetLength() == 2);
@@ -6846,7 +6913,7 @@ asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataTy
 		// If there are multiple valid value casts, then we must choose the most appropriate one
 		if (funcs.GetLength() > 1)
 		{
-			// This should only happen in case of explicit value cast and 
+			// This should only happen in case of explicit value cast and
 			// the application has registered both opImplConv and opConv
 			asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
 			asASSERT(funcs.GetLength() == 2);
@@ -6918,7 +6985,7 @@ asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataTy
 			// If there are multiple valid value casts, then we must choose the most appropriate one
 			if (funcs.GetLength() > 1)
 			{
-				// This should only happen in case of explicit value cast and 
+				// This should only happen in case of explicit value cast and
 				// the application has registered both opImplConv and opConv
 				asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
 				asASSERT(funcs.GetLength() == 2);
@@ -6978,6 +7045,98 @@ asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataTy
 					ctx->type.Set(to);
 				}
 			}
+			else if( CastToObjectType(to.GetTypeInfo()) )
+			{
+				// If no opConv/opImplConv methods were found on the object, then try to find a conversion constructor on the target type
+				if( to.GetTypeInfo()->flags & asOBJ_REF )
+					funcs = CastToObjectType(to.GetTypeInfo())->beh.factories;
+				else
+					funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
+
+				// If not explicit cast, remove any explicit conversion constructors
+				for (asUINT n = 0; n < funcs.GetLength(); n++)
+				{
+					asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
+					if( f == 0 || f->parameterTypes.GetLength() != 1 || (convType != asIC_EXPLICIT_VAL_CAST && f->IsExplicit()) )
+						funcs.RemoveIndex(n--);
+				}
+
+				asCArray<asCExprContext *> args;
+				args.PushLast(ctx);
+
+				cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
+
+				// Did we find a matching constructor?
+				if (funcs.GetLength() == 1)
+				{
+					if (generateCode)
+					{
+						// TODO: This should really reuse the code from CompileConstructCall
+
+						// Allocate the new object
+						asCExprValue tempObj;
+						asCExprContext e(engine);
+						bool onHeap = false;
+						if (to.GetTypeInfo()->flags & asOBJ_VALUE)
+						{
+							tempObj.dataType = to;
+							tempObj.dataType.MakeReference(false);
+							tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
+							tempObj.dataType.MakeReference(true);
+							tempObj.isTemporary = true;
+							tempObj.isVariable = true;
+
+							onHeap = IsVariableOnHeap(tempObj.stackOffset);
+
+							// Push the address of the object on the stack
+							if (onHeap)
+								e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
+						}
+
+						PrepareFunctionCall(funcs[0], &e.bc, args);
+						MoveArgsToStack(funcs[0], &e.bc, args, false);
+
+						if (to.GetTypeInfo()->flags & asOBJ_VALUE)
+						{
+							// If the object is allocated on the stack, then call the constructor as a normal function
+							if (onHeap)
+							{
+								int offset = 0;
+								asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
+								offset = descr->parameterTypes[0].GetSizeOnStackDWords();
+
+								e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
+							}
+							else
+								e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
+						}
+
+						PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
+
+						if (to.GetTypeInfo()->flags & asOBJ_VALUE)
+						{
+							// Add tag that the object has been initialized
+							e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
+
+							// The constructor doesn't return anything,
+							// so we have to manually inform the type of
+							// the return value
+							e.type = tempObj;
+							if (!onHeap)
+								e.type.dataType.MakeReference(false);
+
+							// Push the address of the object on the stack again
+							e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
+						}
+
+						MergeExprBytecodeAndType(ctx, &e);
+					}
+					else
+					{
+						ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
+					}
+				}
+			}
 		}
 	}
 
@@ -7466,25 +7625,42 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDat
 	return cost;
 }
 
-asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *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 = CastToObjectType(to.GetTypeInfo());
 	asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) );
-	if( !objType || (objType->flags & asOBJ_REF) )
+	if( !objType )
 		return asCC_NO_CONV;
 
-	// For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
 	asCArray<int> funcs;
-	for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
+	if (objType->flags & asOBJ_VALUE)
 	{
-		asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
-		if( func->parameterTypes.GetLength() == 1 &&
-			func->parameterTypes[0].IsPrimitive() &&
-			!(func->inOutFlags[0] & asTM_OUTREF) )
+		// For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
+		for (asUINT n = 0; n < objType->beh.constructors.GetLength(); n++)
 		{
-			funcs.PushLast(func->id);
+			asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
+			if (func->parameterTypes.GetLength() == 1 &&
+				func->parameterTypes[0].IsPrimitive() &&
+				!(func->inOutFlags[0] & asTM_OUTREF) &&
+				(isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()) )
+			{
+				funcs.PushLast(func->id);
+			}
+		}
+	}
+	else if (objType->flags & asOBJ_REF)
+	{
+		// For ref types the object must have a factory that takes a single primitive argument either by value or as input reference
+		for (asUINT n = 0; n < objType->beh.factories.GetLength(); n++)
+		{
+			asCScriptFunction *func = engine->scriptFunctions[objType->beh.factories[n]];
+			if (func->parameterTypes.GetLength() == 1 &&
+				func->parameterTypes[0].IsPrimitive() &&
+				!(func->inOutFlags[0] & asTM_OUTREF) &&
+				(isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()))
+			{
+				funcs.PushLast(func->id);
+			}
 		}
 	}
 
@@ -7514,17 +7690,22 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asC
 
 	// Value types and script types are allocated through the constructor
 	asCExprValue tempObj;
-	tempObj.dataType = to;
-	tempObj.stackOffset = (short)AllocateVariable(to, true);
-	tempObj.dataType.MakeReference(true);
-	tempObj.isTemporary = true;
-	tempObj.isVariable = true;
+	bool onHeap = false;
 
-	bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
+	if (!(objType->flags & asOBJ_REF))
+	{
+		tempObj.dataType = to;
+		tempObj.stackOffset = (short)AllocateVariable(to, true);
+		tempObj.dataType.MakeReference(true);
+		tempObj.isTemporary = true;
+		tempObj.isVariable = true;
+
+		onHeap = IsVariableOnHeap(tempObj.stackOffset);
 
-	// Push the address of the object on the stack
-	if( onHeap )
-		ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
+		// Push the address of the object on the stack
+		if (onHeap)
+			ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
+	}
 
 	PrepareFunctionCall(funcs[0], &ctx->bc, args);
 	MoveArgsToStack(funcs[0], &ctx->bc, args, false);
@@ -7561,10 +7742,11 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asC
 	}
 	else
 	{
-		asASSERT( objType->flags & asOBJ_SCOPED );
-
 		// Call the factory to create the reference type
 		PerformFunctionCall(funcs[0], ctx, false, &args);
+
+		// Make another pass to make sure the result has the correct handle and reference settings
+		ImplicitConversion(ctx, to, node, isExplicit, generateCode, allowObjectConstruct);
 	}
 
 	return cost;
@@ -8231,6 +8413,12 @@ int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExpr
 					}
 				}
 
+				if (!rctx->type.dataType.IsObjectHandle() && !rctx->type.dataType.SupportHandles())
+				{
+					Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, rexpr);
+					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.
@@ -8334,7 +8522,9 @@ int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExpr
 		{
 			asCDataType dt = lctx->type.dataType;
 			dt.MakeReference(true);
-			dt.MakeReadOnly(true);
+			// A funcdef can be accessed by ref, but only as read-only
+			if( dt.IsFuncdef() && !dt.IsObjectHandle() )
+				dt.MakeReadOnly(true);
 			int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
 			if( r < 0 )
 				return -1;
@@ -8501,7 +8691,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
 				to.MakeReadOnly(false);
 				ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
 			}
-			
+
 			if (le.IsAnonymousInitList() )
 			{
 				Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next);
@@ -8879,6 +9069,11 @@ int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *c
 		Error(msg, node);
 	}
 
+	// If this is compiled from a default arg, then use the script code for the default arg
+	asCScriptCode *origCode = script;
+	if (ctx->origCode)
+		script = ctx->origCode;
+
 	// Allocate and initialize the temporary object
 	int offset = AllocateVariable(dt, true);
 	CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0);
@@ -8896,6 +9091,9 @@ int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *c
 	// Clear the flag for anonymous initalization list as it is no
 	// longer true now that the object has been initialized.
 	ctx->isAnonymousInitList = false;
+	ctx->origCode = 0;
+
+	script = origCode;
 
 	return 0;
 }
@@ -8919,7 +9117,7 @@ int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx)
 		{
 			// 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);
+			ctx->SetAnonymousInitList(node->firstChild, script);
 			return 0;
 		}
 	}
@@ -9440,7 +9638,15 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
 
 		if (symbolType == SL_CLASSPROPACCESS)
 		{
-			asASSERT(scope == "");
+			if (scope != "")
+			{
+				// Cannot access non-static members like this
+				asCString msg;
+				msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
+				Error(msg, errNode);
+				return -1;
+			}
+
 			// See if there are any matching property accessors
 			asCExprContext access(engine);
 			if (objType)
@@ -9578,8 +9784,16 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
 
 		if (symbolType == SL_CLASSMETHOD)
 		{
-			asASSERT(objType || outFunc->objectType);
+			if (scope != "")
+			{
+				// Cannot access non-static members like this
+				asCString msg;
+				msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
+				Error(msg, errNode);
+				return -1;
+			}
 
+#if AS_DEBUG
 			// If it is not a property, it may still be the name of a method which can be used to create delegates
 			asCObjectType *ot = outFunc->objectType;
 			asCScriptFunction *func = 0;
@@ -9595,7 +9809,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
 			}
 
 			asASSERT(func);
-
+#endif
 			// An object method was found. Keep the name of the method in the expression, but
 			// don't actually modify the bytecode at this point since it is not yet known what
 			// the method will be used for, or even what overloaded method should be used.
@@ -9650,7 +9864,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
 				Error(msg, errNode);
 				return -1;
 			}
-			
+
 			// Prepare the bytecode for the function call
 			MergeExprBytecodeAndType(ctx, &access);
 
@@ -9665,7 +9879,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
 			asQWORD constantValue = 0;
 			asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
 			asASSERT(prop);
-		
+
 			// Verify that the global property has been compiled already
 			if (!isCompiled)
 			{
@@ -9782,8 +9996,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
 			}
 
 			asDWORD value = 0;
-			int r = builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value);
-			asASSERT(r > 0);
+			builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value);
 
 			// Even if the enum type is not shared, and we're compiling a shared object,
 			// the use of the values are still allowed, since they are treated as constants.
@@ -10007,7 +10220,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx
 					// 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 
+					// 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);
@@ -10354,7 +10567,7 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx)
 			expr.type.SetDummy();
 			anyErrors = true;
 		}
-		else if (node->lastChild->firstChild && 
+		else if (node->lastChild->firstChild &&
 			node->lastChild->firstChild->nodeType == snNamedArgument)
 		{
 			Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild);
@@ -10711,7 +10924,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
 	if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
 	{
 		// Check for a value cast behaviour
-		if( args.GetLength() == 1 && args[0]->type.dataType.GetTypeInfo() )
+		if( args.GetLength() == 1 )
 		{
 			asCExprContext conv(engine);
 			conv.type = args[0]->type;
@@ -11018,6 +11231,8 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, a
 		// TODO: Take advantage of the known symbol, so it doesn't have to be looked up again
 		localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType);
 		asASSERT(localVar >= 0);
+		if( localVar < 0 )
+			return -1;
 
 		if (funcExpr.type.dataType.IsFuncdef())
 		{
@@ -11104,7 +11319,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, a
 		}
 
 		// If a class method is being called implicitly, then add the this pointer for the call
-		if (funcs.GetLength() && !objectType)
+		if (funcs.GetLength() && !objectType && outFunc->objectType)
 		{
 			// Verify that the identified function is actually part of the class hierarchy
 			if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo()))
@@ -11122,7 +11337,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, a
 				Error(msg, node);
 				return -1;
 			}
-			
+
 			objectType = outFunc->objectType;
 
 			asCDataType dt = asCDataType::CreateType(objectType, false);
@@ -11134,8 +11349,16 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, a
 
 			Dereference(ctx, true);
 		}
+		else if (funcs.GetLength() && !objectType && !outFunc->objectType)
+		{
+			// Cannot call class methods directly without the object
+			asCString msg;
+			msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
+			Error(msg, node);
+			return -1;
+		}
 	}
-	
+
 	// Is it a global function?
 	if (symbolType == SL_GLOBALFUNC)
 	{
@@ -11828,7 +12051,7 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx
 				else
 				{
 					if( multipleSetFuncs.GetLength() == 0 )
-						multipleSetFuncs.PushLast(getId);
+						multipleSetFuncs.PushLast(setId);
 
 					multipleSetFuncs.PushLast(funcs[n]);
 				}
@@ -12944,7 +13167,7 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *ar
 	if (argExpr->IsAnonymousInitList())
 	{
 		if ((desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] != asTM_INREF) ||
-			desc->parameterTypes[paramNum].GetTypeInfo() == 0 ||
+			desc->parameterTypes[paramNum].GetBehaviour() == 0 ||
 			desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0)
 		{
 			return -1;
@@ -13018,7 +13241,7 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *ar
 	return -1;
 }
 
-void asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
+int 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
@@ -13029,16 +13252,20 @@ void asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asC
 		if( orig == 0 )
 		{
 			// Out of memory
-			return;
+			return -1;
 		}
 		MergeExprBytecodeAndType(orig, arg);
 		arg->origExpr = orig;
 	}
 
-	PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
+	int r = PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
+	if (r < 0)
+		return r;
 
 	// arg still holds the original expression for output parameters
 	ctx->bc.AddCode(&arg->bc);
+
+	return 0;
 }
 
 bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token)
@@ -13354,7 +13581,7 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char
 
 					if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE))
 					{
-						// If the application allows unsafe references, then it is not necessary to 
+						// If the application allows unsafe references, then it is not necessary to
 						// make a copy of the object, just store the reference as a local variable
 
 						// Allocate a temporary variable as reference to the type
@@ -13468,7 +13695,9 @@ void asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectTyp
 	asCByteCode objBC(engine);
 	objBC.AddCode(&ctx->bc);
 
-	PrepareFunctionCall(funcId, &ctx->bc, args);
+	int r = PrepareFunctionCall(funcId, &ctx->bc, args);
+	if (r < 0)
+		return;
 
 	// Verify if any of the args variable offsets are used in the other code.
 	// If they are exchange the offset for a new one
@@ -15674,7 +15903,7 @@ void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
 
 	// This is only done for object methods
 	asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
-	if( desc->objectType == 0 ) return;
+	if( !desc || desc->objectType == 0 ) return;
 
 	// Check if there are any non-const matches
 	asUINT n;
@@ -15682,7 +15911,7 @@ void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
 	for( n = 0; n < funcs.GetLength(); n++ )
 	{
 		desc = builder->GetFunctionDescription(funcs[n]);
-		if( desc->IsReadOnly() != removeConst )
+		if( desc && desc->IsReadOnly() != removeConst )
 		{
 			foundNonConst = true;
 			break;
@@ -15695,7 +15924,7 @@ void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
 		for( n = 0; n < funcs.GetLength(); n++ )
 		{
 			desc = builder->GetFunctionDescription(funcs[n]);
-			if( desc->IsReadOnly() == removeConst )
+			if( desc && desc->IsReadOnly() == removeConst )
 			{
 				if( n == funcs.GetLength() - 1 )
 					funcs.PopLast();
@@ -16001,6 +16230,7 @@ void asCExprContext::Clear()
 	isVoidExpression = false;
 	isCleanArg = false;
 	isAnonymousInitList = false;
+	origCode = 0;
 }
 
 bool asCExprContext::IsClassMethod() const
@@ -16054,10 +16284,11 @@ bool asCExprContext::IsVoidExpression() const
 	return false;
 }
 
-void asCExprContext::SetAnonymousInitList(asCScriptNode *initList)
+void asCExprContext::SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script)
 {
 	Clear();
 	exprNode = initList;
+	origCode = script;
 	isAnonymousInitList = true;
 }
 
@@ -16084,6 +16315,7 @@ void asCExprContext::Merge(asCExprContext *after)
 	isVoidExpression = after->isVoidExpression;
 	isCleanArg = after->isCleanArg;
 	isAnonymousInitList = after->isAnonymousInitList;
+	origCode = after->origCode;
 
 	after->property_arg = 0;
 

+ 5 - 3
Source/ThirdParty/AngelScript/source/as_compiler.h

@@ -149,7 +149,7 @@ struct asCExprContext
 	void SetVoidExpression();
 	bool IsVoidExpression() const;
 	void Merge(asCExprContext *after);
-	void SetAnonymousInitList(asCScriptNode *initList);
+	void SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script);
 	bool IsAnonymousInitList() const;
 
 	asCByteCode bc;
@@ -165,6 +165,7 @@ struct asCExprContext
 	asCArray<asSDeferredParam> deferredParams;
 	asCScriptNode  *exprNode;
 	asCExprContext *origExpr;
+	asCScriptCode *origCode;
 	// TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value
 	asCString methodName;
 	asCString enumValue;
@@ -239,6 +240,7 @@ protected:
 	void CompileContinueStatement(asCScriptNode *node, asCByteCode *bc);
 	void CompileReturnStatement(asCScriptNode *node, asCByteCode *bc);
 	void CompileExpressionStatement(asCScriptNode *node, asCByteCode *bc);
+	void CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc);
 
 	// Expressions
 	int  CompileAssignment(asCScriptNode *expr, asCExprContext *out);
@@ -296,11 +298,11 @@ protected:
 	void PerformFunctionCall(int funcId, asCExprContext *out, bool isConstructor = false, asCArray<asCExprContext*> *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0);
 	void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset);
 	void MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0);
-	void PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args);
+	int  PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args);
 	void AfterFunctionCall(int funcId, asCArray<asCExprContext*> &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);
+	int  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);

+ 259 - 100
Source/ThirdParty/AngelScript/source/as_context.cpp

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2018 Andreas Jonsson
+   Copyright (c) 2003-2019 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
@@ -78,7 +78,10 @@ public:
 		// This code writes out some statistics for the VM.
 		// It's useful for determining what needs to be optimized.
 
+#ifndef __MINGW32__
+		// _mkdir is broken on mingw
 		_mkdir("AS_DEBUG");
+#endif
 		#if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
 			FILE *f;
 			fopen_s(&f, "AS_DEBUG/stats.txt", "wt");
@@ -197,6 +200,7 @@ asCContext::asCContext(asCScriptEngine *engine, bool holdRef)
 	m_doSuspend                 = false;
 	m_userData                  = 0;
 	m_regs.ctx                  = this;
+	m_exceptionWillBeCaught     = false;
 }
 
 asCContext::~asCContext()
@@ -466,6 +470,10 @@ int asCContext::Prepare(asIScriptFunction *func)
 		// Make sure there is enough space on the stack for the arguments and return value
 		if( !ReserveStackSpace(stackSize) )
 			return asOUT_OF_MEMORY;
+
+		// Set up the call stack too
+		if (m_callStack.GetCapacity() < m_engine->ep.initCallStackSize)
+			m_callStack.AllocateNoConstruct(m_engine->ep.initCallStackSize * CALLSTACK_FRAME_SIZE, true);
 	}
 
 	// Reset state
@@ -1314,9 +1322,16 @@ int asCContext::Execute()
 	if( m_engine->ep.autoGarbageCollect )
 		m_engine->gc.GetStatistics(&gcPreObjects, 0, 0, 0, 0);
 
-	while( m_status == asEXECUTION_ACTIVE )
+	while (m_status == asEXECUTION_ACTIVE)
+	{
 		ExecuteNext();
 
+		// If an exception was raised that will be caught, then unwind the stack
+		// and move the program pointer to the catch block before proceeding
+		if (m_status == asEXECUTION_EXCEPTION && m_exceptionWillBeCaught)
+			CleanStack(true);
+	}
+
 	if( m_lineCallback )
 	{
 		// Call the line callback one last time before leaving
@@ -1382,16 +1397,26 @@ int asCContext::PushState()
 		return asERROR;
 	}
 
+	// Allocate space on the callstack for at least two states
+	if (m_callStack.GetLength() >= m_callStack.GetCapacity() - 2*CALLSTACK_FRAME_SIZE)
+	{
+		if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE)
+		{
+			// The call stack is too big to grow further
+			// If an error occurs, no change to the context should be done
+			return asOUT_OF_MEMORY;
+		}
+
+		// Allocate space for 10 call states at a time to save time
+		m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10 * CALLSTACK_FRAME_SIZE, true);
+	}
+
 	// Push the current script function that is calling the system function
+	// This cannot fail, since the memory was already allocated above
 	PushCallState();
 
 	// Push the system function too, which will serve both as a marker and
 	// informing which system function that created the nested call
-	if( m_callStack.GetLength() == m_callStack.GetCapacity() )
-	{
-		// Allocate space for 10 call states at a time to save time
-		m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true);
-	}
 	m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE);
 
 	// Need to push m_initialFunction as it must be restored later
@@ -1467,10 +1492,17 @@ int asCContext::PopState()
 	return asSUCCESS;
 }
 
-void asCContext::PushCallState()
+int asCContext::PushCallState()
 {
 	if( m_callStack.GetLength() == m_callStack.GetCapacity() )
 	{
+		if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE)
+		{
+			// The call stack is too big to grow further
+			SetInternalException(TXT_STACK_OVERFLOW);
+			return asERROR;
+		}
+
 		// Allocate space for 10 call states at a time to save time
 		m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true);
 	}
@@ -1496,6 +1528,8 @@ void asCContext::PushCallState()
 	tmp[2] = s[2];
 	tmp[3] = s[3];
 	tmp[4] = s[4];
+
+	return asSUCCESS;
 }
 
 void asCContext::PopCallState()
@@ -1602,7 +1636,7 @@ bool asCContext::ReserveStackSpace(asUINT size)
 	// Make sure the first stack block is allocated
 	if( m_stackBlocks.GetLength() == 0 )
 	{
-		m_stackBlockSize = m_engine->initialContextStackSize;
+		m_stackBlockSize = m_engine->ep.initContextStackSize;
 		asASSERT( m_stackBlockSize > 0 );
 
 #ifndef WIP_16BYTE_ALIGN
@@ -1639,8 +1673,8 @@ bool asCContext::ReserveStackSpace(asUINT size)
 		// Make sure we don't allocate more space than allowed
 		if( m_engine->ep.maximumContextStackSize )
 		{
-			// This test will only stop growth once it has already crossed the limit
-			if( m_stackBlockSize * ((1 << (m_stackIndex+1)) - 1) > m_engine->ep.maximumContextStackSize )
+			// This test will only stop growth once it is on or already crossed the limit
+			if( m_stackBlockSize * ((1 << (m_stackIndex+1)) - 1) >= m_engine->ep.maximumContextStackSize )
 			{
 				m_isStackMemoryNotAllocated = true;
 
@@ -1705,7 +1739,8 @@ void asCContext::CallScriptFunction(asCScriptFunction *func)
 	asASSERT( func->scriptData );
 
 	// Push the framepointer, function id and programCounter on the stack
-	PushCallState();
+	if (PushCallState() < 0)
+		return;
 
 	// Update the current function and program position before increasing the stack
 	// so the exception handler will know what to do if there is a stack overflow
@@ -4487,17 +4522,18 @@ void asCContext::ExecuteNext()
 	}
 }
 
-int asCContext::SetException(const char *descr)
+// interface
+int asCContext::SetException(const char *descr, bool allowCatch)
 {
 	// Only allow this if we're executing a CALL byte code
 	if( m_callingSystemFunction == 0 ) return asERROR;
 
-	SetInternalException(descr);
+	SetInternalException(descr, allowCatch);
 
 	return 0;
 }
 
-void asCContext::SetInternalException(const char *descr)
+void asCContext::SetInternalException(const char *descr, bool allowCatch)
 {
 	if( m_inExceptionHandler )
 	{
@@ -4524,10 +4560,19 @@ void asCContext::SetInternalException(const char *descr)
 		m_exceptionColumn     = 0;
 	}
 
+	// Recursively search the callstack for try/catch blocks
+	m_exceptionWillBeCaught = allowCatch && FindExceptionTryCatch();
+
 	if( m_exceptionCallback )
 		CallExceptionCallback();
 }
 
+// interface
+bool asCContext::WillExceptionBeCaught()
+{
+	return m_exceptionWillBeCaught;
+}
+
 void asCContext::CleanReturnObject()
 {
 	if( m_initialFunction && m_initialFunction->DoesReturnOnStack() && m_status == asEXECUTION_FINISHED )
@@ -4577,30 +4622,37 @@ void asCContext::CleanReturnObject()
 	}
 }
 
-void asCContext::CleanStack()
+void asCContext::CleanStack(bool catchException)
 {
 	m_inExceptionHandler = true;
 
-	// Run the clean up code for each of the functions called
-	CleanStackFrame();
-
-	// Set the status to exception so that the stack unwind is done correctly.
-	// This shouldn't be done for the current function, which is why we only
-	// do this after the first CleanStackFrame() is done.
-	m_status = asEXECUTION_EXCEPTION;
-
-	while( m_callStack.GetLength() > 0 )
+	// Run the clean up code and move to catch block
+	bool caught = CleanStackFrame(catchException);
+	if( !caught )
 	{
-		// Only clean up until the top most marker for a nested call
-		asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
-		if( s[0] == 0 )
-			break;
+		// Set the status to exception so that the stack unwind is done correctly.
+		// This shouldn't be done for the current function, which is why we only
+		// do this after the first CleanStackFrame() is done.
+		m_status = asEXECUTION_EXCEPTION;
 
-		PopCallState();
+		while (!caught && m_callStack.GetLength() > 0)
+		{
+			// Only clean up until the top most marker for a nested call
+			asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
+			if (s[0] == 0)
+				break;
+
+			PopCallState();
 
-		CleanStackFrame();
+			caught = CleanStackFrame(catchException);
+		}
 	}
 
+	// If the exception was caught, then move the status to 
+	// active as is now possible to resume the execution
+	if (caught)
+		m_status = asEXECUTION_ACTIVE;
+
 	m_inExceptionHandler = false;
 }
 
@@ -4747,7 +4799,7 @@ void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLe
 					break;
 				case asBLOCK_BEGIN: // Start block
 					// We should ignore start blocks, since it just means the
-					// program was within the block when the exception ocurred
+					// program was within the block when the exception occurred
 					break;
 				case asBLOCK_END: // End block
 					// We need to skip the entire block, as the objects created
@@ -4884,8 +4936,46 @@ void asCContext::CleanArgsOnStack()
 	m_needToCleanupArgs = false;
 }
 
-void asCContext::CleanStackFrame()
+bool asCContext::FindExceptionTryCatch()
+{
+	// Check each of the script functions on the callstack to see if 
+	// the current program position is within a try/catch block
+	if (m_currentFunction && m_currentFunction->scriptData)
+	{
+		asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf());
+		for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++)
+		{
+			if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos &&
+				currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos)
+				return true;
+		}
+	}
+
+	int stackSize = GetCallstackSize();
+	for (int level = 1; level < stackSize; level++)
+	{
+		asPWORD *s = m_callStack.AddressOf() + (stackSize - level - 1)*CALLSTACK_FRAME_SIZE;
+		asCScriptFunction *func = (asCScriptFunction*)s[1];
+		if (func && func->scriptData)
+		{
+			asUINT currPos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf());
+			for (asUINT n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++)
+			{
+				if (currPos >= func->scriptData->tryCatchInfo[n].tryPos &&
+					currPos < func->scriptData->tryCatchInfo[n].catchPos)
+					return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+bool asCContext::CleanStackFrame(bool catchException)
 {
+	bool exceptionCaught = false;
+	asSTryCatchInfo *tryCatchInfo = 0;
+
 	// Clean object variables on the stack
 	// If the stack memory is not allocated or the program pointer
 	// is not set, then there is nothing to clean up on the stack frame
@@ -4895,9 +4985,29 @@ void asCContext::CleanStackFrame()
 		// to clean up the arguments that were put on the stack.
 		CleanArgsOnStack();
 
+		// Check if this function will catch the exception
+		// Try blocks can be nested, so use the innermost block
+		asASSERT(m_currentFunction->scriptData);
+		if (catchException && m_currentFunction->scriptData)
+		{
+			asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf());
+			
+			for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++)
+			{
+				if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos &&
+					currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos)
+				{
+					tryCatchInfo = &m_currentFunction->scriptData->tryCatchInfo[n];
+					exceptionCaught = true;
+				}
+				if (currPos < m_currentFunction->scriptData->tryCatchInfo[n].tryPos)
+					break;
+			}
+		}
+
 		// Restore the stack pointer
-		asASSERT( m_currentFunction->scriptData );
-		m_regs.stackPointer += m_currentFunction->scriptData->variableSpace;
+		if( !exceptionCaught )
+			m_regs.stackPointer += m_currentFunction->scriptData->variableSpace;
 
 		// Determine which object variables that are really live ones
 		asCArray<int> liveObjects;
@@ -4906,6 +5016,43 @@ void asCContext::CleanStackFrame()
 		for( asUINT n = 0; n < m_currentFunction->scriptData->objVariablePos.GetLength(); n++ )
 		{
 			int pos = m_currentFunction->scriptData->objVariablePos[n];
+
+			// If the exception was caught, then only clean up objects within the try block
+			if (exceptionCaught)
+			{
+				// Find out where the variable was declared, and skip cleaning of those that were declared before the try catch
+				// Multiple variables in different scopes may occupy the same slot on the stack so it is necessary to search
+				// the entire list to determine which variable occupies the slot now. 
+				int skipClean = 0;
+				for( asUINT p = 0; p < m_currentFunction->scriptData->objVariableInfo.GetLength(); p++ )
+				{
+					asSObjectVariableInfo &info = m_currentFunction->scriptData->objVariableInfo[p];
+					if (info.variableOffset == pos &&
+						info.option == asOBJ_VARDECL )
+					{
+						asUINT progPos = info.programPos;
+						if (progPos < tryCatchInfo->tryPos )
+						{
+							if( skipClean >= 0 )
+								skipClean = 1;
+							break;
+						}
+						else if( progPos < tryCatchInfo->catchPos )
+						{
+							skipClean = -1;
+							break;
+						}
+					}
+				}
+				
+				// Skip only variables that have been declared before the try block. Variables declared 
+				// within the try block and variables whose declaration was not identified (temporary objects)
+				// will not be skipped.
+				// TODO: What if a temporary variable reuses a slot from a declared variable that is no longer in scope?
+				if (skipClean > 0)
+					continue;
+			}
+
 			if( n < m_currentFunction->scriptData->objVariablesOnHeap )
 			{
 				// Check if the pointer is initialized
@@ -4954,9 +5101,16 @@ void asCContext::CleanStackFrame()
 	else
 		m_isStackMemoryNotAllocated = false;
 
+	// If the exception was caught then move the program position to the catch block then stop the unwinding
+	if (exceptionCaught)
+	{
+		m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf() + tryCatchInfo->catchPos;
+		return exceptionCaught;
+	}
+
 	// Functions that do not own the object and parameters shouldn't do any clean up
 	if( m_currentFunction->dontCleanUpOnException )
-		return;
+		return exceptionCaught;
 
 	// Clean object and parameters
 	int offset = 0;
@@ -4997,12 +5151,15 @@ void asCContext::CleanStackFrame()
 
 		offset += m_currentFunction->parameterTypes[n].GetSizeOnStackDWords();
 	}
+
+	return exceptionCaught;
 }
 
 // interface
 int asCContext::GetExceptionLineNumber(int *column, const char **sectionName)
 {
-	if( GetState() != asEXECUTION_EXCEPTION ) return asERROR;
+	// Return the last exception even if the context is no longer in the exception state
+	// if( GetState() != asEXECUTION_EXCEPTION ) return asERROR;
 
 	if( column ) *column = m_exceptionColumn;
 
@@ -5021,7 +5178,8 @@ int asCContext::GetExceptionLineNumber(int *column, const char **sectionName)
 // interface
 asIScriptFunction *asCContext::GetExceptionFunction()
 {
-	if( GetState() != asEXECUTION_EXCEPTION ) return 0;
+	// Return the last exception even if the context is no longer in the exception state
+	// if( GetState() != asEXECUTION_EXCEPTION ) return 0;
 
 	return m_engine->scriptFunctions[m_exceptionFunction];
 }
@@ -5029,7 +5187,8 @@ asIScriptFunction *asCContext::GetExceptionFunction()
 // interface
 const char *asCContext::GetExceptionString()
 {
-	if( GetState() != asEXECUTION_EXCEPTION ) return 0;
+	// Return the last exception even if the context is no longer in the exception state
+	// if( GetState() != asEXECUTION_EXCEPTION ) return 0;
 
 	return m_exceptionString.AddressOf();
 }
@@ -5465,67 +5624,67 @@ const POW_INFO pow_info[] =
 {
 	{          0ULL,          0UL,     0,     0, 0 },  // 0 is a special case
 	{          0ULL,          0UL,     0,     0, 1 },  // 1 is a special case
-    { 3037000499ULL, 2147483647UL, 65535, 46340, 2 },  // 2
-    {    2097152ULL,    1664510UL,  1625,  1290, 2 },  // 3
-    {      55108ULL,      46340UL,   255,   215, 3 },  // 4
-    {       6208ULL,       5404UL,    84,    73, 3 },  // 5
-    {       1448ULL,       1290UL,    40,    35, 3 },  // 6
-    {        511ULL,        463UL,    23,    21, 3 },  // 7
-    {        234ULL,        215UL,    15,    14, 4 },  // 8
-    {        128ULL,        118UL,    11,    10, 4 },  // 9
-    {         78ULL,         73UL,     9,     8, 4 },  // 10
-    {         52ULL,         49UL,     7,     7, 4 },  // 11
-    {         38ULL,         35UL,     6,     5, 4 },  // 12
-    {         28ULL,         27UL,     5,     5, 4 },  // 13
-    {         22ULL,         21UL,     4,     4, 4 },  // 14
-    {         18ULL,         17UL,     4,     4, 4 },  // 15
-    {         15ULL,         14UL,     3,     3, 5 },  // 16
-    {         13ULL,         12UL,     3,     3, 5 },  // 17
-    {         11ULL,         10UL,     3,     3, 5 },  // 18
-    {          9ULL,          9UL,     3,     3, 5 },  // 19
-    {          8ULL,          8UL,     3,     2, 5 },  // 20
-    {          8ULL,          7UL,     2,     2, 5 },  // 21
-    {          7ULL,          7UL,     2,     2, 5 },  // 22
-    {          6ULL,          6UL,     2,     2, 5 },  // 23
-    {          6ULL,          5UL,     2,     2, 5 },  // 24
-    {          5ULL,          5UL,     2,     2, 5 },  // 25
-    {          5ULL,          5UL,     2,     2, 5 },  // 26
-    {          5ULL,          4UL,     2,     2, 5 },  // 27
-    {          4ULL,          4UL,     2,     2, 5 },  // 28
-    {          4ULL,          4UL,     2,     2, 5 },  // 29
-    {          4ULL,          4UL,     2,     2, 5 },  // 30
-    {          4ULL,          4UL,     2,     1, 5 },  // 31
-    {          3ULL,          3UL,     1,     1, 6 },  // 32
-    {          3ULL,          3UL,     1,     1, 6 },  // 33
-    {          3ULL,          3UL,     1,     1, 6 },  // 34
-    {          3ULL,          3UL,     1,     1, 6 },  // 35
-    {          3ULL,          3UL,     1,     1, 6 },  // 36
-    {          3ULL,          3UL,     1,     1, 6 },  // 37
-    {          3ULL,          3UL,     1,     1, 6 },  // 38
-    {          3ULL,          3UL,     1,     1, 6 },  // 39
-    {          2ULL,          2UL,     1,     1, 6 },  // 40
-    {          2ULL,          2UL,     1,     1, 6 },  // 41
-    {          2ULL,          2UL,     1,     1, 6 },  // 42
-    {          2ULL,          2UL,     1,     1, 6 },  // 43
-    {          2ULL,          2UL,     1,     1, 6 },  // 44
-    {          2ULL,          2UL,     1,     1, 6 },  // 45
-    {          2ULL,          2UL,     1,     1, 6 },  // 46
-    {          2ULL,          2UL,     1,     1, 6 },  // 47
-    {          2ULL,          2UL,     1,     1, 6 },  // 48
-    {          2ULL,          2UL,     1,     1, 6 },  // 49
-    {          2ULL,          2UL,     1,     1, 6 },  // 50
-    {          2ULL,          2UL,     1,     1, 6 },  // 51
-    {          2ULL,          2UL,     1,     1, 6 },  // 52
-    {          2ULL,          2UL,     1,     1, 6 },  // 53
-    {          2ULL,          2UL,     1,     1, 6 },  // 54
-    {          2ULL,          2UL,     1,     1, 6 },  // 55
-    {          2ULL,          2UL,     1,     1, 6 },  // 56
-    {          2ULL,          2UL,     1,     1, 6 },  // 57
-    {          2ULL,          2UL,     1,     1, 6 },  // 58
-    {          2ULL,          2UL,     1,     1, 6 },  // 59
-    {          2ULL,          2UL,     1,     1, 6 },  // 60
-    {          2ULL,          2UL,     1,     1, 6 },  // 61
-    {          2ULL,          2UL,     1,     1, 6 },  // 62
+	{ 3037000499ULL, 2147483647UL, 65535, 46340, 2 },  // 2
+	{    2097152ULL,    1664510UL,  1625,  1290, 2 },  // 3
+	{      55108ULL,      46340UL,   255,   215, 3 },  // 4
+	{       6208ULL,       5404UL,    84,    73, 3 },  // 5
+	{       1448ULL,       1290UL,    40,    35, 3 },  // 6
+	{        511ULL,        463UL,    23,    21, 3 },  // 7
+	{        234ULL,        215UL,    15,    14, 4 },  // 8
+	{        128ULL,        118UL,    11,    10, 4 },  // 9
+	{         78ULL,         73UL,     9,     8, 4 },  // 10
+	{         52ULL,         49UL,     7,     7, 4 },  // 11
+	{         38ULL,         35UL,     6,     5, 4 },  // 12
+	{         28ULL,         27UL,     5,     5, 4 },  // 13
+	{         22ULL,         21UL,     4,     4, 4 },  // 14
+	{         18ULL,         17UL,     4,     4, 4 },  // 15
+	{         15ULL,         14UL,     3,     3, 5 },  // 16
+	{         13ULL,         12UL,     3,     3, 5 },  // 17
+	{         11ULL,         10UL,     3,     3, 5 },  // 18
+	{          9ULL,          9UL,     3,     3, 5 },  // 19
+	{          8ULL,          8UL,     3,     2, 5 },  // 20
+	{          8ULL,          7UL,     2,     2, 5 },  // 21
+	{          7ULL,          7UL,     2,     2, 5 },  // 22
+	{          6ULL,          6UL,     2,     2, 5 },  // 23
+	{          6ULL,          5UL,     2,     2, 5 },  // 24
+	{          5ULL,          5UL,     2,     2, 5 },  // 25
+	{          5ULL,          5UL,     2,     2, 5 },  // 26
+	{          5ULL,          4UL,     2,     2, 5 },  // 27
+	{          4ULL,          4UL,     2,     2, 5 },  // 28
+	{          4ULL,          4UL,     2,     2, 5 },  // 29
+	{          4ULL,          4UL,     2,     2, 5 },  // 30
+	{          4ULL,          4UL,     2,     1, 5 },  // 31
+	{          3ULL,          3UL,     1,     1, 6 },  // 32
+	{          3ULL,          3UL,     1,     1, 6 },  // 33
+	{          3ULL,          3UL,     1,     1, 6 },  // 34
+	{          3ULL,          3UL,     1,     1, 6 },  // 35
+	{          3ULL,          3UL,     1,     1, 6 },  // 36
+	{          3ULL,          3UL,     1,     1, 6 },  // 37
+	{          3ULL,          3UL,     1,     1, 6 },  // 38
+	{          3ULL,          3UL,     1,     1, 6 },  // 39
+	{          2ULL,          2UL,     1,     1, 6 },  // 40
+	{          2ULL,          2UL,     1,     1, 6 },  // 41
+	{          2ULL,          2UL,     1,     1, 6 },  // 42
+	{          2ULL,          2UL,     1,     1, 6 },  // 43
+	{          2ULL,          2UL,     1,     1, 6 },  // 44
+	{          2ULL,          2UL,     1,     1, 6 },  // 45
+	{          2ULL,          2UL,     1,     1, 6 },  // 46
+	{          2ULL,          2UL,     1,     1, 6 },  // 47
+	{          2ULL,          2UL,     1,     1, 6 },  // 48
+	{          2ULL,          2UL,     1,     1, 6 },  // 49
+	{          2ULL,          2UL,     1,     1, 6 },  // 50
+	{          2ULL,          2UL,     1,     1, 6 },  // 51
+	{          2ULL,          2UL,     1,     1, 6 },  // 52
+	{          2ULL,          2UL,     1,     1, 6 },  // 53
+	{          2ULL,          2UL,     1,     1, 6 },  // 54
+	{          2ULL,          2UL,     1,     1, 6 },  // 55
+	{          2ULL,          2UL,     1,     1, 6 },  // 56
+	{          2ULL,          2UL,     1,     1, 6 },  // 57
+	{          2ULL,          2UL,     1,     1, 6 },  // 58
+	{          2ULL,          2UL,     1,     1, 6 },  // 59
+	{          2ULL,          2UL,     1,     1, 6 },  // 60
+	{          2ULL,          2UL,     1,     1, 6 },  // 61
+	{          2ULL,          2UL,     1,     1, 6 },  // 62
 	{          2ULL,          1UL,     1,     1, 6 },  // 63
 };
 

+ 8 - 5
Source/ThirdParty/AngelScript/source/as_context.h

@@ -99,10 +99,11 @@ public:
 	void   *GetAddressOfReturnValue();
 
 	// Exception handling
-	int                SetException(const char *descr);
+	int                SetException(const char *descr, bool allowCatch = true);
 	int                GetExceptionLineNumber(int *column, const char **sectionName);
 	asIScriptFunction *GetExceptionFunction();
 	const char *       GetExceptionString();
+	bool               WillExceptionBeCaught();
 	int                SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv);
 	void               ClearExceptionCallback();
 
@@ -144,13 +145,13 @@ public:
 	void DetachEngine();
 
 	void ExecuteNext();
-	void CleanStack();
-	void CleanStackFrame();
+	void CleanStack(bool catchException = false);
+	bool CleanStackFrame(bool catchException = false);
 	void CleanArgsOnStack();
 	void CleanReturnObject();
 	void DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLevel);
 
-	void PushCallState();
+	int  PushCallState();
 	void PopCallState();
 	void CallScriptFunction(asCScriptFunction *func);
 	void CallInterfaceMethod(asCScriptFunction *func);
@@ -158,7 +159,8 @@ public:
 
 	bool ReserveStackSpace(asUINT size);
 
-	void SetInternalException(const char *descr);
+	void SetInternalException(const char *descr, bool allowCatch = true);
+	bool FindExceptionTryCatch();
 
 	// Must be protected for multiple accesses
 	mutable asCAtomic m_refCount;
@@ -192,6 +194,7 @@ public:
 	int       m_exceptionSectionIdx;
 	int       m_exceptionLine;
 	int       m_exceptionColumn;
+	bool      m_exceptionWillBeCaught;
 
 	// The last prepared function, and some cached values related to it
 	asCScriptFunction *m_initialFunction;

+ 170 - 126
Source/ThirdParty/AngelScript/source/as_parser.cpp

@@ -381,13 +381,16 @@ asCScriptNode *asCParser::ParseFunctionDefinition()
 	node->AddChildLast(ParseParameterList());
 	if( isSyntaxError ) return node;
 
-	// Parse an optional const after the function definition (used for object methods)
+	// Parse an optional 'const' after the function definition (used for object methods)
 	sToken t1;
 	GetToken(&t1);
 	RewindTo(&t1);
 	if( t1.type == ttConst )
 		node->AddChildLast(ParseToken(ttConst));
 
+	// Parse an optional 'explicit'
+	ParseMethodAttributes(node);
+
 	return node;
 }
 
@@ -1003,102 +1006,6 @@ void asCParser::Info(const asCString &text, sToken *token)
 		builder->WriteInfo(script->name, text, row, col, false);
 }
 
-// nextToken is only modified if the current position can be interpreted as
-// type, in this case it is set to the next token after the type tokens
-bool asCParser::IsType(sToken &nextToken)
-{
-	// Set a rewind point
-	sToken t, t1;
-	GetToken(&t);
-
-	// A type can start with a const
-	t1 = t;
-	if (t1.type == ttConst)
-		GetToken(&t1);
-
-	sToken t2;
-	if (t1.type != ttAuto)
-	{
-		// The type may be initiated with the scope operator
-		if (t1.type == ttScope)
-			GetToken(&t1);
-
-		// The type may be preceeded with a multilevel scope
-		GetToken(&t2);
-		while (t1.type == ttIdentifier)
-		{
-			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);
-	}
-
-	// We don't validate if the identifier is an actual declared type at this moment
-	// as it may wrongly identify the statement as a non-declaration if the user typed
-	// the name incorrectly. The real type is validated in ParseDeclaration where a
-	// proper error message can be given.
-	if (!IsRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto)
-	{
-		RewindTo(&t);
-		return false;
-	}
-
-	if (!CheckTemplateType(t1))
-	{
-		RewindTo(&t);
-		return false;
-	}
-
-	// Object handles can be interleaved with the array brackets
-	// 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)
-	{
-		if (t2.type == ttOpenBracket)
-		{
-			GetToken(&t2);
-			if (t2.type != ttCloseBracket)
-			{
-				RewindTo(&t);
-				return false;
-			}
-		}
-
-		GetToken(&t2);
-	}
-
-	// Return the next token so the caller can jump directly to it if desired
-	nextToken = t2;
-
-	// Rewind to start point
-	RewindTo(&t);
-
-	return true;
-}
-
 bool asCParser::IsRealType(int tokenType)
 {
 	if( tokenType == ttVoid ||
@@ -1303,8 +1210,122 @@ bool asCParser::IdentifierIs(const sToken &t, const char *str)
 	return script->TokenEquals(t.pos, t.length, str);
 }
 
+void asCParser::ParseMethodAttributes(asCScriptNode *funcNode)
+{
+	sToken t1;
+
+	for(;;)
+	{
+		GetToken(&t1);
+		RewindTo(&t1);
+
+		if( IdentifierIs(t1, FINAL_TOKEN) || 
+			IdentifierIs(t1, OVERRIDE_TOKEN) || 
+			IdentifierIs(t1, EXPLICIT_TOKEN) )
+			funcNode->AddChildLast(ParseIdentifier());
+		else
+			break;
+	}
+}
+
 #ifndef AS_NO_COMPILER
 
+// nextToken is only modified if the current position can be interpreted as
+// type, in this case it is set to the next token after the type tokens
+bool asCParser::IsType(sToken &nextToken)
+{
+	// Set a rewind point
+	sToken t, t1;
+	GetToken(&t);
+
+	// A type can start with a const
+	t1 = t;
+	if (t1.type == ttConst)
+		GetToken(&t1);
+
+	sToken t2;
+	if (t1.type != ttAuto)
+	{
+		// The type may be initiated with the scope operator
+		if (t1.type == ttScope)
+			GetToken(&t1);
+
+		// The type may be preceeded with a multilevel scope
+		GetToken(&t2);
+		while (t1.type == ttIdentifier)
+		{
+			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);
+	}
+
+	// We don't validate if the identifier is an actual declared type at this moment
+	// as it may wrongly identify the statement as a non-declaration if the user typed
+	// the name incorrectly. The real type is validated in ParseDeclaration where a
+	// proper error message can be given.
+	if (!IsRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto)
+	{
+		RewindTo(&t);
+		return false;
+	}
+
+	if (!CheckTemplateType(t1))
+	{
+		RewindTo(&t);
+		return false;
+	}
+
+	// Object handles can be interleaved with the array brackets
+	// 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)
+	{
+		if (t2.type == ttOpenBracket)
+		{
+			GetToken(&t2);
+			if (t2.type != ttCloseBracket)
+			{
+				RewindTo(&t);
+				return false;
+			}
+		}
+
+		GetToken(&t2);
+	}
+
+	// Return the next token so the caller can jump directly to it if desired
+	nextToken = t2;
+
+	// Rewind to start point
+	RewindTo(&t);
+
+	return true;
+}
+
 // 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
@@ -2868,7 +2889,9 @@ bool asCParser::IsFuncDecl(bool isMethod)
 				for( ; ; )
 				{
 					GetToken(&t1);
-					if( !IdentifierIs(t1, FINAL_TOKEN) && !IdentifierIs(t1, OVERRIDE_TOKEN) )
+					if( !IdentifierIs(t1, FINAL_TOKEN) && 
+						!IdentifierIs(t1, OVERRIDE_TOKEN) &&
+						!IdentifierIs(t1, EXPLICIT_TOKEN) )
 					{
 						RewindTo(&t1);
 						break;
@@ -2942,7 +2965,7 @@ asCScriptNode *asCParser::ParseFuncDef()
 	return node;
 }
 
-// BNF:1: FUNC          ::= {'shared' | 'external'} ['private' | 'protected'] [((TYPE ['&']) | '~')] IDENTIFIER PARAMLIST ['const'] {'override' | 'final'} (';' | STATBLOCK)
+// BNF:1: FUNC          ::= {'shared' | 'external'} ['private' | 'protected'] [((TYPE ['&']) | '~')] IDENTIFIER PARAMLIST ['const'] {'override' | 'final' | 'explicit'} (';' | STATBLOCK)
 asCScriptNode *asCParser::ParseFunction(bool isMethod)
 {
 	asCScriptNode *node = CreateNode(snFunction);
@@ -3020,7 +3043,7 @@ asCScriptNode *asCParser::ParseFunction(bool isMethod)
 			node->AddChildLast(ParseToken(ttConst));
 
 		// TODO: Should support abstract methods, in which case no statement block should be provided
-		ParseMethodOverrideBehaviors(node);
+		ParseMethodAttributes(node);
 		if( isSyntaxError ) return node;
 	}
 
@@ -3137,7 +3160,7 @@ asCScriptNode *asCParser::ParseVirtualPropertyDecl(bool isMethod, bool isInterfa
 
 				if( !isInterface )
 				{
-					ParseMethodOverrideBehaviors(accessorNode);
+					ParseMethodAttributes(accessorNode);
 					if( isSyntaxError ) return node;
 				}
 			}
@@ -3882,7 +3905,7 @@ asCScriptNode *asCParser::ParseDeclaration(bool isClassProp, bool isGlobalVar)
 	UNREACHABLE_RETURN;
 }
 
-// BNF:7: STATEMENT     ::= (IF | FOR | WHILE | RETURN | STATBLOCK | BREAK | CONTINUE | DOWHILE | SWITCH | EXPRSTAT)
+// BNF:7: STATEMENT     ::= (IF | FOR | WHILE | RETURN | STATBLOCK | BREAK | CONTINUE | DOWHILE | SWITCH | EXPRSTAT | TRY)
 asCScriptNode *asCParser::ParseStatement()
 {
 	sToken t1;
@@ -3890,24 +3913,26 @@ asCScriptNode *asCParser::ParseStatement()
 	GetToken(&t1);
 	RewindTo(&t1);
 
-	if( t1.type == ttIf )
+	if (t1.type == ttIf)
 		return ParseIf();
-	else if( t1.type == ttFor )
+	else if (t1.type == ttFor)
 		return ParseFor();
-	else if( t1.type == ttWhile )
+	else if (t1.type == ttWhile)
 		return ParseWhile();
-	else if( t1.type == ttReturn )
+	else if (t1.type == ttReturn)
 		return ParseReturn();
-	else if( t1.type == ttStartStatementBlock )
+	else if (t1.type == ttStartStatementBlock)
 		return ParseStatementBlock();
-	else if( t1.type == ttBreak )
+	else if (t1.type == ttBreak)
 		return ParseBreak();
-	else if( t1.type == ttContinue )
+	else if (t1.type == ttContinue)
 		return ParseContinue();
-	else if( t1.type == ttDo )
+	else if (t1.type == ttDo)
 		return ParseDoWhile();
-	else if( t1.type == ttSwitch )
+	else if (t1.type == ttSwitch)
 		return ParseSwitch();
+	else if (t1.type == ttTry)
+		return ParseTryCatch();
 	else
 	{
 		if( IsVarDecl() )
@@ -4135,6 +4160,40 @@ asCScriptNode *asCParser::ParseIf()
 	return node;
 }
 
+// BNF:8: TRY           ::= 'try' STATBLOCK 'catch' STATBLOCK
+asCScriptNode *asCParser::ParseTryCatch()
+{
+	asCScriptNode *node = CreateNode(snTryCatch);
+	if (node == 0) return 0;
+
+	sToken t;
+	GetToken(&t);
+	if (t.type != ttTry)
+	{
+		Error(ExpectedToken("try"), &t);
+		Error(InsteadFound(t), &t);
+		return node;
+	}
+
+	node->UpdateSourcePos(t.pos, t.length);
+
+	node->AddChildLast(ParseStatementBlock());
+	if (isSyntaxError) return node;
+
+	GetToken(&t);
+	if (t.type != ttCatch)
+	{
+		Error(ExpectedToken("catch"), &t);
+		Error(InsteadFound(t), &t);
+		return node;
+	}
+
+	node->AddChildLast(ParseStatementBlock());
+	if (isSyntaxError) return node;
+
+	return node;
+}
+
 // BNF:8: FOR           ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN {',' ASSIGN}] ')' STATEMENT
 asCScriptNode *asCParser::ParseFor()
 {
@@ -4452,21 +4511,6 @@ asCScriptNode *asCParser::ParseTypedef()
 	return node;
 }
 
-void asCParser::ParseMethodOverrideBehaviors(asCScriptNode *funcNode)
-{
-	sToken t1;
-
-	for(;;)
-	{
-		GetToken(&t1);
-		RewindTo(&t1);
-
-		if( IdentifierIs(t1, FINAL_TOKEN) || IdentifierIs(t1, OVERRIDE_TOKEN) )
-			funcNode->AddChildLast(ParseIdentifier());
-		else
-			break;
-	}
-}
 #endif
 
 END_AS_NAMESPACE

+ 3 - 2
Source/ThirdParty/AngelScript/source/as_parser.h

@@ -91,12 +91,12 @@ protected:
 	asCScriptNode *ParseDataType(bool allowVariableType = false, bool allowAuto = false);
 	asCScriptNode *ParseIdentifier();
 	bool           ParseTemplTypeList(asCScriptNode *node, bool required = true);
+	void           ParseMethodAttributes(asCScriptNode *funcNode);
 
 	asCScriptNode *ParseListPattern();
 
 	bool IsRealType(int tokenType);
 	bool IsDataType(const sToken &token);
-	bool IsType(sToken &nextToken);
 	bool IdentifierIs(const sToken &t, const char *str);
 
 #ifndef AS_NO_COMPILER
@@ -115,6 +115,7 @@ protected:
 	asCScriptNode *ParseReturn();
 	asCScriptNode *ParseBreak();
 	asCScriptNode *ParseContinue();
+	asCScriptNode *ParseTryCatch();
 
 	// Declarations
 	asCScriptNode *ParseDeclaration(bool isClassProp = false, bool isGlobalVar = false);
@@ -131,7 +132,6 @@ protected:
 	asCScriptNode *ParseVirtualPropertyDecl(bool isMethod, bool isInterface);
 	asCScriptNode *ParseEnumeration();
 	asCScriptNode *ParseTypedef();
-	void ParseMethodOverrideBehaviors(asCScriptNode *funcNode);
 	bool IsVarDecl();
 	bool IsVirtualPropertyDecl();
 	bool IsFuncDecl(bool isMethod);
@@ -157,6 +157,7 @@ protected:
 	asCScriptNode *ParseStringConstant();
 	asCScriptNode *ParseLambda();
 
+	bool IsType(sToken &nextToken);
 	bool IsConstant(int tokenType);
 	bool IsOperator(int tokenType);
 	bool IsPreOperator(int tokenType);

+ 87 - 41
Source/ThirdParty/AngelScript/source/as_restore.cpp

@@ -1237,6 +1237,7 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
 			char bits;
 			ReadData(&bits, 1);
 			func->SetShared((bits & 1) ? true : false);
+			func->SetExplicit((bits & 32) ? true : false);
 			func->dontCleanUpOnException = (bits & 2) ? true : false;
 			if ((bits & 4) && isExternal)
 				*isExternal = true;
@@ -1260,46 +1261,65 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
 
 				func->scriptData->variableSpace = ReadEncodedUInt();
 
-				count = ReadEncodedUInt();
-				func->scriptData->objVariablePos.Allocate(count, false);
-				func->scriptData->objVariableTypes.Allocate(count, false);
-				for (i = 0; i < count; ++i)
+				func->scriptData->objVariablesOnHeap = 0;
+				if (bits & 8)
 				{
-					func->scriptData->objVariableTypes.PushLast(ReadTypeInfo());
-					num = ReadEncodedUInt();
-					func->scriptData->objVariablePos.PushLast(num);
+					count = ReadEncodedUInt();
+					func->scriptData->objVariablePos.Allocate(count, false);
+					func->scriptData->objVariableTypes.Allocate(count, false);
+					for (i = 0; i < count; ++i)
+					{
+						func->scriptData->objVariableTypes.PushLast(ReadTypeInfo());
+						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();
 
-					if (error)
+					int length = ReadEncodedUInt();
+					func->scriptData->objVariableInfo.SetLength(length);
+					for (i = 0; i < length; ++i)
 					{
-						// No need to continue (the error has already been reported before)
-						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 && 
+							option != asOBJ_VARDECL)
+						{
+							error = true;
+							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)
+				if (bits & 16)
 				{
-					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)
+					// Read info on try/catch blocks
+					int length = ReadEncodedUInt();
+					func->scriptData->tryCatchInfo.SetLength(length);
+					for (i = 0; i < length; ++i)
 					{
-						error = true;
-						func->DestroyHalfCreated();
-						return 0;
+						// The program position must be adjusted to be in number of instructions
+						func->scriptData->tryCatchInfo[i].tryPos = ReadEncodedUInt();
+						func->scriptData->tryCatchInfo[i].catchPos = ReadEncodedUInt();
 					}
 				}
 
 				if (!noDebugInfo)
 				{
-					length = ReadEncodedUInt();
+					int length = ReadEncodedUInt();
 					func->scriptData->lineNumbers.SetLength(length);
 					if (int(func->scriptData->lineNumbers.GetLength()) != length)
 					{
@@ -1337,7 +1357,7 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
 				// Read the variable information
 				if (!noDebugInfo)
 				{
-					length = ReadEncodedUInt();
+					int length = ReadEncodedUInt();
 					func->scriptData->variables.Allocate(length, false);
 					for (i = 0; i < length; i++)
 					{
@@ -3085,6 +3105,12 @@ void asCReader::TranslateFunction(asCScriptFunction *func)
 		func->scriptData->objVariableInfo[n].variableOffset = AdjustStackPosition(func->scriptData->objVariableInfo[n].variableOffset);
 	}
 
+	for (n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++)
+	{
+		func->scriptData->tryCatchInfo[n].tryPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].tryPos];
+		func->scriptData->tryCatchInfo[n].catchPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].catchPos];
+	}
+
 	// 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( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 )
@@ -4144,6 +4170,11 @@ void asCWriter::WriteFunction(asCScriptFunction* func)
 		bits += func->dontCleanUpOnException ? 2 : 0;
 		if (module->externalFunctions.IndexOf(func) >= 0)
 			bits += 4;
+		if (func->scriptData->objVariablePos.GetLength() || func->scriptData->objVariableInfo.GetLength())
+			bits += 8;
+		if (func->scriptData->tryCatchInfo.GetLength())
+			bits += 16;
+		bits += func->IsExplicit() ? 32 : 0;
 		WriteData(&bits, 1);
 
 		// For external shared functions the rest is not needed
@@ -4158,23 +4189,38 @@ void asCWriter::WriteFunction(asCScriptFunction* func)
 		asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace);
 		WriteEncodedInt64(varSpace);
 
-		count = (asUINT)func->scriptData->objVariablePos.GetLength();
-		WriteEncodedInt64(count);
-		for( i = 0; i < count; ++i )
+		if (bits & 8)
 		{
-			WriteTypeInfo(func->scriptData->objVariableTypes[i]);
-			WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i]));
+			count = (asUINT)func->scriptData->objVariablePos.GetLength();
+			WriteEncodedInt64(count);
+			for (i = 0; i < count; ++i)
+			{
+				WriteTypeInfo(func->scriptData->objVariableTypes[i]);
+				WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i]));
+			}
+			if (count > 0)
+				WriteEncodedInt64(func->scriptData->objVariablesOnHeap);
+
+			WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength());
+			for (i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i)
+			{
+				// The program position must be adjusted to be in number of instructions
+				WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]);
+				WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset));
+				WriteEncodedInt64(func->scriptData->objVariableInfo[i].option);
+			}
 		}
-		if( count > 0 )
-			WriteEncodedInt64(func->scriptData->objVariablesOnHeap);
 
-		WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength());
-		for( i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i )
+		if (bits & 16)
 		{
-			// The program position must be adjusted to be in number of instructions
-			WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]);
-			WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset));
-			WriteEncodedInt64(func->scriptData->objVariableInfo[i].option);
+			// Write info on try/catch blocks
+			WriteEncodedInt64((asUINT)func->scriptData->tryCatchInfo.GetLength());
+			for (i = 0; i < func->scriptData->tryCatchInfo.GetLength(); ++i)
+			{
+				// The program position must be adjusted to be in number of instructions
+				WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].tryPos]);
+				WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].catchPos]);
+			}
 		}
 
 		// The program position (every even number) needs to be adjusted

+ 64 - 30
Source/ThirdParty/AngelScript/source/as_scriptengine.cpp

@@ -291,18 +291,24 @@ int asCScriptEngine::SetEngineProperty(asEEngineProp property, asPWORD value)
 		{
 			// Restore default: no limit and initially size 4KB
 			ep.maximumContextStackSize = 0;
-			initialContextStackSize    = 1024;
 		}
 		else
 		{
 			// The size is given in bytes, but we only store dwords
 			ep.maximumContextStackSize = (asUINT)value/4;
-			if( initialContextStackSize > ep.maximumContextStackSize )
-			{
-				initialContextStackSize = ep.maximumContextStackSize;
-				if( initialContextStackSize == 0 )
-					initialContextStackSize = 1;
-			}
+		}
+		break;
+
+	case asEP_INIT_STACK_SIZE:
+		if (value < 4)
+		{
+			// At least one dword
+			ep.initContextStackSize = 1;
+		}
+		else
+		{
+			// The size is given in bytes, but we only store dwords
+			ep.initContextStackSize = (asUINT)value / 4;
 		}
 		break;
 
@@ -426,6 +432,14 @@ int asCScriptEngine::SetEngineProperty(asEEngineProp property, asPWORD value)
 			ep.genericCallMode = (asUINT)value;
 		break;
 
+	case asEP_INIT_CALL_STACK_SIZE:
+		ep.initCallStackSize = (asUINT)value;
+		break;
+
+	case asEP_MAX_CALL_STACK_SIZE:
+		ep.maxCallStackSize = (asUINT)value;
+		break;
+
 	default:
 		return asINVALID_ARG;
 	}
@@ -448,7 +462,10 @@ asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const
 		return ep.copyScriptSections;
 
 	case asEP_MAX_STACK_SIZE:
-		return ep.maximumContextStackSize*4;
+		return ep.maximumContextStackSize * 4;
+
+	case asEP_INIT_STACK_SIZE:
+		return ep.initContextStackSize * 4;
 
 	case asEP_USE_CHARACTER_LITERALS:
 		return ep.useCharacterLiterals;
@@ -522,6 +539,12 @@ asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const
 	case asEP_GENERIC_CALL_MODE:
 		return ep.genericCallMode;
 
+	case asEP_INIT_CALL_STACK_SIZE:
+		return ep.initCallStackSize;
+
+	case asEP_MAX_CALL_STACK_SIZE:
+		return ep.maxCallStackSize;
+
 	default:
 		return 0;
 	}
@@ -561,6 +584,7 @@ asCScriptEngine::asCScriptEngine()
 		ep.optimizeByteCode              = true;
 		ep.copyScriptSections            = true;
 		ep.maximumContextStackSize       = 0;         // no limit
+		ep.initContextStackSize          = 1024;      // 4KB default init stack size
 		ep.useCharacterLiterals          = false;
 		ep.allowMultilineStrings         = false;
 		ep.allowImplicitHandleTypes      = false;
@@ -588,6 +612,8 @@ asCScriptEngine::asCScriptEngine()
 		ep.heredocTrimMode               = 1;         // 0 = never trim, 1 = don't trim on single line, 2 = trim initial and final empty line
 		ep.maxNestedCalls                = 100;
 		ep.genericCallMode               = 1;         // 0 = old (pre 2.33.0) behavior where generic ignored auto handles, 1 = treat handles like in native call
+		ep.initCallStackSize             = 10;        // 10 levels of calls
+		ep.maxCallStackSize              = 0;         // 0 = no limit
 	}
 
 	gc.engine = this;
@@ -601,10 +627,6 @@ asCScriptEngine::asCScriptEngine()
 	deferValidationOfTemplateTypes = false;
 	lastModule = 0;
 
-
-	initialContextStackSize = 1024;      // 4 KB (1024 * sizeof(asDWORD)
-
-
 	typeIdSeqNbr      = 0;
 	currentGroup      = &defaultGroup;
 	defaultAccessMask = 0xFFFFFFFF; // All bits set so that built-in functions/types will be available to all modules
@@ -902,6 +924,8 @@ asCModule *asCScriptEngine::FindNewOwnerForSharedType(asCTypeInfo *in_type, asCM
 			foundIdx = mod->typeDefs.IndexOf(CastToTypedefType(in_type));
 		else if (in_type->flags & asOBJ_FUNCDEF)
 			foundIdx = mod->funcDefs.IndexOf(CastToFuncdefType(in_type));
+		else if (in_type->flags & asOBJ_TEMPLATE)
+			foundIdx = mod->templateInstances.IndexOf(CastToObjectType(in_type));
 		else
 			foundIdx = mod->classTypes.IndexOf(CastToObjectType(in_type));
 
@@ -1517,7 +1541,7 @@ int asCScriptEngine::RegisterInterface(const char *name)
 	if( token != ttIdentifier || strlen(name) != tokenLen )
 		return ConfigError(asINVALID_NAME, "RegisterInterface", name, 0);
 
-	r = bld.CheckNameConflict(name, 0, 0, defaultNamespace);
+	r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true);
 	if( r < 0 )
 		return ConfigError(asNAME_TAKEN, "RegisterInterface", name, 0);
 
@@ -1800,7 +1824,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD
 			if( token != ttIdentifier || typeName.GetLength() != tokenLen )
 				return ConfigError(asINVALID_NAME, "RegisterObjectType", name, 0);
 
-			r = bld.CheckNameConflict(name, 0, 0, defaultNamespace);
+			r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true);
 			if( r < 0 )
 				return ConfigError(asNAME_TAKEN, "RegisterObjectType", name, 0);
 
@@ -2497,6 +2521,7 @@ int asCScriptEngine::AddBehaviourFunction(asCScriptFunction &func, asSSystemFunc
 	f->parameterTypes = func.parameterTypes;
 	f->parameterNames = func.parameterNames;
 	f->inOutFlags     = func.inOutFlags;
+	f->traits         = func.traits;
 	for( n = 0; n < func.defaultArgs.GetLength(); n++ )
 		if( func.defaultArgs[n] )
 			f->defaultArgs.PushLast(asNEW(asCString)(*func.defaultArgs[n]));
@@ -2882,7 +2907,7 @@ int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFu
 	func->nameSpace = defaultNamespace;
 
 	// Check name conflicts
-	r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace);
+	r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace, false);
 	if( r < 0 )
 	{
 		// Set as dummy function before deleting
@@ -3631,6 +3656,11 @@ asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, a
 
 					dt.MakeReference(orig.IsReference());
 					dt.MakeReadOnly(ot->templateSubTypes[n].IsReadOnly() || orig.IsReadOnly());
+
+					// If the target is a @& then don't make the handle const, 
+					// as it is not possible to declare functions with @const &
+					if (orig.IsReference() && dt.IsObjectHandle())
+						dt.MakeReadOnly(false);
 				}
 				break;
 			}
@@ -3746,6 +3776,7 @@ asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *t
 	func->id = GetNextScriptFunctionId();
 	AddScriptFunction(func);
 
+	func->traits = factory->traits;
 	func->SetShared(true);
 	if( templateType->flags & asOBJ_REF )
 	{
@@ -3917,6 +3948,7 @@ bool asCScriptEngine::GenerateNewTemplateFunction(asCObjectType *templateType, a
 
 	func2->parameterNames = func->parameterNames;
 	func2->inOutFlags = func->inOutFlags;
+	func2->traits = func->traits;
 	func2->SetReadOnly(func->IsReadOnly());
 	func2->objectType = ot;
 	func2->objectType->AddRefInternal();
@@ -4889,11 +4921,10 @@ int asCScriptEngine::RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo
 					AddRefScriptObject(*newPtr, toType);
 				return asSUCCESS;
 			}
-			else
+			else if( func->returnType.GetTokenType() == ttVoid &&
+					 func->parameterTypes.GetLength() == 1 &&
+					 func->parameterTypes[0].GetTokenType() == ttQuestion )
 			{
-				asASSERT( func->returnType.GetTokenType() == ttVoid &&
-						  func->parameterTypes.GetLength() == 1 &&
-						  func->parameterTypes[0].GetTokenType() == ttQuestion );
 				universalCastFunc = func;
 			}
 		}
@@ -4963,9 +4994,11 @@ void *asCScriptEngine::CreateScriptObject(const asITypeInfo *type)
 	// Check that there is a default factory for ref types
 	if( objType->beh.factory == 0 && (objType->flags & asOBJ_REF) )
 	{
-		asCString str;
-		str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION);
-		WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
+		// TODO: How to report the reason the object couldn't be created, without writing to the message callback? optional argument with return code?
+		// TODO: Warn about the invalid call to message callback. Make it an optional, so the warning can be turned off
+//		asCString str;
+//		str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION);
+//		WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
 		return 0;
 	}
 
@@ -5017,9 +5050,11 @@ void *asCScriptEngine::CreateScriptObject(const asITypeInfo *type)
 		// Make sure there is a default constructor or that it is a POD type
 		if( objType->beh.construct == 0 && !(objType->flags & asOBJ_POD) )
 		{
-			asCString str;
-			str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION);
-			WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
+			// TODO: How to report the reason the object couldn't be created, without writing to the message callback? optional argument with return code?
+			// TODO: Warn about the invalid call to message callback. Make it an optional, so the warning can be turned off
+//			asCString str;
+//			str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION);
+//			WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
 			return 0;
 		}
 
@@ -5257,8 +5292,7 @@ void asCScriptEngine::ConstructScriptObjectCopy(void *mem, void *obj, asCObjectT
 // interface
 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?
+	// TODO: Warn about invalid call in message stream (make it optional)
 	if( type == 0 || dstObj == 0 || srcObj == 0 ) return asINVALID_ARG;
 
 	const asCObjectType *objType = reinterpret_cast<const asCObjectType*>(type);
@@ -5625,7 +5659,7 @@ int asCScriptEngine::RegisterFuncdef(const char *decl)
 	}
 
 	// Check name conflicts
-	r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace);
+	r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace, true);
 	if( r < 0 )
 	{
 		asDELETE(func,asCScriptFunction);
@@ -5796,7 +5830,7 @@ int asCScriptEngine::RegisterTypedef(const char *type, const char *decl)
 		return ConfigError(asINVALID_NAME, "RegisterTypedef", type, decl);
 
 	asCBuilder bld(this, 0);
-	int r = bld.CheckNameConflict(type, 0, 0, defaultNamespace);
+	int r = bld.CheckNameConflict(type, 0, 0, defaultNamespace, true);
 	if( r < 0 )
 		return ConfigError(asNAME_TAKEN, "RegisterTypedef", type, decl);
 
@@ -5868,7 +5902,7 @@ int asCScriptEngine::RegisterEnum(const char *name)
 	if( token != ttIdentifier || strlen(name) != tokenLen )
 		return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0);
 
-	r = bld.CheckNameConflict(name, 0, 0, defaultNamespace);
+	r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true);
 	if( r < 0 )
 		return ConfigError(asNAME_TAKEN, "RegisterEnum", name, 0);
 

+ 3 - 2
Source/ThirdParty/AngelScript/source/as_scriptengine.h

@@ -321,8 +321,6 @@ public:
 //===========================================================
 	asCMemoryMgr memoryMgr;
 
-	asUINT initialContextStackSize;
-
 	asCObjectType   *defaultArrayObjectType;
 	asCObjectType    scriptTypeBehaviours;
 	asCObjectType    functionBehaviours;
@@ -475,6 +473,7 @@ public:
 		bool   optimizeByteCode;
 		bool   copyScriptSections;
 		asUINT maximumContextStackSize;
+		asUINT initContextStackSize;
 		bool   useCharacterLiterals;
 		bool   allowMultilineStrings;
 		bool   allowImplicitHandleTypes;
@@ -501,6 +500,8 @@ public:
 		int    heredocTrimMode;
 		asUINT maxNestedCalls;
 		asUINT genericCallMode;
+		asUINT initCallStackSize;
+		asUINT maxCallStackSize;
 	} ep;
 
 	// Callbacks

+ 11 - 5
Source/ThirdParty/AngelScript/source/as_scriptfunction.cpp

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2017 Andreas Jonsson
+   Copyright (c) 2003-2018 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
@@ -709,7 +709,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
 		else
 			str += "_unnamed_type_::";
 	}
-	else if( includeNamespace && nameSpace->name != "" )
+	else if( includeNamespace && nameSpace->name != "" && !objectType )
 	{
 		str += nameSpace->name + "::";
 	}
@@ -1683,7 +1683,7 @@ void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *)
 	objForDelegate = 0;
 }
 
-// internal
+// interface
 bool asCScriptFunction::IsShared() const
 {
 	// All system functions are shared
@@ -1700,17 +1700,23 @@ bool asCScriptFunction::IsShared() const
 	return traits.GetTrait(asTRAIT_SHARED);
 }
 
-// internal
+// interface
 bool asCScriptFunction::IsFinal() const
 {
 	return traits.GetTrait(asTRAIT_FINAL);
 }
 
-// internal
+// interface
 bool asCScriptFunction::IsOverride() const
 {
 	return traits.GetTrait(asTRAIT_OVERRIDE);
 }
 
+// interface
+bool asCScriptFunction::IsExplicit() const
+{
+	return traits.GetTrait(asTRAIT_EXPLICIT);
+}
+
 END_AS_NAMESPACE
 

+ 21 - 8
Source/ThirdParty/AngelScript/source/as_scriptfunction.h

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2017 Andreas Jonsson
+   Copyright (c) 2003-2018 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
@@ -91,10 +91,11 @@ struct asSListPatternDataTypeNode : public asSListPatternNode
 
 enum asEObjVarInfoOption
 {
-	asOBJ_UNINIT,
-	asOBJ_INIT,
-	asBLOCK_BEGIN,
-	asBLOCK_END
+	asOBJ_UNINIT,	// object is uninitialized/destroyed
+	asOBJ_INIT,		// object is initialized
+	asBLOCK_BEGIN,	// scope block begins
+	asBLOCK_END,	// scope block ends
+	asOBJ_VARDECL	// object variable is declared (but not necessarily initialized)
 };
 
 enum asEFuncTrait
@@ -107,7 +108,8 @@ enum asEFuncTrait
 	asTRAIT_FINAL       = 32,
 	asTRAIT_OVERRIDE    = 64,
 	asTRAIT_SHARED      = 128,
-	asTRAIT_EXTERNAL    = 256
+	asTRAIT_EXTERNAL    = 256,
+	asTRAIT_EXPLICIT    = 512
 };
 
 struct asSFunctionTraits
@@ -126,6 +128,12 @@ struct asSObjectVariableInfo
 	asEObjVarInfoOption option;
 };
 
+struct asSTryCatchInfo
+{
+	asUINT tryPos;
+	asUINT catchPos;
+};
+
 struct asSSystemFunctionInterface;
 
 // TODO: Might be interesting to allow enumeration of accessed global variables, and
@@ -166,6 +174,7 @@ public:
 	bool                 IsFinal() const;
 	bool                 IsOverride() const;
 	bool                 IsShared() const;
+	bool                 IsExplicit() const;
 	asUINT               GetParamCount() const;
 	int                  GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const;
 	int                  GetReturnTypeId(asDWORD *flags = 0) const;
@@ -196,10 +205,11 @@ public:
 	//-----------------------------------
 	// Internal methods
 
-	void SetShared(bool set) {traits.SetTrait(asTRAIT_SHARED, set);}
+	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 SetExplicit(bool set) { traits.SetTrait(asTRAIT_EXPLICIT, set); }
 	void SetProtected(bool set) { traits.SetTrait(asTRAIT_PROTECTED, set); }
 	void SetPrivate(bool set) { traits.SetTrait(asTRAIT_PRIVATE, set); }
 
@@ -317,7 +327,7 @@ public:
 		// These hold information on objects and function pointers, including temporary
 		// variables used by exception handler and when saving bytecode
 		asCArray<asCTypeInfo*>          objVariableTypes;
-		asCArray<int>                   objVariablePos;
+		asCArray<int>                   objVariablePos; // offset on stackframe
 
 		// The first variables in above array are allocated on the heap, the rest on the stack.
 		// This variable shows how many are on the heap.
@@ -326,6 +336,9 @@ public:
 		// Holds information on scope for object variables on the stack
 		asCArray<asSObjectVariableInfo> objVariableInfo;
 
+		// Holds information on try/catch blocks for exception handling
+		asCArray<asSTryCatchInfo>       tryCatchInfo;
+
 		// The stack needed to execute the function
 		int                             stackNeeded;
 

+ 3 - 2
Source/ThirdParty/AngelScript/source/as_scriptnode.h

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2015 Andreas Jonsson
+   Copyright (c) 2003-2018 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 
@@ -90,7 +90,8 @@ enum eScriptNode
 	snMixin,
 	snListPattern,
 	snNamedArgument,
-	snScope
+	snScope,
+	snTryCatch
 };
 
 struct sToken

+ 2 - 1
Source/ThirdParty/AngelScript/source/as_scriptobject.cpp

@@ -162,7 +162,8 @@ asIScriptObject *ScriptObjectCopyFactory(const asCObjectType *objType, void *ori
 		return 0;
 	}
 
-	ctx->SetArgAddress(0, origObj);
+	// Let the context handle the case for argument by ref (&) or by handle (@)
+	ctx->SetArgObject(0, origObj);
 
 	for (;;)
 	{

+ 2 - 0
Source/ThirdParty/AngelScript/source/as_texts.h

@@ -184,6 +184,7 @@
 #define TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY        "Name conflict. '%s' is a global property."
 #define TXT_NAME_CONFLICT_s_IS_NAMED_TYPE          "Name conflict. '%s' is a named type."
 #define TXT_NAME_CONFLICT_s_IS_FUNCDEF             "Name conflict. '%s' is a funcdef."
+#define TXT_NAME_CONFLICT_s_IS_FUNCTION            "Name conflict. '%s' is a global function."
 #define TXT_NAME_CONFLICT_s_IS_MIXIN               "Name conflict. '%s' is a mixin class."
 #define TXT_NAME_CONFLICT_s_STRUCT                 "Name conflict. '%s' is a class."
 #define TXT_NAME_CONFLICT_s_OBJ_PROPERTY           "Name conflict. '%s' is an object property."
@@ -284,6 +285,7 @@
 #define TXT_VOID_CANT_BE_OPERAND          "Void cannot be an operand in expressions"
 
 #define TXT_WARNINGS_TREATED_AS_ERROR     "Warnings are treated as errors by the application"
+#define TXT_WHERE_s_IS_s                  "Where '%s' is '%s'"
 #define TXT_WHILE_PARSING_ARG_LIST        "While parsing argument list"
 #define TXT_WHILE_PARSING_EXPRESSION      "While parsing expression"
 #define TXT_WHILE_PARSING_INIT_LIST       "While parsing initialization list"

+ 7 - 2
Source/ThirdParty/AngelScript/source/as_tokendef.h

@@ -1,6 +1,6 @@
 /*
    AngelCode Scripting Library
-   Copyright (c) 2003-2017 Andreas Jonsson
+   Copyright (c) 2003-2018 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
@@ -174,7 +174,9 @@ enum eTokenType
 	ttProtected,           // protected
 	ttNamespace,           // namespace
 	ttMixin,               // mixin
-	ttAuto                 // auto
+	ttAuto,                // auto
+	ttTry,                 // try
+	ttCatch                // catch
 };
 
 struct sTokenWord
@@ -246,6 +248,7 @@ sTokenWord const tokenWords[] =
 	asTokenDef("break"     , ttBreak),
 	asTokenDef("case"      , ttCase),
 	asTokenDef("cast"      , ttCast),
+	asTokenDef("catch"     , ttCatch),
 	asTokenDef("class"     , ttClass),
 	asTokenDef("const"     , ttConst),
 	asTokenDef("continue"  , ttContinue),
@@ -284,6 +287,7 @@ sTokenWord const tokenWords[] =
 	asTokenDef("return"    , ttReturn),
 	asTokenDef("switch"    , ttSwitch),
 	asTokenDef("true"      , ttTrue),
+	asTokenDef("try"       , ttTry),
 	asTokenDef("typedef"   , ttTypedef),
 	asTokenDef("uint"      , ttUInt),
 	asTokenDef("uint8"     , ttUInt8),
@@ -314,6 +318,7 @@ 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";
+const char * const EXPLICIT_TOKEN  = "explicit";
 
 END_AS_NAMESPACE
 

+ 2 - 32
Source/Urho3D/IO/MemoryBuffer.cpp

@@ -70,22 +70,7 @@ unsigned MemoryBuffer::Read(void* dest, unsigned size)
     auto* destPtr = (unsigned char*)dest;
     position_ += size;
 
-    unsigned copySize = size;
-    while (copySize >= sizeof(unsigned))
-    {
-        *((unsigned*)destPtr) = *((unsigned*)srcPtr);
-        srcPtr += sizeof(unsigned);
-        destPtr += sizeof(unsigned);
-        copySize -= sizeof(unsigned);
-    }
-    if (copySize & sizeof(unsigned short))
-    {
-        *((unsigned short*)destPtr) = *((unsigned short*)srcPtr);
-        srcPtr += sizeof(unsigned short);
-        destPtr += sizeof(unsigned short);
-    }
-    if (copySize & 1u)
-        *destPtr = *srcPtr;
+    memcpy(destPtr, srcPtr, size);
 
     return size;
 }
@@ -110,22 +95,7 @@ unsigned MemoryBuffer::Write(const void* data, unsigned size)
     unsigned char* destPtr = &buffer_[position_];
     position_ += size;
 
-    unsigned copySize = size;
-    while (copySize >= sizeof(unsigned))
-    {
-        *((unsigned*)destPtr) = *((unsigned*)srcPtr);
-        srcPtr += sizeof(unsigned);
-        destPtr += sizeof(unsigned);
-        copySize -= sizeof(unsigned);
-    }
-    if (copySize & sizeof(unsigned short))
-    {
-        *((unsigned short*)destPtr) = *((unsigned short*)srcPtr);
-        srcPtr += sizeof(unsigned short);
-        destPtr += sizeof(unsigned short);
-    }
-    if (copySize & 1u)
-        *destPtr = *srcPtr;
+    memcpy(destPtr, srcPtr, size);
 
     return size;
 }

+ 2 - 32
Source/Urho3D/IO/VectorBuffer.cpp

@@ -55,22 +55,7 @@ unsigned VectorBuffer::Read(void* dest, unsigned size)
     auto* destPtr = (unsigned char*)dest;
     position_ += size;
 
-    unsigned copySize = size;
-    while (copySize >= sizeof(unsigned))
-    {
-        *((unsigned*)destPtr) = *((unsigned*)srcPtr);
-        srcPtr += sizeof(unsigned);
-        destPtr += sizeof(unsigned);
-        copySize -= sizeof(unsigned);
-    }
-    if (copySize & sizeof(unsigned short))
-    {
-        *((unsigned short*)destPtr) = *((unsigned short*)srcPtr);
-        srcPtr += sizeof(unsigned short);
-        destPtr += sizeof(unsigned short);
-    }
-    if (copySize & 1u)
-        *destPtr = *srcPtr;
+    memcpy(destPtr, srcPtr, size);
 
     return size;
 }
@@ -99,22 +84,7 @@ unsigned VectorBuffer::Write(const void* data, unsigned size)
     unsigned char* destPtr = &buffer_[position_];
     position_ += size;
 
-    unsigned copySize = size;
-    while (copySize >= sizeof(unsigned))
-    {
-        *((unsigned*)destPtr) = *((unsigned*)srcPtr);
-        srcPtr += sizeof(unsigned);
-        destPtr += sizeof(unsigned);
-        copySize -= sizeof(unsigned);
-    }
-    if (copySize & sizeof(unsigned short))
-    {
-        *((unsigned short*)destPtr) = *((unsigned short*)srcPtr);
-        srcPtr += sizeof(unsigned short);
-        destPtr += sizeof(unsigned short);
-    }
-    if (copySize & 1u)
-        *destPtr = *srcPtr;
+    memcpy(destPtr, srcPtr, size);
 
     return size;
 }

+ 12 - 0
Source/Urho3D/Math/MathDefs.h

@@ -169,6 +169,18 @@ template <class T> inline T Round(T x) { return round(x); }
 /// Round value to nearest integer.
 template <class T> inline int RoundToInt(T x) { return static_cast<int>(round(x)); }
 
+/// Round value to nearest multiple. 
+template <class T> inline T RoundToNearestMultiple(T x, T multiple)
+{
+    T mag = Abs(x);
+    multiple = Abs(multiple);
+    T remainder = Mod(mag, multiple);
+    if (remainder >= multiple / 2) 
+        return (FloorToInt<T>(mag / multiple) * multiple + multiple)*Sign(x);
+    else
+        return (FloorToInt<T>(mag / multiple) * multiple)*Sign(x);
+}
+
 /// Round value up.
 template <class T> inline T Ceil(T x) { return ceil(x); }
 

+ 10 - 4
android/launcher-app/build.gradle.kts

@@ -20,6 +20,8 @@
 // THE SOFTWARE.
 //
 
+import java.time.Duration
+
 plugins {
     id("com.android.application")
     kotlin("android")
@@ -54,7 +56,7 @@ android {
                     addAll(listOf(
                             "URHO3D_PLAYER",
                             "URHO3D_SAMPLES")
-                            .map { "-D$it=${if (project.hasProperty(it)) project.property(it) else "1"}" }
+                            .map { "-D$it=${project.findProperty(it) ?: "1"}" }
                     )
                 }
             }
@@ -63,13 +65,13 @@ android {
             abi {
                 isEnable = project.hasProperty("ANDROID_ABI")
                 reset()
-                include(*(if (isEnable) project.property("ANDROID_ABI") as String else "")
+                include(*(project.findProperty("ANDROID_ABI") as String? ?: "")
                         .split(',').toTypedArray())
             }
         }
     }
     buildTypes {
-        getByName("release") {
+        named("release") {
             isMinifyEnabled = false
             proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
         }
@@ -96,7 +98,7 @@ evaluationDependsOn(":android:urho3d-lib")
 
 afterEvaluate {
     tasks {
-        getByName("clean") {
+        "clean" {
             doLast {
                 android.externalNativeBuild.cmake.path?.touch()
             }
@@ -107,6 +109,10 @@ afterEvaluate {
         tasks {
             "externalNativeBuild$config" {
                 mustRunAfter(":android:urho3d-lib:externalNativeBuild$config")
+                if (System.getenv("CI") != null) {
+                    @Suppress("UnstableApiUsage")
+                    timeout.set(Duration.ofMinutes(15))
+                }
             }
         }
     }

+ 92 - 23
android/urho3d-lib/build.gradle.kts

@@ -22,9 +22,11 @@
 
 import org.gradle.internal.io.NullOutputStream
 import org.gradle.internal.os.OperatingSystem
+import java.time.Duration
 
 plugins {
     id("com.android.library")
+    id("com.jfrog.bintray")
     kotlin("android")
     kotlin("android.extensions")
     `maven-publish`
@@ -78,14 +80,13 @@ android {
             abi {
                 isEnable = project.hasProperty("ANDROID_ABI")
                 reset()
-                include(*(if (isEnable) project.property("ANDROID_ABI") as String else "")
-                        .split(',')
-                        .toTypedArray())
+                include(*(project.findProperty("ANDROID_ABI") as String? ?: "")
+                        .split(',').toTypedArray())
             }
         }
     }
     buildTypes {
-        getByName("release") {
+        named("release") {
             isMinifyEnabled = false
             proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
         }
@@ -94,6 +95,9 @@ android {
         cmake {
             setVersion(cmakeVersion)
             setPath(project.file("../../CMakeLists.txt"))
+
+            // Make it explicit as one of the task needs to know the exact path and derived from it
+            setBuildStagingDirectory(".cxx")
         }
     }
 }
@@ -113,7 +117,7 @@ afterEvaluate {
     // When the buildDir is cleaned then we need a way to re-configure that part back
     // It is achieved by ensuring that CMake configuration phase is rerun
     tasks {
-        getByName("clean") {
+        "clean" {
             doLast {
                 android.externalNativeBuild.cmake.path?.touch()
             }
@@ -124,13 +128,13 @@ afterEvaluate {
     android.buildTypes.forEach { buildType ->
         val config = buildType.name.capitalize()
         tasks {
-            create<Zip>("zipBuildTree$config") {
+            register<Zip>("zipBuildTree$config") {
                 archiveClassifier.set(buildType.name)
                 archiveExtension.set("aar")
                 dependsOn("zipBuildTreeConfigurer$config", "bundle${config}Aar")
                 from(zipTree(getByName("bundle${config}Aar").outputs.files.first()))
             }
-            create("zipBuildTreeConfigurer$config") {
+            register<Task>("zipBuildTreeConfigurer$config") {
                 val externalNativeBuildDir = File(buildDir, "tree/$config")
                 doLast {
                     val zipTask = getByName<Zip>("zipBuildTree$config")
@@ -146,16 +150,22 @@ afterEvaluate {
                     }
                 }
             }
+            if (System.getenv("CI") != null) {
+                "externalNativeBuild$config" {
+                    @Suppress("UnstableApiUsage")
+                    timeout.set(Duration.ofMinutes(25))
+                }
+            }
         }
     }
 }
 
 tasks {
-    create<Jar>("sourcesJar") {
+    register<Jar>("sourcesJar") {
         archiveClassifier.set("sources")
         from(android.sourceSets.getByName("main").java.srcDirs)
     }
-    create<Exec>("makeDoc") {
+    register<Exec>("makeDoc") {
         // Ignore the exit status on Windows host system because Doxygen may not return exit status correctly on Windows
         isIgnoreExitValue = OperatingSystem.current().isWindows
         standardOutput = NullOutputStream.INSTANCE
@@ -163,19 +173,19 @@ tasks {
         dependsOn("makeDocConfigurer")
         mustRunAfter("zipBuildTreeRelease")
     }
-    create<Zip>("documentationZip") {
+    register<Zip>("documentationZip") {
         archiveClassifier.set("documentation")
         dependsOn("makeDoc")
     }
-    create("makeDocConfigurer") {
+    register<Task>("makeDocConfigurer") {
         doLast {
-            val buildTree = File(cmakeStagingDir(), "cmake/release/$docABI")
-            getByName<Exec>("makeDoc") {
+            val buildTree = File(android.externalNativeBuild.cmake.buildStagingDirectory, "cmake/release/$docABI")
+            named<Exec>("makeDoc") {
                 // This is a hack - expect the first line to contain the path to the embedded CMake executable
-                executable = File(buildTree, "cmake_build_command.txt").readLines().first().split(":").last().trim()
+                executable = File(buildTree, "build_command.txt").readLines().first().split(":").last().trim()
                 workingDir = buildTree
             }
-            getByName<Zip>("documentationZip") {
+            named<Zip>("documentationZip") {
                 from(File(buildTree, "Docs/html")) {
                     into("docs")
                 }
@@ -185,21 +195,80 @@ tasks {
 }
 
 publishing {
-    (publications) {
-        create<MavenPublication>("mavenAndroid") {
+    publications {
+        register<MavenPublication>("mavenAndroid") {
             artifactId = "${project.name}-${project.libraryType}"
+            if (project.hasProperty("ANDROID_ABI")) {
+                artifactId = "$artifactId-${(project.property("ANDROID_ABI") as String).replace(',', '-')}"
+            }
             afterEvaluate {
-                android.buildTypes.forEach {
-                    artifact(tasks.getByName("zipBuildTree${it.name.capitalize()}"))
+                // Exclude publishing STATIC-debug AAR because its size exceeds 250MB limit allowed by Bintray
+                android.buildTypes
+                        .map { it.name }
+                        .filter { System.getenv("CI") == null || project.libraryType == "SHARED" || it == "release" }
+                        .forEach { artifact(tasks["zipBuildTree${it.capitalize()}"]) }
+            }
+            artifact(tasks["sourcesJar"])
+            artifact(tasks["documentationZip"])
+            pom {
+                @Suppress("UnstableApiUsage")
+                inceptionYear.set("2008")
+                @Suppress("UnstableApiUsage")
+                licenses {
+                    license {
+                        name.set("MIT License")
+                        url.set("https://github.com/urho3d/Urho3D/blob/master/LICENSE")
+                    }
+                }
+                @Suppress("UnstableApiUsage")
+                developers {
+                    developer {
+                        name.set("Urho3D contributors")
+                        url.set("https://github.com/urho3d/Urho3D/graphs/contributors")
+                    }
+                }
+                @Suppress("UnstableApiUsage")
+                scm {
+                    url.set("https://github.com/urho3d/Urho3D.git")
+                    connection.set("scm:git:ssh://[email protected]:urho3d/Urho3D.git")
+                    developerConnection.set("scm:git:ssh://[email protected]:urho3d/Urho3D.git")
+                }
+                withXml {
+                    asNode().apply {
+                        appendNode("name", "Urho3D")
+                        appendNode("description", project.description)
+                        appendNode("url", "https://urho3d.github.io/")
+                    }
                 }
             }
-            artifact(tasks.getByName("sourcesJar"))
-            artifact(tasks.getByName("documentationZip"))
         }
     }
 }
 
-fun cmakeStagingDir() = android.externalNativeBuild.cmake.buildStagingDirectory ?: project.file(".cxx")
+bintray {
+    user = System.getenv("BINTRAY_USER")
+    key = System.getenv("BINTRAY_KEY")
+    publish = true
+    override = true
+    setPublications("mavenAndroid")
+    pkg.apply {
+        repo = "maven"
+        name = project.name
+        setLicenses("MIT")
+        vcsUrl = "https://github.com/urho3d/Urho3D.git"
+        userOrg = "urho3d"
+        setLabels("android", "game-development", "game-engine", "open-source", "urho3d")
+        websiteUrl = "https://urho3d.github.io/"
+        issueTrackerUrl = "https://github.com/urho3d/Urho3D/issues"
+        githubRepo = "urho3d/Urho3D"
+        publicDownloadNumbers = true
+        desc = project.description
+        version.apply {
+            name = project.version.toString()
+            desc = "Continuous delivery from Travis-CI."
+        }
+    }
+}
 
 val Project.libraryType: String
-    get() = if (hasProperty("URHO3D_LIB_TYPE")) property("URHO3D_LIB_TYPE") as String else "STATIC"
+    get() = findProperty("URHO3D_LIB_TYPE") as String? ?: "STATIC"

+ 2 - 1
bin/Data/Scripts/Editor/AttributeEditor.as

@@ -1200,7 +1200,8 @@ ResourcePicker@ GetResourcePicker(StringHash resourceType)
 {
     for (uint i = 0; i < resourcePickers.length; ++i)
     {
-        if (resourcePickers[i].type == resourceType)
+        // TODO: refactor to use dictionary instead
+        if (resourceType == resourcePickers[i].type)
             return resourcePickers[i];
     }
     return null;

+ 2 - 1
bin/Data/Scripts/Editor/EditorView.as

@@ -318,7 +318,8 @@ class ViewportContext
         cameraRotZ.text = String(Floor(cameraNode.rotation.roll * 1000) / 1000);
         cameraZoom.text = String(Floor(camera.zoom * 1000) / 1000);
         cameraOrthoSize.text = String(Floor(camera.orthoSize * 1000) / 1000);
-        cameraOrthographic.checked = camera.orthographic;
+        // FIXME: this line below appears to be not only redundant but may cause infinite loop as well on Clang build
+        // cameraOrthographic.checked = camera.orthographic;
     }
 
     void HandleOrthographicToggled(StringHash eventType, VariantMap& eventData)

+ 60 - 1
build.gradle.kts

@@ -20,15 +20,74 @@
 // THE SOFTWARE.
 //
 
+import org.gradle.internal.io.NullOutputStream
+import java.io.ByteArrayOutputStream
+
 plugins {
     base
+    // For some reasons the lint task requires bintray plugin to be declared here too in order to work as expected
+    id("com.jfrog.bintray") apply false
 }
 
 allprojects {
     group = "com.github.urho3d"
-    version = "1.8-SNAPSHOT"
+    version = determineVersion()
+    description = """Urho3D is a free lightweight,
+                    |cross-platform 2D and 3D game engine implemented in C++ and released under the MIT license.
+                    |Greatly inspired by OGRE and Horde3D.""".trimMargin().replace('\n', ' ')
     repositories {
         google()
         jcenter()
     }
 }
+
+/**
+ * Find the most recent tag that is reachable from a commit and use that to set the Gradle's project version.
+ *
+ * e.g. commit described as "1.7-664-g34b1" will be mapped to "1.8-BETA" (rolling release for the next version)
+ *      tag "1.8" will be mapped to "1.8" as is (point release version), so does tag "1.8-RC" (release candidate)
+ */
+fun determineVersion(): String {
+    // If it is explicitly specified then let return it instead
+    System.getenv("GRADLE_PROJECT_VERSION")?.let { return it }
+    // If it is on CI server then unshallow the clone's repo when necessary
+    if (System.getenv("CI") != null && System.getenv("RELEASE_TAG") == null) unshallowClone()
+    val desc = describeCommit(System.getenv("TRAVIS_COMMIT") ?: System.getenv("APPVEYOR_REPO_COMMIT"))
+    return Regex("^(.+?)-\\d").find(desc)?.destructured?.component1()?.let { "${bumpSemVer(it, 1)}-BETA" } ?: desc
+}
+
+/**
+ * Unshallow the clone's repository and fetch all the tags.
+ */
+fun unshallowClone() = exec {
+    commandLine = listOf("git", "fetch", "--tags", "--unshallow")
+    standardOutput = NullOutputStream.INSTANCE
+    errorOutput = NullOutputStream.INSTANCE
+    isIgnoreExitValue = true
+}
+
+/**
+ * Find the most recent tag that is reachable from a commit.
+ */
+fun describeCommit(sha: String? = null) = ByteArrayOutputStream().also {
+    exec {
+        commandLine = listOf("git", "describe", "--tags", sha ?: "--dirty")
+        standardOutput = it
+        errorOutput = NullOutputStream.INSTANCE
+        isIgnoreExitValue = true    // In case no GIT command line tool or not a GIT repository
+    }
+}.toString().trim().let { if (it.isBlank()) "Unversioned" else it }
+
+/**
+ * Bump the semantic versioning on the specified index, 0 for major version, 1 for minor version, and so on.
+ */
+fun bumpSemVer(version: String, index: Int) = version
+        .split('.')
+        .mapIndexed { i: Int, s: String ->
+            when {
+                i < index -> s
+                i == index -> (s.toInt() + 1).toString()
+                else -> "0"
+            }
+        }
+        .joinToString(".")

+ 6 - 3
buildSrc/src/main/kotlin/UrhoCommon.kt

@@ -20,16 +20,19 @@
 // THE SOFTWARE.
 //
 
+import org.gradle.kotlin.dsl.embeddedKotlinVersion
 import org.gradle.plugin.use.PluginDependenciesSpec
 import org.gradle.plugin.use.PluginDependencySpec
 import java.io.File
 
+val kotlinVersion = embeddedKotlinVersion
+
+const val androidToolsVersion = "3.5.0-alpha13"
+const val bintrayVersion = "1.8.4"
 const val cmakeVersion = "3.10.2"
-const val androidToolsVersion = "3.5.0-alpha10"
-const val kotlinVersion = "1.3.20"
 const val junitVersion = "4.12"
-const val testRunnerVersion = "1.0.2"
 const val testEspressoVersion = "3.0.2"
+const val testRunnerVersion = "1.0.2"
 
 /**
  * Apply Urho3D custom plugin for the given platform.

BIN
gradle/wrapper/gradle-wrapper.jar


+ 1 - 1
gradle/wrapper/gradle-wrapper.properties

@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists

+ 17 - 1
gradlew

@@ -1,5 +1,21 @@
 #!/usr/bin/env sh
 
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 ##############################################################################
 ##
 ##  Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
 APP_BASE_NAME=`basename "$0"`
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
 MAX_FD="maximum"

+ 17 - 1
gradlew.bat

@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
 @if "%DEBUG%" == "" @echo off
 @rem ##########################################################################
 @rem
@@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
 
 @rem Find java.exe
 if defined JAVA_HOME goto findJavaFromJavaHome

+ 4 - 0
script/.env-file

@@ -1,4 +1,5 @@
 ANDROID
+ANDROID_CCACHE
 APPLETVOS_DEPLOYMENT_TARGET
 APPVEYOR
 APPVEYOR_REPO_BRANCH
@@ -10,6 +11,9 @@ ARM_ABI_FLAGS
 ARM_PREFIX
 ARM_SYSROOT
 baseline
+BINTRAY_KEY
+bintrayUpload
+BINTRAY_USER
 build_tree
 CC
 ccache

+ 3 - 0
settings.gradle.kts

@@ -28,10 +28,13 @@ pluginManagement {
                     useModule("com.android.tools.build:gradle:$androidToolsVersion")
                 requested.id.id.startsWith("org.jetbrains.kotlin.") ->
                     useVersion(kotlinVersion)
+                requested.id.id == "com.jfrog.bintray" ->
+                    useVersion(bintrayVersion)
             }
         }
     }
     repositories {
+        @Suppress("UnstableApiUsage")
         gradlePluginPortal()
         google()
         jcenter()