diff --git a/CMakeLists.txt b/CMakeLists.txt
index c13ba7110..cb5caa1ad 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,15 +11,8 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
include(CMakeDependentOption)
-set(DEPENDENCIES "dependencies")
-# In case of 64-bit windows, use a different path for dependencies
-# so that both dependencies can be installed next to each other
-if ( WIN32 AND (CMAKE_SIZEOF_VOID_P EQUAL 8 ) )
- set(DEPENDENCIES "dependencies-64bit")
-endif()
-
include(BuildTypeSTKRelease)
-if (NOT CMAKE_BUILD_TYPE)
+if(NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to STKRelease")
set(CMAKE_BUILD_TYPE "STKRelease")
endif()
@@ -28,12 +21,13 @@ option(SERVER_ONLY "Create a server only (i.e. no graphics or sound)" OFF)
option(USE_FRIBIDI "Support for right-to-left languages" ON)
option(CHECK_ASSETS "Check if assets are installed in ../stk-assets" ON)
option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angelscript. If you enable this option, make sure to use a compatible version." OFF)
+option(USE_SYSTEM_ENET "Use system ENET instead of the built-in version, when available." ON)
option(USE_SYSTEM_GLEW "Use system GLEW instead of the built-in version, when available." ON)
CMAKE_DEPENDENT_OPTION(BUILD_RECORDER "Build opengl recorder" ON
"NOT SERVER_ONLY;NOT USE_GLES2;NOT APPLE" OFF)
-if ((UNIX AND NOT APPLE) AND NOT SERVER_ONLY)
+if((UNIX AND NOT APPLE) AND NOT SERVER_ONLY)
option(ENABLE_WAYLAND_DEVICE "Enable Wayland device for linux build" ON)
option(USE_GLES2 "Use OpenGL ES2 renderer" OFF)
endif()
@@ -73,6 +67,32 @@ set(STK_INSTALL_BINARY_DIR "bin" CACHE
set(STK_INSTALL_DATA_DIR "share/supertuxkart" CACHE
STRING "Install data folder to this directory, absolute or relative to CMAKE_INSTALL_PREFIX")
+# Define dependencies path
+if(MSVC)
+ set(DEPENDENCIES "dependencies-vs")
+elseif(MINGW)
+ set(DEPENDENCIES "dependencies-mingw")
+else()
+ set(DEPENDENCIES "dependencies")
+endif()
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(DEPENDENCIES "${DEPENDENCIES}-64bit")
+endif()
+
+if(WIN32)
+ if(NOT IS_DIRECTORY "${PROJECT_SOURCE_DIR}/${DEPENDENCIES}")
+ set(DEPENDENCIES "dependencies")
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(DEPENDENCIES "${DEPENDENCIES}-64bit")
+ endif()
+ endif()
+
+ if(NOT IS_DIRECTORY "${PROJECT_SOURCE_DIR}/${DEPENDENCIES}")
+ message(FATAL_ERROR "Dependencies directory not found.")
+ endif()
+endif()
+
# These variables enable MSVC to find libraries located in "dependencies"
if(WIN32)
set(ENV{PATH} "$ENV{PATH};${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/include")
@@ -107,14 +127,24 @@ endif()
add_subdirectory("${PROJECT_SOURCE_DIR}/lib/bullet")
include_directories("${PROJECT_SOURCE_DIR}/lib/bullet/src")
-# Build the ENet UDP network library
-add_subdirectory("${PROJECT_SOURCE_DIR}/lib/enet")
-include_directories("${PROJECT_SOURCE_DIR}/lib/enet/include")
+# Find system ENet library or build it if missing
+if((UNIX AND NOT APPLE) AND USE_SYSTEM_ENET)
+ find_package(ENet)
+endif()
+
+if(ENET_FOUND)
+ include_directories(${ENet_INCLUDE_DIRS})
+else()
+ # Fallback to built-in version
+ add_subdirectory("${PROJECT_SOURCE_DIR}/lib/enet")
+ include_directories("${PROJECT_SOURCE_DIR}/lib/enet/include")
+ set(ENet_LIBRARIES "enet")
+endif()
# Find system GLEW library or build it if missing
if(NOT USE_GLES2 AND NOT SERVER_ONLY)
add_definitions(-DGLEW_NO_GLU)
- if(USE_SYSTEM_GLEW)
+ if((UNIX AND NOT APPLE) AND USE_SYSTEM_GLEW)
find_package(PkgConfig)
if(PKGCONFIG_FOUND)
pkg_check_modules(GLEW glew>=2.1)
@@ -434,7 +464,7 @@ target_link_libraries(supertuxkart
bulletdynamics
bulletcollision
bulletmath
- enet
+ ${ENet_LIBRARIES}
stkirrlicht
${Angelscript_LIBRARIES}
${CURL_LIBRARIES}
@@ -575,7 +605,7 @@ install(FILES ${STK_DATA_DIR}/supertuxkart.desktop DESTINATION share/application
install(FILES data/supertuxkart_48.png DESTINATION share/icons/hicolor/48x48/apps RENAME supertuxkart.png)
install(FILES data/supertuxkart_128.png DESTINATION share/icons/hicolor/128x128/apps RENAME supertuxkart.png)
install(FILES data/supertuxkart_48.png DESTINATION share/pixmaps RENAME supertuxkart.png)
-install(FILES data/supertuxkart.appdata.xml DESTINATION share/appdata)
+install(FILES data/supertuxkart.appdata.xml DESTINATION share/metainfo)
if(MINGW)
install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/ DESTINATION ${STK_INSTALL_BINARY_DIR}
diff --git a/README.md b/README.md
index 6e28c7bb4..972109cc0 100644
--- a/README.md
+++ b/README.md
@@ -108,10 +108,10 @@ To Build SuperTuxKart on Windows, follow these instructions:
1. Download and install Visual Studio from here: [Visual Studio - Download](https://www.visualstudio.com/downloads/). The free Visual Studio Community edition works fine.
2. Download the SuperTuxKart source package from either [SuperTuxKart download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart/0.9.2) or [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), and unpack it.
*Note: If you downloaded the source package from here: [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), then both `stk-code` and `stk-assets` **must** be in the same directory, otherwise the build can result in failure*
-3. Download the Windows dependencies package from either [SuperTuxKart download area: Dependecies - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/Windows/)
+3. Download the Windows dependencies package from either [SuperTuxKart download area: Dependencies - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/Windows/)
or [SuperTuxKart on GitHub - Dependencies](https://github.com/supertuxkart/dependencies), and unpack it; then, copy the `dependencies` directory from either the `windows` or the `windows_64bit` directories into the `stk-code` directory, rename it to `dependencies-64bit` if you want to compile a 64bit build.
4. Download CMake from here: [CMake - download page](https://cmake.org/download/), install it; once CMake is installed, double click on the CMake icon on your desktop, and point it towards your `stk-code` directory in the 'Where is the source code' field, and point it to a directory called `build` or `bld` inside the stk-code directory.
-5. Press 'Configure'; CMake will ask you if it is OK to create the aformentioned directory, press `Yes`. CMake will then ask you about your version of Visual Studio.
+5. Press 'Configure'; CMake will ask you if it is OK to create the aforementioned directory, press `Yes`. CMake will then ask you about your version of Visual Studio.
Confirm your selection; *Please look at the table below to avoid confusion between version numbers and releases of Visual Studio*;
CMake will begin creating the required files for the build in the directory.
6. Navigate to your build directory and open the `SuperTuxKart.sln` file; Visual Studio will now load the solution.
diff --git a/android/Android.mk b/android/Android.mk
index 08728da5f..947ca5490 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -162,6 +162,8 @@ LOCAL_CFLAGS := -I../lib/angelscript/include \
-DUSE_GLES2 \
-DHAVE_OGGVORBIS \
-DNDEBUG \
+ -DANDROID_PACKAGE_NAME=\"$(PACKAGE_NAME)\" \
+ -DANDROID_APP_DIR_NAME=\"$(APP_DIR_NAME)\" \
-std=gnu++0x
LOCAL_STATIC_LIBRARIES := irrlicht bullet enet freetype ifaddrs angelscript \
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 5b815379c..71e797ef7 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -8,6 +8,7 @@
@@ -24,12 +25,16 @@
+
+
+
+
diff --git a/android/banner.png b/android/banner.png
new file mode 100644
index 000000000..9d05b0c0d
Binary files /dev/null and b/android/banner.png differ
diff --git a/android/build.gradle b/android/build.gradle
index 4fae7a216..19fda57b1 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -15,7 +15,7 @@ apply plugin: 'com.android.application'
android
{
- compileSdkVersion sdk_version.toInteger()
+ compileSdkVersion compile_sdk_version.toInteger()
buildToolsVersion build_tools_ver
sourceSets
diff --git a/android/make.sh b/android/make.sh
index 7fac9f3c6..3b2732aa9 100755
--- a/android/make.sh
+++ b/android/make.sh
@@ -22,25 +22,39 @@ export NDK_ABI_ARMV7=armeabi-v7a
export ARCH_ARMV7=arm
export HOST_ARMV7=arm-linux-androideabi
export NDK_PLATFORM_ARMV7=android-19
-export SDK_VERSION_ARMV7=19
+export MIN_SDK_VERSION_ARMV7=19
+export TARGET_SDK_VERSION_ARMV7=21
+export COMPILE_SDK_VERSION_ARMV7=21
export NDK_ABI_X86=x86
export ARCH_X86=x86
export HOST_X86=i686-linux-android
export NDK_PLATFORM_X86=android-19
-export SDK_VERSION_X86=19
+export MIN_SDK_VERSION_X86=19
+export TARGET_SDK_VERSION_X86=21
+export COMPILE_SDK_VERSION_X86=21
export NDK_ABI_AARCH64=arm64-v8a
export ARCH_AARCH64=arm64
export HOST_AARCH64=aarch64-linux-android
export NDK_PLATFORM_AARCH64=android-21
-export SDK_VERSION_AARCH64=21
+export MIN_SDK_VERSION_AARCH64=21
+export TARGET_SDK_VERSION_AARCH64=21
+export COMPILE_SDK_VERSION_AARCH64=21
export APP_NAME_RELEASE="SuperTuxKart"
-export APP_NAME_DEBUG="SuperTuxKart Debug"
export PACKAGE_NAME_RELEASE="org.supertuxkart.stk"
-export PACKAGE_NAME_DEBUG="org.supertuxkart.stk_dev"
+export APP_DIR_NAME_RELEASE="supertuxkart"
export APP_ICON_RELEASE="$DIRNAME/icon.png"
+
+export APP_NAME_BETA="SuperTuxKart Beta"
+export PACKAGE_NAME_BETA="org.supertuxkart.stk_beta"
+export APP_DIR_NAME_BETA="supertuxkart-beta"
+export APP_ICON_BETA="$DIRNAME/icon-dbg.png"
+
+export APP_NAME_DEBUG="SuperTuxKart Debug"
+export PACKAGE_NAME_DEBUG="org.supertuxkart.stk_dbg"
+export APP_DIR_NAME_DEBUG="supertuxkart-dbg"
export APP_ICON_DEBUG="$DIRNAME/icon-dbg.png"
@@ -88,19 +102,25 @@ if [ "$COMPILE_ARCH" = "armv7" ]; then
export NDK_ABI=$NDK_ABI_ARMV7
export ARCH=$ARCH_ARMV7
export HOST=$HOST_ARMV7
- export SDK_VERSION=$SDK_VERSION_ARMV7
+ export MIN_SDK_VERSION=$MIN_SDK_VERSION_ARMV7
+ export TARGET_SDK_VERSION=$TARGET_SDK_VERSION_ARMV7
+ export COMPILE_SDK_VERSION=$COMPILE_SDK_VERSION_ARMV7
elif [ "$COMPILE_ARCH" = "x86" ]; then
export NDK_PLATFORM=$NDK_PLATFORM_X86
export NDK_ABI=$NDK_ABI_X86
export ARCH=$ARCH_X86
export HOST=$HOST_X86
- export SDK_VERSION=$SDK_VERSION_X86
+ export MIN_SDK_VERSION=$MIN_SDK_VERSION_X86
+ export TARGET_SDK_VERSION=$TARGET_SDK_VERSION_X86
+ export COMPILE_SDK_VERSION=$COMPILE_SDK_VERSION_X86
elif [ "$COMPILE_ARCH" = "aarch64" ]; then
export NDK_PLATFORM=$NDK_PLATFORM_AARCH64
export NDK_ABI=$NDK_ABI_AARCH64
export ARCH=$ARCH_AARCH64
export HOST=$HOST_AARCH64
- export SDK_VERSION=$SDK_VERSION_AARCH64
+ export MIN_SDK_VERSION=$MIN_SDK_VERSION_AARCH64
+ export TARGET_SDK_VERSION=$TARGET_SDK_VERSION_AARCH64
+ export COMPILE_SDK_VERSION=$COMPILE_SDK_VERSION_AARCH64
else
echo "Unknow COMPILE_ARCH: $COMPILE_ARCH. Possible values are: " \
"armv7, aarch64, x86"
@@ -118,6 +138,7 @@ if [ "$BUILD_TYPE" = "debug" ] || [ "$BUILD_TYPE" = "Debug" ]; then
export IS_DEBUG_BUILD=1
export APP_NAME="$APP_NAME_DEBUG"
export PACKAGE_NAME="$PACKAGE_NAME_DEBUG"
+ export APP_DIR_NAME="$APP_DIR_NAME_DEBUG"
export APP_ICON="$APP_ICON_DEBUG"
elif [ "$BUILD_TYPE" = "release" ] || [ "$BUILD_TYPE" = "Release" ]; then
export ANT_BUILD_TYPE="release"
@@ -125,7 +146,16 @@ elif [ "$BUILD_TYPE" = "release" ] || [ "$BUILD_TYPE" = "Release" ]; then
export IS_DEBUG_BUILD=0
export APP_NAME="$APP_NAME_RELEASE"
export PACKAGE_NAME="$PACKAGE_NAME_RELEASE"
+ export APP_DIR_NAME="$APP_DIR_NAME_RELEASE"
export APP_ICON="$APP_ICON_RELEASE"
+elif [ "$BUILD_TYPE" = "beta" ] || [ "$BUILD_TYPE" = "Beta" ]; then
+ export ANT_BUILD_TYPE="release"
+ export GRADLE_BUILD_TYPE="assembleRelease"
+ export IS_DEBUG_BUILD=0
+ export APP_NAME="$APP_NAME_BETA"
+ export PACKAGE_NAME="$PACKAGE_NAME_BETA"
+ export APP_DIR_NAME="$APP_DIR_NAME_BETA"
+ export APP_ICON="$APP_ICON_BETA"
else
echo "Unsupported BUILD_TYPE: $BUILD_TYPE. Possible values are: " \
"debug, release"
@@ -370,12 +400,16 @@ echo "" >> "$STRINGS_FILE"
echo " $APP_NAME" >> "$STRINGS_FILE"
echo "" >> "$STRINGS_FILE"
-sed -i "s/minSdkVersion=\".*\"/minSdkVersion=\"$SDK_VERSION\"/g" \
+sed -i "s/minSdkVersion=\".*\"/minSdkVersion=\"$MIN_SDK_VERSION\"/g" \
+ "$DIRNAME/AndroidManifest.xml"
+
+sed -i "s/targetSdkVersion=\".*\"/targetSdkVersion=\"$TARGET_SDK_VERSION\"/g" \
"$DIRNAME/AndroidManifest.xml"
sed -i "s/package=\".*\"/package=\"$PACKAGE_NAME\"/g" \
"$DIRNAME/AndroidManifest.xml"
+cp "banner.png" "$DIRNAME/res/drawable/banner.png"
cp "$APP_ICON" "$DIRNAME/res/drawable/icon.png"
convert -scale 72x72 "$APP_ICON" "$DIRNAME/res/drawable-hdpi/icon.png"
convert -scale 48x48 "$APP_ICON" "$DIRNAME/res/drawable-mdpi/icon.png"
@@ -385,12 +419,12 @@ convert -scale 144x144 "$APP_ICON" "$DIRNAME/res/drawable-xxhdpi/icon.png"
if [ "$BUILD_TOOL" = "gradle" ]; then
export ANDROID_HOME="$SDK_PATH"
- gradle -Psdk_version=$SDK_VERSION \
- -Pbuild_tools_ver="$BUILD_TOOLS_VER" \
+ gradle -Pcompile_sdk_version=$COMPILE_SDK_VERSION \
+ -Pbuild_tools_ver="$BUILD_TOOLS_VER" \
$GRADLE_BUILD_TYPE
elif [ "$BUILD_TOOL" = "ant" ]; then
ant -Dsdk.dir="$SDK_PATH" \
- -Dtarget=$NDK_PLATFORM \
+ -Dtarget="android-$TARGET_SDK_VERSION" \
$ANT_BUILD_TYPE
fi
diff --git a/cmake/FindENet.cmake b/cmake/FindENet.cmake
new file mode 100644
index 000000000..91c252713
--- /dev/null
+++ b/cmake/FindENet.cmake
@@ -0,0 +1,48 @@
+# - Try to find enet
+# Once done this will define
+#
+# ENET_FOUND - system has enet
+# ENet_INCLUDE_DIRS - the enet include directory
+# ENet_LIBRARIES - the libraries needed to use enet
+#
+# $ENETDIR is an environment variable used for finding enet.
+#
+# Borrowed from The Mana World
+# http://themanaworld.org/
+#
+# Several changes and additions by Fabian 'x3n' Landau
+# Lots of simplifications by Adrian Friedli
+# > www.orxonox.net <
+
+FIND_PATH(ENet_INCLUDE_DIRS enet/enet.h
+ PATHS
+ $ENV{ENETDIR}
+ /usr/local
+ /usr
+ PATH_SUFFIXES include
+ )
+
+FIND_LIBRARY(ENet_LIBRARY
+ NAMES enet
+ PATHS
+ $ENV{ENETDIR}
+ /usr/local
+ /usr
+ PATH_SUFFIXES lib
+ )
+
+# handle the QUIETLY and REQUIRED arguments and set ENET_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ENet DEFAULT_MSG ENet_LIBRARY ENet_INCLUDE_DIRS)
+
+IF (ENET_FOUND)
+ IF(WIN32)
+ SET(WINDOWS_ENET_DEPENDENCIES "ws2_32;winmm")
+ SET(ENet_LIBRARIES ${ENet_LIBRARY} ${WINDOWS_ENET_DEPENDENCIES})
+ ELSE(WIN32)
+ SET(ENet_LIBRARIES ${ENet_LIBRARY})
+ ENDIF(WIN32)
+ENDIF (ENET_FOUND)
+
+MARK_AS_ADVANCED(ENet_LIBRARY ENet_LIBRARIES ENet_INCLUDE_DIRS)
diff --git a/data/challenges/mansion.challenge b/data/challenges/mansion.challenge
index 662a15879..f3ecabb20 100644
--- a/data/challenges/mansion.challenge
+++ b/data/challenges/mansion.challenge
@@ -3,10 +3,9 @@
-
-
+
diff --git a/data/challenges/mines.challenge b/data/challenges/mines.challenge
index 9d577f030..00e78ee08 100644
--- a/data/challenges/mines.challenge
+++ b/data/challenges/mines.challenge
@@ -6,7 +6,7 @@
-
+
diff --git a/data/challenges/snowmountain.challenge b/data/challenges/snowmountain.challenge
index db4319738..0357581f4 100644
--- a/data/challenges/snowmountain.challenge
+++ b/data/challenges/snowmountain.challenge
@@ -3,10 +3,9 @@
-
-
+
diff --git a/data/gui/options_ui.stkgui b/data/gui/options_ui.stkgui
index 2c654be7b..737104b0d 100644
--- a/data/gui/options_ui.stkgui
+++ b/data/gui/options_ui.stkgui
@@ -72,8 +72,12 @@
-
-
+
+
+
+
+
+
diff --git a/data/shaders/combine_diffuse_color.frag b/data/shaders/combine_diffuse_color.frag
index df7f34e86..68191277e 100644
--- a/data/shaders/combine_diffuse_color.frag
+++ b/data/shaders/combine_diffuse_color.frag
@@ -4,6 +4,9 @@ uniform sampler2D ssao_tex;
uniform sampler2D gloss_map;
uniform sampler2D diffuse_color;
uniform sampler2D depth_stencil;
+uniform sampler2D light_scatter;
+
+uniform vec4 bg_color;
out vec4 o_final_color;
@@ -31,13 +34,28 @@ void main()
vec4 color_1 = vec4(tmp * ao + (emitMapValue * emitCol), diffuseMatColor.a);
// Fog
- float z = texture(depth_stencil, tc).x;
- vec4 xpos = getPosFromUVDepth(vec3(tc, z), u_inverse_projection_matrix);
+ float depth = texture(depth_stencil, tc).x;
+ vec4 xpos = getPosFromUVDepth(vec3(tc, depth), u_inverse_projection_matrix);
float dist = length(xpos.xyz);
// fog density
float factor = (1.0 - exp(u_fog_data.w * dist));
vec3 fog = u_fog_color.xyz * factor;
// Additively blend the color by fog
- o_final_color = color_1 + vec4(fog, factor);
+ color_1 = color_1 + vec4(fog, factor);
+
+ // For skybox blending later
+ if (depth == 1.0)
+ {
+ color_1 = bg_color;
+ }
+
+ // Light scatter (alpha blend function: (GL_ONE, GL_ONE_MINUS_SRC_ALPHA))
+ vec4 ls = texture(light_scatter, tc);
+ vec4 color_2;
+ color_2.r = ls.r + color_1.r * (1.0 - ls.a);
+ color_2.g = ls.g + color_1.g * (1.0 - ls.a);
+ color_2.b = ls.b + color_1.b * (1.0 - ls.a);
+ color_2.a = ls.a + color_1.a * (1.0 - ls.a);
+ o_final_color = color_2;
}
diff --git a/data/shaders/simple_particle.frag b/data/shaders/simple_particle.frag
index 144f42dac..ad12bfc3f 100644
--- a/data/shaders/simple_particle.frag
+++ b/data/shaders/simple_particle.frag
@@ -1,21 +1,25 @@
uniform sampler2D tex;
uniform sampler2D dtex;
+uniform float billboard;
in vec2 tc;
in vec4 pc;
-flat in float billboard_mix;
out vec4 FragColor;
#stk_include "utils/getPosFromUVDepth.frag"
void main(void)
{
+ float billboard_alpha = mix(1.0, texture(tex, tc).a, billboard);
+#if defined(Advanced_Lighting_Enabled)
vec2 xy = gl_FragCoord.xy / u_screen;
float FragZ = gl_FragCoord.z;
vec4 FragmentPos = getPosFromUVDepth(vec3(xy, FragZ), u_inverse_projection_matrix);
float EnvZ = texture(dtex, xy).x;
vec4 EnvPos = getPosFromUVDepth(vec3(xy, EnvZ), u_inverse_projection_matrix);
float alpha = clamp((EnvPos.z - FragmentPos.z) * 0.3, 0., 1.);
- float billboard_alpha = mix(1.0, texture(tex, tc).a, billboard_mix);
+#else
+ float alpha = 1.0;
+#endif
FragColor = texture(tex, tc) * billboard_alpha * pc * alpha;
}
diff --git a/data/shaders/simple_particle.vert b/data/shaders/simple_particle.vert
index 3abc9bbda..d1ab36e09 100644
--- a/data/shaders/simple_particle.vert
+++ b/data/shaders/simple_particle.vert
@@ -23,7 +23,6 @@ in vec2 quadcorner;
in float anglespeed;
#endif
-flat out float billboard_mix;
out vec2 tc;
out vec4 pc;
@@ -34,13 +33,11 @@ void main(void)
gl_Position = vec4(0.);
pc = vec4(0.0);
tc = vec2(0.0);
- billboard_mix = 0.0;
return;
}
float lifetime = color_lifetime.w;
float alpha = mix(smoothstep(1.0, 0.8, lifetime), lifetime, billboard);
- billboard_mix = billboard;
vec4 particle_color = vec4(color_lifetime.zyx, 1.0) * alpha;
tc = Texcoord;
diff --git a/data/shaders/sp_alpha_test.frag b/data/shaders/sp_alpha_test.frag
index 3f9e46f2a..f344c95c3 100644
--- a/data/shaders/sp_alpha_test.frag
+++ b/data/shaders/sp_alpha_test.frag
@@ -1,4 +1,4 @@
-flat in float hue_change;
+in float hue_change;
in vec4 color;
in vec3 normal;
@@ -28,9 +28,7 @@ void main(void)
vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z));
col = vec4(new_color.r, new_color.g, new_color.b, col.a);
}
-
- vec3 final_color = col.xyz * color.xyz;
- o_diffuse_color = vec4(final_color, 1.0);
+ o_diffuse_color = vec4(col.xyz, 1.0);
#if defined(Advanced_Lighting_Enabled)
vec4 layer_2 = sampleTextureLayer2(uv);
diff --git a/data/shaders/sp_ghost.frag b/data/shaders/sp_ghost.frag
index 0887e7a63..2211494b3 100644
--- a/data/shaders/sp_ghost.frag
+++ b/data/shaders/sp_ghost.frag
@@ -1,6 +1,6 @@
uniform float custom_alpha;
-flat in float hue_change;
+in float hue_change;
in vec2 uv;
in vec4 color;
diff --git a/data/shaders/sp_grass.frag b/data/shaders/sp_grass.frag
index 1c166c2f7..412e7a7a9 100644
--- a/data/shaders/sp_grass.frag
+++ b/data/shaders/sp_grass.frag
@@ -1,4 +1,4 @@
-flat in float hue_change;
+in float hue_change;
in vec3 normal;
in vec2 uv;
@@ -26,9 +26,7 @@ void main(void)
vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z));
col = vec4(new_color.r, new_color.g, new_color.b, col.a);
}
-
- vec3 final_color = col.xyz;
- o_diffuse_color = vec4(final_color, 1.0);
+ o_diffuse_color = vec4(col.xyz, 1.0);
#if defined(Advanced_Lighting_Enabled)
vec4 layer_2 = sampleTextureLayer2(uv);
diff --git a/data/shaders/sp_grass_pass.vert b/data/shaders/sp_grass_pass.vert
index 1164ae5f1..074754bea 100644
--- a/data/shaders/sp_grass_pass.vert
+++ b/data/shaders/sp_grass_pass.vert
@@ -25,7 +25,7 @@ layout(location = 12) in ivec2 i_misc_data;
out vec3 normal;
out vec2 uv;
-flat out float hue_change;
+out float hue_change;
void main()
{
diff --git a/data/shaders/sp_normal_map.frag b/data/shaders/sp_normal_map.frag
index 2fee160a5..c98497748 100644
--- a/data/shaders/sp_normal_map.frag
+++ b/data/shaders/sp_normal_map.frag
@@ -1,9 +1,6 @@
-flat in float hue_change;
+in float hue_change;
in vec4 color;
-in vec3 tangent;
-in vec3 bitangent;
-in vec3 normal;
in vec2 uv;
layout(location = 0) out vec4 o_diffuse_color;
@@ -13,6 +10,7 @@ layout(location = 2) out vec2 o_gloss_map;
#stk_include "utils/encode_normal.frag"
#stk_include "utils/rgb_conversion.frag"
#stk_include "utils/sp_texture_sampling.frag"
+#stk_include "utils/sp_normalMapOutput.frag"
void main()
{
@@ -39,16 +37,7 @@ void main()
#if defined(Advanced_Lighting_Enabled)
vec4 layer_3 = sampleTextureLayer3(uv);
- vec3 tangent_space_normal = 2.0 * layer_3.xyz - 1.0;
- vec3 frag_tangent = normalize(tangent);
- vec3 frag_bitangent = normalize(bitangent);
- vec3 frag_normal = normalize(normal);
- mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal);
- vec3 world_normal = t_b_n * tangent_space_normal;
-
vec4 layer_2 = sampleTextureLayer2(uv);
- o_normal_depth.xy = 0.5 * EncodeNormal(normalize(world_normal)) + 0.5;
- o_normal_depth.z = layer_2.x;
- o_gloss_map = layer_2.yz;
+ outputNormalMapPbrData(layer_3.rgb, layer_2.rgb);
#endif
}
diff --git a/data/shaders/sp_normal_visualizer.geom b/data/shaders/sp_normal_visualizer.geom
index c5693d192..9d2d58322 100644
--- a/data/shaders/sp_normal_visualizer.geom
+++ b/data/shaders/sp_normal_visualizer.geom
@@ -1,3 +1,9 @@
+uniform int enable_normals;
+uniform int enable_tangents;
+uniform int enable_bitangents;
+uniform int enable_wireframe;
+uniform int enable_triangle_normals;
+
layout(triangles) in;
layout(line_strip, max_vertices = 24) out;
@@ -9,6 +15,13 @@ flat out vec4 o_color;
void main()
{
+ if (enable_normals == 0 && enable_tangents == 0 &&
+ enable_bitangents == 0 && enable_wireframe == 0 &&
+ enable_triangle_normals == 0)
+ {
+ return;
+ }
+
// colors for different type of new lines
vec4 edge_color = vec4(0.2, 0.1, 0.1, 1.0);
vec4 face_normal_color = vec4(0.5, 0.7, 0.2, 1.0);
@@ -47,56 +60,71 @@ void main()
// get position of the vertex
vec3 P = gl_in[i].gl_Position.xyz;
- // create normal for vertex
- o_color = normal_color;
- gl_Position = pos[i];
- EmitVertex();
- gl_Position = u_projection_view_matrix * vec4(P + o_normal[i].xyz
- * normal_scale, 1.0);
- EmitVertex();
- EndPrimitive();
+ if (enable_normals > 0)
+ {
+ // create normal for vertex
+ o_color = normal_color;
+ gl_Position = pos[i];
+ EmitVertex();
+ gl_Position = u_projection_view_matrix * vec4(P + o_normal[i].xyz
+ * normal_scale, 1.0);
+ EmitVertex();
+ EndPrimitive();
+ }
- // create tangent for vertex
- o_color = tangent_color;
- gl_Position = pos[i];
- EmitVertex();
- gl_Position = u_projection_view_matrix *
- vec4(P + o_tangent[i].xyz * normal_scale, 1.0);
- EmitVertex();
- EndPrimitive();
+ if (enable_tangents > 0)
+ {
+ // create tangent for vertex
+ o_color = tangent_color;
+ gl_Position = pos[i];
+ EmitVertex();
+ gl_Position = u_projection_view_matrix *
+ vec4(P + o_tangent[i].xyz * normal_scale, 1.0);
+ EmitVertex();
+ EndPrimitive();
+ }
- // create bitangent for vertex
- o_color = bitangent_color;
- gl_Position = pos[i];
+ if (enable_bitangents > 0)
+ {
+ // create bitangent for vertex
+ o_color = bitangent_color;
+ gl_Position = pos[i];
+ EmitVertex();
+ gl_Position = u_projection_view_matrix * vec4(P +
+ o_bitangent[i].xyz * normal_scale, 1.0);
+ EmitVertex();
+ EndPrimitive();
+ }
+ }
+
+ if (enable_wireframe > 0)
+ {
+ // create edges for triangle
+ o_color = edge_color;
+ gl_Position = pos[0];
EmitVertex();
- gl_Position = u_projection_view_matrix * vec4(P +
- o_bitangent[i].xyz * normal_scale, 1.0);
+ gl_Position = pos[1];
EmitVertex();
+ gl_Position = pos[2];
+ EmitVertex();
+ gl_Position = pos[0];
+ EmitVertex();
+ // end line strip after four added vertices, so we will get three lines
EndPrimitive();
}
- // create edges for triangle
- o_color = edge_color;
- gl_Position = pos[0];
- EmitVertex();
- gl_Position = pos[1];
- EmitVertex();
- gl_Position = pos[2];
- EmitVertex();
- gl_Position = pos[0];
- EmitVertex();
- // end line strip after four added vertices, so we will get three lines
- EndPrimitive();
+ if (enable_triangle_normals > 0)
+ {
+ // create normal for triangle
+ o_color = face_normal_color;
- // create normal for triangle
- o_color = face_normal_color;
-
- // position as arithmetic average
- vec3 P = (gl_in[0].gl_Position.xyz + gl_in[1].gl_Position.xyz
- + gl_in[2].gl_Position.xyz) / 3.0;
- gl_Position = u_projection_view_matrix * vec4(P, 1.0);
- EmitVertex();
- gl_Position = u_projection_view_matrix * vec4(P + N * normal_scale, 1.0);
- EmitVertex();
- EndPrimitive();
+ // position as arithmetic average
+ vec3 P = (gl_in[0].gl_Position.xyz + gl_in[1].gl_Position.xyz
+ + gl_in[2].gl_Position.xyz) / 3.0;
+ gl_Position = u_projection_view_matrix * vec4(P, 1.0);
+ EmitVertex();
+ gl_Position = u_projection_view_matrix * vec4(P + N * normal_scale, 1.0);
+ EmitVertex();
+ EndPrimitive();
+ }
}
diff --git a/data/shaders/sp_normal_visualizer.vert b/data/shaders/sp_normal_visualizer.vert
index a6c53a21e..83849ec86 100644
--- a/data/shaders/sp_normal_visualizer.vert
+++ b/data/shaders/sp_normal_visualizer.vert
@@ -50,21 +50,55 @@ void main()
vec4 skinned_tangent = vec4(0.0);
int skinning_offset = i_misc_data.x;
- for (int i = 0; i < 4; i++)
- {
- mat4 joint_matrix = mat4(
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 1),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 2),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 3));
- skinned_position += i_weight[i] * joint_matrix * idle_position;
- skinned_normal += i_weight[i] * joint_matrix * idle_normal;
- skinned_tangent += i_weight[i] * joint_matrix * idle_tangent;
- }
+#ifdef GL_ES
+ mat4 joint_matrix =
+ i_weight[0] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[1] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[2] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[3] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0));
+#else
+ mat4 joint_matrix =
+ i_weight[0] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[1] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[2] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[3] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 3));
+#endif
+
+ skinned_position = joint_matrix * idle_position;
+ skinned_normal = joint_matrix * idle_normal;
+ skinned_tangent = joint_matrix * idle_tangent;
float step_mix = step(float(skinning_offset), 0.0);
skinned_position = mix(skinned_position, idle_position, step_mix);
diff --git a/data/shaders/sp_pass.vert b/data/shaders/sp_pass.vert
index c3a2f6e93..1ce18e733 100644
--- a/data/shaders/sp_pass.vert
+++ b/data/shaders/sp_pass.vert
@@ -36,8 +36,9 @@ out vec3 normal;
out vec2 uv;
out vec2 uv_two;
out vec4 color;
+out vec4 world_position;
out float camdist;
-flat out float hue_change;
+out float hue_change;
void main()
{
@@ -49,7 +50,7 @@ void main()
#endif
vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w));
- vec4 world_position = getWorldPosition(i_origin, quaternion, i_scale.xyz,
+ vec4 v_world_position = getWorldPosition(i_origin, quaternion, i_scale.xyz,
i_position);
vec3 world_normal = rotateVector(quaternion, i_normal.xyz);
vec3 world_tangent = rotateVector(quaternion, i_tangent.xyz);
@@ -66,7 +67,8 @@ void main()
uv_two = i_uv_two;
color = i_color.zyxw;
- camdist = length(u_view_matrix * world_position);
+ camdist = length(u_view_matrix * v_world_position);
hue_change = float(i_misc_data.y) * 0.01;
- gl_Position = u_projection_view_matrix * world_position;
+ gl_Position = u_projection_view_matrix * v_world_position;
+ world_position = v_world_position;
}
diff --git a/data/shaders/sp_skinning.vert b/data/shaders/sp_skinning.vert
index 28824111a..af8cf21a5 100644
--- a/data/shaders/sp_skinning.vert
+++ b/data/shaders/sp_skinning.vert
@@ -44,7 +44,7 @@ out vec2 uv;
out vec2 uv_two;
out vec4 color;
out float camdist;
-flat out float hue_change;
+out float hue_change;
void main()
{
@@ -63,33 +63,55 @@ void main()
vec4 skinned_tangent = vec4(0.0);
int skinning_offset = i_misc_data.x;
- for (int i = 0; i < 4; i++)
- {
#ifdef GL_ES
- mat4 joint_matrix = mat4(
- texelFetch(skinning_tex, ivec2
- (0 , clamp(i_joint[i] + skinning_offset, 0, MAX_BONES)), 0),
- texelFetch(skinning_tex, ivec2
- (1, clamp(i_joint[i] + skinning_offset, 0, MAX_BONES)), 0),
- texelFetch(skinning_tex, ivec2
- (2, clamp(i_joint[i] + skinning_offset, 0, MAX_BONES)), 0),
- texelFetch(skinning_tex, ivec2
- (3, clamp(i_joint[i] + skinning_offset, 0, MAX_BONES)), 0));
+ mat4 joint_matrix =
+ i_weight[0] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[1] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[2] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[3] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0));
#else
- mat4 joint_matrix = mat4(
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 1),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 2),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 3));
+ mat4 joint_matrix =
+ i_weight[0] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[1] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[2] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[3] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 3));
#endif
- skinned_position += i_weight[i] * joint_matrix * idle_position;
- skinned_normal += i_weight[i] * joint_matrix * idle_normal;
- skinned_tangent += i_weight[i] * joint_matrix * idle_tangent;
- }
+
+ skinned_position = joint_matrix * idle_position;
+ skinned_normal = joint_matrix * idle_normal;
+ skinned_tangent = joint_matrix * idle_tangent;
vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w));
vec4 world_position = getWorldPosition(i_origin, quaternion, i_scale.xyz,
diff --git a/data/shaders/sp_skinning_shadow.vert b/data/shaders/sp_skinning_shadow.vert
index 81e0b6c3f..96d337fb7 100644
--- a/data/shaders/sp_skinning_shadow.vert
+++ b/data/shaders/sp_skinning_shadow.vert
@@ -36,31 +36,53 @@ void main()
vec4 skinned_position = vec4(0.0);
int skinning_offset = i_misc_data.x;
- for (int i = 0; i < 4; i++)
- {
#ifdef GL_ES
- mat4 joint_matrix = mat4(
- texelFetch(skinning_tex, ivec2
- (0, clamp(i_joint[i] + skinning_offset, 0, MAX_BONES)), 0),
- texelFetch(skinning_tex, ivec2
- (1, clamp(i_joint[i] + skinning_offset, 0, MAX_BONES)), 0),
- texelFetch(skinning_tex, ivec2
- (2, clamp(i_joint[i] + skinning_offset, 0, MAX_BONES)), 0),
- texelFetch(skinning_tex, ivec2
- (3, clamp(i_joint[i] + skinning_offset, 0, MAX_BONES)), 0));
+ mat4 joint_matrix =
+ i_weight[0] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[1] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[2] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES)), 0)) +
+ i_weight[3] * mat4(
+ texelFetch(skinning_tex, ivec2(0, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(1, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(2, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0),
+ texelFetch(skinning_tex, ivec2(3, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES)), 0));
#else
- mat4 joint_matrix = mat4(
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 1),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 2),
- texelFetch(skinning_tex,
- clamp(i_joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 3));
+ mat4 joint_matrix =
+ i_weight[0] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[0] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[1] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[1] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[2] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[2] + skinning_offset, 0, MAX_BONES) * 4 + 3)) +
+ i_weight[3] * mat4(
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 1),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 2),
+ texelFetch(skinning_tex, clamp(i_joint[3] + skinning_offset, 0, MAX_BONES) * 4 + 3));
#endif
- skinned_position += i_weight[i] * joint_matrix * idle_position;
- }
+
+ skinned_position = joint_matrix * idle_position;
vec4 quaternion = normalize(vec4(i_rotation.xyz, i_scale.w));
vec4 world_position = getWorldPosition(i_origin, quaternion, i_scale.xyz,
diff --git a/data/shaders/sp_solid.frag b/data/shaders/sp_solid.frag
index 911ed9e76..b9860f786 100644
--- a/data/shaders/sp_solid.frag
+++ b/data/shaders/sp_solid.frag
@@ -1,4 +1,4 @@
-flat in float hue_change;
+in float hue_change;
in vec4 color;
in vec3 normal;
diff --git a/data/shaders/sps_0_solid.xml b/data/shaders/sps_0_solid.xml
index 41e07c969..477691b17 100644
--- a/data/shaders/sps_0_solid.xml
+++ b/data/shaders/sps_0_solid.xml
@@ -100,18 +100,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/data/skins/Ocean.stkskin b/data/skins/Ocean.stkskin
index b251e5b37..72b93bfda 100644
--- a/data/skins/Ocean.stkskin
+++ b/data/skins/Ocean.stkskin
@@ -128,6 +128,9 @@ when the border that intersect at this corner are enabled.
hborder_out_portion="0.2" />
+
diff --git a/data/skins/Peach.stkskin b/data/skins/Peach.stkskin
index 4b67f0f5b..2f2ab97d4 100644
--- a/data/skins/Peach.stkskin
+++ b/data/skins/Peach.stkskin
@@ -129,6 +129,9 @@ when the border that intersect at this corner are enabled.
+
diff --git a/data/skins/Ruby.stkskin b/data/skins/Ruby.stkskin
index 76407f632..844fcc2d9 100644
--- a/data/skins/Ruby.stkskin
+++ b/data/skins/Ruby.stkskin
@@ -130,6 +130,9 @@ when the border that intersect at this corner are enabled.
+
diff --git a/data/skins/forest/glass_square_focused_bw.png b/data/skins/forest/glass_square_focused_bw.png
new file mode 100644
index 000000000..300633757
Binary files /dev/null and b/data/skins/forest/glass_square_focused_bw.png differ
diff --git a/data/skins/ocean/glass_square_focused_bw.png b/data/skins/ocean/glass_square_focused_bw.png
new file mode 100644
index 000000000..8319920d5
Binary files /dev/null and b/data/skins/ocean/glass_square_focused_bw.png differ
diff --git a/data/skins/peach/glass_square_focused_bw.png b/data/skins/peach/glass_square_focused_bw.png
new file mode 100644
index 000000000..113c08a6f
Binary files /dev/null and b/data/skins/peach/glass_square_focused_bw.png differ
diff --git a/data/skins/ruby/glass_square_focused_bw.png b/data/skins/ruby/glass_square_focused_bw.png
new file mode 100644
index 000000000..5ca9e5454
Binary files /dev/null and b/data/skins/ruby/glass_square_focused_bw.png differ
diff --git a/lib/angelscript/include/angelscript.h b/lib/angelscript/include/angelscript.h
index 98d33c516..72724a65c 100644
--- a/lib/angelscript/include/angelscript.h
+++ b/lib/angelscript/include/angelscript.h
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -58,8 +58,8 @@ BEGIN_AS_NAMESPACE
// AngelScript version
-#define ANGELSCRIPT_VERSION 23002
-#define ANGELSCRIPT_VERSION_STRING "2.30.2"
+#define ANGELSCRIPT_VERSION 23200
+#define ANGELSCRIPT_VERSION_STRING "2.32.0"
// Data types
@@ -68,12 +68,13 @@ class asIScriptModule;
class asIScriptContext;
class asIScriptGeneric;
class asIScriptObject;
-class asIObjectType;
+class asITypeInfo;
class asIScriptFunction;
class asIBinaryStream;
class asIJITCompiler;
class asIThreadManager;
class asILockableSharedBool;
+class asIStringFactory;
// Enumerations and constants
@@ -138,6 +139,9 @@ enum asEEngineProp
asEP_DISABLE_INTEGER_DIVISION = 22,
asEP_DISALLOW_EMPTY_LIST_ELEMENTS = 23,
asEP_PRIVATE_PROP_AS_PROTECTED = 24,
+ asEP_ALLOW_UNICODE_IDENTIFIERS = 25,
+ asEP_HEREDOC_TRIM_MODE = 26,
+ asEP_MAX_NESTED_CALLS = 27,
asEP_LAST_PROPERTY
};
@@ -200,7 +204,7 @@ enum asEObjTypeFlags
asOBJ_SCRIPT_OBJECT = (1<<21),
asOBJ_SHARED = (1<<22),
asOBJ_NOINHERIT = (1<<23),
- asOBJ_SCRIPT_FUNCTION = (1<<24),
+ asOBJ_FUNCDEF = (1<<24),
asOBJ_LIST_PATTERN = (1<<25),
asOBJ_ENUM = (1<<26),
asOBJ_TEMPLATE_SUBTYPE = (1<<27),
@@ -225,14 +229,6 @@ enum asEBehaviours
asBEHAVE_GET_WEAKREF_FLAG,
// Object operators
-#ifdef AS_DEPRECATED
- // Deprecated since 2.30.0, 2014-10-24
- asBEHAVE_VALUE_CAST,
- asBEHAVE_IMPLICIT_VALUE_CAST,
- // Deprecated since 2.30.0, 2014-12-30
- asBEHAVE_REF_CAST,
- asBEHAVE_IMPLICIT_REF_CAST,
-#endif
asBEHAVE_TEMPLATE_CALLBACK,
// Garbage collection behaviours
@@ -356,29 +352,31 @@ enum asEFuncType
// asQWORD = 64 bits
// asPWORD = size of pointer
//
+typedef signed char asINT8;
+typedef signed short asINT16;
typedef unsigned char asBYTE;
typedef unsigned short asWORD;
typedef unsigned int asUINT;
-#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__S3E__)
+#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__S3E__) || (defined(_MSC_VER) && defined(__clang__))
// size_t is not really correct, since it only guaranteed to be large enough to hold the segment size.
// For example, on 16bit systems the size_t may be 16bits only even if pointers are 32bit. But nobody
// is likely to use MSVC6 to compile for 16bit systems anymore, so this should be ok.
- typedef size_t asPWORD;
+ typedef size_t asPWORD;
#else
typedef uintptr_t asPWORD;
#endif
#ifdef __LP64__
- typedef unsigned int asDWORD;
- typedef unsigned long asQWORD;
- typedef long asINT64;
+ typedef unsigned int asDWORD;
+ typedef unsigned long asQWORD;
+ typedef long asINT64;
#else
- typedef unsigned long asDWORD;
- #if defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_CC) || defined(__psp2__)
- typedef uint64_t asQWORD;
- typedef int64_t asINT64;
+ typedef unsigned long asDWORD;
+ #if !defined(_MSC_VER) && (defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_CC) || defined(__psp2__))
+ typedef uint64_t asQWORD;
+ typedef int64_t asINT64;
#else
- typedef unsigned __int64 asQWORD;
- typedef __int64 asINT64;
+ typedef unsigned __int64 asQWORD;
+ typedef __int64 asINT64;
#endif
#endif
@@ -397,7 +395,7 @@ typedef void (*asCLEANENGINEFUNC_t)(asIScriptEngine *);
typedef void (*asCLEANMODULEFUNC_t)(asIScriptModule *);
typedef void (*asCLEANCONTEXTFUNC_t)(asIScriptContext *);
typedef void (*asCLEANFUNCTIONFUNC_t)(asIScriptFunction *);
-typedef void (*asCLEANOBJECTTYPEFUNC_t)(asIObjectType *);
+typedef void (*asCLEANTYPEINFOFUNC_t)(asITypeInfo *);
typedef void (*asCLEANSCRIPTOBJECTFUNC_t)(asIScriptObject *);
typedef asIScriptContext *(*asREQUESTCONTEXTFUNC_t)(asIScriptEngine *, void *);
typedef void (*asRETURNCONTEXTFUNC_t)(asIScriptEngine *, asIScriptContext *, void *);
@@ -425,7 +423,7 @@ typedef void (*asRETURNCONTEXTFUNC_t)(asIScriptEngine *, asIScriptContext *, voi
// BCC v5.8 (C++Builder 2006) and earlier have a similar bug which forces us to fall back to a C-style cast.
#define asFUNCTIONPR(f,p,r) asFunctionPtr((void (*)())((r (*)p)(f)))
#else
-#define asFUNCTIONPR(f,p,r) asFunctionPtr((void (*)())(static_cast(f)))
+#define asFUNCTIONPR(f,p,r) asFunctionPtr(reinterpret_cast(static_cast(f)))
#endif
#ifndef AS_NO_CLASS_METHODS
@@ -584,7 +582,7 @@ BEGIN_AS_NAMESPACE
template
asUINT asGetTypeTraits()
{
-#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5)
+#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5) || defined(__clang__)
// MSVC, XCode/Clang, and gnuc 5+
// C++11 compliant code
bool hasConstructor = std::is_default_constructible::value && !std::is_trivially_default_constructible::value;
@@ -665,7 +663,7 @@ public:
virtual asIJITCompiler *GetJITCompiler() const = 0;
// Global functions
- virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0) = 0;
+ virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0) = 0;
virtual asUINT GetGlobalFunctionCount() const = 0;
virtual asIScriptFunction *GetGlobalFunctionByIndex(asUINT index) const = 0;
virtual asIScriptFunction *GetGlobalFunctionByDecl(const char *declaration) const = 0;
@@ -679,18 +677,16 @@ public:
// Object types
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags) = 0;
- virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset) = 0;
- virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0) = 0;
- virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0) = 0;
+ virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset = 0, bool isCompositeIndirect = false) = 0;
+ virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0;
+ virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0;
virtual int RegisterInterface(const char *name) = 0;
virtual int RegisterInterfaceMethod(const char *intf, const char *declaration) = 0;
virtual asUINT GetObjectTypeCount() const = 0;
- virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const = 0;
- virtual asIObjectType *GetObjectTypeByName(const char *name) const = 0;
- virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const = 0;
+ virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0;
// String factory
- virtual int RegisterStringFactory(const char *datatype, const asSFuncPtr &factoryFunc, asDWORD callConv, void *objForThiscall = 0) = 0;
+ virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory) = 0;
virtual int GetStringFactoryReturnTypeId(asDWORD *flags = 0) const = 0;
// Default array type
@@ -698,22 +694,20 @@ public:
virtual int GetDefaultArrayTypeId() const = 0;
// Enums
- virtual int RegisterEnum(const char *type) = 0;
- virtual int RegisterEnumValue(const char *type, const char *name, int value) = 0;
- virtual asUINT GetEnumCount() const = 0;
- virtual const char *GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace = 0, const char **configGroup = 0, asDWORD *accessMask = 0) const = 0;
- virtual int GetEnumValueCount(int enumTypeId) const = 0;
- virtual const char *GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const = 0;
+ virtual int RegisterEnum(const char *type) = 0;
+ virtual int RegisterEnumValue(const char *type, const char *name, int value) = 0;
+ virtual asUINT GetEnumCount() const = 0;
+ virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0;
// Funcdefs
- virtual int RegisterFuncdef(const char *decl) = 0;
- virtual asUINT GetFuncdefCount() const = 0;
- virtual asIScriptFunction *GetFuncdefByIndex(asUINT index) const = 0;
+ virtual int RegisterFuncdef(const char *decl) = 0;
+ virtual asUINT GetFuncdefCount() const = 0;
+ virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const = 0;
// Typedefs
- virtual int RegisterTypedef(const char *type, const char *decl) = 0;
- virtual asUINT GetTypedefCount() const = 0;
- virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace = 0, const char **configGroup = 0, asDWORD *accessMask = 0) const = 0;
+ virtual int RegisterTypedef(const char *type, const char *decl) = 0;
+ virtual asUINT GetTypedefCount() const = 0;
+ virtual asITypeInfo *GetTypedefByIndex(asUINT index) const = 0;
// Configuration groups
virtual int BeginConfigGroup(const char *groupName) = 0;
@@ -731,29 +725,26 @@ public:
// Script functions
virtual asIScriptFunction *GetFunctionById(int funcId) const = 0;
- virtual asIScriptFunction *GetFuncDefFromTypeId(int typeId) const = 0;
// Type identification
- virtual asIObjectType *GetObjectTypeById(int typeId) const = 0;
virtual int GetTypeIdByDecl(const char *decl) const = 0;
virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const = 0;
virtual int GetSizeOfPrimitiveType(int typeId) const = 0;
+ virtual asITypeInfo *GetTypeInfoById(int typeId) const = 0;
+ virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0;
+ virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0;
// Script execution
virtual asIScriptContext *CreateContext() = 0;
- virtual void *CreateScriptObject(const asIObjectType *type) = 0;
- virtual void *CreateScriptObjectCopy(void *obj, const asIObjectType *type) = 0;
- virtual void *CreateUninitializedScriptObject(const asIObjectType *type) = 0;
+ virtual void *CreateScriptObject(const asITypeInfo *type) = 0;
+ virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type) = 0;
+ virtual void *CreateUninitializedScriptObject(const asITypeInfo *type) = 0;
virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj) = 0;
- virtual int AssignScriptObject(void *dstObj, void *srcObj, const asIObjectType *type) = 0;
- virtual void ReleaseScriptObject(void *obj, const asIObjectType *type) = 0;
- virtual void AddRefScriptObject(void *obj, const asIObjectType *type) = 0;
- virtual int RefCastObject(void *obj, asIObjectType *fromType, asIObjectType *toType, void **newPtr, bool useOnlyImplicitCast = false) = 0;
-#ifdef AS_DEPRECATED
- // Deprecated since 2.30.0, 2014-11-04
- virtual bool IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const = 0;
-#endif
- virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const = 0;
+ virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type) = 0;
+ virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type) = 0;
+ virtual void AddRefScriptObject(void *obj, const asITypeInfo *type) = 0;
+ virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false) = 0;
+ virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const = 0;
// Context pooling
virtual asIScriptContext *RequestContext() = 0;
@@ -766,8 +757,8 @@ public:
// Garbage collection
virtual int GarbageCollect(asDWORD flags = asGC_FULL_CYCLE, asUINT numIterations = 1) = 0;
virtual void GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed = 0, asUINT *totalDetected = 0, asUINT *newObjects = 0, asUINT *totalNewDestroyed = 0) const = 0;
- virtual int NotifyGarbageCollectorOfNewObject(void *obj, asIObjectType *type) = 0;
- virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr = 0, void **obj = 0, asIObjectType **type = 0) = 0;
+ virtual int NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type) = 0;
+ virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr = 0, void **obj = 0, asITypeInfo **type = 0) = 0;
virtual void GCEnumCallback(void *reference) = 0;
// User data
@@ -777,13 +768,24 @@ public:
virtual void SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type = 0) = 0;
virtual void SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type = 0) = 0;
virtual void SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type = 0) = 0;
- virtual void SetObjectTypeUserDataCleanupCallback(asCLEANOBJECTTYPEFUNC_t callback, asPWORD type = 0) = 0;
+ virtual void SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type = 0) = 0;
virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type = 0) = 0;
protected:
virtual ~asIScriptEngine() {}
};
+class asIStringFactory
+{
+public:
+ virtual const void *GetStringConstant(const char *data, asUINT length) = 0;
+ virtual int ReleaseStringConstant(const void *str) = 0;
+ virtual int GetRawStringData(const void *str, char *data, asUINT *length) const = 0;
+
+protected:
+ virtual ~asIStringFactory() {}
+};
+
class asIThreadManager
{
protected:
@@ -826,20 +828,18 @@ public:
// Type identification
virtual asUINT GetObjectTypeCount() const = 0;
- virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const = 0;
- virtual asIObjectType *GetObjectTypeByName(const char *name) const = 0;
- virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const = 0;
+ virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0;
virtual int GetTypeIdByDecl(const char *decl) const = 0;
+ virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0;
+ virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0;
// Enums
- virtual asUINT GetEnumCount() const = 0;
- virtual const char *GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace = 0) const = 0;
- virtual int GetEnumValueCount(int enumTypeId) const = 0;
- virtual const char *GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const = 0;
+ virtual asUINT GetEnumCount() const = 0;
+ virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0;
// Typedefs
- virtual asUINT GetTypedefCount() const = 0;
- virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace = 0) const = 0;
+ virtual asUINT GetTypedefCount() const = 0;
+ virtual asITypeInfo *GetTypedefByIndex(asUINT index) const = 0;
// Dynamic binding between modules
virtual asUINT GetImportedFunctionCount() const = 0;
@@ -948,6 +948,7 @@ public:
// Miscellaneous
virtual asIScriptEngine *GetEngine() const = 0;
virtual asIScriptFunction *GetFunction() const = 0;
+ virtual void *GetAuxiliary() const = 0;
// Object
virtual void *GetObject() = 0;
@@ -992,7 +993,7 @@ public:
// Type info
virtual int GetTypeId() const = 0;
- virtual asIObjectType *GetObjectType() const = 0;
+ virtual asITypeInfo *GetObjectType() const = 0;
// Class properties
virtual asUINT GetPropertyCount() const = 0;
@@ -1012,7 +1013,7 @@ protected:
virtual ~asIScriptObject() {}
};
-class asIObjectType
+class asITypeInfo
{
public:
// Miscellaneous
@@ -1028,19 +1029,19 @@ public:
// Type info
virtual const char *GetName() const = 0;
virtual const char *GetNamespace() const = 0;
- virtual asIObjectType *GetBaseType() const = 0;
- virtual bool DerivesFrom(const asIObjectType *objType) const = 0;
+ virtual asITypeInfo *GetBaseType() const = 0;
+ virtual bool DerivesFrom(const asITypeInfo *objType) const = 0;
virtual asDWORD GetFlags() const = 0;
virtual asUINT GetSize() const = 0;
virtual int GetTypeId() const = 0;
virtual int GetSubTypeId(asUINT subTypeIndex = 0) const = 0;
- virtual asIObjectType *GetSubType(asUINT subTypeIndex = 0) const = 0;
+ virtual asITypeInfo *GetSubType(asUINT subTypeIndex = 0) const = 0;
virtual asUINT GetSubTypeCount() const = 0;
// Interfaces
virtual asUINT GetInterfaceCount() const = 0;
- virtual asIObjectType *GetInterface(asUINT index) const = 0;
- virtual bool Implements(const asIObjectType *objType) const = 0;
+ virtual asITypeInfo *GetInterface(asUINT index) const = 0;
+ virtual bool Implements(const asITypeInfo *objType) const = 0;
// Factories
virtual asUINT GetFactoryCount() const = 0;
@@ -1055,19 +1056,34 @@ public:
// Properties
virtual asUINT GetPropertyCount() const = 0;
- virtual int GetProperty(asUINT index, const char **name, int *typeId = 0, bool *isPrivate = 0, bool *isProtected = 0, int *offset = 0, bool *isReference = 0, asDWORD *accessMask = 0) const = 0;
+ virtual int GetProperty(asUINT index, const char **name, int *typeId = 0, bool *isPrivate = 0, bool *isProtected = 0, int *offset = 0, bool *isReference = 0, asDWORD *accessMask = 0, int *compositeOffset = 0, bool *isCompositeIndirect = 0) const = 0;
virtual const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const = 0;
// Behaviours
virtual asUINT GetBehaviourCount() const = 0;
virtual asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const = 0;
+ // Child types
+ virtual asUINT GetChildFuncdefCount() const = 0;
+ virtual asITypeInfo *GetChildFuncdef(asUINT index) const = 0;
+ virtual asITypeInfo *GetParentType() const = 0;
+
+ // Enums
+ virtual asUINT GetEnumValueCount() const = 0;
+ virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const = 0;
+
+ // Typedef
+ virtual int GetTypedefTypeId() const = 0;
+
+ // Funcdef
+ virtual asIScriptFunction *GetFuncdefSignature() const = 0;
+
// User data
virtual void *SetUserData(void *data, asPWORD type = 0) = 0;
virtual void *GetUserData(asPWORD type = 0) const = 0;
protected:
- virtual ~asIObjectType() {}
+ virtual ~asITypeInfo() {}
};
class asIScriptFunction
@@ -1087,9 +1103,10 @@ public:
virtual const char *GetScriptSectionName() const = 0;
virtual const char *GetConfigGroup() const = 0;
virtual asDWORD GetAccessMask() const = 0;
+ virtual void *GetAuxiliary() const = 0;
// Function signature
- virtual asIObjectType *GetObjectType() const = 0;
+ virtual asITypeInfo *GetObjectType() const = 0;
virtual const char *GetObjectName() const = 0;
virtual const char *GetName() const = 0;
virtual const char *GetNamespace() const = 0;
@@ -1102,10 +1119,6 @@ public:
virtual bool IsShared() const = 0;
virtual asUINT GetParamCount() const = 0;
virtual int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const = 0;
-#ifdef AS_DEPRECATED
- // Deprecated since 2.29.0, 2014-04-06
- virtual int GetParamTypeId(asUINT index, asDWORD *flags = 0) const = 0;
-#endif
virtual int GetReturnTypeId(asDWORD *flags = 0) const = 0;
// Type id for function pointers
@@ -1114,7 +1127,7 @@ public:
// Delegates
virtual void *GetDelegateObject() const = 0;
- virtual asIObjectType *GetDelegateObjectType() const = 0;
+ virtual asITypeInfo *GetDelegateObjectType() const = 0;
virtual asIScriptFunction *GetDelegateFunction() const = 0;
// Debug information
@@ -1137,8 +1150,8 @@ protected:
class asIBinaryStream
{
public:
- virtual void Read(void *ptr, asUINT size) = 0;
- virtual void Write(const void *ptr, asUINT size) = 0;
+ virtual int Read(void *ptr, asUINT size) = 0;
+ virtual int Write(const void *ptr, asUINT size) = 0;
public:
virtual ~asIBinaryStream() {}
@@ -1337,7 +1350,7 @@ struct asSVMRegisters
asDWORD *stackPointer; // top of stack (grows downward)
asQWORD valueRegister; // temp register for primitives
void *objectRegister; // temp register for objects and handles
- asIObjectType *objectType; // type of object held in object register
+ asITypeInfo *objectType; // type of object held in object register
bool doProcessSuspend; // whether or not the JIT should break out when it encounters a suspend instruction
asIScriptContext *ctx; // the active context
};
diff --git a/lib/angelscript/projects/cmake/CMakeLists.txt b/lib/angelscript/projects/cmake/CMakeLists.txt
index 755d8378c..2d0688720 100644
--- a/lib/angelscript/projects/cmake/CMakeLists.txt
+++ b/lib/angelscript/projects/cmake/CMakeLists.txt
@@ -137,8 +137,10 @@ else()
set(ANGELSCRIPT_LIBRARY_NAME Angelscript) # OS X frameworks should have capitalized name
set(BUILD_SHARED_LIBS TRUE)
endif()
+set(ANGELSCRIPT_LIBRARY_NAME ${ANGELSCRIPT_LIBRARY_NAME} CACHE STRING "" FORCE)
add_library(${ANGELSCRIPT_LIBRARY_NAME} ${ANGELSCRIPT_SOURCE} ${ANGELSCRIPT_HEADERS})
+# Don't override the default library output path to avoid conflicts when building for multiple target platforms
#set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib)
target_link_libraries(${ANGELSCRIPT_LIBRARY_NAME} ${CMAKE_THREAD_LIBS_INIT})
@@ -160,7 +162,7 @@ if(MSVC)
set_target_properties(${ANGELSCRIPT_LIBRARY_NAME} PROPERTIES COMPILE_FLAGS "/MP")
endif()
+# Don't override the default runtime output path to avoid conflicts when building for multiple target platforms
#set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../bin)
-#add_subdirectory(../../../samples/game/projects/cmake/ ./game)
diff --git a/lib/angelscript/source/as_array.h b/lib/angelscript/source/as_array.h
index e1487e48d..647495177 100644
--- a/lib/angelscript/source/as_array.h
+++ b/lib/angelscript/source/as_array.h
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2014 Andreas Jonsson
+ Copyright (c) 2003-2015 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -468,10 +468,10 @@ bool asCArray::Concatenate(const asCArray &other)
}
template
-void asCArray::Concatenate(T* array, unsigned int count)
+void asCArray::Concatenate(T* other, unsigned int count)
{
for( unsigned int c = 0; c < count; c++ )
- PushLast(array[c]);
+ PushLast(other[c]);
}
template
diff --git a/lib/angelscript/source/as_builder.cpp b/lib/angelscript/source/as_builder.cpp
index 2ff191c3a..4a852b2f1 100644
--- a/lib/angelscript/source/as_builder.cpp
+++ b/lib/angelscript/source/as_builder.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -248,10 +248,10 @@ void asCBuilder::EvaluateTemplateInstances(asUINT startIdx, bool keepSilent)
if( callback && !engine->CallGlobalFunctionRetBool(tmpl, &dontGarbageCollect, callback->sysFuncIntf, callback) )
{
asCString sub = tmpl->templateSubTypes[0].Format(engine->nameSpaces[0]);
- for( asUINT n = 1; n < tmpl->templateSubTypes.GetLength(); n++ )
+ for( asUINT m = 1; m < tmpl->templateSubTypes.GetLength(); m++ )
{
sub += ",";
- sub += tmpl->templateSubTypes[n].Format(engine->nameSpaces[0]);
+ sub += tmpl->templateSubTypes[m].Format(engine->nameSpaces[0]);
}
asCString str;
str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, tmpl->name.AddressOf(), sub.AddressOf());
@@ -279,11 +279,11 @@ int asCBuilder::Build()
Reset();
// The template callbacks must only be called after the subtypes have a known structure,
- // otherwise the callback may think it is not possible to create the template instance,
+ // otherwise the callback may think it is not possible to create the template instance,
// even though it is.
- // TODO: This flag shouldn't be set globally in the engine, as it would mean that another
- // thread requesting a template instance in parallel to the compilation wouldn't
- // evaluate the template instance.
+ // TODO: This flag shouldn't be set globally in the engine, as it would mean that another
+ // thread requesting a template instance in parallel to the compilation wouldn't
+ // evaluate the template instance.
engine->deferValidationOfTemplateTypes = true;
asUINT numTempl = (asUINT)engine->templateInstanceTypes.GetLength();
@@ -293,7 +293,7 @@ int asCBuilder::Build()
CompileInterfaces();
CompileClasses(numTempl);
- // Evaluate the template instances one last time, this time with error messages, as we know
+ // Evaluate the template instances one last time, this time with error messages, as we know
// all classes have been fully built and it is known which ones will need garbage collection.
EvaluateTemplateInstances(numTempl, false);
engine->deferValidationOfTemplateTypes = false;
@@ -376,7 +376,7 @@ int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
- // None of the functions should be added to the module if any error occurred,
+ // None of the functions should be added to the module if any error occurred,
// or it was requested that the functions wouldn't be added to the scope
if( numErrors > 0 )
{
@@ -520,12 +520,12 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
node = node->firstChild;
// Create the function
- bool isConstructor, isDestructor, isPrivate, isProtected, isFinal, isOverride, isShared;
+ asSFunctionTraits funcTraits;
asCScriptFunction *func = asNEW(asCScriptFunction)(engine, compileFlags & asCOMP_ADD_TO_MODULE ? module : 0, asFUNC_SCRIPT);
if( func == 0 )
return asOUT_OF_MEMORY;
- GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, func->defaultArgs, func->isReadOnly, isConstructor, isDestructor, isPrivate, isProtected, isFinal, isOverride, isShared, module->defaultNamespace);
+ GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, func->defaultArgs, funcTraits, module->defaultNamespace);
func->id = engine->GetNextScriptFunctionId();
func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : "");
int row, col;
@@ -544,7 +544,7 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
// Tell the engine that the function exists already so the compiler can access it
if( compileFlags & asCOMP_ADD_TO_MODULE )
{
- int r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->defaultNamespace);
+ r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->defaultNamespace);
if( r < 0 )
{
func->ReleaseInternal();
@@ -552,7 +552,7 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
}
module->globalFunctions.Put(func);
-
+
module->AddScriptFunction(func);
}
else
@@ -579,8 +579,8 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
for( asUINT n = 0; n < functions.GetLength(); n++ )
{
asCCompiler compiler(engine);
- asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
- int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0);
+ asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId];
+ r = compiler.CompileFunction(this, functions[n]->script, f->parameterNames, functions[n]->node, f, 0);
if( r < 0 )
break;
}
@@ -588,18 +588,18 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
- // None of the functions should be added to the module if any error occurred,
+ // None of the functions should be added to the module if any error occurred,
// or it was requested that the functions wouldn't be added to the scope
if( !(compileFlags & asCOMP_ADD_TO_MODULE) || numErrors > 0 )
{
for( asUINT n = 0; n < functions.GetLength(); n++ )
{
- asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
- if( module->globalFunctions.GetIndex(func) >= 0 )
+ asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId];
+ if( module->globalFunctions.GetIndex(f) >= 0 )
{
- module->globalFunctions.Erase(module->globalFunctions.GetIndex(func));
- module->scriptFunctions.RemoveValue(func);
- func->ReleaseInternal();
+ module->globalFunctions.Erase(module->globalFunctions.GetIndex(f));
+ module->scriptFunctions.RemoveValue(f);
+ f->ReleaseInternal();
}
}
}
@@ -638,16 +638,20 @@ void asCBuilder::ParseScripts()
}
}
- if( numErrors == 0 )
+ if (numErrors == 0)
{
// Find all type declarations
- for( n = 0; n < scripts.GetLength(); n++ )
+ for (n = 0; n < scripts.GetLength(); n++)
{
asCScriptNode *node = parsers[n]->GetScriptNode();
RegisterTypesFromScript(node, scripts[n], engine->nameSpaces[0]);
}
- // Register the complete function definitions
+ // Before moving forward the builder must establish the relationship between types
+ // so that a derived type can see the child types of the parent type.
+ DetermineTypeRelations();
+
+ // Complete function definitions (defining returntype and parameters)
for( n = 0; n < funcDefs.GetLength(); n++ )
CompleteFuncDef(funcDefs[n]);
@@ -667,12 +671,12 @@ void asCBuilder::ParseScripts()
if( node->nodeType == snFunction )
{
node->DisconnectParent();
- RegisterScriptFunctionFromNode(node, decl->script, decl->objType, true, false, 0, decl->isExistingShared);
+ RegisterScriptFunctionFromNode(node, decl->script, CastToObjectType(decl->typeInfo), true, false, 0, decl->isExistingShared);
}
else if( node->nodeType == snVirtualProperty )
{
node->DisconnectParent();
- RegisterVirtualProperty(node, decl->script, decl->objType, true, false, 0, decl->isExistingShared);
+ RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), true, false, 0, decl->isExistingShared);
}
node = next;
@@ -696,44 +700,45 @@ void asCBuilder::ParseScripts()
if( node->nodeType == snFunction )
{
node->DisconnectParent();
- RegisterScriptFunctionFromNode(node, decl->script, decl->objType, false, false, 0, decl->isExistingShared);
+ RegisterScriptFunctionFromNode(node, decl->script, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared);
}
else if( node->nodeType == snVirtualProperty )
{
node->DisconnectParent();
- RegisterVirtualProperty(node, decl->script, decl->objType, false, false, 0, decl->isExistingShared);
+ RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared);
}
node = next;
}
// Make sure the default factory & constructor exists for classes
- if( decl->objType->beh.construct == engine->scriptTypeBehaviours.beh.construct )
+ asCObjectType *ot = CastToObjectType(decl->typeInfo);
+ if( ot->beh.construct == engine->scriptTypeBehaviours.beh.construct )
{
- if( decl->objType->beh.constructors.GetLength() == 1 || engine->ep.alwaysImplDefaultConstruct )
+ if( ot->beh.constructors.GetLength() == 1 || engine->ep.alwaysImplDefaultConstruct )
{
- AddDefaultConstructor(decl->objType, decl->script);
+ AddDefaultConstructor(ot, decl->script);
}
else
{
// As the class has another constructor we shouldn't provide the default constructor
- if( decl->objType->beh.construct )
+ if( ot->beh.construct )
{
- engine->scriptFunctions[decl->objType->beh.construct]->ReleaseInternal();
- decl->objType->beh.construct = 0;
- decl->objType->beh.constructors.RemoveIndex(0);
+ engine->scriptFunctions[ot->beh.construct]->ReleaseInternal();
+ ot->beh.construct = 0;
+ ot->beh.constructors.RemoveIndex(0);
}
- if( decl->objType->beh.factory )
+ if( ot->beh.factory )
{
- engine->scriptFunctions[decl->objType->beh.factory]->ReleaseInternal();
- decl->objType->beh.factory = 0;
- decl->objType->beh.factories.RemoveIndex(0);
+ engine->scriptFunctions[ot->beh.factory]->ReleaseInternal();
+ ot->beh.factory = 0;
+ ot->beh.factories.RemoveIndex(0);
}
// Only remove the opAssign method if the script hasn't provided one
- if( decl->objType->beh.copy == engine->scriptTypeBehaviours.beh.copy )
+ if( ot->beh.copy == engine->scriptTypeBehaviours.beh.copy )
{
- engine->scriptFunctions[decl->objType->beh.copy]->ReleaseInternal();
- decl->objType->beh.copy = 0;
+ engine->scriptFunctions[ot->beh.copy]->ReleaseInternal();
+ ot->beh.copy = 0;
}
}
}
@@ -799,7 +804,7 @@ void asCBuilder::RegisterTypesFromScript(asCScriptNode *node, asCScriptCode *scr
else if( node->nodeType == snFuncDef )
{
node->DisconnectParent();
- RegisterFuncDef(node, script, ns);
+ RegisterFuncDef(node, script, ns, 0);
}
else if( node->nodeType == snMixin )
{
@@ -868,6 +873,10 @@ void asCBuilder::CompileFunctions()
// Don't compile the function again if it was an existing shared function
if( current->isExistingShared ) continue;
+ // Don't compile if there is no statement block
+ if (current->node && !(current->node->nodeType == snStatementBlock || current->node->lastChild->nodeType == snStatementBlock))
+ continue;
+
asCCompiler compiler(engine);
asCScriptFunction *func = engine->scriptFunctions[current->funcId];
@@ -875,11 +884,11 @@ void asCBuilder::CompileFunctions()
sClassDeclaration *classDecl = 0;
if( current->objType && current->name == current->objType->name )
{
- for( asUINT n = 0; n < classDeclarations.GetLength(); n++ )
+ for( asUINT c = 0; c < classDeclarations.GetLength(); c++ )
{
- if( classDeclarations[n]->objType == current->objType )
+ if( classDeclarations[c]->typeInfo == current->objType )
{
- classDecl = classDeclarations[n];
+ classDecl = classDeclarations[c];
break;
}
}
@@ -994,7 +1003,7 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam
if( dt )
{
// Verify that the object type exist
- if( dt->GetObjectType() == 0 )
+ if( CastToObjectType(dt->GetTypeInfo()) == 0 )
return asINVALID_OBJECT;
}
@@ -1018,14 +1027,14 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam
// If an object property is registered, then use the
// object's namespace, otherwise use the specified namespace
- type = CreateDataTypeFromNode(dataType, &source, dt ? dt->GetObjectType()->nameSpace : ns);
+ type = CreateDataTypeFromNode(dataType, &source, dt ? dt->GetTypeInfo()->nameSpace : ns);
name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength);
type.MakeReference(isReference);
// Validate that the type really can be a registered property
// We cannot use CanBeInstantiated, as it is allowed to register
// properties of type that cannot otherwise be instantiated
- if( type.GetFuncDef() && !type.IsObjectHandle() )
+ if( type.IsFuncdef() && !type.IsObjectHandle() )
{
// Function definitions must always be handles
return asINVALID_DECLARATION;
@@ -1034,7 +1043,7 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam
// Verify property name
if( dt )
{
- if( CheckNameConflictMember(dt->GetObjectType(), name.AddressOf(), nameNode, &source, true) < 0 )
+ if( CheckNameConflictMember(dt->GetTypeInfo(), name.AddressOf(), nameNode, &source, true) < 0 )
return asNAME_TAKEN;
}
else
@@ -1052,10 +1061,10 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam
#ifndef AS_NO_COMPILER
asCObjectProperty *asCBuilder::GetObjectProperty(asCDataType &obj, const char *prop)
{
- asASSERT(obj.GetObjectType() != 0);
+ asASSERT(CastToObjectType(obj.GetTypeInfo()) != 0);
// TODO: optimize: Improve linear search
- asCArray &props = obj.GetObjectType()->properties;
+ asCArray &props = CastToObjectType(obj.GetTypeInfo())->properties;
for( asUINT n = 0; n < props.GetLength(); n++ )
{
if( props[n]->name == prop )
@@ -1131,7 +1140,7 @@ asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, asSNameSpace
if( isPureConstant ) *isPureConstant = globDesc->isPureConstant;
if( constantValue ) *constantValue = globDesc->constantValue;
}
- else
+ else
#endif
if( isAppProp )
{
@@ -1145,10 +1154,15 @@ asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, asSNameSpace
return 0;
}
-int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles, bool *returnAutoHandle, asSNameSpace *ns, asCScriptNode **listPattern)
+int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles, bool *returnAutoHandle, asSNameSpace *ns, asCScriptNode **listPattern, asCObjectType **outParentClass)
{
asASSERT( objType || ns );
+ if (listPattern)
+ *listPattern = 0;
+ if (outParentClass)
+ *outParentClass = 0;
+
// TODO: Can't we use GetParsedFunctionDetails to do most of what is done in this function?
Reset();
@@ -1165,13 +1179,15 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec
// Determine scope
asCScriptNode *n = node->firstChild->next->next;
- asCString scope = GetScopeFromNode(n, &source, &n);
- if( scope == "::" )
- func->nameSpace = engine->nameSpaces[0];
- else
- func->nameSpace = engine->FindNameSpace(scope.AddressOf());
- if( func->nameSpace == 0 )
+ asCObjectType *parentClass = 0;
+ func->nameSpace = GetNameSpaceFromNode(n, &source, ns, &n, &parentClass);
+ if( func->nameSpace == 0 && parentClass == 0 )
return asINVALID_DECLARATION;
+ if (parentClass && func->funcType != asFUNC_FUNCDEF)
+ return asINVALID_DECLARATION;
+
+ if (outParentClass)
+ *outParentClass = parentClass;
// Find name
func->name.Assign(&source.code[n->tokenPos], n->tokenLength);
@@ -1180,7 +1196,7 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec
bool autoHandle;
// Scoped reference types are allowed to use handle when returned from application functions
- func->returnType = CreateDataTypeFromNode(node->firstChild, &source, objType ? objType->nameSpace : ns, true, objType);
+ func->returnType = CreateDataTypeFromNode(node->firstChild, &source, objType ? objType->nameSpace : ns, true, parentClass ? parentClass : objType);
func->returnType = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle);
if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) )
return asINVALID_DECLARATION;
@@ -1188,8 +1204,8 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec
// Reference types cannot be returned by value from system functions
if( isSystemFunction &&
- (func->returnType.GetObjectType() &&
- (func->returnType.GetObjectType()->flags & asOBJ_REF)) &&
+ (func->returnType.GetTypeInfo() &&
+ (func->returnType.GetTypeInfo()->flags & asOBJ_REF)) &&
!(func->returnType.IsReference() ||
func->returnType.IsObjectHandle()) )
return asINVALID_DECLARATION;
@@ -1221,13 +1237,13 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec
while( n )
{
asETypeModifiers inOutFlags;
- asCDataType type = CreateDataTypeFromNode(n, &source, objType ? objType->nameSpace : ns, false, objType);
+ asCDataType type = CreateDataTypeFromNode(n, &source, objType ? objType->nameSpace : ns, false, parentClass ? parentClass : objType);
type = ModifyDataTypeFromNode(type, n->next, &source, &inOutFlags, &autoHandle);
// Reference types cannot be passed by value to system functions
if( isSystemFunction &&
- (type.GetObjectType() &&
- (type.GetObjectType()->flags & asOBJ_REF)) &&
+ (type.GetTypeInfo() &&
+ (type.GetTypeInfo()->flags & asOBJ_REF)) &&
!(type.IsReference() ||
type.IsObjectHandle()) )
return asINVALID_DECLARATION;
@@ -1252,7 +1268,7 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec
// Move to next parameter
n = n->next->next;
- if( n && n->nodeType == snIdentifier )
+ if( n && n->nodeType == snIdentifier )
{
func->parameterNames[index] = asCString(&source.code[n->tokenPos], n->tokenLength);
n = n->next;
@@ -1281,17 +1297,17 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec
{
if( objType == 0 )
return asINVALID_DECLARATION;
- func->isReadOnly = true;
+ func->SetReadOnly(true);
n = n->next;
}
else
- func->isReadOnly = false;
+ func->SetReadOnly(false);
// If the caller expects a list pattern, check for the existence, else report an error if not
if( listPattern )
{
- if( n == 0 || n->nodeType != snListPattern )
+ if( n == 0 || n->nodeType != snListPattern )
return asINVALID_DECLARATION;
else
{
@@ -1304,7 +1320,7 @@ int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *dec
if( n )
return asINVALID_DECLARATION;
}
-
+
// Make sure the default args are declared correctly
ValidateDefaultArgs(&source, node, func);
@@ -1331,6 +1347,7 @@ int asCBuilder::ParseVariableDeclaration(const char *decl, asSNameSpace *implici
// Determine the scope from declaration
asCScriptNode *n = node->firstChild->next;
+ // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace
outNamespace = GetNameSpaceFromNode(n, &source, implicitNamespace, &n);
if( outNamespace == 0 )
return asINVALID_DECLARATION;
@@ -1347,12 +1364,16 @@ int asCBuilder::ParseVariableDeclaration(const char *decl, asSNameSpace *implici
return 0;
}
-int asCBuilder::CheckNameConflictMember(asCObjectType *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty)
+int asCBuilder::CheckNameConflictMember(asCTypeInfo *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty)
{
// It's not necessary to check against object types
+ asCObjectType *ot = CastToObjectType(t);
+ if (!ot)
+ return 0;
+
// TODO: optimize: Improve linear search
- asCArray &props = t->properties;
+ asCArray &props = ot->properties;
for( asUINT n = 0; n < props.GetLength(); n++ )
{
if( props[n]->name == name )
@@ -1368,10 +1389,26 @@ int asCBuilder::CheckNameConflictMember(asCObjectType *t, const char *name, asCS
}
}
+ asCArray &funcdefs = ot->childFuncDefs;
+ for (asUINT n = 0; n < funcdefs.GetLength(); n++)
+ {
+ if (funcdefs[n]->name == name)
+ {
+ if (code)
+ {
+ asCString str;
+ str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name);
+ WriteError(str, code, node);
+ }
+
+ return -1;
+ }
+ }
+
// Property names must be checked against method names
if( isProperty )
{
- asCArray methods = t->methods;
+ asCArray methods = ot->methods;
for( asUINT n = 0; n < methods.GetLength(); n++ )
{
if( engine->scriptFunctions[methods[n]]->name == name )
@@ -1395,7 +1432,7 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
{
// Check against registered object types
// TODO: Must check against registered funcdefs too
- if( engine->GetRegisteredObjectType(name, ns) != 0 )
+ if( engine->GetRegisteredType(name, ns) != 0 )
{
if( code )
{
@@ -1428,7 +1465,7 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
for( n = 0; n < classDeclarations.GetLength(); n++ )
{
if( classDeclarations[n]->name == name &&
- classDeclarations[n]->objType->nameSpace == ns )
+ classDeclarations[n]->typeInfo->nameSpace == ns )
{
if( code )
{
@@ -1445,7 +1482,7 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri
for( n = 0; n < namedTypeDeclarations.GetLength(); n++ )
{
if( namedTypeDeclarations[n]->name == name &&
- namedTypeDeclarations[n]->objType->nameSpace == ns )
+ namedTypeDeclarations[n]->typeInfo->nameSpace == ns )
{
if( code )
{
@@ -1503,25 +1540,41 @@ sMixinClass *asCBuilder::GetMixinClass(const char *name, asSNameSpace *ns)
return 0;
}
-int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns)
+int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent)
{
- // TODO: redesign: Allow funcdefs to be explicitly declared as 'shared'. In this case
- // an error should be given if any of the arguments/return type is not
- // shared.
+ // namespace and parent are exclusively mutual
+ asASSERT((ns == 0 && parent) || (ns && parent == 0));
+
+ // Skip leading 'shared' and 'external' keywords
+ asCScriptNode *n = node->firstChild;
+ while (n->nodeType == snIdentifier)
+ n = n->next;
// Find the name
- asASSERT( node->firstChild->nodeType == snDataType );
- asCScriptNode *n = node->firstChild->next->next;
+ asASSERT( n->nodeType == snDataType );
+ n = n->next->next;
asCString name;
name.Assign(&file->code[n->tokenPos], n->tokenLength);
// Check for name conflict with other types
- int r = CheckNameConflict(name.AddressOf(), node, file, ns);
- if( asSUCCESS != r )
+ if (ns)
{
- node->Destroy(engine);
- return r;
+ int r = CheckNameConflict(name.AddressOf(), node, file, ns);
+ if (asSUCCESS != r)
+ {
+ node->Destroy(engine);
+ return r;
+ }
+ }
+ else
+ {
+ int r = CheckNameConflictMember(parent, name.AddressOf(), node, file, false);
+ if (asSUCCESS != r)
+ {
+ node->Destroy(engine);
+ return r;
+ }
}
// The function definition should be stored as a asCScriptFunction so that the application
@@ -1541,7 +1594,7 @@ int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNam
fd->name = name;
fd->node = node;
fd->script = file;
- fd->idx = module->AddFuncDef(name, ns);
+ fd->idx = module->AddFuncDef(name, ns, parent);
funcDefs.PushLast(fd);
@@ -1551,20 +1604,14 @@ int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNam
void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
{
asCArray defaultArgs;
- bool isConstMethod;
- bool isConstructor;
- bool isDestructor;
- bool isProtected;
- bool isPrivate;
- bool isOverride;
- bool isFinal;
- bool isShared;
+ asSFunctionTraits funcTraits;
- asCScriptFunction *func = module->funcDefs[funcDef->idx];
- asASSERT( func );
+ asCFuncdefType *fdt = module->funcDefs[funcDef->idx];
+ asASSERT( fdt );
+ asCScriptFunction *func = fdt->funcdef;
- // TODO: It should be possible to declare funcdef as shared. In this case a compiler error will be given if any of the types it uses are not shared
- GetParsedFunctionDetails(funcDef->node, funcDef->script, 0, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared, func->nameSpace);
+ asSNameSpace *implicitNs = func->nameSpace ? func->nameSpace : fdt->parentClass->nameSpace;
+ GetParsedFunctionDetails(funcDef->node, funcDef->script, fdt->parentClass, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, funcTraits, implicitNs);
// There should not be any defaultArgs, but if there are any we need to delete them to avoid leaks
for( asUINT n = 0; n < defaultArgs.GetLength(); n++ )
@@ -1572,48 +1619,73 @@ void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
asDELETE(defaultArgs[n], asCString);
// All funcdefs are shared, unless one of the parameter types or return type is not shared
- isShared = true;
- if( func->returnType.GetObjectType() && !func->returnType.GetObjectType()->IsShared() )
- isShared = false;
- if( func->returnType.GetFuncDef() && !func->returnType.GetFuncDef()->IsShared() )
- isShared = false;
- for( asUINT n = 0; isShared && n < func->parameterTypes.GetLength(); n++ )
+ bool declaredShared = funcTraits.GetTrait(asTRAIT_SHARED);
+ funcTraits.SetTrait(asTRAIT_SHARED, true);
+ if (func->returnType.GetTypeInfo() && !func->returnType.GetTypeInfo()->IsShared())
{
- if( func->parameterTypes[n].GetObjectType() && !func->parameterTypes[n].GetObjectType()->IsShared() )
- isShared = false;
- if( func->parameterTypes[n].GetFuncDef() && !func->parameterTypes[n].GetFuncDef()->IsShared() )
- isShared = false;
+ if (declaredShared)
+ {
+ asCString s;
+ s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->returnType.GetTypeInfo()->name.AddressOf());
+ WriteError(s.AddressOf(), funcDef->script, funcDef->node);
+ }
+ funcTraits.SetTrait(asTRAIT_SHARED, false);
}
- func->isShared = isShared;
+ for( asUINT n = 0; funcTraits.GetTrait(asTRAIT_SHARED) && n < func->parameterTypes.GetLength(); n++ )
+ if (func->parameterTypes[n].GetTypeInfo() && !func->parameterTypes[n].GetTypeInfo()->IsShared())
+ {
+ if (declaredShared)
+ {
+ asCString s;
+ s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->parameterTypes[n].GetTypeInfo()->name.AddressOf());
+ WriteError(s.AddressOf(), funcDef->script, funcDef->node);
+ }
+ funcTraits.SetTrait(asTRAIT_SHARED, false);
+ }
+ func->SetShared(funcTraits.GetTrait(asTRAIT_SHARED));
// Check if there is another identical funcdef from another module and if so reuse that instead
- if( func->isShared )
+ bool found = false;
+ if( func->IsShared() )
{
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
{
- asCScriptFunction *f2 = engine->funcDefs[n];
- if( f2 == 0 || func == f2 )
+ asCFuncdefType *fdt2 = engine->funcDefs[n];
+ if( fdt2 == 0 || fdt == fdt2 )
continue;
- if( !f2->isShared )
+ if( !fdt2->funcdef->IsShared() )
continue;
- if( f2->name == func->name &&
- f2->nameSpace == func->nameSpace &&
- f2->IsSignatureExceptNameEqual(func) )
+ if( fdt2->name == fdt->name &&
+ fdt2->nameSpace == fdt->nameSpace &&
+ fdt2->funcdef->IsSignatureExceptNameEqual(func) )
{
// Replace our funcdef for the existing one
- funcDef->idx = f2->id;
- module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
- f2->AddRefInternal();
+ funcDef->idx = fdt2->funcdef->id;
+ module->funcDefs[module->funcDefs.IndexOf(fdt)] = fdt2;
+ fdt2->AddRefInternal();
- engine->funcDefs.RemoveValue(func);
+ engine->funcDefs.RemoveValue(fdt);
- func->ReleaseInternal();
+ fdt->ReleaseInternal();
+ found = true;
break;
}
}
}
+
+ // If the funcdef was declared as external then the existing shared declaration must have been found
+ if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !found)
+ {
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf());
+ WriteError(str, funcDef->script, funcDef->node);
+ }
+
+ // Remember if the type was declared as external so the saved bytecode can be flagged accordingly
+ if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && found)
+ module->externalTypes.PushLast(engine->scriptFunctions[funcDef->idx]->funcdefType);
}
int asCBuilder::RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns)
@@ -1741,6 +1813,19 @@ int asCBuilder::RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asS
cl->DisconnectParent();
node->Destroy(engine);
+ // Check that the mixin class doesn't contain any child types
+ // TODO: Add support for child types in mixin classes
+ n = cl->firstChild;
+ while (n)
+ {
+ if (n->nodeType == snFuncDef)
+ {
+ WriteError(TXT_MIXIN_CANNOT_HAVE_CHILD_TYPES, file, n);
+ break;
+ }
+ n = n->next;
+ }
+
return 0;
}
@@ -1750,6 +1835,7 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS
bool isFinal = false;
bool isShared = false;
bool isAbstract = false;
+ bool isExternal = false;
// Check the class modifiers
while( n->tokenType == ttIdentifier )
@@ -1779,6 +1865,16 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS
}
isShared = true;
}
+ else if (file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN))
+ {
+ if (isExternal)
+ {
+ asCString msg;
+ msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf());
+ WriteWarning(msg, file, n);
+ }
+ isExternal = true;
+ }
else if( file->TokenEquals(n->tokenPos, n->tokenLength, ABSTRACT_TOKEN) )
{
if( isFinal )
@@ -1822,14 +1918,29 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS
decl->script = file;
decl->node = node;
+ // External shared interfaces must not try to redefine the interface
+ if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement))
+ {
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf());
+ WriteError(str, file, n);
+ }
+ else if (!isExternal && n->next && n->next->tokenType == ttEndStatement)
+ {
+ asCString str;
+ str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf());
+ WriteError(str, file, n);
+ }
+
// If this type is shared and there already exist another shared
// type of the same name, then that one should be used instead of
// creating a new one.
+ asCObjectType *st = 0;
if( isShared )
{
- for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
+ for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ )
{
- asCObjectType *st = engine->sharedScriptTypes[n];
+ st = CastToObjectType(engine->sharedScriptTypes[i]);
if( st &&
st->IsShared() &&
st->name == name &&
@@ -1838,68 +1949,106 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS
{
// We'll use the existing type
decl->isExistingShared = true;
- decl->objType = st;
+ decl->typeInfo = st;
module->classTypes.PushLast(st);
st->AddRefInternal();
- return 0;
+ break;
}
}
}
- // Create a new object type for this class
- asCObjectType *st = asNEW(asCObjectType)(engine);
- if( st == 0 )
- return asOUT_OF_MEMORY;
-
- // By default all script classes are marked as garbage collected.
- // Only after the complete structure and relationship between classes
- // is known, can the flag be cleared for those objects that truly cannot
- // form circular references. This is important because a template
- // callback may be called with a script class before the compilation
- // completes, and until it is known, the callback must assume the class
- // is garbage collected.
- st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_GC;
-
- if( isShared )
- st->flags |= asOBJ_SHARED;
-
- if( isFinal )
- st->flags |= asOBJ_NOINHERIT;
-
- if( isAbstract )
- st->flags |= asOBJ_ABSTRACT;
-
- if( node->tokenType == ttHandle )
- st->flags |= asOBJ_IMPLICIT_HANDLE;
-
- st->size = sizeof(asCScriptObject);
- st->name = name;
- st->nameSpace = ns;
- st->module = module;
- module->classTypes.PushLast(st);
- if( isShared )
+ // If the class was declared as external then it must have been compiled in a different module first
+ if (isExternal && decl->typeInfo == 0)
{
- engine->sharedScriptTypes.PushLast(st);
- st->AddRefInternal();
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf());
+ WriteError(str, file, n);
}
- decl->objType = st;
- // Use the default script class behaviours
- st->beh = engine->scriptTypeBehaviours.beh;
+ // Remember if the class was declared as external so the saved bytecode can be flagged accordingly
+ if (isExternal)
+ module->externalTypes.PushLast(st);
- // TODO: Move this to asCObjectType so that the asCRestore can reuse it
- engine->scriptFunctions[st->beh.addref]->AddRefInternal();
- engine->scriptFunctions[st->beh.release]->AddRefInternal();
- engine->scriptFunctions[st->beh.gcEnumReferences]->AddRefInternal();
- engine->scriptFunctions[st->beh.gcGetFlag]->AddRefInternal();
- engine->scriptFunctions[st->beh.gcGetRefCount]->AddRefInternal();
- engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRefInternal();
- engine->scriptFunctions[st->beh.gcSetFlag]->AddRefInternal();
- engine->scriptFunctions[st->beh.copy]->AddRefInternal();
- engine->scriptFunctions[st->beh.factory]->AddRefInternal();
- engine->scriptFunctions[st->beh.construct]->AddRefInternal();
- // TODO: weak: Should not do this if the class has been declared with noweak
- engine->scriptFunctions[st->beh.getWeakRefFlag]->AddRefInternal();
+ if (!decl->isExistingShared)
+ {
+ // Create a new object type for this class
+ st = asNEW(asCObjectType)(engine);
+ if (st == 0)
+ return asOUT_OF_MEMORY;
+
+ // By default all script classes are marked as garbage collected.
+ // Only after the complete structure and relationship between classes
+ // is known, can the flag be cleared for those objects that truly cannot
+ // form circular references. This is important because a template
+ // callback may be called with a script class before the compilation
+ // completes, and until it is known, the callback must assume the class
+ // is garbage collected.
+ st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_GC;
+
+ if (isShared)
+ st->flags |= asOBJ_SHARED;
+
+ if (isFinal)
+ st->flags |= asOBJ_NOINHERIT;
+
+ if (isAbstract)
+ st->flags |= asOBJ_ABSTRACT;
+
+ if (node->tokenType == ttHandle)
+ st->flags |= asOBJ_IMPLICIT_HANDLE;
+
+ st->size = sizeof(asCScriptObject);
+ st->name = name;
+ st->nameSpace = ns;
+ st->module = module;
+ module->classTypes.PushLast(st);
+ if (isShared)
+ {
+ engine->sharedScriptTypes.PushLast(st);
+ st->AddRefInternal();
+ }
+ decl->typeInfo = st;
+
+ // Use the default script class behaviours
+ st->beh = engine->scriptTypeBehaviours.beh;
+
+ // TODO: Move this to asCObjectType so that the asCRestore can reuse it
+ engine->scriptFunctions[st->beh.addref]->AddRefInternal();
+ engine->scriptFunctions[st->beh.release]->AddRefInternal();
+ engine->scriptFunctions[st->beh.gcEnumReferences]->AddRefInternal();
+ engine->scriptFunctions[st->beh.gcGetFlag]->AddRefInternal();
+ engine->scriptFunctions[st->beh.gcGetRefCount]->AddRefInternal();
+ engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRefInternal();
+ engine->scriptFunctions[st->beh.gcSetFlag]->AddRefInternal();
+ engine->scriptFunctions[st->beh.copy]->AddRefInternal();
+ engine->scriptFunctions[st->beh.factory]->AddRefInternal();
+ engine->scriptFunctions[st->beh.construct]->AddRefInternal();
+ // TODO: weak: Should not do this if the class has been declared with noweak
+ engine->scriptFunctions[st->beh.getWeakRefFlag]->AddRefInternal();
+
+ // Skip to the content of the class
+ while (n && n->nodeType == snIdentifier)
+ n = n->next;
+ }
+
+ // Register possible child types
+ while (n)
+ {
+ node = n->next;
+ if (n->nodeType == snFuncDef)
+ {
+ n->DisconnectParent();
+ if (!decl->isExistingShared)
+ RegisterFuncDef(n, file, 0, st);
+ else
+ {
+ // Destroy the node, since it won't be used
+ // TODO: Should verify that the funcdef is identical to the one in the existing shared class
+ n->Destroy(engine);
+ }
+ }
+ n = node;
+ }
return 0;
}
@@ -1907,20 +2056,25 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS
int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns)
{
asCScriptNode *n = node->firstChild;
- asCString name(&file->code[n->tokenPos], n->tokenLength);
bool isShared = false;
- if( name == SHARED_TOKEN )
+ bool isExternal = false;
+ while( n->nodeType == snIdentifier )
{
- isShared = true;
-
+ if (file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN))
+ isShared = true;
+ else if (file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN))
+ isExternal = true;
+ else
+ break;
n = n->next;
- name.Assign(&file->code[n->tokenPos], n->tokenLength);
}
int r, c;
file->ConvertPosToRowCol(n->tokenPos, &r, &c);
+ asCString name;
+ name.Assign(&file->code[n->tokenPos], n->tokenLength);
CheckNameConflict(name.AddressOf(), n, file, ns);
sClassDeclaration *decl = asNEW(sClassDeclaration);
@@ -1935,14 +2089,28 @@ int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSN
decl->script = file;
decl->node = node;
+ // External shared interfaces must not try to redefine the interface
+ if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement) )
+ {
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf());
+ WriteError(str, file, n);
+ }
+ else if (!isExternal && n->next && n->next->tokenType == ttEndStatement)
+ {
+ asCString str;
+ str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf());
+ WriteError(str, file, n);
+ }
+
// If this type is shared and there already exist another shared
// type of the same name, then that one should be used instead of
// creating a new one.
if( isShared )
{
- for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
+ for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ )
{
- asCObjectType *st = engine->sharedScriptTypes[n];
+ asCObjectType *st = CastToObjectType(engine->sharedScriptTypes[i]);
if( st &&
st->IsShared() &&
st->name == name &&
@@ -1951,14 +2119,27 @@ int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSN
{
// We'll use the existing type
decl->isExistingShared = true;
- decl->objType = st;
+ decl->typeInfo = st;
module->classTypes.PushLast(st);
st->AddRefInternal();
+
+ // Remember if the interface was declared as external so the saved bytecode can be flagged accordingly
+ if (isExternal)
+ module->externalTypes.PushLast(st);
+
return 0;
}
}
}
+ // If the interface was declared as external then it must have been compiled in a different module first
+ if (isExternal)
+ {
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf());
+ WriteError(str, file, n);
+ }
+
// Register the object type for the interface
asCObjectType *st = asNEW(asCObjectType)(engine);
if( st == 0 )
@@ -1979,7 +2160,7 @@ int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSN
engine->sharedScriptTypes.PushLast(st);
st->AddRefInternal();
}
- decl->objType = st;
+ decl->typeInfo = st;
// Use the default script class behaviours
st->beh.construct = 0;
@@ -2067,7 +2248,7 @@ void asCBuilder::CompileGlobalVariables()
asCScriptFunction func(engine, module, asFUNC_SCRIPT);
// Set the namespace that should be used during the compilation
- func.nameSpace = gvar->datatype.GetObjectType()->nameSpace;
+ func.nameSpace = gvar->datatype.GetTypeInfo()->nameSpace;
// Temporarily switch the type of the variable to int so it can be compiled properly
asCDataType saveType;
@@ -2092,8 +2273,7 @@ void asCBuilder::CompileGlobalVariables()
sGlobalVariableDescription *gvar2 = *prev_it;
if(gvar2->datatype == gvar->datatype )
{
- // The integer value is stored in the lower bytes
- enumVal = (*(int*)&gvar2->constantValue) + 1;
+ enumVal = int(gvar2->constantValue) + 1;
if( !gvar2->isCompiled )
{
@@ -2112,8 +2292,7 @@ void asCBuilder::CompileGlobalVariables()
}
}
- // The integer value is stored in the lower bytes
- *(int*)&gvar->constantValue = enumVal;
+ gvar->constantValue = enumVal;
}
if( r >= 0 )
@@ -2200,8 +2379,8 @@ void asCBuilder::CompileGlobalVariables()
// Convert enums to true enum values, so subsequent compilations can access it as an enum
if( gvar->isEnumValue )
{
- asCObjectType *objectType = gvar->datatype.GetObjectType();
- asASSERT(NULL != objectType);
+ asCEnumType *enumType = CastToEnumType(gvar->datatype.GetTypeInfo());
+ asASSERT(NULL != enumType);
asSEnumValue *e = asNEW(asSEnumValue);
if( e == 0 )
@@ -2212,9 +2391,9 @@ void asCBuilder::CompileGlobalVariables()
}
e->name = gvar->name;
- e->value = *(int*)&gvar->constantValue;
+ e->value = int(gvar->constantValue);
- objectType->enumValues.PushLast(e);
+ enumType->enumValues.PushLast(e);
}
}
else
@@ -2303,9 +2482,11 @@ void asCBuilder::CompileGlobalVariables()
int asCBuilder::GetNamespaceAndNameFromNode(asCScriptNode *n, asCScriptCode *script, asSNameSpace *implicitNs, asSNameSpace *&outNs, asCString &outName)
{
+ // TODO: child funcdef: The node might be a snScope now
asASSERT( n->nodeType == snIdentifier );
// Get the optional scope from the node
+ // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace
asSNameSpace *ns = GetNameSpaceFromNode(n->firstChild, script, implicitNs, 0);
if( ns == 0 )
return -1;
@@ -2345,7 +2526,7 @@ void asCBuilder::AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScript
if( objType && objType->IsInterface() )
{
// Only add the interface if the class doesn't already implement it
- if( !decl->objType->Implements(objType) )
+ if( !decl->typeInfo->Implements(objType) )
AddInterfaceToClass(decl, errNode, objType);
}
else
@@ -2371,7 +2552,7 @@ void asCBuilder::AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScript
void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *errNode, asCObjectType *intfType)
{
// A shared type may only implement from shared interfaces
- if( decl->objType->IsShared() && !intfType->IsShared() )
+ if( decl->typeInfo->IsShared() && !intfType->IsShared() )
{
asCString msg;
msg.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, intfType->name.AddressOf());
@@ -2383,10 +2564,10 @@ void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *err
{
// If the class is an existing shared class, then just check if the
// interface exists in the original declaration too
- if( !decl->objType->Implements(intfType) )
+ if( !decl->typeInfo->Implements(intfType) )
{
asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName());
+ str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName());
WriteError(str, decl->script, errNode);
return;
}
@@ -2394,15 +2575,15 @@ void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *err
else
{
// If the interface is already in the class then don't add it again
- if( decl->objType->Implements(intfType) )
+ if( decl->typeInfo->Implements(intfType) )
return;
// Add the interface to the class
- decl->objType->interfaces.PushLast(intfType);
+ CastToObjectType(decl->typeInfo)->interfaces.PushLast(intfType);
// Add the inherited interfaces too
// For interfaces this will be done outside to handle out-of-order declarations
- if( !decl->objType->IsInterface() )
+ if( !CastToObjectType(decl->typeInfo)->IsInterface() )
{
for( asUINT n = 0; n < intfType->interfaces.GetLength(); n++ )
AddInterfaceToClass(decl, errNode, intfType->interfaces[n]);
@@ -2413,107 +2594,20 @@ void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *err
void asCBuilder::CompileInterfaces()
{
asUINT n;
- for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
- {
- sClassDeclaration *intfDecl = interfaceDeclarations[n];
- asCObjectType *intfType = intfDecl->objType;
-
- asCScriptNode *node = intfDecl->node;
- asASSERT(node && node->nodeType == snInterface);
- node = node->firstChild;
-
- // Skip the 'shared' keyword
- if( intfType->IsShared() )
- node = node->next;
-
- // Skip the name
- node = node->next;
-
- // Verify the inherited interfaces
- while( node && node->nodeType == snIdentifier )
- {
- asSNameSpace *ns;
- asCString name;
- if( GetNamespaceAndNameFromNode(node, intfDecl->script, intfType->nameSpace, ns, name) < 0 )
- {
- node = node->next;
- continue;
- }
-
- // Find the object type for the interface
- asCObjectType *objType = 0;
- while( ns )
- {
- objType = GetObjectType(name.AddressOf(), ns);
- if( objType ) break;
-
- ns = engine->GetParentNameSpace(ns);
- }
-
- // Check that the object type is an interface
- bool ok = true;
- if( objType && objType->IsInterface() )
- {
- // Check that the implemented interface is shared if the base interface is shared
- if( intfType->IsShared() && !objType->IsShared() )
- {
- asCString str;
- str.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, objType->GetName());
- WriteError(str, intfDecl->script, node);
- ok = false;
- }
- }
- else
- {
- WriteError(TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE, intfDecl->script, node);
- ok = false;
- }
-
- if( ok )
- {
- // Make sure none of the implemented interfaces implement from this one
- asCObjectType *base = objType;
- while( base != 0 )
- {
- if( base == intfType )
- {
- WriteError(TXT_CANNOT_IMPLEMENT_SELF, intfDecl->script, node);
- ok = false;
- break;
- }
-
- // At this point there is at most one implemented interface
- if( base->interfaces.GetLength() )
- base = base->interfaces[0];
- else
- break;
- }
- }
-
- if( ok )
- AddInterfaceToClass(intfDecl, node, objType);
-
- // Remove the nodes so they aren't parsed again
- asCScriptNode *delNode = node;
- node = node->next;
- delNode->DisconnectParent();
- delNode->Destroy(engine);
- }
- }
// Order the interfaces with inheritances so that the inherited
// of inherited interfaces can be added properly
for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
{
sClassDeclaration *intfDecl = interfaceDeclarations[n];
- asCObjectType *intfType = intfDecl->objType;
+ asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo);
if( intfType->interfaces.GetLength() == 0 ) continue;
// If any of the derived interfaces are found after this interface, then move this to the end of the list
for( asUINT m = n+1; m < interfaceDeclarations.GetLength(); m++ )
{
- if( intfType->Implements(interfaceDeclarations[m]->objType) )
+ if( intfType->Implements(interfaceDeclarations[m]->typeInfo) )
{
interfaceDeclarations.RemoveIndex(n);
interfaceDeclarations.PushLast(intfDecl);
@@ -2529,7 +2623,7 @@ void asCBuilder::CompileInterfaces()
for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
{
sClassDeclaration *intfDecl = interfaceDeclarations[n];
- asCObjectType *intfType = intfDecl->objType;
+ asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo);
// TODO: Is this really at the correct place? Hasn't the vfTableIdx already been set here?
// Co-opt the vfTableIdx value in our own methods to indicate the
@@ -2553,10 +2647,10 @@ void asCBuilder::CompileInterfaces()
AddInterfaceToClass(intfDecl, intfDecl->node, base->interfaces[l]);
// Add the methods from the implemented interface
- for( asUINT m = 0; m < base->methods.GetLength(); m++ )
+ for( asUINT l = 0; l < base->methods.GetLength(); l++ )
{
// If the derived interface implements the same method, then don't add the base interface' method
- asCScriptFunction *baseFunc = GetFunctionDescription(base->methods[m]);
+ asCScriptFunction *baseFunc = GetFunctionDescription(base->methods[l]);
asCScriptFunction *derivedFunc = 0;
bool found = false;
for( asUINT d = 0; d < intfType->methods.GetLength(); d++ )
@@ -2580,14 +2674,101 @@ void asCBuilder::CompileInterfaces()
}
}
-// numTempl is the number of template instances that existed in the engine before the build begun
-void asCBuilder::CompileClasses(asUINT numTempl)
+void asCBuilder::DetermineTypeRelations()
{
- asUINT n;
- asCArray toValidate((int)classDeclarations.GetLength());
+ // Determine inheritance between interfaces
+ for (asUINT n = 0; n < interfaceDeclarations.GetLength(); n++)
+ {
+ sClassDeclaration *intfDecl = interfaceDeclarations[n];
+ asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo);
+
+ asCScriptNode *node = intfDecl->node;
+ asASSERT(node && node->nodeType == snInterface);
+ node = node->firstChild;
+
+ // Skip the 'shared' & 'external' keywords
+ while( node->nodeType == snIdentifier &&
+ (intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) ||
+ intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) )
+ node = node->next;
+
+ // Skip the name
+ node = node->next;
+
+ // Verify the inherited interfaces
+ while (node && node->nodeType == snIdentifier)
+ {
+ asSNameSpace *ns;
+ asCString name;
+ if (GetNamespaceAndNameFromNode(node, intfDecl->script, intfType->nameSpace, ns, name) < 0)
+ {
+ node = node->next;
+ continue;
+ }
+
+ // Find the object type for the interface
+ asCObjectType *objType = 0;
+ while (ns)
+ {
+ objType = GetObjectType(name.AddressOf(), ns);
+ if (objType) break;
+
+ ns = engine->GetParentNameSpace(ns);
+ }
+
+ // Check that the object type is an interface
+ bool ok = true;
+ if (objType && objType->IsInterface())
+ {
+ // Check that the implemented interface is shared if the base interface is shared
+ if (intfType->IsShared() && !objType->IsShared())
+ {
+ asCString str;
+ str.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, objType->GetName());
+ WriteError(str, intfDecl->script, node);
+ ok = false;
+ }
+ }
+ else
+ {
+ WriteError(TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE, intfDecl->script, node);
+ ok = false;
+ }
+
+ if (ok)
+ {
+ // Make sure none of the implemented interfaces implement from this one
+ asCObjectType *base = objType;
+ while (base != 0)
+ {
+ if (base == intfType)
+ {
+ WriteError(TXT_CANNOT_IMPLEMENT_SELF, intfDecl->script, node);
+ ok = false;
+ break;
+ }
+
+ // At this point there is at most one implemented interface
+ if (base->interfaces.GetLength())
+ base = base->interfaces[0];
+ else
+ break;
+ }
+ }
+
+ if (ok)
+ AddInterfaceToClass(intfDecl, node, objType);
+
+ // Remove the nodes so they aren't parsed again
+ asCScriptNode *delNode = node;
+ node = node->next;
+ delNode->DisconnectParent();
+ delNode->Destroy(engine);
+ }
+ }
// Determine class inheritances and interfaces
- for( n = 0; n < classDeclarations.GetLength(); n++ )
+ for (asUINT n = 0; n < classDeclarations.GetLength(); n++)
{
sClassDeclaration *decl = classDeclarations[n];
asCScriptCode *file = decl->script;
@@ -2596,9 +2777,10 @@ void asCBuilder::CompileClasses(asUINT numTempl)
bool multipleInheritance = false;
asCScriptNode *node = decl->node->firstChild;
- while( file->TokenEquals(node->tokenPos, node->tokenLength, FINAL_TOKEN) ||
- file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) ||
- file->TokenEquals(node->tokenPos, node->tokenLength, ABSTRACT_TOKEN) )
+ while (file->TokenEquals(node->tokenPos, node->tokenLength, FINAL_TOKEN) ||
+ file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) ||
+ file->TokenEquals(node->tokenPos, node->tokenLength, ABSTRACT_TOKEN) ||
+ file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN))
{
node = node->next;
}
@@ -2607,11 +2789,11 @@ void asCBuilder::CompileClasses(asUINT numTempl)
asASSERT(node->tokenType == ttIdentifier);
node = node->next;
- while( node && node->nodeType == snIdentifier )
+ while (node && node->nodeType == snIdentifier)
{
asSNameSpace *ns;
asCString name;
- if( GetNamespaceAndNameFromNode(node, file, decl->objType->nameSpace, ns, name) < 0 )
+ if (GetNamespaceAndNameFromNode(node, file, decl->typeInfo->nameSpace, ns, name) < 0)
{
node = node->next;
continue;
@@ -2621,33 +2803,33 @@ void asCBuilder::CompileClasses(asUINT numTempl)
asCObjectType *objType = 0;
sMixinClass *mixin = 0;
asSNameSpace *origNs = ns;
- while( ns )
+ while (ns)
{
objType = GetObjectType(name.AddressOf(), ns);
- if( objType == 0 )
+ if (objType == 0)
mixin = GetMixinClass(name.AddressOf(), ns);
- if( objType || mixin )
+ if (objType || mixin)
break;
ns = engine->GetParentNameSpace(ns);
}
- if( objType == 0 && mixin == 0 )
+ if (objType == 0 && mixin == 0)
{
asCString str;
- if( origNs->name == "" )
+ if (origNs->name == "")
str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, name.AddressOf());
else
str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, name.AddressOf(), origNs->name.AddressOf());
WriteError(str, file, node);
}
- else if( mixin )
+ else if (mixin)
{
AddInterfaceFromMixinToClass(decl, node, mixin);
}
- else if( !(objType->flags & asOBJ_SCRIPT_OBJECT) ||
- (objType->flags & asOBJ_NOINHERIT) )
+ else if (!(objType->flags & asOBJ_SCRIPT_OBJECT) ||
+ (objType->flags & asOBJ_NOINHERIT))
{
// Either the class is not a script class or interface
// or the class has been declared as 'final'
@@ -2655,12 +2837,12 @@ void asCBuilder::CompileClasses(asUINT numTempl)
str.Format(TXT_CANNOT_INHERIT_FROM_s_FINAL, objType->name.AddressOf());
WriteError(str, file, node);
}
- else if( objType->size != 0 )
+ else if (objType->size != 0)
{
// The class inherits from another script class
- if( !decl->isExistingShared && decl->objType->derivedFrom != 0 )
+ if (!decl->isExistingShared && CastToObjectType(decl->typeInfo)->derivedFrom != 0)
{
- if( !multipleInheritance )
+ if (!multipleInheritance)
{
WriteError(TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES, file, node);
multipleInheritance = true;
@@ -2671,9 +2853,9 @@ void asCBuilder::CompileClasses(asUINT numTempl)
// Make sure none of the base classes inherit from this one
asCObjectType *base = objType;
bool error = false;
- while( base != 0 )
+ while (base != 0)
{
- if( base == decl->objType )
+ if (base == decl->typeInfo)
{
WriteError(TXT_CANNOT_INHERIT_FROM_SELF, file, node);
error = true;
@@ -2683,10 +2865,10 @@ void asCBuilder::CompileClasses(asUINT numTempl)
base = base->derivedFrom;
}
- if( !error )
+ if (!error)
{
// A shared type may only inherit from other shared types
- if( (decl->objType->IsShared()) && !(objType->IsShared()) )
+ if ((decl->typeInfo->IsShared()) && !(objType->IsShared()))
{
asCString msg;
msg.Format(TXT_SHARED_CANNOT_INHERIT_FROM_NON_SHARED_s, objType->name.AddressOf());
@@ -2695,22 +2877,22 @@ void asCBuilder::CompileClasses(asUINT numTempl)
}
}
- if( !error )
+ if (!error)
{
- if( decl->isExistingShared )
+ if (decl->isExistingShared)
{
// Verify that the base class is the same as the original shared type
- if( decl->objType->derivedFrom != objType )
+ if (CastToObjectType(decl->typeInfo)->derivedFrom != objType)
{
asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName());
+ str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName());
WriteError(str, file, node);
}
}
else
{
// Set the base class
- decl->objType->derivedFrom = objType;
+ CastToObjectType(decl->typeInfo)->derivedFrom = objType;
objType->AddRefInternal();
}
}
@@ -2725,13 +2907,21 @@ void asCBuilder::CompileClasses(asUINT numTempl)
node = node->next;
}
}
+}
+
+// numTempl is the number of template instances that existed in the engine before the build begun
+void asCBuilder::CompileClasses(asUINT numTempl)
+{
+ asUINT n;
+ asCArray toValidate((int)classDeclarations.GetLength());
+
// Order class declarations so that base classes are compiled before derived classes.
// This will allow the derived classes to copy properties and methods in the next step.
for( n = 0; n < classDeclarations.GetLength(); n++ )
{
sClassDeclaration *decl = classDeclarations[n];
- asCObjectType *derived = decl->objType;
+ asCObjectType *derived = CastToObjectType(decl->typeInfo);
asCObjectType *base = derived->derivedFrom;
if( base == 0 ) continue;
@@ -2740,7 +2930,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
for( asUINT m = n+1; m < classDeclarations.GetLength(); m++ )
{
sClassDeclaration *declBase = classDeclarations[m];
- if( base == declBase->objType )
+ if( base == declBase->typeInfo )
{
classDeclarations.RemoveIndex(n);
classDeclarations.PushLast(decl);
@@ -2756,6 +2946,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
for( n = 0; n < classDeclarations.GetLength(); n++ )
{
sClassDeclaration *decl = classDeclarations[n];
+ asCObjectType *ot = CastToObjectType(decl->typeInfo);
if( decl->isExistingShared )
{
// Set the declaration as validated already, so that other
@@ -2767,22 +2958,22 @@ void asCBuilder::CompileClasses(asUINT numTempl)
// compilation. We do not care if something that is there in the previous
// declaration is not included in the new declaration though.
- asASSERT( decl->objType->interfaces.GetLength() == decl->objType->interfaceVFTOffsets.GetLength() );
+ asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() );
}
// Methods included from mixin classes should take precedence over inherited methods
IncludeMethodsFromMixins(decl);
// Add all properties and methods from the base class
- if( !decl->isExistingShared && decl->objType->derivedFrom )
+ if( !decl->isExistingShared && ot->derivedFrom )
{
- asCObjectType *baseType = decl->objType->derivedFrom;
+ asCObjectType *baseType = ot->derivedFrom;
// The derived class inherits all interfaces from the base class
- for( unsigned int n = 0; n < baseType->interfaces.GetLength(); n++ )
+ for( unsigned int m = 0; m < baseType->interfaces.GetLength(); m++ )
{
- if( !decl->objType->Implements(baseType->interfaces[n]) )
- decl->objType->interfaces.PushLast(baseType->interfaces[n]);
+ if( !ot->Implements(baseType->interfaces[m]) )
+ ot->interfaces.PushLast(baseType->interfaces[m]);
}
// TODO: Need to check for name conflict with new class methods
@@ -2803,9 +2994,9 @@ void asCBuilder::CompileClasses(asUINT numTempl)
asCScriptFunction *baseFunc = GetFunctionDescription(baseType->methods[m]);
asCScriptFunction *derivedFunc = 0;
bool found = false;
- for( asUINT d = 0; d < decl->objType->methods.GetLength(); d++ )
+ for( asUINT d = 0; d < ot->methods.GetLength(); d++ )
{
- derivedFunc = GetFunctionDescription(decl->objType->methods[d]);
+ derivedFunc = GetFunctionDescription(ot->methods[d]);
if( baseFunc->name == "opConv" || baseFunc->name == "opImplConv" ||
baseFunc->name == "opCast" || baseFunc->name == "opImplCast" )
{
@@ -2821,8 +3012,8 @@ void asCBuilder::CompileClasses(asUINT numTempl)
}
// Move the function from the methods array to the virtualFunctionTable
- decl->objType->methods.RemoveIndex(d);
- decl->objType->virtualFunctionTable.PushLast(derivedFunc);
+ ot->methods.RemoveIndex(d);
+ ot->virtualFunctionTable.PushLast(derivedFunc);
found = true;
break;
}
@@ -2847,8 +3038,8 @@ void asCBuilder::CompileClasses(asUINT numTempl)
}
// Move the function from the methods array to the virtualFunctionTable
- decl->objType->methods.RemoveIndex(d);
- decl->objType->virtualFunctionTable.PushLast(derivedFunc);
+ ot->methods.RemoveIndex(d);
+ ot->virtualFunctionTable.PushLast(derivedFunc);
found = true;
break;
}
@@ -2858,13 +3049,13 @@ void asCBuilder::CompileClasses(asUINT numTempl)
if( !found )
{
// Push the base class function on the virtual function table
- decl->objType->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]);
+ ot->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]);
baseType->virtualFunctionTable[m]->AddRefInternal();
- CheckForConflictsDueToDefaultArgs(decl->script, decl->node, baseType->virtualFunctionTable[m], decl->objType);
+ CheckForConflictsDueToDefaultArgs(decl->script, decl->node, baseType->virtualFunctionTable[m], ot);
}
- decl->objType->methods.PushLast(baseType->methods[m]);
+ ot->methods.PushLast(baseType->methods[m]);
engine->scriptFunctions[baseType->methods[m]]->AddRefInternal();
}
}
@@ -2872,30 +3063,30 @@ void asCBuilder::CompileClasses(asUINT numTempl)
if( !decl->isExistingShared )
{
// Move this class' methods into the virtual function table
- for( asUINT m = 0; m < decl->objType->methods.GetLength(); m++ )
+ for( asUINT m = 0; m < ot->methods.GetLength(); m++ )
{
- asCScriptFunction *func = GetFunctionDescription(decl->objType->methods[m]);
+ asCScriptFunction *func = GetFunctionDescription(ot->methods[m]);
if( func->funcType != asFUNC_VIRTUAL )
{
// Move the reference from the method list to the virtual function list
- decl->objType->methods.RemoveIndex(m);
- decl->objType->virtualFunctionTable.PushLast(func);
+ ot->methods.RemoveIndex(m);
+ ot->virtualFunctionTable.PushLast(func);
// Substitute the function description in the method list for a virtual method
// Make sure the methods are in the same order as the virtual function table
- decl->objType->methods.PushLast(CreateVirtualFunction(func, (int)decl->objType->virtualFunctionTable.GetLength() - 1));
+ ot->methods.PushLast(CreateVirtualFunction(func, (int)ot->virtualFunctionTable.GetLength() - 1));
m--;
}
}
// Make virtual function table chunks for each implemented interface
- for( asUINT n = 0; n < decl->objType->interfaces.GetLength(); n++ )
+ for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ )
{
- asCObjectType *intf = decl->objType->interfaces[n];
+ asCObjectType *intf = ot->interfaces[m];
// Add all the interface's functions to the virtual function table
- asUINT offset = asUINT(decl->objType->virtualFunctionTable.GetLength());
- decl->objType->interfaceVFTOffsets.PushLast(offset);
+ asUINT offset = asUINT(ot->virtualFunctionTable.GetLength());
+ ot->interfaceVFTOffsets.PushLast(offset);
for( asUINT j = 0; j < intf->methods.GetLength(); j++ )
{
@@ -2910,15 +3101,15 @@ void asCBuilder::CompileClasses(asUINT numTempl)
//Find the interface function in the list of methods
asCScriptFunction *realFunc = 0;
- for( asUINT p = 0; p < decl->objType->methods.GetLength(); p++ )
+ for( asUINT p = 0; p < ot->methods.GetLength(); p++ )
{
- asCScriptFunction *func = GetFunctionDescription(decl->objType->methods[p]);
+ asCScriptFunction *func = GetFunctionDescription(ot->methods[p]);
if( func->signatureId == intfFunc->signatureId )
{
if( func->funcType == asFUNC_VIRTUAL )
{
- realFunc = decl->objType->virtualFunctionTable[func->vfTableIdx];
+ realFunc = ot->virtualFunctionTable[func->vfTableIdx];
}
else
{
@@ -2931,7 +3122,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
// If realFunc is still null, the interface was not
// implemented and we error out later in the checks.
- decl->objType->virtualFunctionTable.PushLast(realFunc);
+ ot->virtualFunctionTable.PushLast(realFunc);
if( realFunc )
realFunc->AddRefInternal();
}
@@ -2945,82 +3136,77 @@ void asCBuilder::CompileClasses(asUINT numTempl)
while( node && node->nodeType == snIdentifier )
node = node->next;
- while( node )
+ while( node && node->nodeType == snDeclaration )
{
- if( node->nodeType == snDeclaration )
+ asCScriptNode *nd = node->firstChild;
+
+ // Is the property declared as private or protected?
+ bool isPrivate = false, isProtected = false;
+ if( nd && nd->tokenType == ttPrivate )
{
- asCScriptNode *n = node->firstChild;
-
- // Is the property declared as private or protected?
- bool isPrivate = false, isProtected = false;
- if( n && n->tokenType == ttPrivate )
- {
- isPrivate = true;
- n = n->next;
- }
- else if( n && n->tokenType == ttProtected )
- {
- isProtected = true;
- n = n->next;
- }
-
- // Determine the type of the property
- asCScriptCode *file = decl->script;
- asCDataType dt = CreateDataTypeFromNode(n, file, decl->objType->nameSpace);
- if( decl->objType->IsShared() && dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
- {
- asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
- WriteError(msg, file, node);
- }
-
- if( dt.IsReadOnly() )
- WriteError(TXT_PROPERTY_CANT_BE_CONST, file, node);
-
- // Multiple properties can be declared separated by ,
- n = n->next;
- while( n )
- {
- asCString name(&file->code[n->tokenPos], n->tokenLength);
-
- if( !decl->isExistingShared )
- {
- CheckNameConflictMember(decl->objType, name.AddressOf(), n, file, true);
- AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, n);
- }
- else
- {
- // Verify that the property exists in the original declaration
- bool found = false;
- for( asUINT p = 0; p < decl->objType->properties.GetLength(); p++ )
- {
- asCObjectProperty *prop = decl->objType->properties[p];
- if( prop->isPrivate == isPrivate &&
- prop->isProtected == isProtected &&
- prop->name == name &&
- prop->type.IsEqualExceptRef(dt) )
- {
- found = true;
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName());
- WriteError(str, file, n);
- }
- }
-
- // Skip the initialization node
- if( n->next && n->next->nodeType != snIdentifier )
- n = n->next;
-
- n = n->next;
- }
+ isPrivate = true;
+ nd = nd->next;
+ }
+ else if( nd && nd->tokenType == ttProtected )
+ {
+ isProtected = true;
+ nd = nd->next;
+ }
+
+ // Determine the type of the property
+ asCScriptCode *file = decl->script;
+ asCDataType dt = CreateDataTypeFromNode(nd, file, ot->nameSpace, false, ot);
+ if( ot->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
+ {
+ asCString msg;
+ msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
+ WriteError(msg, file, node);
+ }
+
+ if( dt.IsReadOnly() )
+ WriteError(TXT_PROPERTY_CANT_BE_CONST, file, node);
+
+ // Multiple properties can be declared separated by ,
+ nd = nd->next;
+ while( nd )
+ {
+ asCString name(&file->code[nd->tokenPos], nd->tokenLength);
+
+ if( !decl->isExistingShared )
+ {
+ CheckNameConflictMember(ot, name.AddressOf(), nd, file, true);
+ AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, nd);
+ }
+ else
+ {
+ // Verify that the property exists in the original declaration
+ bool found = false;
+ for( asUINT p = 0; p < ot->properties.GetLength(); p++ )
+ {
+ asCObjectProperty *prop = ot->properties[p];
+ if( prop->isPrivate == isPrivate &&
+ prop->isProtected == isProtected &&
+ prop->name == name &&
+ prop->type.IsEqualExceptRef(dt) )
+ {
+ found = true;
+ break;
+ }
+ }
+ if( !found )
+ {
+ asCString str;
+ str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName());
+ WriteError(str, file, nd);
+ }
+ }
+
+ // Skip the initialization node
+ if( nd->next && nd->next->nodeType != snIdentifier )
+ nd = nd->next;
+
+ nd = nd->next;
}
- else
- asASSERT(false);
node = node->next;
}
@@ -3031,7 +3217,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
if( !decl->isExistingShared )
toValidate.PushLast(decl);
- asASSERT( decl->objType->interfaces.GetLength() == decl->objType->interfaceVFTOffsets.GetLength() );
+ asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() );
}
// TODO: Warn if a method overrides a base method without marking it as 'override'.
@@ -3048,13 +3234,14 @@ void asCBuilder::CompileClasses(asUINT numTempl)
sClassDeclaration *decl = classDeclarations[n];
if( decl->isExistingShared ) continue;
- asCArray overrideValidations(decl->objType->GetMethodCount());
- for( asUINT k = 0; k < decl->objType->methods.GetLength(); k++ )
- overrideValidations.PushLast( !static_cast(decl->objType->GetMethodByIndex(k, false))->IsOverride() );
+ asCObjectType *ot = CastToObjectType(decl->typeInfo);
+ asCArray overrideValidations(ot->GetMethodCount());
+ for( asUINT k = 0; k < ot->methods.GetLength(); k++ )
+ overrideValidations.PushLast( !static_cast(ot->GetMethodByIndex(k, false))->IsOverride() );
- for( asUINT m = 0; m < decl->objType->interfaces.GetLength(); m++ )
+ for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ )
{
- asCObjectType *objType = decl->objType->interfaces[m];
+ asCObjectType *objType = ot->interfaces[m];
for( asUINT i = 0; i < objType->methods.GetLength(); i++ )
{
// Only check the interface methods that was explicitly declared in this interface
@@ -3063,7 +3250,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
continue;
asUINT overrideIndex;
- if( !DoesMethodExist(decl->objType, objType->methods[i], &overrideIndex) )
+ if( !DoesMethodExist(ot, objType->methods[i], &overrideIndex) )
{
asCString str;
str.Format(TXT_MISSING_IMPLEMENTATION_OF_s,
@@ -3075,14 +3262,14 @@ void asCBuilder::CompileClasses(asUINT numTempl)
}
}
- bool hasBaseClass = decl->objType->derivedFrom != 0;
+ bool hasBaseClass = ot->derivedFrom != 0;
for( asUINT j = 0; j < overrideValidations.GetLength(); j++ )
{
- if( !overrideValidations[j] && (!hasBaseClass || !DoesMethodExist(decl->objType->derivedFrom, decl->objType->methods[j])) )
+ if( !overrideValidations[j] && (!hasBaseClass || !DoesMethodExist(ot->derivedFrom, ot->methods[j])) )
{
asCString msg;
- msg.Format(TXT_METHOD_s_DOES_NOT_OVERRIDE, decl->objType->GetMethodByIndex(j, false)->GetDeclaration());
+ msg.Format(TXT_METHOD_s_DOES_NOT_OVERRIDE, ot->GetMethodByIndex(j, false)->GetDeclaration());
WriteError(msg, decl->script, decl->node);
}
}
@@ -3098,15 +3285,16 @@ void asCBuilder::CompileClasses(asUINT numTempl)
while( toValidate.GetLength() > 0 )
{
sClassDeclaration *decl = toValidate[toValidate.GetLength()-1];
+ asCObjectType *ot = CastToObjectType(decl->typeInfo);
int validState = 1;
- for( asUINT n = 0; n < decl->objType->properties.GetLength(); n++ )
+ for( n = 0; n < ot->properties.GetLength(); n++ )
{
// A valid structure is one that uses only primitives or other valid objects
- asCObjectProperty *prop = decl->objType->properties[n];
+ asCObjectProperty *prop = ot->properties[n];
asCDataType dt = prop->type;
// TODO: Add this check again, once solving the issues commented below
- /*
+ /*
if( dt.IsTemplate() )
{
// TODO: This must verify all sub types, not just the first one
@@ -3127,7 +3315,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
sClassDeclaration *pdecl = 0;
for( asUINT p = 0; p < classDeclarations.GetLength(); p++ )
{
- if( classDeclarations[p]->objType == dt.GetObjectType() )
+ if( classDeclarations[p]->typeInfo == dt.GetTypeInfo() )
{
pdecl = classDeclarations[p];
break;
@@ -3136,7 +3324,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
if( pdecl )
{
- if( pdecl->objType == decl->objType )
+ if( pdecl->typeInfo == decl->typeInfo )
{
WriteError(TXT_ILLEGAL_MEMBER_TYPE, decl->script, decl->node);
validState = 2;
@@ -3198,9 +3386,11 @@ void asCBuilder::CompileClasses(asUINT numTempl)
// Existing shared classes won't need evaluating, nor interfaces
sClassDeclaration *decl = classDeclarations[n];
if( decl->isExistingShared ) continue;
- if( decl->objType->IsInterface() ) continue;
- typesToValidate.PushLast(decl->objType);
+ asCObjectType *ot = CastToObjectType(decl->typeInfo);
+ if( ot->IsInterface() ) continue;
+
+ typesToValidate.PushLast(ot);
}
asUINT numReevaluations = 0;
@@ -3208,7 +3398,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
{
if( numReevaluations > typesToValidate.GetLength() )
{
- // No types could be completely evaluated in the last iteration so
+ // No types could be completely evaluated in the last iteration so
// we consider the remaining types in the array as garbage collected
break;
}
@@ -3233,7 +3423,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
// Evaluate template instances (silently) before verifying each of the classes, since it is possible that
// a class will be marked as non-garbage collected, which in turn will mark the template instance that uses
- // it as non-garbage collected, which in turn means the class that contains the array also do not have to be
+ // it as non-garbage collected, which in turn means the class that contains the array also do not have to be
// garbage collected
EvaluateTemplateInstances(numTempl, true);
@@ -3244,10 +3434,28 @@ void asCBuilder::CompileClasses(asUINT numTempl)
for( asUINT p = 0; p < type->properties.GetLength(); p++ )
{
asCDataType dt = type->properties[p]->type;
+
+ if (dt.IsFuncdef())
+ {
+ // If a class holds a function pointer as member then the class must be garbage collected as the
+ // function pointer can form circular references with the class through use of a delegate. Example:
+ //
+ // class A { B @b; void f(); }
+ // class B { F @f; }
+ // funcdef void F();
+ //
+ // A a;
+ // @a.b = B(); // instance of A refers to instance of B
+ // @a.b.f = F(a.f); // instance of B refers to delegate that refers to instance of A
+ //
+ gc = true;
+ break;
+ }
+
if( !dt.IsObject() )
continue;
- if( typesToValidate.Exists(dt.GetObjectType()) )
+ if( typesToValidate.Exists(CastToObjectType(dt.GetTypeInfo())) )
mustReevaluate = true;
else
{
@@ -3255,9 +3463,9 @@ void asCBuilder::CompileClasses(asUINT numTempl)
{
// Check if any of the subtypes are yet to be evaluated
bool skip = false;
- for( asUINT s = 0; s < dt.GetObjectType()->GetSubTypeCount(); s++ )
+ for( asUINT s = 0; s < dt.GetTypeInfo()->GetSubTypeCount(); s++ )
{
- asCObjectType *t = reinterpret_cast(dt.GetObjectType()->GetSubType(s));
+ asCObjectType *t = reinterpret_cast(dt.GetTypeInfo()->GetSubType(s));
if( typesToValidate.Exists(t) )
{
mustReevaluate = true;
@@ -3273,7 +3481,7 @@ void asCBuilder::CompileClasses(asUINT numTempl)
{
// If it is known that the handle can't be involved in a circular reference
// then this object doesn't need to be marked as garbage collected.
- asCObjectType *prop = dt.GetObjectType();
+ asCObjectType *prop = CastToObjectType(dt.GetTypeInfo());
if( prop->flags & asOBJ_SCRIPT_OBJECT )
{
@@ -3292,13 +3500,13 @@ void asCBuilder::CompileClasses(asUINT numTempl)
if( sdt.IsObjectHandle() )
{
// TODO: runtime optimize: If the handle is again to a final class, then we can recursively check if the circular reference can occur
- if( sdt.GetObjectType()->flags & (asOBJ_SCRIPT_OBJECT | asOBJ_GC) )
+ if( sdt.GetTypeInfo()->flags & (asOBJ_SCRIPT_OBJECT | asOBJ_GC) )
{
gc = true;
break;
}
}
- else if( sdt.GetObjectType()->flags & asOBJ_GC )
+ else if( sdt.GetTypeInfo()->flags & asOBJ_GC )
{
// TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is.
// Only if the object is of a type that can reference this type, either directly or indirectly
@@ -3321,14 +3529,14 @@ void asCBuilder::CompileClasses(asUINT numTempl)
else if( prop->flags & asOBJ_GC )
{
// If a type is not a script object, adopt its GC flag
- // TODO: runtime optimize: Just because an application registered class is garbage collected, doesn't mean it
+ // TODO: runtime optimize: Just because an application registered class is garbage collected, doesn't mean it
// can form a circular reference with this script class. Perhaps need a flag to tell
// if the script classes that contains the type should be garbage collected or not.
gc = true;
break;
}
}
- else if( dt.GetObjectType()->flags & asOBJ_GC )
+ else if( dt.GetTypeInfo()->flags & asOBJ_GC )
{
// TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is.
// Only if the object is of a type that can reference this type, either directly or indirectly
@@ -3338,8 +3546,8 @@ void asCBuilder::CompileClasses(asUINT numTempl)
}
}
- // If the class wasn't found to require garbage collection, but it
- // contains another type that has yet to be evaluated then it must be
+ // If the class wasn't found to require garbage collection, but it
+ // contains another type that has yet to be evaluated then it must be
// re-evaluated.
if( !gc && mustReevaluate )
{
@@ -3376,7 +3584,7 @@ void asCBuilder::IncludeMethodsFromMixins(sClassDeclaration *decl)
{
asSNameSpace *ns;
asCString name;
- if( GetNamespaceAndNameFromNode(node, decl->script, decl->objType->nameSpace, ns, name) < 0 )
+ if( GetNamespaceAndNameFromNode(node, decl->script, decl->typeInfo->nameSpace, ns, name) < 0 )
{
node = node->next;
continue;
@@ -3385,11 +3593,11 @@ void asCBuilder::IncludeMethodsFromMixins(sClassDeclaration *decl)
sMixinClass *mixin = 0;
while( ns )
{
- // Need to make sure the name is not an object type
+ // Need to make sure the name is not an object type
asCObjectType *objType = GetObjectType(name.AddressOf(), ns);
if( objType == 0 )
mixin = GetMixinClass(name.AddressOf(), ns);
-
+
if( objType || mixin )
break;
@@ -3416,7 +3624,7 @@ void asCBuilder::IncludeMethodsFromMixins(sClassDeclaration *decl)
asCScriptNode *copy = n->CreateCopy(engine);
// Register the method, but only if it doesn't already exist in the class
- RegisterScriptFunctionFromNode(copy, mixin->script, decl->objType, false, false, mixin->ns, false, true);
+ RegisterScriptFunctionFromNode(copy, mixin->script, CastToObjectType(decl->typeInfo), false, false, mixin->ns, false, true);
}
else if( n->nodeType == snVirtualProperty )
{
@@ -3450,7 +3658,7 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl)
{
asSNameSpace *ns;
asCString name;
- if( GetNamespaceAndNameFromNode(node, decl->script, decl->objType->nameSpace, ns, name) < 0 )
+ if( GetNamespaceAndNameFromNode(node, decl->script, decl->typeInfo->nameSpace, ns, name) < 0 )
{
node = node->next;
continue;
@@ -3459,11 +3667,11 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl)
sMixinClass *mixin = 0;
while( ns )
{
- // Need to make sure the name is not an object type
+ // Need to make sure the name is not an object type
asCObjectType *objType = GetObjectType(name.AddressOf(), ns);
if( objType == 0 )
mixin = GetMixinClass(name.AddressOf(), ns);
-
+
if( objType || mixin )
break;
@@ -3501,10 +3709,10 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl)
asCScriptCode *file = mixin->script;
asCDataType dt = CreateDataTypeFromNode(n2, file, mixin->ns);
- if( decl->objType->IsShared() && dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
+ if( decl->typeInfo->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
{
asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
+ msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
WriteError(msg, file, n);
WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node);
}
@@ -3515,12 +3723,13 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl)
n2 = n2->next;
while( n2 )
{
- asCString name(&file->code[n2->tokenPos], n2->tokenLength);
+ name.Assign(&file->code[n2->tokenPos], n2->tokenLength);
// Add the property only if it doesn't already exist in the class
bool exists = false;
- for( asUINT p = 0; p < decl->objType->properties.GetLength(); p++ )
- if( decl->objType->properties[p]->name == name )
+ asCObjectType *ot = CastToObjectType(decl->typeInfo);
+ for( asUINT p = 0; p < ot->properties.GetLength(); p++ )
+ if( ot->properties[p]->name == name )
{
exists = true;
break;
@@ -3531,7 +3740,7 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl)
if( !decl->isExistingShared )
{
// It must not conflict with the name of methods
- int r = CheckNameConflictMember(decl->objType, name.AddressOf(), n2, file, true);
+ int r = CheckNameConflictMember(ot, name.AddressOf(), n2, file, true);
if( r < 0 )
WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node);
@@ -3541,9 +3750,9 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl)
{
// Verify that the property exists in the original declaration
bool found = false;
- for( asUINT p = 0; p < decl->objType->properties.GetLength(); p++ )
+ for( asUINT p = 0; p < ot->properties.GetLength(); p++ )
{
- asCObjectProperty *prop = decl->objType->properties[p];
+ asCObjectProperty *prop = ot->properties[p];
if( prop->isPrivate == isPrivate &&
prop->isProtected == isProtected &&
prop->name == name &&
@@ -3556,7 +3765,7 @@ void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl)
if( !found )
{
asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName());
+ str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName());
WriteError(str, decl->script, decl->node);
WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node);
}
@@ -3590,15 +3799,14 @@ int asCBuilder::CreateVirtualFunction(asCScriptFunction *func, int idx)
vf->parameterTypes = func->parameterTypes;
vf->inOutFlags = func->inOutFlags;
vf->id = engine->GetNextScriptFunctionId();
- vf->isReadOnly = func->isReadOnly;
vf->objectType = func->objectType;
vf->objectType->AddRefInternal();
vf->signatureId = func->signatureId;
- vf->isPrivate = func->isPrivate;
- vf->isProtected = func->isProtected;
- vf->isFinal = func->isFinal;
- vf->isOverride = func->isOverride;
vf->vfTableIdx = idx;
+ vf->traits = func->traits;
+
+ // Clear the shared trait since the virtual function should not have that
+ vf->SetShared(false);
// It is not necessary to copy the default args, as they have no meaning in the virtual function
@@ -3623,12 +3831,12 @@ asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const
{
asCString str;
if( dt.IsAbstractClass() )
- str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->objType->nameSpace).AddressOf());
+ str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->typeInfo->nameSpace).AddressOf());
else if( dt.IsInterface() )
- str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->objType->nameSpace).AddressOf());
+ str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->typeInfo->nameSpace).AddressOf());
else
// TODO: Improve error message to explain why
- str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(decl->objType->nameSpace).AddressOf());
+ str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(decl->typeInfo->nameSpace).AddressOf());
WriteError(str, file, node);
}
return 0;
@@ -3654,7 +3862,7 @@ asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const
}
// Add the property to the object type
- return decl->objType->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited);
+ return CastToObjectType(decl->typeInfo)->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited);
}
bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex)
@@ -3667,7 +3875,7 @@ bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId, asUINT *m
if( m->name != method->name ) continue;
if( m->returnType != method->returnType ) continue;
- if( m->isReadOnly != method->isReadOnly ) continue;
+ if( m->IsReadOnly() != method->IsReadOnly() ) continue;
if( m->parameterTypes != method->parameterTypes ) continue;
if( m->inOutFlags != method->inOutFlags ) continue;
@@ -3692,7 +3900,7 @@ void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *fi
// Add the script function
// TODO: declaredAt should be set to where the class has been declared
- module->AddScriptFunction(file->idx, 0, funcId, objType->name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, false, objType);
+ module->AddScriptFunction(file->idx, 0, funcId, objType->name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, false, objType, false, asSFunctionTraits(), objType->nameSpace);
// Set it as default constructor
if( objType->beh.construct )
@@ -3735,18 +3943,24 @@ void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *fi
// If the object is shared, then the factory must also be marked as shared
if( objType->flags & asOBJ_SHARED )
- engine->scriptFunctions[funcId]->isShared = true;
+ engine->scriptFunctions[funcId]->SetShared(true);
}
int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns)
{
// Is it a shared enum?
bool isShared = false;
- asCObjectType *existingSharedType = 0;
+ bool isExternal = false;
+ asCEnumType *existingSharedType = 0;
asCScriptNode *tmp = node->firstChild;
- if( tmp->nodeType == snIdentifier && file->TokenEquals(tmp->tokenPos, tmp->tokenLength, SHARED_TOKEN) )
+ while( tmp->nodeType == snIdentifier )
{
- isShared = true;
+ if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, SHARED_TOKEN))
+ isShared = true;
+ else if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, EXTERNAL_TOKEN))
+ isExternal = true;
+ else
+ break;
tmp = tmp->next;
}
@@ -3761,24 +3975,36 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp
// Look for a pre-existing shared enum with the same signature
for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
{
- asCObjectType *o = engine->sharedScriptTypes[n];
+ asCTypeInfo *o = engine->sharedScriptTypes[n];
if( o &&
o->IsShared() &&
(o->flags & asOBJ_ENUM) &&
o->name == name &&
o->nameSpace == ns )
{
- existingSharedType = o;
+ existingSharedType = CastToEnumType(o);
break;
}
}
}
+ // If the enum was declared as external then it must have been compiled in a different module first
+ if (isExternal && existingSharedType == 0)
+ {
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf());
+ WriteError(str, file, tmp);
+ }
+
+ // Remember if the type was declared as external so the saved bytecode can be flagged accordingly
+ if (isExternal && existingSharedType)
+ module->externalTypes.PushLast(existingSharedType);
+
// Check the name and add the enum
int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file, ns);
if( asSUCCESS == r )
{
- asCObjectType *st;
+ asCEnumType *st;
if( existingSharedType )
{
@@ -3787,7 +4013,7 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp
}
else
{
- st = asNEW(asCObjectType)(engine);
+ st = asNEW(asCEnumType)(engine);
if( st == 0 )
return asOUT_OF_MEMORY;
@@ -3814,19 +4040,31 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp
decl->name = name;
decl->script = file;
- decl->objType = st;
+ decl->typeInfo = st;
namedTypeDeclarations.PushLast(decl);
asCDataType type = CreateDataTypeFromNode(tmp, file, ns);
asASSERT(!type.IsReference());
+ // External shared enums must not redeclare the enum values
+ if (isExternal && (tmp->next == 0 || tmp->next->tokenType != ttEndStatement) )
+ {
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf());
+ WriteError(str, file, tmp);
+ }
+ else if (!isExternal && tmp->next && tmp->next->tokenType == ttEndStatement)
+ {
+ asCString str;
+ str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf());
+ WriteError(str, file, tmp);
+ }
+
// Register the enum values
tmp = tmp->next;
- while( tmp )
+ while( tmp && tmp->nodeType == snIdentifier )
{
- asASSERT(snIdentifier == tmp->nodeType);
-
- asCString name(&file->code[tmp->tokenPos], tmp->tokenLength);
+ name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength);
if( existingSharedType )
{
@@ -3890,7 +4128,7 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp
gvar->ns = ns;
// No need to allocate space on the global memory stack since the values are stored in the asCObjectType
// Set the index to a negative to allow compiler to diferentiate from ordinary global var when compiling the initialization
- gvar->index = -1;
+ gvar->index = -1;
gvar->isCompiled = false;
gvar->isPureConstant = true;
gvar->isEnumValue = true;
@@ -3935,11 +4173,11 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam
// If the name is not already in use add it
int r = CheckNameConflict(name.AddressOf(), tmp, file, ns);
- asCObjectType *st = 0;
+ asCTypedefType *st = 0;
if( asSUCCESS == r )
{
// Create the new type
- st = asNEW(asCObjectType)(engine);
+ st = asNEW(asCTypedefType)(engine);
if( st == 0 )
r = asOUT_OF_MEMORY;
}
@@ -3950,7 +4188,7 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam
st->size = dataType.GetSizeInMemoryBytes();
st->name = name;
st->nameSpace = ns;
- st->templateSubTypes.PushLast(dataType);
+ st->aliasForType = dataType;
st->module = module;
module->typeDefs.PushLast(st);
@@ -3963,7 +4201,7 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam
{
decl->name = name;
decl->script = file;
- decl->objType = st;
+ decl->typeInfo = st;
namedTypeDeclarations.PushLast(decl);
}
}
@@ -3973,34 +4211,41 @@ int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNam
return r;
}
-void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, bool &isConstMethod, bool &isConstructor, bool &isDestructor, bool &isPrivate, bool &isProtected, bool &isOverride, bool &isFinal, bool &isShared, asSNameSpace *implicitNamespace)
+void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits &funcTraits, asSNameSpace *implicitNamespace)
{
node = node->firstChild;
+ // Is the function shared?
+ funcTraits.SetTrait(asTRAIT_SHARED, false);
+ funcTraits.SetTrait(asTRAIT_EXTERNAL, false);
+ while (node->tokenType == ttIdentifier)
+ {
+ if (file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN))
+ funcTraits.SetTrait(asTRAIT_SHARED, true);
+ else if (file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN))
+ funcTraits.SetTrait(asTRAIT_EXTERNAL, true);
+ else
+ break;
+ node = node->next;
+ }
+
// Is the function a private or protected class method?
- isPrivate = false, isProtected = false;
+ funcTraits.SetTrait(asTRAIT_PRIVATE, false);
+ funcTraits.SetTrait(asTRAIT_PROTECTED, false);
if( node->tokenType == ttPrivate )
{
- isPrivate = true;
+ funcTraits.SetTrait(asTRAIT_PRIVATE, true);
node = node->next;
}
else if( node->tokenType == ttProtected )
{
- isProtected = true;
- node = node->next;
- }
-
- // Is the function shared?
- isShared = false;
- if( node->tokenType == ttIdentifier && file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) )
- {
- isShared = true;
+ funcTraits.SetTrait(asTRAIT_PROTECTED, true);
node = node->next;
}
// Find the name
- isConstructor = false;
- isDestructor = false;
+ funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, false);
+ funcTraits.SetTrait(asTRAIT_DESTRUCTOR, false);
asCScriptNode *n = 0;
if( node->nodeType == snDataType )
n = node->next->next;
@@ -4010,27 +4255,26 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi
if( node->tokenType == ttBitNot )
{
n = node->next;
- isDestructor = true;
+ funcTraits.SetTrait(asTRAIT_DESTRUCTOR, true);
}
else
{
n = node;
- isConstructor = true;
+ funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, true);
}
}
name.Assign(&file->code[n->tokenPos], n->tokenLength);
- // Initialize a script function object for registration
- if( !isConstructor && !isDestructor )
+ if( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) )
{
- returnType = CreateDataTypeFromNode(node, file, implicitNamespace);
+ returnType = CreateDataTypeFromNode(node, file, implicitNamespace, false, objType);
returnType = ModifyDataTypeFromNode(returnType, node->next, file, 0, 0);
if( engine->ep.disallowValueAssignForRefType &&
- returnType.GetObjectType() &&
- (returnType.GetObjectType()->flags & asOBJ_REF) &&
- !(returnType.GetObjectType()->flags & asOBJ_SCOPED) &&
- !returnType.IsReference() &&
+ returnType.GetTypeInfo() &&
+ (returnType.GetTypeInfo()->flags & asOBJ_REF) &&
+ !(returnType.GetTypeInfo()->flags & asOBJ_SCOPED) &&
+ !returnType.IsReference() &&
!returnType.IsObjectHandle() )
{
WriteError(TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL, file, node);
@@ -4039,9 +4283,9 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi
else
returnType = asCDataType::CreatePrimitive(ttVoid, false);
- isConstMethod = false;
- isFinal = false;
- isOverride = false;
+ funcTraits.SetTrait(asTRAIT_CONST, false);
+ funcTraits.SetTrait(asTRAIT_FINAL, false);
+ funcTraits.SetTrait(asTRAIT_OVERRIDE, false);
if( objType && n->next->next )
{
@@ -4050,16 +4294,16 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi
// Is this a const method?
if( decorator->tokenType == ttConst )
{
- isConstMethod = true;
+ funcTraits.SetTrait(asTRAIT_CONST, true);
decorator = decorator->next;
}
while( decorator )
{
if( decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, FINAL_TOKEN) )
- isFinal = true;
+ funcTraits.SetTrait(asTRAIT_FINAL, true);
else if( decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, OVERRIDE_TOKEN) )
- isOverride = true;
+ funcTraits.SetTrait(asTRAIT_OVERRIDE, true);
decorator = decorator->next;
}
@@ -4087,14 +4331,14 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi
while( n )
{
asETypeModifiers inOutFlag;
- asCDataType type = CreateDataTypeFromNode(n, file, implicitNamespace);
+ asCDataType type = CreateDataTypeFromNode(n, file, implicitNamespace, false, objType);
type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0);
if( engine->ep.disallowValueAssignForRefType &&
- type.GetObjectType() &&
- (type.GetObjectType()->flags & asOBJ_REF) &&
- !(type.GetObjectType()->flags & asOBJ_SCOPED) &&
- !type.IsReference() &&
+ type.GetTypeInfo() &&
+ (type.GetTypeInfo()->flags & asOBJ_REF) &&
+ !(type.GetTypeInfo()->flags & asOBJ_SCOPED) &&
+ !type.IsReference() &&
!type.IsObjectHandle() )
{
WriteError(TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL, file, node);
@@ -4108,9 +4352,8 @@ void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *fi
n = n->next->next;
if( n && n->nodeType == snIdentifier )
{
- asCString name;
- name.Assign(&file->code[n->tokenPos], n->tokenLength);
- parameterNames.PushLast(name);
+ asCString paramName(&file->code[n->tokenPos], n->tokenLength);
+ parameterNames.PushLast(paramName);
n = n->next;
}
else
@@ -4167,14 +4410,7 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod
asCArray parameterTypes;
asCArray inOutFlags;
asCArray defaultArgs;
- bool isConstMethod;
- bool isOverride;
- bool isFinal;
- bool isConstructor;
- bool isDestructor;
- bool isPrivate;
- bool isProtected;
- bool isShared;
+ asSFunctionTraits funcTraits;
asASSERT( (objType && ns == 0) || isGlobalFunction || isMixin );
@@ -4187,9 +4423,9 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod
ns = engine->nameSpaces[0];
}
- GetParsedFunctionDetails(node, file, objType, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared, ns);
+ GetParsedFunctionDetails(node, file, objType, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns);
- return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared);
+ return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits);
}
asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns)
@@ -4212,7 +4448,7 @@ asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode
// Get the return and parameter types from the funcDef
asCString funcName = name;
- int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, false, false, false, false, false, false, false, false);
+ int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, asSFunctionTraits());
if( r < 0 )
return 0;
@@ -4220,7 +4456,7 @@ asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode
return engine->scriptFunctions[functions[functions.GetLength()-1]->funcId];
}
-int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isProtected, bool isOverride, bool isFinal, bool isShared)
+int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits funcTraits)
{
// Determine default namespace if not specified
if( ns == 0 )
@@ -4237,7 +4473,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
// Should validate that the function really exists in the class/interface
bool found = false;
- if( isConstructor || isDestructor )
+ if(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) || funcTraits.GetTrait(asTRAIT_DESTRUCTOR) )
{
// TODO: shared: Should check the existance of these too
found = true;
@@ -4248,7 +4484,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
{
asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]];
if( func->name == name &&
- func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, isConstMethod) )
+ func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) )
{
// Add the shared function in this module too
module->AddScriptFunction(func);
@@ -4276,7 +4512,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
}
// Check for name conflicts
- if( !isConstructor && !isDestructor )
+ if( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) )
{
if( objType )
{
@@ -4308,14 +4544,14 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
if( name != objType->name )
{
asCString str;
- if( isDestructor )
+ if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR) )
str.Format(TXT_DESTRUCTOR_s_s_NAME_ERROR, objType->name.AddressOf(), name.AddressOf());
else
str.Format(TXT_METHOD_s_s_HAS_NO_RETURN_TYPE, objType->name.AddressOf(), name.AddressOf());
WriteError(str, file, node);
}
- if( isDestructor )
+ if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR))
name = "~" + name;
}
@@ -4344,14 +4580,14 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
func->isExistingShared = false;
func->paramNames = parameterNames;
- if( isShared )
+ if(funcTraits.GetTrait(asTRAIT_SHARED))
{
// Look for a pre-existing shared function with the same signature
for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ )
{
asCScriptFunction *f = engine->scriptFunctions[n];
if( f &&
- f->isShared &&
+ f->IsShared() &&
f->name == name &&
f->nameSpace == ns &&
f->objectType == objType &&
@@ -4363,30 +4599,58 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
}
}
}
+
+ // Remember if the function was declared as external so the saved bytecode can be flagged accordingly
+ if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && func->isExistingShared)
+ module->externalFunctions.PushLast(engine->scriptFunctions[func->funcId]);
+
+ if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !func->isExistingShared)
+ {
+ // Mark it as existing shared to avoid compiling it
+ func->isExistingShared = true;
+
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf());
+ WriteError(str, file, node);
+ }
+
+ // External shared function must not try to redefine the interface
+ if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->tokenType == ttEndStatement || node->lastChild->tokenType == ttEndStatement))
+ {
+ asCString str;
+ str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf());
+ WriteError(str, file, node);
+ }
+ else if (!funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->nodeType == snStatementBlock || node->lastChild->nodeType == snStatementBlock) )
+ {
+ asCString str;
+ str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf());
+ WriteError(str, file, node);
+ }
}
// Destructors may not have any parameters
- if( isDestructor && parameterTypes.GetLength() > 0 )
+ if (funcTraits.GetTrait(asTRAIT_DESTRUCTOR) && parameterTypes.GetLength() > 0)
WriteError(TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM, file, node);
// If a function, class, or interface is shared then only shared types may be used in the signature
- if( (objType && objType->IsShared()) || isShared )
+ if( (objType && objType->IsShared()) || funcTraits.GetTrait(asTRAIT_SHARED))
{
- asCObjectType *ot = returnType.GetObjectType();
- if( ot && !ot->IsShared() )
+ asCTypeInfo *ti = returnType.GetTypeInfo();
+ if( ti && !ti->IsShared() )
{
asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
+ msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->name.AddressOf());
WriteError(msg, file, node);
}
for( asUINT p = 0; p < parameterTypes.GetLength(); ++p )
{
- asCObjectType *ot = parameterTypes[p].GetObjectType();
- if( ot && !ot->IsShared() )
+ ti = parameterTypes[p].GetTypeInfo();
+ if( ti && !ti->IsShared() )
{
asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
+ msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->name.AddressOf());
WriteError(msg, file, node);
}
}
@@ -4404,7 +4668,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
for( asUINT n = 0; n < funcs.GetLength(); ++n )
{
asCScriptFunction *func = GetFunctionDescription(funcs[n]);
- if( func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, isConstMethod) )
+ if( func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) )
{
// TODO: clean up: Reuse the same error handling for both opConv and normal methods
if( isMixin )
@@ -4412,11 +4676,11 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
// Clean up the memory, as the function will not be registered
if( node )
node->Destroy(engine);
- sFunctionDescription *func = functions.PopLast();
- asDELETE(func, sFunctionDescription);
+ sFunctionDescription *funcDesc = functions.PopLast();
+ asDELETE(funcDesc, sFunctionDescription);
// Free the default args
- for( asUINT n = 0; n < defaultArgs.GetLength(); n++ )
+ for( n = 0; n < defaultArgs.GetLength(); n++ )
if( defaultArgs[n] )
asDELETE(defaultArgs[n], asCString);
@@ -4433,18 +4697,18 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
for( asUINT n = 0; n < funcs.GetLength(); ++n )
{
asCScriptFunction *func = GetFunctionDescription(funcs[n]);
- if( func->IsSignatureExceptNameAndReturnTypeEqual(parameterTypes, inOutFlags, objType, isConstMethod) )
+ if( func->IsSignatureExceptNameAndReturnTypeEqual(parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) )
{
if( isMixin )
{
// Clean up the memory, as the function will not be registered
if( node )
node->Destroy(engine);
- sFunctionDescription *func = functions.PopLast();
- asDELETE(func, sFunctionDescription);
+ sFunctionDescription *funcDesc = functions.PopLast();
+ asDELETE(funcDesc, sFunctionDescription);
// Free the default args
- for( asUINT n = 0; n < defaultArgs.GetLength(); n++ )
+ for( n = 0; n < defaultArgs.GetLength(); n++ )
if( defaultArgs[n] )
asDELETE(defaultArgs[n], asCString);
@@ -4476,7 +4740,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
int row = 0, col = 0;
if( node )
file->ConvertPosToRowCol(node->tokenPos, &row, &col);
- module->AddScriptFunction(file->idx, (row&0xFFFFF)|((col&0xFFF)<<20), funcId, name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, isInterface, objType, isConstMethod, isGlobalFunction, isPrivate, isProtected, isFinal, isOverride, isShared, ns);
+ module->AddScriptFunction(file->idx, (row&0xFFFFF)|((col&0xFFF)<<20), funcId, name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, isInterface, objType, isGlobalFunction, funcTraits, ns);
}
// Make sure the default args are declared correctly
@@ -4488,7 +4752,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
asASSERT( !isExistingShared );
engine->scriptFunctions[funcId]->AddRefInternal();
- if( isConstructor )
+ if(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR))
{
int factoryId = engine->GetNextScriptFunctionId();
if( parameterTypes.GetLength() == 0 )
@@ -4521,7 +4785,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
// If the object is shared, then the factory must also be marked as shared
if( objType->flags & asOBJ_SHARED )
- engine->scriptFunctions[factoryId]->isShared = true;
+ engine->scriptFunctions[factoryId]->SetShared(true);
// Add a dummy function to the builder so that it doesn't mix up the fund Ids
functions.PushLast(0);
@@ -4531,14 +4795,14 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]);
engine->scriptFunctions[factoryId]->AddRefInternal();
}
- else if( isDestructor )
+ else if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR))
objType->beh.destruct = funcId;
else
{
// If the method is the assignment operator we need to replace the default implementation
asCScriptFunction *f = engine->scriptFunctions[funcId];
if( f->name == "opAssign" && f->parameterTypes.GetLength() == 1 &&
- f->parameterTypes[0].GetObjectType() == f->objectType &&
+ f->parameterTypes[0].GetTypeInfo() == f->objectType &&
(f->inOutFlags[0] & asTM_INREF) )
{
engine->scriptFunctions[objType->beh.copy]->ReleaseInternal();
@@ -4603,14 +4867,12 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file
WriteError(TXT_PROPERTY_WITHOUT_ACCESSOR, file, node);
node = node->next;
- while( node )
+ while (node)
{
- asCScriptNode *next = node->next;
- asCScriptNode *funcNode = 0;
- bool success = false;
- bool isConst = false;
- bool isFinal = false;
- bool isOverride = false;
+ asCScriptNode *next = node->next;
+ asCScriptNode *funcNode = 0;
+ bool success = false;
+ asSFunctionTraits funcTraits;
asCDataType returnType;
asCArray paramNames;
asCArray paramTypes;
@@ -4618,33 +4880,44 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file
asCArray defaultArgs;
asCString name;
+ funcTraits.SetTrait(asTRAIT_PRIVATE, isPrivate);
+ funcTraits.SetTrait(asTRAIT_PROTECTED, isProtected);
+
// TODO: getset: Allow private for individual property accessors
// TODO: getset: If the accessor uses its own name, then the property should be automatically declared
- if( node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, GET_TOKEN) )
+ if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, GET_TOKEN))
+ name = "get_";
+ else if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, SET_TOKEN))
+ name = "set_";
+ else
+ WriteError(TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE, file, node);
+
+ if (name != "")
{
- funcNode = node->firstChild->next;
+ success = true;
+ funcNode = node->firstChild->next;
- if( funcNode && funcNode->tokenType == ttConst )
+ if (funcNode && funcNode->tokenType == ttConst)
{
- isConst = true;
+ funcTraits.SetTrait(asTRAIT_CONST, true);
funcNode = funcNode->next;
}
- while( funcNode && funcNode->nodeType != snStatementBlock )
+ while (funcNode && funcNode->nodeType != snStatementBlock)
{
- if( funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN) )
- isFinal = true;
- else if( funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN) )
- isOverride = true;
+ if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN))
+ funcTraits.SetTrait(asTRAIT_FINAL, true);
+ else if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN))
+ funcTraits.SetTrait(asTRAIT_OVERRIDE, true);
funcNode = funcNode->next;
}
- if( funcNode )
+ if (funcNode)
funcNode->DisconnectParent();
- if( funcNode == 0 && (objType == 0 || !objType->IsInterface()) )
+ if (funcNode == 0 && (objType == 0 || !objType->IsInterface()))
{
// TODO: getset: If no implementation is supplied the builder should provide an automatically generated implementation
// The compiler needs to be able to handle the different types, primitive, value type, and handle
@@ -4652,53 +4925,28 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file
WriteError(TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED, file, node);
}
- // Setup the signature for the get accessor method
- returnType = emulatedType;
- name = "get_" + emulatedName;
- success = true;
- }
- else if( node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, SET_TOKEN) )
- {
- funcNode = node->firstChild->next;
-
- if( funcNode && funcNode->tokenType == ttConst )
+ if (name == "get_")
{
- isConst = true;
- funcNode = funcNode->next;
+ // Setup the signature for the get accessor method
+ returnType = emulatedType;
+ name = "get_" + emulatedName;
}
-
- while( funcNode && funcNode->nodeType != snStatementBlock )
+ else if (name == "set_")
{
- if( funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN) )
- isFinal = true;
- else if( funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN) )
- isOverride = true;
-
- funcNode = funcNode->next;
+ // Setup the signature for the set accessor method
+ returnType = asCDataType::CreatePrimitive(ttVoid, false);
+ paramModifiers.PushLast(asTM_NONE);
+ paramNames.PushLast("value");
+ paramTypes.PushLast(emulatedType);
+ defaultArgs.PushLast(0);
+ name = "set_" + emulatedName;
}
-
- if( funcNode )
- funcNode->DisconnectParent();
-
- if( funcNode == 0 && (objType == 0 || !objType->IsInterface()) )
- WriteError(TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED, file, node);
-
- // Setup the signature for the set accessor method
- returnType = asCDataType::CreatePrimitive(ttVoid, false);
- paramModifiers.PushLast(asTM_NONE);
- paramNames.PushLast("value");
- paramTypes.PushLast(emulatedType);
- defaultArgs.PushLast(0);
- name = "set_" + emulatedName;
- success = true;
}
- else
- WriteError(TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE, file, node);
if( success )
{
if( !isExistingShared )
- RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, isConst, false, false, isPrivate, isProtected, isOverride, isFinal, false);
+ RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, funcTraits);
else
{
// Free the funcNode as it won't be used
@@ -4710,7 +4958,7 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file
{
asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]];
if( func->name == name &&
- func->IsSignatureExceptNameEqual(returnType, paramTypes, paramModifiers, objType, isConst) )
+ func->IsSignatureExceptNameEqual(returnType, paramTypes, paramModifiers, objType, funcTraits.GetTrait(asTRAIT_CONST)) )
{
found = true;
break;
@@ -4742,12 +4990,12 @@ int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCS
asCArray parameterTypes;
asCArray inOutFlags;
asCArray defaultArgs;
- bool isConstMethod, isOverride, isFinal, isConstructor, isDestructor, isPrivate, isProtected, isShared;
+ asSFunctionTraits funcTraits;
if( ns == 0 )
ns = engine->nameSpaces[0];
- GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared, ns);
+ GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns);
CheckNameConflict(name.AddressOf(), node, file, ns);
// Check that the same function hasn't been registered already in the namespace
@@ -4823,73 +5071,70 @@ void asCBuilder::GetFunctionDescriptions(const char *name, asCArray &funcs,
}
}
+// scope is only informed when looking for a base class' method
void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray &methods, bool objIsConst, const asCString &scope, asCScriptNode *errNode, asCScriptCode *script)
{
+ asASSERT(objectType);
+
if( scope != "" )
{
// If searching with a scope informed, then the node and script must also be informed for potential error reporting
asASSERT( errNode && script );
// If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace
+ // TODO: child funcdef: A scope can include a template type, e.g. array
int n = scope.FindLast("::");
asCString className = n >= 0 ? scope.SubString(n+2) : scope;
asCString nsName = n >= 0 ? scope.SubString(0, n) : "";
- // Check if the namespace actually exist, if not return silently as this cannot be the referring to a base class
- asSNameSpace *ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, false);
- if( ns == 0 )
- return;
+ // If a namespace was specifically defined, then this must be used
+ asSNameSpace *ns = 0;
+ if (n >= 0)
+ {
+ if (nsName == "")
+ ns = engine->nameSpaces[0];
+ else
+ ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, 0, false);
+
+ // If the namespace isn't found return silently and let the calling
+ // function report the error if it cannot resolve the symbol
+ if (ns == 0)
+ return;
+ }
// Find the base class with the specified scope
- while( objectType && (objectType->name != className || objectType->nameSpace != ns) )
+ while (objectType)
+ {
+ // If the name and namespace matches it is the correct class. If no
+ // specific namespace was given, then don't compare the namespace
+ if (objectType->name == className && (ns == 0 || objectType->nameSpace == ns))
+ break;
+
objectType = objectType->derivedFrom;
+ }
// If the scope is not any of the base classes, then return no methods
if( objectType == 0 )
return;
}
+ // Find the methods in the object that match the name
// TODO: optimize: Improve linear search
- if( objIsConst )
+ for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
{
- // Only add const methods to the list
- for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
+ asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]];
+ if( func->name == name &&
+ (!objIsConst || func->IsReadOnly()) &&
+ (func->accessMask & module->accessMask) )
{
- asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]];
- if( func->name == name &&
- func->isReadOnly &&
- (func->accessMask & module->accessMask) )
+ // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
+ if( scope == "" )
+ methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
+ else
{
- // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
- if( scope == "" )
- methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
- else
- {
- asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
- asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
- methods.PushLast(realFunc->id);
- }
- }
- }
- }
- else
- {
- // TODO: Prefer non-const over const
- for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
- {
- asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]];
- if( func->name == name &&
- (func->accessMask & module->accessMask) )
- {
- // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
- if( scope == "" )
- methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
- else
- {
- asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
- asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
- methods.PushLast(realFunc->id);
- }
+ asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
+ asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
+ methods.PushLast(realFunc->id);
}
}
}
@@ -4962,16 +5207,25 @@ void asCBuilder::WriteWarning(const asCString &message, asCScriptCode *file, asC
WriteWarning(file ? file->name : asCString(""), message, r, c);
}
+// TODO: child funcdef: Should try to eliminate this function. GetNameSpaceFromNode is more complete
asCString asCBuilder::GetScopeFromNode(asCScriptNode *node, asCScriptCode *script, asCScriptNode **next)
{
+ if (node->nodeType != snScope)
+ {
+ if (next)
+ *next = node;
+ return "";
+ }
+
asCString scope;
- asCScriptNode *sn = node;
+ asCScriptNode *sn = node->firstChild;
if( sn->tokenType == ttScope )
{
scope = "::";
sn = sn->next;
}
+ // TODO: child funcdef: A scope can have a template type as the innermost
while( sn && sn->next && sn->next->tokenType == ttScope )
{
asCString tmp;
@@ -4983,26 +5237,128 @@ asCString asCBuilder::GetScopeFromNode(asCScriptNode *node, asCScriptCode *scrip
}
if( next )
- *next = sn;
+ *next = node->next;
return scope;
}
-asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next)
+asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next, asCObjectType **objType)
{
- asCString scope = GetScopeFromNode(node, script, next);
- return GetNameSpaceByString(scope, implicitNs, node, script);
+ if (objType)
+ *objType = 0;
+
+ // If no scope has been informed, then return the implicit namespace
+ if (node->nodeType != snScope)
+ {
+ if (next)
+ *next = node;
+ return implicitNs ? implicitNs : engine->nameSpaces[0];
+ }
+
+ if (next)
+ *next = node->next;
+
+ asCString scope;
+ asCScriptNode *sn = node->firstChild;
+ if (sn && sn->tokenType == ttScope)
+ {
+ scope = "::";
+ sn = sn->next;
+ }
+
+ while (sn)
+ {
+ if (sn->next->tokenType == ttScope)
+ {
+ asCString tmp;
+ tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength);
+ if (scope != "" && scope != "::")
+ scope += "::";
+ scope += tmp;
+ sn = sn->next->next;
+ }
+ else
+ {
+ // This is a template type
+ asASSERT(sn->next->nodeType == snDataType);
+
+ asSNameSpace *ns = implicitNs;
+ if (scope != "")
+ ns = engine->FindNameSpace(scope.AddressOf());
+
+ asCString templateName(&script->code[sn->tokenPos], sn->tokenLength);
+ asCObjectType *templateType = GetObjectType(templateName.AddressOf(), ns);
+ if (templateType == 0 || (templateType->flags & asOBJ_TEMPLATE) == 0)
+ {
+ // TODO: child funcdef: Report error
+ return ns;
+ }
+
+ if (objType)
+ *objType = GetTemplateInstanceFromNode(sn, script, templateType, implicitNs, 0);
+
+ // Return no namespace, since this is an object type
+ return 0;
+ }
+ }
+
+ asCTypeInfo *ti = 0;
+ asSNameSpace *ns = GetNameSpaceByString(scope, implicitNs ? implicitNs : engine->nameSpaces[0], node, script, &ti);
+ if (ti && objType)
+ *objType = CastToObjectType(ti);
+ return ns;
}
-asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, bool isRequired)
+asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType, bool isRequired)
{
+ if( scopeType )
+ *scopeType = 0;
+
asSNameSpace *ns = implicitNs;
if( nsName == "::" )
ns = engine->nameSpaces[0];
else if( nsName != "" )
{
ns = engine->FindNameSpace(nsName.AddressOf());
- if( ns == 0 && isRequired )
+ if (ns == 0 && scopeType)
+ {
+ asCString typeName;
+ asCString searchNs;
+
+ // Split the scope with at the inner most ::
+ int pos = nsName.FindLast("::");
+ bool recursive = false;
+ if (pos >= 0)
+ {
+ // Fully qualified namespace
+ typeName = nsName.SubString(pos + 2);
+ searchNs = nsName.SubString(0, pos);
+ }
+ else
+ {
+ // Partially qualified, use the implicit namespace and then search recursively for the type
+ typeName = nsName;
+ searchNs = implicitNs->name;
+ recursive = true;
+ }
+
+ asSNameSpace *nsTmp = searchNs == "::" ? engine->nameSpaces[0] : engine->FindNameSpace(searchNs.AddressOf());
+ asCTypeInfo *ti = 0;
+ while( !ti && nsTmp )
+ {
+ // Check if the typeName is an existing type in the namespace
+ ti = GetType(typeName.AddressOf(), nsTmp, 0);
+ if (ti)
+ {
+ // The informed scope is not a namespace, but it does match a type
+ *scopeType = ti;
+ return 0;
+ }
+ nsTmp = recursive ? engine->GetParentNameSpace(nsTmp) : 0;
+ }
+ }
+
+ if (ns == 0 && isRequired)
{
asCString msg;
msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, nsName.AddressOf());
@@ -5013,14 +5369,22 @@ asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameS
return ns;
}
-asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope, asCObjectType *currentType)
+asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope, asCObjectType *currentType, bool reportError, bool *isValid)
{
- asASSERT(node->nodeType == snDataType);
+ asASSERT(node->nodeType == snDataType || node->nodeType == snIdentifier || node->nodeType == snScope );
asCDataType dt;
asCScriptNode *n = node->firstChild;
+ if (isValid)
+ *isValid = true;
+
+ // If the informed node is an identifier or scope, then the
+ // datatype should be identified directly from that
+ if (node->nodeType != snDataType)
+ n = node;
+
bool isConst = false;
bool isImplicitHandle = false;
if( n->tokenType == ttConst )
@@ -5029,12 +5393,15 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
n = n->next;
}
- // Determine namespace
- asSNameSpace *ns = GetNameSpaceFromNode(n, file, implicitNamespace, &n);
- if( ns == 0 )
+ // Determine namespace (or parent type) to search for the data type in
+ asCObjectType *parentType = 0;
+ asSNameSpace *ns = GetNameSpaceFromNode(n, file, implicitNamespace, &n, &parentType);
+ if( ns == 0 && parentType == 0 )
{
- // The namespace doesn't exist. Return a dummy type instead.
+ // The namespace and parent type doesn't exist. Return a dummy type instead.
dt = asCDataType::CreatePrimitive(ttInt, false);
+ if (isValid)
+ *isValid = false;
return dt;
}
@@ -5042,189 +5409,146 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
{
bool found = false;
- asCScriptNode *nameToken = n;
asCString str;
str.Assign(&file->code[n->tokenPos], n->tokenLength);
// Recursively search parent namespaces for matching type
asSNameSpace *origNs = ns;
- while( ns && !found )
+ asCObjectType *origParentType = parentType;
+ while( (ns || parentType) && !found )
{
- asCObjectType *ot = 0;
+ asCTypeInfo *ti = 0;
- // If this is for a template type, then we must first determine if the
- // identifier matches any of the template subtypes
- if( currentType && (currentType->flags & asOBJ_TEMPLATE) )
+ if (currentType)
{
- for( asUINT subtypeIndex = 0; subtypeIndex < currentType->templateSubTypes.GetLength(); subtypeIndex++)
+ // If this is for a template type, then we must first determine if the
+ // identifier matches any of the template subtypes
+ if (currentType->flags & asOBJ_TEMPLATE)
{
- asCObjectType *type = currentType->templateSubTypes[subtypeIndex].GetObjectType();
- if( type && str == type->name )
+ for (asUINT subtypeIndex = 0; subtypeIndex < currentType->templateSubTypes.GetLength(); subtypeIndex++)
{
- ot = type;
- break;
+ asCTypeInfo *type = currentType->templateSubTypes[subtypeIndex].GetTypeInfo();
+ if (type && str == type->name)
+ {
+ ti = type;
+ break;
+ }
+ }
+ }
+
+ if (ti == 0)
+ {
+ // Check if the type is a child type of the current type
+ ti = GetFuncDef(str.AddressOf(), 0, currentType);
+ if (ti)
+ {
+ dt = asCDataType::CreateType(ti, false);
+ found = true;
}
}
}
- if( ot == 0 )
- ot = GetObjectType(str.AddressOf(), ns);
- if( ot == 0 && !module && currentType )
- ot = GetObjectTypeFromTypesKnownByObject(str.AddressOf(), currentType);
+ if( ti == 0 )
+ ti = GetType(str.AddressOf(), ns, parentType);
+ if( ti == 0 && !module && currentType )
+ ti = GetTypeFromTypesKnownByObject(str.AddressOf(), currentType);
- if( ot )
+ if( ti && !found )
{
found = true;
- if( ot->flags & asOBJ_IMPLICIT_HANDLE )
+ if( ti->flags & asOBJ_IMPLICIT_HANDLE )
isImplicitHandle = true;
// Make sure the module has access to the object type
- if( !module || (module->accessMask & ot->accessMask) )
+ if( !module || (module->accessMask & ti->accessMask) )
{
- if( asOBJ_TYPEDEF == (ot->flags & asOBJ_TYPEDEF) )
+ if( asOBJ_TYPEDEF == (ti->flags & asOBJ_TYPEDEF) )
{
// TODO: typedef: A typedef should be considered different from the original type (though with implicit conversions between the two)
// Create primitive data type based on object flags
- dt = ot->templateSubTypes[0];
+ dt = CastToTypedefType(ti)->aliasForType;
dt.MakeReadOnly(isConst);
}
else
{
- if( ot->flags & asOBJ_TEMPLATE )
+ if( ti->flags & asOBJ_TEMPLATE )
{
- // Check if the subtype is a type or the template's subtype
- // if it is the template's subtype then this is the actual template type,
- // orderwise it is a template instance.
- // Only do this for application registered interface, as the
- // scripts cannot implement templates.
- asCArray subTypes;
- asUINT subtypeIndex;
- while( n && n->next && n->next->nodeType == snDataType )
+ ti = GetTemplateInstanceFromNode(n, file, CastToObjectType(ti), implicitNamespace, currentType, &n);
+ if (ti == 0)
{
- n = n->next;
-
- // When parsing function definitions for template registrations (currentType != 0) it is necessary
- // to pass in the current template type to the recursive call since it is this ones sub-template types
- // that should be allowed.
- asCDataType subType = CreateDataTypeFromNode(n, file, implicitNamespace, false, module ? 0 : (currentType ? currentType : ot));
- subTypes.PushLast(subType);
-
- if( subType.IsReadOnly() )
- {
- asCString msg;
- msg.Format(TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY);
- WriteError(msg, file, n);
-
- // Return a dummy
- return asCDataType::CreatePrimitive(ttInt, false);
- }
- }
-
- if( subTypes.GetLength() != ot->templateSubTypes.GetLength() )
- {
- asCString msg;
- msg.Format(TXT_TMPL_s_EXPECTS_d_SUBTYPES, ot->name.AddressOf(), int(ot->templateSubTypes.GetLength()));
- WriteError(msg, file, nameToken);
+ if (isValid)
+ *isValid = false;
// Return a dummy
return asCDataType::CreatePrimitive(ttInt, false);
}
-
- // Check if any of the given subtypes are different from the template's declared subtypes
- bool isDifferent = false;
- for( subtypeIndex = 0; subtypeIndex < subTypes.GetLength(); subtypeIndex++ )
- {
- if( subTypes[subtypeIndex].GetObjectType() != ot->templateSubTypes[subtypeIndex].GetObjectType() )
- {
- isDifferent = true;
- break;
- }
- }
-
- if( isDifferent )
- {
- // This is a template instance
- // Need to find the correct object type
- asCObjectType *otInstance = engine->GetTemplateInstanceType(ot, subTypes, module);
-
- if( otInstance && otInstance->scriptSectionIdx < 0 )
- {
- // If this is the first time the template instance is used, store where it was declared from
- otInstance->scriptSectionIdx = engine->GetScriptSectionNameIndex(file->name.AddressOf());
- int row, column;
- file->ConvertPosToRowCol(n->tokenPos, &row, &column);
- otInstance->declaredAt = (row&0xFFFFF)|(column<<20);
- }
-
- if( !otInstance )
- {
- asCString sub = subTypes[0].Format(ot->nameSpace);
- for( asUINT s = 1; s < subTypes.GetLength(); s++ )
- {
- sub += ",";
- sub += subTypes[s].Format(ot->nameSpace);
- }
- asCString str;
- str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf());
- WriteError(str, file, n);
- }
-
- ot = otInstance;
- }
}
else if( n && n->next && n->next->nodeType == snDataType )
{
- asCString str;
- str.Format(TXT_TYPE_s_NOT_TEMPLATE, ot->name.AddressOf());
- WriteError(str, file, n);
+ if (reportError)
+ {
+ asCString msg;
+ msg.Format(TXT_TYPE_s_NOT_TEMPLATE, ti->name.AddressOf());
+ WriteError(msg, file, n);
+ }
+ if (isValid)
+ *isValid = false;
}
// Create object data type
- if( ot )
- dt = asCDataType::CreateObject(ot, isConst);
+ if( ti )
+ dt = asCDataType::CreateType(ti, isConst);
else
dt = asCDataType::CreatePrimitive(ttInt, isConst);
}
}
else
{
- asCString msg;
- msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf());
- WriteError(msg, file, n);
+ if (reportError)
+ {
+ asCString msg;
+ msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf());
+ WriteError(msg, file, n);
+ }
dt.SetTokenType(ttInt);
- }
- }
- else if( ot == 0 )
- {
- // It can still be a function definition
- asCScriptFunction *funcdef = GetFuncDef(str.AddressOf());
-
- if( funcdef )
- {
- dt = asCDataType::CreateFuncDef(funcdef);
- found = true;
+ if (isValid)
+ *isValid = false;
}
}
if( !found )
{
// Try to find it in the parent namespace
- ns = engine->GetParentNameSpace(ns);
+ if( ns )
+ ns = engine->GetParentNameSpace(ns);
+ if (parentType)
+ parentType = 0;
}
}
if( !found )
{
- asCString msg;
- if( origNs->name == "" )
- msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, str.AddressOf());
- else
- msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), origNs->name.AddressOf());
- WriteError(msg, file, n);
+ if (reportError)
+ {
+ asCString msg;
+ if (origNs && origNs->name == "")
+ msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, str.AddressOf());
+ else if (origNs)
+ msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), origNs->name.AddressOf());
+ else
+ {
+ // TODO: child funcdef: Message should explain that the identifier is not a type of the parent type
+ asCDataType pt = asCDataType::CreateType(origParentType, false);
+ msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), pt.Format(origParentType->nameSpace, false).AddressOf());
+ }
+ WriteError(msg, file, n);
+ }
dt = asCDataType::CreatePrimitive(ttInt, isConst);
+ if (isValid)
+ *isValid = false;
return dt;
}
}
@@ -5247,22 +5571,30 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
// Make sure the sub type can be instantiated
if( !dt.CanBeInstantiated() )
{
- asCString str;
- if( dt.IsAbstractClass() )
- str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf());
- else if( dt.IsInterface() )
- str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf());
- else
- // TODO: Improve error message to explain why
- str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(ns).AddressOf());
+ if (reportError)
+ {
+ asCString str;
+ if (dt.IsAbstractClass())
+ str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf());
+ else if (dt.IsInterface())
+ str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf());
+ else
+ // TODO: Improve error message to explain why
+ str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(ns).AddressOf());
- WriteError(str, file, n);
+ WriteError(str, file, n);
+ }
+ if (isValid)
+ *isValid = false;
}
// Make the type an array (or multidimensional array)
if( dt.MakeArray(engine, module) < 0 )
{
- WriteError(TXT_NO_DEFAULT_ARRAY_TYPE, file, n);
+ if( reportError )
+ WriteError(TXT_NO_DEFAULT_ARRAY_TYPE, file, n);
+ if (isValid)
+ *isValid = false;
break;
}
}
@@ -5271,12 +5603,18 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
// Make the type a handle
if( dt.IsObjectHandle() )
{
- WriteError(TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED, file, n);
+ if( reportError )
+ WriteError(TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED, file, n);
+ if (isValid)
+ *isValid = false;
break;
}
else if( dt.MakeHandle(true, acceptHandleForScope) < 0 )
{
- WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n);
+ if( reportError )
+ WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n);
+ if (isValid)
+ *isValid = false;
break;
}
}
@@ -5286,13 +5624,107 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
if( isImplicitHandle )
{
// Make the type a handle
- if( dt.MakeHandle(true, acceptHandleForScope) < 0 )
- WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n);
+ if (dt.MakeHandle(true, acceptHandleForScope) < 0)
+ {
+ if( reportError )
+ WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n);
+ if (isValid)
+ *isValid = false;
+ }
}
return dt;
}
+asCObjectType *asCBuilder::GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next)
+{
+ // Check if the subtype is a type or the template's subtype
+ // if it is the template's subtype then this is the actual template type,
+ // orderwise it is a template instance.
+ // Only do this for application registered interface, as the
+ // scripts cannot implement templates.
+ asCArray subTypes;
+ asUINT subtypeIndex;
+ asCScriptNode *n = node;
+ while (n && n->next && n->next->nodeType == snDataType)
+ {
+ n = n->next;
+
+ // When parsing function definitions for template registrations (currentType != 0) it is necessary
+ // to pass in the current template type to the recursive call since it is this ones sub-template types
+ // that should be allowed.
+ asCDataType subType = CreateDataTypeFromNode(n, file, implicitNamespace, false, module ? 0 : (currentType ? currentType : templateType));
+ subTypes.PushLast(subType);
+
+ if (subType.IsReadOnly())
+ {
+ asCString msg;
+ msg.Format(TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY);
+ WriteError(msg, file, n);
+
+ // Return a dummy
+ return 0;
+ }
+ }
+
+ if (next)
+ *next = n;
+
+ if (subTypes.GetLength() != templateType->templateSubTypes.GetLength())
+ {
+ asCString msg;
+ msg.Format(TXT_TMPL_s_EXPECTS_d_SUBTYPES, templateType->name.AddressOf(), int(templateType->templateSubTypes.GetLength()));
+ WriteError(msg, file, node);
+
+ // Return a dummy
+ return 0;
+ }
+
+ // Check if any of the given subtypes are different from the template's declared subtypes
+ bool isDifferent = false;
+ for (subtypeIndex = 0; subtypeIndex < subTypes.GetLength(); subtypeIndex++)
+ {
+ if (subTypes[subtypeIndex].GetTypeInfo() != templateType->templateSubTypes[subtypeIndex].GetTypeInfo())
+ {
+ isDifferent = true;
+ break;
+ }
+ }
+
+ if (isDifferent)
+ {
+ // This is a template instance
+ // Need to find the correct object type
+ asCObjectType *otInstance = engine->GetTemplateInstanceType(templateType, subTypes, module);
+
+ if (otInstance && otInstance->scriptSectionIdx < 0)
+ {
+ // If this is the first time the template instance is used, store where it was declared from
+ otInstance->scriptSectionIdx = engine->GetScriptSectionNameIndex(file->name.AddressOf());
+ int row, column;
+ file->ConvertPosToRowCol(n->tokenPos, &row, &column);
+ otInstance->declaredAt = (row & 0xFFFFF) | (column << 20);
+ }
+
+ if (!otInstance)
+ {
+ asCString sub = subTypes[0].Format(templateType->nameSpace);
+ for (asUINT s = 1; s < subTypes.GetLength(); s++)
+ {
+ sub += ",";
+ sub += subTypes[s].Format(templateType->nameSpace);
+ }
+ asCString msg;
+ msg.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, templateType->name.AddressOf(), sub.AddressOf());
+ WriteError(msg, file, n);
+ }
+
+ return otInstance;
+ }
+
+ return templateType;
+}
+
asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlags, bool *autoHandle)
{
asCDataType dt = type;
@@ -5303,6 +5735,14 @@ asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScrip
asCScriptNode *n = node->firstChild;
if( n && n->tokenType == ttAmp )
{
+ if (dt.GetTokenType() == ttVoid)
+ {
+ asCString msg;
+ msg.Format(TXT_TYPE_s_CANNOT_BE_REFERENCE, type.Format(0).AddressOf());
+ WriteError(msg, file, node->firstChild);
+ return dt;
+ }
+
dt.MakeReference(true);
n = n->next;
@@ -5332,7 +5772,7 @@ asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScrip
inOutFlags && *inOutFlags == asTM_INOUTREF )
{
// Verify that the base type support &inout parameter types
- if( !dt.IsObject() || dt.IsObjectHandle() || !((dt.GetObjectType()->flags & asOBJ_NOCOUNT) || (dt.GetObjectType()->beh.addref && dt.GetObjectType()->beh.release)) )
+ if( !dt.IsObject() || dt.IsObjectHandle() || !((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || (CastToObjectType(dt.GetTypeInfo())->beh.addref && CastToObjectType(dt.GetTypeInfo())->beh.release)) )
WriteError(TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, file, node->firstChild);
}
}
@@ -5342,24 +5782,65 @@ asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScrip
if( n && n->tokenType == ttPlus )
{
// Autohandles are not supported for types with NOCOUNT
- // If the type is not a handle then there was an error with building the type, but
+ // If the type is not a handle then there was an error with building the type, but
// this error would already have been reported so no need to report another error here
- if( dt.IsObjectHandle() && (dt.GetObjectType()->flags & asOBJ_NOCOUNT) )
+ if( dt.IsObjectHandle() && (dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) )
WriteError(TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT, file, node->firstChild);
if( autoHandle ) *autoHandle = true;
}
+ if (n && n->tokenType == ttIdentifier)
+ {
+ asCString str;
+ str.Assign(&file->code[n->tokenPos], n->tokenLength);
+ if (str == IF_HANDLE_TOKEN)
+ dt.SetIfHandleThenConst(true);
+ else
+ {
+ // TODO: Should give error if not currently parsing template registration
+ asCString msg;
+ msg.Format(TXT_UNEXPECTED_TOKEN_s, str.AddressOf());
+ WriteError(msg, file, node->firstChild);
+ }
+ }
+
return dt;
}
+asCTypeInfo *asCBuilder::GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType)
+{
+ asASSERT((ns == 0 && parentType) || (ns && parentType == 0));
+
+ if (ns)
+ {
+ asCTypeInfo *ti = engine->GetRegisteredType(type, ns);
+ if (!ti && module)
+ ti = module->GetType(type, ns);
+ return ti;
+ }
+ else
+ {
+ // Recursively check base classes
+ asCObjectType *currType = parentType;
+ while (currType)
+ {
+ for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++)
+ {
+ asCFuncdefType *funcDef = currType->childFuncDefs[n];
+ if (funcDef && funcDef->name == type)
+ return funcDef;
+ }
+ currType = currType->derivedFrom;
+ }
+ }
+
+ return 0;
+}
+
asCObjectType *asCBuilder::GetObjectType(const char *type, asSNameSpace *ns)
{
- asCObjectType *ot = engine->GetRegisteredObjectType(type, ns);
- if( !ot && module )
- ot = module->GetObjectType(type, ns);
-
- return ot;
+ return CastToObjectType(GetType(type, ns, 0));
}
#ifndef AS_NO_COMPILER
@@ -5378,8 +5859,8 @@ bool asCBuilder::DoesTypeExist(const asCString &type)
// Only do this once
hasCachedKnownTypes = true;
- // Add registered object types
- asSMapNode *cursor;
+ // Add registered types
+ asSMapNode *cursor;
engine->allRegisteredTypes.MoveFirst(&cursor);
while( cursor )
{
@@ -5389,31 +5870,26 @@ bool asCBuilder::DoesTypeExist(const asCString &type)
engine->allRegisteredTypes.MoveNext(&cursor, cursor);
}
- // Add registered funcdefs
- for( n = 0; n < engine->registeredFuncDefs.GetLength(); n++ )
- if( !knownTypes.MoveTo(0, engine->registeredFuncDefs[n]->name) )
- knownTypes.Insert(engine->registeredFuncDefs[n]->name, true);
-
- if( module )
+ if (module)
{
// Add script classes and interfaces
- for( n = 0; n < module->classTypes.GetLength(); n++ )
- if( !knownTypes.MoveTo(0, module->classTypes[n]->name) )
+ for (n = 0; n < module->classTypes.GetLength(); n++)
+ if (!knownTypes.MoveTo(0, module->classTypes[n]->name))
knownTypes.Insert(module->classTypes[n]->name, true);
// Add script enums
- for( n = 0; n < module->enumTypes.GetLength(); n++ )
- if( !knownTypes.MoveTo(0, module->enumTypes[n]->name) )
+ for (n = 0; n < module->enumTypes.GetLength(); n++)
+ if (!knownTypes.MoveTo(0, module->enumTypes[n]->name))
knownTypes.Insert(module->enumTypes[n]->name, true);
// Add script typedefs
- for( n = 0; n < module->typeDefs.GetLength(); n++ )
- if( !knownTypes.MoveTo(0, module->typeDefs[n]->name) )
+ for (n = 0; n < module->typeDefs.GetLength(); n++)
+ if (!knownTypes.MoveTo(0, module->typeDefs[n]->name))
knownTypes.Insert(module->typeDefs[n]->name, true);
// Add script funcdefs
- for( n = 0; n < module->funcDefs.GetLength(); n++ )
- if( !knownTypes.MoveTo(0, module->funcDefs[n]->name) )
+ for (n = 0; n < module->funcDefs.GetLength(); n++)
+ if (!knownTypes.MoveTo(0, module->funcDefs[n]->name))
knownTypes.Insert(module->funcDefs[n]->name, true);
}
}
@@ -5423,56 +5899,82 @@ bool asCBuilder::DoesTypeExist(const asCString &type)
}
#endif
-asCObjectType *asCBuilder::GetObjectTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType)
+asCTypeInfo *asCBuilder::GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType)
{
- if( currentType->name == type )
+ if (currentType->name == type)
return currentType;
asUINT n;
- asCObjectType *found = 0;
+ asCTypeInfo *found = 0;
- for( n = 0; found == 0 && n < currentType->properties.GetLength(); n++ )
- if( currentType->properties[n]->type.GetObjectType() &&
- currentType->properties[n]->type.GetObjectType()->name == type )
- found = currentType->properties[n]->type.GetObjectType();
+ for (n = 0; found == 0 && n < currentType->properties.GetLength(); n++)
+ if (currentType->properties[n]->type.GetTypeInfo() &&
+ currentType->properties[n]->type.GetTypeInfo()->name == type)
+ found = currentType->properties[n]->type.GetTypeInfo();
- for( n = 0; found == 0 && n < currentType->methods.GetLength(); n++ )
+ for (n = 0; found == 0 && n < currentType->methods.GetLength(); n++)
{
asCScriptFunction *func = engine->scriptFunctions[currentType->methods[n]];
- if( func->returnType.GetObjectType() &&
- func->returnType.GetObjectType()->name == type )
- found = func->returnType.GetObjectType();
-
- for( asUINT f = 0; found == 0 && f < func->parameterTypes.GetLength(); f++ )
- if( func->parameterTypes[f].GetObjectType() &&
- func->parameterTypes[f].GetObjectType()->name == type )
- found = func->parameterTypes[f].GetObjectType();
+ if (func->returnType.GetTypeInfo() &&
+ func->returnType.GetTypeInfo()->name == type)
+ found = func->returnType.GetTypeInfo();
+
+ for (asUINT f = 0; found == 0 && f < func->parameterTypes.GetLength(); f++)
+ if (func->parameterTypes[f].GetTypeInfo() &&
+ func->parameterTypes[f].GetTypeInfo()->name == type)
+ found = func->parameterTypes[f].GetTypeInfo();
}
- if( found )
+ if (found)
{
// In case we find a template instance it mustn't be returned
// because it is not known if the subtype is really matching
- if( found->flags & asOBJ_TEMPLATE )
+ if (found->flags & asOBJ_TEMPLATE)
return 0;
}
return found;
}
-asCScriptFunction *asCBuilder::GetFuncDef(const char *type)
+asCFuncdefType *asCBuilder::GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType)
{
- for( asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++ )
- // TODO: access: Only return the definitions that the module has access to
- if( engine->registeredFuncDefs[n]->name == type )
- return engine->registeredFuncDefs[n];
+ asASSERT((ns == 0 && parentType) || (ns && parentType == 0));
- if( module )
+ if (ns)
{
- for( asUINT n = 0; n < module->funcDefs.GetLength(); n++ )
- if( module->funcDefs[n]->name == type )
- return module->funcDefs[n];
+ for (asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++)
+ {
+ asCFuncdefType *funcDef = engine->registeredFuncDefs[n];
+ // TODO: access: Only return the definitions that the module has access to
+ if (funcDef && funcDef->nameSpace == ns && funcDef->name == type)
+ return funcDef;
+ }
+
+ if (module)
+ {
+ for (asUINT n = 0; n < module->funcDefs.GetLength(); n++)
+ {
+ asCFuncdefType *funcDef = module->funcDefs[n];
+ if (funcDef && funcDef->nameSpace == ns && funcDef->name == type)
+ return funcDef;
+ }
+ }
+ }
+ else
+ {
+ // Recursively check base classes
+ asCObjectType *currType = parentType;
+ while (currType)
+ {
+ for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++)
+ {
+ asCFuncdefType *funcDef = currType->childFuncDefs[n];
+ if (funcDef && funcDef->name == type)
+ return funcDef;
+ }
+ currType = currType->derivedFrom;
+ }
}
return 0;
@@ -5480,17 +5982,17 @@ asCScriptFunction *asCBuilder::GetFuncDef(const char *type)
#ifndef AS_NO_COMPILER
-int asCBuilder::GetEnumValueFromObjectType(asCObjectType *objType, const char *name, asCDataType &outDt, asDWORD &outValue)
+int asCBuilder::GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue)
{
- if( !objType || !(objType->flags & asOBJ_ENUM) )
+ if( !type || !(type->flags & asOBJ_ENUM) )
return 0;
- for( asUINT n = 0; n < objType->enumValues.GetLength(); ++n )
+ for( asUINT n = 0; n < type->enumValues.GetLength(); ++n )
{
- if( objType->enumValues[n]->name == name )
+ if( type->enumValues[n]->name == name )
{
- outDt = asCDataType::CreateObject(objType, true);
- outValue = objType->enumValues[n]->value;
+ outDt = asCDataType::CreateType(type, true);
+ outValue = type->enumValues[n]->value;
return 1;
}
}
@@ -5506,14 +6008,14 @@ int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outV
asUINT t;
for( t = 0; t < engine->registeredEnums.GetLength(); t++ )
{
- asCObjectType *ot = engine->registeredEnums[t];
- if( ns != ot->nameSpace ) continue;
+ asCEnumType *et = engine->registeredEnums[t];
+ if( ns != et->nameSpace ) continue;
// Don't bother with types the module doesn't have access to
- if( (ot->accessMask & module->accessMask) == 0 )
+ if( (et->accessMask & module->accessMask) == 0 )
continue;
- if( GetEnumValueFromObjectType(ot, name, outDt, outValue) )
+ if( GetEnumValueFromType(et, name, outDt, outValue) )
{
if( !found )
found = true;
@@ -5527,10 +6029,10 @@ int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outV
for( t = 0; t < module->enumTypes.GetLength(); t++ )
{
- asCObjectType *ot = module->enumTypes[t];
- if( ns != ot->nameSpace ) continue;
+ asCEnumType *et = module->enumTypes[t];
+ if( ns != et->nameSpace ) continue;
- if( GetEnumValueFromObjectType(ot, name, outDt, outValue) )
+ if( GetEnumValueFromType(et, name, outDt, outValue) )
{
if( !found )
found = true;
diff --git a/lib/angelscript/source/as_builder.h b/lib/angelscript/source/as_builder.h
index 11c9ed917..988273123 100644
--- a/lib/angelscript/source/as_builder.h
+++ b/lib/angelscript/source/as_builder.h
@@ -1,24 +1,24 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
+ Permission is granted to anyone to use this software for any
+ purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you
+ 1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
- this software in a product, an acknowledgment in the product
+ this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and
+ 2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
+ 3. This notice may not be removed or altered from any source
distribution.
The original version of this library can be located at:
@@ -99,13 +99,13 @@ struct sPropertyInitializer
struct sClassDeclaration
{
- sClassDeclaration() {script = 0; node = 0; validState = 0; objType = 0; isExistingShared = false; isFinal = false;}
+ sClassDeclaration() {script = 0; node = 0; validState = 0; typeInfo = 0; isExistingShared = false; isFinal = false;}
asCScriptCode *script;
asCScriptNode *node;
asCString name;
int validState;
- asCObjectType *objType;
+ asCTypeInfo *typeInfo;
bool isExistingShared;
bool isFinal;
@@ -140,10 +140,10 @@ public:
int VerifyProperty(asCDataType *dt, const char *decl, asCString &outName, asCDataType &outType, asSNameSpace *ns);
int ParseDataType(const char *datatype, asCDataType *result, asSNameSpace *implicitNamespace, bool isReturnType = false);
int ParseTemplateDecl(const char *decl, asCString *name, asCArray &subtypeNames);
- int ParseFunctionDeclaration(asCObjectType *type, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles = 0, bool *returnAutoHandle = 0, asSNameSpace *ns = 0, asCScriptNode **listPattern = 0);
+ int ParseFunctionDeclaration(asCObjectType *type, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles = 0, bool *returnAutoHandle = 0, asSNameSpace *ns = 0, asCScriptNode **outListPattern = 0, asCObjectType **outParentClass = 0);
int ParseVariableDeclaration(const char *decl, asSNameSpace *implicitNamespace, asCString &outName, asSNameSpace *&outNamespace, asCDataType &outDt);
int CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns);
- int CheckNameConflictMember(asCObjectType *type, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty);
+ int CheckNameConflictMember(asCTypeInfo *type, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty);
#ifndef AS_NO_COMPILER
int AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy);
@@ -173,14 +173,16 @@ protected:
int ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func);
asCString GetCleanExpressionString(asCScriptNode *n, asCScriptCode *file);
- asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next);
- asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, bool isRequired = true);
+ asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next, asCObjectType **objType = 0);
+ asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType = 0, bool isRequired = true);
asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0);
+ asCTypeInfo *GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType);
asCObjectType *GetObjectType(const char *type, asSNameSpace *ns);
- asCScriptFunction *GetFuncDef(const char *type);
- asCObjectType *GetObjectTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType);
- asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0);
+ asCFuncdefType *GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType);
+ asCTypeInfo *GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType);
+ asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0, bool reportError = true, bool *isValid = 0);
+ asCObjectType *GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next = 0);
asCDataType ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlag, bool *autoHandle);
int numErrors;
@@ -204,7 +206,7 @@ protected:
void AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScriptNode *errNode, sMixinClass *mixin);
int RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false, bool isMixin = false);
- int RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isProtected, bool isOverride, bool isFinal, bool isShared);
+ int RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits funcTraits);
int RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false);
int RegisterImportedFunction(int funcID, asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
int RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
@@ -212,12 +214,13 @@ protected:
int RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
int RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
- int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
+ int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent);
asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns);
void CompleteFuncDef(sFuncDef *funcDef);
void CompileInterfaces();
void CompileClasses(asUINT originalNumTempl);
- void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, bool &isConstMethod, bool &isConstructor, bool &isDestructor, bool &isPrivate, bool &isProtected, bool &isOverride, bool &isFinal, bool &isShared, asSNameSpace *implicitNamespace);
+ void DetermineTypeRelations();
+ void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits &traits, asSNameSpace *implicitNamespace);
bool DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex = 0);
void AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file);
asCObjectProperty *AddPropertyToClass(sClassDeclaration *c, const asCString &name, const asCDataType &type, bool isPrivate, bool isProtected, bool isInherited, asCScriptCode *file = 0, asCScriptNode *node = 0);
@@ -227,7 +230,7 @@ protected:
void RegisterNonTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns);
void CompileFunctions();
void CompileGlobalVariables();
- int GetEnumValueFromObjectType(asCObjectType *objType, const char *name, asCDataType &outDt, asDWORD &outValue);
+ int GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue);
int GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue, asSNameSpace *ns);
bool DoesTypeExist(const asCString &type);
asCObjectProperty *GetObjectProperty(asCDataType &obj, const char *prop);
diff --git a/lib/angelscript/source/as_bytecode.cpp b/lib/angelscript/source/as_bytecode.cpp
index b0777d4f8..d16dbc201 100644
--- a/lib/angelscript/source/as_bytecode.cpp
+++ b/lib/angelscript/source/as_bytecode.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -1045,7 +1045,7 @@ void asCByteCode::OptimizeLocally(const asCArray &tempVariableOffsets)
short tempVar = last->wArg[0];
asCArray freedVars;
- asCByteInstruction *instr = last->prev;
+ instr = last->prev;
asASSERT( instr && instr->op == asBC_Block );
instr = instr->prev;
while( instr && instr->op == asBC_FREE )
@@ -1164,6 +1164,12 @@ void asCByteCode::Optimize()
DeleteInstruction(instr);
instr = GoBack(DeleteInstruction(curr));
}
+ // LINE, VarDecl, LINE -> VarDecl, LINE
+ else if (instrOp == asBC_VarDecl && instr->next && instr->next->op == asBC_LINE )
+ {
+ // Delete the first instruction
+ instr = GoBack(DeleteInstruction(curr));
+ }
// LINE, LINE -> LINE
else if( instrOp == asBC_LINE )
{
@@ -1390,6 +1396,7 @@ bool asCByteCode::IsTempRegUsed(asCByteInstruction *curr)
curr->op == asBC_PopRPtr ||
curr->op == asBC_CALLSYS ||
curr->op == asBC_CALLBND ||
+ curr->op == asBC_Thiscall1 ||
curr->op == asBC_SUSPEND ||
curr->op == asBC_ALLOC ||
curr->op == asBC_CpyVtoR4 ||
@@ -1444,7 +1451,8 @@ bool asCByteCode::IsSimpleExpression()
instr->op == asBC_FREE ||
instr->op == asBC_CallPtr ||
instr->op == asBC_CALLINTF ||
- instr->op == asBC_CALLBND )
+ instr->op == asBC_CALLBND ||
+ instr->op == asBC_Thiscall1 )
return false;
instr = instr->next;
@@ -1536,7 +1544,7 @@ void asCByteCode::ExtractObjectVariableInfo(asCScriptFunction *outFunc)
asSObjectVariableInfo info;
info.programPos = pos;
info.variableOffset = (short)instr->wArg[0];
- info.option = *(int*)ARG_DW(instr->arg);
+ info.option = (asEObjVarInfoOption)*(int*)ARG_DW(instr->arg);
outFunc->scriptData->objVariableInfo.PushLast(info);
}
else if( instr->op == asBC_VarDecl )
@@ -2064,18 +2072,23 @@ void asCByteCode::PostProcess()
}
#ifdef AS_DEBUG
-void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScriptFunction *func)
+void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func)
{
_mkdir("AS_DEBUG");
- asCString str = "AS_DEBUG/";
- str += name;
+ asCString path = "AS_DEBUG/";
+ path += name;
+
+ // Anonymous functions created from within class methods will contain :: as part of the name
+ // Replace :: with __ to avoid error when creating the file for debug output
+ for (asUINT n = 0; n < path.GetLength(); n++)
+ if (path[n] == ':') path[n] = '_';
#if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
FILE *file;
- fopen_s(&file, str.AddressOf(), "w");
+ fopen_s(&file, path.AddressOf(), "w");
#else
- FILE *file = fopen(str.AddressOf(), "w");
+ FILE *file = fopen(path.AddressOf(), "w");
#endif
#if !defined(AS_XENON) // XBox 360: When running in DVD Emu, no write is allowed
@@ -2186,14 +2199,7 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
switch( asBCInfo[instr->op].type )
{
case asBCTYPE_W_ARG:
- if( instr->op == asBC_STR )
- {
- int id = asWORD(instr->wArg[0]);
- const asCString &str = engine->GetConstantString(id);
- fprintf(file, " %-8s %d (l:%ld s:\"%.10s\")\n", asBCInfo[instr->op].name, asWORD(instr->wArg[0]), (long int)str.GetLength(), str.AddressOf());
- }
- else
- fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, instr->wArg[0]);
+ fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, instr->wArg[0]);
break;
case asBCTYPE_wW_ARG:
@@ -2237,8 +2243,8 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
case asBC_FuncPtr:
{
- asCScriptFunction *func = *(asCScriptFunction**)ARG_DW(instr->arg);
- fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), func->GetDeclaration());
+ asCScriptFunction *f = *(asCScriptFunction**)ARG_DW(instr->arg);
+ fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), f->GetDeclaration());
}
break;
@@ -2298,8 +2304,8 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
case asBC_FuncPtr:
{
- asCScriptFunction *func = *(asCScriptFunction**)ARG_QW(instr->arg);
- fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), func->GetDeclaration());
+ asCScriptFunction *f = *(asCScriptFunction**)ARG_QW(instr->arg);
+ fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), f->GetDeclaration());
}
break;
@@ -2345,8 +2351,8 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
if( instr->op == asBC_ALLOC )
{
asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
- asCScriptFunction *func = engine->scriptFunctions[instr->wArg[0]];
- fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), func ? func->GetDeclaration() : "{no func}");
+ asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]];
+ fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
}
else
fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1));
@@ -2360,19 +2366,19 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
if( instr->op == asBC_ALLOC )
{
asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
- asCScriptFunction *func = engine->scriptFunctions[instr->wArg[0]];
-#ifdef __GNUC__
+ asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]];
+#if defined(__GNUC__) && !defined(_MSC_VER)
#ifdef AS_64BIT_PTR
- fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}");
+ fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
#else
- fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}");
+ fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
#endif
#else
- fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}");
+ fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
#endif
}
else
-#ifdef __GNUC__
+#if defined(__GNUC__) && !defined(_MSC_VER)
#ifdef AS_64BIT_PTR
fprintf(file, " %-8s %lu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2));
#else
diff --git a/lib/angelscript/source/as_bytecode.h b/lib/angelscript/source/as_bytecode.h
index b1bb1127b..1c1067d7d 100644
--- a/lib/angelscript/source/as_bytecode.h
+++ b/lib/angelscript/source/as_bytecode.h
@@ -83,7 +83,7 @@ public:
void PostProcess();
#ifdef AS_DEBUG
- void DebugOutput(const char *name, asCScriptEngine *engine, asCScriptFunction *func);
+ void DebugOutput(const char *name, asCScriptFunction *func);
#endif
int GetLastInstr();
diff --git a/lib/angelscript/source/as_callfunc.cpp b/lib/angelscript/source/as_callfunc.cpp
index 81095ab8b..00d04a9c1 100644
--- a/lib/angelscript/source/as_callfunc.cpp
+++ b/lib/angelscript/source/as_callfunc.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -53,12 +53,12 @@ BEGIN_AS_NAMESPACE
// describes the structure for class method pointers on Itanium and arm64 ABI
// http://clang.llvm.org/doxygen/CodeGen_2ItaniumCXXABI_8cpp_source.html#l00937
-int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal)
+int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal)
{
memset(internal, 0, sizeof(asSSystemFunctionInterface));
- internal->func = ptr.ptr.f.func;
- internal->objForThiscall = 0;
+ internal->func = ptr.ptr.f.func;
+ internal->auxiliary = 0;
// Was a compatible calling convention specified?
if( internal->func )
@@ -80,21 +80,26 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
internal->callConv = ICC_STDCALL;
else if( base == asCALL_THISCALL_ASGLOBAL )
{
- if( objForThiscall == 0 )
+ if(auxiliary == 0)
return asINVALID_ARG;
- internal->objForThiscall = objForThiscall;
- internal->callConv = ICC_THISCALL;
+ internal->auxiliary = auxiliary;
+ internal->callConv = ICC_THISCALL;
// This is really a thiscall, so it is necessary to check for virtual method pointers
base = asCALL_THISCALL;
isMethod = true;
}
- else if( base == asCALL_GENERIC )
+ else if (base == asCALL_GENERIC)
+ {
internal->callConv = ICC_GENERIC_FUNC;
+
+ // The auxiliary object is optional for generic calling convention
+ internal->auxiliary = auxiliary;
+ }
else
return asNOT_SUPPORTED;
}
-
+
if( isMethod )
{
#ifndef AS_NO_CLASS_METHODS
@@ -103,7 +108,7 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
internalCallConv thisCallConv;
if( base == asCALL_THISCALL )
{
- if( callConv != asCALL_THISCALL_ASGLOBAL && objForThiscall )
+ if(callConv != asCALL_THISCALL_ASGLOBAL && auxiliary)
return asINVALID_ARG;
thisCallConv = ICC_THISCALL;
@@ -113,10 +118,10 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
return asNOT_SUPPORTED;
#else
- if( objForThiscall == 0 )
+ if(auxiliary == 0)
return asINVALID_ARG;
- internal->objForThiscall = objForThiscall;
+ internal->auxiliary = auxiliary;
if( base == asCALL_THISCALL_OBJFIRST )
thisCallConv = ICC_THISCALL_OBJFIRST;
else //if( base == asCALL_THISCALL_OBJLAST )
@@ -151,8 +156,11 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
internal->callConv = ICC_CDECL_OBJLAST;
else if( base == asCALL_CDECL_OBJFIRST )
internal->callConv = ICC_CDECL_OBJFIRST;
- else if( base == asCALL_GENERIC )
+ else if (base == asCALL_GENERIC)
+ {
internal->callConv = ICC_GENERIC_METHOD;
+ internal->auxiliary = auxiliary;
+ }
else
return asNOT_SUPPORTED;
}
@@ -161,7 +169,7 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
}
// This function should prepare system functions so that it will be faster to call them
-int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine * /*engine*/)
+int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine)
{
asASSERT(internal->callConv == ICC_GENERIC_METHOD || internal->callConv == ICC_GENERIC_FUNC);
@@ -175,17 +183,25 @@ int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInter
{
asCDataType &dt = func->parameterTypes[n];
- if( dt.IsObject() && !dt.IsReference() )
+ if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() )
{
- asSTypeBehaviour *beh = &dt.GetObjectType()->beh;
- if( dt.GetObjectType()->flags & asOBJ_REF )
+ if (dt.IsFuncdef())
{
- asASSERT( (dt.GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release );
+ asSSystemFunctionInterface::SClean clean;
+ clean.op = 0; // call release
+ clean.ot = &engine->functionBehaviours;
+ clean.off = short(offset);
+ internal->cleanArgs.PushLast(clean);
+ }
+ else if( dt.GetTypeInfo()->flags & asOBJ_REF )
+ {
+ asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh;
+ asASSERT( (dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release );
if( beh->release )
{
asSSystemFunctionInterface::SClean clean;
clean.op = 0; // call release
- clean.ot = dt.GetObjectType();
+ clean.ot = CastToObjectType(dt.GetTypeInfo());
clean.off = short(offset);
internal->cleanArgs.PushLast(clean);
}
@@ -194,10 +210,11 @@ int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInter
{
asSSystemFunctionInterface::SClean clean;
clean.op = 1; // call free
- clean.ot = dt.GetObjectType();
+ clean.ot = CastToObjectType(dt.GetTypeInfo());
clean.off = short(offset);
// Call the destructor then free the memory
+ asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh;
if( beh->destruct )
clean.op = 2; // call destruct, then free
@@ -222,7 +239,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
UNUSED_VAR(internal);
UNUSED_VAR(engine);
- // This should never happen, as when AS_MAX_PORTABILITY is on, all functions
+ // This should never happen, as when AS_MAX_PORTABILITY is on, all functions
// are asCALL_GENERIC, which are prepared by PrepareSystemFunctionGeneric
asASSERT(false);
#else
@@ -236,8 +253,8 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
// Registered types have special flags that determine how they are returned
else if( func->returnType.IsObject() )
{
- asDWORD objType = func->returnType.GetObjectType()->flags;
-
+ asDWORD objType = func->returnType.GetTypeInfo()->flags;
+
// Only value types can be returned by value
asASSERT( objType & asOBJ_VALUE );
@@ -247,7 +264,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
asCString str;
- str.Format(TXT_CANNOT_RET_TYPE_s_BY_VAL, func->returnType.GetObjectType()->name.AddressOf());
+ str.Format(TXT_CANNOT_RET_TYPE_s_BY_VAL, func->returnType.GetTypeInfo()->name.AddressOf());
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
}
@@ -282,7 +299,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
internal->hostReturnInMemory = false;
internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords();
#ifdef SPLIT_OBJS_BY_MEMBER_TYPES
- if( func->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS )
+ if( func->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS )
internal->hostReturnFloat = true;
#endif
}
@@ -329,7 +346,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
// Ref: http://www.agner.org/optimize/calling_conventions.pdf
// If the application informs that the class should be treated as all integers, then we allow it
if( !internal->hostReturnInMemory &&
- !(func->returnType.GetObjectType()->flags & (asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) )
+ !(func->returnType.GetTypeInfo()->flags & (asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) )
{
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
@@ -405,12 +422,12 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
internal->takesObjByVal = true;
// Can't pass objects by value unless the application type is informed
- if( !(func->parameterTypes[n].GetObjectType()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) )
+ if( !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) )
{
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
-
+
asCString str;
- str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetObjectType()->name.AddressOf());
+ str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf());
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
}
@@ -421,19 +438,19 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
// will be used depending on the memory layout of the object
// Ref: http://www.x86-64.org/documentation/abi.pdf
// Ref: http://www.agner.org/optimize/calling_conventions.pdf
- if(
+ if(
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- !(func->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) &&
+ !(func->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) &&
#endif
#ifdef LARGE_OBJS_PASS_BY_REF
func->parameterTypes[n].GetSizeInMemoryDWords() < AS_LARGE_OBJ_MIN_SIZE &&
#endif
- !(func->parameterTypes[n].GetObjectType()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) )
+ !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) )
{
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
asCString str;
- str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetObjectType()->name.AddressOf());
+ str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf());
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
}
@@ -452,24 +469,24 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
#if defined(COMPLEX_OBJS_PASSED_BY_REF) || defined(AS_LARGE_OBJS_PASSED_BY_REF)
bool needFree = false;
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( dt.GetObjectType() && dt.GetObjectType()->flags & COMPLEX_MASK ) needFree = true;
+ if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & COMPLEX_MASK ) needFree = true;
#endif
#ifdef AS_LARGE_OBJS_PASSED_BY_REF
if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ) needFree = true;
#endif
if( needFree &&
dt.IsObject() &&
- !dt.IsObjectHandle() &&
+ !dt.IsObjectHandle() &&
!dt.IsReference() )
{
asSSystemFunctionInterface::SClean clean;
clean.op = 1; // call free
- clean.ot = dt.GetObjectType();
+ clean.ot = CastToObjectType(dt.GetTypeInfo());
clean.off = short(offset);
#ifndef AS_CALLEE_DESTROY_OBJ_BY_VAL
// If the called function doesn't destroy objects passed by value we must do so here
- asSTypeBehaviour *beh = &dt.GetObjectType()->beh;
+ asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh;
if( beh->destruct )
clean.op = 2; // call destruct, then free
#endif
@@ -482,7 +499,10 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
{
asSSystemFunctionInterface::SClean clean;
clean.op = 0; // call release
- clean.ot = dt.GetObjectType();
+ if (dt.IsFuncdef())
+ clean.ot = &engine->functionBehaviours;
+ else
+ clean.ot = CastToObjectType(dt.GetTypeInfo());
clean.off = short(offset);
internal->cleanArgs.PushLast(clean);
}
@@ -533,7 +553,7 @@ int CallSystemFunction(int id, asCContext *context)
//
// Return value:
//
-// The function should return the value that is returned in registers.
+// The function should return the value that is returned in registers.
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObj);
@@ -553,16 +573,22 @@ int CallSystemFunction(int id, asCContext *context)
void *retPointer = 0;
int popSize = sysFunc->paramSize;
+ // TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers
+ // objForThiscall is the object pointer that should be used for the thiscall
+ // objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST
+
+ // Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST
+ void *obj = 0;
+ void *secondObj = 0;
+
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
- void *obj = 0;
- void *secondObj = 0;
if( callConv >= ICC_THISCALL )
{
- if( sysFunc->objForThiscall )
+ if(sysFunc->auxiliary)
{
// This class method is being called as if it is a global function
- obj = sysFunc->objForThiscall;
+ obj = sysFunc->auxiliary;
}
else
{
@@ -593,13 +619,6 @@ int CallSystemFunction(int id, asCContext *context)
}
}
#else
- // TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers
- // objForThiscall is the object pointer that should be used for the thiscall
- // objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST
-
- // Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST
- void *obj = 0;
- void *secondObj = 0;
if( callConv >= ICC_THISCALL )
{
@@ -608,15 +627,15 @@ int CallSystemFunction(int id, asCContext *context)
if( callConv >= ICC_THISCALL_OBJLAST )
{
- asASSERT( sysFunc->objForThiscall != 0 );
- // This class method is being called as object method (sysFunc->objForThiscall must be set).
- obj = sysFunc->objForThiscall;
+ asASSERT( sysFunc->auxiliary != 0 );
+ // This class method is being called as object method (sysFunc->auxiliary must be set).
+ obj = sysFunc->auxiliary;
continueCheckIndex = 1;
}
- else if( sysFunc->objForThiscall )
+ else if(sysFunc->auxiliary)
{
// This class method is being called as if it is a global function
- obj = sysFunc->objForThiscall;
+ obj = sysFunc->auxiliary;
continueCheck = false;
}
@@ -667,14 +686,21 @@ int CallSystemFunction(int id, asCContext *context)
popSize += AS_PTR_SIZE;
args += AS_PTR_SIZE;
- // When returning the value on the location allocated by the called
+ // When returning the value on the location allocated by the called
// we shouldn't set the object type in the register
context->m_regs.objectType = 0;
}
else
{
// Set the object type of the reference held in the register
- context->m_regs.objectType = descr->returnType.GetObjectType();
+ context->m_regs.objectType = descr->returnType.GetTypeInfo();
+ }
+
+ // For composition we need to add the offset and/or dereference the pointer
+ if(obj)
+ {
+ obj = (void*) ((char*) obj + sysFunc->compositeOffset);
+ if(sysFunc->isCompositeIndirect) obj = *((void**)obj);
}
context->m_callingSystemFunction = descr;
@@ -682,10 +708,10 @@ int CallSystemFunction(int id, asCContext *context)
#ifdef AS_NO_EXCEPTIONS
retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj);
#else
- // This try/catch block is to catch potential exception that may
+ // This try/catch block is to catch potential exception that may
// be thrown by the registered function. The implementation of the
// CallSystemFunctionNative() must make sure not to have any manual
- // clean-up after the call to the real function, or that won't be
+ // clean-up after the call to the real function, or that won't be
// executed in case of an exception.
try
{
@@ -695,7 +721,7 @@ int CallSystemFunction(int id, asCContext *context)
{
cppException = true;
- // Convert the exception to a script exception so the VM can
+ // Convert the exception to a script exception so the VM can
// properly report the error to the application and then clean up
context->SetException(TXT_EXCEPTION_CAUGHT);
}
@@ -703,7 +729,7 @@ int CallSystemFunction(int id, asCContext *context)
context->m_callingSystemFunction = 0;
// Store the returned value in our stack
- if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
+ if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
{
if( descr->returnType.IsObjectHandle() )
{
@@ -717,8 +743,8 @@ int CallSystemFunction(int id, asCContext *context)
if( sysFunc->returnAutoHandle && context->m_regs.objectRegister )
{
- asASSERT( !(descr->returnType.GetObjectType()->flags & asOBJ_NOCOUNT) );
- engine->CallObjectMethod(context->m_regs.objectRegister, descr->returnType.GetObjectType()->beh.addref);
+ asASSERT( !(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT) );
+ engine->CallObjectMethod(context->m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref);
}
}
else
@@ -754,12 +780,12 @@ int CallSystemFunction(int id, asCContext *context)
if( context->m_status == asEXECUTION_EXCEPTION && !cppException )
{
- // If the function raised a script exception it really shouldn't have
- // initialized the object. However, as it is a soft exception there is
+ // If the function raised a script exception it really shouldn't have
+ // initialized the object. However, as it is a soft exception there is
// no way for the application to not return a value, so instead we simply
// destroy it here, to pretend it was never created.
- if( descr->returnType.GetObjectType()->beh.destruct )
- engine->CallObjectMethod(retPointer, descr->returnType.GetObjectType()->beh.destruct);
+ if(CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct )
+ engine->CallObjectMethod(retPointer, CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct);
}
}
}
@@ -833,7 +859,7 @@ int CallSystemFunction(int id, asCContext *context)
// Skip the object pointer on the stack
// TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
- if( callConv >= ICC_THISCALL && sysFunc->objForThiscall == 0 )
+ if( callConv >= ICC_THISCALL && sysFunc->auxiliary == 0 )
args += AS_PTR_SIZE;
asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
@@ -848,14 +874,14 @@ int CallSystemFunction(int id, asCContext *context)
*addr = 0;
}
}
- else
+ else
{
asASSERT( clean->op == 1 || clean->op == 2 );
asASSERT( *addr );
if( clean->op == 2 )
engine->CallObjectMethod(*addr, clean->ot->beh.destruct);
-
+
engine->CallFree(*addr);
}
}
diff --git a/lib/angelscript/source/as_callfunc.h b/lib/angelscript/source/as_callfunc.h
index dde7f72d7..c77a4d708 100644
--- a/lib/angelscript/source/as_callfunc.h
+++ b/lib/angelscript/source/as_callfunc.h
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2014 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -49,7 +49,7 @@ class asCScriptFunction;
class asCObjectType;
struct asSSystemFunctionInterface;
-int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal);
+int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal);
int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine);
@@ -59,7 +59,7 @@ int CallSystemFunction(int id, asCContext *context);
inline asPWORD FuncPtrToUInt(asFUNCTION_t func)
{
- // A little trickery as the C++ standard doesn't allow direct
+ // A little trickery as the C++ standard doesn't allow direct
// conversion between function pointer and data pointer
union { asFUNCTION_t func; asPWORD idx; } u;
u.func = func;
@@ -108,7 +108,9 @@ struct asSSystemFunctionInterface
bool takesObjByVal;
asCArray paramAutoHandles; // TODO: Should be able to remove this array. Perhaps the flags can be stored together with the inOutFlags in asCScriptFunction?
bool returnAutoHandle;
- void *objForThiscall;
+ int compositeOffset;
+ bool isCompositeIndirect;
+ void *auxiliary; // can be used for functors, e.g. by asCALL_THISCALL_ASGLOBAL or asCALL_THISCALL_OBJFIRST
struct SClean
{
@@ -118,7 +120,7 @@ struct asSSystemFunctionInterface
};
asCArray cleanArgs;
- asSSystemFunctionInterface() {}
+ asSSystemFunctionInterface() : func(0), baseOffset(0), callConv(ICC_GENERIC_FUNC), scriptReturnSize(0), hostReturnInMemory(false), hostReturnFloat(false), hostReturnSize(0), paramSize(0), takesObjByVal(false), returnAutoHandle(false), compositeOffset(0), isCompositeIndirect(false), auxiliary(0) {}
asSSystemFunctionInterface(const asSSystemFunctionInterface &in)
{
@@ -127,19 +129,21 @@ struct asSSystemFunctionInterface
asSSystemFunctionInterface &operator=(const asSSystemFunctionInterface &in)
{
- func = in.func;
- baseOffset = in.baseOffset;
- callConv = in.callConv;
- scriptReturnSize = in.scriptReturnSize;
- hostReturnInMemory = in.hostReturnInMemory;
- hostReturnFloat = in.hostReturnFloat;
- hostReturnSize = in.hostReturnSize;
- paramSize = in.paramSize;
- takesObjByVal = in.takesObjByVal;
- paramAutoHandles = in.paramAutoHandles;
- returnAutoHandle = in.returnAutoHandle;
- objForThiscall = in.objForThiscall;
- cleanArgs = in.cleanArgs;
+ func = in.func;
+ baseOffset = in.baseOffset;
+ callConv = in.callConv;
+ scriptReturnSize = in.scriptReturnSize;
+ hostReturnInMemory = in.hostReturnInMemory;
+ hostReturnFloat = in.hostReturnFloat;
+ hostReturnSize = in.hostReturnSize;
+ paramSize = in.paramSize;
+ takesObjByVal = in.takesObjByVal;
+ paramAutoHandles = in.paramAutoHandles;
+ returnAutoHandle = in.returnAutoHandle;
+ compositeOffset = in.compositeOffset;
+ isCompositeIndirect = in.isCompositeIndirect;
+ auxiliary = in.auxiliary;
+ cleanArgs = in.cleanArgs;
return *this;
}
};
diff --git a/lib/angelscript/source/as_callfunc_arm.cpp b/lib/angelscript/source/as_callfunc_arm.cpp
index a5d20355e..6d820702f 100644
--- a/lib/angelscript/source/as_callfunc_arm.cpp
+++ b/lib/angelscript/source/as_callfunc_arm.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2014 Andreas Jonsson
+ Copyright (c) 2003-2015 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -150,7 +150,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
{
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
+ if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
{
paramBuffer[dpos++] = args[spos++];
paramSize++;
@@ -159,7 +159,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
#endif
{
#if defined(AS_ANDROID) || defined(AS_LINUX)
- if( (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) &&
+ if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) &&
((dpos & 1) == mask) )
{
// 64 bit value align
@@ -337,8 +337,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
if( sysFunc->hostReturnInMemory )
{
// TODO: runtime optimize: This check should be done in PrepareSystemFunction
- if ( !( descr->returnType.GetObjectType()->flags & COMPLEX_RETURN_MASK ) &&
- ( descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS ) &&
+ if ( !( descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK ) &&
+ ( descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) &&
descr->returnType.GetSizeInMemoryBytes() <= 8 )
callConv--;
@@ -396,10 +396,10 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
{
// TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
- !(descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_ARRAY) )
+ !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) )
{
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
+ if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
{
paramBuffer[dpos++] = args[spos++];
paramSize++;
@@ -407,7 +407,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
else
#endif
{
- if( (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) )
+ if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) )
{
if ( (dpos & 1) == mask )
{
@@ -425,7 +425,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
}
// Copy the object's memory to the buffer
- if (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS)
+ if (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS)
{
int target = (freeFloatSlot > freeDoubleSlot) ? freeFloatSlot : freeDoubleSlot;
@@ -645,8 +645,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
// TODO: runtime optimize: This should be identified with a flag determined in PrepareSystemFunction
if ( !descr->returnType.IsObjectHandle() &&
!descr->returnType.IsReference() &&
- !(descr->returnType.GetObjectType()->flags & COMPLEX_RETURN_MASK) &&
- (descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS) )
+ !(descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK) &&
+ (descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) )
memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() );
}
diff --git a/lib/angelscript/source/as_callfunc_arm_gcc.S b/lib/angelscript/source/as_callfunc_arm_gcc.S
index 3ce5566a4..a311ee773 100644
--- a/lib/angelscript/source/as_callfunc_arm_gcc.S
+++ b/lib/angelscript/source/as_callfunc_arm_gcc.S
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2016 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -717,13 +717,14 @@ nomoreargsarmFuncR0R1:
#endif /* hard float abi */
+#endif /* arm */
+
#if defined(__linux__) && defined(__ELF__)
-/* ref: http://hardened.gentoo.org/gnu-stack.xml */
+/* ref: http://hardened.gentoo.org/gnu-stack.xml
+ ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */
.section .note.GNU-stack,"",%progbits
#endif
-#endif /* arm */
-
#endif /* !AS_MAX_PORTABILITY */
diff --git a/lib/angelscript/source/as_callfunc_mips.cpp b/lib/angelscript/source/as_callfunc_mips.cpp
index 0b2e3b4fc..be7d18952 100644
--- a/lib/angelscript/source/as_callfunc_mips.cpp
+++ b/lib/angelscript/source/as_callfunc_mips.cpp
@@ -135,7 +135,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
asCDataType ¶mType = descr->parameterTypes[n];
if( paramType.IsObject() && !paramType.IsObjectHandle() && !paramType.IsReference() )
{
- if( paramType.GetObjectType()->flags & COMPLEX_MASK )
+ if( paramType.GetTypeInfo()->flags & COMPLEX_MASK )
{
// The object is passed by reference
argBuffer[argOffset++] = args[spos++];
@@ -143,7 +143,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
else
{
// Ensure 8byte alignment for classes that need it
- if( (paramType.GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) )
+ if( (paramType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) )
argOffset++;
// Copy the object's memory to the buffer
@@ -557,7 +557,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
{
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
+ if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
{
paramBuffer[dpos++] = args[spos++];
paramSize++;
diff --git a/lib/angelscript/source/as_callfunc_ppc.cpp b/lib/angelscript/source/as_callfunc_ppc.cpp
index 32a73f8f8..053221fe9 100644
--- a/lib/angelscript/source/as_callfunc_ppc.cpp
+++ b/lib/angelscript/source/as_callfunc_ppc.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2014 Andreas Jonsson
+ Copyright (c) 2003-2015 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -576,7 +576,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
{
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
+ if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
{
argsType[a++] = ppcINTARG;
paramBuffer[dpos++] = args[spos++];
diff --git a/lib/angelscript/source/as_callfunc_ppc_64.cpp b/lib/angelscript/source/as_callfunc_ppc_64.cpp
index a2c62f2b9..275f6152b 100644
--- a/lib/angelscript/source/as_callfunc_ppc_64.cpp
+++ b/lib/angelscript/source/as_callfunc_ppc_64.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2014 Andreas Jonsson
+ Copyright (c) 2003-2016 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -41,6 +41,10 @@
#ifndef AS_MAX_PORTABILITY
#ifdef AS_PPC_64
+#if AS_PTR_SIZE == 2
+// TODO: Add support for PPC 64bit platforms with 64bit pointers, for example Linux PPC64 (big endian) and PPC64 (little endian)
+#error This code has not been prepared for PPC with 64bit pointers. Most likely the ABI is different
+#else
#include "as_callfunc.h"
#include "as_scriptengine.h"
@@ -666,10 +670,10 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
{
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
- !(descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_ARRAY) )
+ !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) )
{
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
+ if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
{
paramBuffer[dpos++] = args[spos++];
++paramSize;
@@ -763,6 +767,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
END_AS_NAMESPACE
+#endif // AS_PTR_SIZE == 2
#endif // AS_PPC_64
#endif // AS_MAX_PORTABILITY
diff --git a/lib/angelscript/source/as_callfunc_sh4.cpp b/lib/angelscript/source/as_callfunc_sh4.cpp
index 2fb4ff68f..b24be9a54 100644
--- a/lib/angelscript/source/as_callfunc_sh4.cpp
+++ b/lib/angelscript/source/as_callfunc_sh4.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2014 Andreas Jonsson
+ Copyright (c) 2003-2015 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -313,7 +313,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
{
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
+ if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
{
paramBuffer[dpos++] = args[spos++];
paramSize++;
diff --git a/lib/angelscript/source/as_callfunc_x64_gcc.cpp b/lib/angelscript/source/as_callfunc_x64_gcc.cpp
index e05ae986f..ad6c27fb6 100644
--- a/lib/angelscript/source/as_callfunc_x64_gcc.cpp
+++ b/lib/angelscript/source/as_callfunc_x64_gcc.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -157,7 +157,7 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
" movq %%rdx, %4 \n"
"endcall: \n"
- : : "r" ((asQWORD)cnt), "r" (args), "r" (func), "m" (retQW1), "m" (retQW2), "m" (returnFloat)
+ : : "g" ((asQWORD)cnt), "g" (args), "g" (func), "m" (retQW1), "m" (retQW2), "m" (returnFloat)
: "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
"%rdi", "%rsi", "%rax", "%rdx", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r15");
@@ -345,7 +345,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
else
{
// An object is being passed by value
- if( (parmType.GetObjectType()->flags & COMPLEX_MASK) ||
+ if( (parmType.GetTypeInfo()->flags & COMPLEX_MASK) ||
parmType.GetSizeInMemoryDWords() > 4 )
{
// Copy the address of the object
@@ -353,8 +353,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asQWORD));
argIndex++;
}
- else if( (parmType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLINTS) ||
- (parmType.GetObjectType()->flags & asOBJ_APP_PRIMITIVE) )
+ else if( (parmType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLINTS) ||
+ (parmType.GetTypeInfo()->flags & asOBJ_APP_PRIMITIVE) )
{
// Copy the value of the object
if( parmType.GetSizeInMemoryDWords() > 2 )
@@ -373,8 +373,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
// Delete the original memory
engine->CallFree(*(void**)stack_pointer);
}
- else if( (parmType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS) ||
- (parmType.GetObjectType()->flags & asOBJ_APP_FLOAT) )
+ else if( (parmType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) ||
+ (parmType.GetTypeInfo()->flags & asOBJ_APP_FLOAT) )
{
// Copy the value of the object
if( parmType.GetSizeInMemoryDWords() > 2 )
diff --git a/lib/angelscript/source/as_callfunc_x64_mingw.cpp b/lib/angelscript/source/as_callfunc_x64_mingw.cpp
index 35e775fe9..1c5bdb552 100644
--- a/lib/angelscript/source/as_callfunc_x64_mingw.cpp
+++ b/lib/angelscript/source/as_callfunc_x64_mingw.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2014 Andreas Jonsson
+ Copyright (c) 2003-2015 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -248,7 +248,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
{
if( descr->parameterTypes[n].GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ||
- (descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) )
+ (descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) )
{
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
spos += AS_PTR_SIZE;
diff --git a/lib/angelscript/source/as_callfunc_x64_msvc.cpp b/lib/angelscript/source/as_callfunc_x64_msvc.cpp
index 84b96c2dd..8af5adc01 100644
--- a/lib/angelscript/source/as_callfunc_x64_msvc.cpp
+++ b/lib/angelscript/source/as_callfunc_x64_msvc.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2014 Andreas Jonsson
+ Copyright (c) 2003-2015 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -119,7 +119,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() )
{
if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ||
- (dt.GetObjectType()->flags & COMPLEX_MASK) )
+ (dt.GetTypeInfo()->flags & COMPLEX_MASK) )
{
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
spos += AS_PTR_SIZE;
diff --git a/lib/angelscript/source/as_callfunc_x86.cpp b/lib/angelscript/source/as_callfunc_x86.cpp
index d6f50db81..0ac690ed7 100644
--- a/lib/angelscript/source/as_callfunc_x86.cpp
+++ b/lib/angelscript/source/as_callfunc_x86.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2016 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -126,7 +126,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
{
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
+ if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
{
paramBuffer[dpos++] = args[spos++];
paramSize++;
@@ -340,6 +340,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)};
asm __volatile__(
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -374,7 +385,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
@@ -444,6 +462,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
asm __volatile__ (
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -479,7 +508,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
@@ -549,6 +585,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
asm __volatile__ (
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -584,7 +631,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
@@ -663,6 +717,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
asm __volatile__ (
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -702,7 +767,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
@@ -777,6 +849,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
asm __volatile__ (
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -813,7 +896,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
@@ -890,6 +980,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
asm __volatile__ (
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -929,7 +1030,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
@@ -994,6 +1102,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)};
asm __volatile__ (
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -1026,7 +1145,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
@@ -1107,6 +1233,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
asm __volatile__ (
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -1148,7 +1285,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
@@ -1236,6 +1380,17 @@ endcopy:
volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
asm __volatile__ (
+#ifdef __OPTIMIZE__
+ // When compiled with optimizations the stack unwind doesn't work properly,
+ // causing exceptions to crash the application. By adding this prologue
+ // and the epilogue below, the stack unwind works as it should.
+ // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
+ "pushl %%ebp \n"
+ ".cfi_adjust_cfa_offset 4 \n"
+ ".cfi_rel_offset ebp, 0 \n"
+ "movl %%esp, %%ebp \n"
+ ".cfi_def_cfa_register ebp \n"
+#endif
_S(CLEAR_FPU_STACK) "\n"
"pushl %%ebx \n"
"movl %%edx, %%ebx \n"
@@ -1290,7 +1445,14 @@ endcopy:
// Pop the alignment bytes
"popl %%esp \n"
"popl %%ebx \n"
-
+#ifdef __OPTIMIZE__
+ // Epilogue
+ "movl %%ebp, %%esp \n"
+ ".cfi_def_cfa_register esp \n"
+ "popl %%ebp \n"
+ ".cfi_adjust_cfa_offset -4 \n"
+ ".cfi_restore ebp \n"
+#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
"leal %1, %%ecx \n"
diff --git a/lib/angelscript/source/as_callfunc_xenon.cpp b/lib/angelscript/source/as_callfunc_xenon.cpp
index aaa4d8586..c52055e99 100644
--- a/lib/angelscript/source/as_callfunc_xenon.cpp
+++ b/lib/angelscript/source/as_callfunc_xenon.cpp
@@ -552,7 +552,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
!descr->parameterTypes[n].IsReference() )
{
#ifdef COMPLEX_OBJS_PASSED_BY_REF
- if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
+ if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
{
paramBuffer[dpos++] = args[spos++];
paramSize++;
diff --git a/lib/angelscript/source/as_compiler.cpp b/lib/angelscript/source/as_compiler.cpp
index 337e209df..e0f487c73 100644
--- a/lib/angelscript/source/as_compiler.cpp
+++ b/lib/angelscript/source/as_compiler.cpp
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -64,7 +64,7 @@ BEGIN_AS_NAMESPACE
-// TODO: I must correct the interpretation of a references to objects in the compiler.
+// TODO: I must correct the interpretation of a reference to objects in the compiler.
// A reference should mean that a pointer to the object is on the stack.
// No expression should end up as non-references to objects, as the actual object is
// never put on the stack.
@@ -96,14 +96,20 @@ asCCompiler::~asCCompiler()
asDELETE(var,asCVariableScope);
}
+
+ // Clean up all the string constants that were allocated. By now the script
+ // functions that were compiled successfully already holds their own references
+ for (asUINT n = 0; n < usedStringConstants.GetLength(); n++)
+ engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]);
+ usedStringConstants.SetLength(0);
}
-void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
+void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
{
- this->builder = builder;
- this->engine = builder->engine;
- this->script = script;
- this->outFunc = outFunc;
+ this->builder = in_builder;
+ this->engine = in_builder->engine;
+ this->script = in_script;
+ this->outFunc = in_outFunc;
hasCompileErrors = false;
@@ -121,11 +127,11 @@ void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFun
byteCode.ClearAll();
}
-int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
+int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
{
- Reset(builder, script, outFunc);
+ Reset(in_builder, in_script, in_outFunc);
- m_classDecl = classDecl;
+ m_classDecl = in_classDecl;
// Insert a JitEntry at the start of the function for JIT compilers
byteCode.InstrPTR(asBC_JitEntry, 0);
@@ -144,7 +150,7 @@ int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *s
{
// Make sure the base class really has a default constructor
if( outFunc->objectType->derivedFrom->beh.construct == 0 )
- Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, node);
+ Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node);
// Call the base class' default constructor
byteCode.InstrSHORT(asBC_PSF, 0);
@@ -172,21 +178,21 @@ int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *s
#ifdef AS_DEBUG
// DEBUG: output byte code
- byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), engine, outFunc);
+ byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc);
#endif
return 0;
}
-int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
+int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
{
- Reset(builder, script, outFunc);
+ Reset(in_builder, in_script, in_outFunc);
// Insert a JitEntry at the start of the function for JIT compilers
byteCode.InstrPTR(asBC_JitEntry, 0);
// Find the corresponding constructor
- asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
+ asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false);
int constructor = 0;
for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
{
@@ -230,7 +236,7 @@ int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCS
}
int argDwords = (int)outFunc->GetSpaceNeededForArguments();
- byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
+ byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE);
// Return a handle to the newly created object
byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
@@ -269,12 +275,11 @@ void asCCompiler::FinalizeFunction()
// Start with the variables allocated on the heap, and then the ones allocated on the stack
for( n = 0; n < variableAllocations.GetLength(); n++ )
{
- if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
+ if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
{
if( variableIsOnHeap[n] )
{
- outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
- outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
+ outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
}
}
@@ -282,12 +287,11 @@ void asCCompiler::FinalizeFunction()
outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
for( n = 0; n < variableAllocations.GetLength(); n++ )
{
- if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
+ if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
{
if( !variableIsOnHeap[n] )
{
- outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
- outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
+ outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
}
}
@@ -413,7 +417,7 @@ int asCCompiler::SetupParametersAndReturnVariable(asCArray ¶meter
return stackPos;
}
-void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDefaults)
+void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults)
{
asASSERT( m_classDecl );
@@ -477,11 +481,11 @@ void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDe
// here we should just validate that the member has a default constructor
if( prop->type.IsObject() &&
!prop->type.IsObjectHandle() &&
- (((prop->type.GetObjectType()->flags & asOBJ_REF) &&
+ (((prop->type.GetTypeInfo()->flags & asOBJ_REF) &&
prop->type.GetBehaviour()->factory == 0) ||
- ((prop->type.GetObjectType()->flags & asOBJ_VALUE) &&
+ ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) &&
prop->type.GetBehaviour()->construct == 0 &&
- !(prop->type.GetObjectType()->flags & asOBJ_POD))) )
+ !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) )
{
// Class has no default factory/constructor.
asCString str;
@@ -489,7 +493,7 @@ void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDe
if( prop->type.GetFuncDef() )
str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
else
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetObjectType()->GetName());
+ str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName());
Error(str, declNode);
}
#else
@@ -499,14 +503,14 @@ void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDe
script = initScript;
// Add a line instruction with the position of the declaration
- LineInstr(byteCode, declNode->tokenPos);
+ LineInstr(bc, declNode->tokenPos);
// Compile the initialization
asQWORD constantValue;
- asCByteCode bc(engine);
- CompileInitialization(initNode, &bc, prop->type, declNode, prop->byteOffset, &constantValue, 2);
- bc.OptimizeLocally(tempVariableOffsets);
- byteCode->AddCode(&bc);
+ asCByteCode bcInit(engine);
+ CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2);
+ bcInit.OptimizeLocally(tempVariableOffsets);
+ bc->AddCode(&bcInit);
script = origScript;
#endif
@@ -515,30 +519,30 @@ void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDe
}
// Entry
-int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray ¶meterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
+int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
{
TimeIt("asCCompiler::CompileFunction");
- Reset(builder, script, outFunc);
+ Reset(in_builder, in_script, in_outFunc);
int buildErrors = builder->numErrors;
- int stackPos = SetupParametersAndReturnVariable(parameterNames, func);
+ int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func);
//--------------------------------------------
// Compile the statement block
if( m_isConstructor )
- m_classDecl = classDecl;
+ m_classDecl = in_classDecl;
// We need to parse the statement block now
asCScriptNode *blockBegin;
// If the function signature was implicit, e.g. virtual property accessor or
// lambda function, then the received node already is the statement block
- if( func->nodeType != snStatementBlock )
- blockBegin = func->lastChild;
+ if( in_func->nodeType != snStatementBlock )
+ blockBegin = in_func->lastChild;
else
- blockBegin = func;
+ blockBegin = in_func;
// TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
// TODO: optimize: For large functions, the parsing of the statement block can take a long time. Presumably because a lot of memory needs to be allocated
@@ -656,7 +660,7 @@ int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asC
// Check if the number of labels in the functions isn't too many to be handled
if( nextLabel >= (1<<15) )
- Error(TXT_TOO_MANY_JUMP_LABELS, func);
+ Error(TXT_TOO_MANY_JUMP_LABELS, in_func);
// If there are compile errors, there is no reason to build the final code
if( hasCompileErrors || builder->numErrors != buildErrors )
@@ -675,15 +679,15 @@ int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asC
#ifdef AS_DEBUG
// DEBUG: output byte code
if( outFunc->objectType )
- byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
+ byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc);
else
- byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
+ byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc);
#endif
return 0;
}
-int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
+int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
{
if( !type.IsObject() )
return 0;
@@ -691,20 +695,20 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec
// CallCopyConstructor should not be called for object handles.
asASSERT( !type.IsObjectHandle() );
- asCArray args;
+ asCArray args;
args.PushLast(arg);
// The reference parameter must be pushed on the stack
- asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
+ asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() );
// Since we're calling the copy constructor, we have to trust the function to not do
// anything stupid otherwise we will just enter a loop, as we try to make temporary
// copies of the argument in order to guarantee safety.
- if( type.GetObjectType()->flags & asOBJ_REF )
+ if( type.GetTypeInfo()->flags & asOBJ_REF )
{
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
int func = 0;
asSTypeBehaviour *beh = type.GetBehaviour();
@@ -715,7 +719,7 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec
if( !isGlobalVar )
{
// Call factory and store the handle in the given variable
- PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
+ PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
// Pop the reference left by the function call
ctx.bc.Instr(asBC_PopPtr);
@@ -723,12 +727,12 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec
else
{
// Call factory
- PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
+ PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
// Store the returned handle in the global variable
ctx.bc.Instr(asBC_RDSPtr);
ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
- ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
+ ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
ctx.bc.Instr(asBC_PopPtr);
ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
}
@@ -769,8 +773,8 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec
}
}
- asSExprContext ctx(engine);
- PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
+ asCExprContext ctx(engine);
+ PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo()));
bc->AddCode(&ctx.bc);
@@ -786,7 +790,7 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec
// Class has no copy constructor/factory.
asCString str;
- str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
+ str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
Error(str, node);
return -1;
@@ -797,9 +801,9 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
if( !type.IsObject() || type.IsObjectHandle() )
return 0;
- if( type.GetObjectType()->flags & asOBJ_REF )
+ if( type.GetTypeInfo()->flags & asOBJ_REF )
{
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
ctx.exprNode = node;
int func = 0;
@@ -826,12 +830,12 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
if( func > 0 )
{
- asCArray args;
+ asCArray args;
asCScriptFunction *f = engine->scriptFunctions[func];
if( f->parameterTypes.GetLength() )
{
// Add the default values for arguments not explicitly supplied
- CompileDefaultAndNamedArgs(node, args, func, type.GetObjectType());
+ CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
PrepareFunctionCall(func, &ctx.bc, args);
@@ -841,7 +845,7 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
if( isVarGlobOrMem == 0 )
{
// Call factory and store the handle in the given variable
- PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
+ PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
// Pop the reference left by the function call
ctx.bc.Instr(asBC_PopPtr);
@@ -849,13 +853,13 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
else
{
// Call factory
- PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
+ PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
// TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
// instead of first storing it in a local variable and then copying it to the
// destination.
- if( !(type.GetObjectType()->flags & asOBJ_SCOPED) )
+ if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) )
{
// Only dereference the variable if not a scoped type
ctx.bc.Instr(asBC_RDSPtr);
@@ -871,10 +875,10 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
// Store the returned handle in the class member
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
- if( type.GetObjectType()->flags & asOBJ_SCOPED )
+ if( type.GetTypeInfo()->flags & asOBJ_SCOPED )
{
// For scoped typed we must move the reference from the local
// variable rather than copy it as there is no AddRef behaviour
@@ -885,7 +889,10 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
}
else
{
- ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
+ if( type.IsFuncdef() )
+ ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
}
ctx.bc.Instr(asBC_PopPtr);
ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
@@ -897,7 +904,7 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
for( asUINT n = 0; n < args.GetLength(); n++ )
if( args[n] )
{
- asDELETE(args[n],asSExprContext);
+ asDELETE(args[n], asCExprContext);
}
return 0;
@@ -905,7 +912,7 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
}
else
{
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
ctx.exprNode = node;
asSTypeBehaviour *beh = type.GetBehaviour();
@@ -932,14 +939,14 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
}
// Allocate and initialize with the default constructor
- if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
+ if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) )
{
- asCArray args;
+ asCArray args;
asCScriptFunction *f = engine->scriptFunctions[func];
if( f && f->parameterTypes.GetLength() )
{
// Add the default values for arguments not explicitly supplied
- CompileDefaultAndNamedArgs(node, args, func, type.GetObjectType());
+ CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
PrepareFunctionCall(func, &ctx.bc, args);
@@ -959,9 +966,9 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
if( derefDest )
bc->Instr(asBC_RDSPtr);
- asSExprContext ctx(engine);
- PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
- bc->AddCode(&ctx.bc);
+ asCExprContext ctxCall(engine);
+ PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
+ bc->AddCode(&ctxCall.bc);
// TODO: value on stack: This probably needs to be done in PerformFunctionCall
// Mark the object as initialized
@@ -971,18 +978,18 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
else if( isVarGlobOrMem == 2 )
{
// Only POD types can be allocated inline in script classes
- asASSERT( type.GetObjectType()->flags & asOBJ_POD );
+ asASSERT( type.GetTypeInfo()->flags & asOBJ_POD );
if( func )
{
// Call the constructor as a normal function
bc->InstrSHORT(asBC_PSF, 0);
bc->Instr(asBC_RDSPtr);
- bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
- asSExprContext ctx(engine);
- PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
- bc->AddCode(&ctx.bc);
+ asCExprContext ctxCall(engine);
+ PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
+ bc->AddCode(&ctxCall.bc);
}
}
else
@@ -1000,10 +1007,10 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
{
bc->InstrSHORT(asBC_PSF, 0);
bc->Instr(asBC_RDSPtr);
- bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
- if( (type.GetObjectType()->flags & asOBJ_TEMPLATE) )
+ if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
{
asCScriptFunction *descr = engine->scriptFunctions[func];
asASSERT( descr->funcType == asFUNC_SCRIPT );
@@ -1023,18 +1030,18 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
asASSERT( id );
- bc->InstrPTR(asBC_OBJTYPE, type.GetObjectType());
- bc->Alloc(asBC_ALLOC, type.GetObjectType(), id, AS_PTR_SIZE + AS_PTR_SIZE);
+ bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo());
+ bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE);
}
else
- bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
+ bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE);
}
// Cleanup
for( asUINT n = 0; n < args.GetLength(); n++ )
if( args[n] )
{
- asDELETE(args[n],asSExprContext);
+ asDELETE(args[n], asCExprContext);
}
return 0;
@@ -1043,11 +1050,7 @@ int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, boo
// Class has no default factory/constructor.
asCString str;
- // TODO: funcdef: asCDataType should have a GetTypeName()
- if( type.GetFuncDef() )
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
- else
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
+ str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
Error(str, node);
return -1;
@@ -1058,29 +1061,32 @@ void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnH
if( !type.IsReference() )
{
// Call destructor for the data type
- if( type.IsObject() )
+ if( type.IsObject() || type.IsFuncdef() )
{
// The null pointer doesn't need to be destroyed
if( type.IsNullHandle() )
return;
// Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
- if( type.GetObjectType()->flags & asOBJ_LIST_PATTERN )
+ if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN )
return;
if( isObjectOnHeap || type.IsObjectHandle() )
{
// Free the memory
- bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
+ if (type.IsFuncdef())
+ bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours);
+ else
+ bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo());
}
else
{
- asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
+ asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE );
if( type.GetBehaviour()->destruct )
{
// Call the destructor as a regular function
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
ctx.bc.OptimizeLocally(tempVariableOffsets);
@@ -1187,47 +1193,56 @@ void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableSc
}
// Entry
-int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
+int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc)
{
- Reset(builder, script, outFunc);
- m_globalVar = gvar;
+ Reset(in_builder, in_script, in_outFunc);
+ m_globalVar = in_gvar;
// Add a variable scope (even though variables can't be declared)
AddVariableScope();
- gvar->isPureConstant = false;
+ in_gvar->isPureConstant = false;
// Parse the initialization nodes
asCParser parser(builder);
- if( node )
+ if (in_node)
{
- int r = parser.ParseVarInit(script, node);
- if( r < 0 )
+ int r = parser.ParseVarInit(in_script, in_node);
+ if (r < 0)
return r;
- node = parser.GetScriptNode();
+ in_node = parser.GetScriptNode();
}
- asSExprContext compiledCtx(engine);
+ asCExprContext compiledCtx(engine);
bool preCompiled = false;
- if( gvar->datatype.IsAuto() )
- preCompiled = CompileAutoType(gvar->datatype, compiledCtx, node, gvar->declaredAtNode);
- if( gvar->property == 0 )
+ if (in_gvar->datatype.IsAuto())
{
- gvar->property = builder->module->AllocateGlobalProperty(gvar->name.AddressOf(), gvar->datatype, gvar->ns);
- gvar->index = gvar->property->id;
+ preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode);
+ if (!preCompiled)
+ {
+ // If it wasn't possible to determine the type from the expression then there
+ // is no need to continue with the initialization. The error was already reported
+ // in CompileAutoType.
+ return -1;
+ }
+ }
+ if( in_gvar->property == 0 )
+ {
+ in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns);
+ in_gvar->index = in_gvar->property->id;
}
// Compile the expression
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
asQWORD constantValue = 0;
- if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->declaredAtNode, gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
+ if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
{
// Should the variable be marked as pure constant?
- if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() )
+ if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() )
{
- gvar->isPureConstant = true;
- gvar->constantValue = constantValue;
+ in_gvar->isPureConstant = true;
+ in_gvar->constantValue = constantValue;
}
}
@@ -1236,10 +1251,10 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
// Add information on the line number for the global variable
size_t pos = 0;
- if( gvar->declaredAtNode )
- pos = gvar->declaredAtNode->tokenPos;
- else if( gvar->initializationNode )
- pos = gvar->initializationNode->tokenPos;
+ if( in_gvar->declaredAtNode )
+ pos = in_gvar->declaredAtNode->tokenPos;
+ else if( in_gvar->initializationNode )
+ pos = in_gvar->initializationNode->tokenPos;
LineInstr(&byteCode, pos);
// Reserve space for all local variables
@@ -1274,13 +1289,13 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
#ifdef AS_DEBUG
// DEBUG: output byte code
- byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
+ byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc);
#endif
return 0;
}
-void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node)
+void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node)
{
// Don't do anything if this is not a deferred global function
if( !ctx->IsGlobalFunc() )
@@ -1336,20 +1351,18 @@ void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node)
// Push the function pointer on the stack
ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
- ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0])));
+ ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false));
ctx->type.dataType.MakeHandle(true);
ctx->type.isExplicitHandle = true;
ctx->methodName = "";
}
-void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination)
+void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination)
{
- asASSERT( dt.GetObjectType() );
-
bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
// Use copy constructor if available.
- if( dt.GetObjectType()->beh.copyconstruct )
+ if(CastToObjectType(dt.GetTypeInfo()) && CastToObjectType(dt.GetTypeInfo())->beh.copyconstruct )
{
PrepareForAssignment(&dt, arg, node, true);
int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination);
@@ -1380,7 +1393,7 @@ void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc
// Call the opAssign method to assign the value to the temporary object
dt.MakeReference(isObjectOnHeap);
- asCTypeInfo type;
+ asCExprValue type;
type.Set(dt);
type.isTemporary = true;
type.stackOffset = (short)offset;
@@ -1401,7 +1414,7 @@ void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc
}
// Pop the reference that was pushed on the stack if the result is an object
- if( type.dataType.IsObject() )
+ if( type.dataType.IsObject() || type.dataType.IsFuncdef() )
bc->Instr(asBC_PopPtr);
// If the assignment operator returned an object by value it will
@@ -1414,7 +1427,7 @@ void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc
}
}
-int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
+int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
{
asCDataType param = *paramType;
if( paramType->GetTokenType() == ttQuestion )
@@ -1433,7 +1446,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
// If value assign is disabled for reference types, then make
// sure to always pass the handle to ? parameters
if( builder->engine->ep.disallowValueAssignForRefType &&
- ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
+ ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
{
param.MakeHandle(true);
}
@@ -1454,7 +1467,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
dt.MakeReadOnly(false);
int offset;
- if( refType == 1 ) // &in
+ if( refType == asTM_INREF )
{
ProcessPropertyGetAccessor(ctx, node);
@@ -1511,6 +1524,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
ctx->bc.InstrWORD(asBC_PSF, (short)offset);
ctx->type.SetVariable(dt, offset, true);
+ ctx->type.isExplicitHandle = true;
}
else
{
@@ -1540,12 +1554,14 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
// the function as it is, since the local variable will stay alive, and since it
// is temporary there is no side effect if the function modifies it.
- // If the parameter is read-only and therefor guaranteed not to be modified by the
+ // If the parameter is read-only and therefore guaranteed not to be modified by the
// function, then it is enough that the variable is local to guarantee the lifetime.
if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) )
{
- if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
+ if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) )
{
+ // Funcdefs only need an extra handle to guarantee the lifetime.
+
// If the object is a reference type (except scoped reference types), and the
// parameter is a const reference, then it is not necessary to make a copy of the
// object. The compiler just needs to hold a handle to guarantee the lifetime.
@@ -1557,17 +1573,26 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
// Copy the handle
Dereference(ctx, true);
ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
- ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
+ if (ctx->type.dataType.IsFuncdef())
+ ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
ctx->bc.Instr(asBC_PopPtr);
ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
// The type should be set to the param type instead of dt to guarantee
// that the expression keeps the correct type for variable ? args. Otherwise
// MoveArgsToStack will use the wrong bytecode to move the arg to the stack
+ bool isExplicitHandle = ctx->type.isExplicitHandle;
ctx->type.SetVariable(param, offset, true);
+ ctx->type.dataType.MakeHandle(true);
+ ctx->type.isExplicitHandle = isExplicitHandle;
}
else
{
+ // Make a copy of the object to guarantee that the original isn't modified
+ asASSERT(!dt.IsFuncdef());
+
// Allocate and initialize a temporary local object
offset = AllocateVariableNotIn(dt, true, false, ctx);
CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
@@ -1588,18 +1613,49 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
ctx->type.dataType.MakeReadOnly(true);
}
}
+
+ // When calling a function expecting a var arg with a parameter received as reference to handle
+ // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will
+ // not be able to do the correct double dereference to put the reference to the object on the stack.
+ if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable)
+ {
+ sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset);
+ if (var && var->type.IsReference() && var->type.IsObjectHandle())
+ {
+ // Copy the handle to local variable
+
+ // Allocate a handle variable
+ dt.MakeHandle(true);
+ offset = AllocateVariableNotIn(dt, true, false, ctx);
+
+ // Copy the handle
+ Dereference(ctx, true);
+ ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
+ if (ctx->type.dataType.IsFuncdef())
+ ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
+ ctx->bc.Instr(asBC_PopPtr);
+ ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
+
+ // The type should be set to the param type instead of dt to guarantee
+ // that the expression keeps the correct type for variable ? args. Otherwise
+ // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
+ ctx->type.SetVariable(param, offset, true);
+ }
+ }
}
else
{
// We must guarantee that the address to the value is on the stack
- if( ctx->type.dataType.IsObject() &&
+ if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
!ctx->type.dataType.IsObjectHandle() &&
ctx->type.dataType.IsReference() )
Dereference(ctx, true);
}
}
}
- else if( refType == 2 ) // &out
+ else if( refType == asTM_OUTREF )
{
// Add the type id as hidden arg if the parameter is a ? type
if( paramType->GetTokenType() == ttQuestion )
@@ -1624,6 +1680,11 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
}
else
{
+ // Null handles and void expressions must be marked as explicit
+ // handles for correct treatement in MoveArgsToStack
+ if (dt.IsNullHandle())
+ ctx->type.isExplicitHandle = true;
+
// Make sure the variable is not used in the expression
offset = AllocateVariableNotIn(dt, true, false, ctx);
@@ -1634,9 +1695,6 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
}
else
{
- // TODO: Need to reserve variables, as the default constructor may need
- // to allocate temporary variables to compute default args
-
// Allocate and construct the temporary object
asCByteCode tmpBC(engine);
CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
@@ -1645,16 +1703,17 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
tmpBC.AddCode(&ctx->bc);
ctx->bc.AddCode(&tmpBC);
- dt.MakeReference(!dt.IsObject() || dt.IsObjectHandle());
- asCTypeInfo type;
+ dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle());
+ asCExprValue type;
type.Set(dt);
type.isTemporary = true;
type.stackOffset = (short)offset;
+ type.isExplicitHandle = ctx->type.isExplicitHandle;
ctx->type = type;
ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
- if( dt.IsObject() && !dt.IsObjectHandle() )
+ if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() )
ctx->bc.Instr(asBC_RDSPtr);
}
@@ -1680,7 +1739,9 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
}
// Literal constants cannot be passed to inout ref arguments
- if( !ctx->type.isVariable && ctx->type.isConstant )
+ if( !ctx->type.isVariable &&
+ ctx->type.isConstant &&
+ !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) )
{
// Unless unsafe references are turned on and the reference is const
if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
@@ -1697,7 +1758,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
}
// Perform implicit ref cast if necessary, but don't allow the implicit conversion to create new objects
- if( ctx->type.dataType.IsObject() && ctx->type.dataType.GetObjectType() != dt.GetObjectType() )
+ if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() )
ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
// Only objects that support object handles
@@ -1706,15 +1767,16 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
// references
if( !engine->ep.allowUnsafeReferences &&
!ctx->type.isVariable &&
- ctx->type.dataType.IsObject() &&
+ (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
!ctx->type.dataType.IsObjectHandle() &&
((ctx->type.dataType.GetBehaviour()->addref &&
ctx->type.dataType.GetBehaviour()->release) ||
- (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
+ (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ||
+ ctx->type.dataType.IsFuncdef()) )
{
// Store a handle to the object as local variable
- asSExprContext tmp(engine);
- asCDataType dt = ctx->type.dataType;
+ asCExprContext tmp(engine);
+ dt = ctx->type.dataType;
dt.MakeHandle(true);
dt.MakeReference(false);
@@ -1724,7 +1786,10 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
ctx->bc.Instr(asBC_RDSPtr);
ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
- ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
+ if( ctx->type.dataType.IsFuncdef() )
+ ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
ctx->bc.Instr(asBC_PopPtr);
ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
@@ -1741,9 +1806,9 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
// Make sure the reference to the value is on the stack
// For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
// For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
- if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
+ if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
Dereference(ctx, true);
- else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
+ else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) )
ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
else if( ctx->type.dataType.IsPrimitive() )
ctx->bc.Instr(asBC_PshRPtr);
@@ -1795,41 +1860,31 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
if( dt.IsObjectHandle() )
ctx->type.isExplicitHandle = true;
- if( dt.IsObject() && !dt.IsNullHandle() )
+ if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() )
{
- if( !dt.IsReference() )
- {
- // Objects passed by value must be placed in temporary variables
- // so that they are guaranteed to not be referenced anywhere else.
- // The object must also be allocated on the heap, as the memory will
- // be deleted by in as_callfunc_xxx.
- // TODO: value on stack: How can we avoid this unnecessary allocation?
+ // Objects passed by value must be placed in temporary variables
+ // so that they are guaranteed to not be referenced anywhere else.
+ // The object must also be allocated on the heap, as the memory will
+ // be deleted by the called function.
- // Local variables doesn't need to be copied into
- // a temp if we're already compiling an assignment
- if( !isMakingCopy || !ctx->type.dataType.IsObjectHandle() || !ctx->type.isVariable )
- PrepareTemporaryObject(node, ctx, true);
+ // Handles passed by value must also be placed in a temporary variable
+ // to guarantee that the object referred to isn't freed too early.
- // The implicit conversion shouldn't convert the object to
- // non-reference yet. It will be dereferenced just before the call.
- // Otherwise the object might be missed by the exception handler.
- dt.MakeReference(true);
- }
- else
- {
- // An object passed by reference should place the pointer to
- // the object on the stack.
- dt.MakeReference(false);
- }
+ // TODO: value on stack: How can we avoid this unnecessary allocation?
+
+ // Don't make temporary copies of handles if it is going to be used
+ // for handle assignment anyway, i.e. REFCPY.
+ if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) )
+ PrepareTemporaryVariable(node, ctx, true);
}
}
}
// Don't put any pointer on the stack yet
- if( param.IsReference() || (param.IsObject() && !param.IsNullHandle()) )
+ if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) )
{
// &inout parameter may leave the reference on the stack already
- if( refType != 3 )
+ if( refType != asTM_INOUTREF )
{
asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
@@ -1846,7 +1901,7 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, as
return 0;
}
-void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args)
+void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args)
{
// When a match has been found, compile the final byte code using correct parameter types
asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
@@ -1858,18 +1913,18 @@ void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArrayparameterTypes.GetLength() == 1 &&
descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
- (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
- (descr->objectType == 0 && args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
+ (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
+ (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
makingCopy = true;
// Add code for arguments
- asSExprContext e(engine);
+ asCExprContext e(engine);
for( int n = (int)args.GetLength()-1; n >= 0; n-- )
{
// Make sure PrepareArgument doesn't use any variable that is already
- // being used by any of the following argument expressions
+ // being used by the argument or any of the following argument expressions
int l = int(reservedVariables.GetLength());
- for( int m = n-1; m >= 0; m-- )
+ for( int m = n; m >= 0; m-- )
args[m]->bc.GetVarsUsed(reservedVariables);
PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
@@ -1879,7 +1934,7 @@ void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArrayAddCode(&e.bc);
}
-void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset)
+void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset)
{
asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
@@ -1897,8 +1952,8 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArrayparameterTypes.GetLength() == 1 &&
descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
- (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
- (descr->objectType == 0 && args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
+ (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
+ (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
makingCopy = true;
#endif
@@ -1907,11 +1962,12 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArrayparameterTypes[n].IsReference() )
{
- if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
+ if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() )
{
if( descr->inOutFlags[n] != asTM_INOUTREF )
{
#ifdef AS_DEBUG
+ // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode
asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
#endif
@@ -1931,7 +1987,8 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArrayinOutFlags[n] != asTM_INOUTREF )
{
if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
- args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
+ (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) &&
+ !args[n]->type.dataType.IsObjectHandle() )
{
// Send the object as a reference to the object,
// and not to the variable holding the object
@@ -1942,21 +1999,42 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArrayInstrWORD(asBC_GETOBJREF, (asWORD)offset);
}
+ else if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
+ args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle)
+ {
+ // The object handle is being passed as an object, so dereference it before
+ // the call so the reference will be to the object rather than to the handle
+ if (engine->ep.disallowValueAssignForRefType )
+ {
+ // With disallow value assign all ref type objects are always passed by handle
+ bc->InstrWORD(asBC_GETREF, (asWORD)offset);
+ }
+ else
+ bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
+ }
else
{
- bc->InstrWORD(asBC_GETREF, (asWORD)offset);
+ // If the variable is really an argument of @& type, then it is necessary
+ // to use asBC_GETOBJREF so the pointer is correctly dereferenced.
+ sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset);
+ if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle())
+ bc->InstrWORD(asBC_GETREF, (asWORD)offset);
+ else
+ bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
}
}
}
- else if( descr->parameterTypes[n].IsObject() )
+ else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() )
{
// TODO: value on stack: What can we do to avoid this unnecessary allocation?
// The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
+ // The pointer in the variable will be moved to the stack
bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
- // The temporary variable must not be freed as it will no longer hold an object
+ // Deallocate the variable slot so it can be reused, but do not attempt to
+ // free the content of the variable since it was moved to the stack for the call
DeallocateVariable(args[n]->type.stackOffset);
args[n]->type.isTemporary = false;
}
@@ -1965,7 +2043,7 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, asCArray &namedArgs)
+int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs)
{
asASSERT(node->nodeType == snArgList);
@@ -2009,11 +2087,11 @@ int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *objectType, asCArray *namedArgs)
+int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *objectType, asCArray *namedArgs)
{
asCScriptFunction *func = builder->GetFunctionDescription(funcId);
if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
@@ -2068,7 +2146,7 @@ int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArraynameSpace;
outFunc->nameSpace = func->nameSpace;
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
r = CompileExpression(arg, &expr);
// Restore the namespace
outFunc->nameSpace = origNameSpace;
// Don't allow address of class method
- if( expr.methodName != "" )
+ if( expr.IsClassMethod() )
{
// TODO: Improve error message
Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
@@ -2178,7 +2256,7 @@ int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
+asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
{
asCArray origFuncs = funcs; // Keep the original list for error message
asUINT cost = 0;
@@ -2348,7 +2426,7 @@ asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArray &funcs, asCArrayIsClassMethod() )
{
attemptsPassingClassMethod = true;
- str += args[n]->type.dataType.GetObjectType()->GetName();
+ str += args[n]->type.dataType.GetTypeInfo()->GetName();
str += "::";
}
str += args[n]->methodName;
}
+ else if (args[n]->IsAnonymousInitList())
+ {
+ str += "{...}";
+ }
else
str += args[n]->type.dataType.Format(outFunc->nameSpace);
}
@@ -2428,7 +2510,7 @@ asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArraymethodName != "" )
str += named.ctx->methodName;
else
@@ -2480,43 +2562,63 @@ asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArraynodeType == snAssignment )
{
int r = CompileAssignment(node, &compiledCtx);
if( r >= 0 )
{
+ // Must not have unused ambiguous names
+ if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc())
+ {
+ // TODO: Should mention that the problem is the ambiguous name
+ Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
+ return false;
+ }
+
+ // Must not have unused anonymous functions
+ if (compiledCtx.IsLambda())
+ {
+ // TODO: Should mention that the problem is the anonymous function
+ Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
+ return false;
+ }
+
+ // Must not be a null handle
+ if (compiledCtx.type.dataType.IsNullHandle())
+ {
+ // TODO: Should mention that the problem is the null pointer
+ Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
+ return false;
+ }
+
asCDataType newType = compiledCtx.type.dataType;
- bool success = true;
// Handle const qualifier on auto
- if( type.IsReadOnly() )
+ if (type.IsReadOnly())
newType.MakeReadOnly(true);
- else if( newType.IsPrimitive() )
+ else if (newType.IsPrimitive())
newType.MakeReadOnly(false);
// Handle reference/value stuff
newType.MakeReference(false);
- if( !newType.IsObjectHandle() )
+ if (!newType.IsObjectHandle())
{
// We got a value object or an object reference.
// Turn the variable into a handle if specified
// as auto@, otherwise make it a 'value'.
- if( type.IsHandleToAuto() )
+ if (type.IsHandleToAuto())
{
- if( newType.MakeHandle(true) < 0 )
+ if (newType.MakeHandle(true) < 0)
{
Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
- success = false;
+ return false;
}
}
}
- if(success)
- type = newType;
- else
- type = asCDataType::CreatePrimitive(ttInt, false);
+ type = newType;
return true;
}
@@ -2533,17 +2635,26 @@ bool asCCompiler::CompileAutoType(asCDataType &type, asSExprContext &compiledCtx
void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
{
// Get the data type
- asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace);
+ asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
// Declare all variables in this declaration
asCScriptNode *node = decl->firstChild->next;
while( node )
{
// If this is an auto type, we have to compile the assignment now to figure out the type
- asSExprContext compiledCtx(engine);
+ asCExprContext compiledCtx(engine);
bool preCompiled = false;
- if( type.IsAuto() )
+ if (type.IsAuto())
+ {
preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
+ if (!preCompiled)
+ {
+ // If it wasn't possible to determine the type from the expression then there
+ // is no need to continue with the initialization. The error was already reported
+ // in CompileAutoType.
+ return;
+ }
+ }
// Is the type allowed?
if( !type.CanBeInstantiated() )
@@ -2558,14 +2669,15 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf());
Error(str, node);
- // Use int instead to avoid further problems
- type = asCDataType::CreatePrimitive(ttInt, false);
+ // Don't continue, as it will most likely lead to further
+ // errors that may just mislead the script writer
+ return;
}
// A shared object may not declare variables of non-shared types
if( outFunc->IsShared() )
{
- asCObjectType *ot = type.GetObjectType();
+ asCTypeInfo *ot = type.GetTypeInfo();
if( ot && !ot->IsShared() )
{
asCString msg;
@@ -2579,7 +2691,7 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
// Verify that the name isn't used by a dynamic data type
// TODO: Must check against registered funcdefs too
- if( engine->GetRegisteredObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
+ if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 )
{
asCString str;
str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
@@ -2646,20 +2758,20 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
}
// Returns true if the initialization expression is a constant expression
-bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asSExprContext *preCompiled)
+bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled)
{
bool isConstantExpression = false;
if( node && node->nodeType == snArgList )
{
// Make sure it is an object and not a handle
- if( type.GetObjectType() == 0 || type.IsObjectHandle() )
+ if( type.GetTypeInfo() == 0 || type.IsObjectHandle() )
{
Error(TXT_MUST_BE_OBJECT, node);
}
else
{
// Compile the arguments
- asCArray args;
+ asCArray args;
asCArray namedArgs;
if( CompileArgumentList(node, args, namedArgs) >= 0 )
{
@@ -2668,7 +2780,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
asSTypeBehaviour *beh = type.GetBehaviour();
if( beh )
{
- if( type.GetObjectType()->flags & asOBJ_REF )
+ if( type.GetTypeInfo()->flags & asOBJ_REF )
funcs = beh->factories;
else
funcs = beh->constructors;
@@ -2680,12 +2792,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
if( funcs.GetLength() == 1 )
{
// Add the default values for arguments not explicitly supplied
- int r = CompileDefaultAndNamedArgs(node, args, funcs[0], type.GetObjectType(), &namedArgs);
+ int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs);
if( r == asSUCCESS )
{
- asSExprContext ctx(engine);
- if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) )
+ asCExprContext ctx(engine);
+ if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
{
if( isVarGlobOrMem == 0 )
MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
@@ -2703,9 +2815,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
// Store the returned handle in the member
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
- ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
+ if( type.IsFuncdef())
+ ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
}
@@ -2736,12 +2851,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
else
{
// Value types may be allocated inline if they are POD types
- onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF);
+ onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
if( onHeap )
{
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
}
@@ -2756,7 +2871,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
{
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
else
{
@@ -2764,7 +2879,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
}
}
- PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
+ PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
if( isVarGlobOrMem == 0 )
{
@@ -2781,18 +2896,18 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
for( asUINT n = 0; n < args.GetLength(); n++ )
if( args[n] )
{
- asDELETE(args[n],asSExprContext);
+ asDELETE(args[n], asCExprContext);
}
for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
if( namedArgs[n].ctx )
{
- asDELETE(namedArgs[n].ctx,asSExprContext);
+ asDELETE(namedArgs[n].ctx, asCExprContext);
}
}
}
else if( node && node->nodeType == snInitList )
{
- asCTypeInfo ti;
+ asCExprValue ti;
ti.Set(type);
ti.isVariable = (isVarGlobOrMem == 0);
ti.isTemporary = false;
@@ -2803,11 +2918,9 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
}
else if( node && node->nodeType == snAssignment )
{
- asSExprContext ctx(engine);
-
// Compile the expression
- asSExprContext newExpr(engine);
- asSExprContext* expr;
+ asCExprContext newExpr(engine);
+ asCExprContext* expr;
int r = 0;
if( preCompiled )
@@ -2820,24 +2933,29 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
r = CompileAssignment(node, expr);
}
+ // handles initialized with null doesn't need any bytecode
+ // since handles will be initialized to null by default anyway
+ if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() )
+ return false;
+
// Look for appropriate constructor
asCArray funcs;
- asCArray args;
+ asCArray args;
// Handles must use the handle assignment operation.
// Types that are ASHANDLE must not allow the use of the constructor in this case,
// because it is ambiguous whether a value assignment or handle assignment will be done.
- // Only do this if the expression is of the same type, as the expression is an assignment
+ // Only do this if the expression is of the same type, as the expression is an assignment
// and an initialization constructor may not have the same meaning.
// TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions.
if( !type.IsObjectHandle() && !expr->type.isExplicitHandle &&
- !(type.GetObjectType() && (type.GetObjectType()->GetFlags() & asOBJ_ASHANDLE)) &&
+ !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) &&
type.IsEqualExceptRefAndConst(expr->type.dataType) )
{
asSTypeBehaviour *beh = type.GetBehaviour();
if( beh )
{
- if( type.GetObjectType()->flags & asOBJ_REF )
+ if( type.GetTypeInfo()->flags & asOBJ_REF )
funcs = beh->factories;
else
funcs = beh->constructors;
@@ -2846,6 +2964,14 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
asCString str = type.Format(outFunc->nameSpace);
args.PushLast(expr);
MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true);
+
+ // Make sure the argument is of the right type (and not just compatible with the expression)
+ if (funcs.GetLength() == 1)
+ {
+ asCScriptFunction *f = engine->scriptFunctions[funcs[0]];
+ if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType))
+ funcs.PopLast();
+ }
}
if( funcs.GetLength() == 1 )
@@ -2855,12 +2981,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
// TODO: clean-up: A large part of this is identical to the initalization with argList above
// Add the default values for arguments not explicitly supplied
- int r = CompileDefaultAndNamedArgs(node, args, funcs[0], type.GetObjectType());
+ r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()));
if( r == asSUCCESS )
{
- asSExprContext ctx(engine);
- if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) )
+ asCExprContext ctx(engine);
+ if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
{
if( isVarGlobOrMem == 0 )
MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
@@ -2878,9 +3004,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
// Store the returned handle in the member
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
- ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
+ if( type.IsFuncdef() )
+ ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
}
@@ -2911,12 +3040,12 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
else
{
// Value types may be allocated inline if they are POD types
- onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF);
+ onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
if( onHeap )
{
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
}
@@ -2931,7 +3060,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
{
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
else
{
@@ -2939,7 +3068,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
}
}
- PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
+ PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
if( isVarGlobOrMem == 0 )
{
@@ -2953,6 +3082,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
else
{
// Call the default constructur, then call the assignment operator
+ asCExprContext ctx(engine);
// Call the default constructor here
if( isVarGlobOrMem == 0 )
@@ -2972,10 +3102,10 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
// Tell caller that the expression is a constant so it can mark the variable as pure constant
isConstantExpression = true;
- *constantValue = expr->type.qwordValue;
+ *constantValue = expr->type.GetConstantData();
}
- asSExprContext lctx(engine);
+ asCExprContext lctx(engine);
if( isVarGlobOrMem == 0 )
lctx.type.SetVariable(type, offset, false);
else if( isVarGlobOrMem == 1 )
@@ -2997,7 +3127,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
// Load the reference of the primitive member into the register
lctx.bc.InstrSHORT(asBC_PSF, 0);
lctx.bc.Instr(asBC_RDSPtr);
- lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
lctx.bc.Instr(asBC_PopRPtr);
}
lctx.type.dataType.MakeReadOnly(false);
@@ -3012,7 +3142,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
// just the copy constructor. Only if no appropriate constructor is
// available should the assignment operator be used.
- asSExprContext lexpr(engine);
+ asCExprContext lexpr(engine);
lexpr.type.Set(type);
if( isVarGlobOrMem == 0 )
lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
@@ -3020,7 +3150,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
lexpr.type.dataType.MakeReference(true);
else if( isVarGlobOrMem == 2 )
{
- if( !lexpr.type.dataType.IsObject() || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_REF) )
+ if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) )
lexpr.type.dataType.MakeReference(true);
}
@@ -3044,7 +3174,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
{
lexpr.bc.InstrSHORT(asBC_PSF, 0);
lexpr.bc.Instr(asBC_RDSPtr);
- lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
lexpr.type.stackOffset = -1;
}
lexpr.type.isLValue = true;
@@ -3057,10 +3187,10 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
// and a simple assignment.
bool assigned = false;
// Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
- if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
+ if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) )
{
bool useHndlAssign = lexpr.type.dataType.IsHandleToAsHandleType();
- assigned = CompileOverloadedDualOperator(node, &lexpr, expr, &ctx, useHndlAssign);
+ assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign);
if( assigned )
{
// Pop the resulting value
@@ -3085,7 +3215,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
if( type.IsReadOnly() && expr->type.isConstant )
{
isConstantExpression = true;
- *constantValue = expr->type.qwordValue;
+ *constantValue = expr->type.GetConstantQW();
}
// Add expression code to bytecode
@@ -3120,7 +3250,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
else if( isVarGlobOrMem == 2 )
{
- if( !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF) )
+ if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) )
CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
else
CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
@@ -3130,10 +3260,10 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
return isConstantExpression;
}
-void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
+void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
{
// Check if the type supports initialization lists
- if( var->dataType.GetObjectType() == 0 ||
+ if( var->dataType.GetTypeInfo() == 0 ||
var->dataType.GetBehaviour()->listFactory == 0 )
{
asCString str;
@@ -3156,20 +3286,25 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
asCObjectType *listPatternType = engine->GetListPatternType(funcId);
// Allocate a temporary variable to hold the pointer to the buffer
- int bufferVar = AllocateVariable(asCDataType::CreateObject(listPatternType, false), true);
+ int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true);
asUINT bufferSize = 0;
// Evaluate all elements of the list
- asSExprContext valueExpr(engine);
+ asCExprContext valueExpr(engine);
asCScriptNode *el = node;
asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
int elementsInSubList = -1;
- int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateObject(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
+ int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
asASSERT( r || patternNode == 0 );
- UNUSED_VAR(r);
+ if (r < 0)
+ {
+ asCString msg;
+ msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
+ Error(msg, node);
+ }
// After all values have been evaluated we know the final size of the buffer
- asSExprContext allocExpr(engine);
+ asCExprContext allocExpr(engine);
allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
// Merge the bytecode into the final sequence
@@ -3177,20 +3312,20 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
bc->AddCode(&valueExpr.bc);
// The object itself is the last to be created and will receive the pointer to the buffer
- asCArray args;
- asSExprContext arg1(engine);
+ asCArray args;
+ asCExprContext arg1(engine);
arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
arg1.type.dataType.MakeReference(true);
arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
args.PushLast(&arg1);
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
if( var->isVariable )
{
asASSERT( isVarGlobOrMem == 0 );
- if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF )
+ if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
{
ctx.bc.AddCode(&arg1.bc);
@@ -3217,7 +3352,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
if( !onHeap )
ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
- PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType());
+ PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
// Mark the object in the local variable as initialized
ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
@@ -3225,7 +3360,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
}
else
{
- if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF )
+ if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
{
ctx.bc.AddCode(&arg1.bc);
@@ -3242,9 +3377,12 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
// Store the returned handle in the member
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
- ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
+ if (var->dataType.IsFuncdef())
+ ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo());
ctx.bc.Instr(asBC_PopPtr);
ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
}
@@ -3257,12 +3395,12 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
else
{
- onHeap = !var->dataType.IsObject() || var->dataType.IsReference() || (var->dataType.GetObjectType()->flags & asOBJ_REF);
+ onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF);
if( onHeap )
{
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
}
@@ -3273,11 +3411,11 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
{
ctx.bc.InstrSHORT(asBC_PSF, 0);
ctx.bc.Instr(asBC_RDSPtr);
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
}
// Call the ALLOC instruction to allocate memory and invoke constructor
- PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType());
+ PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
}
}
@@ -3289,7 +3427,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
ReleaseTemporaryVariable(bufferVar, bc);
}
-int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList)
+int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList)
{
if( patternNode->type == asLPT_START )
{
@@ -3312,7 +3450,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
}
asCScriptNode *errNode = node;
- int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, byteCode, elementsInSubList);
+ int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList);
if( r < 0 ) return r;
if( r == 1 )
@@ -3360,7 +3498,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
int elementsInSubSubList = -1;
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
while( valueNode )
{
patternNode = nextNode;
@@ -3370,7 +3508,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
if( r == 0 )
countElements++;
- else
+ else
{
asASSERT( r == 1 && engine->ep.disallowEmptyListElements );
if( valueNode )
@@ -3419,10 +3557,10 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
}
// The first dword in the buffer will hold the number of elements
- byteCode.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
+ bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
// Add the values
- byteCode.AddCode(&ctx.bc);
+ bcInit.AddCode(&ctx.bc);
}
else if( patternNode->type == asLPT_TYPE )
{
@@ -3435,8 +3573,8 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
{
- asSExprContext lctx(engine);
- asSExprContext rctx(engine);
+ asCExprContext lctx(engine);
+ asCExprContext rctx(engine);
if( valueNode->nodeType == snAssignment )
{
@@ -3445,6 +3583,9 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
if( dt.GetTokenType() == ttQuestion )
{
+ // Make sure the type is not ambiguous
+ DetermineSingleFunc(&rctx, valueNode);
+
// We now know the type
dt = rctx.type.dataType;
dt.MakeReadOnly(false);
@@ -3455,7 +3596,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
bufferSize += 4 - (bufferSize & 0x3);
// Place the type id in the buffer
- byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
+ bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
bufferSize += 4;
}
}
@@ -3491,7 +3632,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
}
// Determine size of the element
- if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
+ if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
size = dt.GetSizeInMemoryBytes();
else
size = AS_PTR_SIZE*4;
@@ -3510,51 +3651,47 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
lctx.type.dataType.MakeReference(true);
}
else if( dt.IsObjectHandle() ||
- dt.GetObjectType()->flags & asOBJ_REF )
+ dt.GetTypeInfo()->flags & asOBJ_REF )
{
lctx.type.isExplicitHandle = true;
lctx.type.dataType.MakeReference(true);
}
else
{
- asASSERT( dt.GetObjectType()->flags & asOBJ_VALUE );
+ asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE );
// Make sure the object has been constructed before the assignment
// TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
asSTypeBehaviour *beh = dt.GetBehaviour();
int func = 0;
if( beh ) func = beh->construct;
- if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
+ if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
{
asCString str;
- // TODO: funcdef: asCDataType should have a GetTypeName()
- if( dt.GetFuncDef() )
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
- else
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
+ str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
Error(str, valueNode);
}
else if( func )
{
// Call the constructor as a normal function
- byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
+ bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
- asSExprContext ctx(engine);
- PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
- byteCode.AddCode(&ctx.bc);
+ asCExprContext ctx(engine);
+ PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
+ bcInit.AddCode(&ctx.bc);
}
}
if( lctx.type.dataType.IsNullHandle() )
{
- // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
+ // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
// The buffer is already initialized to zero in asBC_AllocMem anyway.
asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull );
asASSERT( reinterpret_cast(patternNode)->dataType.GetTokenType() == ttQuestion );
}
else
{
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
if( !lctx.type.dataType.IsPrimitive() )
@@ -3565,7 +3702,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
ProcessDeferredParams(&ctx);
- byteCode.AddCode(&ctx.bc);
+ bcInit.AddCode(&ctx.bc);
}
}
else
@@ -3585,27 +3722,23 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
bufferSize += 4 - (bufferSize & 0x3);
// Place the type id for a null handle in the buffer
- byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
+ bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
bufferSize += 4;
dt = asCDataType::CreateNullHandle();
// No need to initialize the handle as the buffer is already initialized with zeroes
}
- else if( dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_VALUE )
+ else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE )
{
// For value types with default constructor we need to call the constructor
asSTypeBehaviour *beh = dt.GetBehaviour();
int func = 0;
if( beh ) func = beh->construct;
- if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
+ if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
{
asCString str;
- // TODO: funcdef: asCDataType should have a GetTypeName()
- if( dt.GetFuncDef() )
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
- else
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
+ str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
Error(str, valueNode);
}
else if( func )
@@ -3615,14 +3748,14 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
bufferSize += 4 - (bufferSize & 0x3);
// Call the constructor as a normal function
- byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
+ bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
- asSExprContext ctx(engine);
- PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
- byteCode.AddCode(&ctx.bc);
+ asCExprContext ctx(engine);
+ PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
+ bcInit.AddCode(&ctx.bc);
}
}
- else if( !dt.IsObjectHandle() && dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_REF )
+ else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF )
{
// For ref types (not handles) we need to call the default factory
asSTypeBehaviour *beh = dt.GetBehaviour();
@@ -3631,30 +3764,26 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
if( func == 0 )
{
asCString str;
- // TODO: funcdef: asCDataType should have a GetTypeName()
- if( dt.GetFuncDef() )
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
- else
- str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
+ str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
Error(str, valueNode);
}
else if( func )
{
- asSExprContext rctx(engine);
- PerformFunctionCall(func, &rctx, false, 0, dt.GetObjectType());
+ asCExprContext rctx(engine);
+ PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
// Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
if( bufferSize & 0x3 )
bufferSize += 4 - (bufferSize & 0x3);
- asSExprContext lctx(engine);
+ asCExprContext lctx(engine);
lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
lctx.type.Set(dt);
lctx.type.isLValue = true;
lctx.type.isExplicitHandle = true;
lctx.type.dataType.MakeReference(true);
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
if( !lctx.type.dataType.IsPrimitive() )
@@ -3665,7 +3794,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
ProcessDeferredParams(&ctx);
- byteCode.AddCode(&ctx.bc);
+ bcInit.AddCode(&ctx.bc);
}
}
}
@@ -3674,7 +3803,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
if( !isEmpty )
{
// Determine size of the element
- if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
+ if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
size = dt.GetSizeInMemoryBytes();
else
size = AS_PTR_SIZE*4;
@@ -3748,7 +3877,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
//-------------------------------
// Compile the switch expression
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
CompileAssignment(snode->firstChild, &expr);
// Verify that the expression is a primitive type
@@ -3799,7 +3928,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
{
// Compile expression
- asSExprContext c(engine);
+ asCExprContext c(engine);
CompileExpression(cnode->firstChild, &c);
// Verify that the result is a constant
@@ -3807,24 +3936,24 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
// Verify that the result is an integral number
- if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() )
+ if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType())
Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
-
- ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
-
- // Has this case been declared already?
- if( caseValues.IndexOf(c.type.intValue) >= 0 )
+ else
{
- Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
+ ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
+
+ // Has this case been declared already?
+ if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0)
+ Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
+
+ // TODO: Optimize: We can insert the numbers sorted already
+
+ // Store constant for later use
+ caseValues.PushLast(c.type.GetConstantDW());
+
+ // Reserve label for this case
+ caseLabels.PushLast(nextLabel++);
}
-
- // TODO: Optimize: We can insert the numbers sorted already
-
- // Store constant for later use
- caseValues.PushLast(c.type.intValue);
-
- // Reserve label for this case
- caseLabels.PushLast(nextLabel++);
}
else
{
@@ -3843,7 +3972,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
cnode = cnode->next;
}
- // check for empty switch
+ // check for empty switch
if (caseValues.GetLength() == 0)
{
Error(TXT_EMPTY_SWITCH, snode);
@@ -3854,7 +3983,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
defaultLabel = breakLabel;
//---------------------------------
- // Output the optimized case comparisons
+ // Output the optimized case comparisons
// with jumps to the case code
//------------------------------------
@@ -3944,9 +4073,9 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
// Add the list of jumps to the correct labels (any holes, jump to default)
index = ranges[range];
- for( int n = caseValues[index]; n <= maxRange; n++ )
+ for( int i = caseValues[index]; i <= maxRange; i++ )
{
- if( caseValues[index] == n )
+ if( caseValues[index] == i )
expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
else
expr.bc.InstrINT(asBC_JMP, defaultLabel);
@@ -3957,13 +4086,12 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
else
{
// Simply make a comparison with each value
- int n;
- for( n = ranges[range]; n < index; ++n )
+ for( int i = ranges[range]; i < index; ++i )
{
tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
- expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
+ expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]);
expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
- expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
+ expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]);
ReleaseTemporaryVariable(tmpOffset, &expr.bc);
}
}
@@ -4066,12 +4194,12 @@ void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCB
int afterLabel = nextLabel++;
// Compile the expression
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
int r = CompileAssignment(inode->firstChild, &expr);
if( r == 0 )
{
// Allow value types to be converted to bool using 'bool opImplConv()'
- if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
+ if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV);
if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
@@ -4096,7 +4224,11 @@ void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCB
expr.bc.OptimizeLocally(tempVariableOffsets);
bc->AddCode(&expr.bc);
}
- else if( expr.type.dwordValue == 0 )
+#if AS_SIZEOF_BOOL == 1
+ else if( expr.type.GetConstantB() == 0 )
+#else
+ else if (expr.type.GetConstantDW() == 0)
+#endif
{
// Jump to the else case
bc->InstrINT(asBC_JMP, afterLabel);
@@ -4216,7 +4348,7 @@ void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
//-----------------------------------
// Compile the condition statement
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
asCScriptNode *second = fnode->firstChild->next;
if( second->firstChild )
{
@@ -4224,7 +4356,7 @@ void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
if( r >= 0 )
{
// Allow value types to be converted to bool using 'bool opImplConv()'
- if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
+ if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV);
if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
@@ -4333,12 +4465,12 @@ void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
bc->Label((short)beforeLabel);
// Compile expression
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
int r = CompileAssignment(wnode->firstChild, &expr);
if( r == 0 )
{
// Allow value types to be converted to bool using 'bool opImplConv()'
- if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
+ if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV);
if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
@@ -4427,11 +4559,11 @@ void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
LineInstr(bc, wnode->lastChild->tokenPos);
// Compile expression
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
CompileAssignment(wnode->lastChild, &expr);
// Allow value types to be converted to bool using 'bool opImplConv()'
- if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
+ if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV);
if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
@@ -4518,7 +4650,7 @@ void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *
if( enode->firstChild )
{
// Compile the expression
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
CompileAssignment(enode->firstChild, &expr);
// Must not have unused ambiguous names
@@ -4549,8 +4681,11 @@ void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *
}
}
-void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap)
+void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap)
{
+ // The input can be either an object or funcdef, either as handle or reference
+ asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef());
+
// If the object already is stored in temporary variable then nothing needs to be done
// Note, a type can be temporary without being a variable, in which case it is holding off
// on releasing a previously used object.
@@ -4579,13 +4714,20 @@ void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ct
// Objects stored on the stack are not considered references
dt.MakeReference(IsVariableOnHeap(offset));
- asCTypeInfo lvalue;
+ asCExprValue lvalue;
lvalue.Set(dt);
lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
bool isExplicitHandle = ctx->type.isExplicitHandle;
+ bool prevIsTemp = ctx->type.isTemporary;
+ int prevStackOffset = ctx->type.stackOffset;
+
CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
+ // Release the previous temporary variable if it hasn't already been released
+ if( prevIsTemp && tempVariables.Exists(prevStackOffset) )
+ ReleaseTemporaryVariable(prevStackOffset, &ctx->bc);
+
// Push the reference to the temporary variable on the stack
ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
@@ -4618,7 +4760,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
if( rnode->firstChild )
{
// Compile the expression
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
int r = CompileAssignment(rnode->firstChild, &expr);
if( r < 0 ) return;
@@ -4660,7 +4802,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
// The type must match exactly as we cannot convert
// the reference without loosing the original value
if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
- (expr.type.dataType.IsObject() &&
+ ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) &&
!expr.type.dataType.IsObjectHandle() &&
v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
(!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
@@ -4773,7 +4915,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
}
}
- else if( v->type.IsObject() )
+ else if( v->type.IsObject() || v->type.IsFuncdef() )
{
// Value types are returned on the stack, in a location
// that has been reserved by the calling function.
@@ -4803,7 +4945,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
}
else
{
- asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
+ asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() );
// Prepare the expression to be loaded into the object
// register. This will place the reference in local variable
@@ -4932,7 +5074,7 @@ void asCCompiler::PrintMatchingFuncs(asCArray &funcs, asCScriptNode *node,
}
}
-int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx)
+int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx)
{
int l = int(reservedVariables.GetLength());
ctx->bc.GetVarsUsed(reservedVariables);
@@ -4957,7 +5099,7 @@ int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, boo
bool isOnHeap = true;
if( t.IsPrimitive() ||
- (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
+ (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
{
// Primitives and value types (unless overridden) are allocated on the stack
isOnHeap = false;
@@ -5092,6 +5234,7 @@ void asCCompiler::DeallocateVariable(int offset)
}
}
+ // Mark the variable slot available for new allocations
n = GetVariableSlot(offset);
if( n != -1 )
{
@@ -5100,13 +5243,13 @@ void asCCompiler::DeallocateVariable(int offset)
}
// We might get here if the variable was implicitly declared
- // because it was use before a formal declaration, in this case
+ // because it was used before a formal declaration, in this case
// the offset is 0x7FFF
asASSERT(offset == 0x7FFF);
}
-void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
+void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc)
{
if( t.isTemporary )
{
@@ -5137,11 +5280,11 @@ void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
DeallocateVariable(offset);
}
-void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
+void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode)
{
if( ctx->type.dataType.IsReference() )
{
- if( ctx->type.dataType.IsObject() )
+ if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() )
{
ctx->type.dataType.MakeReference(false);
if( generateCode )
@@ -5155,7 +5298,7 @@ void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
}
}
-bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
+bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node)
{
// No need to check if there is no variable scope
if( variables == 0 ) return true;
@@ -5175,7 +5318,7 @@ bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
if( v->isInitialized ) return true;
// Complex types don't need this test
- if( v->type.IsObject() ) return true;
+ if( v->type.IsObject() || v->type.IsFuncdef() ) return true;
// Mark as initialized so that the user will not be bothered again
v->isInitialized = true;
@@ -5188,7 +5331,7 @@ bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
return false;
}
-void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
+void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node)
{
// Check if the variable is initialized (if it indeed is a variable)
IsVariableInitialized(&ctx->type, node);
@@ -5201,7 +5344,7 @@ void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
ProcessDeferredParams(ctx);
}
-void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr)
+void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr)
{
// Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
int l = int(reservedVariables.GetLength());
@@ -5249,14 +5392,14 @@ void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx
// TODO: ImplicitConversion should know to do this by itself
// First convert to a handle which will do a reference cast
if( !lvalue->IsObjectHandle() &&
- (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
+ (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
to.MakeHandle(true);
// Don't allow the implicit conversion to create an object
ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
if( !lvalue->IsObjectHandle() &&
- (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
+ (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
{
// Then convert to a reference, which will validate the handle
to.MakeHandle(false);
@@ -5273,8 +5416,7 @@ void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx
else
{
// If the assignment will be made with the copy behaviour then the rvalue must not be a reference
- if( lvalue->IsObject() )
- asASSERT(!rctx->type.dataType.IsReference());
+ asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference());
}
}
@@ -5282,7 +5424,7 @@ void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx
reservedVariables.SetLength(l);
}
-bool asCCompiler::IsLValue(asCTypeInfo &type)
+bool asCCompiler::IsLValue(asCExprValue &type)
{
if( !type.isLValue ) return false;
if( type.dataType.IsReadOnly() ) return false;
@@ -5290,7 +5432,7 @@ bool asCCompiler::IsLValue(asCTypeInfo &type)
return true;
}
-int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
+int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node)
{
if( lvalue->dataType.IsReadOnly() )
{
@@ -5333,22 +5475,22 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC
}
else if( !lvalue->isExplicitHandle )
{
- asSExprContext ctx(engine);
+ asCExprContext ctx(engine);
ctx.type = *lvalue;
Dereference(&ctx, true);
*lvalue = ctx.type;
bc->AddCode(&ctx.bc);
asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
- if( beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
+ if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
{
- asSExprContext res(engine);
- PerformFunctionCall(beh->copy, &res, false, 0, lvalue->dataType.GetObjectType());
+ asCExprContext res(engine);
+ PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo()));
bc->AddCode(&res.bc);
*lvalue = res.type;
}
- else if( beh->copy == engine->scriptTypeBehaviours.beh.copy )
+ else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy )
{
// Call the default copy operator for script classes
// This is done differently because the default copy operator
@@ -5363,10 +5505,10 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC
{
// Default copy operator
if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
- !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
+ !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) )
{
asCString msg;
- msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf());
+ msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf());
Error(msg, node);
return -1;
}
@@ -5385,7 +5527,10 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC
return -1;
}
- bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
+ if( lvalue->dataType.IsFuncdef() )
+ bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo());
// Mark variable as initialized
if( variables )
@@ -5398,7 +5543,7 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC
return 0;
}
-bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
+bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
{
bool conversionDone = false;
@@ -5409,15 +5554,15 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
bool isConst = ctx->type.dataType.IsObjectConst();
// Find a suitable opCast or opImplCast method
- asCObjectType *ot = ctx->type.dataType.GetObjectType();
- for( n = 0; n < ot->methods.GetLength(); n++ )
+ asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
+ for( n = 0; ot && n < ot->methods.GetLength(); n++ )
{
asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
if( (isExplicit && func->name == "opCast") ||
func->name == "opImplCast" )
{
// Is the operator for the output type?
- if( func->returnType.GetObjectType() != to.GetObjectType() )
+ if( func->returnType.GetTypeInfo() != to.GetTypeInfo() )
continue;
// Can't call a non-const function on a const object
@@ -5431,9 +5576,22 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
// Filter the list by constness to remove const methods if there are matching non-const methods
FilterConst(ops, !isConst);
- // It shouldn't be possible to have more than one
- // TODO: Should be allowed to have different behaviours for const and non-const references
- asASSERT( ops.GetLength() <= 1 );
+ // Give an error more than one opCast methods were found
+ if (ops.GetLength() > 1)
+ {
+ if (isExplicit && generateCode)
+ {
+ asCString str;
+ str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, "opCast");
+ Error(str, node);
+
+ PrintMatchingFuncs(ops, node, ot);
+ }
+ // Return that the conversion was done to avoid further complaints
+ conversionDone = true;
+ ctx->type.Set(to);
+ return conversionDone;
+ }
// Should only have one behaviour for each output type
if( ops.GetLength() == 1 )
@@ -5450,13 +5608,13 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
// functions with 1 parameter, even though they should still be
// registered with RegisterObjectBehaviour()
- if( ctx->type.dataType.GetObjectType()->flags & asOBJ_REF )
+ if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
{
// Add code to avoid calling the cast behaviour if the handle is already null,
// because that will raise a null pointer exception due to the cast behaviour
// being a class method, and the this pointer cannot be null.
- if( !ctx->type.isVariable )
+ if (!ctx->type.isVariable)
{
Dereference(ctx, true);
ConvertToVariable(ctx);
@@ -5480,8 +5638,8 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
ctx->bc.Instr(asBC_RDSPtr);
ctx->type.dataType.MakeReference(false);
- asCArray args;
- MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
+ asCArray args;
+ MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
ctx->bc.Instr(asBC_PopPtr);
int endLabel = nextLabel++;
@@ -5498,11 +5656,15 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
}
else
{
- // Value types cannot be null, so there is no need to check for this
+ // Value types cannot be null, so there is no need to check for this.
+
+ // Likewise for reference types that are registered with asOBJ_NOHANDLE
+ // as those are only expected as registered global properties that cannot
+ // be modified anyway.
// Call the cast operator
- asCArray args;
- MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
+ asCArray args;
+ MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
}
}
else
@@ -5511,10 +5673,10 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
ctx->type.Set(func->returnType);
}
}
- else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
+ else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
{
// Check for the generic ref cast method: void opCast(?&out)
- for( n = 0; n < ot->methods.GetLength(); n++ )
+ for( n = 0; ot && n < ot->methods.GetLength(); n++ )
{
asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
if( (isExplicit && func->name == "opCast") ||
@@ -5542,14 +5704,49 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
{
asASSERT(to.IsObjectHandle());
+ int afterLabel = 0;
+ bool doNullCheck = false;
+ asCExprContext tmp(engine);
+ if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
+ {
+ tmp.bc.AddCode(&ctx->bc);
+ tmp.Merge(ctx);
+
+ // Add code to avoid calling the cast behaviour if the handle is already null,
+ // because that will raise a null pointer exception due to the cast behaviour
+ // being a class method, and the this pointer cannot be null.
+ doNullCheck = true;
+ if (!ctx->type.isVariable)
+ {
+ Dereference(&tmp, true);
+ ConvertToVariable(&tmp);
+ }
+
+ // The reference on the stack will not be used
+ tmp.bc.Instr(asBC_PopPtr);
+
+ // TODO: runtime optimize: should have immediate comparison for null pointer
+ int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
+ // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though)
+ tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
+ tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset);
+ DeallocateVariable(offset);
+
+ afterLabel = nextLabel++;
+ tmp.bc.InstrDWORD(asBC_JZ, afterLabel);
+
+ // Place the object pointer on the stack
+ ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset);
+ }
+
// Allocate a temporary variable of the requested handle type
int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
// Pass the reference of that variable to the function as output parameter
asCDataType toRef(to);
toRef.MakeReference(true);
- asCArray args;
- asSExprContext arg(engine);
+ asCArray args;
+ asCExprContext arg(engine);
arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
// Don't mark the variable as temporary, so it won't be freed too early
arg.type.SetVariable(toRef, stackOffset, false);
@@ -5558,7 +5755,23 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
args.PushLast(&arg);
// Call the behaviour method
- MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
+ MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
+
+ if (doNullCheck)
+ {
+ // Add the call after the null check
+ tmp.bc.AddCode(&ctx->bc);
+ ctx->bc.AddCode(&tmp.bc);
+
+ int endLabel = nextLabel++;
+
+ ctx->bc.InstrINT(asBC_JMP, endLabel);
+ ctx->bc.Label((short)afterLabel);
+
+ // Make a NULL pointer
+ ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset);
+ ctx->bc.Label((short)endLabel);
+ }
// Use the reference to the variable as the result of the expression
// Now we can mark the variable as temporary
@@ -5573,16 +5786,16 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
}
}
- // If the script object didn't implement a matching opCast or opImplCast
+ // If the script object didn't implement a matching opCast or opImplCast
// then check if the desired type is part of the hierarchy
- if( !conversionDone && (ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
+ if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
{
// We need it to be a reference
if( !ctx->type.dataType.IsReference() )
{
- asCDataType to = ctx->type.dataType;
- to.MakeReference(true);
- ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
+ asCDataType toRef = ctx->type.dataType;
+ toRef.MakeReference(true);
+ ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
}
if( isExplicit )
@@ -5616,10 +5829,10 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
}
else
{
- if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
+ if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) )
{
conversionDone = true;
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
}
@@ -5631,7 +5844,7 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
return conversionDone;
}
-asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
+asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
{
asCDataType to = toOrig;
to.MakeReference(false);
@@ -5653,7 +5866,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
// Attempt to resolve an ambiguous enum value
asCDataType out;
asDWORD value;
- if( builder->GetEnumValueFromObjectType(to.GetObjectType(), ctx->enumValue.AddressOf(), out, value) )
+ if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) )
{
ctx->type.SetConstantDW(out, value);
ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
@@ -5678,13 +5891,17 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
asUINT cost = asCC_NO_CONV;
if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
cost = asCC_INT_FLOAT_CONV;
- else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()) )
+ else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()))
cost = asCC_INT_FLOAT_CONV;
+ else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() )
+ cost = asCC_ENUM_SAME_SIZE_CONV;
+ else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes())
+ cost = asCC_ENUM_DIFF_SIZE_CONV;
else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
cost = asCC_SIGNED_CONV;
else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
cost = asCC_SIGNED_CONV;
- else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
+ else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() )
cost = asCC_PRIMITIVE_SIZE_CONV;
// Start by implicitly converting constant values
@@ -5732,7 +5949,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
{
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
else
{
@@ -5748,7 +5965,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ConvertToTempVariable(ctx);
ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
if( convType != asIC_EXPLICIT_VAL_CAST )
Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
@@ -5766,7 +5983,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
}
// Convert to smaller integer if necessary
- int s = to.GetSizeInMemoryBytes();
+ s = to.GetSizeInMemoryBytes();
if( s < 4 )
{
ConvertToTempVariable(ctx);
@@ -5784,7 +6001,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
{
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
else
{
@@ -5814,7 +6031,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ConvertToTempVariable(ctx);
ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
if( convType != asIC_EXPLICIT_VAL_CAST )
Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
@@ -5828,7 +6045,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
{
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
else
{
@@ -5844,7 +6061,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ConvertToTempVariable(ctx);
ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
if( convType != asIC_EXPLICIT_VAL_CAST )
Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
@@ -5862,7 +6079,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
}
// Convert to smaller integer if necessary
- int s = to.GetSizeInMemoryBytes();
+ s = to.GetSizeInMemoryBytes();
if( s < 4 )
{
ConvertToTempVariable(ctx);
@@ -5880,7 +6097,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
{
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
else
{
@@ -5910,7 +6127,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ConvertToTempVariable(ctx);
ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
if( convType != asIC_EXPLICIT_VAL_CAST )
Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
@@ -5923,7 +6140,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ConvertToTempVariable(ctx);
ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
{
@@ -5938,7 +6155,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ConvertToTempVariable(ctx);
ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
{
@@ -5972,7 +6189,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ConvertToTempVariable(ctx);
ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
{
@@ -5987,7 +6204,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ConvertToTempVariable(ctx);
ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
else if( ctx->type.dataType.IsFloatType() )
{
@@ -6008,7 +6225,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
{
ctx->type.dataType.SetTokenType(to.GetTokenType());
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
}
}
@@ -6017,9 +6234,9 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
return cost;
}
-asUINT asCCompiler::ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
+asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
{
- asASSERT( to.GetFuncDef() && ctx->IsLambda() );
+ asASSERT( to.IsFuncdef() && ctx->IsLambda() );
// Check that the lambda has the correct amount of arguments
asUINT count = 0;
@@ -6031,7 +6248,7 @@ asUINT asCCompiler::ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataT
}
asASSERT( argNode->nodeType == snStatementBlock );
- asCScriptFunction *funcDef = to.GetFuncDef();
+ asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef;
if( funcDef->parameterTypes.GetLength() != count )
return asCC_NO_CONV;
@@ -6059,14 +6276,25 @@ asUINT asCCompiler::ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataT
return asCC_CONST_CONV;
}
-asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
+asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
{
asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
- ctx->type.dataType.IsNullHandle() );
+ ctx->type.dataType.IsNullHandle() ||
+ ctx->IsAnonymousInitList() );
- if( to.GetFuncDef() && ctx->IsLambda() )
- {
+ if( to.IsFuncdef() && ctx->IsLambda() )
return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode);
+
+ if (ctx->IsAnonymousInitList())
+ {
+ if (to.GetBehaviour() && to.GetBehaviour()->listFactory)
+ {
+ if (generateCode)
+ CompilerAnonymousInitList(ctx->exprNode, ctx, to);
+ else
+ ctx->type.dataType = to;
+ }
+ return asCC_NO_CONV;
}
// No conversion from void to any other type
@@ -6099,14 +6327,14 @@ asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &t
{
if( ctx->type.dataType.IsPrimitive() )
return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
- else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
+ else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() )
return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
}
return asCC_NO_CONV;
}
-asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
+asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
{
if( ctx->type.isExplicitHandle )
{
@@ -6125,7 +6353,7 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC
// Find matching value cast behaviours
// Here we're only interested in those that convert the type to a primitive type
asCArray funcs;
- asCObjectType *ot = ctx->type.dataType.GetObjectType();
+ asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
if( ot == 0 )
{
if( convType != asIC_IMPLICIT_CONV && node )
@@ -6281,8 +6509,8 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC
asCDataType toRef(to);
toRef.MakeReference(true);
toRef.MakeReadOnly(false);
- asCArray args;
- asSExprContext arg(engine);
+ asCArray args;
+ asCExprContext arg(engine);
// Don't mark the variable as temporary, so it won't be freed too early
arg.type.SetVariable(toRef, stackOffset, false);
arg.type.isLValue = true;
@@ -6290,7 +6518,7 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC
args.PushLast(&arg);
// Call the behaviour method
- MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
+ MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
// Use the reference to the variable as the result of the expression
// Now we can mark the variable as temporary
@@ -6314,7 +6542,7 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC
}
-asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
+asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
{
// Convert null to any object type handle, but not to a non-handle type
if( ctx->type.IsNullConstant() && ctx->methodName == "" )
@@ -6327,47 +6555,47 @@ asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType
return asCC_NO_CONV;
}
- asASSERT(ctx->type.dataType.GetObjectType() || ctx->methodName != "");
+ asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != "");
// First attempt to convert the base type without instantiating another instance
- if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && ctx->methodName == "" )
+ if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" )
{
// If the to type is an interface and the from type implements it, then we can convert it immediately
- if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
+ if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) )
{
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
return asCC_REF_CONV;
}
// If the to type is a class and the from type derives from it, then we can convert it immediately
- else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
+ else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) )
{
- ctx->type.dataType.SetObjectType(to.GetObjectType());
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
return asCC_REF_CONV;
}
// If the types are not equal yet, then we may still be able to find a reference cast
- else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
+ else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() )
{
// We may still be able to find an implicit ref cast behaviour
CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
// Was the conversion done?
- if( ctx->type.dataType.GetObjectType() == to.GetObjectType() )
+ if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() )
return asCC_REF_CONV;
}
}
// Convert matching function types
- if( to.GetFuncDef() )
+ if( to.IsFuncdef() )
{
// If the input expression is already a funcdef, check if it can be converted
- if( ctx->type.dataType.GetFuncDef() &&
- to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
+ if( ctx->type.dataType.IsFuncdef() &&
+ to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
{
- asCScriptFunction *toFunc = to.GetFuncDef();
- asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
+ asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
+ asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef;
if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
{
- ctx->type.dataType.SetFuncDef(toFunc);
+ ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
return asCC_REF_CONV;
}
}
@@ -6399,10 +6627,11 @@ asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType
builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
// Check if any of the functions have perfect match
+ asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
for( asUINT n = 0; n < funcs.GetLength(); n++ )
{
asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
- if( to.GetFuncDef()->IsSignatureExceptNameEqual(func) )
+ if( toFunc->IsSignatureExceptNameEqual(func) )
{
if( generateCode )
{
@@ -6417,7 +6646,7 @@ asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType
}
}
- ctx->type.dataType = asCDataType::CreateFuncDef(to.GetFuncDef());
+ ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false);
return asCC_REF_CONV;
}
}
@@ -6427,16 +6656,16 @@ asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType
return asCC_NO_CONV;
}
-asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
+asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
{
asUINT cost = asCC_NO_CONV;
// If the base type is still different, and we are allowed to instance
// another object then we can try an implicit value cast
- if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
+ if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
{
// TODO: Implement support for implicit constructor/factory
- asCObjectType *ot = ctx->type.dataType.GetObjectType();
+ asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
if( ot == 0 )
return cost;
@@ -6450,7 +6679,7 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy
// accept both implicit and explicit cast
if( (func->name == "opConv" ||
func->name == "opImplConv") &&
- func->returnType.GetObjectType() == to.GetObjectType() &&
+ func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
func->parameterTypes.GetLength() == 0 )
funcs.PushLast(ot->methods[n]);
}
@@ -6463,7 +6692,7 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy
// accept only implicit cast
if( func->name == "opImplConv" &&
- func->returnType.GetObjectType() == to.GetObjectType() &&
+ func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
func->parameterTypes.GetLength() == 0 )
funcs.PushLast(ot->methods[n]);
}
@@ -6538,7 +6767,7 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy
// Pass the reference of that variable to the function as output parameter
asCDataType toRef(to);
toRef.MakeReference(false);
- asSExprContext arg(engine);
+ asCExprContext arg(engine);
arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
// If this an object on the heap, the pointer must be dereferenced
@@ -6550,14 +6779,14 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy
arg.type.isLValue = true;
arg.exprNode = node;
- // Mark the argument as clean, so that MakeFunctionCall knows it
+ // Mark the argument as clean, so that MakeFunctionCall knows it
// doesn't have to make a copy of it in order to protect the value
arg.isCleanArg = true;
// Call the behaviour method
- asCArray args;
+ asCArray args;
args.PushLast(&arg);
- MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
+ MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
// Use the reference to the variable as the result of the expression
// Now we can mark the variable as temporary
@@ -6576,19 +6805,19 @@ asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataTy
return cost;
}
-asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
+asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
{
// First try a ref cast
asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
// If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
// construct the object through any of the available constructors
- if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
+ if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
{
asCArray funcs;
- funcs = to.GetObjectType()->beh.constructors;
+ funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
- asCArray args;
+ asCArray args;
args.PushLast(ctx);
cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
@@ -6619,7 +6848,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
// TODO: This should really reuse the code from CompileConstructCall
// Allocate the new object
- asCTypeInfo tempObj;
+ asCExprValue tempObj;
tempObj.dataType = to;
tempObj.dataType.MakeReference(false);
tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
@@ -6630,7 +6859,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
// Push the address of the object on the stack
- asSExprContext e(engine);
+ asCExprContext e(engine);
if( onHeap )
e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
@@ -6649,7 +6878,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
else
e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
- PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType());
+ PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
// Add tag that the object has been initialized
e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
@@ -6668,14 +6897,14 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
}
else
{
- ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false));
+ ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
}
}
}
// If the base type is still different, and we are allowed to instance
// another object then we can try an implicit value cast
- if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
+ if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
{
// Attempt implicit value cast
cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
@@ -6683,7 +6912,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
// If we still haven't converted the base type to the correct type, then there is
// no need to continue as it is not possible to do the conversion
- if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
+ if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
return asCC_NO_CONV;
@@ -6698,13 +6927,25 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
// reference -> reference to handle
// object -> reference to handle
- // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
-
- // If the rvalue is a handle to a const object, then
- // the lvalue must also be a handle to a const object
- if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
+ if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) ||
+ (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) )
{
- if( convType != asIC_IMPLICIT_CONV )
+ // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
+ // TODO: NEWSTRING: Should have an engine property to warn or error on this
+ if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
+ {
+ if (generateCode)
+ PrepareTemporaryVariable(node, ctx);
+ else
+ {
+ ctx->type.dataType.MakeReadOnly(false);
+ ctx->type.isConstant = false;
+ }
+
+ // Add the cost for the copy
+ cost += asCC_TO_OBJECT_CONV;
+ }
+ else if( convType != asIC_IMPLICIT_CONV )
{
asASSERT(node);
asCString str;
@@ -6755,7 +6996,10 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
if( ctx->type.dataType.IsReference() )
ctx->bc.Instr(asBC_RDSPtr);
ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
- ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType());
+ if (dt.IsFuncdef())
+ ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo());
ctx->bc.Instr(asBC_PopPtr);
ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
@@ -6806,7 +7050,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
// If the object already is a temporary variable, then the copy
// doesn't have to be made as it is already a unique object
- PrepareTemporaryObject(node, ctx);
+ PrepareTemporaryVariable(node, ctx);
ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
ctx->type.isExplicitHandle = isExplicitHandle;
@@ -6862,7 +7106,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
if( generateCode )
{
// Make a temporary object with the copy
- PrepareTemporaryObject(node, ctx);
+ PrepareTemporaryVariable(node, ctx);
}
// In case the object was already in a temporary variable, then the function
@@ -6900,7 +7144,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
if( ctx->type.dataType.IsReference() )
{
- if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
+ if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
{
// ASHANDLE objects are really value types, so explicit handle can be removed
ctx->type.isExplicitHandle = false;
@@ -6919,7 +7163,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
// A reference to a non-const can be converted to a reference to a const
if( to.IsReadOnly() )
ctx->type.dataType.MakeReadOnly(true);
- else if( ctx->type.dataType.IsReadOnly() )
+ else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct )
{
// A reference to a const can be converted to a reference to a
// non-const by copying the object to a temporary variable
@@ -6929,7 +7173,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
{
// If the object already is a temporary variable, then the copy
// doesn't have to be made as it is already a unique object
- PrepareTemporaryObject(node, ctx);
+ PrepareTemporaryVariable(node, ctx);
}
// Add the cost for the copy
@@ -6964,7 +7208,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
// A value type allocated on the stack is differentiated
// by it not being a reference. But it can be handled as
// reference by pushing the pointer on the stack
- if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
+ if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) &&
(ctx->type.isVariable || ctx->type.isTemporary) &&
!IsVariableOnHeap(ctx->type.stackOffset) )
{
@@ -6983,7 +7227,7 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
// If the object already is a temporary variable, then the copy
// doesn't have to be made as it is already a unique object
- PrepareTemporaryObject(node, ctx);
+ PrepareTemporaryVariable(node, ctx);
ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
@@ -6997,9 +7241,45 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
}
- // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
- // Since it is a new temporary variable it doesn't have to be const
- ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
+ if (to.IsReadOnly())
+ {
+ // This doesn't cost anything
+ ctx->type.dataType.MakeReadOnly(true);
+ }
+
+ if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly())
+ {
+ // A const object can be converted to a non-const object through a copy
+ if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST)
+ {
+ ctx->type.dataType.MakeReadOnly(false);
+
+ if (generateCode)
+ {
+ // Make a temporary copy of the object in order to make it non-const
+ PrepareTemporaryVariable(node, ctx);
+ }
+
+ // Add the cost for the copy
+ cost += asCC_TO_OBJECT_CONV;
+ }
+
+ // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
+ // TODO: NEWSTRING: Should have an engine property to warn or error on this
+ if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
+ {
+ if (generateCode)
+ PrepareTemporaryVariable(node, ctx);
+ else
+ {
+ ctx->type.dataType.MakeReadOnly(false);
+ ctx->type.isConstant = false;
+ }
+
+ // Add the cost for the copy
+ cost += asCC_TO_OBJECT_CONV;
+ }
+ }
}
}
}
@@ -7007,12 +7287,12 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
return cost;
}
-asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
+asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
{
// Reference types currently don't allow implicit conversion from primitive to object
// TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
- asCObjectType *objType = to.GetObjectType();
- asASSERT( objType );
+ asCObjectType *objType = CastToObjectType(to.GetTypeInfo());
+ asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) );
if( !objType || (objType->flags & asOBJ_REF) )
return asCC_NO_CONV;
@@ -7033,10 +7313,10 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asC
return asCC_NO_CONV;
// Check if it is possible to choose a best match
- asSExprContext arg(engine);
+ asCExprContext arg(engine);
arg.type = ctx->type;
arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
- asCArray args;
+ asCArray args;
args.PushLast(&arg);
asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
if( funcs.GetLength() != 1 )
@@ -7054,7 +7334,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asC
ctx->type.SetDummy();
// Value types and script types are allocated through the constructor
- asCTypeInfo tempObj;
+ asCExprValue tempObj;
tempObj.dataType = to;
tempObj.stackOffset = (short)AllocateVariable(to, true);
tempObj.dataType.MakeReference(true);
@@ -7085,7 +7365,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asC
else
ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
- PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
+ PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
// Add tag that the object has been initialized
ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
@@ -7111,7 +7391,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asC
return cost;
}
-void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
+void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
{
asASSERT(from->type.isConstant);
@@ -7133,11 +7413,17 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
from->type.dataType.IsUnsignedType() ||
from->type.dataType.IsIntegerType() )
{
+ asCDataType targetDt;
+ if (to.IsEnumType())
+ targetDt = to;
+ else
+ targetDt = asCDataType::CreatePrimitive(ttInt, true);
+
// Transform the value
// Float constants can be implicitly converted to int
if( from->type.dataType.IsFloatType() )
{
- float fc = from->type.floatValue;
+ float fc = from->type.GetConstantF();
int ic = int(fc);
if( float(ic) != fc )
@@ -7145,12 +7431,12 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.intValue = ic;
+ from->type.SetConstantDW(targetDt, ic);
}
// Double constants can be implicitly converted to int
else if( from->type.dataType.IsDoubleType() )
{
- double fc = from->type.doubleValue;
+ double fc = from->type.GetConstantD();
int ic = int(fc);
if( double(ic) != fc )
@@ -7158,42 +7444,60 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.intValue = ic;
+ from->type.SetConstantDW(targetDt, ic);
}
else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
{
// Verify that it is possible to convert to signed without getting negative
- if( from->type.intValue < 0 )
- {
- if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
- }
+ if( from->type.dataType.GetSizeInMemoryBytes() == 4 &&
+ int(from->type.GetConstantDW()) < 0 &&
+ convType != asIC_EXPLICIT_VAL_CAST &&
+ node != 0 )
+ Warning(TXT_CHANGE_SIGN, node);
// Convert to 32bit
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- from->type.intValue = from->type.byteValue;
- else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- from->type.intValue = from->type.wordValue;
+ from->type.SetConstantDW(targetDt, from->type.GetConstantB());
+ else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
+ from->type.SetConstantDW(targetDt, from->type.GetConstantW());
+ else
+ from->type.dataType = targetDt;
}
else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
{
+ if (asQWORD(from->type.GetConstantQW()) >> 31)
+ if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
+
// Convert to 32bit
- from->type.intValue = int(from->type.qwordValue);
+ from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
}
- else if( from->type.dataType.IsIntegerType() &&
- from->type.dataType.GetSizeInMemoryBytes() < 4 )
+ else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2)
+ {
+ if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW()))
+ if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
+
+ // Convert to 32bit
+ from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
+ }
+ else if (from->type.dataType.IsIntegerType() &&
+ from->type.dataType.GetSizeInMemoryBytes() < 4)
{
// Convert to 32bit
- if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- from->type.intValue = (signed char)from->type.byteValue;
- else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- from->type.intValue = (short)from->type.wordValue;
+ if (from->type.dataType.GetSizeInMemoryBytes() == 1)
+ from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB());
+ else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
+ from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW());
}
-
- // Set the resulting type
- if( to.IsEnumType() )
- from->type.dataType = to;
else
- from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
+ {
+ // Only int32 and enums should come here and as these are 32bit
+ // already nothing needs to be done except set the target type
+ asASSERT((from->type.dataType.GetTokenType() == ttInt ||
+ from->type.dataType.IsEnumType()) &&
+ from->type.dataType.GetSizeInMemoryBytes() == 4);
+
+ from->type.dataType = targetDt;
+ }
}
// Check if a downsize is necessary
@@ -7204,20 +7508,18 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
// Verify if it is possible
if( to.GetSizeInMemoryBytes() == 1 )
{
- if( char(from->type.intValue) != from->type.intValue )
+ if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
- from->type.byteValue = char(from->type.intValue);
+ from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW()));
}
else if( to.GetSizeInMemoryBytes() == 2 )
{
- if( short(from->type.intValue) != from->type.intValue )
+ if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
- from->type.wordValue = short(from->type.intValue);
+ from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW()));
}
-
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
}
}
else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
@@ -7225,7 +7527,7 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
// Float constants can be implicitly converted to int
if( from->type.dataType.IsFloatType() )
{
- float fc = from->type.floatValue;
+ float fc = from->type.GetConstantF();
asINT64 ic = asINT64(fc);
if( float(ic) != fc )
@@ -7233,13 +7535,12 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
- from->type.qwordValue = ic;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
}
// Double constants can be implicitly converted to int
else if( from->type.dataType.IsDoubleType() )
{
- double fc = from->type.doubleValue;
+ double fc = from->type.GetConstantD();
asINT64 ic = asINT64(fc);
if( double(ic) != fc )
@@ -7247,46 +7548,42 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
- from->type.qwordValue = ic;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
}
else if( from->type.dataType.IsUnsignedType() )
{
// Convert to 64bit
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- from->type.qwordValue = from->type.byteValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB());
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- from->type.qwordValue = from->type.wordValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW());
else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
- from->type.qwordValue = from->type.dwordValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW());
else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
{
- if( asINT64(from->type.qwordValue) < 0 )
+ if( asINT64(from->type.GetConstantQW()) < 0 )
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
}
+ from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
}
-
- from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
}
else if( from->type.dataType.IsIntegerType() )
{
// Convert to 64bit
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- from->type.qwordValue = (signed char)from->type.byteValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB());
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- from->type.qwordValue = (short)from->type.wordValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW());
else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
- from->type.qwordValue = from->type.intValue;
-
- from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW());
}
}
else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
{
if( from->type.dataType.IsFloatType() )
{
- float fc = from->type.floatValue;
+ float fc = from->type.GetConstantF();
// Some compilers set the value to 0 when converting a negative float to unsigned int.
// To maintain a consistent behaviour across compilers we convert to int first.
asUINT uic = asUINT(int(fc));
@@ -7296,15 +7593,14 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
- from->type.intValue = uic;
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
// Try once more, in case of a smaller type
ImplicitConversionConstant(from, to, node, convType);
}
else if( from->type.dataType.IsDoubleType() )
{
- double fc = from->type.doubleValue;
+ double fc = from->type.GetConstantD();
// Some compilers set the value to 0 when converting a negative double to unsigned int.
// To maintain a consistent behaviour across compilers we convert to int first.
asUINT uic = asUINT(int(fc));
@@ -7314,8 +7610,7 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
- from->type.intValue = uic;
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
// Try once more, in case of a smaller type
ImplicitConversionConstant(from, to, node, convType);
@@ -7323,25 +7618,29 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
else if( from->type.dataType.IsIntegerType() )
{
// Verify that it is possible to convert to unsigned without loosing negative
- if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.qwordValue) < 0) ||
- (from->type.dataType.GetSizeInMemoryBytes() <= 4 && from->type.intValue < 0) )
+ if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) ||
+ (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) ||
+ (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) ||
+ (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0))
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
}
// Check if any data is lost
- if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.qwordValue >> 32) != 0 && (from->type.qwordValue >> 32) != 0xFFFFFFFF )
+ if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF )
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
}
// Convert to 32bit
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- from->type.intValue = (signed char)from->type.byteValue;
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB());
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- from->type.intValue = (short)from->type.wordValue;
-
- from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW());
+ else if (from->type.dataType.GetSizeInMemoryBytes() == 4 )
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW());
+ else
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW());
// Try once more, in case of a smaller type
ImplicitConversionConstant(from, to, node, convType);
@@ -7351,11 +7650,9 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
{
// Convert to 32bit
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- from->type.dwordValue = from->type.byteValue;
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB());
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- from->type.dwordValue = from->type.wordValue;
-
- from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW());
// Try once more, in case of a smaller type
ImplicitConversionConstant(from, to, node, convType);
@@ -7366,27 +7663,32 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
// Verify if it is possible
if( to.GetSizeInMemoryBytes() == 1 )
{
- if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
+ if( asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW() )
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
- from->type.byteValue = asBYTE(from->type.dwordValue);
+ from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
}
else if( to.GetSizeInMemoryBytes() == 2 )
{
- if( asWORD(from->type.dwordValue) != from->type.dwordValue )
+ if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW())
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
- from->type.wordValue = asWORD(from->type.dwordValue);
+ from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
}
+ else if (to.GetSizeInMemoryBytes() == 4)
+ {
+ if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW())
+ if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
+ from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW()));
+ }
}
}
else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
{
if( from->type.dataType.IsFloatType() )
{
- float fc = from->type.floatValue;
+ float fc = from->type.GetConstantF();
// Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
asQWORD uic = asQWORD(asINT64(fc));
@@ -7398,12 +7700,11 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
}
#endif
- from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
- from->type.qwordValue = uic;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
}
else if( from->type.dataType.IsDoubleType() )
{
- double fc = from->type.doubleValue;
+ double fc = from->type.GetConstantD();
// Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
asQWORD uic = asQWORD(asINT64(fc));
@@ -7415,21 +7716,20 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
}
#endif
- from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
- from->type.qwordValue = uic;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
}
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
{
// Convert to 64bit
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB());
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- from->type.qwordValue = (asINT64)(short)from->type.wordValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW());
else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
- from->type.qwordValue = (asINT64)from->type.intValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW());
// Verify that it is possible to convert to unsigned without loosing negative
- if( asINT64(from->type.qwordValue) < 0 )
+ if( asINT64(from->type.GetConstantQW()) < 0 )
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
}
@@ -7439,7 +7739,7 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
{
// Verify that it is possible to convert to unsigned without loosing negative
- if( asINT64(from->type.qwordValue) < 0 )
+ if( asINT64(from->type.GetConstantQW()) < 0 )
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
}
@@ -7450,35 +7750,32 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
{
// Convert to 64bit
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- from->type.qwordValue = from->type.byteValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB());
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- from->type.qwordValue = from->type.wordValue;
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW());
else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
- from->type.qwordValue = from->type.dwordValue;
-
- from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
+ from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW());
}
}
else if( to.IsFloatType() )
{
if( from->type.dataType.IsDoubleType() )
{
- double ic = from->type.doubleValue;
+ double ic = from->type.GetConstantD();
float fc = float(ic);
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.floatValue = fc;
+ from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
{
// Must properly convert value in case the from value is smaller
int ic;
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- ic = (signed char)from->type.byteValue;
+ ic = (asINT8)from->type.GetConstantB();
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- ic = (short)from->type.wordValue;
+ ic = (asINT16)from->type.GetConstantW();
else
- ic = from->type.intValue;
+ ic = (int)from->type.GetConstantDW();
float fc = float(ic);
if( int(fc) != ic )
@@ -7486,30 +7783,28 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.floatValue = fc;
+ from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
{
- float fc = float(asINT64(from->type.qwordValue));
- if( asINT64(fc) != asINT64(from->type.qwordValue) )
+ float fc = float(asINT64(from->type.GetConstantQW()));
+ if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.floatValue = fc;
+ from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
{
// Must properly convert value in case the from value is smaller
unsigned int uic;
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- uic = from->type.byteValue;
+ uic = from->type.GetConstantB();
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- uic = from->type.wordValue;
+ uic = from->type.GetConstantW();
else
- uic = from->type.dwordValue;
+ uic = from->type.GetConstantDW();
float fc = float(uic);
if( (unsigned int)(fc) != uic )
@@ -7517,42 +7812,39 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.floatValue = fc;
+ from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
{
- float fc = float((asINT64)from->type.qwordValue);
+ float fc = float((asINT64)from->type.GetConstantQW());
- if( asQWORD(fc) != from->type.qwordValue )
+ if( asQWORD(fc) != from->type.GetConstantQW())
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.floatValue = fc;
+ from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
}
else if( to.IsDoubleType() )
{
if( from->type.dataType.IsFloatType() )
{
- float ic = from->type.floatValue;
+ float ic = from->type.GetConstantF();
double fc = double(ic);
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.doubleValue = fc;
+ from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
{
// Must properly convert value in case the from value is smaller
int ic;
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- ic = (signed char)from->type.byteValue;
+ ic = (asINT8)from->type.GetConstantB();
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- ic = (short)from->type.wordValue;
+ ic = (asINT16)from->type.GetConstantW();
else
- ic = from->type.intValue;
+ ic = (int)from->type.GetConstantDW();
double fc = double(ic);
if( int(fc) != ic )
@@ -7560,31 +7852,29 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.doubleValue = fc;
+ from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
{
- double fc = double(asINT64(from->type.qwordValue));
+ double fc = double(asINT64(from->type.GetConstantQW()));
- if( asINT64(fc) != asINT64(from->type.qwordValue) )
+ if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.doubleValue = fc;
+ from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
{
// Must properly convert value in case the from value is smaller
unsigned int uic;
if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
- uic = from->type.byteValue;
+ uic = from->type.GetConstantB();
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
- uic = from->type.wordValue;
+ uic = from->type.GetConstantW();
else
- uic = from->type.dwordValue;
+ uic = from->type.GetConstantDW();
double fc = double(uic);
if( (unsigned int)(fc) != uic )
@@ -7592,25 +7882,23 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.doubleValue = fc;
+ from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
{
- double fc = double((asINT64)from->type.qwordValue);
+ double fc = double((asINT64)from->type.GetConstantQW());
- if( asQWORD(fc) != from->type.qwordValue )
+ if( asQWORD(fc) != from->type.GetConstantQW())
{
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
}
- from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
- from->type.doubleValue = fc;
+ from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
}
}
}
-int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
+int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
{
// Don't allow any operators on expressions that take address of class method
// If methodName is set but the type is not an object, then it is a global function
@@ -7621,7 +7909,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
}
// Implicit handle types should always be treated as handles in assignments
- if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
+ if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
{
lctx->type.dataType.MakeHandle(true);
lctx->type.isExplicitHandle = true;
@@ -7678,7 +7966,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
if( op != ttAssignment )
{
// Compute the operator before the assignment
- asCTypeInfo lvalue = lctx->type;
+ asCExprValue lvalue = lctx->type;
if( lctx->type.isTemporary && !lctx->type.isVariable )
{
@@ -7688,7 +7976,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
lctx->type.isTemporary = false;
}
- asSExprContext o(engine);
+ asCExprContext o(engine);
CompileOperator(opNode, lctx, rctx, &o);
MergeExprBytecode(rctx, &o);
rctx->type = o.type;
@@ -7733,13 +8021,13 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
return -1;
}
- if( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
+ if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
{
// The object is a value type but that should be treated as a handle
// Make sure the right hand value is a handle
if( !rctx->type.isExplicitHandle &&
- !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
+ !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) )
{
// Function names can be considered handles already
if( rctx->methodName == "" )
@@ -7757,9 +8045,14 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
return -1;
}
}
+
+ // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise
+ // the code for moving the argument to the stack may not know to correctly handle the argument type
+ // in case of variable parameter type.
+ rctx->type.isExplicitHandle = true;
}
- if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx, true) )
+ if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) )
{
// An overloaded assignment operator was found (or a compilation error occured)
return 0;
@@ -7776,7 +8069,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
asCDataType dt = lctx->type.dataType;
dt.MakeReference(false);
- PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF , true);
+ PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true);
if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
{
asCString str;
@@ -7816,7 +8109,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
}
// Check for overloaded assignment operator
- if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
+ if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) )
{
// An overloaded assignment operator was found (or a compilation error occured)
return 0;
@@ -7844,7 +8137,7 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
// the application developer is responsible for making the
// implementation safe against unwanted destruction of the input
// reference before the time.
- bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
+ bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
// Implicitly convert the rvalue to the type of the lvalue
bool needConversion = false;
@@ -7903,13 +8196,15 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
return 0;
}
-int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
+int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx)
{
+ asASSERT(expr->nodeType == snAssignment);
+
asCScriptNode *lexpr = expr->firstChild;
if( lexpr->next )
{
// Compile the two expression terms
- asSExprContext lctx(engine), rctx(engine);
+ asCExprContext lctx(engine), rctx(engine);
int rr = CompileAssignment(lexpr->next->next, &rctx);
int lr = CompileCondition(lexpr, &lctx);
@@ -7924,9 +8219,9 @@ int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
return CompileCondition(lexpr, ctx);
}
-int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
+int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
{
- asCTypeInfo ctype;
+ asCExprValue ctype;
// Compile the conditional expression
asCScriptNode *cexpr = expr->firstChild;
@@ -7934,13 +8229,13 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
{
//-------------------------------
// Compile the condition
- asSExprContext e(engine);
+ asCExprContext e(engine);
int r = CompileExpression(cexpr, &e);
if( r < 0 )
e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
// Allow value types to be converted to bool using 'bool opImplConv()'
- if( e.type.dataType.GetObjectType() && (e.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
+ if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV);
if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
@@ -7957,13 +8252,17 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
//-------------------------------
// Compile the left expression
- asSExprContext le(engine);
+ asCExprContext le(engine);
int lr = CompileAssignment(cexpr->next, &le);
+ // Resolve any function names already
+ DetermineSingleFunc(&le, cexpr->next);
+
//-------------------------------
// Compile the right expression
- asSExprContext re(engine);
+ asCExprContext re(engine);
int rr = CompileAssignment(cexpr->next->next, &re);
+ DetermineSingleFunc(&re, cexpr->next->next);
if( lr >= 0 && rr >= 0 )
{
@@ -7980,7 +8279,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
// Allow a 0 or null in the first case to be implicitly converted to the second type
- if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsIntegerType() )
+ if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() )
{
asCDataType to = re.type.dataType;
to.MakeReference(false);
@@ -8036,6 +8335,24 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
// Set the type of the result
ctx->type = le.type;
}
+ else if (le.type.IsNullConstant() && re.type.IsNullConstant())
+ {
+ // Special case for when both results are 'null'
+ // TODO: Other expressions where both results are identical literal constants can probably also be handled this way
+
+ // Put the code for the condition expression on the output
+ MergeExprBytecode(ctx, &e);
+
+ // Load the result into the register, but ignore the value since both paths give the same response
+ ctx->type = e.type;
+ ConvertToVariable(ctx);
+ ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
+ ReleaseTemporaryVariable(ctx->type, &ctx->bc);
+
+ // Return a null constant
+ ctx->bc.Instr(asBC_PshNull);
+ ctx->type.SetNullConstant();
+ }
else
{
// Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference)
@@ -8046,12 +8363,12 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
// that would have to be cleaned up after the reference
// 3. neither expression can be temporary
//
- // If either expression is local, the resulting lvalue is not valid
- // for return since it is not allowed to return references to local
+ // If either expression is local, the resulting lvalue is not valid
+ // for return since it is not allowed to return references to local
// variables.
//
// The reference to the local variable must be loaded into the register,
- // the resulting expression must not be considered as a local variable
+ // the resulting expression must not be considered as a local variable
// with a stack offset (i.e. it will not be allowed to use asBC_VAR)
if( le.type.isLValue && re.type.isLValue &&
@@ -8092,7 +8409,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
ctx->bc.Label((short)afterLabel);
- // In case the options were to objects, it is necessary to dereference the pointer on
+ // In case the options were to objects, it is necessary to dereference the pointer on
// the stack so it will point to the actual object, instead of the variable
if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() )
{
@@ -8114,12 +8431,12 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
ctx->type.isTemporary = false;
// Must remember if the reference was to a local variable, since it must not be allowed to be returned
- ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
+ ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
}
else
{
// Allocate temporary variable and copy the result to that one
- asCTypeInfo temp;
+ asCExprValue temp;
temp = le.type;
temp.dataType.MakeReference(false);
temp.dataType.MakeReadOnly(false);
@@ -8135,7 +8452,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
temp.SetVariable(temp.dataType, offset, true);
- // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
+ // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable()
CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
@@ -8151,7 +8468,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
ReleaseTemporaryVariable(ctx->type, &ctx->bc);
// Assign the result of the left expression to the temporary variable
- asCTypeInfo rtemp;
+ asCExprValue rtemp;
rtemp = temp;
if( rtemp.dataType.IsObjectHandle() )
rtemp.isExplicitHandle = true;
@@ -8164,7 +8481,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
}
- asCTypeInfo result;
+ asCExprValue result;
result = rtemp;
PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
if( !result.dataType.IsPrimitive() )
@@ -8228,50 +8545,10 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
return 0;
}
-int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
+int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx)
{
asASSERT(expr->nodeType == snExpression);
- // Check if this is an initialization of a temp object with an initialization list
- if( expr->firstChild && expr->firstChild->nodeType == snDataType )
- {
- // TODO: It should be possible to infer the type of the object from where the
- // expression will be used. The compilation of the initialization list
- // should be deferred until it is known for what it will be used. It will
- // then for example be possible to write expressions like:
- //
- // @dict = {{'key', 'value'}};
- // funcTakingArrayOfInt({1,2,3,4});
-
- // Determine the type of the temporary object
- asCDataType dt = builder->CreateDataTypeFromNode(expr->firstChild, script, outFunc->nameSpace);
-
- // Do not allow constructing non-shared types in shared functions
- if( outFunc->IsShared() &&
- dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
- {
- asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
- Error(msg, expr);
- }
-
- // Allocate and initialize the temporary object
- int offset = AllocateVariable(dt, true);
- CompileInitialization(expr->lastChild, &ctx->bc, dt, expr, offset, 0, 0);
-
- // Push the reference to the object on the stack
- ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
- ctx->type.SetVariable(dt, offset, true);
- ctx->type.isLValue = false;
-
- // If the variable is allocated on the heap we have a reference,
- // otherwise the actual object pointer is pushed on the stack.
- if( IsVariableOnHeap(offset) )
- ctx->type.dataType.MakeReference(true);
-
- return 0;
- }
-
// Convert to polish post fix, i.e: a+b => ab+
asCArray postfix;
ConvertToPostFix(expr, postfix);
@@ -8317,7 +8594,7 @@ void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray *postfix, asSExprContext *ctx)
+int asCCompiler::CompilePostFixExpression(asCArray *postfix, asCExprContext *ctx)
{
// Shouldn't send any byte code
asASSERT(ctx->bc.GetLastInstr() == -1);
@@ -8327,26 +8604,26 @@ int asCCompiler::CompilePostFixExpression(asCArray *postfix, as
ctx->type.SetDummy();
// Evaluate the operands and operators
- asCArray free;
- asCArray expr;
+ asCArray free;
+ asCArray expr;
int ret = 0;
for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
{
asCScriptNode *node = (*postfix)[n];
if( node->nodeType == snExprTerm )
{
- asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
+ asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
expr.PushLast(e);
e->exprNode = node;
ret = CompileExpressionTerm(node, e);
}
else
{
- asSExprContext *r = expr.PopLast();
- asSExprContext *l = expr.PopLast();
+ asCExprContext *r = expr.PopLast();
+ asCExprContext *l = expr.PopLast();
// Now compile the operator
- asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
+ asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
ret = CompileOperator(node, l, r, e);
expr.PushLast(e);
@@ -8369,18 +8646,67 @@ int asCCompiler::CompilePostFixExpression(asCArray *postfix, as
// Clean up
for( asUINT e = 0; e < expr.GetLength(); e++ )
- asDELETE(expr[e], asSExprContext);
+ asDELETE(expr[e], asCExprContext);
for( asUINT f = 0; f < free.GetLength(); f++ )
- asDELETE(free[f], asSExprContext);
+ asDELETE(free[f], asCExprContext);
return ret;
}
-int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
+int asCCompiler::CompilerAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt)
+{
+ asASSERT(node->nodeType == snInitList);
+
+ // Do not allow constructing non-shared types in shared functions
+ if (outFunc->IsShared() &&
+ dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared())
+ {
+ asCString msg;
+ msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
+ Error(msg, node);
+ }
+
+ // Allocate and initialize the temporary object
+ int offset = AllocateVariable(dt, true);
+ CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0);
+
+ // Push the reference to the object on the stack
+ ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
+ ctx->type.SetVariable(dt, offset, true);
+ ctx->type.isLValue = false;
+
+ // If the variable is allocated on the heap we have a reference,
+ // otherwise the actual object pointer is pushed on the stack.
+ if (IsVariableOnHeap(offset))
+ ctx->type.dataType.MakeReference(true);
+
+ return 0;
+}
+
+int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx)
{
// Shouldn't send any byte code
asASSERT(ctx->bc.GetLastInstr() == -1);
+ // Check if this is an initialization of a temp object with an initialization list
+ if (node->firstChild )
+ {
+ if (node->firstChild->nodeType == snDataType)
+ {
+ // Determine the type of the temporary object
+ asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
+
+ return CompilerAnonymousInitList(node->lastChild, ctx, dt);
+ }
+ else if (node->firstChild->nodeType == snInitList)
+ {
+ // As the type is not yet known, the init list will be compiled at a
+ // later time when the type can be determined from the destination
+ ctx->SetAnonymousInitList(node->firstChild);
+ return 0;
+ }
+ }
+
// Set the type as a dummy by default, in case of any compiler errors
ctx->type.SetDummy();
@@ -8389,7 +8715,7 @@ int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
while( vnode->nodeType != snExprValue )
vnode = vnode->next;
- asSExprContext v(engine);
+ asCExprContext v(engine);
int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
// Compile post fix operators
@@ -8414,7 +8740,7 @@ int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
return 0;
}
-int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType)
+int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType)
{
bool found = false;
@@ -8428,7 +8754,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
found = true;
if( v->isPureConstant )
- ctx->type.SetConstantQW(v->type, v->constantValue);
+ ctx->type.SetConstantData(v->type, v->constantValue);
else if( v->type.IsPrimitive() )
{
if( v->type.IsReference() )
@@ -8441,7 +8767,9 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
else
ctx->type.SetVariable(v->type, v->stackOffset, false);
- ctx->type.isLValue = true;
+ // Set as lvalue unless it is a const variable
+ if( !v->type.IsReadOnly() )
+ ctx->type.isLValue = true;
}
else
{
@@ -8456,7 +8784,14 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
ctx->bc.Instr(asBC_RDSPtr);
- ctx->type.isLValue = true;
+ // Mark the object as safe for access unless it is a handle, as the
+ // life time of the object is guaranteed throughout the scope.
+ if( !v->type.IsObjectHandle() )
+ ctx->type.isHandleSafe = true;
+
+ // Set as lvalue unless it is a const variable
+ if (!v->type.IsReadOnly())
+ ctx->type.isLValue = true;
}
}
@@ -8466,7 +8801,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
{
if( name == THIS_TOKEN && !objType )
{
- asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
+ asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
// The object pointer is located at stack position 0
ctx->bc.InstrSHORT(asBC_PSF, 0);
@@ -8474,23 +8809,26 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
ctx->type.dataType.MakeReference(true);
ctx->type.isLValue = true;
+ // The 'this' handle is always considered safe (i.e. life time guaranteed)
+ ctx->type.isHandleSafe = true;
+
found = true;
}
if( !found )
{
// See if there are any matching property accessors
- asSExprContext access(engine);
+ asCExprContext access(engine);
if( objType )
- access.type.Set(asCDataType::CreateObject(objType, false));
+ access.type.Set(asCDataType::CreateType(objType, false));
else
- access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
+ access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()));
access.type.dataType.MakeReference(true);
int r = 0;
if( errNode->next && errNode->next->tokenType == ttOpenBracket )
{
// This is an index access, check if there is a property accessor that takes an index arg
- asSExprContext dummyArg(engine);
+ asCExprContext dummyArg(engine);
r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
}
if( r == 0 )
@@ -8517,9 +8855,9 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
{
asCDataType dt;
if( objType )
- dt = asCDataType::CreateObject(objType, false);
+ dt = asCDataType::CreateType(objType, false);
else
- dt = asCDataType::CreateObject(outFunc->objectType, false);
+ dt = asCDataType::CreateType(outFunc->objectType, false);
asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
if( prop )
{
@@ -8577,10 +8915,20 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
{
// Objects that are members are not references
ctx->type.dataType.MakeReference(false);
+
+ // Objects that are members but not handles are safe as long as the parent object is safe
+ if (!objType || ctx->type.isHandleSafe)
+ ctx->type.isHandleSafe = true;
+ }
+ else if (ctx->type.dataType.IsObjectHandle())
+ {
+ // Objects accessed through handles cannot be considered safe
+ // as the handle can be cleared at any time
+ ctx->type.isHandleSafe = false;
}
// If the object reference is const, the property will also be const
- ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
+ ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly());
found = true;
}
@@ -8613,7 +8961,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
// The object pointer is located at stack position 0
// This is only done when accessing through the implicit this pointer
ctx->bc.InstrSHORT(asBC_PSF, 0);
- ctx->type.SetVariable(asCDataType::CreateObject(outFunc->objectType, false), 0, false);
+ ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false);
ctx->type.dataType.MakeReference(true);
Dereference(ctx, true);
}
@@ -8638,12 +8986,12 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
if( !found && ns )
{
// See if there are any matching global property accessors
- asSExprContext access(engine);
+ asCExprContext access(engine);
int r = 0;
if( errNode->next && errNode->next->tokenType == ttOpenBracket )
{
// This is an index access, check if there is a property accessor that takes an index arg
- asSExprContext dummyArg(engine);
+ asCExprContext dummyArg(engine);
r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
}
if( r == 0 )
@@ -8675,7 +9023,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
// Verify that the global property has been compiled already
if( isCompiled )
{
- if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
+ if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
{
ctx->type.dataType.MakeHandle(true);
ctx->type.isExplicitHandle = true;
@@ -8685,8 +9033,8 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
// we can allow the compiler to optimize it. Pure
// constants are global constant variables that were
// initialized by literal constants.
- if( isPureConstant )
- ctx->type.SetConstantQW(prop->type, constantValue);
+ if (isPureConstant)
+ ctx->type.SetConstantData(prop->type, constantValue);
else
{
// A shared type must not access global vars, unless they
@@ -8724,7 +9072,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
// This check is not needed for application registered properties, since they
// are guaranteed to be valid by the application itself.
if( !isAppProp &&
- ((ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
+ ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
!ctx->type.dataType.IsObjectHandle()) )
{
ctx->bc.Instr(asBC_ChkRefS);
@@ -8733,14 +9081,14 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
// If the address pushed on the stack is to a value type or an object
// handle, then mark the expression as a reference. Addresses to a reference
// type aren't marked as references to get correct behaviour
- if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
+ if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
ctx->type.dataType.IsObjectHandle() )
{
ctx->type.dataType.MakeReference(true);
}
else
{
- asASSERT( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
+ asASSERT( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
// It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
ctx->bc.Instr(asBC_RDSPtr);
@@ -8781,27 +9129,17 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
if( !found )
{
// The enum type may be declared in a namespace too
- asCObjectType *scopeType = 0;
+ asCTypeInfo *scopeType = 0;
if( currScope != "" && currScope != "::" )
{
- // Use the last scope name as the enum type
- asCString enumType = currScope;
- asCString nsScope;
- int p = currScope.FindLast("::");
- if( p != -1 )
- {
- enumType = currScope.SubString(p+2);
- nsScope = currScope.SubString(0, p);
- }
-
- asSNameSpace *ns = engine->FindNameSpace(nsScope.AddressOf());
- if( ns )
- scopeType = builder->GetObjectType(enumType.AddressOf(), ns);
+ builder->GetNameSpaceByString(currScope, outFunc->objectType ? outFunc->objectType->nameSpace : outFunc->nameSpace, errNode, script, &scopeType, false);
+ if (CastToEnumType(scopeType) == 0)
+ scopeType = 0;
}
asDWORD value = 0;
asCDataType dt;
- if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
+ if( scopeType && builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value) )
{
// scoped enum value found
found = true;
@@ -8809,10 +9147,10 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
else if( !engine->ep.requireEnumScope )
{
// Look for the enum value without explicitly informing the enum type
- asSNameSpace *ns = DetermineNameSpace(currScope);
+ asSNameSpace *nsEnum = DetermineNameSpace(currScope);
int e = 0;
- if( ns )
- e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
+ if(nsEnum)
+ e = builder->GetEnumValue(name.AddressOf(), dt, value, nsEnum);
if( e )
{
found = true;
@@ -8895,7 +9233,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
// Mark the variable as initialized so that the user will not be bother by it again
- sVariable *v = variables->GetVariable(name.AddressOf());
+ v = variables->GetVariable(name.AddressOf());
asASSERT(v);
if( v ) v->isInitialized = true;
}
@@ -8907,7 +9245,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
return 0;
}
-int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
+int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx)
{
// Shouldn't receive any byte code
asASSERT(ctx->bc.GetLastInstr() == -1);
@@ -8931,7 +9269,17 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx
{
asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
- asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
+ bool overflow = false;
+ asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow);
+
+ // Is the number bigger than a 64bit word?
+ if (overflow)
+ {
+ Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
+
+ // Set the value to zero to avoid further warnings
+ val = 0;
+ }
// Do we need 64 bits?
// If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
@@ -8952,8 +9300,17 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx
asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
// Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
- // TODO: Check for overflow
- asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0);
+ bool overflow = false;
+ asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow);
+
+ // Is the number bigger than a 64bit word?
+ if (overflow)
+ {
+ Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
+
+ // Set the value to zero to avoid further warnings
+ val = 0;
+ }
// Do we need 64 bits?
if( val>>32 )
@@ -9007,7 +9364,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx
str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
asDWORD val = 0;
- if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
+ if( str.GetLength() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 )
{
// This is the start of a UTF8 encoded character. We need to decode it
val = asStringDecodeUTF8(str.AddressOf(), 0);
@@ -9054,8 +9411,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx
}
// Call the string factory function to create a string object
- asCScriptFunction *descr = engine->stringFactory;
- if( descr == 0 )
+ if(engine->stringFactory == 0 )
{
// Error
Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
@@ -9066,21 +9422,27 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx
}
else
{
- // Register the constant string with the engine
- int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
- ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
-
- bool useVariable = false;
- int stackOffset = 0;
-
- if( descr->DoesReturnOnStack() )
+ void *strPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()));
+ if (strPtr == 0)
{
- useVariable = true;
- stackOffset = AllocateVariable(descr->returnType, true);
- ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
+ // TODO: A better message is needed
+ Error(TXT_NULL_POINTER_ACCESS, vnode);
+ ctx->type.SetDummy();
+ return -1;
}
- PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
+ // Keep the pointer in the list for clean up at exit
+ usedStringConstants.PushLast(strPtr);
+
+ // Push the pointer on the stack. The string factory already guarantees that the
+ // string object is valid throughout the lifetime of the script so no need to add
+ // reference count or make local copy.
+ ctx->bc.InstrPTR(asBC_PGA, strPtr);
+ ctx->type.Set(engine->stringType);
+
+ // Mark the string as literal constant so the compiler knows it is allowed
+ // to treat it differently than an ordinary constant string variable
+ ctx->type.isConstant = true;
}
}
}
@@ -9105,7 +9467,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx
}
else if( vnode->nodeType == snAssignment )
{
- asSExprContext e(engine);
+ asCExprContext e(engine);
int r = CompileAssignment(vnode, &e);
if( r < 0 )
{
@@ -9127,7 +9489,7 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx
else if( vnode->nodeType == snFunction )
{
// This is an anonymous function
- // Defer the evaluation of the function until it known where it
+ // Defer the evaluation of the function until it known where it
// will be used, which is where the signature will be defined
ctx->SetLambda(vnode);
}
@@ -9333,11 +9695,14 @@ asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node,
void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
{
// Remove first line if it only contains whitespace
+ bool isMultiline = false;
int start;
for( start = 0; start < (int)str.GetLength(); start++ )
{
if( str[start] == '\n' )
{
+ isMultiline = true;
+
// Remove the linebreak as well
start++;
break;
@@ -9377,21 +9742,29 @@ void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *no
if( end < 0 ) end = 0;
asCString tmp;
- if( end > start )
- tmp.Assign(&str[start], end-start);
+ if (end > start || engine->ep.heredocTrimMode != 2 )
+ {
+ // if heredocTrimMode == 0 the string shouldn't be trimmed
+ // if heredocTrimMode == 1 the string should only be trimmed if it is multiline
+ // if heredocTrimMode == 2 the string should always be trimmed
+ if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1))
+ tmp.Assign(&str[start], end - start);
+ else
+ tmp = str;
+ }
ProcessStringConstant(tmp, node, false);
str = tmp;
}
-int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
+int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx)
{
- asSExprContext expr(engine);
+ asCExprContext expr(engine);
asCDataType to;
bool anyErrors = false;
EImplicitConv convType;
- if( node->nodeType == snConstructCall )
+ if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall )
{
convType = asIC_EXPLICIT_VAL_CAST;
@@ -9403,6 +9776,13 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
expr.type.SetDummy();
anyErrors = true;
}
+ else if (node->lastChild->firstChild &&
+ node->lastChild->firstChild->nodeType == snNamedArgument)
+ {
+ Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild);
+ expr.type.SetDummy();
+ anyErrors = true;
+ }
else
{
// Compile the expression
@@ -9445,10 +9825,10 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
// Do not allow casting to non shared type if we're compiling a shared method
if( outFunc->IsShared() &&
- to.GetObjectType() && !to.GetObjectType()->IsShared() )
+ to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() )
{
asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf());
+ msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf());
Error(msg, node);
anyErrors = true;
}
@@ -9456,7 +9836,7 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
if( anyErrors )
{
// Assume that the error can be fixed and allow the compilation to continue
- ctx->type.SetConstantDW(to, 0);
+ ctx->type.Set(to);
return -1;
}
@@ -9537,9 +9917,9 @@ int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
return -1;
}
-void asCCompiler::AfterFunctionCall(int funcID, asCArray &args, asSExprContext *ctx, bool deferAll)
+void asCCompiler::AfterFunctionCall(int funcID, asCArray &args, asCExprContext *ctx, bool deferAll)
{
- // deferAll is set to true if for example the function returns a reference, since in
+ // deferAll is set to true if for example the function returns a reference, since in
// this case the function might be returning a reference to one of the arguments.
asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
@@ -9588,7 +9968,7 @@ void asCCompiler::AfterFunctionCall(int funcID, asCArray &args,
}
}
-void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
+void asCCompiler::ProcessDeferredParams(asCExprContext *ctx)
{
if( isProcessingDeferredParams ) return;
@@ -9604,7 +9984,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
}
else if( outParam.argInOutFlags == asTM_OUTREF )
{
- asSExprContext *expr = outParam.origExpr;
+ asCExprContext *expr = outParam.origExpr;
outParam.origExpr = 0;
if( outParam.argType.dataType.IsObjectHandle() )
@@ -9617,7 +9997,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
// Verify that the expression result in a lvalue, or a property accessor
if( IsLValue(expr->type) || expr->property_get || expr->property_set )
{
- asSExprContext rctx(engine);
+ asCExprContext rctx(engine);
rctx.type = outParam.argType;
if( rctx.type.dataType.IsPrimitive() )
rctx.type.dataType.MakeReference(false);
@@ -9629,7 +10009,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
rctx.type.isExplicitHandle = true;
}
- asSExprContext o(engine);
+ asCExprContext o(engine);
DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
@@ -9649,7 +10029,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
ctx->bc.Instr(asBC_PopPtr);
// Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored
- if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
+ if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.GetConstantData() == 0) )
Error(TXT_ARG_NOT_LVALUE, outParam.argNode);
ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
@@ -9658,7 +10038,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
ReleaseTemporaryVariable(expr->type, &ctx->bc);
// Delete the original expression context
- asDELETE(expr,asSExprContext);
+ asDELETE(expr, asCExprContext);
}
else // &inout
{
@@ -9669,7 +10049,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
if( outParam.argType.dataType.IsObject() &&
((outParam.argType.dataType.GetBehaviour()->addref &&
outParam.argType.dataType.GetBehaviour()->release) ||
- (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
+ (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) )
{
// Release the object handle that was taken to guarantee the reference
ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
@@ -9683,11 +10063,11 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
}
-int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
+int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
{
// The first node is a datatype node
asCString name;
- asCTypeInfo tempObj;
+ asCExprValue tempObj;
bool onHeap = true;
asCArray funcs;
bool error = false;
@@ -9701,7 +10081,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
return CompileConversion(node, ctx);
}
- if( dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
+ if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
{
// Types declared as implicit handle must not attempt to construct a handle
dt.MakeHandle(false);
@@ -9717,7 +10097,10 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
return -1;
}
- if( !dt.CanBeInstantiated() )
+ // Make sure the desired type can actually be instantiated
+ // Delegates are allowed to be created through construct calls,
+ // even though they cannot be instantiated as variables
+ if( !dt.CanBeInstantiated() && !dt.IsFuncdef() )
{
asCString str;
if( dt.IsAbstractClass() )
@@ -9734,37 +10117,43 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
// Do not allow constructing non-shared types in shared functions
if( outFunc->IsShared() &&
- dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
+ dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
{
asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
+ msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
Error(msg, node);
return -1;
}
// Compile the arguments
- asCArray args;
+ asCArray args;
asCArray namedArgs;
- asCArray temporaryVariables;
+ asCArray temporaryVariables;
if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
{
// Check for a value cast behaviour
- if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
+ if( args.GetLength() == 1 && args[0]->type.dataType.GetTypeInfo() )
{
- asSExprContext conv(engine);
+ asCExprContext conv(engine);
conv.type = args[0]->type;
asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
// Don't use this if the cost is 0 because it would mean that nothing
- // is done and the scipt wants a new value to be constructed
+ // is done and the script wants a new value to be constructed
if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
{
+ // Make sure the result is a reference, just as if to a local variable
+ dt.MakeReference(true);
+
+ // Make sure any property accessor is already evaluated
+ ProcessPropertyGetAccessor(args[0], args[0]->exprNode);
+
ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
ctx->bc.AddCode(&args[0]->bc);
ctx->type = args[0]->type;
- asDELETE(args[0],asSExprContext);
+ asDELETE(args[0], asCExprContext);
return 0;
}
@@ -9775,7 +10164,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
asSTypeBehaviour *beh = dt.GetBehaviour();
- if( !(dt.GetObjectType()->flags & asOBJ_REF) )
+ if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() )
{
funcs = beh->constructors;
@@ -9792,7 +10181,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
if( onHeap )
ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
}
- else
+ else if( beh )
funcs = beh->factories;
// Special case: Allow calling func(void) with a void expression.
@@ -9800,7 +10189,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
{
// Evaluate the expression before the function call
MergeExprBytecode(ctx, args[0]);
- asDELETE(args[0],asSExprContext);
+ asDELETE(args[0], asCExprContext);
args.SetLength(0);
}
@@ -9808,8 +10197,8 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
// If none has been registered, just allocate the variable and push it on the stack.
if( args.GetLength() == 0 )
{
- asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
- if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
+ beh = tempObj.dataType.GetBehaviour();
+ if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) )
{
// Call the default constructor
ctx->type = tempObj;
@@ -9829,7 +10218,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
}
// Special case: If this is a construction of a delegate and the expression names an object method
- if( dt.GetFuncDef() && args.GetLength() == 1 && args[0]->methodName != "" )
+ if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" )
{
// TODO: delegate: It is possible that the argument returns a function pointer already, in which
// case no object delegate will be created, but instead a delegate for a function pointer
@@ -9848,7 +10237,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
else
{
// Filter the available object methods to find the one that matches the func def
- asCObjectType *type = args[0]->type.dataType.GetObjectType();
+ asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo());
asCScriptFunction *bestMethod = 0;
for( asUINT n = 0; n < type->methods.GetLength(); n++ )
{
@@ -9861,7 +10250,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
continue;
- if( func->IsSignatureExceptNameAndObjectTypeEqual(dt.GetFuncDef()) )
+ if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) )
{
bestMethod = func;
@@ -9880,10 +10269,10 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
// Call the factory function for the delegate
- asCArray funcs;
- builder->GetFunctionDescriptions(DELEGATE_FACTORY, funcs, engine->nameSpaces[0]);
- asASSERT( funcs.GetLength() == 1 );
- ctx->bc.Call(asBC_CALLSYS , funcs[0], 2*AS_PTR_SIZE);
+ asCArray delegateFuncs;
+ builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]);
+ asASSERT(delegateFuncs.GetLength() == 1 );
+ ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE);
// Store the returned delegate in a temporary variable
int returnOffset = AllocateVariable(dt, true, false);
@@ -9900,14 +10289,14 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
else
{
asCString msg;
- msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, dt.GetFuncDef()->GetDeclaration());
+ msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration());
Error(msg.AddressOf(), node);
error = true;
}
}
// Clean-up arg
- asDELETE(args[0],asSExprContext);
+ asDELETE(args[0], asCExprContext);
return error ? -1 : 0;
}
@@ -9926,7 +10315,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
// TODO: Clean up: Merge this with MakeFunctionCall
// Add the default values for arguments not explicitly supplied
- int r = CompileDefaultAndNamedArgs(node, args, funcs[0], dt.GetObjectType(), &namedArgs);
+ int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs);
if( r == asSUCCESS )
{
@@ -9936,7 +10325,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
MoveArgsToStack(funcs[0], &ctx->bc, args, false);
- if( !(dt.GetObjectType()->flags & asOBJ_REF) )
+ if( !(dt.GetTypeInfo()->flags & asOBJ_REF) )
{
// If the object is allocated on the stack, then call the constructor as a normal function
if( onHeap )
@@ -9951,7 +10340,7 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
else
ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
- PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
+ PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
// Add tag that the object has been initialized
ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
@@ -9987,25 +10376,25 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
for( asUINT n = 0; n < args.GetLength(); n++ )
if( args[n] )
{
- asDELETE(args[n],asSExprContext);
+ asDELETE(args[n], asCExprContext);
}
for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
if( namedArgs[n].ctx )
{
- asDELETE(namedArgs[n].ctx,asSExprContext);
+ asDELETE(namedArgs[n].ctx, asCExprContext);
}
return error ? -1 : 0;
}
-int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
+int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
{
- asCTypeInfo tempObj;
+ asCExprValue tempObj;
asCArray funcs;
int localVar = -1;
bool initializeMembers = false;
- asSExprContext funcExpr(engine);
+ asCExprContext funcExpr(engine);
asCScriptNode *nm = node->lastChild->prev;
asCString name(&script->code[nm->tokenPos], nm->tokenLength);
@@ -10017,12 +10406,12 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
{
localVar = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true);
if( localVar >= 0 &&
- !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
+ !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) &&
funcExpr.methodName == "" )
{
// The variable is not a function or object with opCall
asCString msg;
- msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
+ msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), funcExpr.type.dataType.Format(outFunc->nameSpace).AddressOf());
Error(msg, node);
return -1;
}
@@ -10079,12 +10468,12 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
{
int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true, objectType);
if( r >= 0 &&
- !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
+ !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) &&
funcExpr.methodName == "" )
{
// The variable is not a function
asCString msg;
- msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
+ msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), funcExpr.type.dataType.Format(outFunc->nameSpace).AddressOf());
Error(msg, node);
return -1;
}
@@ -10100,7 +10489,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
{
objectType = outFunc->objectType;
- asCDataType dt = asCDataType::CreateObject(objectType, false);
+ asCDataType dt = asCDataType::CreateType(objectType, false);
// The object pointer is located at stack position 0
ctx->bc.InstrSHORT(asBC_PSF, 0);
@@ -10115,26 +10504,26 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
// then look for global functions or global function pointers,
// unless this is an expression post op, incase only member
// functions are expected
- if( objectType == 0 && funcs.GetLength() == 0 && (funcExpr.type.dataType.GetFuncDef() == 0 || funcExpr.type.dataType.IsObject()) )
+ if( objectType == 0 && funcs.GetLength() == 0 && (!funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) )
{
// The scope is used to define the namespace
asSNameSpace *ns = DetermineNameSpace(scope);
if( ns )
{
// Search recursively in parent namespaces
- while( ns && funcs.GetLength() == 0 && funcExpr.type.dataType.GetFuncDef() == 0 )
+ while( ns && funcs.GetLength() == 0 && !funcExpr.type.dataType.IsFuncdef() )
{
builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
if( funcs.GetLength() == 0 )
{
int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true);
if( r >= 0 &&
- !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
+ !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) &&
funcExpr.methodName == "" )
{
// The variable is not a function
asCString msg;
- msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
+ msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), funcExpr.type.dataType.Format(outFunc->nameSpace).AddressOf());
Error(msg, node);
return -1;
}
@@ -10155,9 +10544,9 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
if( funcs.GetLength() == 0 )
{
- if( funcExpr.type.dataType.GetFuncDef() )
+ if( funcExpr.type.dataType.IsFuncdef() )
{
- funcs.PushLast(funcExpr.type.dataType.GetFuncDef()->id);
+ funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id);
}
else if( funcExpr.type.dataType.IsObject() )
{
@@ -10182,7 +10571,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
ProcessPropertyGetAccessor(ctx, node);
Dereference(ctx, true);
- objectType = funcExpr.type.dataType.GetObjectType();
+ objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo());
// Get the opCall methods from the object type
if( funcExpr.type.dataType.IsObjectHandle() )
@@ -10190,12 +10579,21 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
else
objIsConst = funcExpr.type.dataType.IsReadOnly();
- builder->GetObjectMethodDescriptions("opCall", funcExpr.type.dataType.GetObjectType(), funcs, objIsConst);
+ builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst);
}
}
+ // If at this point no functions have been identified, then this may be a construct call
+ if (funcs.GetLength() == 0)
+ {
+ bool isValid = false;
+ asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, 0, false, &isValid);
+ if (isValid)
+ return CompileConstructCall(node, ctx);
+ }
+
// Compile the arguments
- asCArray args;
+ asCArray args;
asCArray namedArgs;
bool isOK = true;
@@ -10206,7 +10604,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
{
// Evaluate the expression before the function call
MergeExprBytecode(ctx, args[0]);
- asDELETE(args[0],asSExprContext);
+ asDELETE(args[0], asCExprContext);
args.SetLength(0);
}
@@ -10238,7 +10636,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
if( objectType && funcExpr.property_get <= 0 )
{
// Dereference the object pointer to access the member
- Dereference(ctx, true);
+ Dereference(ctx, true);
}
if( funcExpr.property_get > 0 )
@@ -10258,7 +10656,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
// The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
funcExpr.bc.Instr(asBC_PopPtr);
- asCTypeInfo tmp = ctx->type;
+ asCExprValue tmp = ctx->type;
MergeExprBytecodeAndType(ctx, &funcExpr);
ReleaseTemporaryVariable(tmp, &ctx->bc);
}
@@ -10280,12 +10678,12 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
for( asUINT n = 0; n < args.GetLength(); n++ )
if( args[n] )
{
- asDELETE(args[n],asSExprContext);
+ asDELETE(args[n], asCExprContext);
}
for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
if( namedArgs[n].ctx )
{
- asDELETE(namedArgs[n].ctx,asSExprContext);
+ asDELETE(namedArgs[n].ctx, asCExprContext);
}
if( initializeMembers )
@@ -10329,7 +10727,7 @@ asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
return ns;
}
-int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
+int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx)
{
int op = node->tokenType;
@@ -10373,9 +10771,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
if( !ctx->type.IsNullConstant() )
{
// Verify that the type allow its handle to be taken
- if( !ctx->type.dataType.IsObject() ||
- !(((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ||
- (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
+ if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() )
{
Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
return -1;
@@ -10384,7 +10780,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
// Objects that are not local variables are not references
// Objects allocated on the stack are also not marked as references
if( !ctx->type.dataType.IsReference() &&
- !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) &&
+ !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) &&
!(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
{
Error(TXT_NOT_VALID_REFERENCE, node);
@@ -10392,7 +10788,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
}
// Convert the expression to a handle
- if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
+ if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
{
asCDataType to = ctx->type.dataType;
to.MakeHandle(true);
@@ -10402,7 +10798,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
asASSERT( ctx->type.dataType.IsObjectHandle() );
}
- else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
+ else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE )
{
// For the ASHANDLE type we'll simply set the expression as a handle
ctx->type.dataType.MakeHandle(true);
@@ -10436,13 +10832,13 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
// Find the correct method
bool isConst = ctx->type.dataType.IsObjectConst();
asCArray funcs;
- asCObjectType *ot = ctx->type.dataType.GetObjectType();
+ asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
{
asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
if( func->name == opName &&
func->parameterTypes.GetLength() == 0 &&
- (!isConst || func->isReadOnly) )
+ (!isConst || func->IsReadOnly()) )
{
funcs.PushLast(func->id);
}
@@ -10451,8 +10847,8 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
// Did we find the method?
if( funcs.GetLength() == 1 )
{
- asCArray args;
- MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
+ asCArray args;
+ MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
return 0;
}
else if( funcs.GetLength() == 0 )
@@ -10551,14 +10947,21 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
{
if( op == ttMinus )
{
- if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
- ctx->type.intValue = -ctx->type.intValue;
- else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
- ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
+ if (ctx->type.dataType.IsIntegerType())
+ {
+ if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
+ ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW());
+ else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
+ ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW());
+ else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1)
+ ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB());
+ else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8)
+ ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW());
+ }
else if( ctx->type.dataType.IsFloatType() )
- ctx->type.floatValue = -ctx->type.floatValue;
+ ctx->type.SetConstantF(-ctx->type.GetConstantF());
else if( ctx->type.dataType.IsDoubleType() )
- ctx->type.doubleValue = -ctx->type.doubleValue;
+ ctx->type.SetConstantD(-ctx->type.GetConstantD());
else
{
Error(TXT_ILLEGAL_OPERATION, node);
@@ -10572,14 +10975,18 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
else if( op == ttNot )
{
// Allow value types to be converted to bool using 'bool opImplConv()'
- if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
+ if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV);
if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
{
if( ctx->type.isConstant )
{
- ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
+ #if AS_SIZEOF_BOOL == 1
+ ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
+ #else
+ ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
+ #endif
return 0;
}
@@ -10626,7 +11033,14 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
{
if( ctx->type.isConstant )
{
- ctx->type.qwordValue = ~ctx->type.qwordValue;
+ if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
+ ctx->type.SetConstantB(~ctx->type.GetConstantB());
+ else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
+ ctx->type.SetConstantW(~ctx->type.GetConstantW());
+ else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
+ ctx->type.SetConstantDW(~ctx->type.GetConstantDW());
+ else
+ ctx->type.SetConstantQW(~ctx->type.GetConstantQW());
return 0;
}
@@ -10741,7 +11155,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
return 0;
}
-void asCCompiler::ConvertToReference(asSExprContext *ctx)
+void asCCompiler::ConvertToReference(asCExprContext *ctx)
{
if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
{
@@ -10751,12 +11165,12 @@ void asCCompiler::ConvertToReference(asSExprContext *ctx)
}
}
-int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
+int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
{
return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
}
-int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
+int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
{
if( engine->ep.propertyAccessorMode == 0 )
{
@@ -10775,11 +11189,11 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx
// Don't look for property accessors in script classes if the script
// property accessors have been disabled by the application
- if( !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ||
+ if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ||
engine->ep.propertyAccessorMode == 2 )
{
// Check if the object has any methods with the corresponding accessor name(s)
- asCObjectType *ot = ctx->type.dataType.GetObjectType();
+ asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
{
asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
@@ -10916,7 +11330,7 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx
int idx = (arg?1:0);
if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
!((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
- (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
+ (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) )
{
asCString str;
str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
@@ -10977,6 +11391,8 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx
ctx->property_get = getId;
ctx->property_set = setId;
+ bool isHandleSafe = ctx->type.isHandleSafe;
+
if( ctx->type.dataType.IsObject() )
{
// If the object is read-only then we need to remember that
@@ -11008,10 +11424,14 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx
ctx->type.isTemporary = isTemp;
ctx->exprNode = node;
+ // Remember if the object is safe, so the invocation of the property
+ // accessor doesn't needlessly make a safe copy of the handle
+ ctx->type.isHandleSafe = isHandleSafe;
+
// Store the argument for later use
if( arg )
{
- ctx->property_arg = asNEW(asSExprContext)(engine);
+ ctx->property_arg = asNEW(asCExprContext)(engine);
if( ctx->property_arg == 0 )
{
// Out of memory
@@ -11028,7 +11448,7 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx
return 0;
}
-int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
+int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node)
{
// TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
@@ -11043,7 +11463,7 @@ int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext
// Make sure the arg match the property
asCArray funcs;
funcs.PushLast(ctx->property_set);
- asCArray args;
+ asCArray args;
if( ctx->property_arg )
args.PushLast(ctx->property_arg);
args.PushLast(arg);
@@ -11053,7 +11473,7 @@ int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext
// MatchFunctions already reported the error
if( ctx->property_arg )
{
- asDELETE(ctx->property_arg, asSExprContext);
+ asDELETE(ctx->property_arg, asCExprContext);
ctx->property_arg = 0;
}
return -1;
@@ -11062,17 +11482,17 @@ int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext
if( func->objectType )
{
// Setup the context with the original type so the method call gets built correctly
- ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
+ ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
// Don't allow the call if the object is read-only and the property accessor is not const
- if( ctx->property_const && !func->isReadOnly )
+ if( ctx->property_const && !func->IsReadOnly() )
{
Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
- asCArray funcs;
- funcs.PushLast(ctx->property_set);
- PrintMatchingFuncs(funcs, node);
+ asCArray funcCandidates;
+ funcCandidates.PushLast(ctx->property_set);
+ PrintMatchingFuncs(funcCandidates, node);
}
}
@@ -11083,17 +11503,17 @@ int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext
ctx->property_set = 0;
if( ctx->property_arg )
{
- asDELETE(ctx->property_arg, asSExprContext);
+ asDELETE(ctx->property_arg, asCExprContext);
ctx->property_arg = 0;
}
return 0;
}
-int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, eTokenType op, asCScriptNode *errNode)
+int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode)
{
- // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
- // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
+ // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
+ // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
// to support value types, since it would be a single call
// Compound assignment for indexed property accessors is not supported yet
@@ -11114,7 +11534,7 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte
return -1;
}
- // Property accessors on value types (or scoped references types) are not supported since
+ // Property accessors on value types (or scoped references types) are not supported since
// it is not possible to guarantee that the object will stay alive between the two calls
asCScriptFunction *func = engine->scriptFunctions[lctx->property_set];
if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) )
@@ -11134,9 +11554,9 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte
case ttDivAssign: op = ttSlash; break;
case ttModAssign: op = ttPercent; break;
case ttPowAssign: op = ttStarStar; break;
-
+
case ttAndAssign: op = ttAmp; break;
- case ttOrAssign: op = ttBitOr; break;
+ case ttOrAssign: op = ttBitOr; break;
case ttXorAssign: op = ttBitXor; break;
case ttShiftLeftAssign: op = ttBitShiftLeft; break;
@@ -11149,14 +11569,14 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte
if( op == ttUnrecognizedToken )
{
// Shouldn't happen
- asASSERT(false);
+ asASSERT(false);
// Process the property to free the memory
ProcessPropertySetAccessor(lctx, rctx, errNode);
return -1;
}
- asSExprContext before(engine);
+ asCExprContext before(engine);
if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF )
{
// Keep a reference to the object in a local variable
@@ -11202,7 +11622,7 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte
}
// Keep the original information on the property
- asSExprContext llctx(engine);
+ asCExprContext llctx(engine);
llctx.type = lctx->type;
llctx.property_arg = lctx->property_arg;
llctx.property_const = lctx->property_const;
@@ -11212,7 +11632,7 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte
llctx.property_set = lctx->property_set;
// Compile the dual operator using the get accessor
- CompileOperator(errNode, lctx, rctx, ctx, op);
+ CompileOperator(errNode, lctx, rctx, ctx, op, false);
// If we made a local variable to hold the reference it must be reused
if( before.type.stackOffset )
@@ -11233,7 +11653,7 @@ int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprConte
return 0;
}
-void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
+void asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node)
{
// If no property accessor has been prepared then don't do anything
if( !ctx->property_get && !ctx->property_set )
@@ -11247,13 +11667,13 @@ void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode
return;
}
- asCTypeInfo objType = ctx->type;
+ asCExprValue objType = ctx->type;
asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
// Make sure the arg match the property
asCArray funcs;
funcs.PushLast(ctx->property_get);
- asCArray args;
+ asCArray args;
if( ctx->property_arg )
args.PushLast(ctx->property_arg);
MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
@@ -11262,7 +11682,7 @@ void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode
// MatchFunctions already reported the error
if( ctx->property_arg )
{
- asDELETE(ctx->property_arg, asSExprContext);
+ asDELETE(ctx->property_arg, asCExprContext);
ctx->property_arg = 0;
}
ctx->type.SetDummy();
@@ -11272,17 +11692,17 @@ void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode
if( func->objectType )
{
// Setup the context with the original type so the method call gets built correctly
- ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
+ ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
// Don't allow the call if the object is read-only and the property accessor is not const
- if( ctx->property_const && !func->isReadOnly )
+ if( ctx->property_const && !func->IsReadOnly() )
{
Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
- asCArray funcs;
- funcs.PushLast(ctx->property_get);
- PrintMatchingFuncs(funcs, node);
+ asCArray funcCandidates;
+ funcCandidates.PushLast(ctx->property_get);
+ PrintMatchingFuncs(funcCandidates, node);
}
}
@@ -11294,17 +11714,17 @@ void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode
if( isExplicitHandle )
ctx->type.isExplicitHandle = true;
- // Clear the property get/set ids
+ // Clear the property get/set ids
ctx->property_get = 0;
ctx->property_set = 0;
if( ctx->property_arg )
{
- asDELETE(ctx->property_arg, asSExprContext);
+ asDELETE(ctx->property_arg, asCExprContext);
ctx->property_arg = 0;
}
}
-int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
+int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx)
{
// Don't allow any postfix operators on expressions that take address of class method
if( ctx->IsClassMethod() )
@@ -11343,13 +11763,13 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
// Find the correct method
bool isConst = ctx->type.dataType.IsObjectConst();
asCArray funcs;
- asCObjectType *ot = ctx->type.dataType.GetObjectType();
+ asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
{
asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
if( func->name == opName &&
func->parameterTypes.GetLength() == 0 &&
- (!isConst || func->isReadOnly) )
+ (!isConst || func->IsReadOnly()) )
{
funcs.PushLast(func->id);
}
@@ -11358,8 +11778,8 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
// Did we find the method?
if( funcs.GetLength() == 1 )
{
- asCArray args;
- MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
+ asCArray args;
+ MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
return 0;
}
else if( funcs.GetLength() == 0 )
@@ -11478,7 +11898,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
if( node->next && node->next->tokenType == ttOpenBracket )
{
// The property accessor should take an index arg
- asSExprContext dummyArg(engine);
+ asCExprContext dummyArg(engine);
r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
}
if( r == 0 )
@@ -11507,7 +11927,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
if( prop )
{
// Is the property access allowed?
- if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
+ if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) )
{
asCString msg;
if( prop->isPrivate )
@@ -11517,8 +11937,16 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
Error(msg, node);
}
+ // Adjust the pointer for composite member
+ // This must always be done even if the offset is 0 because the asCWriter needs the meta data in ADDSi to identify the composite property
+ if( prop->compositeOffset || prop->isCompositeIndirect )
+ ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
+ if (prop->isCompositeIndirect)
+ ctx->bc.Instr(asBC_RDSPtr);
+
// Put the offset on the stack
- ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
+ // This must always be done even if the offset is 0 so the type info is stored
+ ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
if( prop->type.IsReference() )
ctx->bc.Instr(asBC_RDSPtr);
@@ -11548,10 +11976,18 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
ctx->type.isVariable = false;
ctx->type.isTemporary = false;
- if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
+ if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() )
{
// Objects that are members are not references
ctx->type.dataType.MakeReference(false);
+
+ // The object is safe (life time guaranteed) if the parent object is also safe
+ }
+ else if (ctx->type.dataType.IsObjectHandle())
+ {
+ // A object accessed through a handle cannot be considered safe,
+ // as it can be cleared at any time
+ ctx->type.isHandleSafe = false;
}
ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
@@ -11561,7 +11997,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
// If the name is not a property, the compiler must check if the name matches
// a method, which can be used for constructing delegates
asIScriptFunction *func = 0;
- asCObjectType *ot = ctx->type.dataType.GetObjectType();
+ asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
{
if( engine->scriptFunctions[ot->methods[n]]->name == name )
@@ -11610,7 +12046,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
ProcessPropertyGetAccessor(ctx, node);
// Compile function call
- int r = CompileFunctionCall(node->firstChild, ctx, ctx->type.dataType.GetObjectType(), ctx->type.dataType.IsObjectConst());
+ int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst());
if( r < 0 ) return r;
}
}
@@ -11638,7 +12074,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
// Set the original type of the expression so we can re-evaluate the property accessor
if( func->objectType )
{
- ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
+ ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
}
@@ -11653,7 +12089,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
ctx->property_get = ctx->property_set = 0;
if( ctx->property_arg )
{
- asDELETE(ctx->property_arg, asSExprContext);
+ asDELETE(ctx->property_arg, asCExprContext);
ctx->property_arg = 0;
}
}
@@ -11672,7 +12108,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
// Compile the expression
bool isOK = true;
- asCArray args;
+ asCArray args;
asCArray namedArgs;
asASSERT( node->firstChild->nodeType == snArgList );
if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
@@ -11682,7 +12118,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
if( propertyName == "" )
{
bool isConst = ctx->type.dataType.IsObjectConst();
- asCObjectType *objectType = ctx->type.dataType.GetObjectType();
+ asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo());
asCArray funcs;
builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
@@ -11714,29 +12150,31 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
{
if( args.GetLength() != 1 )
{
- // TODO: opIndex: Implement this
- Error("Property accessor with index only support 1 index argument for now", node);
+ // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too
+ Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node);
isOK = false;
}
-
- Dereference(ctx, true);
- asSExprContext lctx(engine);
- MergeExprBytecodeAndType(&lctx, ctx);
-
- // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
- int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
- if( r == 0 )
+ else
{
- asCString str;
- str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
- Error(str, node);
- isOK = false;
- }
- else if( r < 0 )
- isOK = false;
+ Dereference(ctx, true);
+ asCExprContext lctx(engine);
+ MergeExprBytecodeAndType(&lctx, ctx);
- if( isOK )
- MergeExprBytecodeAndType(ctx, &lctx);
+ // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
+ int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
+ if (r == 0)
+ {
+ asCString str;
+ str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
+ Error(str, node);
+ isOK = false;
+ }
+ else if (r < 0)
+ isOK = false;
+
+ if (isOK)
+ MergeExprBytecodeAndType(ctx, &lctx);
+ }
}
}
else
@@ -11746,7 +12184,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
for( asUINT n = 0; n < args.GetLength(); n++ )
if( args[n] )
{
- asDELETE(args[n],asSExprContext);
+ asDELETE(args[n], asCExprContext);
}
if( !isOK )
@@ -11757,30 +12195,30 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
// TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
// Make sure the expression is a funcdef or an object that may have opCall methods
- if( !ctx->type.dataType.GetFuncDef() && !ctx->type.dataType.IsObject() )
+ if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) )
{
Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
return -1;
}
// Compile arguments
- asCArray args;
+ asCArray args;
asCArray namedArgs;
if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
{
// Match arguments with the funcdef
asCArray funcs;
- if( ctx->type.dataType.GetFuncDef() )
+ if( ctx->type.dataType.IsFuncdef() )
{
- funcs.PushLast(ctx->type.dataType.GetFuncDef()->id);
- MatchFunctions(funcs, args, node, ctx->type.dataType.GetFuncDef()->name.AddressOf(), &namedArgs);
+ funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id);
+ MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs);
}
else
{
bool isConst = ctx->type.dataType.IsObjectConst();
- builder->GetObjectMethodDescriptions("opCall", ctx->type.dataType.GetObjectType(), funcs, isConst);
- MatchFunctions(funcs, args, node, "opCall", &namedArgs, ctx->type.dataType.GetObjectType(), isConst);
+ builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst);
+ MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst);
}
if( funcs.GetLength() != 1 )
@@ -11793,7 +12231,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
else
{
// Add the default values for arguments not explicitly supplied
- int r = CompileDefaultAndNamedArgs(node, args, funcs[0], ctx->type.dataType.GetObjectType(), &namedArgs);
+ int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs);
// TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
// is it enough to make sure it is in a local variable?
@@ -11803,7 +12241,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
if( r == asSUCCESS )
{
Dereference(ctx, true);
- if( ctx->type.dataType.GetFuncDef() )
+ if( ctx->type.dataType.IsFuncdef() )
{
if( !ctx->type.isVariable )
ConvertToVariable(ctx);
@@ -11812,7 +12250,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
ctx->bc.Instr(asBC_PopPtr);
}
- MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetFuncDef() ? 0 : ctx->type.dataType.GetObjectType(), args, node, false, 0, ctx->type.stackOffset);
+ MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset);
}
}
}
@@ -11823,12 +12261,12 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
for( asUINT n = 0; n < args.GetLength(); n++ )
if( args[n] )
{
- asDELETE(args[n],asSExprContext);
+ asDELETE(args[n], asCExprContext);
}
for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
if( namedArgs[n].ctx )
{
- asDELETE(namedArgs[n].ctx,asSExprContext);
+ asDELETE(namedArgs[n].ctx, asCExprContext);
}
}
@@ -11900,7 +12338,7 @@ int asCCompiler::GetPrecedence(asCScriptNode *op)
return 0;
}
-asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArray &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct)
+asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArray &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
{
matches.SetLength(0);
@@ -11920,7 +12358,7 @@ asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArrayIsVoidExpression() )
@@ -11930,14 +12368,31 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *ar
return -1;
}
+ // Anonymous init lists can only match parameters that can be initialized with a list
+ if (argExpr->IsAnonymousInitList())
+ {
+ if ((desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] != asTM_INREF) ||
+ desc->parameterTypes[paramNum].GetTypeInfo() == 0 ||
+ desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0)
+ {
+ return -1;
+ }
+ return 0;
+ }
+
// Can we make the match by implicit conversion?
- asSExprContext ti(engine);
+ asCExprContext ti(engine);
ti.type = argExpr->type;
ti.methodName = argExpr->methodName;
ti.enumValue = argExpr->enumValue;
ti.exprNode = argExpr->exprNode;
if( argExpr->type.dataType.IsPrimitive() )
ti.type.dataType.MakeReference(false);
+
+ // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value
+ if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF)
+ allowObjectConstruct = false;
+
int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
// If the function parameter is an inout-reference then it must not be possible to call the
@@ -11960,7 +12415,7 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *ar
// Don't allow an enum to be converted to a reference of another enum type
if( desc->parameterTypes[paramNum].IsEnumType() &&
- desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType() )
+ desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() )
{
asASSERT( engine->ep.allowUnsafeReferences );
return -1;
@@ -11975,8 +12430,8 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *ar
}
// Don't allow a value type to be converted
- if( (desc->parameterTypes[paramNum].GetObjectType() && (desc->parameterTypes[paramNum].GetObjectType()->GetFlags() & asOBJ_VALUE)) &&
- (desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType()) )
+ if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) &&
+ (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) )
{
asASSERT( engine->ep.allowUnsafeReferences );
return -1;
@@ -11991,14 +12446,14 @@ int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *ar
return -1;
}
-void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
+void asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
{
// Reference parameters whose value won't be used don't evaluate the expression
// Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect
if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg )
{
// Store the original bytecode so that it can be reused when processing the deferred output parameter
- asSExprContext *orig = asNEW(asSExprContext)(engine);
+ asCExprContext *orig = asNEW(asCExprContext)(engine);
if( orig == 0 )
{
// Out of memory
@@ -12014,7 +12469,7 @@ void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asC
ctx->bc.AddCode(&arg->bc);
}
-bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool isHandle, eTokenType token)
+bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token)
{
DetermineSingleFunc(lctx, node);
DetermineSingleFunc(rctx, node);
@@ -12044,11 +12499,11 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
{
// TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
// Find the matching opEquals method
- int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
+ int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
if( r == 0 )
{
// Try again by switching the order of the operands
- r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
+ r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
}
if( r == 1 )
@@ -12078,12 +12533,12 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
// TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
// Find the matching opCmp method
- int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
+ int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
if( r == 0 )
{
// Try again by switching the order of the operands
swappedOrder = true;
- r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
+ r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
}
if( r == 1 )
@@ -12121,7 +12576,11 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
else if( r < 0 )
{
// Compiler error, don't continue
- ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
+ #if AS_SIZEOF_BOOL == 1
+ ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
+ #else
+ ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
+ #endif
return true;
}
}
@@ -12150,11 +12609,11 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
{
// TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
// Find the matching operator method
- int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
+ int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx);
if( r == 0 )
{
// Try again by switching the order of the operands, and using the reversed operator
- r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
+ r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx);
}
if( r == 1 )
@@ -12175,7 +12634,7 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
if( isHandle )
{
// Only asOBJ_ASHANDLE types can get here
- asASSERT( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) );
+ asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) );
asASSERT( token == ttAssignment );
if( token == ttAssignment )
@@ -12204,7 +12663,7 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
if( op )
{
if( builder->engine->ep.disallowValueAssignForRefType &&
- lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(lctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
+ lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
{
if( token == ttAssignment )
Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
@@ -12219,7 +12678,7 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
// TODO: Shouldn't accept const lvalue with the assignment operators
// Find the matching operator method
- int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
+ int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx);
if( r == 1 )
{
// Success, don't continue
@@ -12240,12 +12699,12 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
// Returns negative on compile error
// zero on no matching operator
// one on matching operator
-int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
+int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType)
{
// Find the matching method
if( lctx->type.dataType.IsObject() &&
(!lctx->type.isExplicitHandle ||
- lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
+ lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
{
asUINT n;
@@ -12253,7 +12712,7 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char
bool isConst = lctx->type.dataType.IsObjectConst();
asCArray funcs;
- asCObjectType *ot = lctx->type.dataType.GetObjectType();
+ asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo());
for( n = 0; n < ot->methods.GetLength(); n++ )
{
asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
@@ -12261,7 +12720,7 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char
if( func && func->name == methodName &&
(!specificReturn || func->returnType == returnType) &&
func->parameterTypes.GetLength() == 1 &&
- (!isConst || func->isReadOnly) )
+ (!isConst || func->IsReadOnly()) )
{
// Make sure the method is accessible by the module
if( builder->module->accessMask & func->accessMask )
@@ -12297,38 +12756,88 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char
// Did we find an operator?
if( ops.GetLength() == 1 )
{
+ // Reserve the variables used in the right expression so the new temporary
+ // variable allocated for the left operand isn't accidentally overwritten.
+ int l = int(reservedVariables.GetLength());
+ rctx->bc.GetVarsUsed(reservedVariables);
+
// Process the lctx expression as get accessor
ProcessPropertyGetAccessor(lctx, node);
- // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
- // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
- asCArray usedVars;
- lctx->bc.GetVarsUsed(usedVars);
- asUINT oldReservedVars = reservedVariables.GetLength();
- for( asUINT n = 0; n < rctx->deferredParams.GetLength(); n++ )
- {
- if( rctx->deferredParams[n].argType.isTemporary &&
- usedVars.Exists(rctx->deferredParams[n].argType.stackOffset) )
- {
- if( reservedVariables.GetLength() == oldReservedVars )
- reservedVariables.Concatenate(usedVars);
+ reservedVariables.SetLength(l);
- // Allocate a new variable for the deferred argument
- int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
- int oldVar = rctx->deferredParams[n].argType.stackOffset;
- rctx->deferredParams[n].argType.stackOffset = short(offset);
- rctx->bc.ExchangeVar(oldVar, offset);
- ReleaseTemporaryVariable(oldVar, 0);
+ asCExprContext tmpCtx(engine);
+ if (leftToRight)
+ {
+ // Make sure lctx is in fact a variable. If it is a reference there is no
+ // guarantee that the reference will stay alive throughout the evaluation of rctx
+ if (!lctx->type.isVariable)
+ {
+ // Reserve the variables used in the right expression so the new temporary
+ // variable allocated for the left operand isn't accidentally overwritten.
+ l = int(reservedVariables.GetLength());
+ rctx->bc.GetVarsUsed(reservedVariables);
+
+ if (lctx->type.dataType.SupportHandles())
+ lctx->type.dataType.MakeHandle(true);
+ PrepareTemporaryVariable(node, lctx);
+
+ reservedVariables.SetLength(l);
}
+
+ // Move the bytecode for the left operand to a temporary context
+ // so we can later make sure this is computed first
+ tmpCtx.bc.AddCode(&lctx->bc);
+ tmpCtx.bc.Instr(asBC_PopPtr);
+
+ // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer
+ // This will be placed after rctx by MakeFunctionCall below
+ lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset);
+
+ // Implicitly dereference handle parameters sent by reference
+ sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset);
+ if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()))
+ lctx->bc.Instr(asBC_RDSPtr);
+ }
+ else
+ {
+ // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
+ // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
+ asCArray usedVars;
+ lctx->bc.GetVarsUsed(usedVars);
+ asUINT oldReservedVars = reservedVariables.GetLength();
+ for (n = 0; n < rctx->deferredParams.GetLength(); n++)
+ {
+ if (rctx->deferredParams[n].argType.isTemporary &&
+ usedVars.Exists(rctx->deferredParams[n].argType.stackOffset))
+ {
+ if (reservedVariables.GetLength() == oldReservedVars)
+ reservedVariables.Concatenate(usedVars);
+
+ // Allocate a new variable for the deferred argument
+ int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
+ int oldVar = rctx->deferredParams[n].argType.stackOffset;
+ rctx->deferredParams[n].argType.stackOffset = short(offset);
+ rctx->bc.ExchangeVar(oldVar, offset);
+ ReleaseTemporaryVariable(oldVar, 0);
+ }
+ }
+ reservedVariables.SetLength(oldReservedVars);
}
- reservedVariables.SetLength(oldReservedVars);
// Merge the bytecode so that it forms lvalue.methodName(rvalue)
- asCArray args;
+ asCArray args;
args.PushLast(rctx);
MergeExprBytecode(ctx, lctx);
ctx->type = lctx->type;
- MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
+ MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
+
+ // Rearrange the bytecode so the left argument is computed first
+ if (leftToRight)
+ {
+ tmpCtx.bc.AddCode(&ctx->bc);
+ ctx->bc.AddCode(&tmpCtx.bc);
+ }
// Found matching operator
return 1;
@@ -12349,7 +12858,7 @@ int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char
return 0;
}
-void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
+void asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
{
if( objectType )
Dereference(ctx, true);
@@ -12410,7 +12919,7 @@ void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectTyp
PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
}
-int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
+int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight)
{
// Don't allow any operators on expressions that take address of class method, but allow it on global functions
if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
@@ -12442,7 +12951,7 @@ int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSE
else
{
// Compile an overloaded operator for the two operands
- if( CompileOverloadedDualOperator(node, lctx, rctx, ctx, false, op) )
+ if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) )
return 0;
// If both operands are objects, then we shouldn't continue
@@ -12520,7 +13029,7 @@ int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSE
return -1;
}
-void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
+void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
{
int l = int(reservedVariables.GetLength());
if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
@@ -12528,7 +13037,7 @@ void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext
reservedVariables.SetLength(l);
}
-void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
+void asCCompiler::ConvertToTempVariable(asCExprContext *ctx)
{
// This is only used for primitive types and null handles
asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
@@ -12554,7 +13063,7 @@ void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
}
}
-void asCCompiler::ConvertToVariable(asSExprContext *ctx)
+void asCCompiler::ConvertToVariable(asCExprContext *ctx)
{
// We should never get here while the context is still an unprocessed property accessor
asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
@@ -12577,7 +13086,10 @@ void asCCompiler::ConvertToVariable(asSExprContext *ctx)
// Copy the object handle to a variable
ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
- ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
+ if( ctx->type.dataType.IsFuncdef() )
+ ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
+ else
+ ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
ctx->bc.Instr(asBC_PopPtr);
}
@@ -12596,13 +13108,13 @@ void asCCompiler::ConvertToVariable(asSExprContext *ctx)
{
offset = AllocateVariable(ctx->type.dataType, true);
if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
- ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
+ ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB());
else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
- ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
+ ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW());
else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
- ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
+ ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW());
else
- ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
+ ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW());
ctx->type.SetVariable(ctx->type.dataType, offset, true);
return;
@@ -12631,7 +13143,7 @@ void asCCompiler::ConvertToVariable(asSExprContext *ctx)
}
}
-void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
+void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
{
int l = int(reservedVariables.GetLength());
if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
@@ -12639,10 +13151,10 @@ void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *ex
reservedVariables.SetLength(l);
}
-void asCCompiler::ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node)
+void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node)
{
asCArray funcs;
- asCObjectType *ot = ctx->type.dataType.GetObjectType();
+ asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
if( ot )
{
for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
@@ -12702,7 +13214,7 @@ void asCCompiler::ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScrip
}
}
-void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
+void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
{
// TODO: If a constant is only using 32bits, then a 32bit operation is preferred
@@ -12833,9 +13345,13 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
// Verify if we are dividing with a constant zero
- if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
+ if( rctx->type.isConstant &&
(op == ttSlash || op == ttDivAssign ||
- op == ttPercent || op == ttModAssign) )
+ op == ttPercent || op == ttModAssign) &&
+ ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) ||
+ (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) ||
+ (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) ||
+ (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) )
{
Error(TXT_DIVIDE_BY_ZERO, node);
}
@@ -12998,40 +13514,40 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
{
int v = 0;
if( op == ttPlus )
- v = lctx->type.intValue + rctx->type.intValue;
+ v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW());
else if( op == ttMinus )
- v = lctx->type.intValue - rctx->type.intValue;
+ v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
else if( op == ttStar )
- v = lctx->type.intValue * rctx->type.intValue;
+ v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW());
else if( op == ttSlash )
{
// TODO: Should probably report an error, rather than silently convert the value to 0
- if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
+ if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
v = 0;
else
if( lctx->type.dataType.IsIntegerType() )
- v = lctx->type.intValue / rctx->type.intValue;
+ v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW());
else
- v = lctx->type.dwordValue / rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW();
}
else if( op == ttPercent )
{
// TODO: Should probably report an error, rather than silently convert the value to 0
- if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
+ if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
v = 0;
else
if( lctx->type.dataType.IsIntegerType() )
- v = lctx->type.intValue % rctx->type.intValue;
+ v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW());
else
- v = lctx->type.dwordValue % rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW();
}
else if( op == ttStarStar )
{
bool isOverflow;
if( lctx->type.dataType.IsIntegerType() )
- v = as_powi(lctx->type.intValue, rctx->type.intValue, isOverflow);
+ v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow);
else
- v = as_powu(lctx->type.dwordValue, rctx->type.dwordValue, isOverflow);
+ v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow);
if( isOverflow )
Error(TXT_POW_OVERFLOW, node);
@@ -13040,47 +13556,47 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
ctx->type.SetConstantDW(lctx->type.dataType, v);
// If the right value is greater than the left value in a minus operation, then we need to convert the type to int
- if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
+ if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW())
ctx->type.dataType.SetTokenType(ttInt);
}
else
{
asQWORD v = 0;
if( op == ttPlus )
- v = lctx->type.qwordValue + rctx->type.qwordValue;
+ v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW());
else if( op == ttMinus )
- v = lctx->type.qwordValue - rctx->type.qwordValue;
+ v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
else if( op == ttStar )
- v = lctx->type.qwordValue * rctx->type.qwordValue;
+ v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW());
else if( op == ttSlash )
{
// TODO: Should probably report an error, rather than silently convert the value to 0
- if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
+ if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
v = 0;
else
if( lctx->type.dataType.IsIntegerType() )
- v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
+ v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW());
else
- v = lctx->type.qwordValue / rctx->type.qwordValue;
+ v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW();
}
else if( op == ttPercent )
{
// TODO: Should probably report an error, rather than silently convert the value to 0
- if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
+ if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
v = 0;
else
if( lctx->type.dataType.IsIntegerType() )
- v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
+ v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW());
else
- v = lctx->type.qwordValue % rctx->type.qwordValue;
+ v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW();
}
else if( op == ttStarStar )
{
bool isOverflow;
if( lctx->type.dataType.IsIntegerType() )
- v = as_powi64(asINT64(lctx->type.qwordValue), asINT64(rctx->type.qwordValue), isOverflow);
+ v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow);
else
- v = as_powu64(lctx->type.qwordValue, rctx->type.qwordValue, isOverflow);
+ v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow);
if( isOverflow )
Error(TXT_POW_OVERFLOW, node);
@@ -13089,7 +13605,7 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
ctx->type.SetConstantQW(lctx->type.dataType, v);
// If the right value is greater than the left value in a minus operation, then we need to convert the type to int
- if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
+ if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW())
ctx->type.dataType.SetTokenType(ttInt64);
}
}
@@ -13097,28 +13613,28 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
{
float v = 0.0f;
if( op == ttPlus )
- v = lctx->type.floatValue + rctx->type.floatValue;
+ v = lctx->type.GetConstantF() + rctx->type.GetConstantF();
else if( op == ttMinus )
- v = lctx->type.floatValue - rctx->type.floatValue;
+ v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
else if( op == ttStar )
- v = lctx->type.floatValue * rctx->type.floatValue;
+ v = lctx->type.GetConstantF() * rctx->type.GetConstantF();
else if( op == ttSlash )
{
- if( rctx->type.floatValue == 0 )
+ if( rctx->type.GetConstantF() == 0 )
v = 0;
else
- v = lctx->type.floatValue / rctx->type.floatValue;
+ v = lctx->type.GetConstantF() / rctx->type.GetConstantF();
}
else if( op == ttPercent )
{
- if( rctx->type.floatValue == 0 )
+ if( rctx->type.GetConstantF() == 0 )
v = 0;
else
- v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
+ v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
}
else if( op == ttStarStar )
{
- v = pow(lctx->type.floatValue, rctx->type.floatValue);
+ v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
if( v == HUGE_VAL )
Error(TXT_POW_OVERFLOW, node);
@@ -13135,7 +13651,7 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
if( op == ttStarStar || op == ttPowAssign )
{
- v = pow(lctx->type.doubleValue, rctx->type.intValue);
+ v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW()));
if( v == HUGE_VAL )
Error(TXT_POW_OVERFLOW, node);
}
@@ -13145,28 +13661,28 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
else
{
if( op == ttPlus )
- v = lctx->type.doubleValue + rctx->type.doubleValue;
+ v = lctx->type.GetConstantD() + rctx->type.GetConstantD();
else if( op == ttMinus )
- v = lctx->type.doubleValue - rctx->type.doubleValue;
+ v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
else if( op == ttStar )
- v = lctx->type.doubleValue * rctx->type.doubleValue;
+ v = lctx->type.GetConstantD() * rctx->type.GetConstantD();
else if( op == ttSlash )
{
- if( rctx->type.doubleValue == 0 )
+ if( rctx->type.GetConstantD() == 0 )
v = 0;
else
- v = lctx->type.doubleValue / rctx->type.doubleValue;
+ v = lctx->type.GetConstantD() / rctx->type.GetConstantD();
}
else if( op == ttPercent )
{
- if( rctx->type.doubleValue == 0 )
+ if( rctx->type.GetConstantD() == 0 )
v = 0;
else
- v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
+ v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD());
}
else if( op == ttStarStar )
{
- v = pow(lctx->type.doubleValue, rctx->type.doubleValue);
+ v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD());
if( v == HUGE_VAL )
Error(TXT_POW_OVERFLOW, node);
}
@@ -13182,7 +13698,7 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
}
}
-void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
+void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
{
// TODO: If a constant is only using 32bits, then a 32bit operation is preferred
@@ -13291,11 +13807,11 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc
{
asQWORD v = 0;
if( op == ttAmp )
- v = lctx->type.qwordValue & rctx->type.qwordValue;
+ v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW();
else if( op == ttBitOr )
- v = lctx->type.qwordValue | rctx->type.qwordValue;
+ v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW();
else if( op == ttBitXor )
- v = lctx->type.qwordValue ^ rctx->type.qwordValue;
+ v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW();
// Remember the result
ctx->type.SetConstantQW(lctx->type.dataType, v);
@@ -13304,11 +13820,11 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc
{
asDWORD v = 0;
if( op == ttAmp )
- v = lctx->type.dwordValue & rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW();
else if( op == ttBitOr )
- v = lctx->type.dwordValue | rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW();
else if( op == ttBitXor )
- v = lctx->type.dwordValue ^ rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW();
// Remember the result
ctx->type.SetConstantDW(lctx->type.dataType, v);
@@ -13336,15 +13852,15 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc
if( lctx->type.dataType.IsUnsignedType() &&
lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
{
+ // Upgrade to 32bit
to = asCDataType::CreatePrimitive(ttUInt, false);
}
else if( !lctx->type.dataType.IsUnsignedType() )
{
- asCDataType to;
- if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
- to.SetTokenType(ttInt64);
+ if (lctx->type.dataType.GetSizeInMemoryDWords() == 2)
+ to = asCDataType::CreatePrimitive(ttInt64, false);
else
- to.SetTokenType(ttInt);
+ to = asCDataType::CreatePrimitive(ttInt, false);
}
// Do the actual conversion
@@ -13430,11 +13946,11 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc
{
asDWORD v = 0;
if( op == ttBitShiftLeft )
- v = lctx->type.dwordValue << rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW();
else if( op == ttBitShiftRight )
- v = lctx->type.dwordValue >> rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW();
else if( op == ttBitShiftRightArith )
- v = lctx->type.intValue >> rctx->type.dwordValue;
+ v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW();
ctx->type.SetConstantDW(lctx->type.dataType, v);
}
@@ -13442,11 +13958,11 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc
{
asQWORD v = 0;
if( op == ttBitShiftLeft )
- v = lctx->type.qwordValue << rctx->type.dwordValue;
+ v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW();
else if( op == ttBitShiftRight )
- v = lctx->type.qwordValue >> rctx->type.dwordValue;
+ v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW();
else if( op == ttBitShiftRightArith )
- v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
+ v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW();
ctx->type.SetConstantQW(lctx->type.dataType, v);
}
@@ -13454,7 +13970,7 @@ void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lc
}
}
-void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
+void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
{
// Both operands must be of the same type
@@ -13516,22 +14032,32 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext
bool signMismatch = false;
for( int n = 0; !signMismatch && n < 2; n++ )
{
- asSExprContext *op = n ? rctx : lctx;
+ asCExprContext *opCtx = n ? rctx : lctx;
- if( op->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
+ if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
{
// We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
signMismatch = true;
- if( op->type.isConstant )
+ if( opCtx->type.isConstant )
{
- if( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 )
+ if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 )
{
- if( !(op->type.qwordValue & (asQWORD(1)<<63)) )
+ if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) )
signMismatch = false;
}
- else
+ else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() )
{
- if( !(op->type.dwordValue & (1<<31)) )
+ if( !(opCtx->type.GetConstantDW() & (1<<31)) )
+ signMismatch = false;
+ }
+ else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16)
+ {
+ if (!(opCtx->type.GetConstantW() & (1 << 15)))
+ signMismatch = false;
+ }
+ else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8)
+ {
+ if (!(opCtx->type.GetConstantB() & (1 << 7)))
signMismatch = false;
}
@@ -13586,12 +14112,16 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext
{
// It wasn't possible to get two valid operands, so we just return
// a boolean result and let the compiler continue.
+#if AS_SIZEOF_BOOL == 1
+ ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
+#else
ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
+#endif
return;
}
bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
-
+
if( op == ttUnrecognizedToken )
op = node->tokenType;
@@ -13638,7 +14168,11 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext
{
// TODO: Use TXT_ILLEGAL_OPERATION_ON
Error(TXT_ILLEGAL_OPERATION, node);
+#if AS_SIZEOF_BOOL == 1
+ ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0);
+#else
ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
+#endif
}
}
else
@@ -13699,23 +14233,30 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext
{
if( op == ttEqual || op == ttNotEqual )
{
+ asDWORD lv, rv;
+ #if AS_SIZEOF_BOOL == 1
+ lv = lctx->type.GetConstantB();
+ rv = rctx->type.GetConstantB();
+ #else
+ lv = lctx->type.GetConstantDW();
+ rv = rctx->type.GetConstantDW();
+ #endif
+
// Make sure they are equal if not false
- if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
- if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
+ if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE;
+ if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE;
asDWORD v = 0;
- if( op == ttEqual )
- {
- v = lctx->type.intValue - rctx->type.intValue;
- if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
- }
- else if( op == ttNotEqual )
- {
- v = lctx->type.intValue - rctx->type.intValue;
- if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
- }
+ if (op == ttEqual)
+ v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
+ else if (op == ttNotEqual)
+ v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
- ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
+ #if AS_SIZEOF_BOOL == 1
+ ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v);
+ #else
+ ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
+ #endif
}
else
{
@@ -13728,39 +14269,39 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext
int i = 0;
if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
{
- int v = lctx->type.intValue - rctx->type.intValue;
+ int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
if( v < 0 ) i = -1;
if( v > 0 ) i = 1;
}
else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
{
- asDWORD v1 = lctx->type.dwordValue;
- asDWORD v2 = rctx->type.dwordValue;
+ asDWORD v1 = lctx->type.GetConstantDW();
+ asDWORD v2 = rctx->type.GetConstantDW();
if( v1 < v2 ) i = -1;
if( v1 > v2 ) i = 1;
}
else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
{
- asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
+ asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
if( v < 0 ) i = -1;
if( v > 0 ) i = 1;
}
else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
{
- asQWORD v1 = lctx->type.qwordValue;
- asQWORD v2 = rctx->type.qwordValue;
+ asQWORD v1 = lctx->type.GetConstantQW();
+ asQWORD v2 = rctx->type.GetConstantQW();
if( v1 < v2 ) i = -1;
if( v1 > v2 ) i = 1;
}
else if( lctx->type.dataType.IsFloatType() )
{
- float v = lctx->type.floatValue - rctx->type.floatValue;
+ float v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
if( v < 0 ) i = -1;
if( v > 0 ) i = 1;
}
else if( lctx->type.dataType.IsDoubleType() )
{
- double v = lctx->type.doubleValue - rctx->type.doubleValue;
+ double v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
if( v < 0 ) i = -1;
if( v > 0 ) i = 1;
}
@@ -13779,12 +14320,16 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext
else if( op == ttGreaterThanOrEqual )
i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
- ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
+ #if AS_SIZEOF_BOOL == 1
+ ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i);
+ #else
+ ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
+ #endif
}
}
}
-void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
+void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference)
{
// Put the result on the stack
if( asReference )
@@ -13801,7 +14346,7 @@ void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
}
}
-void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
+void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
{
// Both operands must be booleans
asCDataType to;
@@ -13813,9 +14358,9 @@ void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lc
lctx->bc.GetVarsUsed(reservedVariables);
// Allow value types to be converted to bool using 'bool opImplConv()'
- if( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
+ if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
- if( rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
+ if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
reservedVariables.SetLength(l);
@@ -13875,25 +14420,25 @@ void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lc
{
// Make sure they are equal if not false
#if AS_SIZEOF_BOOL == 1
- if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
- if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
+ if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
+ if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
asBYTE v = 0;
- v = lctx->type.byteValue - rctx->type.byteValue;
+ v = lctx->type.GetConstantB() - rctx->type.GetConstantB();
if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
ctx->type.isConstant = true;
- ctx->type.byteValue = v;
+ ctx->type.SetConstantB(v);
#else
- if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
- if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
+ if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
+ if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
asDWORD v = 0;
- v = lctx->type.intValue - rctx->type.intValue;
+ v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW();
if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
ctx->type.isConstant = true;
- ctx->type.dwordValue = v;
+ ctx->type.SetConstantDW(v);
#endif
}
}
@@ -13946,29 +14491,29 @@ void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lc
#if AS_SIZEOF_BOOL == 1
asBYTE v = 0;
if( op == ttAnd )
- v = lctx->type.byteValue && rctx->type.byteValue;
+ v = lctx->type.GetConstantB() && rctx->type.GetConstantB();
else if( op == ttOr )
- v = lctx->type.byteValue || rctx->type.byteValue;
+ v = lctx->type.GetConstantB() || rctx->type.GetConstantB();
// Remember the result
ctx->type.isConstant = true;
- ctx->type.byteValue = v;
+ ctx->type.SetConstantB(v);
#else
asDWORD v = 0;
if( op == ttAnd )
- v = lctx->type.dwordValue && rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW();
else if( op == ttOr )
- v = lctx->type.dwordValue || rctx->type.dwordValue;
+ v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW();
// Remember the result
ctx->type.isConstant = true;
- ctx->type.dwordValue = v;
+ ctx->type.SetConstantDW(v);
#endif
}
}
}
-void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType opToken)
+void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken)
{
// Process the property accessor as get
ProcessPropertyGetAccessor(lctx, node);
@@ -13992,25 +14537,25 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *
// Warn if not both operands are explicit handles or null handles
if( (opToken == ttEqual || opToken == ttNotEqual) &&
- ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
- (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
+ ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) ||
+ (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) )
{
Warning(TXT_HANDLE_COMPARISON, node);
}
// If one of the operands is a value type used as handle, we should look for the opEquals method
- if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
- (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
+ if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ||
+ (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) &&
(opToken == ttEqual || opToken == ttIs ||
opToken == ttNotEqual || opToken == ttNotIs) )
{
// TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
// Find the matching opEquals method
- int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
+ int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
if( r == 0 )
{
// Try again by switching the order of the operands
- r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
+ r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
}
if( r == 1 )
@@ -14042,10 +14587,10 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *
else
{
// Find a common base type
- asSExprContext tmp(engine);
+ asCExprContext tmp(engine);
tmp.type = rctx->type;
ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
- if( tmp.type.dataType.GetObjectType() == lctx->type.dataType.GetObjectType() )
+ if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
to = lctx->type.dataType;
else
to = rctx->type.dataType;
@@ -14068,7 +14613,11 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *
{
// Compiler error, don't continue
Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
+#if AS_SIZEOF_BOOL == 1
+ ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
+#else
ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
+#endif
return;
}
@@ -14103,7 +14652,7 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *
if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs )
{
- // Make sure handles received as parameters by reference are copied to a local variable before the
+ // Make sure handles received as parameters by reference are copied to a local variable before the
// asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself
if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 )
lctx->type.isVariable = false;
@@ -14148,7 +14697,7 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *
}
-void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
+void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
{
asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
@@ -14161,14 +14710,14 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
}
// Check if the function is private or protected
- if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
+ if( descr->IsPrivate() && descr->GetObjectType() != outFunc->GetObjectType() )
{
asCString msg;
msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
Error(msg, ctx->exprNode);
}
- else if( descr->isProtected &&
- !(descr->GetObjectType() == outFunc->GetObjectType() ||
+ else if( descr->IsProtected() &&
+ !(descr->GetObjectType() == outFunc->GetObjectType() ||
(outFunc->GetObjectType() && outFunc->GetObjectType()->DerivesFrom(descr->GetObjectType()))) )
{
asCString msg;
@@ -14182,25 +14731,24 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
// alive throughout the call by holding on to a reference in a local variable. This must
// be done for any methods that return references, and any calls on script objects.
// Application registered objects are assumed to know to keep themselves alive even
- // if the method doesn't return a refernce.
- if( descr->objectType &&
+ // if the method doesn't return a reference.
+ if( !ctx->type.isHandleSafe &&
+ descr->objectType &&
(ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
- (descr->returnType.IsReference() || (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
+ (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
!(ctx->type.isVariable || ctx->type.isTemporary) &&
- !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
- !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
+ !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) &&
+ !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) )
{
- // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
+ // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
// local variable and then refer to the same for each call. An alias for the global variable
- // should be stored in the variable scope so that the compiler can find it. For loops and
- // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
+ // should be stored in the variable scope so that the compiler can find it. For loops and
+ // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
// higher scope to increase the probability of re-use.
- // TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
-
int tempRef = AllocateVariable(ctx->type.dataType, true);
ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
- ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
+ ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
// Add the release of this reference as a deferred expression
asSDeferredParam deferred;
@@ -14302,11 +14850,11 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
else if( descr->funcType == asFUNC_SYSTEM )
{
// Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of
- // type &obj::func(int)
+ // type &obj::func(int)
// type &obj::func(uint)
- if( descr->GetObjectType() && descr->returnType.IsReference() &&
- descr->parameterTypes.GetLength() == 1 &&
- (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
+ if( descr->GetObjectType() && descr->returnType.IsReference() &&
+ descr->parameterTypes.GetLength() == 1 &&
+ (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 &&
!descr->parameterTypes[0].IsReference() )
ctx->bc.Call(asBC_Thiscall1, descr->id, argSize);
@@ -14317,11 +14865,11 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
}
- if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
+ if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
{
int returnOffset = 0;
- asCTypeInfo tmpExpr = ctx->type;
+ asCExprValue tmpExpr = ctx->type;
if( descr->DoesReturnOnStack() )
{
@@ -14413,7 +14961,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
{
asASSERT(useVariable == false);
- asCTypeInfo tmpExpr = ctx->type;
+ asCExprValue tmpExpr = ctx->type;
if( descr->returnType.GetSizeInMemoryBytes() )
{
@@ -14422,7 +14970,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
int l = int(reservedVariables.GetLength());
for( asUINT n = 0; args && n < args->GetLength(); n++ )
{
- asSExprContext *expr = (*args)[n]->origExpr;
+ asCExprContext *expr = (*args)[n]->origExpr;
if( expr )
expr->bc.GetVarsUsed(reservedVariables);
}
@@ -14453,7 +15001,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
}
// This only merges the bytecode, but doesn't modify the type of the final context
-void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
+void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after)
{
before->bc.AddCode(&after->bc);
@@ -14467,7 +15015,7 @@ void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *afte
}
// This merges both bytecode and the type of the final context
-void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
+void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after)
{
MergeExprBytecode(before, after);
@@ -14488,7 +15036,7 @@ void asCCompiler::FilterConst(asCArray &funcs, bool removeConst)
for( n = 0; n < funcs.GetLength(); n++ )
{
desc = builder->GetFunctionDescription(funcs[n]);
- if( desc->isReadOnly != removeConst )
+ if( desc->IsReadOnly() != removeConst )
{
foundNonConst = true;
break;
@@ -14501,7 +15049,7 @@ void asCCompiler::FilterConst(asCArray &funcs, bool removeConst)
for( n = 0; n < funcs.GetLength(); n++ )
{
desc = builder->GetFunctionDescription(funcs[n]);
- if( desc->isReadOnly == removeConst )
+ if( desc->IsReadOnly() == removeConst )
{
if( n == funcs.GetLength() - 1 )
funcs.PopLast();
@@ -14514,6 +15062,389 @@ void asCCompiler::FilterConst(asCArray &funcs, bool removeConst)
}
}
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+asCExprValue::asCExprValue()
+{
+ isTemporary = false;
+ stackOffset = 0;
+ isConstant = false;
+ isVariable = false;
+ isExplicitHandle = false;
+ qwordValue = 0;
+ isLValue = false;
+ isRefToLocal = false;
+ isHandleSafe = false;
+}
+
+void asCExprValue::Set(const asCDataType &dt)
+{
+ dataType = dt;
+
+ isTemporary = false;
+ stackOffset = 0;
+ isConstant = false;
+ isVariable = false;
+ isExplicitHandle = false;
+ qwordValue = 0;
+ isLValue = false;
+ isRefToLocal = false;
+ isHandleSafe = false;
+}
+
+void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary)
+{
+ Set(in_dt);
+
+ this->isVariable = true;
+ this->isTemporary = in_isTemporary;
+ this->stackOffset = (short)in_stackOffset;
+}
+
+void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value)
+{
+ Set(dt);
+
+ isConstant = true;
+ SetConstantQW(value);
+}
+
+void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value)
+{
+ Set(dt);
+
+ isConstant = true;
+ SetConstantDW(value);
+}
+
+void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value)
+{
+ Set(dt);
+
+ isConstant = true;
+ SetConstantB(value);
+}
+
+void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value)
+{
+ Set(dt);
+
+ isConstant = true;
+ SetConstantW(value);
+}
+
+void asCExprValue::SetConstantF(const asCDataType &dt, float value)
+{
+ Set(dt);
+
+ isConstant = true;
+ SetConstantF(value);
+}
+
+void asCExprValue::SetConstantD(const asCDataType &dt, double value)
+{
+ Set(dt);
+
+ isConstant = true;
+ SetConstantD(value);
+}
+
+void asCExprValue::SetConstantQW(asQWORD value)
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 8);
+ qwordValue = value;
+}
+
+void asCExprValue::SetConstantDW(asDWORD value)
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 4);
+ dwordValue = value;
+}
+
+void asCExprValue::SetConstantW(asWORD value)
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 2);
+ wordValue = value;
+}
+
+void asCExprValue::SetConstantB(asBYTE value)
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 1);
+ byteValue = value;
+}
+
+void asCExprValue::SetConstantF(float value)
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 4);
+ floatValue = value;
+}
+
+void asCExprValue::SetConstantD(double value)
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 8);
+ doubleValue = value;
+}
+
+asQWORD asCExprValue::GetConstantQW()
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 8);
+ return qwordValue;
+}
+
+asDWORD asCExprValue::GetConstantDW()
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 4);
+ return dwordValue;
+}
+
+asWORD asCExprValue::GetConstantW()
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 2);
+ return wordValue;
+}
+
+asBYTE asCExprValue::GetConstantB()
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 1);
+ return byteValue;
+}
+
+float asCExprValue::GetConstantF()
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 4);
+ return floatValue;
+}
+
+double asCExprValue::GetConstantD()
+{
+ asASSERT(dataType.GetSizeInMemoryBytes() == 8);
+ return doubleValue;
+}
+
+void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw)
+{
+ Set(dt);
+
+ isConstant = true;
+
+ // This code is necessary to guarantee that the code
+ // works on both big endian and little endian CPUs.
+ if (dataType.GetSizeInMemoryBytes() == 1)
+ byteValue = (asBYTE)qw;
+ if (dataType.GetSizeInMemoryBytes() == 2)
+ wordValue = (asWORD)qw;
+ if (dataType.GetSizeInMemoryBytes() == 4)
+ dwordValue = (asDWORD)qw;
+ else
+ qwordValue = qw;
+}
+
+asQWORD asCExprValue::GetConstantData()
+{
+ asQWORD qw = 0;
+ // This code is necessary to guarantee that the code
+ // works on both big endian and little endian CPUs.
+ if (dataType.GetSizeInMemoryBytes() == 1)
+ qw = byteValue;
+ if (dataType.GetSizeInMemoryBytes() == 2)
+ qw = wordValue;
+ if (dataType.GetSizeInMemoryBytes() == 4)
+ qw = dwordValue;
+ else
+ qw = qwordValue;
+ return qw;
+}
+
+void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine)
+{
+ // This is used for when the expression evaluates to a
+ // function, but it is not yet known exactly which. The
+ // owner expression will hold the name of the function
+ // to determine the exact function when the signature is
+ // known.
+ Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true));
+ isConstant = true;
+ isExplicitHandle = false;
+ qwordValue = 1; // Set to a different value than 0 to differentiate from null constant
+ isLValue = false;
+}
+
+bool asCExprValue::IsUndefinedFuncHandle() const
+{
+ if (isConstant == false) return false;
+ if (qwordValue == 0) return false;
+ if (isLValue) return false;
+ if (dataType.GetTypeInfo() == 0) return false;
+ if (dataType.GetTypeInfo()->name != "$func") return false;
+ if (dataType.IsFuncdef()) return false;
+
+ return true;
+}
+
+void asCExprValue::SetNullConstant()
+{
+ Set(asCDataType::CreateNullHandle());
+ isConstant = true;
+ isExplicitHandle = false;
+ qwordValue = 0;
+ isLValue = false;
+}
+
+bool asCExprValue::IsNullConstant() const
+{
+ // We can't check the actual object type, because the null constant may have been cast to another type
+ if (isConstant && dataType.IsObjectHandle() && qwordValue == 0)
+ return true;
+
+ return false;
+}
+
+void asCExprValue::SetVoid()
+{
+ Set(asCDataType::CreatePrimitive(ttVoid, false));
+ isLValue = false;
+ isConstant = true;
+}
+
+bool asCExprValue::IsVoid() const
+{
+ if (dataType.GetTokenType() == ttVoid)
+ return true;
+
+ return false;
+}
+
+void asCExprValue::SetDummy()
+{
+ SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine)
+{
+ property_arg = 0;
+
+ Clear();
+}
+
+asCExprContext::~asCExprContext()
+{
+ if (property_arg)
+ asDELETE(property_arg, asCExprContext);
+}
+
+void asCExprContext::Clear()
+{
+ bc.ClearAll();
+ type.Set(asCDataType());
+ deferredParams.SetLength(0);
+ if (property_arg)
+ asDELETE(property_arg, asCExprContext);
+ property_arg = 0;
+ exprNode = 0;
+ origExpr = 0;
+ property_get = 0;
+ property_set = 0;
+ property_const = false;
+ property_handle = false;
+ property_ref = false;
+ methodName = "";
+ enumValue = "";
+ isVoidExpression = false;
+ isCleanArg = false;
+ isAnonymousInitList = false;
+}
+
+bool asCExprContext::IsClassMethod() const
+{
+ if (type.dataType.GetTypeInfo() == 0) return false;
+ if (methodName == "") return false;
+ if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
+ if (isAnonymousInitList) return false;
+ return true;
+}
+
+bool asCExprContext::IsGlobalFunc() const
+{
+ if (type.dataType.GetTypeInfo() == 0) return false;
+ if (methodName == "") return false;
+ if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
+ if (isAnonymousInitList) return false;
+ return true;
+}
+
+void asCExprContext::SetLambda(asCScriptNode *funcDecl)
+{
+ asASSERT(funcDecl && funcDecl->nodeType == snFunction);
+ asASSERT(bc.GetLastInstr() == -1);
+
+ Clear();
+ type.SetUndefinedFuncHandle(bc.GetEngine());
+ exprNode = funcDecl;
+}
+
+bool asCExprContext::IsLambda() const
+{
+ if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction)
+ return true;
+
+ return false;
+}
+
+void asCExprContext::SetVoidExpression()
+{
+ Clear();
+ type.SetVoid();
+ isVoidExpression = true;
+}
+
+bool asCExprContext::IsVoidExpression() const
+{
+ if (isVoidExpression && type.IsVoid() && exprNode == 0)
+ return true;
+
+ return false;
+}
+
+void asCExprContext::SetAnonymousInitList(asCScriptNode *initList)
+{
+ Clear();
+ exprNode = initList;
+ isAnonymousInitList = true;
+}
+
+bool asCExprContext::IsAnonymousInitList() const
+{
+ if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList)
+ return true;
+
+ return false;
+}
+
+void asCExprContext::Merge(asCExprContext *after)
+{
+ type = after->type;
+ property_get = after->property_get;
+ property_set = after->property_set;
+ property_const = after->property_const;
+ property_handle = after->property_handle;
+ property_ref = after->property_ref;
+ property_arg = after->property_arg;
+ exprNode = after->exprNode;
+ methodName = after->methodName;
+ enumValue = after->enumValue;
+ isVoidExpression = after->isVoidExpression;
+ isCleanArg = after->isCleanArg;
+ isAnonymousInitList = after->isAnonymousInitList;
+
+ after->property_arg = 0;
+
+ // Do not copy the origExpr member
+}
+
+
+
END_AS_NAMESPACE
#endif // AS_NO_COMPILER
diff --git a/lib/angelscript/source/as_compiler.h b/lib/angelscript/source/as_compiler.h
index f9de7e475..61e9f3490 100644
--- a/lib/angelscript/source/as_compiler.h
+++ b/lib/angelscript/source/as_compiler.h
@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
- Copyright (c) 2003-2015 Andreas Jonsson
+ Copyright (c) 2003-2017 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
@@ -50,123 +50,110 @@
#include "as_bytecode.h"
#include "as_array.h"
#include "as_datatype.h"
-#include "as_typeinfo.h"
BEGIN_AS_NAMESPACE
-struct asSExprContext;
+// This class represents the value of an expression as evaluated by the compiler.
+// It holds information such as the type of the value, stack offset for a local
+// variable, value of constants, whether the value can be modified (i.e. lvalue), etc.
+struct asCExprValue
+{
+ asCExprValue();
+ void Set(const asCDataType &dataType);
+ void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary);
+ void SetConstantB(const asCDataType &dataType, asBYTE value);
+ void SetConstantQW(const asCDataType &dataType, asQWORD value);
+ void SetConstantDW(const asCDataType &dataType, asDWORD value);
+ void SetConstantW(const asCDataType &dataType, asWORD value);
+ void SetConstantF(const asCDataType &dataType, float value);
+ void SetConstantD(const asCDataType &dataType, double value);
+ void SetConstantB(asBYTE value);
+ void SetConstantW(asWORD value);
+ void SetConstantQW(asQWORD value);
+ void SetConstantDW(asDWORD value);
+ void SetConstantF(float value);
+ void SetConstantD(double value);
+ asBYTE GetConstantB();
+ asWORD GetConstantW();
+ asQWORD GetConstantQW();
+ asDWORD GetConstantDW();
+ float GetConstantF();
+ double GetConstantD();
+
+ void SetConstantData(const asCDataType &dataType, asQWORD value);
+ asQWORD GetConstantData();
+
+ void SetNullConstant();
+ void SetUndefinedFuncHandle(asCScriptEngine *engine);
+ void SetVoid();
+ void SetDummy();
+
+ bool IsUndefinedFuncHandle() const;
+ bool IsNullConstant() const;
+ bool IsVoid() const;
+
+ asCDataType dataType;
+ bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc
+ bool isTemporary : 1;
+ bool isConstant : 1;
+ bool isVariable : 1;
+ bool isExplicitHandle : 1;
+ bool isRefToLocal : 1; // The reference may be to a local variable
+ bool isHandleSafe : 1; // the life-time of the handle is guaranteed for the duration of the access
+ short dummy : 9;
+ short stackOffset;
+
+private:
+ // These values must not be accessed directly in order to avoid problems with endianess.
+ // Use the appropriate accessor methods instead
+ union
+ {
+ asQWORD qwordValue;
+ double doubleValue;
+ asDWORD dwordValue;
+ float floatValue;
+ asWORD wordValue;
+ asBYTE byteValue;
+ };
+};
+
+struct asCExprContext;
+
+// This class holds information for arguments that needs to be
+// cleaned up after the result of a function has been evaluated.
struct asSDeferredParam
{
asSDeferredParam() {argNode = 0; origExpr = 0;}
asCScriptNode *argNode;
- asCTypeInfo argType;
+ asCExprValue argType;
int argInOutFlags;
- asSExprContext *origExpr;
+ asCExprContext *origExpr;
};
-// TODO: refactor: asSExprContext should have indicators to inform where the value is,
+// TODO: refactor: asCExprContext should have indicators to inform where the value is,
// i.e. if the reference to an object is pushed on the stack or not, etc
-struct asSExprContext
+// This class holds information about an expression that is being evaluated, e.g.
+// the current bytecode, ambiguous symbol names, property accessors, etc.
+struct asCExprContext
{
- asSExprContext(asCScriptEngine *engine) : bc(engine)
- {
- property_arg = 0;
-
- Clear();
- }
- ~asSExprContext()
- {
- if( property_arg )
- asDELETE(property_arg, asSExprContext);
- }
- void Clear()
- {
- bc.ClearAll();
- type.Set(asCDataType());
- deferredParams.SetLength(0);
- if( property_arg )
- asDELETE(property_arg, asSExprContext);
- property_arg = 0;
- exprNode = 0;
- origExpr = 0;
- property_get = 0;
- property_set = 0;
- property_const = false;
- property_handle = false;
- property_ref = false;
- methodName = "";
- enumValue = "";
- isVoidExpression = false;
- isCleanArg = false;
- }
- bool IsClassMethod() const
- {
- if( type.dataType.GetObjectType() == 0 ) return false;
- if( methodName == "" ) return false;
- if( type.dataType.GetObjectType() == &type.dataType.GetObjectType()->engine->functionBehaviours ) return false;
- return true;
- }
- bool IsGlobalFunc() const
- {
- if( type.dataType.GetObjectType() == 0 ) return false;
- if( methodName == "" ) return false;
- if( type.dataType.GetObjectType() != &type.dataType.GetObjectType()->engine->functionBehaviours ) return false;
- return true;
- }
- void SetLambda(asCScriptNode *funcDecl)
- {
- asASSERT( funcDecl && funcDecl->nodeType == snFunction );
- asASSERT( bc.GetLastInstr() == -1 );
-
- Clear();
- type.SetUndefinedFuncHandle(bc.GetEngine());
- exprNode = funcDecl;
- }
- bool IsLambda() const
- {
- if( type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction )
- return true;
-
- return false;
- }
- void SetVoidExpression()
- {
- Clear();
- type.SetVoid();
- isVoidExpression = true;
- }
- bool IsVoidExpression() const
- {
- if( isVoidExpression && type.IsVoid() && exprNode == 0 )
- return true;
-
- return false;
- }
- void Merge(asSExprContext *after)
- {
- type = after->type;
- property_get = after->property_get;
- property_set = after->property_set;
- property_const = after->property_const;
- property_handle = after->property_handle;
- property_ref = after->property_ref;
- property_arg = after->property_arg;
- exprNode = after->exprNode;
- methodName = after->methodName;
- enumValue = after->enumValue;
- isVoidExpression = after->isVoidExpression;
- isCleanArg = after->isCleanArg;
-
- after->property_arg = 0;
-
- // Do not copy the origExpr member
- }
+ asCExprContext(asCScriptEngine *engine);
+ ~asCExprContext();
+ void Clear();
+ bool IsClassMethod() const;
+ bool IsGlobalFunc() const;
+ void SetLambda(asCScriptNode *funcDecl);
+ bool IsLambda() const;
+ void SetVoidExpression();
+ bool IsVoidExpression() const;
+ void Merge(asCExprContext *after);
+ void SetAnonymousInitList(asCScriptNode *initList);
+ bool IsAnonymousInitList() const;
asCByteCode bc;
- asCTypeInfo type;
+ asCExprValue type;
int property_get;
int property_set;
bool property_const; // If the object that is being accessed through property accessor is read-only
@@ -174,19 +161,20 @@ struct asSExprContext
bool property_ref; // If the property accessor is called on a reference
bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls
bool isCleanArg; // Set to true if the expression has only been initialized with default constructor
- asSExprContext *property_arg;
+ asCExprContext *property_arg;
asCArray deferredParams;
asCScriptNode *exprNode;
- asSExprContext *origExpr;
+ asCExprContext *origExpr;
// TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value
asCString methodName;
asCString enumValue;
+ bool isAnonymousInitList; // Set to true if the expression is an init list for which the type has not yet been determined
};
struct asSOverloadCandidate
{
asSOverloadCandidate() : funcId(0), cost(0) {}
- asSOverloadCandidate(int _id, asUINT _cost ) : funcId(_id), cost(_cost) {}
+ asSOverloadCandidate(int _id, asUINT _cost) : funcId(_id), cost(_cost) {}
int funcId;
asUINT cost;
};
@@ -194,7 +182,7 @@ struct asSOverloadCandidate
struct asSNamedArgument
{
asCString name;
- asSExprContext *ctx;
+ asCExprContext *ctx;
asUINT match;
};
@@ -209,13 +197,15 @@ enum EConvCost
{
asCC_NO_CONV = 0,
asCC_CONST_CONV = 1,
- asCC_PRIMITIVE_SIZE_CONV = 2,
- asCC_SIGNED_CONV = 3,
- asCC_INT_FLOAT_CONV = 4,
- asCC_REF_CONV = 5,
- asCC_OBJ_TO_PRIMITIVE_CONV = 6,
- asCC_TO_OBJECT_CONV = 7,
- asCC_VARIABLE_CONV = 8
+ asCC_ENUM_SAME_SIZE_CONV = 2,
+ asCC_ENUM_DIFF_SIZE_CONV = 3,
+ asCC_PRIMITIVE_SIZE_CONV = 4,
+ asCC_SIGNED_CONV = 5,
+ asCC_INT_FLOAT_CONV = 6,
+ asCC_REF_CONV = 7,
+ asCC_OBJ_TO_PRIMITIVE_CONV = 8,
+ asCC_TO_OBJECT_CONV = 9,
+ asCC_VARIABLE_CONV = 10
};
class asCCompiler
@@ -250,93 +240,94 @@ protected:
void CompileExpressionStatement(asCScriptNode *node, asCByteCode *bc);
// Expressions
- int CompileAssignment(asCScriptNode *expr, asSExprContext *out);
- int CompileCondition(asCScriptNode *expr, asSExprContext *out);
- int CompileExpression(asCScriptNode *expr, asSExprContext *out);
- int CompilePostFixExpression(asCArray *postfix, asSExprContext *out);
- int CompileExpressionTerm(asCScriptNode *node, asSExprContext *out);
- int CompileExpressionPreOp(asCScriptNode *node, asSExprContext *out);
- int CompileExpressionPostOp(asCScriptNode *node, asSExprContext *out);
- int CompileExpressionValue(asCScriptNode *node, asSExprContext *out);
- int CompileFunctionCall(asCScriptNode *node, asSExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = "");
- int CompileConstructCall(asCScriptNode *node, asSExprContext *out);
- int CompileConversion(asCScriptNode *node, asSExprContext *out);
- int CompileOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
- void CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
- void CompileMathOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
- void CompileBitwiseOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
- void CompileComparisonOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
- void CompileBooleanOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
- bool CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken);
- int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *l, asSExprContext *r, asSExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false));
+ int CompileAssignment(asCScriptNode *expr, asCExprContext *out);
+ int CompileCondition(asCScriptNode *expr, asCExprContext *out);
+ int CompileExpression(asCScriptNode *expr, asCExprContext *out);
+ int CompilePostFixExpression(asCArray *postfix, asCExprContext *out);
+ int CompileExpressionTerm(asCScriptNode *node, asCExprContext *out);
+ int CompileExpressionPreOp(asCScriptNode *node, asCExprContext *out);
+ int CompileExpressionPostOp(asCScriptNode *node, asCExprContext *out);
+ int CompileExpressionValue(asCScriptNode *node, asCExprContext *out);
+ int CompileFunctionCall(asCScriptNode *node, asCExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = "");
+ int CompileConstructCall(asCScriptNode *node, asCExprContext *out);
+ int CompileConversion(asCScriptNode *node, asCExprContext *out);
+ int CompileOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken, bool leftToRight = true);
+ void CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
+ void CompileMathOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
+ void CompileBitwiseOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
+ void CompileComparisonOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
+ void CompileBooleanOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
+ bool CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken);
+ int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false));
- void CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem);
+ void CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem);
int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList);
+ int CompilerAnonymousInitList(asCScriptNode *listNode, asCExprContext *ctx, const asCDataType &dt);
int CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false);
- int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false);
+ int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false);
void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc);
- int CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs);
- int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *type, asCArray *namedArgs = 0);
- asUINT MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs = NULL, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = "");
- int CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, bool noFunction = false, bool noGlobal = false, asCObjectType *objType = 0);
+ int CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs);
+ int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *type, asCArray *namedArgs = 0);
+ asUINT MatchFunctions(asCArray