From f00d799aff752a593dcc4badbe41f3c708e428a4 Mon Sep 17 00:00:00 2001 From: Edgar Date: Mon, 24 Jan 2022 19:05:12 +0000 Subject: [PATCH 01/12] :boom: Devendored all deps --- CMakeLists.txt | 26 +- cmake/FindAngelscript.cmake | 60 + cmake/FindSocketW.cmake | 60 + contrib/rorserver-initscript | 171 + dependencies/angelscript/CMakeLists.txt | 27 - .../add_on/autowrapper/aswrappedcall.h | 581 - .../autowrapper/generator/generateheader.cpp | 166 - .../autowrapper/generator/generator.sln | 20 - .../autowrapper/generator/generator.vcproj | 236 - .../add_on/contextmgr/contextmgr.cpp | 376 - .../add_on/contextmgr/contextmgr.h | 92 - .../angelscript/add_on/debugger/debugger.cpp | 758 - .../angelscript/add_on/debugger/debugger.h | 77 - .../add_on/scriptfile/scriptfile.cpp | 661 - .../add_on/scriptfile/scriptfile.h | 101 - .../add_on/scriptgrid/scriptgrid.cpp | 786 - .../add_on/scriptgrid/scriptgrid.h | 82 - .../add_on/scripthandle/scripthandle.cpp | 355 - .../add_on/scripthandle/scripthandle.h | 62 - .../add_on/scripthelper/scripthelper.cpp | 918 - .../add_on/scripthelper/scripthelper.h | 48 - .../add_on/serializer/serializer.cpp | 528 - .../add_on/serializer/serializer.h | 193 - .../angelscript/add_on/weakref/weakref.cpp | 320 - .../angelscript/add_on/weakref/weakref.h | 56 - .../angelscript/include/angelscript.h | 1902 --- dependencies/angelscript/source.txt | 4 - dependencies/angelscript/source/as_array.h | 528 - dependencies/angelscript/source/as_atomic.cpp | 179 - dependencies/angelscript/source/as_atomic.h | 69 - .../angelscript/source/as_builder.cpp | 5232 ------ dependencies/angelscript/source/as_builder.h | 254 - .../angelscript/source/as_bytecode.cpp | 2844 ---- dependencies/angelscript/source/as_bytecode.h | 200 - .../angelscript/source/as_callfunc.cpp | 810 - dependencies/angelscript/source/as_callfunc.h | 142 - .../angelscript/source/as_callfunc_arm.cpp | 705 - .../angelscript/source/as_callfunc_arm_gcc.S | 698 - .../source/as_callfunc_arm_msvc.asm | 249 - .../source/as_callfunc_arm_xcode.S | 237 - .../angelscript/source/as_callfunc_mips.cpp | 440 - .../angelscript/source/as_callfunc_ppc.cpp | 672 - .../angelscript/source/as_callfunc_ppc_64.cpp | 765 - .../angelscript/source/as_callfunc_sh4.cpp | 391 - .../source/as_callfunc_x64_gcc.cpp | 479 - .../source/as_callfunc_x64_mingw.cpp | 353 - .../source/as_callfunc_x64_msvc.cpp | 237 - .../source/as_callfunc_x64_msvc_asm.asm | 208 - .../angelscript/source/as_callfunc_x86.cpp | 1376 -- .../angelscript/source/as_callfunc_xenon.cpp | 735 - .../angelscript/source/as_compiler.cpp | 13851 ---------------- dependencies/angelscript/source/as_compiler.h | 362 - dependencies/angelscript/source/as_config.h | 1174 -- .../angelscript/source/as_configgroup.cpp | 254 - .../angelscript/source/as_configgroup.h | 82 - .../angelscript/source/as_context.cpp | 5621 ------- dependencies/angelscript/source/as_context.h | 244 - .../angelscript/source/as_criticalsection.h | 187 - .../angelscript/source/as_datatype.cpp | 663 - dependencies/angelscript/source/as_datatype.h | 156 - dependencies/angelscript/source/as_debug.h | 271 - dependencies/angelscript/source/as_gc.cpp | 990 -- dependencies/angelscript/source/as_gc.h | 147 - .../angelscript/source/as_generic.cpp | 520 - dependencies/angelscript/source/as_generic.h | 107 - .../angelscript/source/as_globalproperty.cpp | 265 - dependencies/angelscript/source/as_map.h | 786 - dependencies/angelscript/source/as_memory.cpp | 268 - dependencies/angelscript/source/as_memory.h | 135 - dependencies/angelscript/source/as_module.cpp | 1431 -- dependencies/angelscript/source/as_module.h | 230 - .../angelscript/source/as_namespace.h | 77 - .../angelscript/source/as_objecttype.cpp | 1032 -- .../angelscript/source/as_objecttype.h | 232 - .../angelscript/source/as_outputbuffer.cpp | 109 - .../angelscript/source/as_outputbuffer.h | 80 - dependencies/angelscript/source/as_parser.cpp | 4130 ----- dependencies/angelscript/source/as_parser.h | 192 - dependencies/angelscript/source/as_property.h | 135 - .../angelscript/source/as_restore.cpp | 4906 ------ dependencies/angelscript/source/as_restore.h | 255 - .../angelscript/source/as_scriptcode.cpp | 151 - .../angelscript/source/as_scriptcode.h | 72 - .../angelscript/source/as_scriptengine.cpp | 6049 ------- .../angelscript/source/as_scriptengine.h | 490 - .../angelscript/source/as_scriptfunction.cpp | 1765 -- .../angelscript/source/as_scriptfunction.h | 330 - .../angelscript/source/as_scriptnode.cpp | 178 - .../angelscript/source/as_scriptnode.h | 136 - .../angelscript/source/as_scriptobject.cpp | 954 -- .../angelscript/source/as_scriptobject.h | 161 - dependencies/angelscript/source/as_string.cpp | 483 - dependencies/angelscript/source/as_string.h | 134 - .../angelscript/source/as_string_util.cpp | 371 - .../angelscript/source/as_string_util.h | 51 - .../angelscript/source/as_symboltable.h | 567 - dependencies/angelscript/source/as_texts.h | 332 - dependencies/angelscript/source/as_thread.cpp | 468 - dependencies/angelscript/source/as_thread.h | 108 - dependencies/angelscript/source/as_tokendef.h | 315 - .../angelscript/source/as_tokenizer.cpp | 468 - .../angelscript/source/as_tokenizer.h | 79 - .../angelscript/source/as_typeinfo.cpp | 175 - dependencies/angelscript/source/as_typeinfo.h | 95 - .../angelscript/source/as_variablescope.cpp | 142 - .../angelscript/source/as_variablescope.h | 87 - dependencies/jsoncpp/AUTHORS | 1 - dependencies/jsoncpp/CMakeLists.txt | 19 - dependencies/jsoncpp/LICENSE | 55 - dependencies/jsoncpp/NEWS.txt | 175 - dependencies/jsoncpp/README.md | 224 - dependencies/jsoncpp/SConstruct | 248 - dependencies/jsoncpp/amalgamate.py | 150 - dependencies/jsoncpp/dev.makefile | 14 - dependencies/jsoncpp/devtools/__init__.py | 1 - dependencies/jsoncpp/devtools/agent_vmw7.json | 33 - dependencies/jsoncpp/devtools/agent_vmxp.json | 26 - dependencies/jsoncpp/devtools/antglob.py | 202 - dependencies/jsoncpp/devtools/batchbuild.py | 281 - dependencies/jsoncpp/devtools/fixeol.py | 64 - .../jsoncpp/devtools/licenseupdater.py | 94 - dependencies/jsoncpp/devtools/tarball.py | 53 - dependencies/jsoncpp/doc/doxyfile.in | 2302 --- dependencies/jsoncpp/doc/footer.html | 3 - dependencies/jsoncpp/doc/header.html | 24 - dependencies/jsoncpp/doc/jsoncpp.dox | 119 - dependencies/jsoncpp/doc/readme.txt | 1 - dependencies/jsoncpp/doc/roadmap.dox | 3 - dependencies/jsoncpp/doxybuild.py | 169 - dependencies/jsoncpp/include/CMakeLists.txt | 2 - .../jsoncpp/include/json/assertions.h | 41 - dependencies/jsoncpp/include/json/autolink.h | 25 - dependencies/jsoncpp/include/json/config.h | 112 - dependencies/jsoncpp/include/json/features.h | 57 - dependencies/jsoncpp/include/json/forwards.h | 43 - dependencies/jsoncpp/include/json/json.h | 15 - dependencies/jsoncpp/include/json/reader.h | 276 - dependencies/jsoncpp/include/json/value.h | 1088 -- dependencies/jsoncpp/include/json/writer.h | 213 - .../jsoncpp/makefiles/msvc2010/jsoncpp.sln | 42 - .../makefiles/msvc2010/jsontest.vcxproj | 96 - .../msvc2010/jsontest.vcxproj.filters | 13 - .../makefiles/msvc2010/lib_json.vcxproj | 143 - .../msvc2010/lib_json.vcxproj.filters | 33 - .../makefiles/msvc2010/test_lib_json.vcxproj | 109 - .../msvc2010/test_lib_json.vcxproj.filters | 24 - .../jsoncpp/makefiles/vs71/jsoncpp.sln | 46 - .../jsoncpp/makefiles/vs71/jsontest.vcproj | 119 - .../jsoncpp/makefiles/vs71/lib_json.vcproj | 214 - .../makefiles/vs71/test_lib_json.vcproj | 130 - dependencies/jsoncpp/makerelease.py | 384 - dependencies/jsoncpp/pkg-config/jsoncpp.pc.in | 11 - dependencies/jsoncpp/scons-tools/globtool.py | 53 - dependencies/jsoncpp/scons-tools/srcdist.py | 179 - .../jsoncpp/scons-tools/substinfile.py | 80 - dependencies/jsoncpp/scons-tools/targz.py | 82 - dependencies/jsoncpp/src/CMakeLists.txt | 5 - .../jsoncpp/src/jsontestrunner/CMakeLists.txt | 22 - .../jsoncpp/src/jsontestrunner/main.cpp | 277 - .../jsoncpp/src/jsontestrunner/sconscript | 9 - .../jsoncpp/src/lib_json/CMakeLists.txt | 57 - .../src/lib_json/json_batchallocator.h | 121 - .../src/lib_json/json_internalarray.inl | 360 - .../jsoncpp/src/lib_json/json_internalmap.inl | 473 - .../jsoncpp/src/lib_json/json_reader.cpp | 885 - dependencies/jsoncpp/src/lib_json/json_tool.h | 87 - .../jsoncpp/src/lib_json/json_value.cpp | 1478 -- .../src/lib_json/json_valueiterator.inl | 241 - .../jsoncpp/src/lib_json/json_writer.cpp | 690 - dependencies/jsoncpp/src/lib_json/sconscript | 8 - .../jsoncpp/src/lib_json/version.h.in | 14 - .../jsoncpp/src/test_lib_json/CMakeLists.txt | 22 - .../jsoncpp/src/test_lib_json/jsontest.cpp | 443 - .../jsoncpp/src/test_lib_json/jsontest.h | 280 - .../jsoncpp/src/test_lib_json/main.cpp | 1637 -- .../jsoncpp/src/test_lib_json/sconscript | 10 - dependencies/jsoncpp/test/cleantests.py | 10 - .../jsoncpp/test/data/fail_test_array_01.json | 1 - .../jsoncpp/test/data/test_array_01.expected | 1 - .../jsoncpp/test/data/test_array_01.json | 1 - .../jsoncpp/test/data/test_array_02.expected | 2 - .../jsoncpp/test/data/test_array_02.json | 1 - .../jsoncpp/test/data/test_array_03.expected | 6 - .../jsoncpp/test/data/test_array_03.json | 1 - .../jsoncpp/test/data/test_array_04.expected | 5 - .../jsoncpp/test/data/test_array_04.json | 1 - .../jsoncpp/test/data/test_array_05.expected | 100 - .../jsoncpp/test/data/test_array_05.json | 1 - .../jsoncpp/test/data/test_array_06.expected | 5 - .../jsoncpp/test/data/test_array_06.json | 4 - .../jsoncpp/test/data/test_array_07.expected | 2122 --- .../jsoncpp/test/data/test_array_07.json | 2 - .../jsoncpp/test/data/test_basic_01.expected | 1 - .../jsoncpp/test/data/test_basic_01.json | 1 - .../jsoncpp/test/data/test_basic_02.expected | 1 - .../jsoncpp/test/data/test_basic_02.json | 1 - .../jsoncpp/test/data/test_basic_03.expected | 3 - .../jsoncpp/test/data/test_basic_03.json | 3 - .../jsoncpp/test/data/test_basic_04.expected | 2 - .../jsoncpp/test/data/test_basic_04.json | 2 - .../jsoncpp/test/data/test_basic_05.expected | 2 - .../jsoncpp/test/data/test_basic_05.json | 2 - .../jsoncpp/test/data/test_basic_06.expected | 2 - .../jsoncpp/test/data/test_basic_06.json | 2 - .../jsoncpp/test/data/test_basic_07.expected | 2 - .../jsoncpp/test/data/test_basic_07.json | 2 - .../jsoncpp/test/data/test_basic_08.expected | 3 - .../jsoncpp/test/data/test_basic_08.json | 3 - .../jsoncpp/test/data/test_basic_09.expected | 4 - .../jsoncpp/test/data/test_basic_09.json | 4 - .../test/data/test_comment_01.expected | 8 - .../jsoncpp/test/data/test_comment_01.json | 8 - .../test/data/test_comment_02.expected | 14 - .../jsoncpp/test/data/test_comment_02.json | 17 - .../test/data/test_complex_01.expected | 20 - .../jsoncpp/test/data/test_complex_01.json | 17 - .../test/data/test_integer_01.expected | 2 - .../jsoncpp/test/data/test_integer_01.json | 2 - .../test/data/test_integer_02.expected | 2 - .../jsoncpp/test/data/test_integer_02.json | 2 - .../test/data/test_integer_03.expected | 2 - .../jsoncpp/test/data/test_integer_03.json | 2 - .../test/data/test_integer_04.expected | 3 - .../jsoncpp/test/data/test_integer_04.json | 3 - .../test/data/test_integer_05.expected | 2 - .../jsoncpp/test/data/test_integer_05.json | 2 - .../test/data/test_integer_06_64bits.expected | 1 - .../test/data/test_integer_06_64bits.json | 2 - .../test/data/test_integer_07_64bits.expected | 1 - .../test/data/test_integer_07_64bits.json | 2 - .../test/data/test_integer_08_64bits.expected | 1 - .../test/data/test_integer_08_64bits.json | 2 - .../jsoncpp/test/data/test_large_01.expected | 2122 --- .../jsoncpp/test/data/test_large_01.json | 2 - .../jsoncpp/test/data/test_object_01.expected | 1 - .../jsoncpp/test/data/test_object_01.json | 1 - .../jsoncpp/test/data/test_object_02.expected | 2 - .../jsoncpp/test/data/test_object_02.json | 1 - .../jsoncpp/test/data/test_object_03.expected | 4 - .../jsoncpp/test/data/test_object_03.json | 5 - .../jsoncpp/test/data/test_object_04.expected | 2 - .../jsoncpp/test/data/test_object_04.json | 3 - .../data/test_preserve_comment_01.expected | 11 - .../test/data/test_preserve_comment_01.json | 14 - .../jsoncpp/test/data/test_real_01.expected | 3 - .../jsoncpp/test/data/test_real_01.json | 3 - .../jsoncpp/test/data/test_real_02.expected | 3 - .../jsoncpp/test/data/test_real_02.json | 3 - .../jsoncpp/test/data/test_real_03.expected | 3 - .../jsoncpp/test/data/test_real_03.json | 3 - .../jsoncpp/test/data/test_real_04.expected | 3 - .../jsoncpp/test/data/test_real_04.json | 3 - .../jsoncpp/test/data/test_real_05.expected | 4 - .../jsoncpp/test/data/test_real_05.json | 3 - .../jsoncpp/test/data/test_real_06.expected | 4 - .../jsoncpp/test/data/test_real_06.json | 3 - .../jsoncpp/test/data/test_real_07.expected | 4 - .../jsoncpp/test/data/test_real_07.json | 3 - .../jsoncpp/test/data/test_real_08.expected | 4 - .../jsoncpp/test/data/test_real_08.json | 4 - .../jsoncpp/test/data/test_real_09.expected | 4 - .../jsoncpp/test/data/test_real_09.json | 4 - .../jsoncpp/test/data/test_real_10.expected | 4 - .../jsoncpp/test/data/test_real_10.json | 4 - .../jsoncpp/test/data/test_real_11.expected | 4 - .../jsoncpp/test/data/test_real_11.json | 4 - .../jsoncpp/test/data/test_real_12.expected | 2 - .../jsoncpp/test/data/test_real_12.json | 2 - .../jsoncpp/test/data/test_string_01.expected | 1 - .../jsoncpp/test/data/test_string_01.json | 1 - .../jsoncpp/test/data/test_string_02.expected | 1 - .../jsoncpp/test/data/test_string_02.json | 1 - .../jsoncpp/test/data/test_string_03.expected | 1 - .../jsoncpp/test/data/test_string_03.json | 1 - .../jsoncpp/test/data/test_string_04.expected | 2 - .../jsoncpp/test/data/test_string_04.json | 2 - .../jsoncpp/test/data/test_string_05.expected | 2 - .../jsoncpp/test/data/test_string_05.json | 2 - .../test/data/test_string_unicode_01.expected | 1 - .../test/data/test_string_unicode_01.json | 1 - .../test/data/test_string_unicode_02.expected | 1 - .../test/data/test_string_unicode_02.json | 1 - .../test/data/test_string_unicode_03.expected | 1 - .../test/data/test_string_unicode_03.json | 1 - .../test/data/test_string_unicode_04.expected | 1 - .../test/data/test_string_unicode_04.json | 1 - .../test/data/test_string_unicode_05.expected | 2 - .../test/data/test_string_unicode_05.json | 1 - .../jsoncpp/test/generate_expected.py | 12 - .../jsoncpp/test/jsonchecker/fail1.json | 1 - .../jsoncpp/test/jsonchecker/fail10.json | 1 - .../jsoncpp/test/jsonchecker/fail11.json | 1 - .../jsoncpp/test/jsonchecker/fail12.json | 1 - .../jsoncpp/test/jsonchecker/fail13.json | 1 - .../jsoncpp/test/jsonchecker/fail14.json | 1 - .../jsoncpp/test/jsonchecker/fail15.json | 1 - .../jsoncpp/test/jsonchecker/fail16.json | 1 - .../jsoncpp/test/jsonchecker/fail17.json | 1 - .../jsoncpp/test/jsonchecker/fail18.json | 1 - .../jsoncpp/test/jsonchecker/fail19.json | 1 - .../jsoncpp/test/jsonchecker/fail2.json | 1 - .../jsoncpp/test/jsonchecker/fail20.json | 1 - .../jsoncpp/test/jsonchecker/fail21.json | 1 - .../jsoncpp/test/jsonchecker/fail22.json | 1 - .../jsoncpp/test/jsonchecker/fail23.json | 1 - .../jsoncpp/test/jsonchecker/fail24.json | 1 - .../jsoncpp/test/jsonchecker/fail25.json | 1 - .../jsoncpp/test/jsonchecker/fail26.json | 1 - .../jsoncpp/test/jsonchecker/fail27.json | 2 - .../jsoncpp/test/jsonchecker/fail28.json | 2 - .../jsoncpp/test/jsonchecker/fail29.json | 1 - .../jsoncpp/test/jsonchecker/fail3.json | 1 - .../jsoncpp/test/jsonchecker/fail30.json | 1 - .../jsoncpp/test/jsonchecker/fail31.json | 1 - .../jsoncpp/test/jsonchecker/fail32.json | 1 - .../jsoncpp/test/jsonchecker/fail33.json | 1 - .../jsoncpp/test/jsonchecker/fail4.json | 1 - .../jsoncpp/test/jsonchecker/fail5.json | 1 - .../jsoncpp/test/jsonchecker/fail6.json | 1 - .../jsoncpp/test/jsonchecker/fail7.json | 1 - .../jsoncpp/test/jsonchecker/fail8.json | 1 - .../jsoncpp/test/jsonchecker/fail9.json | 1 - .../jsoncpp/test/jsonchecker/pass1.json | 58 - .../jsoncpp/test/jsonchecker/pass2.json | 1 - .../jsoncpp/test/jsonchecker/pass3.json | 6 - .../jsoncpp/test/jsonchecker/readme.txt | 3 - dependencies/jsoncpp/test/pyjsontestrunner.py | 64 - dependencies/jsoncpp/test/runjsontests.py | 135 - dependencies/jsoncpp/test/rununittests.py | 74 - dependencies/jsoncpp/version | 1 - dependencies/socketw/CMakeLists.txt | 30 - dependencies/socketw/SocketW.h | 23 - dependencies/socketw/sw_base.cxx | 744 - dependencies/socketw/sw_base.h | 198 - dependencies/socketw/sw_config.h | 1 - dependencies/socketw/sw_inet.cxx | 249 - dependencies/socketw/sw_inet.h | 48 - dependencies/socketw/sw_internal.h | 83 - dependencies/socketw/sw_unix.cxx | 99 - dependencies/socketw/sw_unix.h | 41 - source/angelscript_add_on/CMakeLists.txt | 14 + .../scriptany/scriptany.cpp | 105 +- .../angelscript_add_on}/scriptany/scriptany.h | 0 .../scriptarray/scriptarray.cpp | 670 +- .../scriptarray/scriptarray.h | 50 +- .../scriptbuilder/scriptbuilder.cpp | 546 +- .../scriptbuilder/scriptbuilder.h | 98 +- .../scriptdictionary/scriptdictionary.cpp | 2356 +-- .../scriptdictionary/scriptdictionary.h | 85 +- .../scriptmath/scriptmath.cpp | 2 +- .../scriptmath/scriptmath.h | 0 .../scriptmath/scriptmathcomplex.cpp | 13 +- .../scriptmath/scriptmathcomplex.h | 0 .../scriptmath3d/scriptmath3d.cpp | 0 .../scriptmath3d/scriptmath3d.h | 0 .../scriptstdstring/scriptstdstring.cpp | 867 +- .../scriptstdstring/scriptstdstring.h | 17 +- .../scriptstdstring/scriptstdstring_utils.cpp | 9 +- source/server/CMakeLists.txt | 18 +- source/server/ScriptEngine.cpp | 4 +- 360 files changed, 3321 insertions(+), 102662 deletions(-) create mode 100644 cmake/FindAngelscript.cmake create mode 100644 cmake/FindSocketW.cmake create mode 100755 contrib/rorserver-initscript delete mode 100644 dependencies/angelscript/CMakeLists.txt delete mode 100644 dependencies/angelscript/add_on/autowrapper/aswrappedcall.h delete mode 100644 dependencies/angelscript/add_on/autowrapper/generator/generateheader.cpp delete mode 100644 dependencies/angelscript/add_on/autowrapper/generator/generator.sln delete mode 100644 dependencies/angelscript/add_on/autowrapper/generator/generator.vcproj delete mode 100644 dependencies/angelscript/add_on/contextmgr/contextmgr.cpp delete mode 100644 dependencies/angelscript/add_on/contextmgr/contextmgr.h delete mode 100644 dependencies/angelscript/add_on/debugger/debugger.cpp delete mode 100644 dependencies/angelscript/add_on/debugger/debugger.h delete mode 100644 dependencies/angelscript/add_on/scriptfile/scriptfile.cpp delete mode 100644 dependencies/angelscript/add_on/scriptfile/scriptfile.h delete mode 100644 dependencies/angelscript/add_on/scriptgrid/scriptgrid.cpp delete mode 100644 dependencies/angelscript/add_on/scriptgrid/scriptgrid.h delete mode 100644 dependencies/angelscript/add_on/scripthandle/scripthandle.cpp delete mode 100644 dependencies/angelscript/add_on/scripthandle/scripthandle.h delete mode 100644 dependencies/angelscript/add_on/scripthelper/scripthelper.cpp delete mode 100644 dependencies/angelscript/add_on/scripthelper/scripthelper.h delete mode 100644 dependencies/angelscript/add_on/serializer/serializer.cpp delete mode 100644 dependencies/angelscript/add_on/serializer/serializer.h delete mode 100644 dependencies/angelscript/add_on/weakref/weakref.cpp delete mode 100644 dependencies/angelscript/add_on/weakref/weakref.h delete mode 100644 dependencies/angelscript/include/angelscript.h delete mode 100644 dependencies/angelscript/source.txt delete mode 100644 dependencies/angelscript/source/as_array.h delete mode 100644 dependencies/angelscript/source/as_atomic.cpp delete mode 100644 dependencies/angelscript/source/as_atomic.h delete mode 100644 dependencies/angelscript/source/as_builder.cpp delete mode 100644 dependencies/angelscript/source/as_builder.h delete mode 100644 dependencies/angelscript/source/as_bytecode.cpp delete mode 100644 dependencies/angelscript/source/as_bytecode.h delete mode 100644 dependencies/angelscript/source/as_callfunc.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc.h delete mode 100644 dependencies/angelscript/source/as_callfunc_arm.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_arm_gcc.S delete mode 100644 dependencies/angelscript/source/as_callfunc_arm_msvc.asm delete mode 100644 dependencies/angelscript/source/as_callfunc_arm_xcode.S delete mode 100644 dependencies/angelscript/source/as_callfunc_mips.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_ppc.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_ppc_64.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_sh4.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_x64_gcc.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_x64_mingw.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_x64_msvc.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_x64_msvc_asm.asm delete mode 100644 dependencies/angelscript/source/as_callfunc_x86.cpp delete mode 100644 dependencies/angelscript/source/as_callfunc_xenon.cpp delete mode 100644 dependencies/angelscript/source/as_compiler.cpp delete mode 100644 dependencies/angelscript/source/as_compiler.h delete mode 100644 dependencies/angelscript/source/as_config.h delete mode 100644 dependencies/angelscript/source/as_configgroup.cpp delete mode 100644 dependencies/angelscript/source/as_configgroup.h delete mode 100644 dependencies/angelscript/source/as_context.cpp delete mode 100644 dependencies/angelscript/source/as_context.h delete mode 100644 dependencies/angelscript/source/as_criticalsection.h delete mode 100644 dependencies/angelscript/source/as_datatype.cpp delete mode 100644 dependencies/angelscript/source/as_datatype.h delete mode 100644 dependencies/angelscript/source/as_debug.h delete mode 100644 dependencies/angelscript/source/as_gc.cpp delete mode 100644 dependencies/angelscript/source/as_gc.h delete mode 100644 dependencies/angelscript/source/as_generic.cpp delete mode 100644 dependencies/angelscript/source/as_generic.h delete mode 100644 dependencies/angelscript/source/as_globalproperty.cpp delete mode 100644 dependencies/angelscript/source/as_map.h delete mode 100644 dependencies/angelscript/source/as_memory.cpp delete mode 100644 dependencies/angelscript/source/as_memory.h delete mode 100644 dependencies/angelscript/source/as_module.cpp delete mode 100644 dependencies/angelscript/source/as_module.h delete mode 100644 dependencies/angelscript/source/as_namespace.h delete mode 100644 dependencies/angelscript/source/as_objecttype.cpp delete mode 100644 dependencies/angelscript/source/as_objecttype.h delete mode 100644 dependencies/angelscript/source/as_outputbuffer.cpp delete mode 100644 dependencies/angelscript/source/as_outputbuffer.h delete mode 100644 dependencies/angelscript/source/as_parser.cpp delete mode 100644 dependencies/angelscript/source/as_parser.h delete mode 100644 dependencies/angelscript/source/as_property.h delete mode 100644 dependencies/angelscript/source/as_restore.cpp delete mode 100644 dependencies/angelscript/source/as_restore.h delete mode 100644 dependencies/angelscript/source/as_scriptcode.cpp delete mode 100644 dependencies/angelscript/source/as_scriptcode.h delete mode 100644 dependencies/angelscript/source/as_scriptengine.cpp delete mode 100644 dependencies/angelscript/source/as_scriptengine.h delete mode 100644 dependencies/angelscript/source/as_scriptfunction.cpp delete mode 100644 dependencies/angelscript/source/as_scriptfunction.h delete mode 100644 dependencies/angelscript/source/as_scriptnode.cpp delete mode 100644 dependencies/angelscript/source/as_scriptnode.h delete mode 100644 dependencies/angelscript/source/as_scriptobject.cpp delete mode 100644 dependencies/angelscript/source/as_scriptobject.h delete mode 100644 dependencies/angelscript/source/as_string.cpp delete mode 100644 dependencies/angelscript/source/as_string.h delete mode 100644 dependencies/angelscript/source/as_string_util.cpp delete mode 100644 dependencies/angelscript/source/as_string_util.h delete mode 100644 dependencies/angelscript/source/as_symboltable.h delete mode 100644 dependencies/angelscript/source/as_texts.h delete mode 100644 dependencies/angelscript/source/as_thread.cpp delete mode 100644 dependencies/angelscript/source/as_thread.h delete mode 100644 dependencies/angelscript/source/as_tokendef.h delete mode 100644 dependencies/angelscript/source/as_tokenizer.cpp delete mode 100644 dependencies/angelscript/source/as_tokenizer.h delete mode 100644 dependencies/angelscript/source/as_typeinfo.cpp delete mode 100644 dependencies/angelscript/source/as_typeinfo.h delete mode 100644 dependencies/angelscript/source/as_variablescope.cpp delete mode 100644 dependencies/angelscript/source/as_variablescope.h delete mode 100644 dependencies/jsoncpp/AUTHORS delete mode 100644 dependencies/jsoncpp/CMakeLists.txt delete mode 100644 dependencies/jsoncpp/LICENSE delete mode 100644 dependencies/jsoncpp/NEWS.txt delete mode 100644 dependencies/jsoncpp/README.md delete mode 100644 dependencies/jsoncpp/SConstruct delete mode 100644 dependencies/jsoncpp/amalgamate.py delete mode 100644 dependencies/jsoncpp/dev.makefile delete mode 100644 dependencies/jsoncpp/devtools/__init__.py delete mode 100644 dependencies/jsoncpp/devtools/agent_vmw7.json delete mode 100644 dependencies/jsoncpp/devtools/agent_vmxp.json delete mode 100644 dependencies/jsoncpp/devtools/antglob.py delete mode 100644 dependencies/jsoncpp/devtools/batchbuild.py delete mode 100644 dependencies/jsoncpp/devtools/fixeol.py delete mode 100644 dependencies/jsoncpp/devtools/licenseupdater.py delete mode 100644 dependencies/jsoncpp/devtools/tarball.py delete mode 100644 dependencies/jsoncpp/doc/doxyfile.in delete mode 100644 dependencies/jsoncpp/doc/footer.html delete mode 100644 dependencies/jsoncpp/doc/header.html delete mode 100644 dependencies/jsoncpp/doc/jsoncpp.dox delete mode 100644 dependencies/jsoncpp/doc/readme.txt delete mode 100644 dependencies/jsoncpp/doc/roadmap.dox delete mode 100644 dependencies/jsoncpp/doxybuild.py delete mode 100644 dependencies/jsoncpp/include/CMakeLists.txt delete mode 100644 dependencies/jsoncpp/include/json/assertions.h delete mode 100644 dependencies/jsoncpp/include/json/autolink.h delete mode 100644 dependencies/jsoncpp/include/json/config.h delete mode 100644 dependencies/jsoncpp/include/json/features.h delete mode 100644 dependencies/jsoncpp/include/json/forwards.h delete mode 100644 dependencies/jsoncpp/include/json/json.h delete mode 100644 dependencies/jsoncpp/include/json/reader.h delete mode 100644 dependencies/jsoncpp/include/json/value.h delete mode 100644 dependencies/jsoncpp/include/json/writer.h delete mode 100644 dependencies/jsoncpp/makefiles/msvc2010/jsoncpp.sln delete mode 100644 dependencies/jsoncpp/makefiles/msvc2010/jsontest.vcxproj delete mode 100644 dependencies/jsoncpp/makefiles/msvc2010/jsontest.vcxproj.filters delete mode 100644 dependencies/jsoncpp/makefiles/msvc2010/lib_json.vcxproj delete mode 100644 dependencies/jsoncpp/makefiles/msvc2010/lib_json.vcxproj.filters delete mode 100644 dependencies/jsoncpp/makefiles/msvc2010/test_lib_json.vcxproj delete mode 100644 dependencies/jsoncpp/makefiles/msvc2010/test_lib_json.vcxproj.filters delete mode 100644 dependencies/jsoncpp/makefiles/vs71/jsoncpp.sln delete mode 100644 dependencies/jsoncpp/makefiles/vs71/jsontest.vcproj delete mode 100644 dependencies/jsoncpp/makefiles/vs71/lib_json.vcproj delete mode 100644 dependencies/jsoncpp/makefiles/vs71/test_lib_json.vcproj delete mode 100644 dependencies/jsoncpp/makerelease.py delete mode 100644 dependencies/jsoncpp/pkg-config/jsoncpp.pc.in delete mode 100644 dependencies/jsoncpp/scons-tools/globtool.py delete mode 100644 dependencies/jsoncpp/scons-tools/srcdist.py delete mode 100644 dependencies/jsoncpp/scons-tools/substinfile.py delete mode 100644 dependencies/jsoncpp/scons-tools/targz.py delete mode 100644 dependencies/jsoncpp/src/CMakeLists.txt delete mode 100644 dependencies/jsoncpp/src/jsontestrunner/CMakeLists.txt delete mode 100644 dependencies/jsoncpp/src/jsontestrunner/main.cpp delete mode 100644 dependencies/jsoncpp/src/jsontestrunner/sconscript delete mode 100644 dependencies/jsoncpp/src/lib_json/CMakeLists.txt delete mode 100644 dependencies/jsoncpp/src/lib_json/json_batchallocator.h delete mode 100644 dependencies/jsoncpp/src/lib_json/json_internalarray.inl delete mode 100644 dependencies/jsoncpp/src/lib_json/json_internalmap.inl delete mode 100644 dependencies/jsoncpp/src/lib_json/json_reader.cpp delete mode 100644 dependencies/jsoncpp/src/lib_json/json_tool.h delete mode 100644 dependencies/jsoncpp/src/lib_json/json_value.cpp delete mode 100644 dependencies/jsoncpp/src/lib_json/json_valueiterator.inl delete mode 100644 dependencies/jsoncpp/src/lib_json/json_writer.cpp delete mode 100644 dependencies/jsoncpp/src/lib_json/sconscript delete mode 100644 dependencies/jsoncpp/src/lib_json/version.h.in delete mode 100644 dependencies/jsoncpp/src/test_lib_json/CMakeLists.txt delete mode 100644 dependencies/jsoncpp/src/test_lib_json/jsontest.cpp delete mode 100644 dependencies/jsoncpp/src/test_lib_json/jsontest.h delete mode 100644 dependencies/jsoncpp/src/test_lib_json/main.cpp delete mode 100644 dependencies/jsoncpp/src/test_lib_json/sconscript delete mode 100644 dependencies/jsoncpp/test/cleantests.py delete mode 100644 dependencies/jsoncpp/test/data/fail_test_array_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_array_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_array_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_array_02.expected delete mode 100644 dependencies/jsoncpp/test/data/test_array_02.json delete mode 100644 dependencies/jsoncpp/test/data/test_array_03.expected delete mode 100644 dependencies/jsoncpp/test/data/test_array_03.json delete mode 100644 dependencies/jsoncpp/test/data/test_array_04.expected delete mode 100644 dependencies/jsoncpp/test/data/test_array_04.json delete mode 100644 dependencies/jsoncpp/test/data/test_array_05.expected delete mode 100644 dependencies/jsoncpp/test/data/test_array_05.json delete mode 100644 dependencies/jsoncpp/test/data/test_array_06.expected delete mode 100644 dependencies/jsoncpp/test/data/test_array_06.json delete mode 100644 dependencies/jsoncpp/test/data/test_array_07.expected delete mode 100644 dependencies/jsoncpp/test/data/test_array_07.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_02.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_02.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_03.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_03.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_04.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_04.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_05.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_05.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_06.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_06.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_07.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_07.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_08.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_08.json delete mode 100644 dependencies/jsoncpp/test/data/test_basic_09.expected delete mode 100644 dependencies/jsoncpp/test/data/test_basic_09.json delete mode 100644 dependencies/jsoncpp/test/data/test_comment_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_comment_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_comment_02.expected delete mode 100644 dependencies/jsoncpp/test/data/test_comment_02.json delete mode 100644 dependencies/jsoncpp/test/data/test_complex_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_complex_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_integer_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_integer_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_integer_02.expected delete mode 100644 dependencies/jsoncpp/test/data/test_integer_02.json delete mode 100644 dependencies/jsoncpp/test/data/test_integer_03.expected delete mode 100644 dependencies/jsoncpp/test/data/test_integer_03.json delete mode 100644 dependencies/jsoncpp/test/data/test_integer_04.expected delete mode 100644 dependencies/jsoncpp/test/data/test_integer_04.json delete mode 100644 dependencies/jsoncpp/test/data/test_integer_05.expected delete mode 100644 dependencies/jsoncpp/test/data/test_integer_05.json delete mode 100644 dependencies/jsoncpp/test/data/test_integer_06_64bits.expected delete mode 100644 dependencies/jsoncpp/test/data/test_integer_06_64bits.json delete mode 100644 dependencies/jsoncpp/test/data/test_integer_07_64bits.expected delete mode 100644 dependencies/jsoncpp/test/data/test_integer_07_64bits.json delete mode 100644 dependencies/jsoncpp/test/data/test_integer_08_64bits.expected delete mode 100644 dependencies/jsoncpp/test/data/test_integer_08_64bits.json delete mode 100644 dependencies/jsoncpp/test/data/test_large_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_large_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_object_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_object_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_object_02.expected delete mode 100644 dependencies/jsoncpp/test/data/test_object_02.json delete mode 100644 dependencies/jsoncpp/test/data/test_object_03.expected delete mode 100644 dependencies/jsoncpp/test/data/test_object_03.json delete mode 100644 dependencies/jsoncpp/test/data/test_object_04.expected delete mode 100644 dependencies/jsoncpp/test/data/test_object_04.json delete mode 100644 dependencies/jsoncpp/test/data/test_preserve_comment_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_preserve_comment_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_02.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_02.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_03.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_03.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_04.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_04.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_05.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_05.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_06.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_06.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_07.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_07.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_08.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_08.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_09.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_09.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_10.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_10.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_11.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_11.json delete mode 100644 dependencies/jsoncpp/test/data/test_real_12.expected delete mode 100644 dependencies/jsoncpp/test/data/test_real_12.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_02.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_02.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_03.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_03.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_04.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_04.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_05.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_05.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_01.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_01.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_02.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_02.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_03.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_03.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_04.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_04.json delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_05.expected delete mode 100644 dependencies/jsoncpp/test/data/test_string_unicode_05.json delete mode 100644 dependencies/jsoncpp/test/generate_expected.py delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail1.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail10.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail11.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail12.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail13.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail14.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail15.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail16.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail17.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail18.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail19.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail2.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail20.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail21.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail22.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail23.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail24.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail25.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail26.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail27.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail28.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail29.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail3.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail30.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail31.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail32.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail33.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail4.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail5.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail6.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail7.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail8.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/fail9.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/pass1.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/pass2.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/pass3.json delete mode 100644 dependencies/jsoncpp/test/jsonchecker/readme.txt delete mode 100644 dependencies/jsoncpp/test/pyjsontestrunner.py delete mode 100644 dependencies/jsoncpp/test/runjsontests.py delete mode 100644 dependencies/jsoncpp/test/rununittests.py delete mode 100644 dependencies/jsoncpp/version delete mode 100644 dependencies/socketw/CMakeLists.txt delete mode 100644 dependencies/socketw/SocketW.h delete mode 100644 dependencies/socketw/sw_base.cxx delete mode 100644 dependencies/socketw/sw_base.h delete mode 100644 dependencies/socketw/sw_config.h delete mode 100644 dependencies/socketw/sw_inet.cxx delete mode 100644 dependencies/socketw/sw_inet.h delete mode 100644 dependencies/socketw/sw_internal.h delete mode 100644 dependencies/socketw/sw_unix.cxx delete mode 100644 dependencies/socketw/sw_unix.h create mode 100644 source/angelscript_add_on/CMakeLists.txt rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptany/scriptany.cpp (73%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptany/scriptany.h (100%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptarray/scriptarray.cpp (68%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptarray/scriptarray.h (68%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptbuilder/scriptbuilder.cpp (55%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptbuilder/scriptbuilder.h (51%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptdictionary/scriptdictionary.cpp (66%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptdictionary/scriptdictionary.h (67%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptmath/scriptmath.cpp (97%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptmath/scriptmath.h (100%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptmath/scriptmathcomplex.cpp (90%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptmath/scriptmathcomplex.h (100%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptmath3d/scriptmath3d.cpp (100%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptmath3d/scriptmath3d.h (100%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptstdstring/scriptstdstring.cpp (53%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptstdstring/scriptstdstring.h (79%) rename {dependencies/angelscript/add_on => source/angelscript_add_on}/scriptstdstring/scriptstdstring_utils.cpp (91%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4cb48f9..18a4d476 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,25 @@ # ensure cmake features we need CMAKE_MINIMUM_REQUIRED(VERSION 3.1) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) + +include(CMakeDependentOption) +include(FeatureSummary) project(rorserver VERSION "2021.10") +find_package(Angelscript) +find_package(jsoncpp REQUIRED) +find_package(SocketW REQUIRED) + # setup paths -SET(RUNTIME_OUTPUT_DIRECTORY "${rorserver_SOURCE_DIR}/bin/") -SET(LIBRARY_OUTPUT_DIRECTORY "${rorserver_SOURCE_DIR}/lib/") -SET(ARCHIVE_OUTPUT_DIRECTORY "${rorserver_SOURCE_DIR}/lib/") +SET(RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/") +SET(LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/") +SET(ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/") SET(EXECUTABLE_OUTPUT_PATH ${RUNTIME_OUTPUT_DIRECTORY}) SET(LIBRARY_OUTPUT_PATH ${RUNTIME_OUTPUT_DIRECTORY}) #options -option(RORSERVER_WITH_ANGELSCRIPT "adds scripting support" FALSE) +cmake_dependent_option(RORSERVER_WITH_ANGELSCRIPT "adds scripting support" ON "AngelScript_FOUND" OFF) # hide some settings mark_as_advanced( @@ -57,7 +65,7 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${RUNTIME_OUTPUT_DIRECTORY}) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${RUNTIME_OUTPUT_DIRECTORY}) -if (NOT WIN32) +if (UNIX) add_definitions(-Wall) option(RORSERVER_CRASHHANDLER "enables linux startup script crashhandling" FALSE) @@ -69,12 +77,8 @@ if (NOT WIN32) mark_as_advanced(GDB_EXECUTABLE) endif () - -add_subdirectory("dependencies/socketw") -add_subdirectory("dependencies/jsoncpp") +add_subdirectory("source/angelscript_add_on") add_subdirectory("source/server") -if (RORSERVER_WITH_ANGELSCRIPT) - add_subdirectory("dependencies/angelscript") -endif (RORSERVER_WITH_ANGELSCRIPT) +feature_summary(WHAT ALL) \ No newline at end of file diff --git a/cmake/FindAngelscript.cmake b/cmake/FindAngelscript.cmake new file mode 100644 index 00000000..ac39f5d4 --- /dev/null +++ b/cmake/FindAngelscript.cmake @@ -0,0 +1,60 @@ +# The MIT License (MIT) +# +# Copyright (c) 2015 Fabian Killus +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Find AngelScript +# ---------------- +# +# Find AngelScript include directories and libraries. +# This module will set the following variables: +# +# * AngelScript_FOUND - True if AngelScript is found +# * AngelScript_INCLUDE_DIR - The include directory +# * AngelScript_LIBRARY - The libraries to link against +# +# In addition the following imported targets are defined: +# +# * Angelscript::angelscript +# * AngelScript::use_namespace +# + +find_path(AngelScript_INCLUDE_DIR angelscript.h) +find_library(AngelScript_LIBRARY angelscript PATH_SUFFIXES Debug Release) + +set(AngelScript_INCLUDE_DIRS ${AngelScript_INCLUDE_DIR}) +set(AngelScript_LIBRARIES ${AngelScript_LIBRARY}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(AngelScript FOUND_VAR AngelScript_FOUND + REQUIRED_VARS AngelScript_INCLUDE_DIRS AngelScript_LIBRARIES + ) + +if (AngelScript_FOUND) + add_library(Angelscript::angelscript INTERFACE IMPORTED) + set_target_properties(Angelscript::angelscript PROPERTIES + INTERFACE_LINK_LIBRARIES "${AngelScript_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${AngelScript_INCLUDE_DIRS}" + ) + add_library(AngelScript::use_namespace INTERFACE IMPORTED) + set_target_properties(AngelScript::use_namespace PROPERTIES INTERFACE_COMPILE_DEFINITIONS AS_USE_NAMESPACE) +endif () + +mark_as_advanced(AngelScript_INCLUDE_DIR AngelScript_LIBRARY) diff --git a/cmake/FindSocketW.cmake b/cmake/FindSocketW.cmake new file mode 100644 index 00000000..ce066658 --- /dev/null +++ b/cmake/FindSocketW.cmake @@ -0,0 +1,60 @@ +# The MIT License (MIT) +# +# Copyright (c) 2015 Fabian Killus +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Find SocketW +# ------------ +# +# Find SocketW include directories and libraries. +# This module will set the following variables: +# +# * SocketW_FOUND - True if SocketW is found +# * SocketW_INCLUDE_DIRS - The include directory +# * SocketW_LIBRARIES - The libraries to link against +# +# In addition the following imported targets are defined: +# +# * SocketW::SocketW +# + +find_path(SocketW_INCLUDE_DIR SocketW.h) +find_library(SocketW_LIBRARY SocketW) + +set(SocketW_INCLUDE_DIRS ${SocketW_INCLUDE_DIR}) +set(SocketW_LIBRARIES ${SocketW_LIBRARY}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SocketW FOUND_VAR SocketW_FOUND + REQUIRED_VARS SocketW_INCLUDE_DIRS SocketW_LIBRARIES + ) + +if (SocketW_FOUND) + add_library(SocketW::SocketW INTERFACE IMPORTED) + set_target_properties(SocketW::SocketW PROPERTIES + INTERFACE_LINK_LIBRARIES "${SocketW_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${SocketW_INCLUDE_DIRS}" + ) + if (WIN32) + set_property(TARGET SocketW::SocketW APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32) + endif () +endif () + +mark_as_advanced(SocketW_INCLUDE_DIR SocketW_LIBRARY) diff --git a/contrib/rorserver-initscript b/contrib/rorserver-initscript new file mode 100755 index 00000000..3607a1e9 --- /dev/null +++ b/contrib/rorserver-initscript @@ -0,0 +1,171 @@ +#!/bin/bash +### BEGIN INIT INFO +# Provides: rorserver +# Required-Start: $remote_fs $syslog $network +# Required-Stop: $remote_fs $syslog $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Rigs of Rods multiplayer server +# Description: rorserver is a server for the Rigs of Rods Game +### END INIT INFO + +PATH=/usr/local:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +NAME=rorserver +DESC="Rigs of Rods Multiplayer Server" + +# if you set CRASHREPORTS=1 then the init script will use gdb to catch errors. +# you should use Debug compile mode. Look in /var/log/rorserver/ for the results +CRASHREPORTS="OFF" + +USERNAME=rorserver +DAEMON=/usr/local/bin/rorserver +CFGDIR=/etc/rorserver +LOGDIR=/var/log/rorserver +PIDDIR=/var/run/rorserver +RESDIR=/usr/local/share/rorserver/ + +[ -x "$DAEMON" ] || exit 0 +[ -d "$CFGDIR" ] || exit 0 +[ -d "$LOGDIR" ] || exit 0 +[ -d "$PIDDIR" ] || exit 0 +[ -d "$RESDIR" ] || exit 0 + +. /lib/lsb/init-functions + +case "$1" in + start) + CONFIGS=$(ls ${CFGDIR}/*.cfg 2>/dev/null) + if [[ "${CONFIGS}" == "" ]] + then + log_daemon_msg "no configurations found in ${CFGDIR}" + log_end_msg 1 + exit 0 + fi + for CONFIG in ${CONFIGS} + do + SRVNAME=$(basename ${CONFIG} | awk -F. '{ print $1 }') + PIDFILE=${PIDDIR}/${SRVNAME}.pid + LOGFILE=${LOGDIR}/${SRVNAME}.log + RUNNING=0 + if [[ -f ${PIDFILE} ]] + then + PIDNUM=$(cat ${PIDFILE}) + RUNNING=$(ps -p ${PIDNUM} 2>/dev/null | wc -l) + fi + if [[ "${RUNNING}" != "2" ]] + then + # start + rm -f ${PIDFILE} >>/dev/null 2>&1 + log_daemon_msg "starting ${NAME} with config ${SRVNAME}" + echo "LOG STARTED" > ${LOGFILE} + chown $USERNAME:$USERNAME ${LOGFILE} + if [[ "${CRASHREPORTS}" == "OFF" ]] + then + # normal startup, no gdb + start-stop-daemon --start --background --user ${USERNAME} --chuid ${USERNAME} --name ${NAME}-${SRVNAME} --exec ${DAEMON} --make-pidfile --pidfile ${PIDFILE} -- -c ${CONFIG} -resdir ${RESDIR} -logfilename ${LOGFILE} -inet + log_end_msg $? + else + # gdb startup + DATENOW=$(date +%s) + GDB=/usr/bin/gdb + GDBCMDFILE=${LOGFILE}.${DATENOW}.gdb.cmds + GDBLOG=${LOGFILE}.${DATENOW}.gdb.log + GDBCORE=${LOGFILE}.${DATENOW}.gdb.core + echo "" > ${GDBCMDFILE} + # now create the gdb command script + echo "set logging file ${GDBLOG}" >> ${GDBCMDFILE} + echo "set logging on" >> ${GDBCMDFILE} + # prevent output wrapping and pagination + echo "set trace-commands on" >> ${GDBCMDFILE} + echo "set width 0" >> ${GDBCMDFILE} + echo "set height 0" >> ${GDBCMDFILE} + echo "set pagination off" >> ${GDBCMDFILE} + echo "set confirm off" >> ${GDBCMDFILE} + # improve verbosity of the log + echo "set follow-fork-mode child" >> ${GDBCMDFILE} + echo "set verbose on" >> ${GDBCMDFILE} + echo "set print elements 0" >> ${GDBCMDFILE} + echo "set print address on" >> ${GDBCMDFILE} + echo "set print symbol-filename on" >> ${GDBCMDFILE} + echo "set print array on" >> ${GDBCMDFILE} + echo "set print pretty on" >> ${GDBCMDFILE} + echo "set print union on" >> ${GDBCMDFILE} + echo "set print demangle on" >> ${GDBCMDFILE} + echo "set print asm-demangle on" >> ${GDBCMDFILE} + echo "set print object on" >> ${GDBCMDFILE} + echo "set print vtbl on" >> ${GDBCMDFILE} + echo "set listsize 60" >> ${GDBCMDFILE} + # add the directory as source lookup path + echo "directory /workspaces/ror-server/source/server/" >> ${GDBCMDFILE} + echo "pwd" >> ${GDBCMDFILE} + # set program arguments + echo "set args -c ${CONFIG} -resdir ${RESDIR} -logfilename ${LOGFILE}" >> ${GDBCMDFILE} + # now start the application + echo "run" >> ${GDBCMDFILE} + # upon crash, print out the callstack + echo "bt full" >> ${GDBCMDFILE} + echo "thread apply all backtrace full" >> ${GDBCMDFILE} + echo "show paths" >> ${GDBCMDFILE} + echo "show environment" >> ${GDBCMDFILE} + echo "info threads" >> ${GDBCMDFILE} + echo "info all-registers" >> ${GDBCMDFILE} + echo "info float" >> ${GDBCMDFILE} + echo "info vector" >> ${GDBCMDFILE} + echo "info mem" >> ${GDBCMDFILE} + echo "info frame" >> ${GDBCMDFILE} + echo "info args" >> ${GDBCMDFILE} + echo "info locals" >> ${GDBCMDFILE} + echo "info catch" >> ${GDBCMDFILE} + echo "info frame 2" >> ${GDBCMDFILE} + echo "info frame 3" >> ${GDBCMDFILE} + echo "info sources" >> ${GDBCMDFILE} + echo "info functions" >> ${GDBCMDFILE} + echo "info variables" >> ${GDBCMDFILE} + echo "info classes" >> ${GDBCMDFILE} + echo "show osabi" >> ${GDBCMDFILE} + echo "show architecture" >> ${GDBCMDFILE} + echo "show cp-abi" >> ${GDBCMDFILE} + # now produce core file + echo "generate-core-file ${GDBCORE}" >> ${GDBCMDFILE} + # kill the client process + echo "kill" >> ${GDBCMDFILE} + # quit gdb (and the client app) + echo "quit" >> ${GDBCMDFILE} + + start-stop-daemon --start --background --user ${USERNAME} --name ${NAME}-${SRVNAME} --exec ${GDB} --make-pidfile --pidfile ${PIDFILE} -- ${DAEMON} -x ${GDBCMDFILE} + log_end_msg $? + fi + else + log_daemon_msg "${NAME} with config ${SRVNAME} already running" + log_end_msg 0 + fi + done + ;; + stop) + PIDS=$(ls ${PIDDIR}/*.pid 2>/dev/null) + if [[ "${PIDS}" == "" ]] + then + log_daemon_msg "no rorservers detected running" + log_end_msg 1 + exit 0 + fi + for PID in ${PIDS} + do + PIDNAME=$(basename ${PID}) + log_daemon_msg "Stopping ${NAME} - ${PIDNAME}" + start-stop-daemon --stop --pidfile ${PID} --retry=TERM/30/KILL/5 + RES=$? + rm ${PID} >>/dev/null 2>&1 + log_end_msg ${RES} + done + ;; + restart) + $0 stop && $0 start + ;; + *) + echo "Usage: $0 {start|stop|restart}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/dependencies/angelscript/CMakeLists.txt b/dependencies/angelscript/CMakeLists.txt deleted file mode 100644 index f906079c..00000000 --- a/dependencies/angelscript/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -FILE(GLOB_RECURSE angelscript_src source/*.cpp) -FILE(GLOB_RECURSE angelscript_include include/*.h) - -FILE(GLOB_RECURSE angelscript_add_on_dict add_on/scriptdictionary/*.cpp) -FILE(GLOB_RECURSE angelscript_add_on_math add_on/scriptmath/*.cpp) -FILE(GLOB_RECURSE angelscript_add_on_math3d add_on/scriptmath3d/*.cpp) -FILE(GLOB_RECURSE angelscript_add_on_array add_on/scriptarray/*.cpp) -FILE(GLOB_RECURSE angelscript_add_on_stdstring add_on/scriptstdstring/*.cpp) -FILE(GLOB_RECURSE angelscript_add_on_builder add_on/scriptbuilder/*.cpp) -FILE(GLOB_RECURSE angelscript_add_on_any add_on/scriptany/*.cpp) - -if(MSVC AND CMAKE_CL_64) - enable_language(ASM_MASM) - if(CMAKE_ASM_MASM_COMPILER_WORKS) - set(angelscript_src ${angelscript_src} source/as_callfunc_x64_msvc_asm.asm) - else() - message(FATAL ERROR "MSVC x86_64 target requires a working assembler") - endif() -endif() - -include_directories(include) -add_definitions("-DANGELSCRIPT_EXPORT -D_LIB") - -add_library(angelscript STATIC ${angelscript_src} ${angelscript_include} ${angelscript_add_on_dict} ${angelscript_add_on_math} ${angelscript_add_on_math3d} ${angelscript_add_on_array} ${angelscript_add_on_stdstring} ${angelscript_add_on_builder} ${angelscript_add_on_any}) - -# ignore warnings -set_target_properties(angelscript PROPERTIES COMPILE_FLAGS "-w") diff --git a/dependencies/angelscript/add_on/autowrapper/aswrappedcall.h b/dependencies/angelscript/add_on/autowrapper/aswrappedcall.h deleted file mode 100644 index 75f44be9..00000000 --- a/dependencies/angelscript/add_on/autowrapper/aswrappedcall.h +++ /dev/null @@ -1,581 +0,0 @@ -#ifndef AS_GEN_WRAPPER_H -#define AS_GEN_WRAPPER_H - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -#include - -namespace gw { - -template class Proxy { - public: - T value; - Proxy(T value) : value(value) {} - static T cast(void * ptr) { - return reinterpret_cast *>(&ptr)->value; - } - private: - Proxy(const Proxy &); - Proxy & operator=(const Proxy &); -}; - -template struct Wrapper {}; -template struct ObjFirst {}; -template struct ObjLast {}; -template struct Constructor {}; - -template -void destroy(asIScriptGeneric * gen) { - static_cast(gen->GetObject())->~T(); -} -template <> -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)()); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)()); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)()); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)()); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)()); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)()); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - Proxy::cast(gen->GetObject()))); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - Proxy::cast(gen->GetObject()))); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - Proxy::cast(gen->GetObject()))); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - Proxy::cast(gen->GetObject()))); - } -}; -template -struct Constructor { - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetObject()) T(); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value)); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - Proxy::cast(gen->GetObject()), - static_cast *>(gen->GetAddressOfArg(0))->value)); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - Proxy::cast(gen->GetObject()), - static_cast *>(gen->GetAddressOfArg(0))->value)); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - Proxy::cast(gen->GetObject()))); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - Proxy::cast(gen->GetObject()))); - } -}; -template -struct Constructor { - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetObject()) T( - static_cast *>(gen->GetAddressOfArg(0))->value); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value)); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - Proxy::cast(gen->GetObject()), - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value)); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - Proxy::cast(gen->GetObject()), - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value)); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - Proxy::cast(gen->GetObject()))); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - Proxy::cast(gen->GetObject()))); - } -}; -template -struct Constructor { - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetObject()) T( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value)); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - Proxy::cast(gen->GetObject()), - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value)); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - Proxy::cast(gen->GetObject()), - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value)); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - Proxy::cast(gen->GetObject()))); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - Proxy::cast(gen->GetObject()))); - } -}; -template -struct Constructor { - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetObject()) T( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value)); - } -}; -template -struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value)); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - Proxy::cast(gen->GetObject()), - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value)); - } -}; -template -struct ObjFirst { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - Proxy::cast(gen->GetObject()), - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value)); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - ((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value, - Proxy::cast(gen->GetObject()))); - } -}; -template -struct ObjLast { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetAddressOfReturnLocation()) Proxy((fp)( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value, - Proxy::cast(gen->GetObject()))); - } -}; -template -struct Constructor { - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { - new (gen->GetObject()) T( - static_cast *>(gen->GetAddressOfArg(0))->value, - static_cast *>(gen->GetAddressOfArg(1))->value, - static_cast *>(gen->GetAddressOfArg(2))->value, - static_cast *>(gen->GetAddressOfArg(3))->value); - } -}; -template -struct Id { - template AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&Wrapper::template f); } - template AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&ObjFirst::template f); } - template AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&ObjLast::template f); } -}; - -template -Id id(T fn_ptr) { return Id(); } - -// On some versions of GNUC it is necessary to use the template keyword as disambiguator, -// on others the template keyword gives an error, hence the need for the following define. -// MSVC on the other hand seems to accept both with or without the template keyword. -#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) - // GNUC 4.4.3 doesn't need the template keyword, and - // hopefully upcoming versions won't need it either - #define TMPL template -#else - #define TMPL -#endif - -#define WRAP_FN(name) (::gw::id(name).TMPL f< name >()) -#define WRAP_MFN(ClassType, name) (::gw::id(&ClassType::name).TMPL f< &ClassType::name >()) -#define WRAP_OBJ_FIRST(name) (::gw::id(name).TMPL of< name >()) -#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >()) - -#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< name >)) -#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< &ClassType::name >)) -#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst::TMPL f< name >)) -#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast::TMPL f< name >)) - -#define WRAP_CON(ClassType, Parameters) asFUNCTION((::gw::Constructor::f)) -#define WRAP_DES(ClassType) asFUNCTION((::gw::destroy)) - - -} // end namespace gw - -#endif diff --git a/dependencies/angelscript/add_on/autowrapper/generator/generateheader.cpp b/dependencies/angelscript/add_on/autowrapper/generator/generateheader.cpp deleted file mode 100644 index 37bd910c..00000000 --- a/dependencies/angelscript/add_on/autowrapper/generator/generateheader.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// -// This generator creates a header file that implements automatic -// wrapper functions for the generic calling convention. -// -// Originally implemented by George Yohng from 4Front Technologies in 2009-03-11 -// Modifications by Pierre Fortin in order to add constructor wrapper generation -// -// A completely new implementation of automatic wrapper functions was -// implemented by SiCrane at GameDev.net in 2011-12-18. The generator was -// adapted from Python to C++ by Andreas. -// -// ref: http://www.gamedev.net/topic/617111-more-angelscript-binding-wrappers/ -// - - -#include -#include - -// Generate templates for up to this number of function parameters -const int max_args = 4; - -using namespace std; - -void PrintTemplate(const char *base, const char *typeNameList, const char *retType, const char *objType, const char *isConst, const char *newExpr, const char *objExpr, const char *argList1, const char *argList2, const char *wrapName); -void PrintConstructor(const char *comma, const char *typeNameList, const char *typeList, const char *argList); - -int main() -{ - printf("#ifndef AS_GEN_WRAPPER_H\n" - "#define AS_GEN_WRAPPER_H\n" - "\n" - "#ifndef ANGELSCRIPT_H\n" - "// Avoid having to inform include path if header is already include before\n" - "#include \n" - "#endif\n" - "#include \n" - "\n" - "namespace gw {\n" - "\n" - "template class Proxy {\n" - " public:\n" - " T value;\n" - " Proxy(T value) : value(value) {}\n" - " static T cast(void * ptr) {\n" - " return reinterpret_cast *>(&ptr)->value;\n" - " }\n" - " private:\n" - " Proxy(const Proxy &);\n" - " Proxy & operator=(const Proxy &);\n" - "};\n" - "\n" - "template struct Wrapper {};\n" - "template struct ObjFirst {};\n" - "template struct ObjLast {};\n" - "template struct Constructor {};\n" - "\n" - "template \n" - "void destroy(asIScriptGeneric * gen) {\n" - " static_cast(gen->GetObject())->~T();\n" - "}\n"); - - string typename_list = "typename A0"; - string type_list = "A0"; - string arg_list = "\n static_cast *>(gen->GetAddressOfArg(0))->value"; - string new_exp = "new (gen->GetAddressOfReturnLocation()) Proxy"; - string obj_exp = "static_cast(gen->GetObject())->*"; - string obj_arg_exp = "\n Proxy::cast(gen->GetObject())"; - - PrintTemplate("", "", "void", "", "", "", "", "void", "", "Wrapper"); - PrintTemplate("typename R", "", "R", "", "", new_exp.c_str(), "", "void", "", "Wrapper"); - PrintTemplate("typename T", "", "void", "T::", "", "", obj_exp.c_str(), "void", "", "Wrapper"); - PrintTemplate("typename T, typename R", "", "R", "T::", "", new_exp.c_str(), obj_exp.c_str(), "void", "", "Wrapper"); - PrintTemplate("typename T", "", "void", "T::", " const", "", obj_exp.c_str(), "void", "", "Wrapper"); - PrintTemplate("typename T, typename R", "", "R", "T::", " const", new_exp.c_str(), obj_exp.c_str(), "void", "", "Wrapper"); - - PrintTemplate("typename T", "", "void", "", "", "", "", "T", obj_arg_exp.c_str(), "ObjFirst"); - PrintTemplate("typename T, typename R", "", "R", "", "", new_exp.c_str(), "", "T", obj_arg_exp.c_str(), "ObjFirst"); - PrintTemplate("typename T", "", "void", "", "", "", "", "T", obj_arg_exp.c_str(), "ObjLast"); - PrintTemplate("typename T, typename R", "", "R", "", "", new_exp.c_str(), "", "T", obj_arg_exp.c_str(), "ObjLast"); - - PrintConstructor("", "", "", ""); - - for( int i = 0; i < max_args; i++ ) - { - PrintTemplate("", typename_list.c_str(), "void", "", "", "", "", type_list.c_str(), arg_list.c_str(), "Wrapper"); - PrintTemplate("typename R, ", typename_list.c_str(), "R", "", "", new_exp.c_str(), "", type_list.c_str(), arg_list.c_str(), "Wrapper"); - PrintTemplate("typename T, ", typename_list.c_str(), "void", "T::", "", "", obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper"); - PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R", "T::", "", new_exp.c_str(), obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper"); - PrintTemplate("typename T, ", typename_list.c_str(), "void", "T::", " const", "", obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper"); - PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R", "T::", " const", new_exp.c_str(), obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper"); - - PrintTemplate("typename T, ", typename_list.c_str(), "void", "", "", "", "", ("T, " + type_list).c_str(), (obj_arg_exp + "," + arg_list).c_str(), "ObjFirst"); - PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R", "", "", new_exp.c_str(), "", ("T, " + type_list).c_str(), (obj_arg_exp + "," + arg_list).c_str(), "ObjFirst"); - PrintTemplate("typename T, ", typename_list.c_str(), "void", "", "", "", "", (type_list + ", T").c_str(), (arg_list + "," + obj_arg_exp).c_str(), "ObjLast"); - PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R", "", "", new_exp.c_str(), "", (type_list + ", T").c_str(), (arg_list + "," + obj_arg_exp).c_str(), "ObjLast"); - - PrintConstructor(", ", typename_list.c_str(), type_list.c_str(), arg_list.c_str()); - - char buf[5]; - sprintf(buf, "%d", i + 1); - typename_list += ", typename A" + string(buf); - type_list += ", A" + string(buf); - arg_list += ",\n static_cast *>(gen->GetAddressOfArg(" + string(buf) + "))->value"; - } - - printf("template \n" - "struct Id {\n" - " template AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&Wrapper::template f); }\n" - " template AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&ObjFirst::template f); }\n" - " template AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&ObjLast::template f); }\n" - "};\n" - "\n" - "template \n" - "Id id(T fn_ptr) { return Id(); }\n" - "\n" - "// On some versions of GNUC it is necessary to use the template keyword as disambiguator,\n" - "// on others the template keyword gives an error, hence the need for the following define.\n" - "// MSVC on the other hand seems to accept both with or without the template keyword.\n" - "#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))\n" - " // GNUC 4.4.3 doesn't need the template keyword, and\n" - " // hopefully upcoming versions won't need it either\n" - " #define TMPL template\n" - "#else\n" - " #define TMPL\n" - "#endif\n" - "\n" - "#define WRAP_FN(name) (::gw::id(name).TMPL f< name >())\n" - "#define WRAP_MFN(ClassType, name) (::gw::id(&ClassType::name).TMPL f< &ClassType::name >())\n" - "#define WRAP_OBJ_FIRST(name) (::gw::id(name).TMPL of< name >())\n" - "#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >())\n" - "\n" - "#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< name >))\n" - "#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< &ClassType::name >))\n" - "#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst::TMPL f< name >))\n" - "#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast::TMPL f< name >))\n" - "\n" - "#define WRAP_CON(ClassType, Parameters) asFUNCTION((::gw::Constructor::f))\n" - "#define WRAP_DES(ClassType) asFUNCTION((::gw::destroy))\n" - "\n" - "} // end namespace gw\n" - "\n" - "#endif\n"); - - return 0; -} - -void PrintTemplate(const char *base, const char *typeNameList, const char *retType, const char *objType, const char *isConst, const char *newExpr, const char *objExpr, const char *argList1, const char *argList2, const char *wrapName) -{ - printf("template <%s%s>\n", base, typeNameList); - printf("struct %s<%s (%s*)(%s)%s> {\n", wrapName, retType, objType, argList1, isConst); - printf(" template <%s (%s*fp)(%s)%s>\n", retType, objType, argList1, isConst); - printf(" static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {\n"); - printf(" %s((%sfp)(%s));\n", newExpr, objExpr, argList2); - printf(" }\n"); - printf("};\n"); -} - -void PrintConstructor(const char *comma, const char *typeNameList, const char *typeList, const char *argList) -{ - printf("template \n", comma, typeNameList); - printf("struct Constructor {\n", typeList); - printf(" static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {\n"); - printf(" new (gen->GetObject()) T(%s);\n", argList); - printf(" }\n"); - printf("};\n"); -} \ No newline at end of file diff --git a/dependencies/angelscript/add_on/autowrapper/generator/generator.sln b/dependencies/angelscript/add_on/autowrapper/generator/generator.sln deleted file mode 100644 index a54cec4b..00000000 --- a/dependencies/angelscript/add_on/autowrapper/generator/generator.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generator", "generator.vcproj", "{086A2F1A-01B1-4EB3-A8FA-0926FF10E953}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {086A2F1A-01B1-4EB3-A8FA-0926FF10E953}.Debug|Win32.ActiveCfg = Debug|Win32 - {086A2F1A-01B1-4EB3-A8FA-0926FF10E953}.Debug|Win32.Build.0 = Debug|Win32 - {086A2F1A-01B1-4EB3-A8FA-0926FF10E953}.Release|Win32.ActiveCfg = Release|Win32 - {086A2F1A-01B1-4EB3-A8FA-0926FF10E953}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/dependencies/angelscript/add_on/autowrapper/generator/generator.vcproj b/dependencies/angelscript/add_on/autowrapper/generator/generator.vcproj deleted file mode 100644 index dddd9509..00000000 --- a/dependencies/angelscript/add_on/autowrapper/generator/generator.vcproj +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dependencies/angelscript/add_on/contextmgr/contextmgr.cpp b/dependencies/angelscript/add_on/contextmgr/contextmgr.cpp deleted file mode 100644 index fd4cbc9f..00000000 --- a/dependencies/angelscript/add_on/contextmgr/contextmgr.cpp +++ /dev/null @@ -1,376 +0,0 @@ -#include -#include - -#include "contextmgr.h" - -using namespace std; - -// TODO: Should have a pool of free asIScriptContext so that new contexts -// won't be allocated every time. The application must not keep -// its own references, instead it must tell the context manager -// that it is using the context. Otherwise the context manager may -// think it can reuse the context too early. - -// TODO: Need to have a callback for when scripts finishes, so that the -// application can receive return values. - -BEGIN_AS_NAMESPACE - -// The id for the context manager user data. -// The add-ons have reserved the numbers 1000 -// through 1999 for this purpose, so we should be fine. -const asPWORD CONTEXT_MGR = 1002; - -struct SContextInfo -{ - asUINT sleepUntil; - vector coRoutines; - asUINT currentCoRoutine; -}; - -static void ScriptSleep(asUINT milliSeconds) -{ - // Get a pointer to the context that is currently being executed - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - // Get the context manager from the user data - CContextMgr *ctxMgr = reinterpret_cast(ctx->GetUserData(CONTEXT_MGR)); - if( ctxMgr ) - { - // Suspend its execution. The VM will continue until the current - // statement is finished and then return from the Execute() method - ctx->Suspend(); - - // Tell the context manager when the context is to continue execution - ctxMgr->SetSleeping(ctx, milliSeconds); - } - } -} - -static void ScriptYield() -{ - // Get a pointer to the context that is currently being executed - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - // Get the context manager from the user data - CContextMgr *ctxMgr = reinterpret_cast(ctx->GetUserData(CONTEXT_MGR)); - if( ctxMgr ) - { - // Let the context manager know that it should run the next co-routine - ctxMgr->NextCoRoutine(); - - // The current context must be suspended so that VM will return from - // the Execute() method where the context manager will continue. - ctx->Suspend(); - } - } -} - -void ScriptCreateCoRoutine(asIScriptFunction *func, CScriptDictionary *arg) -{ - if( func == 0 ) - return; - - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - // Get the context manager from the user data - CContextMgr *ctxMgr = reinterpret_cast(ctx->GetUserData(CONTEXT_MGR)); - if( ctxMgr ) - { - // Create a new context for the co-routine - asIScriptContext *coctx = ctxMgr->AddContextForCoRoutine(ctx, func); - - // Pass the argument to the context - coctx->SetArgObject(0, arg); - - // The context manager will call Execute() on the context when it is time - } - } -} - -CContextMgr::CContextMgr() -{ - m_getTimeFunc = 0; - m_currentThread = 0; - - m_numExecutions = 0; - m_numGCObjectsCreated = 0; - m_numGCObjectsDestroyed = 0; -} - -CContextMgr::~CContextMgr() -{ - asUINT n; - - // Free the memory - for( n = 0; n < m_threads.size(); n++ ) - { - if( m_threads[n] ) - { - for( asUINT c = 0; c < m_threads[n]->coRoutines.size(); c++ ) - { - asIScriptContext *ctx = m_threads[n]->coRoutines[c]; - if( ctx ) - { - // Return the context to the engine (and possible context pool configured in it) - ctx->GetEngine()->ReturnContext(ctx); - } - } - - delete m_threads[n]; - } - } - - for( n = 0; n < m_freeThreads.size(); n++ ) - { - if( m_freeThreads[n] ) - { - assert( m_freeThreads[n]->coRoutines.size() == 0 ); - - delete m_freeThreads[n]; - } - } -} - -int CContextMgr::ExecuteScripts() -{ - // TODO: Should have an optional time out for this function. If not all scripts executed before the - // time out, the next time the function is called the loop should continue - // where it left off. - - // TODO: There should be a time out per thread as well. If a thread executes for too - // long, it should be aborted. A group of co-routines count as a single thread. - - // Check if the system time is higher than the time set for the contexts - asUINT time = m_getTimeFunc ? m_getTimeFunc() : asUINT(-1); - for( m_currentThread = 0; m_currentThread < m_threads.size(); m_currentThread++ ) - { - SContextInfo *thread = m_threads[m_currentThread]; - if( thread->sleepUntil < time ) - { - int currentCoRoutine = thread->currentCoRoutine; - - // Gather some statistics from the GC - asIScriptEngine *engine = thread->coRoutines[currentCoRoutine]->GetEngine(); - asUINT gcSize1, gcSize2, gcSize3; - engine->GetGCStatistics(&gcSize1); - - // Execute the script for this thread and co-routine - int r = thread->coRoutines[currentCoRoutine]->Execute(); - - // Determine how many new objects were created in the GC - engine->GetGCStatistics(&gcSize2); - m_numGCObjectsCreated += gcSize2 - gcSize1; - m_numExecutions++; - - if( r != asEXECUTION_SUSPENDED ) - { - // TODO: It should be possible to retrieve the return value before the context is released. - // Maybe by calling a callback, or by storing the context somewhere until it has been - // accessed. - - // The context has terminated execution (for one reason or other) - engine->ReturnContext(thread->coRoutines[currentCoRoutine]); - thread->coRoutines[currentCoRoutine] = 0; - - thread->coRoutines.erase(thread->coRoutines.begin() + thread->currentCoRoutine); - if( thread->currentCoRoutine >= thread->coRoutines.size() ) - thread->currentCoRoutine = 0; - - // If this was the last co-routine terminate the thread - if( thread->coRoutines.size() == 0 ) - { - m_freeThreads.push_back(thread); - m_threads.erase(m_threads.begin() + m_currentThread); - m_currentThread--; - } - } - - // Destroy all known garbage if any new objects were created - if( gcSize2 > gcSize1 ) - { - engine->GarbageCollect(asGC_FULL_CYCLE | asGC_DESTROY_GARBAGE); - - // Determine how many objects were destroyed - engine->GetGCStatistics(&gcSize3); - m_numGCObjectsDestroyed += gcSize3 - gcSize2; - } - - // TODO: If more objects are created per execution than destroyed on average - // then it may be necessary to run more iterations of the detection of - // cyclic references. At the startup of an application there is usually - // a lot of objects created that will live on through out the application - // so the average number of objects created per execution will be higher - // than the number of destroyed objects in the beginning, but afterwards - // it usually levels out to be more or less equal. - - // Just run an incremental step for detecting cyclic references - engine->GarbageCollect(asGC_ONE_STEP | asGC_DETECT_GARBAGE); - } - } - - return int(m_threads.size()); -} - -void CContextMgr::NextCoRoutine() -{ - m_threads[m_currentThread]->currentCoRoutine++; - if( m_threads[m_currentThread]->currentCoRoutine >= m_threads[m_currentThread]->coRoutines.size() ) - m_threads[m_currentThread]->currentCoRoutine = 0; -} - -void CContextMgr::AbortAll() -{ - // Abort all contexts and release them. The script engine will make - // sure that all resources held by the scripts are properly released. - - for( asUINT n = 0; n < m_threads.size(); n++ ) - { - for( asUINT c = 0; c < m_threads[n]->coRoutines.size(); c++ ) - { - asIScriptContext *ctx = m_threads[n]->coRoutines[c]; - if( ctx ) - { - ctx->Abort(); - ctx->GetEngine()->ReturnContext(ctx); - ctx = 0; - } - } - m_threads[n]->coRoutines.resize(0); - - m_freeThreads.push_back(m_threads[n]); - } - - m_threads.resize(0); - - m_currentThread = 0; -} - -asIScriptContext *CContextMgr::AddContext(asIScriptEngine *engine, asIScriptFunction *func) -{ - // Use RequestContext instead of CreateContext so we can take - // advantage of possible context pooling configured with the engine - asIScriptContext *ctx = engine->RequestContext(); - if( ctx == 0 ) - return 0; - - // Prepare it to execute the function - int r = ctx->Prepare(func); - if( r < 0 ) - { - engine->ReturnContext(ctx); - return 0; - } - - // Set the context manager as user data with the context so it - // can be retrieved by the functions registered with the engine - ctx->SetUserData(this, CONTEXT_MGR); - - // Add the context to the list for execution - SContextInfo *info = 0; - if( m_freeThreads.size() > 0 ) - { - info = *m_freeThreads.rbegin(); - m_freeThreads.pop_back(); - } - else - { - info = new SContextInfo; - } - - info->coRoutines.push_back(ctx); - info->currentCoRoutine = 0; - info->sleepUntil = 0; - m_threads.push_back(info); - - return ctx; -} - -asIScriptContext *CContextMgr::AddContextForCoRoutine(asIScriptContext *currCtx, asIScriptFunction *func) -{ - asIScriptEngine *engine = currCtx->GetEngine(); - asIScriptContext *coctx = engine->RequestContext(); - if( coctx == 0 ) - { - return 0; - } - - // Prepare the context - int r = coctx->Prepare(func); - if( r < 0 ) - { - // Couldn't prepare the context - engine->ReturnContext(coctx); - return 0; - } - - // Set the context manager as user data with the context so it - // can be retrieved by the functions registered with the engine - coctx->SetUserData(this, CONTEXT_MGR); - - // Find the current context thread info - // TODO: Start with the current thread so that we can find the group faster - for( asUINT n = 0; n < m_threads.size(); n++ ) - { - if( m_threads[n]->coRoutines[m_threads[n]->currentCoRoutine] == currCtx ) - { - // Add the coRoutine to the list - m_threads[n]->coRoutines.push_back(coctx); - } - } - - return coctx; -} - -void CContextMgr::SetSleeping(asIScriptContext *ctx, asUINT milliSeconds) -{ - assert( m_getTimeFunc != 0 ); - - // Find the context and update the timeStamp - // for when the context is to be continued - - // TODO: Start with the current thread - - for( asUINT n = 0; n < m_threads.size(); n++ ) - { - if( m_threads[n]->coRoutines[m_threads[n]->currentCoRoutine] == ctx ) - { - m_threads[n]->sleepUntil = (m_getTimeFunc ? m_getTimeFunc() : 0) + milliSeconds; - } - } -} - -void CContextMgr::RegisterThreadSupport(asIScriptEngine *engine) -{ - int r; - - // Must set the get time callback function for this to work - assert( m_getTimeFunc != 0 ); - - // Register the sleep function - r = engine->RegisterGlobalFunction("void sleep(uint)", asFUNCTION(ScriptSleep), asCALL_CDECL); assert( r >= 0 ); - - // TODO: Add support for spawning new threads, waiting for signals, etc -} - -void CContextMgr::RegisterCoRoutineSupport(asIScriptEngine *engine) -{ - int r; - - // The dictionary add-on must have been registered already - assert( engine->GetObjectTypeByDecl("dictionary") ); - - r = engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterFuncdef("void coroutine(dictionary@)"); - r = engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine), asCALL_CDECL); assert( r >= 0 ); -} - -void CContextMgr::SetGetTimeCallback(TIMEFUNC_t func) -{ - m_getTimeFunc = func; -} - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/add_on/contextmgr/contextmgr.h b/dependencies/angelscript/add_on/contextmgr/contextmgr.h deleted file mode 100644 index 669596c2..00000000 --- a/dependencies/angelscript/add_on/contextmgr/contextmgr.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef CONTEXTMGR_H -#define CONTEXTMGR_H - -// The context manager simplifies the management of multiple concurrent scripts - -// More than one context manager can be used, if you wish to control different -// groups of scripts separately, e.g. game object scripts, and GUI scripts. - -// OBSERVATION: This class is currently not thread safe. - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -#include - -BEGIN_AS_NAMESPACE - -class CScriptDictionary; - -// The internal structure for holding contexts -struct SContextInfo; - -// The signature of the get time callback function -typedef asUINT (*TIMEFUNC_t)(); - -class CContextMgr -{ -public: - CContextMgr(); - ~CContextMgr(); - - // Set the function that the manager will use to obtain the time in milliseconds - void SetGetTimeCallback(TIMEFUNC_t func); - - // Registers the following: - // - // void sleep(uint milliseconds) - // - // The application must set the get time callback for this to work - void RegisterThreadSupport(asIScriptEngine *engine); - - // Registers the following: - // - // funcdef void coroutine(dictionary@) - // void createCoRoutine(coroutine @func, dictionary @args) - // void yield() - void RegisterCoRoutineSupport(asIScriptEngine *engine); - - // Create a new context, prepare it with the function id, then return - // it so that the application can pass the argument values. The context - // will be released by the manager after the execution has completed. - asIScriptContext *AddContext(asIScriptEngine *engine, asIScriptFunction *func); - - // Create a new context, prepare it with the function id, then return - // it so that the application can pass the argument values. The context - // will be added as a co-routine in the same thread as the currCtx. - asIScriptContext *AddContextForCoRoutine(asIScriptContext *currCtx, asIScriptFunction *func); - - // Execute each script that is not currently sleeping. The function returns after - // each script has been executed once. The application should call this function - // for each iteration of the message pump, or game loop, or whatever. - // Returns the number of scripts still in execution. - int ExecuteScripts(); - - // Put a script to sleep for a while - void SetSleeping(asIScriptContext *ctx, asUINT milliSeconds); - - // Switch the execution to the next co-routine in the group. - // Returns true if the switch was successful. - void NextCoRoutine(); - - // Abort all scripts - void AbortAll(); - -protected: - std::vector m_threads; - std::vector m_freeThreads; - asUINT m_currentThread; - TIMEFUNC_t m_getTimeFunc; - - // Statistics for Garbage Collection - asUINT m_numExecutions; - asUINT m_numGCObjectsCreated; - asUINT m_numGCObjectsDestroyed; -}; - - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/add_on/debugger/debugger.cpp b/dependencies/angelscript/add_on/debugger/debugger.cpp deleted file mode 100644 index 3d77994c..00000000 --- a/dependencies/angelscript/add_on/debugger/debugger.cpp +++ /dev/null @@ -1,758 +0,0 @@ -#include "debugger.h" -#include // cout -#include // stringstream -#include // atoi -#include // assert - -using namespace std; - -BEGIN_AS_NAMESPACE - -CDebugger::CDebugger() -{ - m_action = CONTINUE; - m_lastFunction = 0; -} - -CDebugger::~CDebugger() -{ -} - -string CDebugger::ToString(void *value, asUINT typeId, bool expandMembers, asIScriptEngine *engine) -{ - if( value == 0 ) - return ""; - - stringstream s; - if( typeId == asTYPEID_VOID ) - return ""; - else if( typeId == asTYPEID_BOOL ) - return *(bool*)value ? "true" : "false"; - else if( typeId == asTYPEID_INT8 ) - s << (int)*(signed char*)value; - else if( typeId == asTYPEID_INT16 ) - s << (int)*(signed short*)value; - else if( typeId == asTYPEID_INT32 ) - s << *(signed int*)value; - else if( typeId == asTYPEID_INT64 ) -#if defined(_MSC_VER) && _MSC_VER <= 1200 - s << "{...}"; // MSVC6 doesn't like the << operator for 64bit integer -#else - s << *(asINT64*)value; -#endif - else if( typeId == asTYPEID_UINT8 ) - s << (unsigned int)*(unsigned char*)value; - else if( typeId == asTYPEID_UINT16 ) - s << (unsigned int)*(unsigned short*)value; - else if( typeId == asTYPEID_UINT32 ) - s << *(unsigned int*)value; - else if( typeId == asTYPEID_UINT64 ) -#if defined(_MSC_VER) && _MSC_VER <= 1200 - s << "{...}"; // MSVC6 doesn't like the << operator for 64bit integer -#else - s << *(asQWORD*)value; -#endif - else if( typeId == asTYPEID_FLOAT ) - s << *(float*)value; - else if( typeId == asTYPEID_DOUBLE ) - s << *(double*)value; - else if( (typeId & asTYPEID_MASK_OBJECT) == 0 ) - { - // The type is an enum - s << *(asUINT*)value; - - // Check if the value matches one of the defined enums - for( int n = engine->GetEnumValueCount(typeId); n-- > 0; ) - { - int enumVal; - const char *enumName = engine->GetEnumValueByIndex(typeId, n, &enumVal); - if( enumVal == *(int*)value ) - { - s << ", " << enumName; - break; - } - } - } - else if( typeId & asTYPEID_SCRIPTOBJECT ) - { - // Dereference handles, so we can see what it points to - if( typeId & asTYPEID_OBJHANDLE ) - value = *(void**)value; - - asIScriptObject *obj = (asIScriptObject *)value; - - // Print the address of the object - s << "{" << obj << "}"; - - // Print the members - if( obj && expandMembers ) - { - asIObjectType *type = obj->GetObjectType(); - for( asUINT n = 0; n < obj->GetPropertyCount(); n++ ) - { - s << endl << " " << type->GetPropertyDeclaration(n) << " = " << ToString(obj->GetAddressOfProperty(n), obj->GetPropertyTypeId(n), false, engine); - } - } - } - else - { - // Dereference handles, so we can see what it points to - if( typeId & asTYPEID_OBJHANDLE ) - value = *(void**)value; - - // Print the address for reference types so it will be - // possible to see when handles point to the same object - asIObjectType *type = engine->GetObjectTypeById(typeId); - if( type->GetFlags() & asOBJ_REF ) - s << "{" << value << "}"; - - if( value ) - { - // Check if there is a registered to-string callback - map::iterator it = m_toStringCallbacks.find(type); - if( it == m_toStringCallbacks.end() ) - { - // If the type is a template instance, there might be a - // to-string callback for the generic template type - if( type->GetFlags() & asOBJ_TEMPLATE ) - { - asIObjectType *tmplType = engine->GetObjectTypeByName(type->GetName()); - it = m_toStringCallbacks.find(tmplType); - } - } - - if( it != m_toStringCallbacks.end() ) - { - if( type->GetFlags() & asOBJ_REF ) - s << endl; - - // Invoke the callback to get the string representation of this type - string str = it->second(value, expandMembers, this); - s << str; - } - else - { - // TODO: Value types can have their properties expanded by default - } - } - } - - return s.str(); -} - -void CDebugger::RegisterToStringCallback(const asIObjectType *ot, ToStringCallback callback) -{ - if( m_toStringCallbacks.find(ot) == m_toStringCallbacks.end() ) - m_toStringCallbacks.insert(map::value_type(ot, callback)); -} - -void CDebugger::LineCallback(asIScriptContext *ctx) -{ - assert( ctx ); - - // This should never happen, but it doesn't hurt to validate it - if( ctx == 0 ) - return; - - // By default we ignore callbacks when the context is not active. - // An application might override this to for example disconnect the - // debugger as the execution finished. - if( ctx->GetState() != asEXECUTION_ACTIVE ) - return; - - if( m_action == CONTINUE ) - { - if( !CheckBreakPoint(ctx) ) - return; - } - else if( m_action == STEP_OVER ) - { - if( ctx->GetCallstackSize() > m_lastCommandAtStackLevel ) - { - if( !CheckBreakPoint(ctx) ) - return; - } - } - else if( m_action == STEP_OUT ) - { - if( ctx->GetCallstackSize() >= m_lastCommandAtStackLevel ) - { - if( !CheckBreakPoint(ctx) ) - return; - } - } - else if( m_action == STEP_INTO ) - { - CheckBreakPoint(ctx); - - // Always break, but we call the check break point anyway - // to tell user when break point has been reached - } - - stringstream s; - const char *file = 0; - int lineNbr = ctx->GetLineNumber(0, 0, &file); - s << (file ? file : "{unnamed}") << ":" << lineNbr << "; " << ctx->GetFunction()->GetDeclaration() << endl; - Output(s.str()); - - TakeCommands(ctx); -} - -bool CDebugger::CheckBreakPoint(asIScriptContext *ctx) -{ - if( ctx == 0 ) - return false; - - // TODO: Should cache the break points in a function by checking which possible break points - // can be hit when entering a function. If there are no break points in the current function - // then there is no need to check every line. - - const char *tmp = 0; - int lineNbr = ctx->GetLineNumber(0, 0, &tmp); - - // Consider just filename, not the full path - string file = tmp ? tmp : ""; - size_t r = file.find_last_of("\\/"); - if( r != string::npos ) - file = file.substr(r+1); - - // Did we move into a new function? - asIScriptFunction *func = ctx->GetFunction(); - if( m_lastFunction != func ) - { - // Check if any breakpoints need adjusting - for( size_t n = 0; n < m_breakPoints.size(); n++ ) - { - // We need to check for a breakpoint at entering the function - if( m_breakPoints[n].func ) - { - if( m_breakPoints[n].name == func->GetName() ) - { - stringstream s; - s << "Entering function '" << m_breakPoints[n].name << "'. Transforming it into break point" << endl; - Output(s.str()); - - // Transform the function breakpoint into a file breakpoint - m_breakPoints[n].name = file; - m_breakPoints[n].lineNbr = lineNbr; - m_breakPoints[n].func = false; - m_breakPoints[n].needsAdjusting = false; - } - } - // Check if a given breakpoint fall on a line with code or else adjust it to the next line - else if( m_breakPoints[n].needsAdjusting && - m_breakPoints[n].name == file ) - { - int line = func->FindNextLineWithCode(m_breakPoints[n].lineNbr); - if( line >= 0 ) - { - m_breakPoints[n].needsAdjusting = false; - if( line != m_breakPoints[n].lineNbr ) - { - stringstream s; - s << "Moving break point " << n << " in file '" << file << "' to next line with code at line " << line << endl; - Output(s.str()); - - // Move the breakpoint to the next line - m_breakPoints[n].lineNbr = line; - } - } - } - } - } - m_lastFunction = func; - - // Determine if there is a breakpoint at the current line - for( size_t n = 0; n < m_breakPoints.size(); n++ ) - { - // TODO: do case-less comparison for file name - - // Should we break? - if( !m_breakPoints[n].func && - m_breakPoints[n].lineNbr == lineNbr && - m_breakPoints[n].name == file ) - { - stringstream s; - s << "Reached break point " << n << " in file '" << file << "' at line " << lineNbr << endl; - Output(s.str()); - return true; - } - } - - return false; -} - -void CDebugger::TakeCommands(asIScriptContext *ctx) -{ - for(;;) - { - char buf[512]; - - Output("[dbg]> "); - cin.getline(buf, 512); - - if( InterpretCommand(string(buf), ctx) ) - break; - } -} - -bool CDebugger::InterpretCommand(const string &cmd, asIScriptContext *ctx) -{ - if( cmd.length() == 0 ) return true; - - switch( cmd[0] ) - { - case 'c': - m_action = CONTINUE; - break; - - case 's': - m_action = STEP_INTO; - break; - - case 'n': - if( ctx == 0 ) - { - Output("No script is running\n"); - return false; - } - m_action = STEP_OVER; - m_lastCommandAtStackLevel = ctx->GetCallstackSize(); - break; - - case 'o': - if( ctx == 0 ) - { - Output("No script is running\n"); - return false; - } - m_action = STEP_OUT; - m_lastCommandAtStackLevel = ctx->GetCallstackSize(); - break; - - case 'b': - { - // Set break point - size_t div = cmd.find(':'); - if( div != string::npos && div > 2 ) - { - string file = cmd.substr(2, div-2); - string line = cmd.substr(div+1); - - int nbr = atoi(line.c_str()); - - AddFileBreakPoint(file, nbr); - } - else if( div == string::npos && (div = cmd.find_first_not_of(" \t", 1)) != string::npos ) - { - string func = cmd.substr(div); - - AddFuncBreakPoint(func); - } - else - { - Output("Incorrect format for setting break point, expected one of:\n" - "b :\n" - "b \n"); - } - } - // take more commands - return false; - - case 'r': - { - // Remove break point - if( cmd.length() > 2 ) - { - string br = cmd.substr(2); - if( br == "all" ) - { - m_breakPoints.clear(); - Output("All break points have been removed\n"); - } - else - { - int nbr = atoi(br.c_str()); - if( nbr >= 0 && nbr < (int)m_breakPoints.size() ) - m_breakPoints.erase(m_breakPoints.begin()+nbr); - ListBreakPoints(); - } - } - else - { - Output("Incorrect format for removing break points, expected:\n" - "r \n"); - } - } - // take more commands - return false; - - case 'l': - { - // List something - size_t p = cmd.find_first_not_of(" \t", 1); - if( p != string::npos ) - { - if( cmd[p] == 'b' ) - { - ListBreakPoints(); - } - else if( cmd[p] == 'v' ) - { - ListLocalVariables(ctx); - } - else if( cmd[p] == 'g' ) - { - ListGlobalVariables(ctx); - } - else if( cmd[p] == 'm' ) - { - ListMemberProperties(ctx); - } - else if( cmd[p] == 's' ) - { - ListStatistics(ctx); - } - else - { - Output("Unknown list option, expected one of:\n" - "b - breakpoints\n" - "v - local variables\n" - "m - member properties\n" - "g - global variables\n" - "s - statistics\n"); - } - } - else - { - Output("Incorrect format for list, expected:\n" - "l \n"); - } - } - // take more commands - return false; - - case 'h': - PrintHelp(); - // take more commands - return false; - - case 'p': - { - // Print a value - size_t p = cmd.find_first_not_of(" \t", 1); - if( p != string::npos ) - { - PrintValue(cmd.substr(p), ctx); - } - else - { - Output("Incorrect format for print, expected:\n" - "p \n"); - } - } - // take more commands - return false; - - case 'w': - // Where am I? - PrintCallstack(ctx); - // take more commands - return false; - - case 'a': - // abort the execution - if( ctx == 0 ) - { - Output("No script is running\n"); - return false; - } - ctx->Abort(); - break; - - default: - Output("Unknown command\n"); - // take more commands - return false; - } - - // Continue execution - return true; -} - -void CDebugger::PrintValue(const std::string &expr, asIScriptContext *ctx) -{ - if( ctx == 0 ) - { - Output("No script is running\n"); - return; - } - - asIScriptEngine *engine = ctx->GetEngine(); - - int len = 0; - asETokenClass t = engine->ParseToken(expr.c_str(), 0, &len); - - // TODO: If the expression starts with :: we should only look for global variables - // TODO: If the expression starts with identifier followed by ::, then use that as namespace - if( t == asTC_IDENTIFIER ) - { - string name(expr.c_str(), len); - - // Find the variable - void *ptr = 0; - int typeId = 0; - - asIScriptFunction *func = ctx->GetFunction(); - if( !func ) return; - - // We start from the end, in case the same name is reused in different scopes - for( asUINT n = func->GetVarCount(); n-- > 0; ) - { - if( ctx->IsVarInScope(n) && name == ctx->GetVarName(n) ) - { - ptr = ctx->GetAddressOfVar(n); - typeId = ctx->GetVarTypeId(n); - break; - } - } - - // Look for class members, if we're in a class method - if( !ptr && func->GetObjectType() ) - { - if( name == "this" ) - { - ptr = ctx->GetThisPointer(); - typeId = ctx->GetThisTypeId(); - } - else - { - asIObjectType *type = engine->GetObjectTypeById(ctx->GetThisTypeId()); - for( asUINT n = 0; n < type->GetPropertyCount(); n++ ) - { - const char *propName = 0; - int offset = 0; - bool isReference = 0; - type->GetProperty(n, &propName, &typeId, 0, &offset, &isReference); - if( name == propName ) - { - ptr = (void*)(((asBYTE*)ctx->GetThisPointer())+offset); - if( isReference ) ptr = *(void**)ptr; - break; - } - } - } - } - - // Look for global variables - if( !ptr ) - { - asIScriptModule *mod = func->GetModule(); - if( mod ) - { - for( asUINT n = 0; n < mod->GetGlobalVarCount(); n++ ) - { - // TODO: Handle namespace too - const char *varName = 0, *nameSpace = 0; - mod->GetGlobalVar(n, &varName, &nameSpace, &typeId); - if( name == varName ) - { - ptr = mod->GetAddressOfGlobalVar(n); - break; - } - } - } - } - - if( ptr ) - { - // TODO: If there is a . after the identifier, check for members - - stringstream s; - s << ToString(ptr, typeId, true, engine) << endl; - Output(s.str()); - } - } - else - { - Output("Invalid expression. Expected identifier\n"); - } -} - -void CDebugger::ListBreakPoints() -{ - // List all break points - stringstream s; - for( size_t b = 0; b < m_breakPoints.size(); b++ ) - if( m_breakPoints[b].func ) - s << b << " - " << m_breakPoints[b].name << endl; - else - s << b << " - " << m_breakPoints[b].name << ":" << m_breakPoints[b].lineNbr << endl; - Output(s.str()); -} - -void CDebugger::ListMemberProperties(asIScriptContext *ctx) -{ - if( ctx == 0 ) - { - Output("No script is running\n"); - return; - } - - void *ptr = ctx->GetThisPointer(); - if( ptr ) - { - stringstream s; - s << "this = " << ToString(ptr, ctx->GetThisTypeId(), true, ctx->GetEngine()) << endl; - Output(s.str()); - } -} - -void CDebugger::ListLocalVariables(asIScriptContext *ctx) -{ - if( ctx == 0 ) - { - Output("No script is running\n"); - return; - } - - asIScriptFunction *func = ctx->GetFunction(); - if( !func ) return; - - stringstream s; - for( asUINT n = 0; n < func->GetVarCount(); n++ ) - { - if( ctx->IsVarInScope(n) ) - s << func->GetVarDecl(n) << " = " << ToString(ctx->GetAddressOfVar(n), ctx->GetVarTypeId(n), false, ctx->GetEngine()) << endl; - } - Output(s.str()); -} - -void CDebugger::ListGlobalVariables(asIScriptContext *ctx) -{ - if( ctx == 0 ) - { - Output("No script is running\n"); - return; - } - - // Determine the current module from the function - asIScriptFunction *func = ctx->GetFunction(); - if( !func ) return; - - asIScriptModule *mod = func->GetModule(); - if( !mod ) return; - - stringstream s; - for( asUINT n = 0; n < mod->GetGlobalVarCount(); n++ ) - { - int typeId = 0; - mod->GetGlobalVar(n, 0, 0, &typeId); - s << mod->GetGlobalVarDeclaration(n) << " = " << ToString(mod->GetAddressOfGlobalVar(n), typeId, false, ctx->GetEngine()) << endl; - } - Output(s.str()); -} - -void CDebugger::ListStatistics(asIScriptContext *ctx) -{ - if( ctx == 0 ) - { - Output("No script is running\n"); - return; - } - - asIScriptEngine *engine = ctx->GetEngine(); - - asUINT gcCurrSize, gcTotalDestr, gcTotalDet, gcNewObjects, gcTotalNewDestr; - engine->GetGCStatistics(&gcCurrSize, &gcTotalDestr, &gcTotalDet, &gcNewObjects, &gcTotalNewDestr); - - stringstream s; - s << "Garbage collector:" << endl; - s << " current size: " << gcCurrSize << endl; - s << " total destroyed: " << gcTotalDestr << endl; - s << " total detected: " << gcTotalDet << endl; - s << " new objects: " << gcNewObjects << endl; - s << " new objects destroyed: " << gcTotalNewDestr << endl; - - Output(s.str()); -} - -void CDebugger::PrintCallstack(asIScriptContext *ctx) -{ - if( ctx == 0 ) - { - Output("No script is running\n"); - return; - } - - stringstream s; - const char *file = 0; - int lineNbr = 0; - for( asUINT n = 0; n < ctx->GetCallstackSize(); n++ ) - { - lineNbr = ctx->GetLineNumber(n, 0, &file); - s << file << ":" << lineNbr << "; " << ctx->GetFunction(n)->GetDeclaration() << endl; - } - Output(s.str()); -} - -void CDebugger::AddFuncBreakPoint(const string &func) -{ - // Trim the function name - size_t b = func.find_first_not_of(" \t"); - size_t e = func.find_last_not_of(" \t"); - string actual = func.substr(b, e != string::npos ? e-b+1 : string::npos); - - stringstream s; - s << "Adding deferred break point for function '" << actual << "'" << endl; - Output(s.str()); - - BreakPoint bp(actual, 0, true); - m_breakPoints.push_back(bp); -} - -void CDebugger::AddFileBreakPoint(const string &file, int lineNbr) -{ - // Store just file name, not entire path - size_t r = file.find_last_of("\\/"); - string actual; - if( r != string::npos ) - actual = file.substr(r+1); - else - actual = file; - - // Trim the file name - size_t b = actual.find_first_not_of(" \t"); - size_t e = actual.find_last_not_of(" \t"); - actual = actual.substr(b, e != string::npos ? e-b+1 : string::npos); - - stringstream s; - s << "Setting break point in file '" << actual << "' at line " << lineNbr << endl; - Output(s.str()); - - BreakPoint bp(actual, lineNbr, false); - m_breakPoints.push_back(bp); -} - -void CDebugger::PrintHelp() -{ - Output("c - Continue\n" - "s - Step into\n" - "n - Next step\n" - "o - Step out\n" - "b - Set break point\n" - "l - List various things\n" - "r - Remove break point\n" - "p - Print value\n" - "w - Where am I?\n" - "a - Abort execution\n" - "h - Print this help text\n"); -} - -void CDebugger::Output(const string &str) -{ - // By default we just output to stdout - cout << str; -} - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/add_on/debugger/debugger.h b/dependencies/angelscript/add_on/debugger/debugger.h deleted file mode 100644 index fc212b3a..00000000 --- a/dependencies/angelscript/add_on/debugger/debugger.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef DEBUGGER_H -#define DEBUGGER_H - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -#include -#include -#include - -BEGIN_AS_NAMESPACE - -class CDebugger -{ -public: - CDebugger(); - virtual ~CDebugger(); - - // Register callbacks to handle to-string conversions of application types - typedef std::string (*ToStringCallback)(void *obj, bool expandMembers, CDebugger *dbg); - virtual void RegisterToStringCallback(const asIObjectType *ot, ToStringCallback callback); - - // User interaction - virtual void TakeCommands(asIScriptContext *ctx); - virtual void Output(const std::string &str); - - // Line callback invoked by context - virtual void LineCallback(asIScriptContext *ctx); - - // Commands - virtual void PrintHelp(); - virtual void AddFileBreakPoint(const std::string &file, int lineNbr); - virtual void AddFuncBreakPoint(const std::string &func); - virtual void ListBreakPoints(); - virtual void ListLocalVariables(asIScriptContext *ctx); - virtual void ListGlobalVariables(asIScriptContext *ctx); - virtual void ListMemberProperties(asIScriptContext *ctx); - virtual void ListStatistics(asIScriptContext *ctx); - virtual void PrintCallstack(asIScriptContext *ctx); - virtual void PrintValue(const std::string &expr, asIScriptContext *ctx); - - // Helpers - virtual bool InterpretCommand(const std::string &cmd, asIScriptContext *ctx); - virtual bool CheckBreakPoint(asIScriptContext *ctx); - virtual std::string ToString(void *value, asUINT typeId, bool expandMembers, asIScriptEngine *engine); - -protected: - enum DebugAction - { - CONTINUE, // continue until next break point - STEP_INTO, // stop at next instruction - STEP_OVER, // stop at next instruction, skipping called functions - STEP_OUT // run until returning from current function - }; - DebugAction m_action; - asUINT m_lastCommandAtStackLevel; - asIScriptFunction *m_lastFunction; - - struct BreakPoint - { - BreakPoint(std::string f, int n, bool _func) : name(f), lineNbr(n), func(_func), needsAdjusting(true) {} - std::string name; - int lineNbr; - bool func; - bool needsAdjusting; - }; - std::vector m_breakPoints; - - // Registered callbacks for converting objects to strings - std::map m_toStringCallbacks; -}; - -END_AS_NAMESPACE - -#endif \ No newline at end of file diff --git a/dependencies/angelscript/add_on/scriptfile/scriptfile.cpp b/dependencies/angelscript/add_on/scriptfile/scriptfile.cpp deleted file mode 100644 index c3ab612a..00000000 --- a/dependencies/angelscript/add_on/scriptfile/scriptfile.cpp +++ /dev/null @@ -1,661 +0,0 @@ -#include "scriptfile.h" -#include -#include -#include -#include -#include - -#ifdef _WIN32_WCE -#include // For GetModuleFileName -#ifdef GetObject -#undef GetObject -#endif -#endif - -using namespace std; - -BEGIN_AS_NAMESPACE - -CScriptFile *ScriptFile_Factory() -{ - return new CScriptFile(); -} - -void ScriptFile_Factory_Generic(asIScriptGeneric *gen) -{ - *(CScriptFile**)gen->GetAddressOfReturnLocation() = ScriptFile_Factory(); -} - -void ScriptFile_AddRef_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - file->AddRef(); -} - -void ScriptFile_Release_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - file->Release(); -} - -void ScriptFile_Open_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - std::string *f = (std::string*)gen->GetArgAddress(0); - std::string *m = (std::string*)gen->GetArgAddress(1); - int r = file->Open(*f, *m); - gen->SetReturnDWord(r); -} - -void ScriptFile_Close_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - int r = file->Close(); - gen->SetReturnDWord(r); -} - -void ScriptFile_GetSize_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - int r = file->GetSize(); - gen->SetReturnDWord(r); -} - -void ScriptFile_ReadString_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - int len = gen->GetArgDWord(0); - std::string *str = (std::string*)gen->GetArgAddress(1); - len = file->ReadString(len, *str); - gen->SetReturnDWord(len); -} - -void ScriptFile_ReadLine_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - std::string *str = (std::string*)gen->GetArgAddress(0); - int len = file->ReadLine(*str); - gen->SetReturnDWord(len); -} - -void ScriptFile_ReadInt_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - asUINT bytes = *(asUINT*)gen->GetAddressOfArg(0); - *(asINT64*)gen->GetAddressOfReturnLocation() = file->ReadInt(bytes); -} - -void ScriptFile_ReadUInt_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - asUINT bytes = *(asUINT*)gen->GetAddressOfArg(0); - *(asQWORD*)gen->GetAddressOfReturnLocation() = file->ReadUInt(bytes); -} - -void ScriptFile_ReadFloat_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - *(float*)gen->GetAddressOfReturnLocation() = file->ReadFloat(); -} - -void ScriptFile_ReadDouble_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - *(double*)gen->GetAddressOfReturnLocation() = file->ReadDouble(); -} - -void ScriptFile_WriteString_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - std::string *str = (std::string*)gen->GetArgAddress(0); - gen->SetReturnDWord(file->WriteString(*str)); -} - -void ScriptFile_WriteInt_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - asINT64 val = *(asINT64*)gen->GetAddressOfArg(0); - asUINT bytes = *(asUINT*)gen->GetAddressOfArg(1); - *(int*)gen->GetAddressOfReturnLocation() = file->WriteInt(val, bytes); -} - -void ScriptFile_WriteUInt_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - asQWORD val = *(asQWORD*)gen->GetAddressOfArg(0); - asUINT bytes = *(asUINT*)gen->GetAddressOfArg(1); - *(int*)gen->GetAddressOfReturnLocation() = file->WriteUInt(val, bytes); -} - -void ScriptFile_WriteFloat_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - float val = *(float*)gen->GetAddressOfArg(0); - *(int*)gen->GetAddressOfReturnLocation() = file->WriteFloat(val); -} - -void ScriptFile_WriteDouble_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - double val = *(double*)gen->GetAddressOfArg(0); - *(int*)gen->GetAddressOfReturnLocation() = file->WriteDouble(val); -} - -void ScriptFile_IsEOF_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - bool r = file->IsEOF(); - gen->SetReturnByte(r); -} - -void ScriptFile_GetPos_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - gen->SetReturnDWord(file->GetPos()); -} - -void ScriptFile_SetPos_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - int pos = (int)gen->GetArgDWord(0); - gen->SetReturnDWord(file->SetPos(pos)); -} - -void ScriptFile_MovePos_Generic(asIScriptGeneric *gen) -{ - CScriptFile *file = (CScriptFile*)gen->GetObject(); - int delta = (int)gen->GetArgDWord(0); - gen->SetReturnDWord(file->MovePos(delta)); -} - -void RegisterScriptFile_Native(asIScriptEngine *engine) -{ - int r; - - r = engine->RegisterObjectType("file", 0, asOBJ_REF); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("file", asBEHAVE_FACTORY, "file @f()", asFUNCTION(ScriptFile_Factory), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("file", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptFile,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("file", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptFile,Release), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("file", "int open(const string &in, const string &in)", asMETHOD(CScriptFile,Open), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int close()", asMETHOD(CScriptFile,Close), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int getSize() const", asMETHOD(CScriptFile,GetSize), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "bool isEndOfFile() const", asMETHOD(CScriptFile,IsEOF), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int readString(uint, string &out)", asMETHOD(CScriptFile,ReadString), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int readLine(string &out)", asMETHOD(CScriptFile,ReadLine), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int64 readInt(uint)", asMETHOD(CScriptFile,ReadInt), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "uint64 readUInt(uint)", asMETHOD(CScriptFile,ReadUInt), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "float readFloat()", asMETHOD(CScriptFile,ReadFloat), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "double readDouble()", asMETHOD(CScriptFile,ReadDouble), asCALL_THISCALL); assert( r >= 0 ); -#if AS_WRITE_OPS == 1 - r = engine->RegisterObjectMethod("file", "int writeString(const string &in)", asMETHOD(CScriptFile,WriteString), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int writeInt(int64, uint)", asMETHOD(CScriptFile,WriteInt), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int writeUInt(uint64, uint)", asMETHOD(CScriptFile,WriteUInt), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int writeFloat(float)", asMETHOD(CScriptFile,WriteFloat), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int writeDouble(double)", asMETHOD(CScriptFile,WriteDouble), asCALL_THISCALL); assert( r >= 0 ); -#endif - r = engine->RegisterObjectMethod("file", "int getPos() const", asMETHOD(CScriptFile,GetPos), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int setPos(int)", asMETHOD(CScriptFile,SetPos), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int movePos(int)", asMETHOD(CScriptFile,MovePos), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectProperty("file", "bool mostSignificantByteFirst", asOFFSET(CScriptFile, mostSignificantByteFirst)); assert( r >= 0 ); -} - -void RegisterScriptFile_Generic(asIScriptEngine *engine) -{ - int r; - - r = engine->RegisterObjectType("file", 0, asOBJ_REF); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("file", asBEHAVE_FACTORY, "file @f()", asFUNCTION(ScriptFile_Factory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("file", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFile_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("file", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFile_Release_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("file", "int open(const string &in, const string &in)", asFUNCTION(ScriptFile_Open_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int close()", asFUNCTION(ScriptFile_Close_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int getSize() const", asFUNCTION(ScriptFile_GetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "bool isEndOfFile() const", asFUNCTION(ScriptFile_IsEOF_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int readString(uint, string &out)", asFUNCTION(ScriptFile_ReadString_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int readLine(string &out)", asFUNCTION(ScriptFile_ReadLine_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int64 readInt(uint)", asFUNCTION(ScriptFile_ReadInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "uint64 readUInt(uint)", asFUNCTION(ScriptFile_ReadUInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "float readFloat()", asFUNCTION(ScriptFile_ReadFloat_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "double readDouble()", asFUNCTION(ScriptFile_ReadDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); -#if AS_WRITE_OPS == 1 - r = engine->RegisterObjectMethod("file", "int writeString(const string &in)", asFUNCTION(ScriptFile_WriteString_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int writeInt(int64, uint)", asFUNCTION(ScriptFile_WriteInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int writeUInt(uint64, uint)", asFUNCTION(ScriptFile_WriteUInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int writeFloat(float)", asFUNCTION(ScriptFile_WriteFloat_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int writeDouble(double)", asFUNCTION(ScriptFile_WriteDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); -#endif - r = engine->RegisterObjectMethod("file", "int getPos() const", asFUNCTION(ScriptFile_GetPos_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int setPos(int)", asFUNCTION(ScriptFile_SetPos_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "int movePos(int)", asFUNCTION(ScriptFile_MovePos_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectProperty("file", "bool mostSignificantByteFirst", asOFFSET(CScriptFile, mostSignificantByteFirst)); assert( r >= 0 ); -} - -void RegisterScriptFile(asIScriptEngine *engine) -{ - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptFile_Generic(engine); - else - RegisterScriptFile_Native(engine); -} - -CScriptFile::CScriptFile() -{ - refCount = 1; - file = 0; - mostSignificantByteFirst = false; -} - -CScriptFile::~CScriptFile() -{ - Close(); -} - -void CScriptFile::AddRef() const -{ - asAtomicInc(refCount); -} - -void CScriptFile::Release() const -{ - if( asAtomicDec(refCount) == 0 ) - delete this; -} - -int CScriptFile::Open(const std::string &filename, const std::string &mode) -{ - // Close the previously opened file handle - if( file ) - Close(); - - std::string myFilename = filename; - - // Validate the mode - string m; -#if AS_WRITE_OPS == 1 - if( mode != "r" && mode != "w" && mode != "a" ) -#else - if( mode != "r" ) -#endif - return -1; - else - m = mode; - -#ifdef _WIN32_WCE - // no relative pathing on CE - char buf[MAX_PATH]; - static TCHAR apppath[MAX_PATH] = TEXT(""); - if (!apppath[0]) - { - GetModuleFileName(NULL, apppath, MAX_PATH); - - int appLen = _tcslen(apppath); - while (appLen > 1) - { - if (apppath[appLen-1] == TEXT('\\')) - break; - appLen--; - } - - // Terminate the string after the trailing backslash - apppath[appLen] = TEXT('\0'); - } -#ifdef _UNICODE - wcstombs(buf, apppath, wcslen(apppath)+1); -#else - memcpy(buf, apppath, strlen(apppath)); -#endif - myFilename = buf + myFilename; -#endif - - - // By default windows translates "\r\n" to "\n", but we want to read the file as-is. - m += "b"; - - // Open the file -#if _MSC_VER >= 1400 && !defined(__S3E__) - // MSVC 8.0 / 2005 introduced new functions - // Marmalade doesn't use these, even though it uses the MSVC compiler - fopen_s(&file, myFilename.c_str(), m.c_str()); -#else - file = fopen(myFilename.c_str(), m.c_str()); -#endif - if( file == 0 ) - return -1; - - return 0; -} - -int CScriptFile::Close() -{ - if( file == 0 ) - return -1; - - fclose(file); - file = 0; - - return 0; -} - -int CScriptFile::GetSize() const -{ - if( file == 0 ) - return -1; - - int pos = ftell(file); - fseek(file, 0, SEEK_END); - int size = ftell(file); - fseek(file, pos, SEEK_SET); - - return size; -} - -int CScriptFile::GetPos() const -{ - if( file == 0 ) - return -1; - - return ftell(file); -} - -int CScriptFile::SetPos(int pos) -{ - if( file == 0 ) - return -1; - - int r = fseek(file, pos, SEEK_SET); - - // Return -1 on error - return r ? -1 : 0; -} - -int CScriptFile::MovePos(int delta) -{ - if( file == 0 ) - return -1; - - int r = fseek(file, delta, SEEK_CUR); - - // Return -1 on error - return r ? -1 : 0; -} - -int CScriptFile::ReadString(unsigned int length, std::string &str) -{ - if( file == 0 ) - return 0; - - // Read the string - str.resize(length); - int size = (int)fread(&str[0], 1, length, file); - str.resize(size); - - return size; -} - -int CScriptFile::ReadLine(std::string &str) -{ - if( file == 0 ) - return 0; - - // Read until the first new-line character - str = ""; - char buf[256]; - - do - { - // Get the current position so we can determine how many characters were read - int start = ftell(file); - - // Set the last byte to something different that 0, so that we can check if the buffer was filled up - buf[255] = 1; - - // Read the line (or first 255 characters, which ever comes first) - char *r = fgets(buf, 256, file); - if( r == 0 ) break; - - // Get the position after the read - int end = ftell(file); - - // Add the read characters to the output buffer - str.append(buf, end-start); - } - while( !feof(file) && buf[255] == 0 && buf[254] != '\n' ); - - return int(str.size()); -} - -asINT64 CScriptFile::ReadInt(asUINT bytes) -{ - if( file == 0 ) - return 0; - - if( bytes > 8 ) bytes = 8; - if( bytes == 0 ) return 0; - - unsigned char buf[8]; - size_t r = fread(buf, bytes, 1, file); - if( r == 0 ) return 0; - - asINT64 val = 0; - if( mostSignificantByteFirst ) - { - unsigned int n = 0; - for( ; n < bytes; n++ ) - val |= asQWORD(buf[n]) << ((bytes-n-1)*8); - - // Check the most significant byte to determine if the rest - // of the qword must be filled to give a negative value - if( buf[0] & 0x80 ) - for( ; n < 8; n++ ) - val |= asQWORD(0xFF) << (n*8); - } - else - { - unsigned int n = 0; - for( ; n < bytes; n++ ) - val |= asQWORD(buf[n]) << (n*8); - - // Check the most significant byte to determine if the rest - // of the qword must be filled to give a negative value - if( buf[bytes-1] & 0x80 ) - for( ; n < 8; n++ ) - val |= asQWORD(0xFF) << (n*8); - } - - return val; -} - -asQWORD CScriptFile::ReadUInt(asUINT bytes) -{ - if( file == 0 ) - return 0; - - if( bytes > 8 ) bytes = 8; - if( bytes == 0 ) return 0; - - unsigned char buf[8]; - size_t r = fread(buf, bytes, 1, file); - if( r == 0 ) return 0; - - asQWORD val = 0; - if( mostSignificantByteFirst ) - { - unsigned int n = 0; - for( ; n < bytes; n++ ) - val |= asQWORD(buf[n]) << ((bytes-n-1)*8); - } - else - { - unsigned int n = 0; - for( ; n < bytes; n++ ) - val |= asQWORD(buf[n]) << (n*8); - } - - return val; -} - -float CScriptFile::ReadFloat() -{ - if( file == 0 ) - return 0; - - unsigned char buf[4]; - size_t r = fread(buf, 4, 1, file); - if( r == 0 ) return 0; - - asUINT val = 0; - if( mostSignificantByteFirst ) - { - unsigned int n = 0; - for( ; n < 4; n++ ) - val |= asUINT(buf[n]) << ((3-n)*8); - } - else - { - unsigned int n = 0; - for( ; n < 4; n++ ) - val |= asUINT(buf[n]) << (n*8); - } - - return *reinterpret_cast(&val); -} - -double CScriptFile::ReadDouble() -{ - if( file == 0 ) - return 0; - - unsigned char buf[8]; - size_t r = fread(buf, 8, 1, file); - if( r == 0 ) return 0; - - asQWORD val = 0; - if( mostSignificantByteFirst ) - { - unsigned int n = 0; - for( ; n < 8; n++ ) - val |= asQWORD(buf[n]) << ((7-n)*8); - } - else - { - unsigned int n = 0; - for( ; n < 8; n++ ) - val |= asQWORD(buf[n]) << (n*8); - } - - return *reinterpret_cast(&val); -} - -bool CScriptFile::IsEOF() const -{ - if( file == 0 ) - return true; - - return feof(file) ? true : false; -} - -#if AS_WRITE_OPS == 1 -int CScriptFile::WriteString(const std::string &str) -{ - if( file == 0 ) - return -1; - - // Write the entire string - size_t r = fwrite(&str[0], 1, str.length(), file); - - return int(r); -} - -int CScriptFile::WriteInt(asINT64 val, asUINT bytes) -{ - if( file == 0 ) - return 0; - - unsigned char buf[8]; - if( mostSignificantByteFirst ) - { - for( unsigned int n = 0; n < bytes; n++ ) - buf[n] = (val >> ((bytes-n-1)*8)) & 0xFF; - } - else - { - for( unsigned int n = 0; n < bytes; n++ ) - buf[n] = (val >> (n*8)) & 0xFF; - } - - size_t r = fwrite(&buf, bytes, 1, file); - return int(r); -} - -int CScriptFile::WriteUInt(asQWORD val, asUINT bytes) -{ - if( file == 0 ) - return 0; - - unsigned char buf[8]; - if( mostSignificantByteFirst ) - { - for( unsigned int n = 0; n < bytes; n++ ) - buf[n] = (val >> ((bytes-n-1)*8)) & 0xFF; - } - else - { - for( unsigned int n = 0; n < bytes; n++ ) - buf[n] = (val >> (n*8)) & 0xFF; - } - - size_t r = fwrite(&buf, bytes, 1, file); - return int(r); -} - -int CScriptFile::WriteFloat(float f) -{ - if( file == 0 ) - return 0; - - unsigned char buf[4]; - asUINT val = *reinterpret_cast(&f); - if( mostSignificantByteFirst ) - { - for( unsigned int n = 0; n < 4; n++ ) - buf[n] = (val >> ((3-n)*4)) & 0xFF; - } - else - { - for( unsigned int n = 0; n < 4; n++ ) - buf[n] = (val >> (n*8)) & 0xFF; - } - - size_t r = fwrite(&buf, 4, 1, file); - return int(r); -} - -int CScriptFile::WriteDouble(double d) -{ - if( file == 0 ) - return 0; - - unsigned char buf[8]; - asQWORD val = *reinterpret_cast(&d); - if( mostSignificantByteFirst ) - { - for( unsigned int n = 0; n < 8; n++ ) - buf[n] = (val >> ((7-n)*8)) & 0xFF; - } - else - { - for( unsigned int n = 0; n < 8; n++ ) - buf[n] = (val >> (n*8)) & 0xFF; - } - - size_t r = fwrite(&buf, 8, 1, file); - return int(r); -} -#endif - - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/add_on/scriptfile/scriptfile.h b/dependencies/angelscript/add_on/scriptfile/scriptfile.h deleted file mode 100644 index ec4c13f2..00000000 --- a/dependencies/angelscript/add_on/scriptfile/scriptfile.h +++ /dev/null @@ -1,101 +0,0 @@ -// -// CScriptFile -// -// This class encapsulates a FILE pointer in a reference counted class for -// use within AngelScript. -// - -#ifndef SCRIPTFILE_H -#define SCRIPTFILE_H - -//--------------------------- -// Compilation settings -// - -// Set this flag to turn on/off write support -// 0 = off -// 1 = on - -#ifndef AS_WRITE_OPS -#define AS_WRITE_OPS 1 -#endif - - - - -//--------------------------- -// Declaration -// - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -#include -#include - -BEGIN_AS_NAMESPACE - -class CScriptFile -{ -public: - CScriptFile(); - - void AddRef() const; - void Release() const; - - // TODO: Implement the "r+", "w+" and "a+" modes - // mode = "r" -> open the file for reading - // "w" -> open the file for writing (overwrites existing file) - // "a" -> open the file for appending - int Open(const std::string &filename, const std::string &mode); - int Close(); - int GetSize() const; - bool IsEOF() const; - - // Reading - int ReadString(unsigned int length, std::string &str); - int ReadLine(std::string &str); - asINT64 ReadInt(asUINT bytes); - asQWORD ReadUInt(asUINT bytes); - float ReadFloat(); - double ReadDouble(); - - // Writing - int WriteString(const std::string &str); - int WriteInt(asINT64 v, asUINT bytes); - int WriteUInt(asQWORD v, asUINT bytes); - int WriteFloat(float v); - int WriteDouble(double v); - - // Cursor - int GetPos() const; - int SetPos(int pos); - int MovePos(int delta); - - // Big-endian = most significant byte first - bool mostSignificantByteFirst; - -protected: - ~CScriptFile(); - - mutable int refCount; - FILE *file; -}; - -// This function will determine the configuration of the engine -// and use one of the two functions below to register the file type -void RegisterScriptFile(asIScriptEngine *engine); - -// Call this function to register the file type -// using native calling conventions -void RegisterScriptFile_Native(asIScriptEngine *engine); - -// Use this one instead if native calling conventions -// are not supported on the target platform -void RegisterScriptFile_Generic(asIScriptEngine *engine); - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/add_on/scriptgrid/scriptgrid.cpp b/dependencies/angelscript/add_on/scriptgrid/scriptgrid.cpp deleted file mode 100644 index b96535d5..00000000 --- a/dependencies/angelscript/add_on/scriptgrid/scriptgrid.cpp +++ /dev/null @@ -1,786 +0,0 @@ -#include -#include -#include -#include -#include // sprintf - -#include "scriptgrid.h" - -using namespace std; - -BEGIN_AS_NAMESPACE - -// Set the default memory routines -// Use the angelscript engine's memory routines by default -static asALLOCFUNC_t userAlloc = asAllocMem; -static asFREEFUNC_t userFree = asFreeMem; - -// Allows the application to set which memory routines should be used by the array object -void CScriptGrid::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) -{ - userAlloc = allocFunc; - userFree = freeFunc; -} - -static void RegisterScriptGrid_Native(asIScriptEngine *engine); - -struct SGridBuffer -{ - asDWORD width; - asDWORD height; - asBYTE data[1]; -}; - -CScriptGrid *CScriptGrid::Create(asIObjectType *ot) -{ - return CScriptGrid::Create(ot, 0, 0); -} - -CScriptGrid *CScriptGrid::Create(asIObjectType *ot, asUINT w, asUINT h) -{ - asIScriptContext *ctx = asGetActiveContext(); - - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptGrid)); - if( mem == 0 ) - { - if( ctx ) - ctx->SetException("Out of memory"); - - return 0; - } - - // Initialize the object - CScriptGrid *a = new(mem) CScriptGrid(w, h, ot); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } - - return a; -} - -CScriptGrid *CScriptGrid::Create(asIObjectType *ot, void *initList) -{ - asIScriptContext *ctx = asGetActiveContext(); - - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptGrid)); - if( mem == 0 ) - { - if( ctx ) - ctx->SetException("Out of memory"); - - return 0; - } - - // Initialize the object - CScriptGrid *a = new(mem) CScriptGrid(ot, initList); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } - - return a; -} - -CScriptGrid *CScriptGrid::Create(asIObjectType *ot, asUINT w, asUINT h, void *defVal) -{ - asIScriptContext *ctx = asGetActiveContext(); - - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptGrid)); - if( mem == 0 ) - { - if( ctx ) - ctx->SetException("Out of memory"); - - return 0; - } - - // Initialize the object - CScriptGrid *a = new(mem) CScriptGrid(w, h, defVal, ot); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } - - return a; -} - -// This optional callback is called when the template type is first used by the compiler. -// It allows the application to validate if the template can be instantiated for the requested -// subtype at compile time, instead of at runtime. The output argument dontGarbageCollect -// allow the callback to tell the engine if the template instance type shouldn't be garbage collected, -// i.e. no asOBJ_GC flag. -static bool ScriptGridTemplateCallback(asIObjectType *ot, bool &dontGarbageCollect) -{ - // Make sure the subtype can be instantiated with a default factory/constructor, - // otherwise we won't be able to instantiate the elements. - int typeId = ot->GetSubTypeId(); - if( typeId == asTYPEID_VOID ) - return false; - if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) - { - asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId); - asDWORD flags = subtype->GetFlags(); - if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) ) - { - // Verify that there is a default constructor - bool found = false; - for( asUINT n = 0; n < subtype->GetBehaviourCount(); n++ ) - { - asEBehaviours beh; - asIScriptFunction *func = subtype->GetBehaviourByIndex(n, &beh); - if( beh != asBEHAVE_CONSTRUCT ) continue; - - if( func->GetParamCount() == 0 ) - { - // Found the default constructor - found = true; - break; - } - } - - if( !found ) - { - // There is no default constructor - ot->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); - return false; - } - } - else if( (flags & asOBJ_REF) ) - { - bool found = false; - - // If value assignment for ref type has been disabled then the array - // can be created if the type has a default factory function - if( !ot->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) - { - // Verify that there is a default factory - for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) - { - asIScriptFunction *func = subtype->GetFactoryByIndex(n); - if( func->GetParamCount() == 0 ) - { - // Found the default factory - found = true; - break; - } - } - } - - if( !found ) - { - // No default factory - ot->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); - return false; - } - } - - // If the object type is not garbage collected then the array also doesn't need to be - if( !(flags & asOBJ_GC) ) - dontGarbageCollect = true; - } - else if( !(typeId & asTYPEID_OBJHANDLE) ) - { - // Arrays with primitives cannot form circular references, - // thus there is no need to garbage collect them - dontGarbageCollect = true; - } - - // The type is ok - return true; -} - -// Registers the template array type -void RegisterScriptGrid(asIScriptEngine *engine) -{ - // TODO: Implement the generic calling convention - RegisterScriptGrid_Native(engine); -} - -static void RegisterScriptGrid_Native(asIScriptEngine *engine) -{ - int r; - - // Register the grid type as a template - r = engine->RegisterObjectType("grid", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); - - // Register a callback for validating the subtype before it is used - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptGridTemplateCallback), asCALL_CDECL); assert( r >= 0 ); - - // Templates receive the object type as the first parameter. To the script writer this is hidden - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_FACTORY, "grid@ f(int&in)", asFUNCTIONPR(CScriptGrid::Create, (asIObjectType*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_FACTORY, "grid@ f(int&in, uint, uint)", asFUNCTIONPR(CScriptGrid::Create, (asIObjectType*, asUINT, asUINT), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_FACTORY, "grid@ f(int&in, uint, uint, const T &in)", asFUNCTIONPR(CScriptGrid::Create, (asIObjectType*, asUINT, asUINT, void *), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); - - // Register the factory that will be used for initialization lists - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_LIST_FACTORY, "grid@ f(int&in type, int&in list) {repeat {repeat_same T}}", asFUNCTIONPR(CScriptGrid::Create, (asIObjectType*, void*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); - - // The memory management methods - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptGrid,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptGrid,Release), asCALL_THISCALL); assert( r >= 0 ); - - // The index operator returns the template subtype - r = engine->RegisterObjectMethod("grid", "T &opIndex(uint, uint)", asMETHODPR(CScriptGrid, At, (asUINT, asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("grid", "const T &opIndex(uint, uint) const", asMETHODPR(CScriptGrid, At, (asUINT, asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); - - // Other methods - r = engine->RegisterObjectMethod("grid", "void resize(uint width, uint height)", asMETHODPR(CScriptGrid, Resize, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("grid", "uint width() const", asMETHOD(CScriptGrid, GetWidth), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("grid", "uint height() const", asMETHOD(CScriptGrid, GetHeight), asCALL_THISCALL); assert( r >= 0 ); - - // Register GC behaviours in case the array needs to be garbage collected - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptGrid, GetRefCount), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptGrid, SetFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptGrid, GetFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptGrid, EnumReferences), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptGrid, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); -} - -CScriptGrid::CScriptGrid(asIObjectType *ot, void *buf) -{ - refCount = 1; - gcFlag = false; - objType = ot; - objType->AddRef(); - buffer = 0; - subTypeId = objType->GetSubTypeId(); - - asIScriptEngine *engine = ot->GetEngine(); - - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = engine->GetSizeOfPrimitiveType(subTypeId); - - // Determine the initial size from the buffer - asUINT height = *(asUINT*)buf; - asUINT width = *(asUINT*)((char*)(buf)+4); - - // Make sure the grid size isn't too large for us to handle - if( !CheckMaxSize(width, height) ) - { - // Don't continue with the initialization - return; - } - - // Skip the height value at the start of the buffer - buf = (asUINT*)(buf)+1; - - // Copy the values of the grid elements from the buffer - if( (ot->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) - { - CreateBuffer(&buffer, width, height); - - // Copy the values of the primitive type into the internal buffer - for( asUINT y = 0; y < height; y++ ) - { - // Skip the length value at the start of each row - buf = (asUINT*)(buf)+1; - - // Copy the line - if( width > 0 ) - memcpy(At(0,y), buf, width*elementSize); - - // Move to next line - buf = (char*)(buf) + width*elementSize; - - // Align to 4 byte boundary - if( asPWORD(buf) & 0x3 ) - buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3); - } - } - else if( ot->GetSubTypeId() & asTYPEID_OBJHANDLE ) - { - CreateBuffer(&buffer, width, height); - - // Copy the handles into the internal buffer - for( asUINT y = 0; y < height; y++ ) - { - // Skip the length value at the start of each row - buf = (asUINT*)(buf)+1; - - // Copy the line - if( width > 0 ) - memcpy(At(0,y), buf, width*elementSize); - - // With object handles it is safe to clear the memory in the received buffer - // instead of increasing the ref count. It will save time both by avoiding the - // call the increase ref, and also relieve the engine from having to release - // its references too - memset(buf, 0, width*elementSize); - - // Move to next line - buf = (char*)(buf) + width*elementSize; - - // Align to 4 byte boundary - if( asPWORD(buf) & 0x3 ) - buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3); - } - } - else if( ot->GetSubType()->GetFlags() & asOBJ_REF ) - { - // Only allocate the buffer, but not the objects - subTypeId |= asTYPEID_OBJHANDLE; - CreateBuffer(&buffer, width, height); - subTypeId &= ~asTYPEID_OBJHANDLE; - - // Copy the handles into the internal buffer - for( asUINT y = 0; y < height; y++ ) - { - // Skip the length value at the start of each row - buf = (asUINT*)(buf)+1; - - // Copy the line - if( width > 0 ) - memcpy(At(0,y), buf, width*elementSize); - - // With object handles it is safe to clear the memory in the received buffer - // instead of increasing the ref count. It will save time both by avoiding the - // call the increase ref, and also relieve the engine from having to release - // its references too - memset(buf, 0, width*elementSize); - - // Move to next line - buf = (char*)(buf) + width*elementSize; - - // Align to 4 byte boundary - if( asPWORD(buf) & 0x3 ) - buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3); - } - } - else - { - // TODO: Optimize by calling the copy constructor of the object instead of - // constructing with the default constructor and then assigning the value - // TODO: With C++11 ideally we should be calling the move constructor, instead - // of the copy constructor as the engine will just discard the objects in the - // buffer afterwards. - CreateBuffer(&buffer, width, height); - - // For value types we need to call the opAssign for each individual object - asIObjectType *subType = ot->GetSubType(); - asUINT subTypeSize = subType->GetSize(); - for( asUINT y = 0;y < height; y++ ) - { - // Skip the length value at the start of each row - buf = (asUINT*)(buf)+1; - - // Call opAssign for each of the objects on the row - for( asUINT x = 0; x < width; x++ ) - { - void *obj = At(x,y); - asBYTE *srcObj = (asBYTE*)(buf) + x*subTypeSize; - engine->AssignScriptObject(obj, srcObj, subType); - } - - // Move to next line - buf = (char*)(buf) + width*subTypeSize; - - // Align to 4 byte boundary - if( asPWORD(buf) & 0x3 ) - buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3); - } - } - - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); -} - -CScriptGrid::CScriptGrid(asUINT width, asUINT height, asIObjectType *ot) -{ - refCount = 1; - gcFlag = false; - objType = ot; - objType->AddRef(); - buffer = 0; - subTypeId = objType->GetSubTypeId(); - - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); - - // Make sure the array size isn't too large for us to handle - if( !CheckMaxSize(width, height) ) - { - // Don't continue with the initialization - return; - } - - CreateBuffer(&buffer, width, height); - - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); -} - -void CScriptGrid::Resize(asUINT width, asUINT height) -{ - // Make sure the size isn't too large for us to handle - if( !CheckMaxSize(width, height) ) - return; - - // Create a new buffer - SGridBuffer *tmpBuffer = 0; - CreateBuffer(&tmpBuffer, width, height); - if( tmpBuffer == 0 ) - return; - - if( buffer ) - { - // Copy the existing values to the new buffer - asUINT w = width > buffer->width ? buffer->width : width; - asUINT h = height > buffer->height ? buffer->height : height; - for( asUINT y = 0; y < h; y++ ) - for( asUINT x = 0; x < w; x++ ) - SetValue(tmpBuffer, x, y, At(buffer, x, y)); - - // Replace the internal buffer - DeleteBuffer(buffer); - } - - buffer = tmpBuffer; -} - -CScriptGrid::CScriptGrid(asUINT width, asUINT height, void *defVal, asIObjectType *ot) -{ - refCount = 1; - gcFlag = false; - objType = ot; - objType->AddRef(); - buffer = 0; - subTypeId = objType->GetSubTypeId(); - - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); - - // Make sure the array size isn't too large for us to handle - if( !CheckMaxSize(width, height) ) - { - // Don't continue with the initialization - return; - } - - CreateBuffer(&buffer, width, height); - - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); - - // Initialize the elements with the default value - for( asUINT y = 0; y < GetHeight(); y++ ) - for( asUINT x = 0; x < GetWidth(); x++ ) - SetValue(x, y, defVal); -} - -void CScriptGrid::SetValue(asUINT x, asUINT y, void *value) -{ - SetValue(buffer, x, y, value); -} - -void CScriptGrid::SetValue(SGridBuffer *buf, asUINT x, asUINT y, void *value) -{ - // At() will take care of the out-of-bounds checking, though - // if called from the application then nothing will be done - void *ptr = At(buf, x, y); - if( ptr == 0 ) return; - - if( (subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE) ) - objType->GetEngine()->AssignScriptObject(ptr, value, objType->GetSubType()); - else if( subTypeId & asTYPEID_OBJHANDLE ) - { - void *tmp = *(void**)ptr; - *(void**)ptr = *(void**)value; - objType->GetEngine()->AddRefScriptObject(*(void**)value, objType->GetSubType()); - if( tmp ) - objType->GetEngine()->ReleaseScriptObject(tmp, objType->GetSubType()); - } - else if( subTypeId == asTYPEID_BOOL || - subTypeId == asTYPEID_INT8 || - subTypeId == asTYPEID_UINT8 ) - *(char*)ptr = *(char*)value; - else if( subTypeId == asTYPEID_INT16 || - subTypeId == asTYPEID_UINT16 ) - *(short*)ptr = *(short*)value; - else if( subTypeId == asTYPEID_INT32 || - subTypeId == asTYPEID_UINT32 || - subTypeId == asTYPEID_FLOAT || - subTypeId > asTYPEID_DOUBLE ) // enums have a type id larger than doubles - *(int*)ptr = *(int*)value; - else if( subTypeId == asTYPEID_INT64 || - subTypeId == asTYPEID_UINT64 || - subTypeId == asTYPEID_DOUBLE ) - *(double*)ptr = *(double*)value; -} - -CScriptGrid::~CScriptGrid() -{ - if( buffer ) - { - DeleteBuffer(buffer); - buffer = 0; - } - if( objType ) objType->Release(); -} - -asUINT CScriptGrid::GetWidth() const -{ - if( buffer ) - return buffer->width; - - return 0; -} - -asUINT CScriptGrid::GetHeight() const -{ - if( buffer ) - return buffer->height; - - return 0; -} - -// internal -bool CScriptGrid::CheckMaxSize(asUINT width, asUINT height) -{ - // This code makes sure the size of the buffer that is allocated - // for the array doesn't overflow and becomes smaller than requested - - asUINT maxSize = 0xFFFFFFFFul - sizeof(SGridBuffer) + 1; - if( elementSize > 0 ) - maxSize /= elementSize; - - asINT64 numElements = width * height; - - if( (numElements >> 32) || numElements > maxSize ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Too large grid size"); - - return false; - } - - // OK - return true; -} - -asIObjectType *CScriptGrid::GetGridObjectType() const -{ - return objType; -} - -int CScriptGrid::GetGridTypeId() const -{ - return objType->GetTypeId(); -} - -int CScriptGrid::GetElementTypeId() const -{ - return subTypeId; -} - -void *CScriptGrid::At(asUINT x, asUINT y) -{ - return At(buffer, x, y); -} - -// Return a pointer to the array element. Returns 0 if the index is out of bounds -void *CScriptGrid::At(SGridBuffer *buf, asUINT x, asUINT y) -{ - if( buf == 0 || x >= buf->width || y >= buf->height ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Index out of bounds"); - return 0; - } - - asUINT index = x+y*buf->width; - if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) - return *(void**)(buf->data + elementSize*index); - else - return buf->data + elementSize*index; -} -const void *CScriptGrid::At(asUINT x, asUINT y) const -{ - return const_cast(this)->At(const_cast(buffer), x, y); -} - - -// internal -void CScriptGrid::CreateBuffer(SGridBuffer **buf, asUINT w, asUINT h) -{ - asUINT numElements = w * h; - - *buf = reinterpret_cast(userAlloc(sizeof(SGridBuffer)-1+elementSize*numElements)); - - if( *buf ) - { - (*buf)->width = w; - (*buf)->height = h; - Construct(*buf); - } - else - { - // Oops, out of memory - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - } -} - -// internal -void CScriptGrid::DeleteBuffer(SGridBuffer *buf) -{ - assert( buf ); - - Destruct(buf); - - // Free the buffer - userFree(buf); -} - -// internal -void CScriptGrid::Construct(SGridBuffer *buf) -{ - assert( buf ); - - if( subTypeId & asTYPEID_OBJHANDLE ) - { - // Set all object handles to null - void *d = (void*)(buf->data); - memset(d, 0, (buf->width*buf->height)*sizeof(void*)); - } - else if( subTypeId & asTYPEID_MASK_OBJECT ) - { - void **max = (void**)(buf->data + (buf->width*buf->height) * sizeof(void*)); - void **d = (void**)(buf->data); - - asIScriptEngine *engine = objType->GetEngine(); - asIObjectType *subType = objType->GetSubType(); - - for( ; d < max; d++ ) - { - *d = (void*)engine->CreateScriptObject(subType); - if( *d == 0 ) - { - // Set the remaining entries to null so the destructor - // won't attempt to destroy invalid objects later - memset(d, 0, sizeof(void*)*(max-d)); - - // There is no need to set an exception on the context, - // as CreateScriptObject has already done that - return; - } - } - } -} - -// internal -void CScriptGrid::Destruct(SGridBuffer *buf) -{ - assert( buf ); - - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - asIScriptEngine *engine = objType->GetEngine(); - - void **max = (void**)(buf->data + (buf->width*buf->height) * sizeof(void*)); - void **d = (void**)(buf->data); - - for( ; d < max; d++ ) - { - if( *d ) - engine->ReleaseScriptObject(*d, objType->GetSubType()); - } - } -} - -// GC behaviour -void CScriptGrid::EnumReferences(asIScriptEngine *engine) -{ - if( buffer == 0 ) return; - - // If the array is holding handles, then we need to notify the GC of them - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - asUINT numElements = buffer->width * buffer->height; - void **d = (void**)buffer->data; - for( asUINT n = 0; n < numElements; n++ ) - { - if( d[n] ) - engine->GCEnumCallback(d[n]); - } - } -} - -// GC behaviour -void CScriptGrid::ReleaseAllHandles(asIScriptEngine*) -{ - if( buffer == 0 ) return; - - DeleteBuffer(buffer); - buffer = 0; -} - -void CScriptGrid::AddRef() const -{ - // Clear the GC flag then increase the counter - gcFlag = false; - asAtomicInc(refCount); -} - -void CScriptGrid::Release() const -{ - // Clearing the GC flag then descrease the counter - gcFlag = false; - if( asAtomicDec(refCount) == 0 ) - { - // When reaching 0 no more references to this instance - // exists and the object should be destroyed - this->~CScriptGrid(); - userFree(const_cast(this)); - } -} - -// GC behaviour -int CScriptGrid::GetRefCount() -{ - return refCount; -} - -// GC behaviour -void CScriptGrid::SetFlag() -{ - gcFlag = true; -} - -// GC behaviour -bool CScriptGrid::GetFlag() -{ - return gcFlag; -} - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/add_on/scriptgrid/scriptgrid.h b/dependencies/angelscript/add_on/scriptgrid/scriptgrid.h deleted file mode 100644 index e45882f0..00000000 --- a/dependencies/angelscript/add_on/scriptgrid/scriptgrid.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef SCRIPTGRID_H -#define SCRIPTGRID_H - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -BEGIN_AS_NAMESPACE - -struct SGridBuffer; - -class CScriptGrid -{ -public: - // Set the memory functions that should be used by all CScriptGrids - static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); - - // Factory functions - static CScriptGrid *Create(asIObjectType *ot); - static CScriptGrid *Create(asIObjectType *ot, asUINT width, asUINT height); - static CScriptGrid *Create(asIObjectType *ot, asUINT width, asUINT height, void *defaultValue); - static CScriptGrid *Create(asIObjectType *ot, void *listBuffer); - - // Memory management - void AddRef() const; - void Release() const; - - // Type information - asIObjectType *GetGridObjectType() const; - int GetGridTypeId() const; - int GetElementTypeId() const; - - // Size - asUINT GetWidth() const; - asUINT GetHeight() const; - void Resize(asUINT width, asUINT height); - - // Get a pointer to an element. Returns 0 if out of bounds - void *At(asUINT x, asUINT y); - const void *At(asUINT x, asUINT y) const; - - // Set value of an element - // Remember, if the grid holds handles the value parameter should be the - // address of the handle. The refCount of the object will also be incremented - void SetValue(asUINT x, asUINT y, void *value); - - // GC methods - int GetRefCount(); - void SetFlag(); - bool GetFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllHandles(asIScriptEngine *engine); - -protected: - mutable int refCount; - mutable bool gcFlag; - asIObjectType *objType; - SGridBuffer *buffer; - int elementSize; - int subTypeId; - - // Constructors - CScriptGrid(asIObjectType *ot, void *initBuf); // Called from script when initialized with list - CScriptGrid(asUINT w, asUINT h, asIObjectType *ot); - CScriptGrid(asUINT w, asUINT h, void *defVal, asIObjectType *ot); - virtual ~CScriptGrid(); - - bool CheckMaxSize(asUINT x, asUINT y); - void CreateBuffer(SGridBuffer **buf, asUINT w, asUINT h); - void DeleteBuffer(SGridBuffer *buf); - void Construct(SGridBuffer *buf); - void Destruct(SGridBuffer *buf); - void SetValue(SGridBuffer *buf, asUINT x, asUINT y, void *value); - void *At(SGridBuffer *buf, asUINT x, asUINT y); -}; - -void RegisterScriptGrid(asIScriptEngine *engine); - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/add_on/scripthandle/scripthandle.cpp b/dependencies/angelscript/add_on/scripthandle/scripthandle.cpp deleted file mode 100644 index 1cbcdc2f..00000000 --- a/dependencies/angelscript/add_on/scripthandle/scripthandle.cpp +++ /dev/null @@ -1,355 +0,0 @@ -#include "scripthandle.h" -#include -#include -#include - -BEGIN_AS_NAMESPACE - -static void Construct(CScriptHandle *self) { new(self) CScriptHandle(); } -static void Construct(CScriptHandle *self, const CScriptHandle &o) { new(self) CScriptHandle(o); } -// This one is not static because it needs to be friend with the CScriptHandle class -void Construct(CScriptHandle *self, void *ref, int typeId) { new(self) CScriptHandle(ref, typeId); } -static void Destruct(CScriptHandle *self) { self->~CScriptHandle(); } - -CScriptHandle::CScriptHandle() -{ - m_ref = 0; - m_type = 0; -} - -CScriptHandle::CScriptHandle(const CScriptHandle &other) -{ - m_ref = other.m_ref; - m_type = other.m_type; - - AddRefHandle(); -} - -CScriptHandle::CScriptHandle(void *ref, asIObjectType *type) -{ - m_ref = ref; - m_type = type; - - AddRefHandle(); -} - -// This constructor shouldn't be called from the application -// directly as it requires an active script context -CScriptHandle::CScriptHandle(void *ref, int typeId) -{ - m_ref = 0; - m_type = 0; - - Assign(ref, typeId); -} - -CScriptHandle::~CScriptHandle() -{ - ReleaseHandle(); -} - -void CScriptHandle::ReleaseHandle() -{ - if( m_ref && m_type ) - { - asIScriptEngine *engine = m_type->GetEngine(); - engine->ReleaseScriptObject(m_ref, m_type); - - engine->Release(); - - m_ref = 0; - m_type = 0; - } -} - -void CScriptHandle::AddRefHandle() -{ - if( m_ref && m_type ) - { - asIScriptEngine *engine = m_type->GetEngine(); - engine->AddRefScriptObject(m_ref, m_type); - - // Hold on to the engine so it isn't destroyed while - // a reference to a script object is still held - engine->AddRef(); - } -} - -CScriptHandle &CScriptHandle::operator =(const CScriptHandle &other) -{ - Set(other.m_ref, other.m_type); - - return *this; -} - -void CScriptHandle::Set(void *ref, asIObjectType *type) -{ - if( m_ref == ref ) return; - - ReleaseHandle(); - - m_ref = ref; - m_type = type; - - AddRefHandle(); -} - -asIObjectType *CScriptHandle::GetType() const -{ - return m_type; -} - -int CScriptHandle::GetTypeId() const -{ - if( m_type == 0 ) return 0; - - if( m_type->GetFlags() & asOBJ_SCRIPT_FUNCTION ) - { - asIScriptFunction *func = reinterpret_cast(m_ref); - return func->GetTypeId() | asTYPEID_OBJHANDLE; - } - - return m_type->GetTypeId() | asTYPEID_OBJHANDLE; -} - -// This method shouldn't be called from the application -// directly as it requires an active script context -CScriptHandle &CScriptHandle::Assign(void *ref, int typeId) -{ - // When receiving a null handle we just clear our memory - if( typeId == 0 ) - { - Set(0, 0); - return *this; - } - - // Dereference received handles to get the object - if( typeId & asTYPEID_OBJHANDLE ) - { - // Store the actual reference - ref = *(void**)ref; - typeId &= ~asTYPEID_OBJHANDLE; - } - - // Get the object type - asIScriptContext *ctx = asGetActiveContext(); - asIScriptEngine *engine = ctx->GetEngine(); - asIObjectType *type = engine->GetObjectTypeById(typeId); - - // If the argument is another CScriptHandle, we should copy the content instead - if( type && strcmp(type->GetName(), "ref") == 0 ) - { - CScriptHandle *r = (CScriptHandle*)ref; - ref = r->m_ref; - type = r->m_type; - } - - Set(ref, type); - - return *this; -} - -bool CScriptHandle::operator==(const CScriptHandle &o) const -{ - if( m_ref == o.m_ref && - m_type == o.m_type ) - return true; - - // TODO: If type is not the same, we should attempt to do a dynamic cast, - // which may change the pointer for application registered classes - - return false; -} - -bool CScriptHandle::operator!=(const CScriptHandle &o) const -{ - return !(*this == o); -} - -bool CScriptHandle::Equals(void *ref, int typeId) const -{ - // Null handles are received as reference to a null handle - if( typeId == 0 ) - ref = 0; - - // Dereference handles to get the object - if( typeId & asTYPEID_OBJHANDLE ) - { - // Compare the actual reference - ref = *(void**)ref; - typeId &= ~asTYPEID_OBJHANDLE; - } - - // TODO: If typeId is not the same, we should attempt to do a dynamic cast, - // which may change the pointer for application registered classes - - if( ref == m_ref ) return true; - - return false; -} - -// AngelScript: used as '@obj = cast(ref);' -void CScriptHandle::Cast(void **outRef, int typeId) -{ - // If we hold a null handle, then just return null - if( m_type == 0 ) - { - *outRef = 0; - return; - } - - // It is expected that the outRef is always a handle - assert( typeId & asTYPEID_OBJHANDLE ); - - // Compare the type id of the actual object - typeId &= ~asTYPEID_OBJHANDLE; - asIScriptEngine *engine = m_type->GetEngine(); - asIObjectType *type = engine->GetObjectTypeById(typeId); - - *outRef = 0; - - if( type == m_type ) - { - // If the requested type is a script function it is - // necessary to check if the functions are compatible too - if( m_type->GetFlags() & asOBJ_SCRIPT_FUNCTION ) - { - asIScriptFunction *func = reinterpret_cast(m_ref); - if( !func->IsCompatibleWithTypeId(typeId) ) - return; - } - - // Must increase the ref count as we're returning a new reference to the object - engine->AddRefScriptObject(m_ref, m_type); - *outRef = m_ref; - } - else if( m_type->GetFlags() & asOBJ_SCRIPT_OBJECT ) - { - // Attempt a dynamic cast of the stored handle to the requested handle type - if( engine->IsHandleCompatibleWithObject(m_ref, m_type->GetTypeId(), typeId) ) - { - // The script type is compatible so we can simply return the same pointer - engine->AddRefScriptObject(m_ref, m_type); - *outRef = m_ref; - } - } - else - { - // TODO: Check for the existance of a reference cast behaviour. - // Both implicit and explicit casts may be used - // Calling the reference cast behaviour may change the actual - // pointer so the AddRef must be called on the new pointer - } -} - - - -void RegisterScriptHandle_Native(asIScriptEngine *engine) -{ - int r; - - r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(Construct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTIONPR(Construct, (CScriptHandle *, const CScriptHandle &), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTIONPR(Construct, (CScriptHandle *, void *, int), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTIONPR(Destruct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_REF_CAST, "void f(?&out)", asMETHODPR(CScriptHandle, Cast, (void **, int), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asMETHOD(CScriptHandle, operator=), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 ); -} - -void CScriptHandle_Construct_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - new(self) CScriptHandle(); -} - -void CScriptHandle_ConstructCopy_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - new(self) CScriptHandle(*other); -} - -void CScriptHandle_ConstructVar_Generic(asIScriptGeneric *gen) -{ - void *ref = gen->GetArgAddress(0); - int typeId = gen->GetArgTypeId(0); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - Construct(self, ref, typeId); -} - -void CScriptHandle_Destruct_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->~CScriptHandle(); -} - -void CScriptHandle_Cast_Generic(asIScriptGeneric *gen) -{ - void **ref = reinterpret_cast(gen->GetArgAddress(0)); - int typeId = gen->GetArgTypeId(0); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->Cast(ref, typeId); -} - -void CScriptHandle_Assign_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - *self = *other; - gen->SetReturnAddress(self); -} - -void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen) -{ - void *ref = gen->GetArgAddress(0); - int typeId = gen->GetArgTypeId(0); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->Assign(ref, typeId); - gen->SetReturnAddress(self); -} - -void CScriptHandle_Equals_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - gen->SetReturnByte(*self == *other); -} - -void CScriptHandle_EqualsVar_Generic(asIScriptGeneric *gen) -{ - void *ref = gen->GetArgAddress(0); - int typeId = gen->GetArgTypeId(0); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - gen->SetReturnByte(self->Equals(ref, typeId)); -} - -void RegisterScriptHandle_Generic(asIScriptEngine *engine) -{ - int r; - - r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptHandle_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTION(CScriptHandle_ConstructCopy_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTION(CScriptHandle_ConstructVar_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptHandle_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_REF_CAST, "void f(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 ); -} - -void RegisterScriptHandle(asIScriptEngine *engine) -{ - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptHandle_Generic(engine); - else - RegisterScriptHandle_Native(engine); -} - - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/add_on/scripthandle/scripthandle.h b/dependencies/angelscript/add_on/scripthandle/scripthandle.h deleted file mode 100644 index d4564448..00000000 --- a/dependencies/angelscript/add_on/scripthandle/scripthandle.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef SCRIPTHANDLE_H -#define SCRIPTHANDLE_H - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - - -BEGIN_AS_NAMESPACE - -class CScriptHandle -{ -public: - // Constructors - CScriptHandle(); - CScriptHandle(const CScriptHandle &other); - CScriptHandle(void *ref, asIObjectType *type); - ~CScriptHandle(); - - // Copy the stored value from another any object - CScriptHandle &operator=(const CScriptHandle &other); - - // Set the reference - void Set(void *ref, asIObjectType *type); - - // Compare equalness - bool operator==(const CScriptHandle &o) const; - bool operator!=(const CScriptHandle &o) const; - bool Equals(void *ref, int typeId) const; - - // Dynamic cast to desired handle type - void Cast(void **outRef, int typeId); - - // Returns the type of the reference held - asIObjectType *GetType() const; - int GetTypeId() const; - -protected: - // These functions need to have access to protected - // members in order to call them from the script engine - friend void Construct(CScriptHandle *self, void *ref, int typeId); - friend void RegisterScriptHandle_Native(asIScriptEngine *engine); - friend void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen); - - void ReleaseHandle(); - void AddRefHandle(); - - // These shouldn't be called directly by the - // application as they requires an active context - CScriptHandle(void *ref, int typeId); - CScriptHandle &Assign(void *ref, int typeId); - - void *m_ref; - asIObjectType *m_type; -}; - -void RegisterScriptHandle(asIScriptEngine *engine); - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/add_on/scripthelper/scripthelper.cpp b/dependencies/angelscript/add_on/scripthelper/scripthelper.cpp deleted file mode 100644 index c3f917e1..00000000 --- a/dependencies/angelscript/add_on/scripthelper/scripthelper.cpp +++ /dev/null @@ -1,918 +0,0 @@ -#include -#include "scripthelper.h" -#include -#include -#include -#include - -using namespace std; - -BEGIN_AS_NAMESPACE - -int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result) -{ - // TODO: If a lot of script objects are going to be compared, e.g. when sorting an array, - // then the method id and context should be cached between calls. - - int retval = -1; - asIScriptFunction *func = 0; - - asIObjectType *ot = engine->GetObjectTypeById(typeId); - if( ot ) - { - // Check if the object type has a compatible opCmp method - for( asUINT n = 0; n < ot->GetMethodCount(); n++ ) - { - asIScriptFunction *f = ot->GetMethodByIndex(n); - asDWORD flags; - if( strcmp(f->GetName(), "opCmp") == 0 && - f->GetReturnTypeId(&flags) == asTYPEID_INT32 && - flags == asTM_NONE && - f->GetParamCount() == 1 ) - { - int paramTypeId; - f->GetParam(0, ¶mTypeId, &flags); - - // The parameter must be an input reference of the same type - // If the reference is a inout reference, then it must also be read-only - if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) ) - break; - - // Found the method - func = f; - break; - } - } - } - - if( func ) - { - // Call the method - asIScriptContext *ctx = engine->CreateContext(); - ctx->Prepare(func); - ctx->SetObject(lobj); - ctx->SetArgAddress(0, robj); - int r = ctx->Execute(); - if( r == asEXECUTION_FINISHED ) - { - result = (int)ctx->GetReturnDWord(); - - // The comparison was successful - retval = 0; - } - ctx->Release(); - } - - return retval; -} - -int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result) -{ - // TODO: If a lot of script objects are going to be compared, e.g. when searching for an - // entry in a set, then the method and context should be cached between calls. - - int retval = -1; - asIScriptFunction *func = 0; - - asIObjectType *ot = engine->GetObjectTypeById(typeId); - if( ot ) - { - // Check if the object type has a compatible opEquals method - for( asUINT n = 0; n < ot->GetMethodCount(); n++ ) - { - asIScriptFunction *f = ot->GetMethodByIndex(n); - asDWORD flags; - if( strcmp(f->GetName(), "opEquals") == 0 && - f->GetReturnTypeId(&flags) == asTYPEID_BOOL && - flags == asTM_NONE && - f->GetParamCount() == 1 ) - { - int paramTypeId; - f->GetParam(0, ¶mTypeId, &flags); - - // The parameter must be an input reference of the same type - // If the reference is a inout reference, then it must also be read-only - if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) ) - break; - - // Found the method - func = f; - break; - } - } - } - - if( func ) - { - // Call the method - asIScriptContext *ctx = engine->CreateContext(); - ctx->Prepare(func); - ctx->SetObject(lobj); - ctx->SetArgAddress(0, robj); - int r = ctx->Execute(); - if( r == asEXECUTION_FINISHED ) - { - result = ctx->GetReturnByte() ? true : false; - - // The comparison was successful - retval = 0; - } - ctx->Release(); - } - else - { - // If the opEquals method doesn't exist, then we try with opCmp instead - int relation; - retval = CompareRelation(engine, lobj, robj, typeId, relation); - if( retval >= 0 ) - result = relation == 0 ? true : false; - } - - return retval; -} - -int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod, asIScriptContext *ctx) -{ - return ExecuteString(engine, code, 0, asTYPEID_VOID, mod, ctx); -} - -int ExecuteString(asIScriptEngine *engine, const char *code, void *ref, int refTypeId, asIScriptModule *mod, asIScriptContext *ctx) -{ - // Wrap the code in a function so that it can be compiled and executed - string funcCode = " ExecuteString() {\n"; - funcCode += code; - funcCode += "\n;}"; - - // Determine the return type based on the type of the ref arg - funcCode = engine->GetTypeDeclaration(refTypeId, true) + funcCode; - - // GetModule will free unused types, so to be on the safe side we'll hold on to a reference to the type - asIObjectType *type = 0; - if( refTypeId & asTYPEID_MASK_OBJECT ) - { - type = engine->GetObjectTypeById(refTypeId); - if( type ) - type->AddRef(); - } - - // If no module was provided, get a dummy from the engine - asIScriptModule *execMod = mod ? mod : engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE); - - // Now it's ok to release the type - if( type ) - type->Release(); - - // Compile the function that can be executed - asIScriptFunction *func = 0; - int r = execMod->CompileFunction("ExecuteString", funcCode.c_str(), -1, 0, &func); - if( r < 0 ) - return r; - - // If no context was provided, request a new one from the engine - asIScriptContext *execCtx = ctx ? ctx : engine->CreateContext(); - r = execCtx->Prepare(func); - if( r < 0 ) - { - func->Release(); - if( !ctx ) execCtx->Release(); - return r; - } - - // Execute the function - r = execCtx->Execute(); - - // Unless the provided type was void retrieve it's value - if( ref != 0 && refTypeId != asTYPEID_VOID ) - { - if( refTypeId & asTYPEID_OBJHANDLE ) - { - // Expect the pointer to be null to start with - assert( *reinterpret_cast(ref) == 0 ); - *reinterpret_cast(ref) = *reinterpret_cast(execCtx->GetAddressOfReturnValue()); - engine->AddRefScriptObject(*reinterpret_cast(ref), engine->GetObjectTypeById(refTypeId)); - } - else if( refTypeId & asTYPEID_MASK_OBJECT ) - { - // Expect the pointer to point to a valid object - assert( *reinterpret_cast(ref) != 0 ); - engine->AssignScriptObject(ref, execCtx->GetAddressOfReturnValue(), engine->GetObjectTypeById(refTypeId)); - } - else - { - // Copy the primitive value - memcpy(ref, execCtx->GetAddressOfReturnValue(), engine->GetSizeOfPrimitiveType(refTypeId)); - } - } - - // Clean up - func->Release(); - if( !ctx ) execCtx->Release(); - - return r; -} - -int WriteConfigToFile(asIScriptEngine *engine, const char *filename) -{ - ofstream strm; - strm.open(filename); - - return WriteConfigToStream(engine, strm); -} - -int WriteConfigToStream(asIScriptEngine *engine, ostream &strm) -{ - // A helper function for escaping quotes in default arguments - struct Escape - { - static string Quotes(const char *decl) - { - string str = decl; - size_t pos = 0; - for(;;) - { - // Find " characters - pos = str.find("\"",pos); - if( pos == string::npos ) - break; - - // Add a \ to escape them - str.insert(pos, "\\"); - pos += 2; - } - - return str; - } - }; - - - int c, n; - - asDWORD currAccessMask = 0; - string currNamespace = ""; - - // Export the engine version, just for info - strm << "// AngelScript " << asGetLibraryVersion() << "\n"; - strm << "// Lib options " << asGetLibraryOptions() << "\n"; - - // Export the relevant engine properties - strm << "// Engine properties\n"; - for( n = 0; n < asEP_LAST_PROPERTY; n++ ) - strm << "ep " << n << " " << engine->GetEngineProperty(asEEngineProp(n)) << "\n"; - - // Make sure the default array type is expanded to the template form - bool expandDefArrayToTempl = engine->GetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL) ? true : false; - engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true); - - // Write enum types and their values - strm << "\n// Enums\n"; - c = engine->GetEnumCount(); - for( n = 0; n < c; n++ ) - { - int typeId; - asDWORD accessMask; - const char *nameSpace; - const char *enumName = engine->GetEnumByIndex(n, &typeId, &nameSpace, 0, &accessMask); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - if( nameSpace != currNamespace ) - { - strm << "namespace " << nameSpace << "\n"; - currNamespace = nameSpace; - } - strm << "enum " << enumName << "\n"; - for( int m = 0; m < engine->GetEnumValueCount(typeId); m++ ) - { - const char *valName; - int val; - valName = engine->GetEnumValueByIndex(typeId, m, &val); - strm << "enumval " << enumName << " " << valName << " " << val << "\n"; - } - } - - // Enumerate all types - strm << "\n// Types\n"; - - c = engine->GetObjectTypeCount(); - for( n = 0; n < c; n++ ) - { - asIObjectType *type = engine->GetObjectTypeByIndex(n); - asDWORD accessMask = type->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - const char *nameSpace = type->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace " << nameSpace << "\n"; - currNamespace = nameSpace; - } - if( type->GetFlags() & asOBJ_SCRIPT_OBJECT ) - { - // This should only be interfaces - assert( type->GetSize() == 0 ); - - strm << "intf " << type->GetName() << "\n"; - } - else - { - // Only the type flags are necessary. The application flags are application - // specific and doesn't matter to the offline compiler. The object size is also - // unnecessary for the offline compiler - strm << "objtype \"" << engine->GetTypeDeclaration(type->GetTypeId()) << "\" " << (unsigned int)(type->GetFlags() & 0xFF) << "\n"; - } - } - - c = engine->GetTypedefCount(); - for( n = 0; n < c; n++ ) - { - int typeId; - asDWORD accessMask; - const char *nameSpace; - const char *typeDef = engine->GetTypedefByIndex(n, &typeId, &nameSpace, 0, &accessMask); - if( nameSpace != currNamespace ) - { - strm << "namespace " << nameSpace << "\n"; - currNamespace = nameSpace; - } - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "typedef " << typeDef << " \"" << engine->GetTypeDeclaration(typeId) << "\"\n"; - } - - c = engine->GetFuncdefCount(); - for( n = 0; n < c; n++ ) - { - asIScriptFunction *funcDef = engine->GetFuncdefByIndex(n); - asDWORD accessMask = funcDef->GetAccessMask(); - const char *nameSpace = funcDef->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace " << nameSpace << "\n"; - currNamespace = nameSpace; - } - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "funcdef \"" << funcDef->GetDeclaration() << "\"\n"; - } - - // Write the object types members - // TODO: All function declarations must use escape sequences for " so as not to cause the parsing of the file to fail - strm << "\n// Type members\n"; - - c = engine->GetObjectTypeCount(); - for( n = 0; n < c; n++ ) - { - asIObjectType *type = engine->GetObjectTypeByIndex(n); - const char *nameSpace = type->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace " << nameSpace << "\n"; - currNamespace = nameSpace; - } - string typeDecl = engine->GetTypeDeclaration(type->GetTypeId()); - if( type->GetFlags() & asOBJ_SCRIPT_OBJECT ) - { - for( asUINT m = 0; m < type->GetMethodCount(); m++ ) - { - asIScriptFunction *func = type->GetMethodByIndex(m); - asDWORD accessMask = func->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "intfmthd " << typeDecl.c_str() << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; - } - } - else - { - asUINT m; - for( m = 0; m < type->GetFactoryCount(); m++ ) - { - asIScriptFunction *func = type->GetFactoryByIndex(m); - asDWORD accessMask = func->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "objbeh \"" << typeDecl.c_str() << "\" " << asBEHAVE_FACTORY << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; - } - for( m = 0; m < type->GetBehaviourCount(); m++ ) - { - asEBehaviours beh; - asIScriptFunction *func = type->GetBehaviourByIndex(m, &beh); - - if( beh == asBEHAVE_CONSTRUCT ) - // Prefix 'void' - strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; - else if( beh == asBEHAVE_DESTRUCT ) - // Prefix 'void' and remove ~ - strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str()+1 << "\"\n"; - else - strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; - } - for( m = 0; m < type->GetMethodCount(); m++ ) - { - asIScriptFunction *func = type->GetMethodByIndex(m); - asDWORD accessMask = func->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "objmthd \"" << typeDecl.c_str() << "\" \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; - } - for( m = 0; m < type->GetPropertyCount(); m++ ) - { - asDWORD accessMask; - type->GetProperty(m, 0, 0, 0, 0, 0, &accessMask); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "objprop \"" << typeDecl.c_str() << "\" \"" << type->GetPropertyDeclaration(m) << "\"\n"; - } - } - } - - // Write functions - strm << "\n// Functions\n"; - - c = engine->GetGlobalFunctionCount(); - for( n = 0; n < c; n++ ) - { - asIScriptFunction *func = engine->GetGlobalFunctionByIndex(n); - const char *nameSpace = func->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace " << nameSpace << "\n"; - currNamespace = nameSpace; - } - asDWORD accessMask = func->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "func \"" << Escape::Quotes(func->GetDeclaration()).c_str() << "\"\n"; - } - - // Write global properties - strm << "\n// Properties\n"; - - c = engine->GetGlobalPropertyCount(); - for( n = 0; n < c; n++ ) - { - const char *name; - int typeId; - bool isConst; - asDWORD accessMask; - const char *nameSpace; - engine->GetGlobalPropertyByIndex(n, &name, &nameSpace, &typeId, &isConst, 0, 0, &accessMask); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - if( nameSpace != currNamespace ) - { - strm << "namespace " << nameSpace << "\n"; - currNamespace = nameSpace; - } - strm << "prop \"" << (isConst ? "const " : "") << engine->GetTypeDeclaration(typeId) << " " << name << "\"\n"; - } - - // Write string factory - strm << "\n// String factory\n"; - asDWORD flags = 0; - int typeId = engine->GetStringFactoryReturnTypeId(&flags); - if( typeId > 0 ) - strm << "strfactory \"" << ((flags & asTM_CONST) ? "const " : "") << engine->GetTypeDeclaration(typeId) << ((flags & asTM_INOUTREF) ? "&" : "") << "\"\n"; - - // Write default array type - strm << "\n// Default array type\n"; - typeId = engine->GetDefaultArrayTypeId(); - if( typeId > 0 ) - strm << "defarray \"" << engine->GetTypeDeclaration(typeId) << "\"\n"; - - // Restore original settings - engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, expandDefArrayToTempl); - - return 0; -} - -int ConfigEngineFromStream(asIScriptEngine *engine, istream &strm, const char *configFile) -{ - int r; - - // Some helper functions for parsing the configuration - struct in - { - static asETokenClass GetToken(asIScriptEngine *engine, string &token, const string &text, asUINT &pos) - { - int len; - asETokenClass t = engine->ParseToken(&text[pos], text.length() - pos, &len); - while( (t == asTC_WHITESPACE || t == asTC_COMMENT) && pos < text.length() ) - { - pos += len; - t = engine->ParseToken(&text[pos], text.length() - pos, &len); - } - - token.assign(&text[pos], len); - - pos += len; - - return t; - } - - static void ReplaceSlashQuote(string &str) - { - size_t pos = 0; - for(;;) - { - // Search for \" in the string - pos = str.find("\\\"", pos); - if( pos == string::npos ) - break; - - // Remove the \ character - str.erase(pos, 1); - } - } - - static asUINT GetLineNumber(const string &text, asUINT pos) - { - asUINT count = 1; - for( asUINT n = 0; n < pos; n++ ) - if( text[n] == '\n' ) - count++; - - return count; - } - }; - - // Since we are only going to compile the script and never actually execute it, - // we turn off the initialization of global variables, so that the compiler can - // just register dummy types and functions for the application interface. - r = engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false); assert( r >= 0 ); - - // Read the entire file - char buffer[1000]; - string config; - do { - strm.getline(buffer, 1000); - config += buffer; - config += "\n"; - } while( !strm.eof() ); - - // Process the configuration file and register each entity - asUINT pos = 0; - while( pos < config.length() ) - { - string token; - // TODO: The position where the initial token is found should be stored for error messages - in::GetToken(engine, token, config, pos); - if( token == "ep" ) - { - string tmp; - in::GetToken(engine, tmp, config, pos); - - asEEngineProp ep = asEEngineProp(atol(tmp.c_str())); - - // Only set properties that affect the compiler - switch( ep ) - { - case asEP_ALLOW_UNSAFE_REFERENCES: - case asEP_OPTIMIZE_BYTECODE: - case asEP_USE_CHARACTER_LITERALS: - case asEP_ALLOW_MULTILINE_STRINGS: - case asEP_ALLOW_IMPLICIT_HANDLE_TYPES: - case asEP_BUILD_WITHOUT_LINE_CUES: - case asEP_REQUIRE_ENUM_SCOPE: - case asEP_SCRIPT_SCANNER: - case asEP_INCLUDE_JIT_INSTRUCTIONS: - case asEP_STRING_ENCODING: - case asEP_PROPERTY_ACCESSOR_MODE: - case asEP_DISALLOW_GLOBAL_VARS: - case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT: - case asEP_COMPILER_WARNINGS: - case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE: - { - // Get the value for the property - in::GetToken(engine, tmp, config, pos); - stringstream s(tmp); - asPWORD value; - - s >> value; - - engine->SetEngineProperty(ep, value); - } - break; - - case asEP_COPY_SCRIPT_SECTIONS: - case asEP_MAX_STACK_SIZE: - case asEP_INIT_GLOBAL_VARS_AFTER_BUILD: - case asEP_EXPAND_DEF_ARRAY_TO_TMPL: - case asEP_AUTO_GARBAGE_COLLECT: - // These don't affect the compiler, so there is no need to export them - break; - } - } - else if( token == "namespace" ) - { - string ns; - in::GetToken(engine, ns, config, pos); - - r = engine->SetDefaultNamespace(ns.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to set namespace"); - return -1; - } - } - else if( token == "access" ) - { - string maskStr; - in::GetToken(engine, maskStr, config, pos); - asDWORD mask = strtol(maskStr.c_str(), 0, 16); - engine->SetDefaultAccessMask(mask); - } - else if( token == "objtype" ) - { - string name, flags; - in::GetToken(engine, name, config, pos); - name = name.substr(1, name.length() - 2); - in::GetToken(engine, flags, config, pos); - - // The size of the value type doesn't matter, because the - // engine must adjust it anyway for different platforms - r = engine->RegisterObjectType(name.c_str(), (atol(flags.c_str()) & asOBJ_VALUE) ? 1 : 0, atol(flags.c_str())); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object type"); - return -1; - } - } - else if( token == "objbeh" ) - { - string name, behaviour, decl; - in::GetToken(engine, name, config, pos); - name = name.substr(1, name.length() - 2); - in::GetToken(engine, behaviour, config, pos); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::ReplaceSlashQuote(decl); - - asEBehaviours behave = static_cast(atol(behaviour.c_str())); - if( behave == asBEHAVE_TEMPLATE_CALLBACK ) - { - // TODO: How can we let the compiler register this? Maybe through a plug-in system? Or maybe by implementing the callback as a script itself - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register template callback without the actual implementation"); - } - else - { - r = engine->RegisterObjectBehaviour(name.c_str(), behave, decl.c_str(), asFUNCTION(0), asCALL_GENERIC); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register behaviour"); - return -1; - } - } - } - else if( token == "objmthd" ) - { - string name, decl; - in::GetToken(engine, name, config, pos); - name = name.substr(1, name.length() - 2); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::ReplaceSlashQuote(decl); - - r = engine->RegisterObjectMethod(name.c_str(), decl.c_str(), asFUNCTION(0), asCALL_GENERIC); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object method"); - return -1; - } - } - else if( token == "objprop" ) - { - string name, decl; - in::GetToken(engine, name, config, pos); - name = name.substr(1, name.length() - 2); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - - asIObjectType *type = engine->GetObjectTypeById(engine->GetTypeIdByDecl(name.c_str())); - if( type == 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Type doesn't exist for property registration"); - return -1; - } - - // All properties must have different offsets in order to make them - // distinct, so we simply register them with an incremental offset - r = engine->RegisterObjectProperty(name.c_str(), decl.c_str(), type->GetPropertyCount()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object property"); - return -1; - } - } - else if( token == "intf" ) - { - string name, size, flags; - in::GetToken(engine, name, config, pos); - - r = engine->RegisterInterface(name.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface"); - return -1; - } - } - else if( token == "intfmthd" ) - { - string name, decl; - in::GetToken(engine, name, config, pos); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::ReplaceSlashQuote(decl); - - r = engine->RegisterInterfaceMethod(name.c_str(), decl.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface method"); - return -1; - } - } - else if( token == "func" ) - { - string decl; - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::ReplaceSlashQuote(decl); - - r = engine->RegisterGlobalFunction(decl.c_str(), asFUNCTION(0), asCALL_GENERIC); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global function"); - return -1; - } - } - else if( token == "prop" ) - { - string decl; - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - - // All properties must have different offsets in order to make them - // distinct, so we simply register them with an incremental offset. - // The pointer must also be non-null so we add 1 to have a value. - r = engine->RegisterGlobalProperty(decl.c_str(), (void*)(engine->GetGlobalPropertyCount()+1)); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global property"); - return -1; - } - } - else if( token == "strfactory" ) - { - string type; - in::GetToken(engine, type, config, pos); - type = type.substr(1, type.length() - 2); - - r = engine->RegisterStringFactory(type.c_str(), asFUNCTION(0), asCALL_GENERIC); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register string factory"); - return -1; - } - } - else if( token == "defarray" ) - { - string type; - in::GetToken(engine, type, config, pos); - type = type.substr(1, type.length() - 2); - - r = engine->RegisterDefaultArrayType(type.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register the default array type"); - return -1; - } - } - else if( token == "enum" ) - { - string type; - in::GetToken(engine, type, config, pos); - - r = engine->RegisterEnum(type.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum type"); - return -1; - } - } - else if( token == "enumval" ) - { - string type, name, value; - in::GetToken(engine, type, config, pos); - in::GetToken(engine, name, config, pos); - in::GetToken(engine, value, config, pos); - - r = engine->RegisterEnumValue(type.c_str(), name.c_str(), atol(value.c_str())); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum value"); - return -1; - } - } - else if( token == "typedef" ) - { - string type, decl; - in::GetToken(engine, type, config, pos); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - - r = engine->RegisterTypedef(type.c_str(), decl.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register typedef"); - return -1; - } - } - else if( token == "funcdef" ) - { - string decl; - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - - r = engine->RegisterFuncdef(decl.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register funcdef"); - return -1; - } - } - } - - return 0; -} - -string GetExceptionInfo(asIScriptContext *ctx, bool showStack) -{ - if( ctx->GetState() != asEXECUTION_EXCEPTION ) return ""; - - stringstream text; - - const asIScriptFunction *function = ctx->GetExceptionFunction(); - text << "func: " << function->GetDeclaration() << "\n"; - text << "modl: " << function->GetModuleName() << "\n"; - text << "sect: " << function->GetScriptSectionName() << "\n"; - text << "line: " << ctx->GetExceptionLineNumber() << "\n"; - text << "desc: " << ctx->GetExceptionString() << "\n"; - - if( showStack ) - { - text << "--- call stack ---\n"; - for( asUINT n = 1; n < ctx->GetCallstackSize(); n++ ) - { - function = ctx->GetFunction(n); - if( function ) - { - if( function->GetFuncType() == asFUNC_SCRIPT ) - { - text << function->GetScriptSectionName() << " (" << ctx->GetLineNumber(n) << "): " << function->GetDeclaration() << "\n"; - } - else - { - // The context is being reused by the application for a nested call - text << "{...application...}: " << function->GetDeclaration() << "\n"; - } - } - else - { - // The context is being reused by the script engine for a nested call - text << "{...script engine...}\n"; - } - } - } - - return text.str(); -} - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/add_on/scripthelper/scripthelper.h b/dependencies/angelscript/add_on/scripthelper/scripthelper.h deleted file mode 100644 index 340408ac..00000000 --- a/dependencies/angelscript/add_on/scripthelper/scripthelper.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef SCRIPTHELPER_H -#define SCRIPTHELPER_H - -#include -#include - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - - -BEGIN_AS_NAMESPACE - -// Compare relation between two objects of the same type -int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result); - -// Compare equality between two objects of the same type -int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result); - -// Compile and execute simple statements -// The module is optional. If given the statements can access the entities compiled in the module. -// The caller can optionally provide its own context, for example if a context should be reused. -int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod = 0, asIScriptContext *ctx = 0); - -// Compile and execute simple statements with option of return value -// The module is optional. If given the statements can access the entitites compiled in the module. -// The caller can optionally provide its own context, for example if a context should be reused. -int ExecuteString(asIScriptEngine *engine, const char *code, void *ret, int retTypeId, asIScriptModule *mod = 0, asIScriptContext *ctx = 0); - -// Write the registered application interface to a file for an offline compiler. -// The format is compatible with the offline compiler in /sdk/samples/asbuild/. -int WriteConfigToFile(asIScriptEngine *engine, const char *filename); - -// Write the registered application interface to a text stream. -int WriteConfigToStream(asIScriptEngine *engine, std::ostream &strm); - -// Loads an interface from a text stream and configures the engine with it. This will not -// set the correct function pointers, so it is not possible to use this engine to execute -// scripts, but it can be used to compile scripts and save the byte code. -int ConfigEngineFromStream(asIScriptEngine *engine, std::istream &strm, const char *nameOfStream = "config"); - -// Format the details of the script exception into a human readable text -std::string GetExceptionInfo(asIScriptContext *ctx, bool showStack = false); - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/add_on/serializer/serializer.cpp b/dependencies/angelscript/add_on/serializer/serializer.cpp deleted file mode 100644 index f1ed1395..00000000 --- a/dependencies/angelscript/add_on/serializer/serializer.cpp +++ /dev/null @@ -1,528 +0,0 @@ -// -// CSerializer -// -// This code was based on the CScriptReloader written by FDsagizi -// http://www.gamedev.net/topic/604890-dynamic-reloading-script/ -// - -#include -#include // strstr -#include // sprintf -#include "serializer.h" - -using namespace std; - -BEGIN_AS_NAMESPACE - -/////////////////////////////////////////////////////////////////////////////////// - -CSerializer::CSerializer() -{ - m_engine = 0; -} - -CSerializer::~CSerializer() -{ - // Clean the serialized values before we remove the user types - m_root.Uninit(); - - // Delete the user types - std::map::iterator it; - for( it = m_userTypes.begin(); it != m_userTypes.end(); it++ ) - delete it->second; - - if( m_engine ) - m_engine->Release(); -} - -void CSerializer::AddUserType(CUserType *ref, const std::string &name) -{ - m_userTypes[name] = ref; -} - -int CSerializer::Store(asIScriptModule *mod) -{ - m_mod = mod; - - // The engine must not be destroyed before we're completed, so we'll hold on to a reference - mod->GetEngine()->AddRef(); - if( m_engine ) m_engine->Release(); - m_engine = mod->GetEngine(); - - m_root.m_serializer = this; - - // First store global variables - asUINT i; - for( i = 0; i < mod->GetGlobalVarCount(); i++ ) - { - const char *name, *nameSpace; - int typeId; - mod->GetGlobalVar(i, &name, &nameSpace, &typeId); - m_root.m_children.push_back(new CSerializedValue(&m_root, name, nameSpace, mod->GetAddressOfGlobalVar(i), typeId)); - } - - // Second store extra objects - for( i = 0; i < m_extraObjects.size(); i++ ) - m_root.m_children.push_back(new CSerializedValue(&m_root, "", "", m_extraObjects[i].originalObject, m_extraObjects[i].originalTypeId)); - - // For the handles that were stored, we need to substitute the stored pointer - // that is still pointing to the original object to an internal reference so - // it can be restored later on. - m_root.ReplaceHandles(); - - return 0; -} - -// Retrieve all global variables after reload script. -int CSerializer::Restore(asIScriptModule *mod) -{ - m_mod = mod; - - // The engine must not be destroyed before we're completed, so we'll hold on to a reference - mod->GetEngine()->AddRef(); - if( m_engine ) m_engine->Release(); - m_engine = mod->GetEngine(); - - // First restore extra objects, i.e. the ones that are not directly seen from the module's global variables - asUINT i; - for( i = 0; i < m_extraObjects.size(); i++ ) - { - SExtraObject &o = m_extraObjects[i]; - asIObjectType *type = m_mod->GetObjectTypeByName( o.originalClassName.c_str() ); - if( type ) - { - for( size_t i2 = 0; i2 < m_root.m_children.size(); i2++ ) - { - if( m_root.m_children[i2]->m_originalPtr == o.originalObject ) - { - // Create a new script object, but don't call its constructor as we will initialize the members. - // Calling the constructor may have unwanted side effects if for example the constructor changes - // any outside entities, such as setting global variables to point to new objects, etc. - void *newPtr = m_engine->CreateUninitializedScriptObject( type ); - m_root.m_children[i2]->Restore( newPtr, type->GetTypeId() ); - } - } - } - } - - // Second restore the global variables - asUINT varCount = mod->GetGlobalVarCount(); - for( i = 0; i < varCount; i++ ) - { - const char *name, *nameSpace; - int typeId; - mod->GetGlobalVar(i, &name, &nameSpace, &typeId); - - CSerializedValue *v = m_root.FindByName(name, nameSpace); - if( v ) - v->Restore(mod->GetAddressOfGlobalVar(i), typeId); - } - - // The handles that were restored needs to be - // updated to point to their final objects. - m_root.RestoreHandles(); - - return 0; -} - -void *CSerializer::GetPointerToRestoredObject(void *ptr) -{ - return m_root.GetPointerToRestoredObject( ptr ); -} - -void CSerializer::AddExtraObjectToStore( asIScriptObject *object ) -{ - if( !object ) - return; - - // Check if the object hasn't been included already - for( size_t i=0; i < m_extraObjects.size(); i++ ) - if( m_extraObjects[i].originalObject == object ) - return; - - SExtraObject o; - o.originalObject = object; - o.originalClassName = object->GetObjectType()->GetName(); - o.originalTypeId = object->GetTypeId(); - - m_extraObjects.push_back( o ); -} - - -/////////////////////////////////////////////////////////////////////////////////// - -CSerializedValue::CSerializedValue() -{ - Init(); -} - -CSerializedValue::CSerializedValue(CSerializedValue *parent, const std::string &name, const std::string &nameSpace, void *ref, int typeId) -{ - Init(); - - m_name = name; - m_nameSpace = nameSpace; - m_serializer = parent->m_serializer; - Store(ref, typeId); -} - -void CSerializedValue::Init() -{ - m_handlePtr = 0; - m_restorePtr = 0; - m_typeId = 0; - m_isInit = false; - m_serializer = 0; - m_userData = 0; - m_originalPtr = 0; -} - -void CSerializedValue::Uninit() -{ - m_isInit = false; - - ClearChildren(); - - if( m_userData ) - { - CUserType *type = m_serializer->m_userTypes[m_typeName]; - if( type ) - type->CleanupUserData(this); - m_userData = 0; - } -} - -void CSerializedValue::ClearChildren() -{ - // If this value is for an object handle that created an object during the restore - // then it is necessary to release the handle here, so we won't get a memory leak - if( (m_typeId & asTYPEID_OBJHANDLE) && m_children.size() == 1 && m_children[0]->m_restorePtr ) - { - m_serializer->m_engine->ReleaseScriptObject(m_children[0]->m_restorePtr, m_serializer->m_engine->GetObjectTypeById(m_children[0]->m_typeId)); - } - - for( size_t n = 0; n < m_children.size(); n++ ) - delete m_children[n]; - m_children.clear(); -} - -CSerializedValue::~CSerializedValue() -{ - Uninit(); -} - -CSerializedValue *CSerializedValue::FindByName(const std::string &name, const std::string &nameSpace) -{ - for( size_t i = 0; i < m_children.size(); i++ ) - if( m_children[i]->m_name == name && - m_children[i]->m_nameSpace == nameSpace ) - return m_children[i]; - - return 0; -} - -void CSerializedValue::GetAllPointersOfChildren(std::vector *ptrs) -{ - ptrs->push_back(m_originalPtr); - - for( size_t i = 0; i < m_children.size(); ++i ) - m_children[i]->GetAllPointersOfChildren(ptrs); -} - -CSerializedValue *CSerializedValue::FindByPtr(void *ptr) -{ - if( m_originalPtr == ptr ) - return this; - - for( size_t i = 0; i < m_children.size(); i++ ) - { - CSerializedValue *find = m_children[i]->FindByPtr(ptr); - if( find ) - return find; - } - - return 0; -} - -void *CSerializedValue::GetPointerToRestoredObject(void *ptr) -{ - if( m_originalPtr == ptr ) - return m_restorePtr; - - for( size_t i = 0; i < m_children.size(); ++i ) - { - void *ret = m_children[i]->GetPointerToRestoredObject(ptr); - if( ret ) - return ret; - } - - return 0; -} - -// find variable by ptr but looking only at those in the references, which will create a new object -CSerializedValue *CSerializedValue::FindByPtrInHandles(void *ptr) -{ - // if this handle created object - if( (m_typeId & asTYPEID_OBJHANDLE) && m_children.size() == 1 ) - { - if( m_children[0]->m_originalPtr == ptr ) - return this; - } - - if( !(m_typeId & asTYPEID_OBJHANDLE) ) - { - for( size_t i = 0; i < m_children.size(); i++ ) - { - CSerializedValue *find = m_children[i]->FindByPtrInHandles(ptr); - if( find ) - return find; - } - } - - return 0; -} - -void CSerializedValue::Store(void *ref, int typeId) -{ - m_isInit = true; - SetType(typeId); - m_originalPtr = ref; - - if( m_typeId & asTYPEID_OBJHANDLE ) - { - m_handlePtr = *(void**)ref; - } - else if( m_typeId & asTYPEID_SCRIPTOBJECT ) - { - asIScriptObject *obj = (asIScriptObject *)ref; - asIObjectType *type = obj->GetObjectType(); - SetType(type->GetTypeId()); - - // Store children - for( asUINT i = 0; i < type->GetPropertyCount(); i++ ) - { - int childId; - const char *childName; - type->GetProperty(i, &childName, &childId); - - m_children.push_back(new CSerializedValue(this, childName, "", obj->GetAddressOfProperty(i), childId)); - } - } - else - { - int size = m_serializer->m_engine->GetSizeOfPrimitiveType(m_typeId); - - if( size == 0 ) - { - // if it is user type( string, array, etc ... ) - if( m_serializer->m_userTypes[m_typeName] ) - m_serializer->m_userTypes[m_typeName]->Store(this, m_originalPtr); - - // it is script class - else if( GetType() ) - size = GetType()->GetSize(); - } - - if( size ) - { - m_mem.resize(size); - memcpy(&m_mem[0], ref, size); - } - } -} - -void CSerializedValue::Restore(void *ref, int typeId) -{ - if( !this || !m_isInit || !ref ) - return; - - // Verify that the stored type matched the new type of the value being restored - if( typeId <= asTYPEID_DOUBLE && typeId != m_typeId ) return; // TODO: We may try to do a type conversion for primitives - if( (typeId & ~asTYPEID_MASK_SEQNBR) ^ (m_typeId & ~asTYPEID_MASK_SEQNBR) ) return; - asIObjectType *type = m_serializer->m_engine->GetObjectTypeById(typeId); - if( type && m_typeName != type->GetName() ) return; - - // Set the new pointer and type - m_restorePtr = ref; - SetType(typeId); - - // Restore the value - if( m_typeId & asTYPEID_OBJHANDLE ) - { - // if need create objects - if( m_children.size() == 1 ) - { - asIObjectType *type = m_children[0]->GetType(); - - if( type->GetFactoryCount() == 0 ) - { - m_children[0]->m_restorePtr = m_handlePtr; - } - else - { - // Create a new script object, but don't call its constructor as we will initialize the members. - // Calling the constructor may have unwanted side effects if for example the constructor changes - // any outside entities, such as setting global variables to point to new objects, etc. - void *newObject = m_serializer->m_engine->CreateUninitializedScriptObject(type); - m_children[0]->Restore(newObject, type->GetTypeId()); - } - } - } - else if( m_typeId & asTYPEID_SCRIPTOBJECT ) - { - asIScriptObject *obj = (asIScriptObject *)ref; - asIObjectType *type = GetType(); - - // Retrieve children - for( asUINT i = 0; i < type->GetPropertyCount() ; i++ ) - { - const char *nameProperty; - int typeId; - type->GetProperty(i, &nameProperty, &typeId); - - CSerializedValue *var = FindByName(nameProperty, ""); - if( var ) - var->Restore(obj->GetAddressOfProperty(i), typeId); - } - } - else - { - if( m_mem.size() ) - { - // POD values can be restored with direct copy - memcpy(ref, &m_mem[0], m_mem.size()); - } - else if( m_serializer->m_userTypes[m_typeName] ) - { - // user type restore - m_serializer->m_userTypes[m_typeName]->Restore(this, m_restorePtr); - } - else - { - std::string str = "Cannot restore type '"; - str += type->GetName(); - str += "'"; - m_serializer->m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.c_str()); - } - } -} - -void CSerializedValue::CancelDuplicates(CSerializedValue *from) -{ - std::vector ptrs; - from->GetAllPointersOfChildren(&ptrs); - - for( size_t i = 0; i < ptrs.size(); ++i ) - { - CSerializedValue *find = m_serializer->m_root.FindByPtrInHandles(ptrs[i]); - - while( find ) - { - // cancel create object - find->ClearChildren(); - - // Find next link to this ptr - find = m_serializer->m_root.FindByPtrInHandles(ptrs[i]); - } - } -} - -void CSerializedValue::ReplaceHandles() -{ - if( m_handlePtr ) - { - // Find the object that the handle is referring to - CSerializedValue *handle_to = m_serializer->m_root.FindByPtr(m_handlePtr); - - // If the object hasn't been stored yet... - if( handle_to == 0 ) - { - // Store the object now - asIObjectType *type = GetType(); - CSerializedValue *need_create = new CSerializedValue(this, m_name, m_nameSpace, m_handlePtr, type->GetTypeId()); - - // Make sure all other handles that point to the same object - // are updated, so we don't end up creating duplicates - CancelDuplicates(need_create); - - m_children.push_back(need_create); - } - } - - // Replace the handles in the children too - for( size_t i = 0; i < m_children.size(); ++i ) - m_children[i]->ReplaceHandles(); -} - -void CSerializedValue::RestoreHandles() -{ - if( m_typeId & asTYPEID_OBJHANDLE ) - { - if( m_handlePtr ) - { - // Find the object the handle is supposed to point to - CSerializedValue *handleTo = m_serializer->m_root.FindByPtr(m_handlePtr); - - if( m_restorePtr && handleTo && handleTo->m_restorePtr ) - { - asIObjectType *type = m_serializer->m_engine->GetObjectTypeById(m_typeId); - - // If the handle is already pointing to something it must be released first - if( *(void**)m_restorePtr ) - m_serializer->m_engine->ReleaseScriptObject(*(void**)m_restorePtr, type); - - // Update the internal pointer - *(void**)m_restorePtr = handleTo->m_restorePtr; - - // Increase the reference - m_serializer->m_engine->AddRefScriptObject(handleTo->m_restorePtr, type); - } - } - else - { - // If the handle is pointing to something, we must release it to restore the null pointer - if( m_restorePtr && *(void**)m_restorePtr ) - { - m_serializer->m_engine->ReleaseScriptObject(*(void**)m_restorePtr, m_serializer->m_engine->GetObjectTypeById(m_typeId)); - *(void**)m_restorePtr = 0; - } - } - } - - // Do the same for the children - for( size_t i = 0; i < m_children.size(); ++i ) - m_children[i]->RestoreHandles(); -} - -void CSerializedValue::SetType(int typeId) -{ - m_typeId = typeId; - - asIObjectType *type = m_serializer->m_engine->GetObjectTypeById(typeId); - - if( type ) - m_typeName = type->GetName(); -} - -asIObjectType *CSerializedValue::GetType() -{ - if( !m_typeName.empty() ) - { - int newTypeId = m_serializer->m_mod->GetTypeIdByDecl(m_typeName.c_str()); - return m_serializer->m_engine->GetObjectTypeById(newTypeId); - } - - return 0; -} - -void CSerializedValue::SetUserData(void *data) -{ - m_userData = data; -} - -void *CSerializedValue::GetUserData() -{ - return m_userData; -} - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/add_on/serializer/serializer.h b/dependencies/angelscript/add_on/serializer/serializer.h deleted file mode 100644 index d44787af..00000000 --- a/dependencies/angelscript/add_on/serializer/serializer.h +++ /dev/null @@ -1,193 +0,0 @@ -// -// CSerializer -// -// This code was based on the CScriptReloader written by FDsagizi -// http://www.gamedev.net/topic/604890-dynamic-reloading-script/ -// - -#ifndef SERIALIZER_H -#define SERIALIZER_H - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -#include -#include -#include - -BEGIN_AS_NAMESPACE - -class CSerializer; -class CSerializedValue; - -// Need for register user types objects -// string, any, array... for all object -// user ref type. -struct CUserType -{ - virtual ~CUserType() {}; - virtual void Store(CSerializedValue *val, void *ptr) = 0; - virtual void Restore(CSerializedValue *val, void *ptr) = 0; - virtual void CleanupUserData(CSerializedValue * /*val*/) {} -}; - - -class CSerializedValue -{ -public: - CSerializedValue(); - CSerializedValue(CSerializedValue *parent, const std::string &name, const std::string &nameSpace, void *ref, int typeId); - ~CSerializedValue(); - - // Save the object and its children - void Store(void *ref, int refTypeId); - - // Restore the object and its children - void Restore(void *ref, int refTypeId); - - // Set type of this var - void SetType(int typeId); - - // Returns the object type for non-primitives - asIObjectType *GetType(); - - // Get child by name variable - CSerializedValue *FindByName(const std::string &name, const std::string &nameSpace); - - // Find variable by ptr - CSerializedValue *FindByPtr(void *ptr); - - // User data - void *GetUserData(); - void SetUserData(void *data); - - // Children, e.g. properties of a script class, or elements - // of an array, or object pointed to by a handle unless it - // is already a variable) - std::vector m_children; - -protected: - friend class CSerializer; - - void Init(); - void Uninit(); - - // you first need to save all the objects before you can save references to objects - void ReplaceHandles(); - - // After the objects has been restored, the handles needs to - // be updated to point to the right objects - void RestoreHandles(); - - // Recursively get all ptrs of the children - void GetAllPointersOfChildren(std::vector *ptrs); - - // may be that the two references refer to the same variable. - // But this variable is not available in the global list. - // According to this reference will be restores it. - // And so two links are not created 2 variables, - // it is necessary to cancel the creation of one of them. - void CancelDuplicates(CSerializedValue *from); - - // Find variable by ptr but looking only at those in the references, which will create a new object - CSerializedValue *FindByPtrInHandles(void *ptr); - - // ptr - is a handle to class - void *GetPointerToRestoredObject(void *ptr); - - // Cleanup children - void ClearChildren(); - - // The serializer object - CSerializer *m_serializer; - - // The user data can be used by CUserType to store extra information - void *m_userData; - - // The type id of the stored value - int m_typeId; - - // For non-primitives the typeId may change if the module is reloaded so - // it is necessary to store the type name to determine the new type id - std::string m_typeName; - - // Name of variable or property - std::string m_name; - std::string m_nameSpace; - - // Is initialized - bool m_isInit; - - // 'this' pointer to variable. - // While storing, this points to the actual variable that was stored. - // While restoring, it is just a unique identifier. - void *m_originalPtr; - - // where handle references - // While storing, this points to the actual object. - // While restoring, it is just a unique identifier. - void *m_handlePtr; - - // new address object, ie address the restoration - // While storing this isn't used. - // While restoring it will point to the actual variable/object that is restored. - void *m_restorePtr; - - // Serialized data for primitives - std::vector m_mem; -}; - - -// This class keeps a list of variables, then restores them after the script is rebuilt. -// But you have to be careful with the change of signature in classes, or -// changing the types of objects. You can remove or add variables, functions, -// methods, but you can not (yet) change the type of variables. -// -// You also need to understand that after a rebuild you should get -// new functions and typeids from the module. -class CSerializer -{ -public: - CSerializer(); - ~CSerializer(); - - // Add implementation for serializing user types - void AddUserType(CUserType *ref, const std::string &name); - - // Store all global variables in the module - int Store(asIScriptModule *mod); - - // Restore all global variables after reloading script - int Restore(asIScriptModule *mod); - - // Store extra objects that are not seen from the module's global variables - void AddExtraObjectToStore(asIScriptObject *object); - - // Return new pointer to restored object - void *GetPointerToRestoredObject(void *originalObject); - -protected: - friend class CSerializedValue; - - CSerializedValue m_root; - asIScriptEngine *m_engine; - asIScriptModule *m_mod; - - std::map m_userTypes; - - struct SExtraObject - { - asIScriptObject *originalObject; - std::string originalClassName; - int originalTypeId; - }; - - std::vector m_extraObjects; -}; - - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/add_on/weakref/weakref.cpp b/dependencies/angelscript/add_on/weakref/weakref.cpp deleted file mode 100644 index 23cc7bb6..00000000 --- a/dependencies/angelscript/add_on/weakref/weakref.cpp +++ /dev/null @@ -1,320 +0,0 @@ - -// The CScriptWeakRef class was originally implemented by vroad in March 2013 - -#include "weakref.h" -#include -#include -#include // strstr() - -BEGIN_AS_NAMESPACE - -static CScriptWeakRef* ScriptWeakRefFactory(asIObjectType *type) -{ - return new CScriptWeakRef(type); -} - -static CScriptWeakRef* ScriptWeakRefFactory2(asIObjectType *type, void *ref) -{ - CScriptWeakRef *wr = new CScriptWeakRef(ref, type); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - asIScriptContext *ctx = asGetActiveContext(); - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - wr->Release(); - return 0; - } - - return wr; -} - -static bool ScriptWeakRefTemplateCallback(asIObjectType *ot, bool &/*dontGarbageCollect*/) -{ - asIObjectType *subType = ot->GetSubType(); - - // Weak references only work for reference types - if( subType == 0 ) return false; - if( !(subType->GetFlags() & asOBJ_REF) ) return false; - - // The subtype shouldn't be a handle - if( ot->GetSubTypeId() & asTYPEID_OBJHANDLE ) - return false; - - // Make sure the type really supports weak references - asUINT cnt = subType->GetBehaviourCount(); - for( asUINT n = 0; n < cnt; n++ ) - { - asEBehaviours beh; - subType->GetBehaviourByIndex(n, &beh); - if( beh == asBEHAVE_GET_WEAKREF_FLAG ) - return true; - } - - ot->GetEngine()->WriteMessage("weakref", 0, 0, asMSGTYPE_ERROR, "The subtype doesn't support weak references"); - return false; -} - -CScriptWeakRef::CScriptWeakRef(asIObjectType *type) -{ - refCount = 1; - m_ref = 0; - m_type = type; - m_type->AddRef(); - m_weakRefFlag = 0; -} - -CScriptWeakRef::CScriptWeakRef(const CScriptWeakRef &other) -{ - refCount = 1; - m_ref = other.m_ref; - m_type = other.m_type; - m_type->AddRef(); - m_weakRefFlag = other.m_weakRefFlag; - if( m_weakRefFlag ) - m_weakRefFlag->AddRef(); -} - -CScriptWeakRef::CScriptWeakRef(void *ref, asIObjectType *type) -{ - refCount = 1; - m_ref = ref; - m_type = type; - m_type->AddRef(); - - // The given type should be the weakref template instance - assert( strcmp(type->GetName(), "weakref") == 0 || - strcmp(type->GetName(), "const_weakref") == 0 ); - - // Get the shared flag that will tell us when the object has been destroyed - // This is threadsafe as we hold a strong reference to the object - m_weakRefFlag = m_type->GetEngine()->GetWeakRefFlagOfScriptObject(m_ref, m_type->GetSubType()); - if( m_weakRefFlag ) - m_weakRefFlag->AddRef(); -} - -CScriptWeakRef::~CScriptWeakRef() -{ - if( m_type ) - m_type->Release(); - if( m_weakRefFlag ) - m_weakRefFlag->Release(); -} - -void CScriptWeakRef::AddRef() const -{ - asAtomicInc(refCount); -} - -void CScriptWeakRef::Release() const -{ - if( asAtomicDec(refCount) == 0 ) - { - // When reaching 0 no more references to this instance - // exists and the object should be destroyed - delete this; - } -} - -CScriptWeakRef &CScriptWeakRef::operator =(const CScriptWeakRef &other) -{ - // Don't do anything if it is the same reference - if( m_ref == other.m_ref ) - return *this; - - m_ref = other.m_ref; - - if( m_type ) - m_type->Release(); - m_type = other.m_type; - if( m_type ) - m_type->AddRef(); - - if( m_weakRefFlag ) - m_weakRefFlag->Release(); - m_weakRefFlag = other.m_weakRefFlag; - if( m_weakRefFlag ) - m_weakRefFlag->AddRef(); - - return *this; -} - -asIObjectType *CScriptWeakRef::GetRefType() const -{ - return m_type->GetSubType(); -} - -bool CScriptWeakRef::operator==(const CScriptWeakRef &o) const -{ - if( m_ref == o.m_ref && - m_type == o.m_type ) - return true; - - // TODO: If type is not the same, we should attempt to do a dynamic cast, - // which may change the pointer for application registered classes - - return false; -} - -bool CScriptWeakRef::operator!=(const CScriptWeakRef &o) const -{ - return !(*this == o); -} - -// AngelScript: used as '@obj = ref.get();' -void *CScriptWeakRef::Get() const -{ - // If we hold a null handle, then just return null - if( m_ref == 0 || m_weakRefFlag == 0 ) - return 0; - - // Lock on the shared bool, so we can be certain it won't be changed to true - // between the inspection of the flag and the increase of the ref count in the - // owning object. - m_weakRefFlag->Lock(); - if( !m_weakRefFlag->Get() ) - { - m_type->GetEngine()->AddRefScriptObject(m_ref, m_type->GetSubType()); - m_weakRefFlag->Unlock(); - return m_ref; - } - m_weakRefFlag->Unlock(); - - return 0; -} - -void RegisterScriptWeakRef_Native(asIScriptEngine *engine) -{ - int r; - - // Register a type for non-const handles - r = engine->RegisterObjectType("weakref", 0, asOBJ_REF | asOBJ_TEMPLATE); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_FACTORY, "weakref@ f(int&in)", asFUNCTION(ScriptWeakRefFactory), asCALL_CDECL); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_FACTORY, "weakref@ f(int&in, T@+)", asFUNCTION(ScriptWeakRefFactory2), asCALL_CDECL); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptWeakRef,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptWeakRef,Release), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("weakref", "T@ get() const", asMETHODPR(CScriptWeakRef, Get, () const, void*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("weakref", "weakref &opAssign(const weakref &in)", asMETHOD(CScriptWeakRef, operator=), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("weakref", "bool opEquals(const weakref &in) const", asMETHODPR(CScriptWeakRef, operator==, (const CScriptWeakRef &) const, bool), asCALL_THISCALL); assert( r >= 0 ); - - // Register another type for const handles - r = engine->RegisterObjectType("const_weakref", 0, asOBJ_REF | asOBJ_TEMPLATE); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_FACTORY, "const_weakref@ f(int&in)", asFUNCTION(ScriptWeakRefFactory), asCALL_CDECL); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_FACTORY, "const_weakref@ f(int&in, const T@+)", asFUNCTION(ScriptWeakRefFactory2), asCALL_CDECL); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptWeakRef,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptWeakRef,Release), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("const_weakref", "const T@ get() const", asMETHODPR(CScriptWeakRef, Get, () const, void*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opAssign(const const_weakref &in)", asMETHOD(CScriptWeakRef, operator=), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const const_weakref &in) const", asMETHODPR(CScriptWeakRef, operator==, (const CScriptWeakRef &) const, bool), asCALL_THISCALL); assert( r >= 0 ); - - // Allow non-const weak references to be converted to const weak references - r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opAssign(const weakref &in)", asMETHOD(CScriptWeakRef, operator=), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const weakref &in) const", asMETHODPR(CScriptWeakRef, operator==, (const CScriptWeakRef &) const, bool), asCALL_THISCALL); assert( r >= 0 ); -} - -static void ScriptWeakRefFactory_Generic(asIScriptGeneric *gen) -{ - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); - - *(CScriptWeakRef**)gen->GetAddressOfReturnLocation() = ScriptWeakRefFactory(ot); -} - -static void ScriptWeakRefFactory2_Generic(asIScriptGeneric *gen) -{ - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); - void *ref = gen->GetArgAddress(1); - - *(CScriptWeakRef**)gen->GetAddressOfReturnLocation() = ScriptWeakRefFactory2(ot, ref); -} - -static void ScriptWeakRefAddRef_Generic(asIScriptGeneric *gen) -{ - CScriptWeakRef *self = (CScriptWeakRef*)gen->GetObject(); - self->AddRef(); -} - -static void ScriptWeakRefRelease_Generic(asIScriptGeneric *gen) -{ - CScriptWeakRef *self = (CScriptWeakRef*)gen->GetObject(); - self->Release(); -} - -void CScriptWeakRef_Get_Generic(asIScriptGeneric *gen) -{ - CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); - gen->SetReturnAddress(self->Get()); -} - -void CScriptWeakRef_Assign_Generic(asIScriptGeneric *gen) -{ - CScriptWeakRef *other = reinterpret_cast(gen->GetArgAddress(0)); - CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); - *self = *other; - gen->SetReturnAddress(self); -} - -void CScriptWeakRef_Equals_Generic(asIScriptGeneric *gen) -{ - CScriptWeakRef *other = reinterpret_cast(gen->GetArgAddress(0)); - CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); - gen->SetReturnByte(*self == *other); -} - -static void ScriptWeakRefTemplateCallback_Generic(asIScriptGeneric *gen) -{ - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); - bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1); - *(bool*)gen->GetAddressOfReturnLocation() = ScriptWeakRefTemplateCallback(ot, *dontGarbageCollect); -} - -void RegisterScriptWeakRef_Generic(asIScriptEngine *engine) -{ - int r; - - // Register a type for non-const handles - r = engine->RegisterObjectType("weakref", 0, asOBJ_REF | asOBJ_TEMPLATE); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_FACTORY, "weakref@ f(int&in)", asFUNCTION(ScriptWeakRefFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_FACTORY, "weakref@ f(int&in, T@)", asFUNCTION(ScriptWeakRefFactory2_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptWeakRefAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptWeakRefRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("weakref", "T@ get() const", asFUNCTION(CScriptWeakRef_Get_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("weakref", "weakref &opAssign(const weakref &in)", asFUNCTION(CScriptWeakRef_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("weakref", "bool opEquals(const weakref &in) const", asFUNCTION(CScriptWeakRef_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); - - // Register another type for const handles - r = engine->RegisterObjectType("const_weakref", 0, asOBJ_REF | asOBJ_TEMPLATE); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_FACTORY, "const_weakref@ f(int&in)", asFUNCTION(ScriptWeakRefFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_FACTORY, "const_weakref@ f(int&in, const T@)", asFUNCTION(ScriptWeakRefFactory2_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptWeakRefAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptWeakRefRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("const_weakref", "const T@ get() const", asFUNCTION(CScriptWeakRef_Get_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opAssign(const const_weakref &in)", asFUNCTION(CScriptWeakRef_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const const_weakref &in) const", asFUNCTION(CScriptWeakRef_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); - - // Allow non-const weak references to be converted to const weak references - r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opAssign(const weakref &in)", asFUNCTION(CScriptWeakRef_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const weakref &in) const", asFUNCTION(CScriptWeakRef_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); -} - -void RegisterScriptWeakRef(asIScriptEngine *engine) -{ - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptWeakRef_Generic(engine); - else - RegisterScriptWeakRef_Native(engine); -} - - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/add_on/weakref/weakref.h b/dependencies/angelscript/add_on/weakref/weakref.h deleted file mode 100644 index ccea897a..00000000 --- a/dependencies/angelscript/add_on/weakref/weakref.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef SCRIPTWEAKREF_H -#define SCRIPTWEAKREF_H - -// The CScriptWeakRef class was originally implemented by vroad in March 2013 - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - - -BEGIN_AS_NAMESPACE - -class CScriptWeakRef -{ -public: - // Constructors - CScriptWeakRef(asIObjectType *type); - CScriptWeakRef(const CScriptWeakRef &other); - CScriptWeakRef(void *ref, asIObjectType *type); - - // Memory management - void AddRef() const; - void Release() const; - - // Copy the stored value from another weakref object - CScriptWeakRef &operator=(const CScriptWeakRef &other); - - // Compare equalness - bool operator==(const CScriptWeakRef &o) const; - bool operator!=(const CScriptWeakRef &o) const; - - // Returns the object if it is still alive - void *Get() const; - - // Returns the type of the reference held - asIObjectType *GetRefType() const; - -protected: - ~CScriptWeakRef(); - - // These functions need to have access to protected - // members in order to call them from the script engine - friend void RegisterScriptWeakRef_Native(asIScriptEngine *engine); - - mutable int refCount; - void *m_ref; - asIObjectType *m_type; - asILockableSharedBool *m_weakRefFlag; -}; - -void RegisterScriptWeakRef(asIScriptEngine *engine); - -END_AS_NAMESPACE - -#endif \ No newline at end of file diff --git a/dependencies/angelscript/include/angelscript.h b/dependencies/angelscript/include/angelscript.h deleted file mode 100644 index d1e43b53..00000000 --- a/dependencies/angelscript/include/angelscript.h +++ /dev/null @@ -1,1902 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// angelscript.h -// -// The script engine interface -// - - -#ifndef ANGELSCRIPT_H -#define ANGELSCRIPT_H - -#include -#ifndef _MSC_VER -#include -#endif - -#ifdef AS_USE_NAMESPACE - #define BEGIN_AS_NAMESPACE namespace AngelScript { - #define END_AS_NAMESPACE } - #define AS_NAMESPACE_QUALIFIER AngelScript:: -#else - #define BEGIN_AS_NAMESPACE - #define END_AS_NAMESPACE - #define AS_NAMESPACE_QUALIFIER :: -#endif - -BEGIN_AS_NAMESPACE - -// AngelScript version - -#define ANGELSCRIPT_VERSION 22902 -#define ANGELSCRIPT_VERSION_STRING "2.29.2" - -// Data types - -class asIScriptEngine; -class asIScriptModule; -class asIScriptContext; -class asIScriptGeneric; -class asIScriptObject; -class asIObjectType; -class asIScriptFunction; -class asIBinaryStream; -class asIJITCompiler; -class asIThreadManager; -class asILockableSharedBool; - -// Enumerations and constants - -// Return codes -enum asERetCodes -{ - asSUCCESS = 0, - asERROR = -1, - asCONTEXT_ACTIVE = -2, - asCONTEXT_NOT_FINISHED = -3, - asCONTEXT_NOT_PREPARED = -4, - asINVALID_ARG = -5, - asNO_FUNCTION = -6, - asNOT_SUPPORTED = -7, - asINVALID_NAME = -8, - asNAME_TAKEN = -9, - asINVALID_DECLARATION = -10, - asINVALID_OBJECT = -11, - asINVALID_TYPE = -12, - asALREADY_REGISTERED = -13, - asMULTIPLE_FUNCTIONS = -14, - asNO_MODULE = -15, - asNO_GLOBAL_VAR = -16, - asINVALID_CONFIGURATION = -17, - asINVALID_INTERFACE = -18, - asCANT_BIND_ALL_FUNCTIONS = -19, - asLOWER_ARRAY_DIMENSION_NOT_REGISTERED = -20, - asWRONG_CONFIG_GROUP = -21, - asCONFIG_GROUP_IS_IN_USE = -22, - asILLEGAL_BEHAVIOUR_FOR_TYPE = -23, - asWRONG_CALLING_CONV = -24, - asBUILD_IN_PROGRESS = -25, - asINIT_GLOBAL_VARS_FAILED = -26, - asOUT_OF_MEMORY = -27 -}; - -// Engine properties -enum asEEngineProp -{ - asEP_ALLOW_UNSAFE_REFERENCES = 1, - asEP_OPTIMIZE_BYTECODE = 2, - asEP_COPY_SCRIPT_SECTIONS = 3, - asEP_MAX_STACK_SIZE = 4, - asEP_USE_CHARACTER_LITERALS = 5, - asEP_ALLOW_MULTILINE_STRINGS = 6, - asEP_ALLOW_IMPLICIT_HANDLE_TYPES = 7, - asEP_BUILD_WITHOUT_LINE_CUES = 8, - asEP_INIT_GLOBAL_VARS_AFTER_BUILD = 9, - asEP_REQUIRE_ENUM_SCOPE = 10, - asEP_SCRIPT_SCANNER = 11, - asEP_INCLUDE_JIT_INSTRUCTIONS = 12, - asEP_STRING_ENCODING = 13, - asEP_PROPERTY_ACCESSOR_MODE = 14, - asEP_EXPAND_DEF_ARRAY_TO_TMPL = 15, - asEP_AUTO_GARBAGE_COLLECT = 16, - asEP_DISALLOW_GLOBAL_VARS = 17, - asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT = 18, - asEP_COMPILER_WARNINGS = 19, - asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE = 20, - asEP_ALTER_SYNTAX_NAMED_ARGS = 21, - asEP_DISABLE_INTEGER_DIVISION = 22, - - asEP_LAST_PROPERTY -}; - -// Calling conventions -enum asECallConvTypes -{ - asCALL_CDECL = 0, - asCALL_STDCALL = 1, - asCALL_THISCALL_ASGLOBAL = 2, - asCALL_THISCALL = 3, - asCALL_CDECL_OBJLAST = 4, - asCALL_CDECL_OBJFIRST = 5, - asCALL_GENERIC = 6, - asCALL_THISCALL_OBJLAST = 7, - asCALL_THISCALL_OBJFIRST = 8 -}; - -// Object type flags -enum asEObjTypeFlags -{ - asOBJ_REF = (1<<0), - asOBJ_VALUE = (1<<1), - asOBJ_GC = (1<<2), - asOBJ_POD = (1<<3), - asOBJ_NOHANDLE = (1<<4), - asOBJ_SCOPED = (1<<5), - asOBJ_TEMPLATE = (1<<6), - asOBJ_ASHANDLE = (1<<7), - asOBJ_APP_CLASS = (1<<8), - asOBJ_APP_CLASS_CONSTRUCTOR = (1<<9), - asOBJ_APP_CLASS_DESTRUCTOR = (1<<10), - asOBJ_APP_CLASS_ASSIGNMENT = (1<<11), - asOBJ_APP_CLASS_COPY_CONSTRUCTOR = (1<<12), - asOBJ_APP_CLASS_C = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR), - asOBJ_APP_CLASS_CD = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR), - asOBJ_APP_CLASS_CA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), - asOBJ_APP_CLASS_CK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), - asOBJ_APP_CLASS_CDA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), - asOBJ_APP_CLASS_CDK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), - asOBJ_APP_CLASS_CAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), - asOBJ_APP_CLASS_CDAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), - asOBJ_APP_CLASS_D = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR), - asOBJ_APP_CLASS_DA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), - asOBJ_APP_CLASS_DK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), - asOBJ_APP_CLASS_DAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), - asOBJ_APP_CLASS_A = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_ASSIGNMENT), - asOBJ_APP_CLASS_AK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), - asOBJ_APP_CLASS_K = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), - asOBJ_APP_PRIMITIVE = (1<<13), - asOBJ_APP_FLOAT = (1<<14), - asOBJ_APP_ARRAY = (1<<15), - asOBJ_APP_CLASS_ALLINTS = (1<<16), - asOBJ_APP_CLASS_ALLFLOATS = (1<<17), - asOBJ_NOCOUNT = (1<<18), - asOBJ_APP_CLASS_ALIGN8 = (1<<19), - asOBJ_MASK_VALID_FLAGS = 0x0FFFFF, - // Internal flags - asOBJ_SCRIPT_OBJECT = (1<<20), - asOBJ_SHARED = (1<<21), - asOBJ_NOINHERIT = (1<<22), - asOBJ_SCRIPT_FUNCTION = (1<<23), - asOBJ_IMPLICIT_HANDLE = (1<<24), - asOBJ_LIST_PATTERN = (1<<25), - asOBJ_ENUM = (1<<26), - asOBJ_TEMPLATE_SUBTYPE = (1<<27), - asOBJ_TYPEDEF = (1<<28), - asOBJ_ABSTRACT = (1<<29), - asOBJ_APP_ALIGN16 = (1<<30) -}; - -// Behaviours -enum asEBehaviours -{ - // Value object memory management - asBEHAVE_CONSTRUCT, - asBEHAVE_LIST_CONSTRUCT, - asBEHAVE_DESTRUCT, - - // Reference object memory management - asBEHAVE_FACTORY, - asBEHAVE_LIST_FACTORY, - asBEHAVE_ADDREF, - asBEHAVE_RELEASE, - asBEHAVE_GET_WEAKREF_FLAG, - - // Object operators - asBEHAVE_VALUE_CAST, - asBEHAVE_IMPLICIT_VALUE_CAST, - asBEHAVE_REF_CAST, - asBEHAVE_IMPLICIT_REF_CAST, - asBEHAVE_TEMPLATE_CALLBACK, - - // Garbage collection behaviours - asBEHAVE_FIRST_GC, - asBEHAVE_GETREFCOUNT = asBEHAVE_FIRST_GC, - asBEHAVE_SETGCFLAG, - asBEHAVE_GETGCFLAG, - asBEHAVE_ENUMREFS, - asBEHAVE_RELEASEREFS, - asBEHAVE_LAST_GC = asBEHAVE_RELEASEREFS, - - asBEHAVE_MAX -}; - -// Context states -enum asEContextState -{ - asEXECUTION_FINISHED = 0, - asEXECUTION_SUSPENDED = 1, - asEXECUTION_ABORTED = 2, - asEXECUTION_EXCEPTION = 3, - asEXECUTION_PREPARED = 4, - asEXECUTION_UNINITIALIZED = 5, - asEXECUTION_ACTIVE = 6, - asEXECUTION_ERROR = 7 -}; - -// Message types -enum asEMsgType -{ - asMSGTYPE_ERROR = 0, - asMSGTYPE_WARNING = 1, - asMSGTYPE_INFORMATION = 2 -}; - -// Garbage collector flags -enum asEGCFlags -{ - asGC_FULL_CYCLE = 1, - asGC_ONE_STEP = 2, - asGC_DESTROY_GARBAGE = 4, - asGC_DETECT_GARBAGE = 8 -}; - -// Token classes -enum asETokenClass -{ - asTC_UNKNOWN = 0, - asTC_KEYWORD = 1, - asTC_VALUE = 2, - asTC_IDENTIFIER = 3, - asTC_COMMENT = 4, - asTC_WHITESPACE = 5 -}; - -// Type id flags -enum asETypeIdFlags -{ - asTYPEID_VOID = 0, - asTYPEID_BOOL = 1, - asTYPEID_INT8 = 2, - asTYPEID_INT16 = 3, - asTYPEID_INT32 = 4, - asTYPEID_INT64 = 5, - asTYPEID_UINT8 = 6, - asTYPEID_UINT16 = 7, - asTYPEID_UINT32 = 8, - asTYPEID_UINT64 = 9, - asTYPEID_FLOAT = 10, - asTYPEID_DOUBLE = 11, - asTYPEID_OBJHANDLE = 0x40000000, - asTYPEID_HANDLETOCONST = 0x20000000, - asTYPEID_MASK_OBJECT = 0x1C000000, - asTYPEID_APPOBJECT = 0x04000000, - asTYPEID_SCRIPTOBJECT = 0x08000000, - asTYPEID_TEMPLATE = 0x10000000, - asTYPEID_MASK_SEQNBR = 0x03FFFFFF -}; - -// Type modifiers -enum asETypeModifiers -{ - asTM_NONE = 0, - asTM_INREF = 1, - asTM_OUTREF = 2, - asTM_INOUTREF = 3, - asTM_CONST = 4 -}; - -// GetModule flags -enum asEGMFlags -{ - asGM_ONLY_IF_EXISTS = 0, - asGM_CREATE_IF_NOT_EXISTS = 1, - asGM_ALWAYS_CREATE = 2 -}; - -// Compile flags -enum asECompileFlags -{ - asCOMP_ADD_TO_MODULE = 1 -}; - -// Function types -enum asEFuncType -{ - asFUNC_DUMMY =-1, - asFUNC_SYSTEM = 0, - asFUNC_SCRIPT = 1, - asFUNC_INTERFACE = 2, - asFUNC_VIRTUAL = 3, - asFUNC_FUNCDEF = 4, - asFUNC_IMPORTED = 5, - asFUNC_DELEGATE = 6 -}; - -// -// asBYTE = 8 bits -// asWORD = 16 bits -// asDWORD = 32 bits -// asQWORD = 64 bits -// asPWORD = size of pointer -// -typedef unsigned char asBYTE; -typedef unsigned short asWORD; -typedef unsigned int asUINT; -#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__S3E__) - // 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; -#else - typedef uintptr_t asPWORD; -#endif -#ifdef __LP64__ - typedef unsigned int asDWORD; - typedef unsigned long asQWORD; - typedef long asINT64; -#else - typedef unsigned long asDWORD; - #if defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_CC) - typedef uint64_t asQWORD; - typedef int64_t asINT64; - #else - typedef unsigned __int64 asQWORD; - typedef __int64 asINT64; - #endif -#endif - -// Is the target a 64bit system? -#if defined(__LP64__) || defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) - #ifndef AS_64BIT_PTR - #define AS_64BIT_PTR - #endif -#endif - -typedef void (*asFUNCTION_t)(); -typedef void (*asGENFUNC_t)(asIScriptGeneric *); -typedef void *(*asALLOCFUNC_t)(size_t); -typedef void (*asFREEFUNC_t)(void *); -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 asIScriptContext *(*asREQUESTCONTEXTFUNC_t)(asIScriptEngine *, void *); -typedef void (*asRETURNCONTEXTFUNC_t)(asIScriptEngine *, asIScriptContext *, void *); - -// Check if the compiler can use C++11 features -#if !defined(_MSC_VER) || _MSC_VER >= 1700 // MSVC 2012 -#if !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) // gnuc 4.7 -#if !(defined(__GNUC__) && defined(__cplusplus) && __cplusplus < 201103L) // g++ -std=c++11 -#if !defined(__SUNPRO_CC) -#define AS_CAN_USE_CPP11 1 -#endif -#endif -#endif -#endif - -// This macro does basically the same thing as offsetof defined in stddef.h, but -// GNUC should not complain about the usage as I'm not using 0 as the base pointer. -#define asOFFSET(s,m) ((size_t)(&reinterpret_cast(100000)->m)-100000) - -#define asFUNCTION(f) asFunctionPtr(f) -#if (defined(_MSC_VER) && _MSC_VER <= 1200) || (defined(__BORLANDC__) && __BORLANDC__ < 0x590) -// MSVC 6 has a bug that prevents it from properly compiling using the correct asFUNCTIONPR with operator > -// so we need to use ordinary C style cast instead of static_cast. The drawback is that the compiler can't -// check that the cast is really valid. -// 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))) -#endif - -#ifndef AS_NO_CLASS_METHODS - -class asCUnknownClass; -typedef void (asCUnknownClass::*asMETHOD_t)(); - -struct asSFuncPtr -{ - asSFuncPtr(asBYTE f = 0) - { - for( size_t n = 0; n < sizeof(ptr.dummy); n++ ) - ptr.dummy[n] = 0; - flag = f; - } - - void CopyMethodPtr(const void *mthdPtr, size_t size) - { - for( size_t n = 0; n < size; n++ ) - ptr.dummy[n] = reinterpret_cast(mthdPtr)[n]; - } - - union - { - // The largest known method point is 20 bytes (MSVC 64bit), - // but with 8byte alignment this becomes 24 bytes. So we need - // to be able to store at least that much. - char dummy[25]; - struct {asMETHOD_t mthd; char dummy[25-sizeof(asMETHOD_t)];} m; - struct {asFUNCTION_t func; char dummy[25-sizeof(asFUNCTION_t)];} f; - } ptr; - asBYTE flag; // 1 = generic, 2 = global func, 3 = method -}; - -#if defined(__BORLANDC__) -// A bug in BCC (QC #85374) makes it impossible to distinguish const/non-const method overloads -// with static_cast<>. The workaround is to use an _implicit_cast instead. - - #if __BORLANDC__ < 0x590 - // BCC v5.8 (C++Builder 2006) and earlier have an even more annoying bug which causes - // the "pretty" workaround below (with _implicit_cast<>) to fail. For these compilers - // we need to use a traditional C-style cast. - #define AS_METHOD_AMBIGUITY_CAST(t) (t) - #else -template - T _implicit_cast (T val) -{ return val; } - #define AS_METHOD_AMBIGUITY_CAST(t) AS_NAMESPACE_QUALIFIER _implicit_cast - #endif -#else - #define AS_METHOD_AMBIGUITY_CAST(t) static_cast -#endif - -#define asMETHOD(c,m) asSMethodPtr::Convert((void (c::*)())(&c::m)) -#define asMETHODPR(c,m,p,r) asSMethodPtr::Convert(AS_METHOD_AMBIGUITY_CAST(r (c::*)p)(&c::m)) - -#else // Class methods are disabled - -struct asSFuncPtr -{ - asSFuncPtr(asBYTE f) - { - for( int n = 0; n < sizeof(ptr.dummy); n++ ) - ptr.dummy[n] = 0; - flag = f; - } - - union - { - char dummy[25]; // largest known class method pointer - struct {asFUNCTION_t func; char dummy[25-sizeof(asFUNCTION_t)];} f; - } ptr; - asBYTE flag; // 1 = generic, 2 = global func -}; - -#endif - -struct asSMessageInfo -{ - const char *section; - int row; - int col; - asEMsgType type; - const char *message; -}; - - -// API functions - -// ANGELSCRIPT_EXPORT is defined when compiling the dll or lib -// ANGELSCRIPT_DLL_LIBRARY_IMPORT is defined when dynamically linking to the -// dll through the link lib automatically generated by MSVC++ -// ANGELSCRIPT_DLL_MANUAL_IMPORT is defined when manually loading the dll -// Don't define anything when linking statically to the lib - -#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) - #if defined(ANGELSCRIPT_EXPORT) - #define AS_API __declspec(dllexport) - #elif defined(ANGELSCRIPT_DLL_LIBRARY_IMPORT) - #define AS_API __declspec(dllimport) - #else // statically linked library - #define AS_API - #endif -#elif defined(__GNUC__) - #if defined(ANGELSCRIPT_EXPORT) - #define AS_API __attribute__((visibility ("default"))) - #else - #define AS_API - #endif -#else - #define AS_API -#endif - -#ifndef ANGELSCRIPT_DLL_MANUAL_IMPORT -extern "C" -{ - // Engine - AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version); - AS_API const char *asGetLibraryVersion(); - AS_API const char *asGetLibraryOptions(); - - // Context - AS_API asIScriptContext *asGetActiveContext(); - - // Thread support - AS_API int asPrepareMultithread(asIThreadManager *externalMgr = 0); - AS_API void asUnprepareMultithread(); - AS_API asIThreadManager *asGetThreadManager(); - AS_API void asAcquireExclusiveLock(); - AS_API void asReleaseExclusiveLock(); - AS_API void asAcquireSharedLock(); - AS_API void asReleaseSharedLock(); - AS_API int asAtomicInc(int &value); - AS_API int asAtomicDec(int &value); - AS_API int asThreadCleanup(); - - // Memory management - AS_API int asSetGlobalMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); - AS_API int asResetGlobalMemoryFunctions(); - AS_API void *asAllocMem(size_t size); - AS_API void asFreeMem(void *mem); - - // Auxiliary - AS_API asILockableSharedBool *asCreateLockableSharedBool(); -} -#endif // ANGELSCRIPT_DLL_MANUAL_IMPORT - -// Determine traits of a type for registration of value types -// Relies on C++11 features so it can not be used with non-compliant compilers -#ifdef AS_CAN_USE_CPP11 - -END_AS_NAMESPACE -#include -BEGIN_AS_NAMESPACE - -template -asUINT asGetTypeTraits() -{ -#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5) - // MSVC & XCode/Clang & gnuc 5+ - // C++11 compliant code - bool hasConstructor = std::is_default_constructible::value && !std::is_trivially_default_constructible::value; - bool hasDestructor = std::is_destructible::value && !std::is_trivially_destructible::value; - bool hasAssignmentOperator = std::is_copy_assignable::value && !std::is_trivially_copy_assignable::value; - bool hasCopyConstructor = std::is_copy_constructible::value && !std::is_trivially_copy_constructible::value; -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - // gnuc 4.8+ - // gnuc is using a mix of C++11 standard and pre-standard templates - bool hasConstructor = std::is_default_constructible::value && !std::has_trivial_default_constructor::value; - bool hasDestructor = std::is_destructible::value && !std::is_trivially_destructible::value; - bool hasAssignmentOperator = std::is_copy_assignable::value && !std::has_trivial_copy_assign::value; - bool hasCopyConstructor = std::is_copy_constructible::value && !std::has_trivial_copy_constructor::value; -#else - // Not fully C++11 compliant. The has_trivial checks were used while the standard was still - // being elaborated, but were then removed in favor of the above is_trivially checks - // http://stackoverflow.com/questions/12702103/writing-code-that-works-when-has-trivial-destructor-is-defined-instead-of-is - // https://github.com/mozart/mozart2/issues/51 - bool hasConstructor = std::is_default_constructible::value && !std::has_trivial_default_constructor::value; - bool hasDestructor = std::is_destructible::value && !std::has_trivial_destructor::value; - bool hasAssignmentOperator = std::is_copy_assignable::value && !std::has_trivial_copy_assign::value; - bool hasCopyConstructor = std::is_copy_constructible::value && !std::has_trivial_copy_constructor::value; -#endif - bool isFloat = std::is_floating_point::value; - bool isPrimitive = std::is_integral::value || std::is_pointer::value || std::is_enum::value; - bool isClass = std::is_class::value; - bool isArray = std::is_array::value; - if( isFloat ) - return asOBJ_APP_FLOAT; - if( isPrimitive ) - return asOBJ_APP_PRIMITIVE; - if( isClass ) - { - asDWORD flags = asOBJ_APP_CLASS; - if( hasConstructor ) - flags |= asOBJ_APP_CLASS_CONSTRUCTOR; - if( hasDestructor ) - flags |= asOBJ_APP_CLASS_DESTRUCTOR; - if( hasAssignmentOperator ) - flags |= asOBJ_APP_CLASS_ASSIGNMENT; - if( hasCopyConstructor ) - flags |= asOBJ_APP_CLASS_COPY_CONSTRUCTOR; - return flags; - } - if( isArray ) - return asOBJ_APP_ARRAY; - // Unknown type traits - return 0; - } - -#endif // c++11 - -// Interface declarations - -class asIScriptEngine -{ -public: - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; - - // Engine properties - virtual int SetEngineProperty(asEEngineProp property, asPWORD value) = 0; - virtual asPWORD GetEngineProperty(asEEngineProp property) const = 0; - - // Compiler messages - virtual int SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv) = 0; - virtual int ClearMessageCallback() = 0; - virtual int WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message) = 0; - - // JIT Compiler - virtual int SetJITCompiler(asIJITCompiler *compiler) = 0; - virtual asIJITCompiler *GetJITCompiler() const = 0; - - // Global functions - virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0) = 0; - virtual asUINT GetGlobalFunctionCount() const = 0; - virtual asIScriptFunction *GetGlobalFunctionByIndex(asUINT index) const = 0; - virtual asIScriptFunction *GetGlobalFunctionByDecl(const char *declaration) const = 0; - - // Global properties - virtual int RegisterGlobalProperty(const char *declaration, void *pointer) = 0; - virtual asUINT GetGlobalPropertyCount() const = 0; - virtual int GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace = 0, int *typeId = 0, bool *isConst = 0, const char **configGroup = 0, void **pointer = 0, asDWORD *accessMask = 0) const = 0; - virtual int GetGlobalPropertyIndexByName(const char *name) const = 0; - virtual int GetGlobalPropertyIndexByDecl(const char *decl) const = 0; - - // 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 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; - - // String factory - virtual int RegisterStringFactory(const char *datatype, const asSFuncPtr &factoryFunc, asDWORD callConv, void *objForThiscall = 0) = 0; - virtual int GetStringFactoryReturnTypeId(asDWORD *flags = 0) const = 0; - - // Default array type - virtual int RegisterDefaultArrayType(const char *type) = 0; - 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; - - // Funcdefs - virtual int RegisterFuncdef(const char *decl) = 0; - virtual asUINT GetFuncdefCount() const = 0; - virtual asIScriptFunction *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; - - // Configuration groups - virtual int BeginConfigGroup(const char *groupName) = 0; - virtual int EndConfigGroup() = 0; - virtual int RemoveConfigGroup(const char *groupName) = 0; - virtual asDWORD SetDefaultAccessMask(asDWORD defaultMask) = 0; - virtual int SetDefaultNamespace(const char *nameSpace) = 0; - virtual const char *GetDefaultNamespace() const = 0; - - // Script modules - virtual asIScriptModule *GetModule(const char *module, asEGMFlags flag = asGM_ONLY_IF_EXISTS) = 0; - virtual int DiscardModule(const char *module) = 0; - virtual asUINT GetModuleCount() const = 0; - virtual asIScriptModule *GetModuleByIndex(asUINT index) const = 0; - - // 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; - - // 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 asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj) = 0; - virtual void 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 bool IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const = 0; - virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const = 0; - - // Context pooling - virtual asIScriptContext *RequestContext() = 0; - virtual void ReturnContext(asIScriptContext *ctx) = 0; - virtual int SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param = 0) = 0; - - // String interpretation - virtual asETokenClass ParseToken(const char *string, size_t stringLength = 0, int *tokenLength = 0) const = 0; - - // 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 void GCEnumCallback(void *reference) = 0; - - // User data - virtual void *SetUserData(void *data, asPWORD type = 0) = 0; - virtual void *GetUserData(asPWORD type = 0) const = 0; - virtual void SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type = 0) = 0; - 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; - -protected: - virtual ~asIScriptEngine() {} -}; - -class asIThreadManager -{ -protected: - virtual ~asIThreadManager() {} -}; - -class asIScriptModule -{ -public: - virtual asIScriptEngine *GetEngine() const = 0; - virtual void SetName(const char *name) = 0; - virtual const char *GetName() const = 0; - virtual void Discard() = 0; - - // Compilation - virtual int AddScriptSection(const char *name, const char *code, size_t codeLength = 0, int lineOffset = 0) = 0; - virtual int Build() = 0; - virtual int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asIScriptFunction **outFunc) = 0; - virtual int CompileGlobalVar(const char *sectionName, const char *code, int lineOffset) = 0; - virtual asDWORD SetAccessMask(asDWORD accessMask) = 0; - virtual int SetDefaultNamespace(const char *nameSpace) = 0; - virtual const char *GetDefaultNamespace() const = 0; - - // Functions - virtual asUINT GetFunctionCount() const = 0; - virtual asIScriptFunction *GetFunctionByIndex(asUINT index) const = 0; - virtual asIScriptFunction *GetFunctionByDecl(const char *decl) const = 0; - virtual asIScriptFunction *GetFunctionByName(const char *name) const = 0; - virtual int RemoveFunction(asIScriptFunction *func) = 0; - - // Global variables - virtual int ResetGlobalVars(asIScriptContext *ctx = 0) = 0; - virtual asUINT GetGlobalVarCount() const = 0; - virtual int GetGlobalVarIndexByName(const char *name) const = 0; - virtual int GetGlobalVarIndexByDecl(const char *decl) const = 0; - virtual const char *GetGlobalVarDeclaration(asUINT index, bool includeNamespace = false) const = 0; - virtual int GetGlobalVar(asUINT index, const char **name, const char **nameSpace = 0, int *typeId = 0, bool *isConst = 0) const = 0; - virtual void *GetAddressOfGlobalVar(asUINT index) = 0; - virtual int RemoveGlobalVar(asUINT index) = 0; - - // 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 int GetTypeIdByDecl(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; - - // Typedefs - virtual asUINT GetTypedefCount() const = 0; - virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace = 0) const = 0; - - // Dynamic binding between modules - virtual asUINT GetImportedFunctionCount() const = 0; - virtual int GetImportedFunctionIndexByDecl(const char *decl) const = 0; - virtual const char *GetImportedFunctionDeclaration(asUINT importIndex) const = 0; - virtual const char *GetImportedFunctionSourceModule(asUINT importIndex) const = 0; - virtual int BindImportedFunction(asUINT importIndex, asIScriptFunction *func) = 0; - virtual int UnbindImportedFunction(asUINT importIndex) = 0; - virtual int BindAllImportedFunctions() = 0; - virtual int UnbindAllImportedFunctions() = 0; - - // Byte code saving and loading - virtual int SaveByteCode(asIBinaryStream *out, bool stripDebugInfo = false) const = 0; - virtual int LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped = 0) = 0; - - // User data - virtual void *SetUserData(void *data, asPWORD type = 0) = 0; - virtual void *GetUserData(asPWORD type = 0) const = 0; - -protected: - virtual ~asIScriptModule() {} -}; - -class asIScriptContext -{ -public: - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; - - // Miscellaneous - virtual asIScriptEngine *GetEngine() const = 0; - - // Execution - virtual int Prepare(asIScriptFunction *func) = 0; - virtual int Unprepare() = 0; - virtual int Execute() = 0; - virtual int Abort() = 0; - virtual int Suspend() = 0; - virtual asEContextState GetState() const = 0; - virtual int PushState() = 0; - virtual int PopState() = 0; - virtual bool IsNested(asUINT *nestCount = 0) const = 0; - - // Object pointer for calling class methods - virtual int SetObject(void *obj) = 0; - - // Arguments - virtual int SetArgByte(asUINT arg, asBYTE value) = 0; - virtual int SetArgWord(asUINT arg, asWORD value) = 0; - virtual int SetArgDWord(asUINT arg, asDWORD value) = 0; - virtual int SetArgQWord(asUINT arg, asQWORD value) = 0; - virtual int SetArgFloat(asUINT arg, float value) = 0; - virtual int SetArgDouble(asUINT arg, double value) = 0; - virtual int SetArgAddress(asUINT arg, void *addr) = 0; - virtual int SetArgObject(asUINT arg, void *obj) = 0; - virtual void *GetAddressOfArg(asUINT arg) = 0; - - // Return value - virtual asBYTE GetReturnByte() = 0; - virtual asWORD GetReturnWord() = 0; - virtual asDWORD GetReturnDWord() = 0; - virtual asQWORD GetReturnQWord() = 0; - virtual float GetReturnFloat() = 0; - virtual double GetReturnDouble() = 0; - virtual void *GetReturnAddress() = 0; - virtual void *GetReturnObject() = 0; - virtual void *GetAddressOfReturnValue() = 0; - - // Exception handling - virtual int SetException(const char *string) = 0; - virtual int GetExceptionLineNumber(int *column = 0, const char **sectionName = 0) = 0; - virtual asIScriptFunction *GetExceptionFunction() = 0; - virtual const char * GetExceptionString() = 0; - virtual int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv) = 0; - virtual void ClearExceptionCallback() = 0; - - // Debugging - virtual int SetLineCallback(asSFuncPtr callback, void *obj, int callConv) = 0; - virtual void ClearLineCallback() = 0; - virtual asUINT GetCallstackSize() const = 0; - virtual asIScriptFunction *GetFunction(asUINT stackLevel = 0) = 0; - virtual int GetLineNumber(asUINT stackLevel = 0, int *column = 0, const char **sectionName = 0) = 0; - virtual int GetVarCount(asUINT stackLevel = 0) = 0; - virtual const char *GetVarName(asUINT varIndex, asUINT stackLevel = 0) = 0; - virtual const char *GetVarDeclaration(asUINT varIndex, asUINT stackLevel = 0, bool includeNamespace = false) = 0; - virtual int GetVarTypeId(asUINT varIndex, asUINT stackLevel = 0) = 0; - virtual void *GetAddressOfVar(asUINT varIndex, asUINT stackLevel = 0) = 0; - virtual bool IsVarInScope(asUINT varIndex, asUINT stackLevel = 0) = 0; - virtual int GetThisTypeId(asUINT stackLevel = 0) = 0; - virtual void *GetThisPointer(asUINT stackLevel = 0) = 0; - virtual asIScriptFunction *GetSystemFunction() = 0; - - // User data - virtual void *SetUserData(void *data, asPWORD type = 0) = 0; - virtual void *GetUserData(asPWORD type = 0) const = 0; - -protected: - virtual ~asIScriptContext() {} -}; - -class asIScriptGeneric -{ -public: - // Miscellaneous - virtual asIScriptEngine *GetEngine() const = 0; - virtual asIScriptFunction *GetFunction() const = 0; - - // Object - virtual void *GetObject() = 0; - virtual int GetObjectTypeId() const = 0; - - // Arguments - virtual int GetArgCount() const = 0; - virtual int GetArgTypeId(asUINT arg, asDWORD *flags = 0) const = 0; - virtual asBYTE GetArgByte(asUINT arg) = 0; - virtual asWORD GetArgWord(asUINT arg) = 0; - virtual asDWORD GetArgDWord(asUINT arg) = 0; - virtual asQWORD GetArgQWord(asUINT arg) = 0; - virtual float GetArgFloat(asUINT arg) = 0; - virtual double GetArgDouble(asUINT arg) = 0; - virtual void *GetArgAddress(asUINT arg) = 0; - virtual void *GetArgObject(asUINT arg) = 0; - virtual void *GetAddressOfArg(asUINT arg) = 0; - - // Return value - virtual int GetReturnTypeId(asDWORD *flags = 0) const = 0; - virtual int SetReturnByte(asBYTE val) = 0; - virtual int SetReturnWord(asWORD val) = 0; - virtual int SetReturnDWord(asDWORD val) = 0; - virtual int SetReturnQWord(asQWORD val) = 0; - virtual int SetReturnFloat(float val) = 0; - virtual int SetReturnDouble(double val) = 0; - virtual int SetReturnAddress(void *addr) = 0; - virtual int SetReturnObject(void *obj) = 0; - virtual void *GetAddressOfReturnLocation() = 0; - -protected: - virtual ~asIScriptGeneric() {} -}; - -class asIScriptObject -{ -public: - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; - - // Type info - virtual int GetTypeId() const = 0; - virtual asIObjectType *GetObjectType() const = 0; - - // Class properties - virtual asUINT GetPropertyCount() const = 0; - virtual int GetPropertyTypeId(asUINT prop) const = 0; - virtual const char *GetPropertyName(asUINT prop) const = 0; - virtual void *GetAddressOfProperty(asUINT prop) = 0; - - virtual asIScriptEngine *GetEngine() const = 0; - virtual int CopyFrom(asIScriptObject *other) = 0; - -protected: - virtual ~asIScriptObject() {} -}; - -class asIObjectType -{ -public: - virtual asIScriptEngine *GetEngine() const = 0; - virtual const char *GetConfigGroup() const = 0; - virtual asDWORD GetAccessMask() const = 0; - virtual asIScriptModule *GetModule() const = 0; - - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; - - // 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 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 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; - - // Factories - virtual asUINT GetFactoryCount() const = 0; - virtual asIScriptFunction *GetFactoryByIndex(asUINT index) const = 0; - virtual asIScriptFunction *GetFactoryByDecl(const char *decl) const = 0; - - // Methods - virtual asUINT GetMethodCount() const = 0; - virtual asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual = true) const = 0; - virtual asIScriptFunction *GetMethodByName(const char *name, bool getVirtual = true) const = 0; - virtual asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual = true) const = 0; - - // Properties - virtual asUINT GetPropertyCount() const = 0; - virtual int GetProperty(asUINT index, const char **name, int *typeId = 0, bool *isPrivate = 0, int *offset = 0, bool *isReference = 0, asDWORD *accessMask = 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; - - // User data - virtual void *SetUserData(void *data, asPWORD type = 0) = 0; - virtual void *GetUserData(asPWORD type = 0) const = 0; - -protected: - virtual ~asIObjectType() {} -}; - -class asIScriptFunction -{ -public: - virtual asIScriptEngine *GetEngine() const = 0; - - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; - - // Miscellaneous - virtual int GetId() const = 0; - virtual asEFuncType GetFuncType() const = 0; - virtual const char *GetModuleName() const = 0; - virtual asIScriptModule *GetModule() const = 0; - virtual const char *GetScriptSectionName() const = 0; - virtual const char *GetConfigGroup() const = 0; - virtual asDWORD GetAccessMask() const = 0; - - // Function signature - virtual asIObjectType *GetObjectType() const = 0; - virtual const char *GetObjectName() const = 0; - virtual const char *GetName() const = 0; - virtual const char *GetNamespace() const = 0; - virtual const char *GetDeclaration(bool includeObjectName = true, bool includeNamespace = false, bool includeParamNames = false) const = 0; - virtual bool IsReadOnly() const = 0; - virtual bool IsPrivate() const = 0; - virtual bool IsFinal() const = 0; - virtual bool IsOverride() const = 0; - 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 - virtual int GetTypeId() const = 0; - virtual bool IsCompatibleWithTypeId(int typeId) const = 0; - - // Delegates - virtual void *GetDelegateObject() const = 0; - virtual asIObjectType *GetDelegateObjectType() const = 0; - virtual asIScriptFunction *GetDelegateFunction() const = 0; - - // Debug information - virtual asUINT GetVarCount() const = 0; - virtual int GetVar(asUINT index, const char **name, int *typeId = 0) const = 0; - virtual const char *GetVarDecl(asUINT index, bool includeNamespace = false) const = 0; - virtual int FindNextLineWithCode(int line) const = 0; - - // For JIT compilation - virtual asDWORD *GetByteCode(asUINT *length = 0) = 0; - - // User data - virtual void *SetUserData(void *userData, asPWORD type = 0) = 0; - virtual void *GetUserData(asPWORD type = 0) const = 0; - -protected: - virtual ~asIScriptFunction() {}; -}; - -class asIBinaryStream -{ -public: - virtual void Read(void *ptr, asUINT size) = 0; - virtual void Write(const void *ptr, asUINT size) = 0; - -public: - virtual ~asIBinaryStream() {} -}; - -class asILockableSharedBool -{ -public: - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; - - // Value - virtual bool Get() const = 0; - virtual void Set(bool val) = 0; - - // Thread management - virtual void Lock() const = 0; - virtual void Unlock() const = 0; - -protected: - virtual ~asILockableSharedBool() {} -}; - -//----------------------------------------------------------------- -// Function pointers - -// Template function to capture all global functions, -// except the ones using the generic calling convention -template -inline asSFuncPtr asFunctionPtr(T func) -{ - // Mark this as a global function - asSFuncPtr p(2); - -#ifdef AS_64BIT_PTR - // The size_t cast is to avoid a compiler warning with asFUNCTION(0) - // on 64bit, as 0 is interpreted as a 32bit int value - p.ptr.f.func = reinterpret_cast(size_t(func)); -#else - // MSVC6 doesn't like the size_t cast above so I - // solved this with a separate code for 32bit. - p.ptr.f.func = reinterpret_cast(func); -#endif - - return p; -} - -// Specialization for functions using the generic calling convention -template<> -inline asSFuncPtr asFunctionPtr(asGENFUNC_t func) -{ - // Mark this as a generic function - asSFuncPtr p(1); - p.ptr.f.func = reinterpret_cast(func); - return p; -} - -#ifndef AS_NO_CLASS_METHODS - -// Method pointers - -// Declare a dummy class so that we can determine the size of a simple method pointer -class asCSimpleDummy {}; -typedef void (asCSimpleDummy::*asSIMPLEMETHOD_t)(); -const int SINGLE_PTR_SIZE = sizeof(asSIMPLEMETHOD_t); - -// Define template -template -struct asSMethodPtr -{ - template - static asSFuncPtr Convert(M Mthd) - { - // This version of the function should never be executed, nor compiled, - // as it would mean that the size of the method pointer cannot be determined. - - int ERROR_UnsupportedMethodPtr[N-100]; - - asSFuncPtr p(0); - return p; - } -}; - -// Template specialization -template <> -struct asSMethodPtr -{ - template - static asSFuncPtr Convert(M Mthd) - { - // Mark this as a class method - asSFuncPtr p(3); - p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE); - return p; - } -}; - -#if defined(_MSC_VER) && !defined(__MWERKS__) - -// MSVC and Intel uses different sizes for different class method pointers -template <> -struct asSMethodPtr -{ - template - static asSFuncPtr Convert(M Mthd) - { - // Mark this as a class method - asSFuncPtr p(3); - p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE+sizeof(int)); - return p; - } -}; - -template <> -struct asSMethodPtr -{ - template - static asSFuncPtr Convert(M Mthd) - { - // On 32bit platforms with is where a class with virtual inheritance falls. - // On 64bit platforms we can also fall here if 8byte data alignments is used. - - // Mark this as a class method - asSFuncPtr p(3); - p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE+2*sizeof(int)); - - // Microsoft has a terrible optimization on class methods with virtual inheritance. - // They are hardcoding an important offset, which is not coming in the method pointer. - -#if defined(_MSC_VER) && !defined(AS_64BIT_PTR) - // Method pointers for virtual inheritance is not supported, - // as it requires the location of the vbase table, which is - // only available to the C++ compiler, but not in the method - // pointer. - - // You can get around this by forward declaring the class and - // storing the sizeof its method pointer in a constant. Example: - - // class ClassWithVirtualInheritance; - // const int ClassWithVirtualInheritance_workaround = sizeof(void ClassWithVirtualInheritance::*()); - - // This will force the compiler to use the unknown type - // for the class, which falls under the next case - - - // Copy the virtual table index to the 4th dword so that AngelScript - // can properly detect and deny the use of methods with virtual inheritance. - *(reinterpret_cast(&p)+3) = *(reinterpret_cast(&p)+2); -#endif - - return p; - } -}; - -template <> -struct asSMethodPtr -{ - template - static asSFuncPtr Convert(M Mthd) - { - // Mark this as a class method - asSFuncPtr p(3); - p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE+3*sizeof(int)); - return p; - } -}; - -template <> -struct asSMethodPtr -{ - template - static asSFuncPtr Convert(M Mthd) - { - // On 64bit platforms with 8byte data alignment - // the unknown class method pointers will come here. - - // Mark this as a class method - asSFuncPtr p(3); - p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE+4*sizeof(int)); - return p; - } -}; - -#endif - -#endif // AS_NO_CLASS_METHODS - -//---------------------------------------------------------------- -// JIT compiler - -struct asSVMRegisters -{ - asDWORD *programPointer; // points to current bytecode instruction - asDWORD *stackFramePointer; // function stack frame - 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 - bool doProcessSuspend; // whether or not the JIT should break out when it encounters a suspend instruction - asIScriptContext *ctx; // the active context -}; - -typedef void (*asJITFunction)(asSVMRegisters *registers, asPWORD jitArg); - -class asIJITCompiler -{ -public: - virtual int CompileFunction(asIScriptFunction *function, asJITFunction *output) = 0; - virtual void ReleaseJITFunction(asJITFunction func) = 0; -public: - virtual ~asIJITCompiler() {} -}; - -// Byte code instructions -enum asEBCInstr -{ - asBC_PopPtr = 0, - asBC_PshGPtr = 1, - asBC_PshC4 = 2, - asBC_PshV4 = 3, - asBC_PSF = 4, - asBC_SwapPtr = 5, - asBC_NOT = 6, - asBC_PshG4 = 7, - asBC_LdGRdR4 = 8, - asBC_CALL = 9, - asBC_RET = 10, - asBC_JMP = 11, - asBC_JZ = 12, - asBC_JNZ = 13, - asBC_JS = 14, - asBC_JNS = 15, - asBC_JP = 16, - asBC_JNP = 17, - asBC_TZ = 18, - asBC_TNZ = 19, - asBC_TS = 20, - asBC_TNS = 21, - asBC_TP = 22, - asBC_TNP = 23, - asBC_NEGi = 24, - asBC_NEGf = 25, - asBC_NEGd = 26, - asBC_INCi16 = 27, - asBC_INCi8 = 28, - asBC_DECi16 = 29, - asBC_DECi8 = 30, - asBC_INCi = 31, - asBC_DECi = 32, - asBC_INCf = 33, - asBC_DECf = 34, - asBC_INCd = 35, - asBC_DECd = 36, - asBC_IncVi = 37, - asBC_DecVi = 38, - asBC_BNOT = 39, - asBC_BAND = 40, - asBC_BOR = 41, - asBC_BXOR = 42, - asBC_BSLL = 43, - asBC_BSRL = 44, - asBC_BSRA = 45, - asBC_COPY = 46, - asBC_PshC8 = 47, - asBC_PshVPtr = 48, - asBC_RDSPtr = 49, - asBC_CMPd = 50, - asBC_CMPu = 51, - asBC_CMPf = 52, - asBC_CMPi = 53, - asBC_CMPIi = 54, - asBC_CMPIf = 55, - asBC_CMPIu = 56, - asBC_JMPP = 57, - asBC_PopRPtr = 58, - asBC_PshRPtr = 59, - asBC_STR = 60, - asBC_CALLSYS = 61, - asBC_CALLBND = 62, - asBC_SUSPEND = 63, - asBC_ALLOC = 64, - asBC_FREE = 65, - asBC_LOADOBJ = 66, - asBC_STOREOBJ = 67, - asBC_GETOBJ = 68, - asBC_REFCPY = 69, - asBC_CHKREF = 70, - asBC_GETOBJREF = 71, - asBC_GETREF = 72, - asBC_PshNull = 73, - asBC_ClrVPtr = 74, - asBC_OBJTYPE = 75, - asBC_TYPEID = 76, - asBC_SetV4 = 77, - asBC_SetV8 = 78, - asBC_ADDSi = 79, - asBC_CpyVtoV4 = 80, - asBC_CpyVtoV8 = 81, - asBC_CpyVtoR4 = 82, - asBC_CpyVtoR8 = 83, - asBC_CpyVtoG4 = 84, - asBC_CpyRtoV4 = 85, - asBC_CpyRtoV8 = 86, - asBC_CpyGtoV4 = 87, - asBC_WRTV1 = 88, - asBC_WRTV2 = 89, - asBC_WRTV4 = 90, - asBC_WRTV8 = 91, - asBC_RDR1 = 92, - asBC_RDR2 = 93, - asBC_RDR4 = 94, - asBC_RDR8 = 95, - asBC_LDG = 96, - asBC_LDV = 97, - asBC_PGA = 98, - asBC_CmpPtr = 99, - asBC_VAR = 100, - asBC_iTOf = 101, - asBC_fTOi = 102, - asBC_uTOf = 103, - asBC_fTOu = 104, - asBC_sbTOi = 105, - asBC_swTOi = 106, - asBC_ubTOi = 107, - asBC_uwTOi = 108, - asBC_dTOi = 109, - asBC_dTOu = 110, - asBC_dTOf = 111, - asBC_iTOd = 112, - asBC_uTOd = 113, - asBC_fTOd = 114, - asBC_ADDi = 115, - asBC_SUBi = 116, - asBC_MULi = 117, - asBC_DIVi = 118, - asBC_MODi = 119, - asBC_ADDf = 120, - asBC_SUBf = 121, - asBC_MULf = 122, - asBC_DIVf = 123, - asBC_MODf = 124, - asBC_ADDd = 125, - asBC_SUBd = 126, - asBC_MULd = 127, - asBC_DIVd = 128, - asBC_MODd = 129, - asBC_ADDIi = 130, - asBC_SUBIi = 131, - asBC_MULIi = 132, - asBC_ADDIf = 133, - asBC_SUBIf = 134, - asBC_MULIf = 135, - asBC_SetG4 = 136, - asBC_ChkRefS = 137, - asBC_ChkNullV = 138, - asBC_CALLINTF = 139, - asBC_iTOb = 140, - asBC_iTOw = 141, - asBC_SetV1 = 142, - asBC_SetV2 = 143, - asBC_Cast = 144, - asBC_i64TOi = 145, - asBC_uTOi64 = 146, - asBC_iTOi64 = 147, - asBC_fTOi64 = 148, - asBC_dTOi64 = 149, - asBC_fTOu64 = 150, - asBC_dTOu64 = 151, - asBC_i64TOf = 152, - asBC_u64TOf = 153, - asBC_i64TOd = 154, - asBC_u64TOd = 155, - asBC_NEGi64 = 156, - asBC_INCi64 = 157, - asBC_DECi64 = 158, - asBC_BNOT64 = 159, - asBC_ADDi64 = 160, - asBC_SUBi64 = 161, - asBC_MULi64 = 162, - asBC_DIVi64 = 163, - asBC_MODi64 = 164, - asBC_BAND64 = 165, - asBC_BOR64 = 166, - asBC_BXOR64 = 167, - asBC_BSLL64 = 168, - asBC_BSRL64 = 169, - asBC_BSRA64 = 170, - asBC_CMPi64 = 171, - asBC_CMPu64 = 172, - asBC_ChkNullS = 173, - asBC_ClrHi = 174, - asBC_JitEntry = 175, - asBC_CallPtr = 176, - asBC_FuncPtr = 177, - asBC_LoadThisR = 178, - asBC_PshV8 = 179, - asBC_DIVu = 180, - asBC_MODu = 181, - asBC_DIVu64 = 182, - asBC_MODu64 = 183, - asBC_LoadRObjR = 184, - asBC_LoadVObjR = 185, - asBC_RefCpyV = 186, - asBC_JLowZ = 187, - asBC_JLowNZ = 188, - asBC_AllocMem = 189, - asBC_SetListSize = 190, - asBC_PshListElmnt = 191, - asBC_SetListType = 192, - asBC_POWi = 193, - asBC_POWu = 194, - asBC_POWf = 195, - asBC_POWd = 196, - asBC_POWdi = 197, - asBC_POWi64 = 198, - asBC_POWu64 = 199, - - asBC_MAXBYTECODE = 200, - - // Temporary tokens. Can't be output to the final program - asBC_VarDecl = 251, - asBC_Block = 252, - asBC_ObjInfo = 253, - asBC_LINE = 254, - asBC_LABEL = 255 -}; - -// Instruction types -enum asEBCType -{ - asBCTYPE_INFO = 0, - asBCTYPE_NO_ARG = 1, - asBCTYPE_W_ARG = 2, - asBCTYPE_wW_ARG = 3, - asBCTYPE_DW_ARG = 4, - asBCTYPE_rW_DW_ARG = 5, - asBCTYPE_QW_ARG = 6, - asBCTYPE_DW_DW_ARG = 7, - asBCTYPE_wW_rW_rW_ARG = 8, - asBCTYPE_wW_QW_ARG = 9, - asBCTYPE_wW_rW_ARG = 10, - asBCTYPE_rW_ARG = 11, - asBCTYPE_wW_DW_ARG = 12, - asBCTYPE_wW_rW_DW_ARG = 13, - asBCTYPE_rW_rW_ARG = 14, - asBCTYPE_wW_W_ARG = 15, - asBCTYPE_QW_DW_ARG = 16, - asBCTYPE_rW_QW_ARG = 17, - asBCTYPE_W_DW_ARG = 18, - asBCTYPE_rW_W_DW_ARG = 19, - asBCTYPE_rW_DW_DW_ARG = 20 -}; - -// Instruction type sizes -const int asBCTypeSize[21] = -{ - 0, // asBCTYPE_INFO - 1, // asBCTYPE_NO_ARG - 1, // asBCTYPE_W_ARG - 1, // asBCTYPE_wW_ARG - 2, // asBCTYPE_DW_ARG - 2, // asBCTYPE_rW_DW_ARG - 3, // asBCTYPE_QW_ARG - 3, // asBCTYPE_DW_DW_ARG - 2, // asBCTYPE_wW_rW_rW_ARG - 3, // asBCTYPE_wW_QW_ARG - 2, // asBCTYPE_wW_rW_ARG - 1, // asBCTYPE_rW_ARG - 2, // asBCTYPE_wW_DW_ARG - 3, // asBCTYPE_wW_rW_DW_ARG - 2, // asBCTYPE_rW_rW_ARG - 2, // asBCTYPE_wW_W_ARG - 4, // asBCTYPE_QW_DW_ARG - 3, // asBCTYPE_rW_QW_ARG - 2, // asBCTYPE_W_DW_ARG - 3, // asBCTYPE_rW_W_DW_ARG - 3 // asBCTYPE_rW_DW_DW_ARG -}; - -// Instruction info -struct asSBCInfo -{ - asEBCInstr bc; - asEBCType type; - int stackInc; - const char *name; -}; - -#ifndef AS_64BIT_PTR - #define asBCTYPE_PTR_ARG asBCTYPE_DW_ARG - #define asBCTYPE_PTR_DW_ARG asBCTYPE_DW_DW_ARG - #define asBCTYPE_wW_PTR_ARG asBCTYPE_wW_DW_ARG - #define asBCTYPE_rW_PTR_ARG asBCTYPE_rW_DW_ARG - #ifndef AS_PTR_SIZE - #define AS_PTR_SIZE 1 - #endif -#else - #define asBCTYPE_PTR_ARG asBCTYPE_QW_ARG - #define asBCTYPE_PTR_DW_ARG asBCTYPE_QW_DW_ARG - #define asBCTYPE_wW_PTR_ARG asBCTYPE_wW_QW_ARG - #define asBCTYPE_rW_PTR_ARG asBCTYPE_rW_QW_ARG - #ifndef AS_PTR_SIZE - #define AS_PTR_SIZE 2 - #endif -#endif - -#define asBCINFO(b,t,s) {asBC_##b, asBCTYPE_##t, s, #b} -#define asBCINFO_DUMMY(b) {asBC_MAXBYTECODE, asBCTYPE_INFO, 0, "BC_" #b} - -const asSBCInfo asBCInfo[256] = -{ - asBCINFO(PopPtr, NO_ARG, -AS_PTR_SIZE), - asBCINFO(PshGPtr, PTR_ARG, AS_PTR_SIZE), - asBCINFO(PshC4, DW_ARG, 1), - asBCINFO(PshV4, rW_ARG, 1), - asBCINFO(PSF, rW_ARG, AS_PTR_SIZE), - asBCINFO(SwapPtr, NO_ARG, 0), - asBCINFO(NOT, rW_ARG, 0), - asBCINFO(PshG4, PTR_ARG, 1), - asBCINFO(LdGRdR4, wW_PTR_ARG, 0), - asBCINFO(CALL, DW_ARG, 0xFFFF), - asBCINFO(RET, W_ARG, 0xFFFF), - asBCINFO(JMP, DW_ARG, 0), - asBCINFO(JZ, DW_ARG, 0), - asBCINFO(JNZ, DW_ARG, 0), - asBCINFO(JS, DW_ARG, 0), - asBCINFO(JNS, DW_ARG, 0), - asBCINFO(JP, DW_ARG, 0), - asBCINFO(JNP, DW_ARG, 0), - asBCINFO(TZ, NO_ARG, 0), - asBCINFO(TNZ, NO_ARG, 0), - asBCINFO(TS, NO_ARG, 0), - asBCINFO(TNS, NO_ARG, 0), - asBCINFO(TP, NO_ARG, 0), - asBCINFO(TNP, NO_ARG, 0), - asBCINFO(NEGi, rW_ARG, 0), - asBCINFO(NEGf, rW_ARG, 0), - asBCINFO(NEGd, rW_ARG, 0), - asBCINFO(INCi16, NO_ARG, 0), - asBCINFO(INCi8, NO_ARG, 0), - asBCINFO(DECi16, NO_ARG, 0), - asBCINFO(DECi8, NO_ARG, 0), - asBCINFO(INCi, NO_ARG, 0), - asBCINFO(DECi, NO_ARG, 0), - asBCINFO(INCf, NO_ARG, 0), - asBCINFO(DECf, NO_ARG, 0), - asBCINFO(INCd, NO_ARG, 0), - asBCINFO(DECd, NO_ARG, 0), - asBCINFO(IncVi, rW_ARG, 0), - asBCINFO(DecVi, rW_ARG, 0), - asBCINFO(BNOT, rW_ARG, 0), - asBCINFO(BAND, wW_rW_rW_ARG, 0), - asBCINFO(BOR, wW_rW_rW_ARG, 0), - asBCINFO(BXOR, wW_rW_rW_ARG, 0), - asBCINFO(BSLL, wW_rW_rW_ARG, 0), - asBCINFO(BSRL, wW_rW_rW_ARG, 0), - asBCINFO(BSRA, wW_rW_rW_ARG, 0), - asBCINFO(COPY, W_DW_ARG, -AS_PTR_SIZE), - asBCINFO(PshC8, QW_ARG, 2), - asBCINFO(PshVPtr, rW_ARG, AS_PTR_SIZE), - asBCINFO(RDSPtr, NO_ARG, 0), - asBCINFO(CMPd, rW_rW_ARG, 0), - asBCINFO(CMPu, rW_rW_ARG, 0), - asBCINFO(CMPf, rW_rW_ARG, 0), - asBCINFO(CMPi, rW_rW_ARG, 0), - asBCINFO(CMPIi, rW_DW_ARG, 0), - asBCINFO(CMPIf, rW_DW_ARG, 0), - asBCINFO(CMPIu, rW_DW_ARG, 0), - asBCINFO(JMPP, rW_ARG, 0), - asBCINFO(PopRPtr, NO_ARG, -AS_PTR_SIZE), - asBCINFO(PshRPtr, NO_ARG, AS_PTR_SIZE), - asBCINFO(STR, W_ARG, 1+AS_PTR_SIZE), - asBCINFO(CALLSYS, DW_ARG, 0xFFFF), - asBCINFO(CALLBND, DW_ARG, 0xFFFF), - asBCINFO(SUSPEND, NO_ARG, 0), - asBCINFO(ALLOC, PTR_DW_ARG, 0xFFFF), - asBCINFO(FREE, wW_PTR_ARG, 0), - asBCINFO(LOADOBJ, rW_ARG, 0), - asBCINFO(STOREOBJ, wW_ARG, 0), - asBCINFO(GETOBJ, W_ARG, 0), - asBCINFO(REFCPY, PTR_ARG, -AS_PTR_SIZE), - asBCINFO(CHKREF, NO_ARG, 0), - asBCINFO(GETOBJREF, W_ARG, 0), - asBCINFO(GETREF, W_ARG, 0), - asBCINFO(PshNull, NO_ARG, AS_PTR_SIZE), - asBCINFO(ClrVPtr, wW_ARG, 0), - asBCINFO(OBJTYPE, PTR_ARG, AS_PTR_SIZE), - asBCINFO(TYPEID, DW_ARG, 1), - asBCINFO(SetV4, wW_DW_ARG, 0), - asBCINFO(SetV8, wW_QW_ARG, 0), - asBCINFO(ADDSi, W_DW_ARG, 0), - asBCINFO(CpyVtoV4, wW_rW_ARG, 0), - asBCINFO(CpyVtoV8, wW_rW_ARG, 0), - asBCINFO(CpyVtoR4, rW_ARG, 0), - asBCINFO(CpyVtoR8, rW_ARG, 0), - asBCINFO(CpyVtoG4, rW_PTR_ARG, 0), - asBCINFO(CpyRtoV4, wW_ARG, 0), - asBCINFO(CpyRtoV8, wW_ARG, 0), - asBCINFO(CpyGtoV4, wW_PTR_ARG, 0), - asBCINFO(WRTV1, rW_ARG, 0), - asBCINFO(WRTV2, rW_ARG, 0), - asBCINFO(WRTV4, rW_ARG, 0), - asBCINFO(WRTV8, rW_ARG, 0), - asBCINFO(RDR1, wW_ARG, 0), - asBCINFO(RDR2, wW_ARG, 0), - asBCINFO(RDR4, wW_ARG, 0), - asBCINFO(RDR8, wW_ARG, 0), - asBCINFO(LDG, PTR_ARG, 0), - asBCINFO(LDV, rW_ARG, 0), - asBCINFO(PGA, PTR_ARG, AS_PTR_SIZE), - asBCINFO(CmpPtr, rW_rW_ARG, 0), - asBCINFO(VAR, rW_ARG, AS_PTR_SIZE), - asBCINFO(iTOf, rW_ARG, 0), - asBCINFO(fTOi, rW_ARG, 0), - asBCINFO(uTOf, rW_ARG, 0), - asBCINFO(fTOu, rW_ARG, 0), - asBCINFO(sbTOi, rW_ARG, 0), - asBCINFO(swTOi, rW_ARG, 0), - asBCINFO(ubTOi, rW_ARG, 0), - asBCINFO(uwTOi, rW_ARG, 0), - asBCINFO(dTOi, wW_rW_ARG, 0), - asBCINFO(dTOu, wW_rW_ARG, 0), - asBCINFO(dTOf, wW_rW_ARG, 0), - asBCINFO(iTOd, wW_rW_ARG, 0), - asBCINFO(uTOd, wW_rW_ARG, 0), - asBCINFO(fTOd, wW_rW_ARG, 0), - asBCINFO(ADDi, wW_rW_rW_ARG, 0), - asBCINFO(SUBi, wW_rW_rW_ARG, 0), - asBCINFO(MULi, wW_rW_rW_ARG, 0), - asBCINFO(DIVi, wW_rW_rW_ARG, 0), - asBCINFO(MODi, wW_rW_rW_ARG, 0), - asBCINFO(ADDf, wW_rW_rW_ARG, 0), - asBCINFO(SUBf, wW_rW_rW_ARG, 0), - asBCINFO(MULf, wW_rW_rW_ARG, 0), - asBCINFO(DIVf, wW_rW_rW_ARG, 0), - asBCINFO(MODf, wW_rW_rW_ARG, 0), - asBCINFO(ADDd, wW_rW_rW_ARG, 0), - asBCINFO(SUBd, wW_rW_rW_ARG, 0), - asBCINFO(MULd, wW_rW_rW_ARG, 0), - asBCINFO(DIVd, wW_rW_rW_ARG, 0), - asBCINFO(MODd, wW_rW_rW_ARG, 0), - asBCINFO(ADDIi, wW_rW_DW_ARG, 0), - asBCINFO(SUBIi, wW_rW_DW_ARG, 0), - asBCINFO(MULIi, wW_rW_DW_ARG, 0), - asBCINFO(ADDIf, wW_rW_DW_ARG, 0), - asBCINFO(SUBIf, wW_rW_DW_ARG, 0), - asBCINFO(MULIf, wW_rW_DW_ARG, 0), - asBCINFO(SetG4, PTR_DW_ARG, 0), - asBCINFO(ChkRefS, NO_ARG, 0), - asBCINFO(ChkNullV, rW_ARG, 0), - asBCINFO(CALLINTF, DW_ARG, 0xFFFF), - asBCINFO(iTOb, rW_ARG, 0), - asBCINFO(iTOw, rW_ARG, 0), - asBCINFO(SetV1, wW_DW_ARG, 0), - asBCINFO(SetV2, wW_DW_ARG, 0), - asBCINFO(Cast, DW_ARG, -AS_PTR_SIZE), - asBCINFO(i64TOi, wW_rW_ARG, 0), - asBCINFO(uTOi64, wW_rW_ARG, 0), - asBCINFO(iTOi64, wW_rW_ARG, 0), - asBCINFO(fTOi64, wW_rW_ARG, 0), - asBCINFO(dTOi64, rW_ARG, 0), - asBCINFO(fTOu64, wW_rW_ARG, 0), - asBCINFO(dTOu64, rW_ARG, 0), - asBCINFO(i64TOf, wW_rW_ARG, 0), - asBCINFO(u64TOf, wW_rW_ARG, 0), - asBCINFO(i64TOd, rW_ARG, 0), - asBCINFO(u64TOd, rW_ARG, 0), - asBCINFO(NEGi64, rW_ARG, 0), - asBCINFO(INCi64, NO_ARG, 0), - asBCINFO(DECi64, NO_ARG, 0), - asBCINFO(BNOT64, rW_ARG, 0), - asBCINFO(ADDi64, wW_rW_rW_ARG, 0), - asBCINFO(SUBi64, wW_rW_rW_ARG, 0), - asBCINFO(MULi64, wW_rW_rW_ARG, 0), - asBCINFO(DIVi64, wW_rW_rW_ARG, 0), - asBCINFO(MODi64, wW_rW_rW_ARG, 0), - asBCINFO(BAND64, wW_rW_rW_ARG, 0), - asBCINFO(BOR64, wW_rW_rW_ARG, 0), - asBCINFO(BXOR64, wW_rW_rW_ARG, 0), - asBCINFO(BSLL64, wW_rW_rW_ARG, 0), - asBCINFO(BSRL64, wW_rW_rW_ARG, 0), - asBCINFO(BSRA64, wW_rW_rW_ARG, 0), - asBCINFO(CMPi64, rW_rW_ARG, 0), - asBCINFO(CMPu64, rW_rW_ARG, 0), - asBCINFO(ChkNullS, W_ARG, 0), - asBCINFO(ClrHi, NO_ARG, 0), - asBCINFO(JitEntry, PTR_ARG, 0), - asBCINFO(CallPtr, rW_ARG, 0xFFFF), - asBCINFO(FuncPtr, PTR_ARG, AS_PTR_SIZE), - asBCINFO(LoadThisR, W_DW_ARG, 0), - asBCINFO(PshV8, rW_ARG, 2), - asBCINFO(DIVu, wW_rW_rW_ARG, 0), - asBCINFO(MODu, wW_rW_rW_ARG, 0), - asBCINFO(DIVu64, wW_rW_rW_ARG, 0), - asBCINFO(MODu64, wW_rW_rW_ARG, 0), - asBCINFO(LoadRObjR, rW_W_DW_ARG, 0), - asBCINFO(LoadVObjR, rW_W_DW_ARG, 0), - asBCINFO(RefCpyV, wW_PTR_ARG, 0), - asBCINFO(JLowZ, DW_ARG, 0), - asBCINFO(JLowNZ, DW_ARG, 0), - asBCINFO(AllocMem, wW_DW_ARG, 0), - asBCINFO(SetListSize, rW_DW_DW_ARG, 0), - asBCINFO(PshListElmnt, rW_DW_ARG, AS_PTR_SIZE), - asBCINFO(SetListType, rW_DW_DW_ARG, 0), - asBCINFO(POWi, wW_rW_rW_ARG, 0), - asBCINFO(POWu, wW_rW_rW_ARG, 0), - asBCINFO(POWf, wW_rW_rW_ARG, 0), - asBCINFO(POWd, wW_rW_rW_ARG, 0), - asBCINFO(POWdi, wW_rW_rW_ARG, 0), - asBCINFO(POWi64, wW_rW_rW_ARG, 0), - asBCINFO(POWu64, wW_rW_rW_ARG, 0), - - asBCINFO_DUMMY(200), - asBCINFO_DUMMY(201), - asBCINFO_DUMMY(202), - asBCINFO_DUMMY(203), - asBCINFO_DUMMY(204), - asBCINFO_DUMMY(205), - asBCINFO_DUMMY(206), - asBCINFO_DUMMY(207), - asBCINFO_DUMMY(208), - asBCINFO_DUMMY(209), - asBCINFO_DUMMY(210), - asBCINFO_DUMMY(211), - asBCINFO_DUMMY(212), - asBCINFO_DUMMY(213), - asBCINFO_DUMMY(214), - asBCINFO_DUMMY(215), - asBCINFO_DUMMY(216), - asBCINFO_DUMMY(217), - asBCINFO_DUMMY(218), - asBCINFO_DUMMY(219), - asBCINFO_DUMMY(220), - asBCINFO_DUMMY(221), - asBCINFO_DUMMY(222), - asBCINFO_DUMMY(223), - asBCINFO_DUMMY(224), - asBCINFO_DUMMY(225), - asBCINFO_DUMMY(226), - asBCINFO_DUMMY(227), - asBCINFO_DUMMY(228), - asBCINFO_DUMMY(229), - asBCINFO_DUMMY(230), - asBCINFO_DUMMY(231), - asBCINFO_DUMMY(232), - asBCINFO_DUMMY(233), - asBCINFO_DUMMY(234), - asBCINFO_DUMMY(235), - asBCINFO_DUMMY(236), - asBCINFO_DUMMY(237), - asBCINFO_DUMMY(238), - asBCINFO_DUMMY(239), - asBCINFO_DUMMY(240), - asBCINFO_DUMMY(241), - asBCINFO_DUMMY(242), - asBCINFO_DUMMY(243), - asBCINFO_DUMMY(244), - asBCINFO_DUMMY(245), - asBCINFO_DUMMY(246), - asBCINFO_DUMMY(247), - asBCINFO_DUMMY(248), - asBCINFO_DUMMY(249), - asBCINFO_DUMMY(250), - - asBCINFO(VarDecl, W_ARG, 0), - asBCINFO(Block, INFO, 0), - asBCINFO(ObjInfo, rW_DW_ARG, 0), - asBCINFO(LINE, INFO, 0), - asBCINFO(LABEL, INFO, 0) -}; - -// Macros to access bytecode instruction arguments -#define asBC_DWORDARG(x) (*(((asDWORD*)x)+1)) -#define asBC_INTARG(x) (*(int*)(((asDWORD*)x)+1)) -#define asBC_QWORDARG(x) (*(asQWORD*)(((asDWORD*)x)+1)) -#define asBC_FLOATARG(x) (*(float*)(((asDWORD*)x)+1)) -#define asBC_PTRARG(x) (*(asPWORD*)(((asDWORD*)x)+1)) -#define asBC_WORDARG0(x) (*(((asWORD*)x)+1)) -#define asBC_WORDARG1(x) (*(((asWORD*)x)+2)) -#define asBC_SWORDARG0(x) (*(((short*)x)+1)) -#define asBC_SWORDARG1(x) (*(((short*)x)+2)) -#define asBC_SWORDARG2(x) (*(((short*)x)+3)) - - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source.txt b/dependencies/angelscript/source.txt deleted file mode 100644 index 0f856b21..00000000 --- a/dependencies/angelscript/source.txt +++ /dev/null @@ -1,4 +0,0 @@ -http://www.angelcode.com/angelscript/ -version: AngelScript 2.29.2 (2014/10/21) -With the following changes: - - Added addon 'scriptMath3D' from 2.22.0 to the 'add_on' folder. diff --git a/dependencies/angelscript/source/as_array.h b/dependencies/angelscript/source/as_array.h deleted file mode 100644 index 0291269f..00000000 --- a/dependencies/angelscript/source/as_array.h +++ /dev/null @@ -1,528 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - -#ifndef AS_ARRAY_H -#define AS_ARRAY_H - -#if !defined(AS_NO_MEMORY_H) -#include -#endif -#include // some compilers declare memcpy() here - -#ifdef _MSC_VER -#pragma warning(disable:4345) // warning about a change in how the code is handled in this version -#endif - -BEGIN_AS_NAMESPACE - -template class asCArray -{ -public: - asCArray(); - asCArray(const asCArray &); - asCArray(size_t reserve); - ~asCArray(); - - void Allocate(size_t numElements, bool keepData); - void AllocateNoConstruct(size_t numElements, bool keepData); - size_t GetCapacity() const; - - void PushLast(const T &element); - T PopLast(); - - bool SetLength(size_t numElements); - bool SetLengthNoConstruct(size_t numElements); - size_t GetLength() const; - - void Copy(const T*, size_t count); - asCArray &operator =(const asCArray &); - void SwapWith(asCArray &other); - - const T &operator [](size_t index) const; - T &operator [](size_t index); - T *AddressOf(); - const T *AddressOf() const; - - bool Concatenate(const asCArray &); - void Concatenate(T*, unsigned int count); - - bool Exists(const T &element) const; - int IndexOf(const T &element) const; - void RemoveIndex(size_t index); // Removes the entry without reordering the array - void RemoveValue(const T &element); // Removes the value without reordering the array - void RemoveIndexUnordered(size_t index); // Removes the entry without keeping the order - - bool operator==(const asCArray &) const; - bool operator!=(const asCArray &) const; - -protected: - T *array; - size_t length; - size_t maxLength; - char buf[8]; -}; - -// Implementation - -template -T *asCArray::AddressOf() -{ - return array; -} - -template -const T *asCArray::AddressOf() const -{ - return array; -} - -template -asCArray::asCArray(void) -{ - array = 0; - length = 0; - maxLength = 0; -} - -template -asCArray::asCArray(const asCArray ©) -{ - array = 0; - length = 0; - maxLength = 0; - - *this = copy; -} - -template -asCArray::asCArray(size_t reserve) -{ - array = 0; - length = 0; - maxLength = 0; - - Allocate(reserve, false); -} - -template -asCArray::~asCArray(void) -{ - // Allocating a zero length array will free all memory - Allocate(0,0); -} - -template -size_t asCArray::GetLength() const -{ - return length; -} - -template -const T &asCArray::operator [](size_t index) const -{ - asASSERT(index < length); - - return array[index]; -} - -template -T &asCArray::operator [](size_t index) -{ - asASSERT(index < length); - - return array[index]; -} - -template -void asCArray::PushLast(const T &element) -{ - if( length == maxLength ) - { - if( maxLength == 0 ) - Allocate(1, false); - else - Allocate(2*maxLength, true); - - if( length == maxLength ) - { - // Out of memory. Return without doing anything - return; - } - } - - array[length++] = element; -} - -template -T asCArray::PopLast() -{ - asASSERT(length > 0); - - return array[--length]; -} - -template -void asCArray::Allocate(size_t numElements, bool keepData) -{ - // We have 4 situations - // 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller - // 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes - // 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller - // 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes - - T *tmp = 0; - if( numElements ) - { - if( sizeof(T)*numElements <= 8 ) - // Use the internal buffer - tmp = reinterpret_cast(buf); - else - { - // Allocate the array and construct each of the elements - tmp = asNEWARRAY(T,numElements); - if( tmp == 0 ) - { - // Out of memory. Return without doing anything - return; - } - } - - if( array == tmp ) - { - // Construct only the newly allocated elements - for( size_t n = length; n < numElements; n++ ) - new (&tmp[n]) T(); - } - else - { - // Construct all elements - for( size_t n = 0; n < numElements; n++ ) - new (&tmp[n]) T(); - } - } - - if( array ) - { - size_t oldLength = length; - - if( array == tmp ) - { - if( keepData ) - { - if( length > numElements ) - length = numElements; - } - else - length = 0; - - // Call the destructor for elements that are no longer used - for( size_t n = length; n < oldLength; n++ ) - array[n].~T(); - } - else - { - if( keepData ) - { - if( length > numElements ) - length = numElements; - - for( size_t n = 0; n < length; n++ ) - tmp[n] = array[n]; - } - else - length = 0; - - // Call the destructor for all elements - for( size_t n = 0; n < oldLength; n++ ) - array[n].~T(); - - if( array != reinterpret_cast(buf) ) - asDELETEARRAY(array); - } - } - - array = tmp; - maxLength = numElements; -} - -template -void asCArray::AllocateNoConstruct(size_t numElements, bool keepData) -{ - // We have 4 situations - // 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller - // 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes - // 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller - // 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes - - T *tmp = 0; - if( numElements ) - { - if( sizeof(T)*numElements <= 8 ) - // Use the internal buffer - tmp = reinterpret_cast(buf); - else - { - // Allocate the array and construct each of the elements - tmp = asNEWARRAY(T,numElements); - if( tmp == 0 ) - { - // Out of memory. Return without doing anything - return; - } - } - } - - if( array ) - { - if( array == tmp ) - { - if( keepData ) - { - if( length > numElements ) - length = numElements; - } - else - length = 0; - } - else - { - if( keepData ) - { - if( length > numElements ) - length = numElements; - - memcpy(tmp, array, sizeof(T)*length); - } - else - length = 0; - - if( array != reinterpret_cast(buf) ) - asDELETEARRAY(array); - } - } - - array = tmp; - maxLength = numElements; -} - -template -size_t asCArray::GetCapacity() const -{ - return maxLength; -} - -template -bool asCArray::SetLength(size_t numElements) -{ - if( numElements > maxLength ) - { - Allocate(numElements, true); - if( numElements > maxLength ) - { - // Out of memory. Return without doing anything - return false; - } - } - - length = numElements; - return true; -} - -template -bool asCArray::SetLengthNoConstruct(size_t numElements) -{ - if( numElements > maxLength ) - { - AllocateNoConstruct(numElements, true); - if( numElements > maxLength ) - { - // Out of memory. Return without doing anything - return false; - } - } - - length = numElements; - return true; -} - -template -void asCArray::Copy(const T *data, size_t count) -{ - if( maxLength < count ) - { - Allocate(count, false); - if( maxLength < count ) - { - // Out of memory. Return without doing anything - return; - } - } - - for( size_t n = 0; n < count; n++ ) - array[n] = data[n]; - - length = count; -} - -template -asCArray &asCArray::operator =(const asCArray ©) -{ - Copy(copy.array, copy.length); - - return *this; -} - -template -void asCArray::SwapWith(asCArray &other) -{ - T *tmpArray = array; - size_t tmpLength = length; - size_t tmpMaxLength = maxLength; - char tmpBuf[sizeof(buf)]; - memcpy(tmpBuf, buf, sizeof(buf)); - - array = other.array; - length = other.length; - maxLength = other.maxLength; - memcpy(buf, other.buf, sizeof(buf)); - - other.array = tmpArray; - other.length = tmpLength; - other.maxLength = tmpMaxLength; - memcpy(other.buf, tmpBuf, sizeof(buf)); - - // If the data is in the internal buffer, then the array pointer must refer to it - if( array == reinterpret_cast(other.buf) ) - array = reinterpret_cast(buf); - if( other.array == reinterpret_cast(buf) ) - other.array = reinterpret_cast(other.buf); -} - -template -bool asCArray::operator ==(const asCArray &other) const -{ - if( length != other.length ) return false; - - for( size_t n = 0; n < length; n++ ) - if( array[n] != other.array[n] ) - return false; - - return true; -} - -template -bool asCArray::operator !=(const asCArray &other) const -{ - return !(*this == other); -} - - -// Returns false if the concatenation wasn't successful due to out of memory -template -bool asCArray::Concatenate(const asCArray &other) -{ - if( maxLength < length + other.length ) - { - Allocate(length + other.length, true); - if( maxLength < length + other.length ) - { - // Out of memory - return false; - } - } - - for( size_t n = 0; n < other.length; n++ ) - array[length+n] = other.array[n]; - - length += other.length; - - // Success - return true; -} - -template -void asCArray::Concatenate(T* array, unsigned int count) -{ - for( unsigned int c = 0; c < count; c++ ) - PushLast(array[c]); -} - -template -bool asCArray::Exists(const T &e) const -{ - return IndexOf(e) == -1 ? false : true; -} - -template -int asCArray::IndexOf(const T &e) const -{ - for( size_t n = 0; n < length; n++ ) - if( array[n] == e ) return static_cast(n); - - return -1; -} - -template -void asCArray::RemoveIndex(size_t index) -{ - if( index < length ) - { - for( size_t n = index; n < length-1; n++ ) - array[n] = array[n+1]; - - PopLast(); - } -} - -template -void asCArray::RemoveValue(const T &e) -{ - for( size_t n = 0; n < length; n++ ) - { - if( array[n] == e ) - { - RemoveIndex(n); - break; - } - } -} - -template -void asCArray::RemoveIndexUnordered(size_t index) -{ - if( index == length - 1 ) - PopLast(); - else if( index < length ) - array[index] = PopLast(); -} - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_atomic.cpp b/dependencies/angelscript/source/as_atomic.cpp deleted file mode 100644 index c74cd4db..00000000 --- a/dependencies/angelscript/source/as_atomic.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - -// -// as_atomic.cpp -// -// The implementation of the atomic class for thread safe reference counting -// - -#include "as_atomic.h" - -BEGIN_AS_NAMESPACE - -asCAtomic::asCAtomic() -{ - value = 0; -} - -asDWORD asCAtomic::get() const -{ - // A very high ref count is highly unlikely. It most likely a problem with - // memory that has been overwritten or is being accessed after it was deleted. - asASSERT(value < 1000000); - - return value; -} - -void asCAtomic::set(asDWORD val) -{ - // A very high ref count is highly unlikely. It most likely a problem with - // memory that has been overwritten or is being accessed after it was deleted. - asASSERT(value < 1000000); - - value = val; -} - -asDWORD asCAtomic::atomicInc() -{ - // A very high ref count is highly unlikely. It most likely a problem with - // memory that has been overwritten or is being accessed after it was deleted. - asASSERT(value < 1000000); - - return asAtomicInc((int&)value); -} - -asDWORD asCAtomic::atomicDec() -{ - // A very high ref count is highly unlikely. It most likely a problem with - // memory that has been overwritten or is being accessed after it was deleted. - asASSERT(value < 1000000); - - return asAtomicDec((int&)value); -} - -// -// The following code implements the atomicInc and atomicDec on different platforms -// -#if defined(AS_NO_THREADS) || defined(AS_NO_ATOMIC) - -int asAtomicInc(int &value) -{ - return ++value; -} - -int asAtomicDec(int &value) -{ - return --value; -} - -#elif defined(AS_XENON) /// XBox360 - -END_AS_NAMESPACE -#include -BEGIN_AS_NAMESPACE - -int asAtomicInc(int &value) -{ - return InterlockedIncrement((LONG*)&value); -} - -int asAtomicDec(int &value) -{ - return InterlockedDecrement((LONG*)&value); -} - -#elif defined(AS_WIN) - -END_AS_NAMESPACE -#define WIN32_MEAN_AND_LEAN -#include -BEGIN_AS_NAMESPACE - -int asAtomicInc(int &value) -{ - return InterlockedIncrement((LONG*)&value); -} - -int asAtomicDec(int &value) -{ - asASSERT(value > 0); - return InterlockedDecrement((LONG*)&value); -} - -#elif defined(AS_LINUX) || defined(AS_BSD) || defined(AS_ILLUMOS) || defined(AS_ANDROID) - -// -// atomic_inc_and_test() and atomic_dec_and_test() from asm/atomic.h is not meant -// to be used outside the Linux kernel. Instead we should use the GNUC provided -// __sync_add_and_fetch() and __sync_sub_and_fetch() functions. -// -// Reference: http://golubenco.org/blog/atomic-operations/ -// -// These are only available in GCC 4.1 and above, so for older versions we -// use the critical sections, though it is a lot slower. -// - -int asAtomicInc(int &value) -{ - return __sync_add_and_fetch(&value, 1); -} - -int asAtomicDec(int &value) -{ - return __sync_sub_and_fetch(&value, 1); -} - -#elif defined(AS_MAC) || defined(AS_IPHONE) - -END_AS_NAMESPACE -#include -BEGIN_AS_NAMESPACE - -int asAtomicInc(int &value) -{ - return OSAtomicIncrement32((int32_t*)&value); -} - -int asAtomicDec(int &value) -{ - return OSAtomicDecrement32((int32_t*)&value); -} - -#else - -// If we get here, then the configuration in as_config.h -// is wrong for the compiler/platform combination. -int ERROR_PleaseFixTheConfig[-1]; - -#endif - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_atomic.h b/dependencies/angelscript/source/as_atomic.h deleted file mode 100644 index 13eff5e2..00000000 --- a/dependencies/angelscript/source/as_atomic.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_atomic.h -// -// The asCAtomic class provides methods for performing threadsafe -// operations on a single dword, e.g. reference counting and -// bitfields. -// - - - -#ifndef AS_ATOMIC_H -#define AS_ATOMIC_H - -#include "as_config.h" - -BEGIN_AS_NAMESPACE - -class asCAtomic -{ -public: - asCAtomic(); - - asDWORD get() const; - void set(asDWORD val); - - // Increase and return new value - asDWORD atomicInc(); - - // Decrease and return new value - asDWORD atomicDec(); - -protected: - asDWORD value; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_builder.cpp b/dependencies/angelscript/source/as_builder.cpp deleted file mode 100644 index 522629a5..00000000 --- a/dependencies/angelscript/source/as_builder.cpp +++ /dev/null @@ -1,5232 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_builder.cpp -// -// This is the class that manages the compilation of the scripts -// - - -#include "as_config.h" -#include "as_builder.h" -#include "as_parser.h" -#include "as_compiler.h" -#include "as_tokendef.h" -#include "as_string_util.h" -#include "as_outputbuffer.h" -#include "as_texts.h" -#include "as_scriptobject.h" -#include "as_debug.h" - -BEGIN_AS_NAMESPACE - -#ifndef AS_NO_COMPILER - -// asCSymbolTable template specializations for sGlobalVariableDescription entries -template<> -void asCSymbolTable::GetKey(const sGlobalVariableDescription *entry, asSNameSpaceNamePair &key) const -{ - asSNameSpace *ns = entry->ns; - asCString name = entry->name; - key = asSNameSpaceNamePair(ns, name); -} - -// Comparator for exact variable search -class asCCompGlobVarType : public asIFilter -{ -public: - const asCDataType &m_type; - asCCompGlobVarType(const asCDataType &type) : m_type(type) {} - - bool operator()(const void *p) const - { - const sGlobalVariableDescription* desc = reinterpret_cast(p); - return desc->datatype == m_type; - } - -private: - // The assignment operator is required for MSVC9, otherwise it will complain that it is not possible to auto generate the operator - asCCompGlobVarType &operator=(const asCCompGlobVarType &) {return *this;} -}; - -#endif - -asCBuilder::asCBuilder(asCScriptEngine *_engine, asCModule *_module) -{ - this->engine = _engine; - this->module = _module; - silent = false; -} - -asCBuilder::~asCBuilder() -{ -#ifndef AS_NO_COMPILER - asUINT n; - - // Free all functions - for( n = 0; n < functions.GetLength(); n++ ) - { - if( functions[n] ) - { - if( functions[n]->node ) - functions[n]->node->Destroy(engine); - - asDELETE(functions[n],sFunctionDescription); - } - - functions[n] = 0; - } - - // Free all global variables - asCSymbolTable::iterator it = globVariables.List(); - while( it ) - { - if( (*it)->declaredAtNode ) - (*it)->declaredAtNode->Destroy(engine); - if( (*it)->initializationNode ) - (*it)->initializationNode->Destroy(engine); - asDELETE((*it),sGlobalVariableDescription); - it++; - } - globVariables.Clear(); - - // Free all the loaded files - for( n = 0; n < scripts.GetLength(); n++ ) - { - if( scripts[n] ) - asDELETE(scripts[n],asCScriptCode); - - scripts[n] = 0; - } - - // Free all class declarations - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - if( classDeclarations[n] ) - { - if( classDeclarations[n]->node ) - classDeclarations[n]->node->Destroy(engine); - - asDELETE(classDeclarations[n],sClassDeclaration); - classDeclarations[n] = 0; - } - } - - for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) - { - if( interfaceDeclarations[n] ) - { - if( interfaceDeclarations[n]->node ) - interfaceDeclarations[n]->node->Destroy(engine); - - asDELETE(interfaceDeclarations[n],sClassDeclaration); - interfaceDeclarations[n] = 0; - } - } - - for( n = 0; n < namedTypeDeclarations.GetLength(); n++ ) - { - if( namedTypeDeclarations[n] ) - { - if( namedTypeDeclarations[n]->node ) - namedTypeDeclarations[n]->node->Destroy(engine); - - asDELETE(namedTypeDeclarations[n],sClassDeclaration); - namedTypeDeclarations[n] = 0; - } - } - - for( n = 0; n < funcDefs.GetLength(); n++ ) - { - if( funcDefs[n] ) - { - if( funcDefs[n]->node ) - funcDefs[n]->node->Destroy(engine); - - asDELETE(funcDefs[n],sFuncDef); - funcDefs[n] = 0; - } - } - - for( n = 0; n < mixinClasses.GetLength(); n++ ) - { - if( mixinClasses[n] ) - { - if( mixinClasses[n]->node ) - mixinClasses[n]->node->Destroy(engine); - - asDELETE(mixinClasses[n],sMixinClass); - mixinClasses[n] = 0; - } - } - -#endif // AS_NO_COMPILER -} - -void asCBuilder::Reset() -{ - numErrors = 0; - numWarnings = 0; - engine->preMessage.isSet = false; - -#ifndef AS_NO_COMPILER - // Clear the cache of known types - hasCachedKnownTypes = false; - knownTypes.EraseAll(); -#endif -} - -#ifndef AS_NO_COMPILER -int asCBuilder::AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy) -{ - asCScriptCode *script = asNEW(asCScriptCode); - if( script == 0 ) - return asOUT_OF_MEMORY; - - int r = script->SetCode(name, code, codeLength, makeCopy); - if( r < 0 ) - { - asDELETE(script, asCScriptCode); - return r; - } - - script->lineOffset = lineOffset; - script->idx = sectionIdx; - scripts.PushLast(script); - - return 0; -} - -int asCBuilder::Build() -{ - Reset(); - - ParseScripts(); - - // Compile the types first - CompileInterfaces(); - CompileClasses(); - - // Then the global variables. Here the variables declared with auto - // will be resolved, so they can be accessed properly in the functions - CompileGlobalVariables(); - - // Finally the global functions and class methods - CompileFunctions(); - - // TODO: Attempt to reorder the initialization of global variables so that - // they do not access other uninitialized global variables out-of-order - // The builder needs to check for each of the global variable, what functions - // that are accessed, and what global variables are access by these functions. - - if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) - WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); - - if( numErrors > 0 ) - return asERROR; - - // Make sure something was compiled, otherwise return an error - if( module->IsEmpty() ) - { - WriteError(TXT_NOTHING_WAS_BUILT, 0, 0); - return asERROR; - } - - return asSUCCESS; -} - -int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int lineOffset) -{ - Reset(); - - // Add the string to the script code - asCScriptCode *script = asNEW(asCScriptCode); - if( script == 0 ) - return asOUT_OF_MEMORY; - - script->SetCode(sectionName, code, true); - script->lineOffset = lineOffset; - script->idx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : ""); - scripts.PushLast(script); - - // Parse the string - asCParser parser(this); - if( parser.ParseScript(scripts[0]) < 0 ) - return asERROR; - - asCScriptNode *node = parser.GetScriptNode(); - - // Make sure there is nothing else than the global variable in the script code - if( node == 0 || - node->firstChild == 0 || - node->firstChild != node->lastChild || - node->firstChild->nodeType != snDeclaration ) - { - WriteError(TXT_ONLY_ONE_VARIABLE_ALLOWED, script, 0); - return asERROR; - } - - node = node->firstChild; - node->DisconnectParent(); - RegisterGlobalVar(node, script, module->defaultNamespace); - - CompileGlobalVariables(); - - if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) - WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); - - if( numErrors > 0 ) - { - // Remove the variable from the module, if it was registered - if( globVariables.GetSize() > 0 ) - module->RemoveGlobalVar(module->GetGlobalVarCount()-1); - - return asERROR; - } - - return 0; -} -#endif - -int asCBuilder::ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func) -{ - int firstArgWithDefaultValue = -1; - for( asUINT n = 0; n < func->defaultArgs.GetLength(); n++ ) - { - if( func->defaultArgs[n] ) - firstArgWithDefaultValue = n; - else if( firstArgWithDefaultValue >= 0 ) - { - asCString str; - str.Format(TXT_DEF_ARG_MISSING_IN_FUNC_s, func->GetDeclaration()); - WriteError(str, script, node); - return asINVALID_DECLARATION; - } - } - - return 0; -} - -#ifndef AS_NO_COMPILER -// This function will verify if the newly created function will conflict another overload due to having -// identical function arguments that are not default args, e.g: foo(int) and foo(int, int=0) -int asCBuilder::CheckForConflictsDueToDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func, asCObjectType *objType) -{ - // TODO: Implement for global functions too - if( func->objectType == 0 || objType == 0 ) return 0; - - asCArray funcs; - GetObjectMethodDescriptions(func->name.AddressOf(), objType, funcs, false); - for( asUINT n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *func2 = engine->scriptFunctions[funcs[n]]; - if( func == func2 ) - continue; - - if( func->IsReadOnly() != func2->IsReadOnly() ) - continue; - - bool match = true; - asUINT p = 0; - for( ; p < func->parameterTypes.GetLength() && p < func2->parameterTypes.GetLength(); p++ ) - { - // Only verify until the first argument with default args - if( (func->defaultArgs.GetLength() > p && func->defaultArgs[p]) || - (func2->defaultArgs.GetLength() > p && func2->defaultArgs[p]) ) - break; - - if( func->parameterTypes[p] != func2->parameterTypes[p] || - func->inOutFlags[p] != func2->inOutFlags[p] ) - { - match = false; - break; - } - } - - if( match ) - { - if( !((p >= func->parameterTypes.GetLength() && p < func2->defaultArgs.GetLength() && func2->defaultArgs[p]) || - (p >= func2->parameterTypes.GetLength() && p < func->defaultArgs.GetLength() && func->defaultArgs[p])) ) - { - // The argument lists match for the full length of the shorter, but the next - // argument on the longer does not have a default arg so there is no conflict - match = false; - } - } - - if( match ) - { - WriteWarning(TXT_OVERLOAD_CONFLICTS_DUE_TO_DEFAULT_ARGS, script, node); - WriteInfo(func->GetDeclaration(), script, node); - WriteInfo(func2->GetDeclaration(), script, node); - break; - } - } - - return 0; -} - -int asCBuilder::CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asCScriptFunction **outFunc) -{ - asASSERT(outFunc != 0); - - Reset(); - - // Add the string to the script code - asCScriptCode *script = asNEW(asCScriptCode); - if( script == 0 ) - return asOUT_OF_MEMORY; - - script->SetCode(sectionName, code, true); - script->lineOffset = lineOffset; - script->idx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : ""); - scripts.PushLast(script); - - // Parse the string - asCParser parser(this); - if( parser.ParseScript(scripts[0]) < 0 ) - return asERROR; - - asCScriptNode *node = parser.GetScriptNode(); - - // Make sure there is nothing else than the function in the script code - if( node == 0 || - node->firstChild == 0 || - node->firstChild != node->lastChild || - node->firstChild->nodeType != snFunction ) - { - WriteError(TXT_ONLY_ONE_FUNCTION_ALLOWED, script, 0); - return asERROR; - } - - // Find the function node - node = node->firstChild; - - // Create the function - bool isConstructor, isDestructor, isPrivate, isFinal, isOverride, isShared; - 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, isFinal, isOverride, isShared, module->defaultNamespace); - func->id = engine->GetNextScriptFunctionId(); - func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : ""); - int row, col; - scripts[0]->ConvertPosToRowCol(node->tokenPos, &row, &col); - func->scriptData->declaredAt = (row & 0xFFFFF)|((col & 0xFFF)<<20); - func->nameSpace = module->defaultNamespace; - - // Make sure the default args are declared correctly - int r = ValidateDefaultArgs(script, node, func); - if( r < 0 ) - { - func->Release(); - return asERROR; - } - - // 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); - if( r < 0 ) - { - func->Orphan(module); - return asERROR; - } - - module->globalFunctions.Put(func); - func->AddRef(); - module->AddScriptFunction(func); - } - else - engine->SetScriptFunction(func); - - // Fill in the function info for the builder too - node->DisconnectParent(); - sFunctionDescription *funcDesc = asNEW(sFunctionDescription); - if( funcDesc == 0 ) - { - func->Release(); - return asOUT_OF_MEMORY; - } - - functions.PushLast(funcDesc); - funcDesc->script = scripts[0]; - funcDesc->node = node; - funcDesc->name = func->name; - funcDesc->funcId = func->id; - funcDesc->paramNames = func->parameterNames; - funcDesc->isExistingShared = false; - - asCCompiler compiler(engine); - compiler.CompileFunction(this, functions[0]->script, func->parameterNames, functions[0]->node, func, 0); - - if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) - WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); - - if( numErrors > 0 ) - { - // If the function was added to the module then remove it again - if( compileFlags & asCOMP_ADD_TO_MODULE ) - { - module->globalFunctions.Erase(module->globalFunctions.GetIndex(func)); - module->scriptFunctions.RemoveValue(func); - func->Release(); - func->Orphan(module); - } - - func->Release(); - - return asERROR; - } - - // Return the function - *outFunc = func; - - return asSUCCESS; -} - -void asCBuilder::ParseScripts() -{ - TimeIt("asCBuilder::ParseScripts"); - - asCArray parsers((int)scripts.GetLength()); - - // Parse all the files as if they were one - asUINT n = 0; - for( n = 0; n < scripts.GetLength(); n++ ) - { - asCParser *parser = asNEW(asCParser)(this); - if( parser != 0 ) - { - parsers.PushLast(parser); - - // Parse the script file - parser->ParseScript(scripts[n]); - } - } - - if( numErrors == 0 ) - { - // Find all type declarations - for( n = 0; n < scripts.GetLength(); n++ ) - { - asCScriptNode *node = parsers[n]->GetScriptNode(); - RegisterTypesFromScript(node, scripts[n], engine->nameSpaces[0]); - } - - // Register the complete function definitions - for( n = 0; n < funcDefs.GetLength(); n++ ) - CompleteFuncDef(funcDefs[n]); - - // Register script methods found in the interfaces - for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) - { - sClassDeclaration *decl = interfaceDeclarations[n]; - asCScriptNode *node = decl->node->firstChild->next; - - // Skip list of inherited interfaces - while( node && node->nodeType == snIdentifier ) - node = node->next; - - while( node ) - { - asCScriptNode *next = node->next; - if( node->nodeType == snFunction ) - { - node->DisconnectParent(); - RegisterScriptFunctionFromNode(node, decl->script, decl->objType, true, false, 0, decl->isExistingShared); - } - else if( node->nodeType == snVirtualProperty ) - { - node->DisconnectParent(); - RegisterVirtualProperty(node, decl->script, decl->objType, true, false, 0, decl->isExistingShared); - } - - node = next; - } - } - - // Register script methods found in the classes - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - sClassDeclaration *decl = classDeclarations[n]; - - asCScriptNode *node = decl->node->firstChild->next; - - // Skip list of classes and interfaces - while( node && node->nodeType == snIdentifier ) - node = node->next; - - while( node ) - { - asCScriptNode *next = node->next; - if( node->nodeType == snFunction ) - { - node->DisconnectParent(); - RegisterScriptFunctionFromNode(node, decl->script, decl->objType, false, false, 0, decl->isExistingShared); - } - else if( node->nodeType == snVirtualProperty ) - { - node->DisconnectParent(); - RegisterVirtualProperty(node, decl->script, decl->objType, 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 ) - { - if( decl->objType->beh.constructors.GetLength() == 1 || engine->ep.alwaysImplDefaultConstruct ) - { - AddDefaultConstructor(decl->objType, decl->script); - } - else - { - // As the class has another constructor we shouldn't provide the default constructor - if( decl->objType->beh.construct ) - { - engine->scriptFunctions[decl->objType->beh.construct]->Release(); - decl->objType->beh.construct = 0; - decl->objType->beh.constructors.RemoveIndex(0); - } - if( decl->objType->beh.factory ) - { - engine->scriptFunctions[decl->objType->beh.factory]->Release(); - decl->objType->beh.factory = 0; - decl->objType->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 ) - { - engine->scriptFunctions[decl->objType->beh.copy]->Release(); - decl->objType->beh.copy = 0; - } - } - } - } - - // Find other global nodes - for( n = 0; n < scripts.GetLength(); n++ ) - { - // Find other global nodes - asCScriptNode *node = parsers[n]->GetScriptNode(); - RegisterNonTypesFromScript(node, scripts[n], engine->nameSpaces[0]); - } - } - - for( n = 0; n < parsers.GetLength(); n++ ) - { - asDELETE(parsers[n],asCParser); - } -} - -void asCBuilder::RegisterTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns) -{ - asASSERT(node->nodeType == snScript); - - // Find structure definitions first - node = node->firstChild; - while( node ) - { - asCScriptNode *next = node->next; - if( node->nodeType == snNamespace ) - { - // Recursively register the entities defined in the namespace - asCString nsName; - nsName.Assign(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength); - if( ns->name != "" ) - nsName = ns->name + "::" + nsName; - - asSNameSpace *nsChild = engine->AddNameSpace(nsName.AddressOf()); - RegisterTypesFromScript(node->lastChild, script, nsChild); - } - else - { - if( node->nodeType == snClass ) - { - node->DisconnectParent(); - RegisterClass(node, script, ns); - } - else if( node->nodeType == snInterface ) - { - node->DisconnectParent(); - RegisterInterface(node, script, ns); - } - else if( node->nodeType == snEnum ) - { - node->DisconnectParent(); - RegisterEnum(node, script, ns); - } - else if( node->nodeType == snTypedef ) - { - node->DisconnectParent(); - RegisterTypedef(node, script, ns); - } - else if( node->nodeType == snFuncDef ) - { - node->DisconnectParent(); - RegisterFuncDef(node, script, ns); - } - else if( node->nodeType == snMixin ) - { - node->DisconnectParent(); - RegisterMixinClass(node, script, ns); - } - } - - node = next; - } -} - -void asCBuilder::RegisterNonTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns) -{ - node = node->firstChild; - while( node ) - { - asCScriptNode *next = node->next; - if( node->nodeType == snNamespace ) - { - // Determine the name of the namespace - asCString nsName; - nsName.Assign(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength); - if( ns->name != "" ) - nsName = ns->name + "::" + nsName; - - // Declare the namespace, then add the entities - asSNameSpace *nsChild = engine->AddNameSpace(nsName.AddressOf()); - RegisterNonTypesFromScript(node->lastChild, script, nsChild); - } - else - { - node->DisconnectParent(); - if( node->nodeType == snFunction ) - RegisterScriptFunctionFromNode(node, script, 0, false, true, ns); - else if( node->nodeType == snDeclaration ) - RegisterGlobalVar(node, script, ns); - else if( node->nodeType == snVirtualProperty ) - RegisterVirtualProperty(node, script, 0, false, true, ns); - else if( node->nodeType == snImport ) - RegisterImportedFunction(module->GetNextImportedFunctionId(), node, script, ns); - else - { - // Unused script node - int r, c; - script->ConvertPosToRowCol(node->tokenPos, &r, &c); - - WriteWarning(script->name, TXT_UNUSED_SCRIPT_NODE, r, c); - - node->Destroy(engine); - } - } - - node = next; - } -} - -void asCBuilder::CompileFunctions() -{ - // Compile each function - for( asUINT n = 0; n < functions.GetLength(); n++ ) - { - sFunctionDescription *current = functions[n]; - if( current == 0 ) continue; - - // Don't compile the function again if it was an existing shared function - if( current->isExistingShared ) continue; - - asCCompiler compiler(engine); - asCScriptFunction *func = engine->scriptFunctions[current->funcId]; - - // Find the class declaration for constructors - sClassDeclaration *classDecl = 0; - if( current->objType && current->name == current->objType->name ) - { - for( asUINT n = 0; n < classDeclarations.GetLength(); n++ ) - { - if( classDeclarations[n]->objType == current->objType ) - { - classDecl = classDeclarations[n]; - break; - } - } - - asASSERT( classDecl ); - } - - if( current->node ) - { - int r, c; - current->script->ConvertPosToRowCol(current->node->tokenPos, &r, &c); - - asCString str = func->GetDeclarationStr(); - str.Format(TXT_COMPILING_s, str.AddressOf()); - WriteInfo(current->script->name, str, r, c, true); - - // When compiling a constructor need to pass the class declaration for member initializations - compiler.CompileFunction(this, current->script, current->paramNames, current->node, func, classDecl); - - engine->preMessage.isSet = false; - } - else if( current->objType && current->name == current->objType->name ) - { - asCScriptNode *node = classDecl->node; - - int r = 0, c = 0; - if( node ) - current->script->ConvertPosToRowCol(node->tokenPos, &r, &c); - - asCString str = func->GetDeclarationStr(); - str.Format(TXT_COMPILING_s, str.AddressOf()); - WriteInfo(current->script->name, str, r, c, true); - - // This is the default constructor that is generated - // automatically if not implemented by the user. - compiler.CompileDefaultConstructor(this, current->script, node, func, classDecl); - - engine->preMessage.isSet = false; - } - else - { - asASSERT( false ); - } - } -} -#endif - -// Called from module and engine -int asCBuilder::ParseDataType(const char *datatype, asCDataType *result, asSNameSpace *implicitNamespace, bool isReturnType) -{ - Reset(); - - asCScriptCode source; - source.SetCode("", datatype, true); - - asCParser parser(this); - int r = parser.ParseDataType(&source, isReturnType); - if( r < 0 ) - return asINVALID_TYPE; - - // Get data type and property name - asCScriptNode *dataType = parser.GetScriptNode()->firstChild; - - *result = CreateDataTypeFromNode(dataType, &source, implicitNamespace, true); - if( isReturnType ) - *result = ModifyDataTypeFromNode(*result, dataType->next, &source, 0, 0); - - if( numErrors > 0 ) - return asINVALID_TYPE; - - return asSUCCESS; -} - -int asCBuilder::ParseTemplateDecl(const char *decl, asCString *name, asCArray &subtypeNames) -{ - Reset(); - - asCScriptCode source; - source.SetCode("", decl, true); - - asCParser parser(this); - int r = parser.ParseTemplateDecl(&source); - if( r < 0 ) - return asINVALID_TYPE; - - // Get the template name and subtype names - asCScriptNode *node = parser.GetScriptNode()->firstChild; - - name->Assign(&decl[node->tokenPos], node->tokenLength); - while( (node = node->next) != 0 ) - { - asCString subtypeName; - subtypeName.Assign(&decl[node->tokenPos], node->tokenLength); - subtypeNames.PushLast(subtypeName); - } - - // TODO: template: check for name conflicts - - if( numErrors > 0 ) - return asINVALID_DECLARATION; - - return asSUCCESS; -} - -int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &name, asCDataType &type, asSNameSpace *ns) -{ - // Either datatype or namespace must be informed - asASSERT( dt || ns ); - - Reset(); - - if( dt ) - { - // Verify that the object type exist - if( dt->GetObjectType() == 0 ) - return asINVALID_OBJECT; - } - - // Check property declaration and type - asCScriptCode source; - source.SetCode(TXT_PROPERTY, decl, true); - - asCParser parser(this); - int r = parser.ParsePropertyDeclaration(&source); - if( r < 0 ) - return asINVALID_DECLARATION; - - // Get data type and property name - asCScriptNode *dataType = parser.GetScriptNode()->firstChild; - - asCScriptNode *nameNode = dataType->next; - - // 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); - name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength); - - // 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() ) - { - // Function definitions must always be handles - return asINVALID_DECLARATION; - } - - // Verify property name - if( dt ) - { - if( CheckNameConflictMember(dt->GetObjectType(), name.AddressOf(), nameNode, &source, true) < 0 ) - return asNAME_TAKEN; - } - else - { - if( CheckNameConflict(name.AddressOf(), nameNode, &source, ns) < 0 ) - return asNAME_TAKEN; - } - - if( numErrors > 0 ) - return asINVALID_DECLARATION; - - return asSUCCESS; -} - -#ifndef AS_NO_COMPILER -asCObjectProperty *asCBuilder::GetObjectProperty(asCDataType &obj, const char *prop) -{ - asASSERT(obj.GetObjectType() != 0); - - // TODO: optimize: Improve linear search - asCArray &props = obj.GetObjectType()->properties; - for( asUINT n = 0; n < props.GetLength(); n++ ) - { - if( props[n]->name == prop ) - { - if( module->accessMask & props[n]->accessMask ) - return props[n]; - else - return 0; - } - } - - return 0; -} -#endif - -bool asCBuilder::DoesGlobalPropertyExist(const char *prop, asSNameSpace *ns, asCGlobalProperty **outProp, sGlobalVariableDescription **outDesc, bool *isAppProp) -{ - if( outProp ) *outProp = 0; - if( outDesc ) *outDesc = 0; - if( isAppProp ) *isAppProp = false; - - // Check application registered properties - asCString name(prop); - asCGlobalProperty *globProp = engine->registeredGlobalProps.GetFirst(ns, name); - if( globProp ) - { - if( isAppProp ) *isAppProp = true; - if( outProp ) *outProp = globProp; - return true; - } - -#ifndef AS_NO_COMPILER - // Check properties being compiled now - sGlobalVariableDescription* desc = globVariables.GetFirst(ns, prop); - if( desc && !desc->isEnumValue ) - { - if( outProp ) *outProp = desc->property; - if( outDesc ) *outDesc = desc; - return true; - } -#endif - - // Check previously compiled global variables - if( module ) - { - globProp = module->scriptGlobals.GetFirst(ns, prop); - if( globProp ) - { - if( outProp ) *outProp = globProp; - return true; - } - } - - return false; -} - -asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, asSNameSpace *ns, bool *isCompiled, bool *isPureConstant, asQWORD *constantValue, bool *isAppProp) -{ - if( isCompiled ) *isCompiled = true; - if( isPureConstant ) *isPureConstant = false; - if( isAppProp ) *isAppProp = false; - if( constantValue ) *constantValue = 0; - - asCGlobalProperty *globProp = 0; - sGlobalVariableDescription *globDesc = 0; - if( DoesGlobalPropertyExist(prop, ns, &globProp, &globDesc, isAppProp) ) - { -#ifndef AS_NO_COMPILER - if( globDesc ) - { - // The property was declared in this build call, check if it has been compiled successfully already - if( isCompiled ) *isCompiled = globDesc->isCompiled; - if( isPureConstant ) *isPureConstant = globDesc->isPureConstant; - if( constantValue ) *constantValue = globDesc->constantValue; - } - else -#endif - if( isAppProp ) - { - // Don't return the property if the module doesn't have access to it - if( !(module->accessMask & globProp->accessMask) ) - globProp = 0; - } - return globProp; - } - - return 0; -} - -int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles, bool *returnAutoHandle, asSNameSpace *ns, asCScriptNode **listPattern) -{ - asASSERT( objType || ns ); - - // TODO: Can't we use GetParsedFunctionDetails to do most of what is done in this function? - - Reset(); - - asCScriptCode source; - source.SetCode(TXT_SYSTEM_FUNCTION, decl, true); - - asCParser parser(this); - int r = parser.ParseFunctionDefinition(&source, listPattern != 0); - if( r < 0 ) - return asINVALID_DECLARATION; - - asCScriptNode *node = parser.GetScriptNode(); - - // Determine scope - asCScriptNode *n = node->firstChild->next->next; - asCString scope = GetScopeFromNode(n, &source, &n); - func->nameSpace = engine->FindNameSpace(scope.AddressOf()); - if( func->nameSpace == 0 ) - return asINVALID_DECLARATION; - - // Find name - func->name.Assign(&source.code[n->tokenPos], n->tokenLength); - - // Initialize a script function object for registration - 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 = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle); - if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) ) - return asINVALID_DECLARATION; - if( returnAutoHandle ) *returnAutoHandle = autoHandle; - - // Reference types cannot be returned by value from system functions - if( isSystemFunction && - (func->returnType.GetObjectType() && - (func->returnType.GetObjectType()->flags & asOBJ_REF)) && - !(func->returnType.IsReference() || - func->returnType.IsObjectHandle()) ) - return asINVALID_DECLARATION; - - // Count number of parameters - int paramCount = 0; - asCScriptNode *paramList = n->next; - n = paramList->firstChild; - while( n ) - { - paramCount++; - n = n->next->next; - if( n && n->nodeType == snIdentifier ) - n = n->next; - - if( n && n->nodeType == snExpression ) - n = n->next; - } - - // Preallocate memory - func->parameterTypes.Allocate(paramCount, false); - func->parameterNames.SetLength(paramCount); - func->inOutFlags.Allocate(paramCount, false); - func->defaultArgs.Allocate(paramCount, false); - if( paramAutoHandles ) paramAutoHandles->Allocate(paramCount, false); - - n = paramList->firstChild; - asUINT index = 0; - while( n ) - { - asETypeModifiers inOutFlags; - asCDataType type = CreateDataTypeFromNode(n, &source, objType ? objType->nameSpace : ns, false, 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.IsReference() || - type.IsObjectHandle()) ) - return asINVALID_DECLARATION; - - // Store the parameter type - func->parameterTypes.PushLast(type); - func->inOutFlags.PushLast(inOutFlags); - - // Don't permit void parameters - if( type.GetTokenType() == ttVoid ) - return asINVALID_DECLARATION; - - if( autoHandle && (!type.IsObjectHandle() || type.IsReference()) ) - return asINVALID_DECLARATION; - - if( paramAutoHandles ) paramAutoHandles->PushLast(autoHandle); - - // Make sure that var type parameters are references - if( type.GetTokenType() == ttQuestion && - !type.IsReference() ) - return asINVALID_DECLARATION; - - // Move to next parameter - n = n->next->next; - if( n && n->nodeType == snIdentifier ) - { - func->parameterNames[index] = asCString(&source.code[n->tokenPos], n->tokenLength); - n = n->next; - } - ++index; - - if( n && n->nodeType == snExpression ) - { - // Strip out white space and comments to better share the string - asCString *defaultArgStr = asNEW(asCString); - if( defaultArgStr ) - { - *defaultArgStr = GetCleanExpressionString(n, &source); - func->defaultArgs.PushLast(defaultArgStr); - } - - n = n->next; - } - else - func->defaultArgs.PushLast(0); - } - - // Set the read-only flag if const is declared after parameter list - n = paramList->next; - if( n && n->nodeType == snUndefined && n->tokenType == ttConst ) - { - if( objType == 0 ) - return asINVALID_DECLARATION; - func->isReadOnly = true; - - n = n->next; - } - else - func->isReadOnly = 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 ) - return asINVALID_DECLARATION; - else - { - *listPattern = n; - n->DisconnectParent(); - } - } - else - { - if( n ) - return asINVALID_DECLARATION; - } - - // Make sure the default args are declared correctly - ValidateDefaultArgs(&source, node, func); - - if( numErrors > 0 || numWarnings > 0 ) - return asINVALID_DECLARATION; - - return 0; -} - -int asCBuilder::ParseVariableDeclaration(const char *decl, asSNameSpace *implicitNamespace, asCString &outName, asSNameSpace *&outNamespace, asCDataType &outDt) -{ - Reset(); - - asCScriptCode source; - source.SetCode(TXT_VARIABLE_DECL, decl, true); - - asCParser parser(this); - - int r = parser.ParsePropertyDeclaration(&source); - if( r < 0 ) - return asINVALID_DECLARATION; - - asCScriptNode *node = parser.GetScriptNode(); - - // Determine the scope from declaration - asCScriptNode *n = node->firstChild->next; - outNamespace = GetNameSpaceFromNode(n, &source, implicitNamespace, &n); - if( outNamespace == 0 ) - return asINVALID_DECLARATION; - - // Find name - outName.Assign(&source.code[n->tokenPos], n->tokenLength); - - // Initialize a script variable object for registration - outDt = CreateDataTypeFromNode(node->firstChild, &source, implicitNamespace); - - if( numErrors > 0 || numWarnings > 0 ) - return asINVALID_DECLARATION; - - return 0; -} - -int asCBuilder::CheckNameConflictMember(asCObjectType *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty) -{ - // It's not necessary to check against object types - - // TODO: optimize: Improve linear search - asCArray &props = t->properties; - for( asUINT n = 0; n < props.GetLength(); n++ ) - { - if( props[n]->name == name ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_OBJ_PROPERTY, name); - WriteError(str, code, node); - } - - return -1; - } - } - - // Property names must be checked against method names - if( isProperty ) - { - asCArray methods = t->methods; - for( asUINT n = 0; n < methods.GetLength(); n++ ) - { - if( engine->scriptFunctions[methods[n]]->name == name ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_METHOD, name); - WriteError(str, code, node); - } - - return -1; - } - } - } - - return 0; -} - -int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns) -{ - // Check against registered object types - // TODO: Must check against registered funcdefs too - if( engine->GetRegisteredObjectType(name, ns) != 0 ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, name); - WriteError(str, code, node); - } - - return -1; - } - - // Check against global properties - if( DoesGlobalPropertyExist(name, ns) ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, name); - WriteError(str, code, node); - } - - return -1; - } - - // TODO: Property names must be checked against function names - -#ifndef AS_NO_COMPILER - // Check against class types - asUINT n; - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - if( classDeclarations[n]->name == name && - classDeclarations[n]->objType->nameSpace == ns ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_STRUCT, name); - WriteError(str, code, node); - } - - return -1; - } - } - - // Check against named types - for( n = 0; n < namedTypeDeclarations.GetLength(); n++ ) - { - if( namedTypeDeclarations[n]->name == name && - namedTypeDeclarations[n]->objType->nameSpace == ns ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_IS_NAMED_TYPE, name); - WriteError(str, code, node); - } - - return -1; - } - } - - // Must check for name conflicts with funcdefs - for( n = 0; n < funcDefs.GetLength(); n++ ) - { - if( funcDefs[n]->name == name && - module->funcDefs[funcDefs[n]->idx]->nameSpace == ns ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name); - WriteError(str, code, node); - } - - return -1; - } - } - - // Check against mixin classes - if( GetMixinClass(name, ns) ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_IS_MIXIN, name); - WriteError(str, code, node); - } - - return -1; - } -#endif - - return 0; -} - -#ifndef AS_NO_COMPILER -sMixinClass *asCBuilder::GetMixinClass(const char *name, asSNameSpace *ns) -{ - for( asUINT n = 0; n < mixinClasses.GetLength(); n++ ) - if( mixinClasses[n]->name == name && - mixinClasses[n]->ns == ns ) - return mixinClasses[n]; - - return 0; -} - -int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) -{ - // Find the name - asASSERT( node->firstChild->nodeType == snDataType ); - asCScriptNode *n = node->firstChild->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 ) - { - node->Destroy(engine); - return r; - } - - // The function definition should be stored as a asCScriptFunction so that the application - // can use the asIScriptFunction interface to enumerate the return type and parameters - - // The return type and parameter types aren't determined in this function. A second pass is - // necessary after all type declarations have been identified. The second pass is implemented - // in CompleteFuncDef(). - - sFuncDef *fd = asNEW(sFuncDef); - if( fd == 0 ) - { - node->Destroy(engine); - return asOUT_OF_MEMORY; - } - - fd->name = name; - fd->node = node; - fd->script = file; - fd->idx = module->AddFuncDef(name, ns); - - funcDefs.PushLast(fd); - - return 0; -} - -void asCBuilder::CompleteFuncDef(sFuncDef *funcDef) -{ - asCArray defaultArgs; - bool isConstMethod; - bool isConstructor; - bool isDestructor; - bool isPrivate; - bool isOverride; - bool isFinal; - bool isShared; - - asCScriptFunction *func = module->funcDefs[funcDef->idx]; - asASSERT( func ); - - GetParsedFunctionDetails(funcDef->node, funcDef->script, 0, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isOverride, isFinal, isShared, func->nameSpace); - - // 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++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - // TODO: Should we force the use of 'shared' for this check to be done? - // Check if there is another identical funcdef from another module and if so reuse that instead - for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) - { - asCScriptFunction *f2 = engine->funcDefs[n]; - if( f2 == 0 || func == f2 ) - continue; - - if( f2->name == func->name && - f2->nameSpace == func->nameSpace && - f2->IsSignatureExceptNameEqual(func) ) - { - // Replace our funcdef for the existing one - funcDef->idx = f2->id; - module->funcDefs[module->funcDefs.IndexOf(func)] = f2; - f2->AddRef(); - - engine->funcDefs.RemoveValue(func); - - func->Release(); - - // funcdefs aren't destroyed when the refCount reaches zero so we need to manually delete them - asDELETE(func, asCScriptFunction); - break; - } - } -} - -int asCBuilder::RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) -{ - // Has the application disabled global vars? - if( engine->ep.disallowGlobalVars ) - WriteError(TXT_GLOBAL_VARS_NOT_ALLOWED, file, node); - - // What data type is it? - asCDataType type = CreateDataTypeFromNode(node->firstChild, file, ns); - - if( !type.CanBeInstantiated() ) - { - asCString str; - if( type.IsAbstractClass() ) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format().AddressOf()); - else if( type.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format().AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf()); - - WriteError(str, file, node); - } - - asCScriptNode *n = node->firstChild->next; - - while( n ) - { - // Verify that the name isn't taken - asCString name(&file->code[n->tokenPos], n->tokenLength); - CheckNameConflict(name.AddressOf(), n, file, ns); - - // Register the global variable - sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription); - if( gvar == 0 ) - { - node->Destroy(engine); - return asOUT_OF_MEMORY; - } - - gvar->script = file; - gvar->name = name; - gvar->isCompiled = false; - gvar->datatype = type; - gvar->isEnumValue = false; - gvar->ns = ns; - - // TODO: Give error message if wrong - asASSERT(!gvar->datatype.IsReference()); - - // Allocation is done when the variable is compiled, to allow for autos - gvar->property = 0; - gvar->index = 0; - - globVariables.Put(gvar); - - - gvar->declaredAtNode = n; - n = n->next; - gvar->declaredAtNode->DisconnectParent(); - gvar->initializationNode = 0; - if( n && - ( n->nodeType == snAssignment || - n->nodeType == snArgList || - n->nodeType == snInitList ) ) - { - gvar->initializationNode = n; - n = n->next; - gvar->initializationNode->DisconnectParent(); - } - } - - node->Destroy(engine); - - return 0; -} - -int asCBuilder::RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) -{ - asCScriptNode *cl = node->firstChild; - asASSERT( cl->nodeType == snClass ); - - asCScriptNode *n = cl->firstChild; - - // Skip potential 'final' and 'shared' tokens - while( n->tokenType == ttIdentifier && - (file->TokenEquals(n->tokenPos, n->tokenLength, FINAL_TOKEN) || - file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN)) ) - { - // Report error, because mixin class cannot be final or shared - asCString msg; - msg.Format(TXT_MIXIN_CANNOT_BE_DECLARED_AS_s, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); - WriteError(msg, file, n); - - asCScriptNode *tmp = n; - n = n->next; - - // Remove the invalid node, so compilation can continue as if it wasn't there - tmp->DisconnectParent(); - tmp->Destroy(engine); - } - - asCString name(&file->code[n->tokenPos], n->tokenLength); - - int r, c; - file->ConvertPosToRowCol(n->tokenPos, &r, &c); - - CheckNameConflict(name.AddressOf(), n, file, ns); - - sMixinClass *decl = asNEW(sMixinClass); - if( decl == 0 ) - { - node->Destroy(engine); - return asOUT_OF_MEMORY; - } - - mixinClasses.PushLast(decl); - decl->name = name; - decl->ns = ns; - decl->node = cl; - decl->script = file; - - // Clean up memory - cl->DisconnectParent(); - node->Destroy(engine); - - return 0; -} - -int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) -{ - asCScriptNode *n = node->firstChild; - bool isFinal = false; - bool isShared = false; - bool isAbstract = false; - - // Check the class modifiers - while( n->tokenType == ttIdentifier ) - { - if( file->TokenEquals(n->tokenPos, n->tokenLength, FINAL_TOKEN) ) - { - if( isAbstract ) - WriteError(TXT_CLASS_CANT_BE_FINAL_AND_ABSTRACT, file, n); - else - { - if( isFinal ) - { - asCString msg; - msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); - WriteWarning(msg, file, n); - } - isFinal = true; - } - } - else if( file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN) ) - { - if( isShared ) - { - asCString msg; - msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); - WriteWarning(msg, file, n); - } - isShared = true; - } - else if( file->TokenEquals(n->tokenPos, n->tokenLength, ABSTRACT_TOKEN) ) - { - if( isFinal ) - WriteError(TXT_CLASS_CANT_BE_FINAL_AND_ABSTRACT, file, n); - else - { - if( isAbstract ) - { - asCString msg; - msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); - WriteWarning(msg, file, n); - } - isAbstract = true; - } - } - else - { - // This is the name of the class - break; - } - - n = n->next; - } - - asCString name(&file->code[n->tokenPos], n->tokenLength); - - int r, c; - file->ConvertPosToRowCol(n->tokenPos, &r, &c); - - CheckNameConflict(name.AddressOf(), n, file, ns); - - sClassDeclaration *decl = asNEW(sClassDeclaration); - if( decl == 0 ) - { - node->Destroy(engine); - return asOUT_OF_MEMORY; - } - - classDeclarations.PushLast(decl); - decl->name = name; - decl->script = file; - decl->node = node; - - // 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->scriptTypes.GetLength(); n++ ) - { - asCObjectType *st = engine->scriptTypes[n]; - if( st && - st->IsShared() && - st->name == name && - st->nameSpace == ns && - !st->IsInterface() ) - { - // We'll use the existing type - decl->isExistingShared = true; - decl->objType = st; - module->classTypes.PushLast(st); - st->AddRef(); - return 0; - } - } - } - - // 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); - engine->scriptTypes.PushLast(st); - st->AddRef(); - decl->objType = 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]->AddRef(); - engine->scriptFunctions[st->beh.release]->AddRef(); - engine->scriptFunctions[st->beh.gcEnumReferences]->AddRef(); - engine->scriptFunctions[st->beh.gcGetFlag]->AddRef(); - engine->scriptFunctions[st->beh.gcGetRefCount]->AddRef(); - engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRef(); - engine->scriptFunctions[st->beh.gcSetFlag]->AddRef(); - engine->scriptFunctions[st->beh.copy]->AddRef(); - engine->scriptFunctions[st->beh.factory]->AddRef(); - engine->scriptFunctions[st->beh.construct]->AddRef(); - // TODO: weak: Should not do this if the class has been declared with noweak - engine->scriptFunctions[st->beh.getWeakRefFlag]->AddRef(); - for( asUINT i = 1; i < st->beh.operators.GetLength(); i += 2 ) - engine->scriptFunctions[st->beh.operators[i]]->AddRef(); - - return 0; -} - -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 ) - { - isShared = true; - - n = n->next; - name.Assign(&file->code[n->tokenPos], n->tokenLength); - } - - int r, c; - file->ConvertPosToRowCol(n->tokenPos, &r, &c); - - CheckNameConflict(name.AddressOf(), n, file, ns); - - sClassDeclaration *decl = asNEW(sClassDeclaration); - if( decl == 0 ) - { - node->Destroy(engine); - return asOUT_OF_MEMORY; - } - - interfaceDeclarations.PushLast(decl); - decl->name = name; - decl->script = file; - decl->node = node; - - // 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->scriptTypes.GetLength(); n++ ) - { - asCObjectType *st = engine->scriptTypes[n]; - if( st && - st->IsShared() && - st->name == name && - st->nameSpace == ns && - st->IsInterface() ) - { - // We'll use the existing type - decl->isExistingShared = true; - decl->objType = st; - module->classTypes.PushLast(st); - st->AddRef(); - return 0; - } - } - } - - // Register the object type for the interface - asCObjectType *st = asNEW(asCObjectType)(engine); - if( st == 0 ) - return asOUT_OF_MEMORY; - - st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT; - - if( isShared ) - st->flags |= asOBJ_SHARED; - - st->size = 0; // Cannot be instantiated - st->name = name; - st->nameSpace = ns; - st->module = module; - module->classTypes.PushLast(st); - engine->scriptTypes.PushLast(st); - st->AddRef(); - decl->objType = st; - - // Use the default script class behaviours - st->beh.construct = 0; - st->beh.addref = engine->scriptTypeBehaviours.beh.addref; - engine->scriptFunctions[st->beh.addref]->AddRef(); - st->beh.release = engine->scriptTypeBehaviours.beh.release; - engine->scriptFunctions[st->beh.release]->AddRef(); - st->beh.copy = 0; - - return 0; -} - -void asCBuilder::CompileGlobalVariables() -{ - bool compileSucceeded = true; - - // Store state of compilation (errors, warning, output) - int currNumErrors = numErrors; - int currNumWarnings = numWarnings; - - // Backup the original message stream - bool msgCallback = engine->msgCallback; - asSSystemFunctionInterface msgCallbackFunc = engine->msgCallbackFunc; - void *msgCallbackObj = engine->msgCallbackObj; - - // Set the new temporary message stream - asCOutputBuffer outBuffer; - engine->SetMessageCallback(asMETHOD(asCOutputBuffer, Callback), &outBuffer, asCALL_THISCALL); - - asCOutputBuffer finalOutput; - asCScriptFunction *initFunc = 0; - - asCSymbolTable initOrder; - - // We first try to compile all the primitive global variables, and only after that - // compile the non-primitive global variables. This permits the constructors - // for the complex types to use the already initialized variables of primitive - // type. Note, we currently don't know which global variables are used in the - // constructors, so we cannot guarantee that variables of complex types are - // initialized in the correct order, so we won't reorder those. - bool compilingPrimitives = true; - - // Compile each global variable - while( compileSucceeded ) - { - compileSucceeded = false; - - int accumErrors = 0; - int accumWarnings = 0; - - // Restore state of compilation - finalOutput.Clear(); - asCSymbolTable::iterator it = globVariables.List(); - for( ; it; it++ ) - { - sGlobalVariableDescription *gvar = *it; - if( gvar->isCompiled ) - continue; - - asCByteCode init(engine); - numWarnings = 0; - numErrors = 0; - outBuffer.Clear(); - - // Skip this for now if we're not compiling complex types yet - if( compilingPrimitives && !gvar->datatype.IsPrimitive() ) - continue; - - if( gvar->declaredAtNode ) - { - int r, c; - gvar->script->ConvertPosToRowCol(gvar->declaredAtNode->tokenPos, &r, &c); - asCString str = gvar->datatype.Format(); - str += " " + gvar->name; - str.Format(TXT_COMPILING_s, str.AddressOf()); - WriteInfo(gvar->script->name, str, r, c, true); - } - - if( gvar->isEnumValue ) - { - int r; - if( gvar->initializationNode ) - { - asCCompiler comp(engine); - asCScriptFunction func(engine, module, asFUNC_SCRIPT); - - // Set the namespace that should be used during the compilation - func.nameSpace = gvar->datatype.GetObjectType()->nameSpace; - - // Temporarily switch the type of the variable to int so it can be compiled properly - asCDataType saveType; - saveType = gvar->datatype; - gvar->datatype = asCDataType::CreatePrimitive(ttInt, true); - r = comp.CompileGlobalVariable(this, gvar->script, gvar->initializationNode, gvar, &func); - gvar->datatype = saveType; - - // Make the function a dummy so it doesn't try to release objects while destroying the function - func.funcType = asFUNC_DUMMY; - } - else - { - r = 0; - - // When there is no assignment the value is the last + 1 - int enumVal = 0; - asCSymbolTable::iterator prev_it = it; - prev_it--; - if( prev_it ) - { - sGlobalVariableDescription *gvar2 = *prev_it; - if(gvar2->datatype == gvar->datatype ) - { - // The integer value is stored in the lower bytes - enumVal = (*(int*)&gvar2->constantValue) + 1; - - if( !gvar2->isCompiled ) - { - int row, col; - gvar->script->ConvertPosToRowCol(gvar->declaredAtNode->tokenPos, &row, &col); - - asCString str = gvar->datatype.Format(); - str += " " + gvar->name; - str.Format(TXT_COMPILING_s, str.AddressOf()); - WriteInfo(gvar->script->name, str, row, col, true); - - str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, gvar2->name.AddressOf()); - WriteError(gvar->script->name, str, row, col); - r = -1; - } - } - } - - // The integer value is stored in the lower bytes - *(int*)&gvar->constantValue = enumVal; - } - - if( r >= 0 ) - { - // Set the value as compiled - gvar->isCompiled = true; - compileSucceeded = true; - } - } - else - { - // Compile the global variable - initFunc = asNEW(asCScriptFunction)(engine, module, asFUNC_SCRIPT); - if( initFunc == 0 ) - { - // Out of memory - return; - } - - // Set the namespace that should be used for this function - initFunc->nameSpace = gvar->ns; - - asCCompiler comp(engine); - int r = comp.CompileGlobalVariable(this, gvar->script, gvar->initializationNode, gvar, initFunc); - if( r >= 0 ) - { - // Compilation succeeded - gvar->isCompiled = true; - compileSucceeded = true; - } - else - { - // Compilation failed - initFunc->funcType = asFUNC_DUMMY; - asDELETE(initFunc, asCScriptFunction); - initFunc = 0; - } - } - - if( gvar->isCompiled ) - { - // Add warnings for this constant to the total build - if( numWarnings ) - { - currNumWarnings += numWarnings; - if( msgCallback ) - outBuffer.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj); - } - - // Determine order of variable initializations - if( gvar->property && !gvar->isEnumValue ) - initOrder.Put(gvar->property); - - // Does the function contain more than just a SUSPEND followed by a RET instruction? - if( initFunc && initFunc->scriptData->byteCode.GetLength() > 2 ) - { - // Create the init function for this variable - initFunc->id = engine->GetNextScriptFunctionId(); - engine->SetScriptFunction(initFunc); - - // Finalize the init function for this variable - initFunc->returnType = asCDataType::CreatePrimitive(ttVoid, false); - initFunc->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(gvar->script->name.AddressOf()); - if( gvar->declaredAtNode ) - { - int row, col; - gvar->script->ConvertPosToRowCol(gvar->declaredAtNode->tokenPos, &row, &col); - initFunc->scriptData->declaredAt = (row & 0xFFFFF)|((col & 0xFFF)<<20); - } - - gvar->property->SetInitFunc(initFunc); - - initFunc->Release(); - initFunc = 0; - } - else if( initFunc ) - { - // Destroy the function as it won't be used - initFunc->funcType = asFUNC_DUMMY; - asDELETE(initFunc, asCScriptFunction); - initFunc = 0; - } - - // 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); - - asSEnumValue *e = asNEW(asSEnumValue); - if( e == 0 ) - { - // Out of memory - numErrors++; - return; - } - - e->name = gvar->name; - e->value = *(int*)&gvar->constantValue; - - objectType->enumValues.PushLast(e); - } - } - else - { - // Add output to final output - finalOutput.Append(outBuffer); - accumErrors += numErrors; - accumWarnings += numWarnings; - } - - engine->preMessage.isSet = false; - } - - if( !compileSucceeded ) - { - if( compilingPrimitives ) - { - // No more primitives could be compiled, so - // switch to compiling the complex variables - compilingPrimitives = false; - compileSucceeded = true; - } - else - { - // No more variables can be compiled - // Add errors and warnings to total build - currNumWarnings += accumWarnings; - currNumErrors += accumErrors; - if( msgCallback ) - finalOutput.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj); - } - } - } - - // Restore states - engine->msgCallback = msgCallback; - engine->msgCallbackFunc = msgCallbackFunc; - engine->msgCallbackObj = msgCallbackObj; - - numWarnings = currNumWarnings; - numErrors = currNumErrors; - - // Set the correct order of initialization - if( numErrors == 0 ) - { - // If the length of the arrays are not the same, then this is the compilation - // of a single variable, in which case the initialization order of the previous - // variables must be preserved. - if( module->scriptGlobals.GetSize() == initOrder.GetSize() ) - module->scriptGlobals.SwapWith(initOrder); - } - - // Delete the enum expressions - asCSymbolTableIterator it = globVariables.List(); - while( it ) - { - sGlobalVariableDescription *gvar = *it; - if( gvar->isEnumValue ) - { - // Remove from symboltable. This has to be done prior to freeing the memeory - globVariables.Erase(it.GetIndex()); - - // Destroy the gvar property - if( gvar->declaredAtNode ) - { - gvar->declaredAtNode->Destroy(engine); - gvar->declaredAtNode = 0; - } - if( gvar->initializationNode ) - { - gvar->initializationNode->Destroy(engine); - gvar->initializationNode = 0; - } - if( gvar->property ) - { - asDELETE(gvar->property, asCGlobalProperty); - gvar->property = 0; - } - - asDELETE(gvar, sGlobalVariableDescription); - } - else - it++; - } -} - -int asCBuilder::GetNamespaceAndNameFromNode(asCScriptNode *n, asCScriptCode *script, asSNameSpace *implicitNs, asSNameSpace *&outNs, asCString &outName) -{ - asASSERT( n->nodeType == snIdentifier ); - - // Get the optional scope from the node - asSNameSpace *ns = GetNameSpaceFromNode(n->firstChild, script, implicitNs, 0); - if( ns == 0 ) - return -1; - - // Get the name - asCString name(&script->code[n->lastChild->tokenPos], n->lastChild->tokenLength); - - outNs = ns; - outName = name; - - return 0; -} - -void asCBuilder::AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScriptNode *errNode, sMixinClass *mixin) -{ - // Determine what interfaces that the mixin implements - asCScriptNode *node = mixin->node; - asASSERT(node->nodeType == snClass); - - // Skip the name of the mixin - node = node->firstChild->next; - - - while( node && node->nodeType == snIdentifier ) - { - bool ok = true; - asSNameSpace *ns; - asCString name; - if( GetNamespaceAndNameFromNode(node, mixin->script, mixin->ns, ns, name) < 0 ) - ok = false; - else - { - // Find the object type for the interface - asCObjectType *objType = GetObjectType(name.AddressOf(), ns); - - // Check that the object type is an interface - if( objType && objType->IsInterface() ) - { - // Only add the interface if the class doesn't already implement it - if( !decl->objType->Implements(objType) ) - AddInterfaceToClass(decl, errNode, objType); - } - else - { - WriteError(TXT_MIXIN_CLASS_CANNOT_INHERIT, mixin->script, node); - ok = false; - } - } - - if( !ok ) - { - // Remove this node so the error isn't reported again - asCScriptNode *delNode = node; - node = node->prev; - delNode->DisconnectParent(); - delNode->Destroy(engine); - } - - node = node->next; - } -} - -void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *errNode, asCObjectType *intfType) -{ - // A shared type may only implement from shared interfaces - if( decl->objType->IsShared() && !intfType->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, intfType->name.AddressOf()); - WriteError(msg, decl->script, errNode); - return; - } - - if( decl->isExistingShared ) - { - // 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) ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName()); - WriteError(str, decl->script, errNode); - return; - } - } - else - { - // If the interface is already in the class then don't add it again - if( decl->objType->Implements(intfType) ) - return; - - // Add the interface to the class - decl->objType->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() ) - { - for( asUINT n = 0; n < intfType->interfaces.GetLength(); n++ ) - AddInterfaceToClass(decl, errNode, intfType->interfaces[n]); - } - } -} - -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 = 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; - - 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) ) - { - interfaceDeclarations.RemoveIndex(n); - interfaceDeclarations.PushLast(intfDecl); - - // Decrease index so that we don't skip an entry - n--; - break; - } - } - } - - // Now recursively add the additional inherited interfaces - for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) - { - sClassDeclaration *intfDecl = interfaceDeclarations[n]; - asCObjectType *intfType = intfDecl->objType; - - // TODO: 2.28.1: 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 - // index the function should have in the table chunk for this interface. - for( asUINT d = 0; d < intfType->methods.GetLength(); d++ ) - { - asCScriptFunction *func = GetFunctionDescription(intfType->methods[d]); - func->vfTableIdx = d; - - asASSERT(func->objectType == intfType); - } - - // As new interfaces will be added to the end of the list, all - // interfaces will be traversed the same as recursively - for( asUINT m = 0; m < intfType->interfaces.GetLength(); m++ ) - { - asCObjectType *base = intfType->interfaces[m]; - - // Add any interfaces not already implemented - for( asUINT l = 0; l < base->interfaces.GetLength(); l++ ) - AddInterfaceToClass(intfDecl, intfDecl->node, base->interfaces[l]); - - // Add the methods from the implemented interface - for( asUINT m = 0; m < base->methods.GetLength(); m++ ) - { - // If the derived interface implements the same method, then don't add the base interface' method - asCScriptFunction *baseFunc = GetFunctionDescription(base->methods[m]); - asCScriptFunction *derivedFunc = 0; - bool found = false; - for( asUINT d = 0; d < intfType->methods.GetLength(); d++ ) - { - derivedFunc = GetFunctionDescription(intfType->methods[d]); - if( derivedFunc->IsSignatureEqual(baseFunc) ) - { - found = true; - break; - } - } - - if( !found ) - { - // Add the method - intfType->methods.PushLast(baseFunc->id); - baseFunc->AddRef(); - } - } - } - } -} - -void asCBuilder::CompileClasses() -{ - asUINT n; - asCArray toValidate((int)classDeclarations.GetLength()); - - // Determine class inheritances and interfaces - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - sClassDeclaration *decl = classDeclarations[n]; - asCScriptCode *file = decl->script; - - // Find the base class that this class inherits from - 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) ) - { - node = node->next; - } - - // Skip the name of the class - asASSERT(node->tokenType == ttIdentifier); - node = node->next; - - while( node && node->nodeType == snIdentifier ) - { - asSNameSpace *ns; - asCString name; - if( GetNamespaceAndNameFromNode(node, file, decl->objType->nameSpace, ns, name) < 0 ) - { - node = node->next; - continue; - } - - // Find the object type for the interface - asCObjectType *objType = 0; - sMixinClass *mixin = 0; - asSNameSpace *origNs = ns; - while( ns ) - { - objType = GetObjectType(name.AddressOf(), ns); - if( objType == 0 ) - mixin = GetMixinClass(name.AddressOf(), ns); - - if( objType || mixin ) - break; - - ns = GetParentNameSpace(ns); - } - - if( objType == 0 && mixin == 0 ) - { - asCString str; - 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 ) - { - AddInterfaceFromMixinToClass(decl, node, mixin); - } - 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' - asCString str; - str.Format(TXT_CANNOT_INHERIT_FROM_s_FINAL, objType->name.AddressOf()); - WriteError(str, file, node); - } - else if( objType->size != 0 ) - { - // The class inherits from another script class - if( !decl->isExistingShared && decl->objType->derivedFrom != 0 ) - { - if( !multipleInheritance ) - { - WriteError(TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES, file, node); - multipleInheritance = true; - } - } - else - { - // Make sure none of the base classes inherit from this one - asCObjectType *base = objType; - bool error = false; - while( base != 0 ) - { - if( base == decl->objType ) - { - WriteError(TXT_CANNOT_INHERIT_FROM_SELF, file, node); - error = true; - break; - } - - base = base->derivedFrom; - } - - if( !error ) - { - // A shared type may only inherit from other shared types - if( (decl->objType->IsShared()) && !(objType->IsShared()) ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_INHERIT_FROM_NON_SHARED_s, objType->name.AddressOf()); - WriteError(msg, file, node); - error = true; - } - } - - if( !error ) - { - if( decl->isExistingShared ) - { - // Verify that the base class is the same as the original shared type - if( decl->objType->derivedFrom != objType ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName()); - WriteError(str, file, node); - } - } - else - { - // Set the base class - decl->objType->derivedFrom = objType; - objType->AddRef(); - } - } - } - } - else - { - // The class implements an interface - AddInterfaceToClass(decl, node, objType); - } - - node = node->next; - } - } - - // 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 *base = derived->derivedFrom; - - if( base == 0 ) continue; - - // If the base class is found after the derived class, then move the derived class to the end of the list - for( asUINT m = n+1; m < classDeclarations.GetLength(); m++ ) - { - sClassDeclaration *declBase = classDeclarations[m]; - if( base == declBase->objType ) - { - classDeclarations.RemoveIndex(n); - classDeclarations.PushLast(decl); - - // Decrease index so that we don't skip an entry - n--; - break; - } - } - } - - // Go through each of the classes and register the object type descriptions - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - sClassDeclaration *decl = classDeclarations[n]; - if( decl->isExistingShared ) - { - // Set the declaration as validated already, so that other - // types that contain this will accept this type - decl->validState = 1; - - // We'll still validate the declaration to make sure nothing new is - // added to the shared class that wasn't there in the previous - // 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() ); - } - - // 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 ) - { - asCObjectType *baseType = decl->objType->derivedFrom; - - // The derived class inherits all interfaces from the base class - for( unsigned int n = 0; n < baseType->interfaces.GetLength(); n++ ) - { - if( !decl->objType->Implements(baseType->interfaces[n]) ) - decl->objType->interfaces.PushLast(baseType->interfaces[n]); - } - - // TODO: Need to check for name conflict with new class methods - - // Copy properties from base class to derived class - for( asUINT p = 0; p < baseType->properties.GetLength(); p++ ) - { - asCObjectProperty *prop = AddPropertyToClass(decl, baseType->properties[p]->name, baseType->properties[p]->type, baseType->properties[p]->isPrivate); - - // The properties must maintain the same offset - asASSERT(prop && prop->byteOffset == baseType->properties[p]->byteOffset); UNUSED_VAR(prop); - } - - // Copy methods from base class to derived class - for( asUINT m = 0; m < baseType->methods.GetLength(); m++ ) - { - // If the derived class implements the same method, then don't add the base class' method - asCScriptFunction *baseFunc = GetFunctionDescription(baseType->methods[m]); - asCScriptFunction *derivedFunc = 0; - bool found = false; - for( asUINT d = 0; d < decl->objType->methods.GetLength(); d++ ) - { - derivedFunc = GetFunctionDescription(decl->objType->methods[d]); - if( baseFunc->name == "opConv" || baseFunc->name == "opImplConv" ) - { - // For the opConv and opImplConv methods, the return type can differ if they are different methods - if( derivedFunc->name == baseFunc->name && - derivedFunc->IsSignatureExceptNameEqual(baseFunc) ) - { - if( baseFunc->IsFinal() ) - { - asCString msg; - msg.Format(TXT_METHOD_CANNOT_OVERRIDE_s, baseFunc->GetDeclaration()); - WriteError(msg, decl->script, decl->node); - } - - // Move the function from the methods array to the virtualFunctionTable - decl->objType->methods.RemoveIndex(d); - decl->objType->virtualFunctionTable.PushLast(derivedFunc); - found = true; - break; - } - } - else - { - if( derivedFunc->name == baseFunc->name && - derivedFunc->IsSignatureExceptNameAndReturnTypeEqual(baseFunc) ) - { - if( baseFunc->returnType != derivedFunc->returnType ) - { - asCString msg; - msg.Format(TXT_DERIVED_METHOD_MUST_HAVE_SAME_RETTYPE_s, baseFunc->GetDeclaration()); - WriteError(msg, decl->script, decl->node); - } - - if( baseFunc->IsFinal() ) - { - asCString msg; - msg.Format(TXT_METHOD_CANNOT_OVERRIDE_s, baseFunc->GetDeclaration()); - WriteError(msg, decl->script, decl->node); - } - - // Move the function from the methods array to the virtualFunctionTable - decl->objType->methods.RemoveIndex(d); - decl->objType->virtualFunctionTable.PushLast(derivedFunc); - found = true; - break; - } - } - } - - if( !found ) - { - // Push the base class function on the virtual function table - decl->objType->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]); - baseType->virtualFunctionTable[m]->AddRef(); - - CheckForConflictsDueToDefaultArgs(decl->script, decl->node, baseType->virtualFunctionTable[m], decl->objType); - } - - decl->objType->methods.PushLast(baseType->methods[m]); - engine->scriptFunctions[baseType->methods[m]]->AddRef(); - } - } - - if( !decl->isExistingShared ) - { - // Move this class' methods into the virtual function table - for( asUINT m = 0; m < decl->objType->methods.GetLength(); m++ ) - { - asCScriptFunction *func = GetFunctionDescription(decl->objType->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); - - // 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)); - m--; - } - } - - // Make virtual function table chunks for each implemented interface - for( asUINT n = 0; n < decl->objType->interfaces.GetLength(); n++ ) - { - asCObjectType *intf = decl->objType->interfaces[n]; - - // Add all the interface's functions to the virtual function table - asUINT offset = asUINT(decl->objType->virtualFunctionTable.GetLength()); - decl->objType->interfaceVFTOffsets.PushLast(offset); - - for( asUINT j = 0; j < intf->methods.GetLength(); j++ ) - { - asCScriptFunction *intfFunc = GetFunctionDescription(intf->methods[j]); - - // Only create the table for functions that are explicitly from this interface, - // inherited interface methods will be put in that interface's table. - if( intfFunc->objectType != intf ) - continue; - - asASSERT((asUINT)intfFunc->vfTableIdx == j); - - //Find the interface function in the list of methods - asCScriptFunction *realFunc = 0; - for( asUINT p = 0; p < decl->objType->methods.GetLength(); p++ ) - { - asCScriptFunction *func = GetFunctionDescription(decl->objType->methods[p]); - - if( func->signatureId == intfFunc->signatureId ) - { - if( func->funcType == asFUNC_VIRTUAL ) - { - realFunc = decl->objType->virtualFunctionTable[func->vfTableIdx]; - } - else - { - // This should not happen, all methods were moved into the virtual table - asASSERT(false); - } - break; - } - } - - // If realFunc is still null, the interface was not - // implemented and we error out later in the checks. - decl->objType->virtualFunctionTable.PushLast(realFunc); - if( realFunc ) - realFunc->AddRef(); - } - } - } - - // Enumerate each of the declared properties - asCScriptNode *node = decl->node->firstChild->next; - - // Skip list of classes and interfaces - while( node && node->nodeType == snIdentifier ) - node = node->next; - - while( node ) - { - if( node->nodeType == snDeclaration ) - { - asCScriptNode *n = node->firstChild; - - // Is the property declared as private? - bool isPrivate = false; - if( n && n->tokenType == ttPrivate ) - { - isPrivate = 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, 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->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; - } - } - else - asASSERT(false); - - node = node->next; - } - - // Add properties from included mixin classes that don't conflict with existing properties - IncludePropertiesFromMixins(decl); - - if( !decl->isExistingShared ) - toValidate.PushLast(decl); - - asASSERT( decl->objType->interfaces.GetLength() == decl->objType->interfaceVFTOffsets.GetLength() ); - } - - // TODO: Warn if a method overrides a base method without marking it as 'override'. - // It must be possible to turn off this warning through engine property. - - // TODO: A base class should be able to mark a method as 'abstract'. This will - // allow a base class to provide a partial implementation, but still force - // derived classes to implement specific methods. - - // Verify that all interface methods are implemented in the classes - // We do this here so the base class' methods have already been inherited - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - 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() ); - - for( asUINT m = 0; m < decl->objType->interfaces.GetLength(); m++ ) - { - asCObjectType *objType = decl->objType->interfaces[m]; - for( asUINT i = 0; i < objType->methods.GetLength(); i++ ) - { - // Only check the interface methods that was explicitly declared in this interface - // Methods that was inherited from other interfaces will be checked in those interfaces - if( objType != engine->scriptFunctions[objType->methods[i]]->objectType ) - continue; - - asUINT overrideIndex; - if( !DoesMethodExist(decl->objType, objType->methods[i], &overrideIndex) ) - { - asCString str; - str.Format(TXT_MISSING_IMPLEMENTATION_OF_s, - engine->GetFunctionDeclaration(objType->methods[i]).AddressOf()); - WriteError(str, decl->script, decl->node); - } - else - overrideValidations[overrideIndex] = true; - } - } - - bool hasBaseClass = decl->objType->derivedFrom != 0; - - for( asUINT j = 0; j < overrideValidations.GetLength(); j++ ) - { - if( !overrideValidations[j] && (!hasBaseClass || !DoesMethodExist(decl->objType->derivedFrom, decl->objType->methods[j])) ) - { - asCString msg; - msg.Format(TXT_METHOD_s_DOES_NOT_OVERRIDE, decl->objType->GetMethodByIndex(j, false)->GetDeclaration()); - WriteError(msg, decl->script, decl->node); - } - } - } - - // Verify that the declared structures are valid, e.g. that the structure - // doesn't contain a member of its own type directly or indirectly - while( toValidate.GetLength() > 0 ) - { - asUINT numClasses = (asUINT)toValidate.GetLength(); - - asCArray toValidateNext((int)toValidate.GetLength()); - while( toValidate.GetLength() > 0 ) - { - sClassDeclaration *decl = toValidate[toValidate.GetLength()-1]; - int validState = 1; - for( asUINT n = 0; n < decl->objType->properties.GetLength(); n++ ) - { - // A valid structure is one that uses only primitives or other valid objects - asCObjectProperty *prop = decl->objType->properties[n]; - asCDataType dt = prop->type; - - if( dt.IsTemplate() ) - { - asCDataType sub = dt; - while( sub.IsTemplate() && !sub.IsObjectHandle() ) - sub = sub.GetSubType(); - - dt = sub; - } - - if( dt.IsObject() && !dt.IsObjectHandle() ) - { - // Find the class declaration - sClassDeclaration *pdecl = 0; - for( asUINT p = 0; p < classDeclarations.GetLength(); p++ ) - { - if( classDeclarations[p]->objType == dt.GetObjectType() ) - { - pdecl = classDeclarations[p]; - break; - } - } - - if( pdecl ) - { - if( pdecl->objType == decl->objType ) - { - WriteError(TXT_ILLEGAL_MEMBER_TYPE, decl->script, decl->node); - validState = 2; - break; - } - else if( pdecl->validState != 1 ) - { - validState = pdecl->validState; - break; - } - } - } - } - - if( validState == 1 ) - { - decl->validState = 1; - toValidate.PopLast(); - } - else if( validState == 2 ) - { - decl->validState = 2; - toValidate.PopLast(); - } - else - { - toValidateNext.PushLast(toValidate.PopLast()); - } - } - - toValidate = toValidateNext; - toValidateNext.SetLength(0); - - if( numClasses == toValidate.GetLength() ) - { - WriteError(TXT_ILLEGAL_MEMBER_TYPE, toValidate[0]->script, toValidate[0]->node); - break; - } - } - - if( numErrors > 0 ) return; - - // Verify which script classes can really form circular references, and mark only those as garbage collected. - - // TODO: runtime optimize: This algorithm can be further improved by checking the types that inherits from - // a base class. If the base class is not shared all the classes that derive from it - // are known at compile time, and can thus be checked for potential circular references too. - // - // Observe, that doing this would conflict with another potential future feature, which is to - // allow incremental builds, i.e. allow application to add or replace classes in an - // existing module. However, the applications that want to use that should use a special - // build flag to not finalize the module. - - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - sClassDeclaration *decl = classDeclarations[n]; - - // Existing shared classes won't be re-evaluated - if( decl->isExistingShared ) continue; - - asCObjectType *ot = decl->objType; - - // Is there some path in which this structure is involved in circular references? - bool gc = false; - for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) - { - asCDataType dt = ot->properties[p]->type; - if( !dt.IsObject() ) - continue; - - if( dt.IsObjectHandle() ) - { - // 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(); - - if( prop->flags & asOBJ_SCRIPT_OBJECT ) - { - // For script objects, treat non-final classes as if they can contain references - // as it is not known what derived classes might do. For final types, check all - // properties to determine if any of those can cause a circular reference. - if( prop->flags & asOBJ_NOINHERIT ) - { - for( asUINT sp = 0; sp < prop->properties.GetLength(); sp++ ) - { - asCDataType sdt = prop->properties[sp]->type; - - if( sdt.IsObject() ) - { - 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) ) - { - gc = true; - break; - } - } - else if( sdt.GetObjectType()->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 - gc = true; - break; - } - } - } - - if( gc ) - break; - } - else - { - // Assume it is garbage collected as it is not known at compile time what might inherit from this type - gc = true; - break; - } - } - else if( prop->flags & asOBJ_GC ) - { - // If a type is not a script object, adopt its GC flag - gc = true; - break; - } - } - else if( dt.GetObjectType()->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 - gc = true; - break; - } - } - - // Update the flag in the object type - if( gc ) - ot->flags |= asOBJ_GC; - else - ot->flags &= ~asOBJ_GC; - } -} - -void asCBuilder::IncludeMethodsFromMixins(sClassDeclaration *decl) -{ - asCScriptNode *node = decl->node->firstChild; - - // Skip the class attributes - while( node->nodeType == snIdentifier && - !decl->script->TokenEquals(node->tokenPos, node->tokenLength, decl->name.AddressOf()) ) - node = node->next; - - // Skip the name of the class - node = node->next; - - // Find the included mixin classes - while( node && node->nodeType == snIdentifier ) - { - asSNameSpace *ns; - asCString name; - if( GetNamespaceAndNameFromNode(node, decl->script, decl->objType->nameSpace, ns, name) < 0 ) - { - node = node->next; - continue; - } - - sMixinClass *mixin = 0; - while( ns ) - { - // 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; - - ns = GetParentNameSpace(ns); - } - - if( mixin ) - { - // Find methods from mixin declaration - asCScriptNode *n = mixin->node->firstChild; - - // Skip to the member declarations - // Possible keywords 'final' and 'shared' are removed in RegisterMixinClass so we don't need to worry about those here - while( n && n->nodeType == snIdentifier ) - n = n->next; - - // Add methods from the mixin that are not already existing in the class - while( n ) - { - if( n->nodeType == snFunction ) - { - // Instead of disconnecting the node, we need to clone it, otherwise other - // classes that include the same mixin will not see the methods - 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, 0, false, true); - } - else if( n->nodeType == snVirtualProperty ) - { - // TODO: mixin: Support virtual properties too - WriteError("The virtual property syntax is currently not supported for mixin classes", mixin->script, n); - //RegisterVirtualProperty(node, decl->script, decl->objType, false, false); - } - - n = n->next; - } - } - - node = node->next; - } -} - -void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) -{ - asCScriptNode *node = decl->node->firstChild; - - // Skip the class attributes - while( node->nodeType == snIdentifier && - !decl->script->TokenEquals(node->tokenPos, node->tokenLength, decl->name.AddressOf()) ) - node = node->next; - - // Skip the name of the class - node = node->next; - - // Find the included mixin classes - while( node && node->nodeType == snIdentifier ) - { - asSNameSpace *ns; - asCString name; - if( GetNamespaceAndNameFromNode(node, decl->script, decl->objType->nameSpace, ns, name) < 0 ) - { - node = node->next; - continue; - } - - sMixinClass *mixin = 0; - while( ns ) - { - // 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; - - ns = GetParentNameSpace(ns); - } - - if( mixin ) - { - // Find properties from mixin declaration - asCScriptNode *n = mixin->node->firstChild; - - // Skip to the member declarations - // Possible keywords 'final' and 'shared' are removed in RegisterMixinClass so we don't need to worry about those here - while( n && n->nodeType == snIdentifier ) - n = n->next; - - // Add properties from the mixin that are not already existing in the class - while( n ) - { - if( n->nodeType == snDeclaration ) - { - asCScriptNode *n2 = n->firstChild; - bool isPrivate = false; - if( n2 && n2->tokenType == ttPrivate ) - { - isPrivate = true; - n2 = n2->next; - } - - asCScriptCode *file = mixin->script; - asCDataType dt = CreateDataTypeFromNode(n2, file, mixin->ns); - - 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, n); - WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); - } - - if( dt.IsReadOnly() ) - WriteError(TXT_PROPERTY_CANT_BE_CONST, file, n); - - n2 = n2->next; - while( n2 ) - { - asCString name(&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 ) - { - exists = true; - break; - } - - if( !exists ) - { - if( !decl->isExistingShared ) - { - // It must not conflict with the name of methods - int r = CheckNameConflictMember(decl->objType, name.AddressOf(), n2, file, true); - if( r < 0 ) - WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); - - AddPropertyToClass(decl, name, dt, isPrivate, file, n2); - } - 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->name == name && - prop->type == dt ) - { - found = true; - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->objType->GetName()); - WriteError(str, decl->script, decl->node); - WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); - } - } - } - - // Skip the initialization expression - if( n2->next && n2->next->nodeType != snIdentifier ) - n2 = n2->next; - - n2 = n2->next; - } - } - - n = n->next; - } - } - - node = node->next; - } -} - -int asCBuilder::CreateVirtualFunction(asCScriptFunction *func, int idx) -{ - asCScriptFunction *vf = asNEW(asCScriptFunction)(engine, module, asFUNC_VIRTUAL); - if( vf == 0 ) - return asOUT_OF_MEMORY; - - vf->name = func->name; - vf->returnType = func->returnType; - vf->parameterTypes = func->parameterTypes; - vf->inOutFlags = func->inOutFlags; - vf->id = engine->GetNextScriptFunctionId(); - vf->isReadOnly = func->isReadOnly; - vf->objectType = func->objectType; - vf->signatureId = func->signatureId; - vf->isPrivate = func->isPrivate; - vf->isFinal = func->isFinal; - vf->isOverride = func->isOverride; - vf->vfTableIdx = idx; - - // It is not necessary to copy the default args, as they have no meaning in the virtual function - - module->AddScriptFunction(vf); - - // Add a dummy to the builder so that it doesn't mix up function ids - functions.PushLast(0); - - return vf->id; -} - -asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const asCString &name, const asCDataType &dt, bool isPrivate, asCScriptCode *file, asCScriptNode *node) -{ - // If the declaration node is not given, then - // this property is inherited from a base class - if( node ) - { - // Check if the property is allowed - if( !dt.CanBeInstantiated() ) - { - if( file && node ) - { - asCString str; - if( dt.IsAbstractClass() ) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format().AddressOf()); - else if( dt.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format().AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf()); - WriteError(str, file, node); - } - return 0; - } - - // Register the initialization expression (if any) to be compiled later - asCScriptNode *declNode = node; - asCScriptNode *initNode = 0; - if( node->next && node->next->nodeType != snIdentifier ) - { - asASSERT( node->next->nodeType == snAssignment ); - initNode = node->next; - } - - sPropertyInitializer p(name, declNode, initNode, file); - decl->propInits.PushLast(p); - } - - // Add the property to the object type - return decl->objType->AddPropertyToClass(name, dt, isPrivate); -} - -bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex) -{ - asCScriptFunction *method = GetFunctionDescription(methodId); - - for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) - { - asCScriptFunction *m = GetFunctionDescription(objType->methods[n]); - - if( m->name != method->name ) continue; - if( m->returnType != method->returnType ) continue; - if( m->isReadOnly != method->isReadOnly ) continue; - if( m->parameterTypes != method->parameterTypes ) continue; - if( m->inOutFlags != method->inOutFlags ) continue; - - if( methodIndex ) - *methodIndex = n; - - return true; - } - - return false; -} - -void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file) -{ - int funcId = engine->GetNextScriptFunctionId(); - - asCDataType returnType = asCDataType::CreatePrimitive(ttVoid, false); - asCArray parameterTypes; - asCArray inOutFlags; - asCArray defaultArgs; - asCArray parameterNames; - - // 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); - - // Set it as default constructor - if( objType->beh.construct ) - engine->scriptFunctions[objType->beh.construct]->Release(); - objType->beh.construct = funcId; - objType->beh.constructors[0] = funcId; - engine->scriptFunctions[funcId]->AddRef(); - - // The bytecode for the default constructor will be generated - // only after the potential inheritance has been established - sFunctionDescription *func = asNEW(sFunctionDescription); - if( func == 0 ) - { - // Out of memory - return; - } - - functions.PushLast(func); - - func->script = file; - func->node = 0; - func->name = objType->name; - func->objType = objType; - func->funcId = funcId; - func->isExistingShared = false; - - // Add a default factory as well - funcId = engine->GetNextScriptFunctionId(); - if( objType->beh.factory ) - engine->scriptFunctions[objType->beh.factory]->Release(); - objType->beh.factory = funcId; - objType->beh.factories[0] = funcId; - returnType = asCDataType::CreateObjectHandle(objType, false); - // TODO: should be the same as the constructor - module->AddScriptFunction(file->idx, 0, funcId, objType->name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, false); - functions.PushLast(0); - asCCompiler compiler(engine); - compiler.CompileFactory(this, file, engine->scriptFunctions[funcId]); - engine->scriptFunctions[funcId]->AddRef(); - - // If the object is shared, then the factory must also be marked as shared - if( objType->flags & asOBJ_SHARED ) - engine->scriptFunctions[funcId]->isShared = true; -} - -int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) -{ - // Is it a shared enum? - bool isShared = false; - asCObjectType *existingSharedType = 0; - asCScriptNode *tmp = node->firstChild; - if( tmp->nodeType == snIdentifier && file->TokenEquals(tmp->tokenPos, tmp->tokenLength, SHARED_TOKEN) ) - { - isShared = true; - tmp = tmp->next; - } - - // Grab the name of the enumeration - asCString name; - asASSERT(snDataType == tmp->nodeType); - asASSERT(snIdentifier == tmp->firstChild->nodeType); - name.Assign(&file->code[tmp->firstChild->tokenPos], tmp->firstChild->tokenLength); - - if( isShared ) - { - // Look for a pre-existing shared enum with the same signature - for( asUINT n = 0; n < engine->scriptTypes.GetLength(); n++ ) - { - asCObjectType *o = engine->scriptTypes[n]; - if( o && - o->IsShared() && - (o->flags & asOBJ_ENUM) && - o->name == name && - o->nameSpace == ns ) - { - existingSharedType = o; - break; - } - } - } - - // Check the name and add the enum - int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file, ns); - if( asSUCCESS == r ) - { - asCObjectType *st; - - if( existingSharedType ) - st = existingSharedType; - else - { - st = asNEW(asCObjectType)(engine); - if( st == 0 ) - return asOUT_OF_MEMORY; - - st->flags = asOBJ_ENUM; - if( isShared ) - st->flags |= asOBJ_SHARED; - st->size = 4; - st->name = name; - st->nameSpace = ns; - st->module = module; - } - module->enumTypes.PushLast(st); - st->AddRef(); - - // TODO: cleanup: Should the enum type really be stored in the engine->classTypes? - // http://www.gamedev.net/topic/616912-c-header-file-shared-with-scripts/page__gopid__4895940 - if( !existingSharedType ) - engine->scriptTypes.PushLast(st); - - // Store the location of this declaration for reference in name collisions - sClassDeclaration *decl = asNEW(sClassDeclaration); - if( decl == 0 ) - return asOUT_OF_MEMORY; - - decl->name = name; - decl->script = file; - decl->objType = st; - namedTypeDeclarations.PushLast(decl); - - asCDataType type = CreateDataTypeFromNode(tmp, file, ns); - asASSERT(!type.IsReference()); - - // Register the enum values - tmp = tmp->next; - while( tmp ) - { - asASSERT(snIdentifier == tmp->nodeType); - - asCString name(&file->code[tmp->tokenPos], tmp->tokenLength); - - if( existingSharedType ) - { - // If this is a pre-existent shared enum, then just double check - // that the value is already defined in the original declaration - bool found = false; - for( size_t n = 0; n < st->enumValues.GetLength(); n++ ) - if( st->enumValues[n]->name == name ) - { - found = true; - break; - } - - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, st->GetName()); - WriteError(str, file, tmp); - break; - } - - tmp = tmp->next; - if( tmp && tmp->nodeType == snAssignment ) - tmp = tmp->next; - continue; - } - else - { - // Check for name conflict errors with other values in the enum - if( globVariables.GetFirst(ns, name, asCCompGlobVarType(type)) ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_ALREADY_USED, name.AddressOf()); - WriteError(str, file, tmp); - - tmp = tmp->next; - if( tmp && tmp->nodeType == snAssignment ) - tmp = tmp->next; - continue; - } - - // Check for assignment - asCScriptNode *asnNode = tmp->next; - if( asnNode && snAssignment == asnNode->nodeType ) - asnNode->DisconnectParent(); - else - asnNode = 0; - - // Create the global variable description so the enum value can be evaluated - sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription); - if( gvar == 0 ) - return asOUT_OF_MEMORY; - - gvar->script = file; - gvar->declaredAtNode = tmp; - tmp = tmp->next; - gvar->declaredAtNode->DisconnectParent(); - gvar->initializationNode = asnNode; - gvar->name = name; - gvar->datatype = type; - 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->isCompiled = false; - gvar->isPureConstant = true; - gvar->isEnumValue = true; - gvar->constantValue = 0xdeadbeef; - - // Allocate dummy property so we can compile the value. - // This will be removed later on so we don't add it to the engine. - gvar->property = asNEW(asCGlobalProperty); - if( gvar->property == 0 ) - return asOUT_OF_MEMORY; - - gvar->property->name = name; - gvar->property->nameSpace = ns; - gvar->property->type = gvar->datatype; - gvar->property->id = 0; - - globVariables.Put(gvar); - } - } - } - - node->Destroy(engine); - - return r; -} - -int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) -{ - // Get the native data type - asCScriptNode *tmp = node->firstChild; - asASSERT(NULL != tmp && snDataType == tmp->nodeType); - asCDataType dataType; - dataType.CreatePrimitive(tmp->tokenType, false); - dataType.SetTokenType(tmp->tokenType); - tmp = tmp->next; - - // Grab the name of the typedef - asASSERT(NULL != tmp && NULL == tmp->next); - asCString name; - name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength); - - // If the name is not already in use add it - int r = CheckNameConflict(name.AddressOf(), tmp, file, ns); - - asCObjectType *st = 0; - if( asSUCCESS == r ) - { - // Create the new type - st = asNEW(asCObjectType)(engine); - if( st == 0 ) - r = asOUT_OF_MEMORY; - } - - if( asSUCCESS == r ) - { - st->flags = asOBJ_TYPEDEF; - st->size = dataType.GetSizeInMemoryBytes(); - st->name = name; - st->nameSpace = ns; - st->templateSubTypes.PushLast(dataType); - st->module = module; - - st->AddRef(); - - module->typeDefs.PushLast(st); - engine->scriptTypes.PushLast(st); - - // Store the location of this declaration for reference in name collisions - sClassDeclaration *decl = asNEW(sClassDeclaration); - if( decl == 0 ) - r = asOUT_OF_MEMORY; - else - { - decl->name = name; - decl->script = file; - decl->objType = st; - namedTypeDeclarations.PushLast(decl); - } - } - - node->Destroy(engine); - - 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 &isOverride, bool &isFinal, bool &isShared, asSNameSpace *implicitNamespace) -{ - node = node->firstChild; - - // Is the function a private class method? - isPrivate = false; - if( node->tokenType == ttPrivate ) - { - isPrivate = true; - node = node->next; - } - - // Is the function shared? - isShared = false; - if( node->tokenType == ttIdentifier && file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) ) - { - isShared = true; - node = node->next; - } - - // Find the name - isConstructor = false; - isDestructor = false; - asCScriptNode *n = 0; - if( node->nodeType == snDataType ) - n = node->next->next; - else - { - // If the first node is a ~ token, then we know it is a destructor - if( node->tokenType == ttBitNot ) - { - n = node->next; - isDestructor = true; - } - else - { - n = node; - isConstructor = true; - } - } - name.Assign(&file->code[n->tokenPos], n->tokenLength); - - // Initialize a script function object for registration - if( !isConstructor && !isDestructor ) - { - returnType = CreateDataTypeFromNode(node, file, implicitNamespace); - 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.IsObjectHandle() ) - { - WriteError(TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL, file, node); - } - } - else - returnType = asCDataType::CreatePrimitive(ttVoid, false); - - isConstMethod = false; - isFinal = false; - isOverride = false; - - if( objType && n->next->next ) - { - asCScriptNode *decorator = n->next->next; - - // Is this a const method? - if( decorator->tokenType == ttConst ) - { - isConstMethod = true; - decorator = decorator->next; - } - - while( decorator ) - { - if( decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, FINAL_TOKEN) ) - isFinal = true; - else if( decorator->tokenType == ttIdentifier && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, OVERRIDE_TOKEN) ) - isOverride = true; - - decorator = decorator->next; - } - } - - // Count the number of parameters - int count = 0; - asCScriptNode *c = n->next->firstChild; - while( c ) - { - count++; - c = c->next->next; - if( c && c->nodeType == snIdentifier ) - c = c->next; - if( c && c->nodeType == snExpression ) - c = c->next; - } - - // Get the parameter types - parameterNames.Allocate(count, false); - parameterTypes.Allocate(count, false); - inOutFlags.Allocate(count, false); - defaultArgs.Allocate(count, false); - n = n->next->firstChild; - while( n ) - { - asETypeModifiers inOutFlag; - asCDataType type = CreateDataTypeFromNode(n, file, implicitNamespace); - 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.IsObjectHandle() ) - { - WriteError(TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL, file, node); - } - - // Store the parameter type - parameterTypes.PushLast(type); - inOutFlags.PushLast(inOutFlag); - - // Move to next parameter - n = n->next->next; - if( n && n->nodeType == snIdentifier ) - { - asCString name; - name.Assign(&file->code[n->tokenPos], n->tokenLength); - parameterNames.PushLast(name); - n = n->next; - } - else - { - // No name was given for the parameter - parameterNames.PushLast(asCString()); - } - - if( n && n->nodeType == snExpression ) - { - // Strip out white space and comments to better share the string - asCString *defaultArgStr = asNEW(asCString); - if( defaultArgStr ) - *defaultArgStr = GetCleanExpressionString(n, file); - defaultArgs.PushLast(defaultArgStr); - - n = n->next; - } - else - defaultArgs.PushLast(0); - } -} -#endif - -asCString asCBuilder::GetCleanExpressionString(asCScriptNode *node, asCScriptCode *file) -{ - asASSERT(node && node->nodeType == snExpression); - - asCString str; - str.Assign(file->code + node->tokenPos, node->tokenLength); - - asCString cleanStr; - for( asUINT n = 0; n < str.GetLength(); ) - { - int len; - asETokenClass tok = engine->ParseToken(str.AddressOf() + n, str.GetLength() - n, &len); - if( tok != asTC_COMMENT && tok != asTC_WHITESPACE ) - { - if( cleanStr.GetLength() ) cleanStr += " "; - cleanStr.Concatenate(str.AddressOf() + n, len); - } - n += len; - } - - return cleanStr; -} - -#ifndef AS_NO_COMPILER -int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin) -{ - asCString name; - asCDataType returnType; - asCArray parameterNames; - asCArray parameterTypes; - asCArray inOutFlags; - asCArray defaultArgs; - bool isConstMethod; - bool isOverride; - bool isFinal; - bool isConstructor; - bool isDestructor; - bool isPrivate; - bool isShared; - - asASSERT( (objType && ns == 0) || isGlobalFunction ); - - // Set the default namespace - if( ns == 0 ) - { - if( objType ) - ns = objType->nameSpace; - else - ns = engine->nameSpaces[0]; - } - - GetParsedFunctionDetails(node, file, objType, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isOverride, isFinal, isShared, ns); - - return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isOverride, isFinal, 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, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isOverride, bool isFinal, bool isShared) -{ - // Determine default namespace if not specified - if( ns == 0 ) - { - if( objType ) - ns = objType->nameSpace; - else - ns = engine->nameSpaces[0]; - } - - if( isExistingShared ) - { - asASSERT( objType ); - - // Should validate that the function really exists in the class/interface - bool found = false; - if( isConstructor || isDestructor ) - { - // TODO: shared: Should check the existance of these too - found = true; - } - else - { - for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]]; - if( func->name == name && - func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, isConstMethod) ) - { - found = true; - break; - } - } - } - - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, objType->GetName()); - WriteError(str, file, node); - } - - // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - node->Destroy(engine); - return 0; - } - - // Check for name conflicts - if( !isConstructor && !isDestructor ) - { - if( objType ) - { - CheckNameConflictMember(objType, name.AddressOf(), node, file, false); - - if( name == objType->name ) - WriteError(TXT_METHOD_CANT_HAVE_NAME_OF_CLASS, file, node); - } - else - CheckNameConflict(name.AddressOf(), node, file, ns); - } - else - { - if( isMixin ) - { - // Mixins cannot implement constructors/destructors - WriteError(TXT_MIXIN_CANNOT_HAVE_CONSTRUCTOR, file, node); - - // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - node->Destroy(engine); - return 0; - } - - // Verify that the name of the constructor/destructor is the same as the class - if( name != objType->name ) - WriteError(TXT_CONSTRUCTOR_NAME_ERROR, file, node); - - if( isDestructor ) - name = "~" + name; - } - - isExistingShared = false; - int funcId = engine->GetNextScriptFunctionId(); - if( !isInterface ) - { - sFunctionDescription *func = asNEW(sFunctionDescription); - if( func == 0 ) - { - // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - return asOUT_OF_MEMORY; - } - - functions.PushLast(func); - - func->script = file; - func->node = node; - func->name = name; - func->objType = objType; - func->funcId = funcId; - func->isExistingShared = false; - func->paramNames = parameterNames; - - if( isShared ) - { - // 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->name == name && - f->nameSpace == ns && - f->objectType == objType && - f->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, 0, false) ) - { - funcId = func->funcId = f->id; - isExistingShared = func->isExistingShared = true; - break; - } - } - } - } - - // Destructors may not have any parameters - if( isDestructor && 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 ) - { - asCObjectType *ot = returnType.GetObjectType(); - if( ot && !ot->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf()); - WriteError(msg, file, node); - } - - for( asUINT p = 0; p < parameterTypes.GetLength(); ++p ) - { - asCObjectType *ot = parameterTypes[p].GetObjectType(); - if( ot && !ot->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf()); - WriteError(msg, file, node); - } - } - } - - // Check that the same function hasn't been registered already in the namespace - asCArray funcs; - if( objType ) - GetObjectMethodDescriptions(name.AddressOf(), objType, funcs, false); - else - GetFunctionDescriptions(name.AddressOf(), funcs, ns); - if( objType && (name == "opConv" || name == "opImplConv") && parameterTypes.GetLength() == 0 ) - { - // opConv and opImplConv are special methods used for type casts - for( asUINT n = 0; n < funcs.GetLength(); ++n ) - { - asCScriptFunction *func = GetFunctionDescription(funcs[n]); - if( func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, isConstMethod) ) - { - // TODO: clean up: Reuse the same error handling for both opConv and normal methods - 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); - - // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - return 0; - } - - WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); - break; - } - } - } - else - { - for( asUINT n = 0; n < funcs.GetLength(); ++n ) - { - asCScriptFunction *func = GetFunctionDescription(funcs[n]); - if( func->IsSignatureExceptNameAndReturnTypeEqual(parameterTypes, inOutFlags, objType, isConstMethod) ) - { - 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); - - // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - return 0; - } - - WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); - break; - } - } - } - - // Register the function - if( isExistingShared ) - { - // Delete the default args as they won't be used anymore - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - asCScriptFunction *f = engine->scriptFunctions[funcId]; - module->AddScriptFunction(f); - - // TODO: clean up: This should be done by AddScriptFunction() itself - module->globalFunctions.Put(f); - f->AddRef(); - } - else - { - 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, isFinal, isOverride, isShared, ns); - } - - // Make sure the default args are declared correctly - ValidateDefaultArgs(file, node, engine->scriptFunctions[funcId]); - CheckForConflictsDueToDefaultArgs(file, node, engine->scriptFunctions[funcId], objType); - - if( objType ) - { - asASSERT( !isExistingShared ); - - engine->scriptFunctions[funcId]->AddRef(); - if( isConstructor ) - { - int factoryId = engine->GetNextScriptFunctionId(); - if( parameterTypes.GetLength() == 0 ) - { - // Overload the default constructor - engine->scriptFunctions[objType->beh.construct]->Release(); - objType->beh.construct = funcId; - objType->beh.constructors[0] = funcId; - - // Register the default factory as well - engine->scriptFunctions[objType->beh.factory]->Release(); - objType->beh.factory = factoryId; - objType->beh.factories[0] = factoryId; - } - else - { - objType->beh.constructors.PushLast(funcId); - - // Register the factory as well - objType->beh.factories.PushLast(factoryId); - } - - // We must copy the default arg strings to avoid deleting the same object multiple times - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - defaultArgs[n] = asNEW(asCString)(*defaultArgs[n]); - - asCDataType dt = asCDataType::CreateObjectHandle(objType, false); - module->AddScriptFunction(file->idx, engine->scriptFunctions[funcId]->scriptData->declaredAt, factoryId, name, dt, parameterTypes, parameterNames, inOutFlags, defaultArgs, false); - - // If the object is shared, then the factory must also be marked as shared - if( objType->flags & asOBJ_SHARED ) - engine->scriptFunctions[factoryId]->isShared = true; - - // Add a dummy function to the builder so that it doesn't mix up the fund Ids - functions.PushLast(0); - - // Compile the factory immediately - asCCompiler compiler(engine); - compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]); - engine->scriptFunctions[factoryId]->AddRef(); - } - else if( isDestructor ) - 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->inOutFlags[0] & asTM_INREF) ) - { - engine->scriptFunctions[objType->beh.copy]->Release(); - objType->beh.copy = funcId; - f->AddRef(); - } - - objType->methods.PushLast(funcId); - } - } - - // We need to delete the node already if this is an interface method - if( isInterface && node ) - node->Destroy(engine); - - return 0; -} - -int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared) -{ - if( engine->ep.propertyAccessorMode != 2 ) - { - WriteError(TXT_PROPERTY_ACCESSOR_DISABLED, file, node); - node->Destroy(engine); - return 0; - } - - asASSERT( (objType && ns == 0) || isGlobalFunction ); - - if( ns == 0 ) - { - if( objType ) - ns = objType->nameSpace; - else - ns = engine->nameSpaces[0]; - } - - bool isPrivate = false; - asCString emulatedName; - asCDataType emulatedType; - - asCScriptNode *mainNode = node; - node = node->firstChild; - - if( !isGlobalFunction && node->tokenType == ttPrivate ) - { - isPrivate = true; - node = node->next; - } - - emulatedType = CreateDataTypeFromNode(node, file, ns); - emulatedType = ModifyDataTypeFromNode(emulatedType, node->next, file, 0, 0); - node = node->next->next; - emulatedName.Assign(&file->code[node->tokenPos], node->tokenLength); - - if( node->next == 0 ) - WriteError(TXT_PROPERTY_WITHOUT_ACCESSOR, file, node); - - node = node->next; - while( node ) - { - asCScriptNode *next = node->next; - asCScriptNode *funcNode = 0; - bool success = false; - bool isConst = false; - bool isFinal = false; - bool isOverride = false; - asCDataType returnType; - asCArray paramNames; - asCArray paramTypes; - asCArray paramModifiers; - asCArray defaultArgs; - asCString name; - - // 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) ) - { - funcNode = node->firstChild->next; - - if( funcNode && funcNode->tokenType == ttConst ) - { - isConst = true; - funcNode = funcNode->next; - } - - 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; - - funcNode = funcNode->next; - } - - if( funcNode ) - funcNode->DisconnectParent(); - - 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 - // The code is also different for global property accessors - 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 ) - { - isConst = true; - funcNode = funcNode->next; - } - - 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; - - funcNode = funcNode->next; - } - - 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, isOverride, isFinal, false); - else - { - // Free the funcNode as it won't be used - if( funcNode ) funcNode->Destroy(engine); - - // Should validate that the function really exists in the class/interface - bool found = false; - for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]]; - if( func->name == name && - func->IsSignatureExceptNameEqual(returnType, paramTypes, paramModifiers, objType, isConst) ) - { - found = true; - break; - } - } - - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, objType->GetName()); - WriteError(str, file, node); - } - } - } - - node = next; - }; - - mainNode->Destroy(engine); - - return 0; -} - -int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) -{ - asCString name; - asCDataType returnType; - asCArray parameterNames; - asCArray parameterTypes; - asCArray inOutFlags; - asCArray defaultArgs; - bool isConstMethod, isOverride, isFinal, isConstructor, isDestructor, isPrivate, isShared; - - if( ns == 0 ) - ns = engine->nameSpaces[0]; - - GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isOverride, isFinal, isShared, ns); - CheckNameConflict(name.AddressOf(), node, file, ns); - - // Check that the same function hasn't been registered already in the namespace - asCArray funcs; - GetFunctionDescriptions(name.AddressOf(), funcs, ns); - for( asUINT n = 0; n < funcs.GetLength(); ++n ) - { - asCScriptFunction *func = GetFunctionDescription(funcs[n]); - if( func->IsSignatureExceptNameAndReturnTypeEqual(parameterTypes, inOutFlags, 0, false) ) - { - WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); - break; - } - } - - // Read the module name as well - asCScriptNode *nd = node->lastChild; - asASSERT( nd->nodeType == snConstant && nd->tokenType == ttStringConstant ); - asCString moduleName; - moduleName.Assign(&file->code[nd->tokenPos+1], nd->tokenLength-2); - - node->Destroy(engine); - - // Register the function - module->AddImportedFunction(importID, name, returnType, parameterTypes, inOutFlags, defaultArgs, ns, moduleName); - - return 0; -} - -asCScriptFunction *asCBuilder::GetFunctionDescription(int id) -{ - // TODO: import: This should be improved when the imported functions are removed - // Get the description from the engine - if( (id & FUNC_IMPORTED) == 0 ) - return engine->scriptFunctions[id]; - else - return engine->importedFunctions[id & ~FUNC_IMPORTED]->importedFunctionSignature; -} - -void asCBuilder::GetFunctionDescriptions(const char *name, asCArray &funcs, asSNameSpace *ns) -{ - asUINT n; - - // Get the script declared global functions - const asCArray &idxs = module->globalFunctions.GetIndexes(ns, name); - for( n = 0; n < idxs.GetLength(); n++ ) - { - const asCScriptFunction *f = module->globalFunctions.Get(idxs[n]); - asASSERT( f->objectType == 0 ); - funcs.PushLast(f->id); - } - - // Add the imported functions - // TODO: optimize: Linear search: This is probably not that critial. Also bindInformation will probably be removed in near future - for( n = 0; n < module->bindInformations.GetLength(); n++ ) - { - if( module->bindInformations[n]->importedFunctionSignature->name == name ) - funcs.PushLast(module->bindInformations[n]->importedFunctionSignature->id); - } - - // Add the registered global functions - const asCArray &idxs2 = engine->registeredGlobalFuncs.GetIndexes(ns, name); - for( n = 0; n < idxs2.GetLength(); n++ ) - { - asCScriptFunction *f = engine->registeredGlobalFuncs.Get(idxs2[n]); - - // Verify if the module has access to the function - if( module->accessMask & f->accessMask ) - { - funcs.PushLast(f->id); - } - } -} - -void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray &methods, bool objIsConst, const asCString &scope) -{ - if( scope != "" ) - { - // Find the base class with the specified scope - while( objectType && objectType->name != scope ) - objectType = objectType->derivedFrom; - - // If the scope is not any of the base classes, then return no methods - if( objectType == 0 ) - return; - } - - // TODO: optimize: Improve linear search - if( objIsConst ) - { - // Only add const methods to the list - for( asUINT n = 0; n < objectType->methods.GetLength(); n++ ) - { - if( engine->scriptFunctions[objectType->methods[n]]->name == name && - engine->scriptFunctions[objectType->methods[n]]->isReadOnly ) - { - // 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++ ) - { - if( engine->scriptFunctions[objectType->methods[n]]->name == name ) - { - // 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); - } - } - } - } -} -#endif - -void asCBuilder::WriteInfo(const asCString &scriptname, const asCString &message, int r, int c, bool pre) -{ - // Need to store the pre message in a structure - if( pre ) - { - engine->preMessage.isSet = true; - engine->preMessage.c = c; - engine->preMessage.r = r; - engine->preMessage.message = message; - engine->preMessage.scriptname = scriptname; - } - else - { - engine->preMessage.isSet = false; - - if( !silent ) - engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_INFORMATION, message.AddressOf()); - } -} - -void asCBuilder::WriteInfo(const asCString &message, asCScriptCode *file, asCScriptNode *node) -{ - int r = 0, c = 0; - if( node ) - file->ConvertPosToRowCol(node->tokenPos, &r, &c); - - WriteInfo(file->name, message, r, c, false); -} - -void asCBuilder::WriteError(const asCString &message, asCScriptCode *file, asCScriptNode *node) -{ - int r = 0, c = 0; - if( node && file ) - file->ConvertPosToRowCol(node->tokenPos, &r, &c); - - WriteError(file ? file->name : asCString(""), message, r, c); -} - -void asCBuilder::WriteError(const asCString &scriptname, const asCString &message, int r, int c) -{ - numErrors++; - - if( !silent ) - engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_ERROR, message.AddressOf()); -} - -void asCBuilder::WriteWarning(const asCString &scriptname, const asCString &message, int r, int c) -{ - if( engine->ep.compilerWarnings ) - { - numWarnings++; - - if( !silent ) - engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_WARNING, message.AddressOf()); - } -} - -void asCBuilder::WriteWarning(const asCString &message, asCScriptCode *file, asCScriptNode *node) -{ - int r = 0, c = 0; - if( node && file ) - file->ConvertPosToRowCol(node->tokenPos, &r, &c); - - WriteWarning(file ? file->name : asCString(""), message, r, c); -} - -asCString asCBuilder::GetScopeFromNode(asCScriptNode *node, asCScriptCode *script, asCScriptNode **next) -{ - asCString scope; - asCScriptNode *sn = node; - if( sn->tokenType == ttScope ) - { - scope = "::"; - sn = sn->next; - } - - while( sn && sn->next && sn->next->tokenType == ttScope ) - { - asCString tmp; - tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength); - if( scope != "" && scope != "::" ) - scope += "::"; - scope += tmp; - sn = sn->next->next; - } - - if( next ) - *next = sn; - - return scope; -} - -asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next) -{ - asCString scope = GetScopeFromNode(node, script, next); - asSNameSpace *ns = implicitNs; - if( scope == "::" ) - ns = engine->nameSpaces[0]; - else if( scope != "" ) - { - ns = engine->FindNameSpace(scope.AddressOf()); - if( ns == 0 ) - { - asCString msg; - msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, scope.AddressOf()); - WriteError(msg, script, node); - } - } - - return ns; -} - -asSNameSpace *asCBuilder::GetParentNameSpace(asSNameSpace *ns) -{ - if( ns == 0 ) return 0; - if( ns == engine->nameSpaces[0] ) return 0; - - asCString scope = ns->name; - int pos = scope.FindLast("::"); - if( pos >= 0 ) - { - scope = scope.SubString(0, pos); - return engine->FindNameSpace(scope.AddressOf()); - } - - return engine->nameSpaces[0]; -} - -asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope, asCObjectType *currentType) -{ - asASSERT(node->nodeType == snDataType); - - asCDataType dt; - - asCScriptNode *n = node->firstChild; - - bool isConst = false; - bool isImplicitHandle = false; - if( n->tokenType == ttConst ) - { - isConst = true; - n = n->next; - } - - // Determine namespace - asSNameSpace *ns = GetNameSpaceFromNode(n, file, implicitNamespace, &n); - if( ns == 0 ) - { - // The namespace doesn't exist. Return a dummy type instead. - dt = asCDataType::CreatePrimitive(ttInt, false); - return dt; - } - - if( n->tokenType == ttIdentifier ) - { - 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 *ot = 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) ) - { - for( asUINT subtypeIndex = 0; subtypeIndex < currentType->templateSubTypes.GetLength(); subtypeIndex++) - { - asCObjectType *type = currentType->templateSubTypes[subtypeIndex].GetObjectType(); - if( type && str == type->name ) - { - ot = type; - break; - } - } - } - - if( ot == 0 ) - ot = GetObjectType(str.AddressOf(), ns); - if( ot == 0 && !module && currentType ) - ot = GetObjectTypeFromTypesKnownByObject(str.AddressOf(), currentType); - - if( ot ) - { - found = true; - - if( ot->flags & asOBJ_IMPLICIT_HANDLE ) - isImplicitHandle = true; - - // Make sure the module has access to the object type - if( !module || (module->accessMask & ot->accessMask) ) - { - if( asOBJ_TYPEDEF == (ot->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.MakeReadOnly(isConst); - } - else - { - if( ot->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 ) - { - 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); - - // 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); - - if( !otInstance ) - { - asCString msg; - // TODO: Should name all subtypes - msg.Format(TXT_CANNOT_INSTANTIATE_TEMPLATE_s_WITH_s, ot->name.AddressOf(), subTypes[0].Format().AddressOf()); - WriteError(msg, file, n); - } - - ot = otInstance; - } - } - - // Create object data type - if( ot ) - dt = asCDataType::CreateObject(ot, 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); - - 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( !found ) - { - // Try to find it in the parent namespace - ns = GetParentNameSpace(ns); - } - } - - 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); - - dt = asCDataType::CreatePrimitive(ttInt, isConst); - return dt; - } - } - else if( n->tokenType == ttAuto ) - { - dt = asCDataType::CreateAuto(isConst); - } - else - { - // Create primitive data type - dt = asCDataType::CreatePrimitive(n->tokenType, isConst); - } - - // Determine array dimensions and object handles - n = n->next; - while( n && (n->tokenType == ttOpenBracket || n->tokenType == ttHandle) ) - { - if( n->tokenType == ttOpenBracket ) - { - // 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().AddressOf()); - else if( dt.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format().AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf()); - - WriteError(str, file, n); - } - - // Make the type an array (or multidimensional array) - if( dt.MakeArray(engine) < 0 ) - { - WriteError(TXT_NO_DEFAULT_ARRAY_TYPE, file, n); - break; - } - } - else - { - // Make the type a handle - if( dt.IsObjectHandle() ) - { - WriteError(TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED, file, n); - break; - } - else if( dt.MakeHandle(true, acceptHandleForScope) < 0 ) - { - WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); - break; - } - } - n = n->next; - } - - if( isImplicitHandle ) - { - // Make the type a handle - if( dt.MakeHandle(true, acceptHandleForScope) < 0 ) - WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); - } - - return dt; -} - -asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlags, bool *autoHandle) -{ - asCDataType dt = type; - - if( inOutFlags ) *inOutFlags = asTM_NONE; - - // Is the argument sent by reference? - asCScriptNode *n = node->firstChild; - if( n && n->tokenType == ttAmp ) - { - dt.MakeReference(true); - n = n->next; - - if( n ) - { - if( inOutFlags ) - { - if( n->tokenType == ttIn ) - *inOutFlags = asTM_INREF; - else if( n->tokenType == ttOut ) - *inOutFlags = asTM_OUTREF; - else if( n->tokenType == ttInOut ) - *inOutFlags = asTM_INOUTREF; - else - asASSERT(false); - } - - n = n->next; - } - else - { - if( inOutFlags ) - *inOutFlags = asTM_INOUTREF; // ttInOut - } - - if( !engine->ep.allowUnsafeReferences && - 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)) ) - WriteError(TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, file, node->firstChild); - } - } - - if( autoHandle ) *autoHandle = false; - - 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 - // this error would already have been reported so no need to report another error here - if( dt.IsObjectHandle() && (dt.GetObjectType()->flags & asOBJ_NOCOUNT) ) - WriteError(TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT, file, node->firstChild); - - if( autoHandle ) *autoHandle = true; - } - - return dt; -} - -asCObjectType *asCBuilder::GetObjectType(const char *type, asSNameSpace *ns) -{ - asCObjectType *ot = engine->GetRegisteredObjectType(type, ns); - if( !ot && module ) - ot = module->GetObjectType(type, ns); - - return ot; -} - -#ifndef AS_NO_COMPILER -// This function will return true if there are any types in the engine or module -// with the given name. The namespace is ignored in this verification. -bool asCBuilder::DoesTypeExist(const asCString &type) -{ - asUINT n; - - // This function is only used when parsing expressions for building bytecode - // and this is only done after all types are known. For this reason the types - // can be safely cached in a map for quick lookup. Once the builder is released - // the cache will also be destroyed thus avoiding unnecessary memory consumption. - if( !hasCachedKnownTypes ) - { - // Only do this once - hasCachedKnownTypes = true; - - // Add registered object types - asSMapNode *cursor; - engine->allRegisteredTypes.MoveFirst(&cursor); - while( cursor ) - { - if( !knownTypes.MoveTo(0, cursor->key.name) ) - knownTypes.Insert(cursor->key.name, true); - - 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 ) - { - // Add script classes and interfaces - 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) ) - 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) ) - 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) ) - knownTypes.Insert(module->funcDefs[n]->name, true); - } - } - - // Check if the type is known - return knownTypes.MoveTo(0, type); -} -#endif - -asCObjectType *asCBuilder::GetObjectTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType) -{ - if( currentType->name == type ) - return currentType; - - asUINT n; - - asCObjectType *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->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( 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 ) - return 0; - } - - return found; -} - -asCScriptFunction *asCBuilder::GetFuncDef(const char *type) -{ - 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]; - - if( module ) - { - for( asUINT n = 0; n < module->funcDefs.GetLength(); n++ ) - if( module->funcDefs[n]->name == type ) - return module->funcDefs[n]; - } - - return 0; -} - -#ifndef AS_NO_COMPILER - -int asCBuilder::GetEnumValueFromObjectType(asCObjectType *objType, const char *name, asCDataType &outDt, asDWORD &outValue) -{ - if( !objType || !(objType->flags & asOBJ_ENUM) ) - return 0; - - for( asUINT n = 0; n < objType->enumValues.GetLength(); ++n ) - { - if( objType->enumValues[n]->name == name ) - { - outDt = asCDataType::CreateObject(objType, true); - outValue = objType->enumValues[n]->value; - return 1; - } - } - - return 0; -} - -int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue, asSNameSpace *ns) -{ - bool found = false; - - // Search all available enum types - asUINT t; - for( t = 0; t < engine->registeredEnums.GetLength(); t++ ) - { - asCObjectType *ot = engine->registeredEnums[t]; - if( ns != ot->nameSpace ) continue; - - // Don't bother with types the module doesn't have access to - if( (ot->accessMask & module->accessMask) == 0 ) - continue; - - if( GetEnumValueFromObjectType(ot, name, outDt, outValue) ) - { - if( !found ) - found = true; - else - { - // Found more than one value in different enum types - return 2; - } - } - } - - for( t = 0; t < module->enumTypes.GetLength(); t++ ) - { - asCObjectType *ot = module->enumTypes[t]; - if( ns != ot->nameSpace ) continue; - - if( GetEnumValueFromObjectType(ot, name, outDt, outValue) ) - { - if( !found ) - found = true; - else - { - // Found more than one value in different enum types - return 2; - } - } - } - - if( found ) - return 1; - - // Didn't find any value - return 0; -} - -#endif // AS_NO_COMPILER - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/source/as_builder.h b/dependencies/angelscript/source/as_builder.h deleted file mode 100644 index 6cd30662..00000000 --- a/dependencies/angelscript/source/as_builder.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_builder.h -// -// This is the class that manages the compilation of the scripts -// - - -#ifndef AS_BUILDER_H -#define AS_BUILDER_H - -#include "as_config.h" -#include "as_symboltable.h" -#include "as_scriptengine.h" -#include "as_module.h" -#include "as_array.h" -#include "as_scriptcode.h" -#include "as_scriptnode.h" -#include "as_datatype.h" -#include "as_property.h" - -BEGIN_AS_NAMESPACE - -#ifdef AS_NO_COMPILER -// Forward declare the structure, as it is part of some function signatures used even without the compiler -struct sGlobalVariableDescription; -#endif - -#ifndef AS_NO_COMPILER - -struct sFunctionDescription -{ - asCScriptCode *script; - asCScriptNode *node; - asCString name; - asCObjectType *objType; - asCArray paramNames; - int funcId; - bool isExistingShared; -}; - -struct sGlobalVariableDescription -{ - asCScriptCode *script; - asCScriptNode *declaredAtNode; - asCScriptNode *initializationNode; - asCString name; - asCGlobalProperty *property; - asCDataType datatype; - asSNameSpace *ns; - int index; - bool isCompiled; - bool isPureConstant; - bool isEnumValue; - asQWORD constantValue; -}; - -struct sPropertyInitializer -{ - sPropertyInitializer() : declNode(0), initNode(0), file(0) {} - sPropertyInitializer(const asCString &nm, asCScriptNode *decl, asCScriptNode *init, asCScriptCode *f) : name(nm), declNode(decl), initNode(init), file(f) {} - sPropertyInitializer &operator=(const sPropertyInitializer &o) {name = o.name; declNode = o.declNode; initNode = o.initNode; file = o.file; return *this;} - - asCString name; - asCScriptNode *declNode; - asCScriptNode *initNode; - asCScriptCode *file; -}; - -struct sClassDeclaration -{ - sClassDeclaration() {script = 0; node = 0; validState = 0; objType = 0; isExistingShared = false; isFinal = false;} - - asCScriptCode *script; - asCScriptNode *node; - asCString name; - int validState; - asCObjectType *objType; - bool isExistingShared; - bool isFinal; - - asCArray propInits; -}; - -struct sFuncDef -{ - asCScriptCode *script; - asCScriptNode *node; - asCString name; - int idx; -}; - -struct sMixinClass -{ - asCScriptCode *script; - asCScriptNode *node; - asCString name; - asSNameSpace *ns; -}; - -#endif // AS_NO_COMPILER - -class asCBuilder -{ -public: - asCBuilder(asCScriptEngine *engine, asCModule *module); - ~asCBuilder(); - - // These methods are used by the application interface - 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 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); - -#ifndef AS_NO_COMPILER - int AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy); - int Build(); - - int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asCScriptFunction **outFunc); - int CompileGlobalVar(const char *sectionName, const char *code, int lineOffset); -#endif - -protected: - friend class asCModule; - friend class asCParser; - friend class asCScriptFunction; - friend class asCScriptEngine; - - void Reset(); - - void WriteInfo(const asCString &scriptname, const asCString &msg, int r, int c, bool preMessage); - void WriteInfo(const asCString &msg, asCScriptCode *file, asCScriptNode *node); - void WriteError(const asCString &scriptname, const asCString &msg, int r, int c); - void WriteError(const asCString &msg, asCScriptCode *file, asCScriptNode *node); - void WriteWarning(const asCString &scriptname, const asCString &msg, int r, int c); - void WriteWarning(const asCString &msg, asCScriptCode *file, asCScriptNode *node); - - bool DoesGlobalPropertyExist(const char *prop, asSNameSpace *ns, asCGlobalProperty **outProp = 0, sGlobalVariableDescription **outDesc = 0, bool *isAppProp = 0); - asCGlobalProperty *GetGlobalProperty(const char *prop, asSNameSpace *ns, bool *isCompiled, bool *isPureConstant, asQWORD *constantValue, bool *isAppProp); - int ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func); - asCString GetCleanExpressionString(asCScriptNode *n, asCScriptCode *file); - - asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next); - asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0); - asSNameSpace *GetParentNameSpace(asSNameSpace *ns); - - 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); - asCDataType ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlag, bool *autoHandle); - - int numErrors; - int numWarnings; - bool silent; - - asCScriptEngine *engine; - asCModule *module; - -#ifndef AS_NO_COMPILER -protected: - friend class asCCompiler; - - int CheckForConflictsDueToDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func, asCObjectType *objType); - int GetNamespaceAndNameFromNode(asCScriptNode *n, asCScriptCode *script, asSNameSpace *implicitNs, asSNameSpace *&outNs, asCString &outName); - int RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); - sMixinClass *GetMixinClass(const char *name, asSNameSpace *ns); - void IncludePropertiesFromMixins(sClassDeclaration *decl); - void IncludeMethodsFromMixins(sClassDeclaration *decl); - void AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *errNode, asCObjectType *intf); - 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 isOverride, bool isFinal, bool isShared); - 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); - int RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); - 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); - void CompleteFuncDef(sFuncDef *funcDef); - void CompileInterfaces(); - void CompileClasses(); - 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 &isOverride, bool &isFinal, bool &isShared, 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, asCScriptCode *file = 0, asCScriptNode *node = 0); - int CreateVirtualFunction(asCScriptFunction *func, int idx); - void ParseScripts(); - void RegisterTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns); - void RegisterNonTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns); - void CompileFunctions(); - void CompileGlobalVariables(); - int GetEnumValueFromObjectType(asCObjectType *objType, 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); - asCScriptFunction *GetFunctionDescription(int funcId); - void GetFunctionDescriptions(const char *name, asCArray &funcs, asSNameSpace *ns); - void GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray &methods, bool objIsConst, const asCString &scope = ""); - - asCArray scripts; - asCArray functions; - asCSymbolTable globVariables; - asCArray classDeclarations; - asCArray interfaceDeclarations; - asCArray namedTypeDeclarations; - asCArray funcDefs; - asCArray mixinClasses; - - // For use with the DoesTypeExists() method - bool hasCachedKnownTypes; - asCMap knownTypes; -#endif -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_bytecode.cpp b/dependencies/angelscript/source/as_bytecode.cpp deleted file mode 100644 index 526ab4ba..00000000 --- a/dependencies/angelscript/source/as_bytecode.cpp +++ /dev/null @@ -1,2844 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_bytecode.cpp -// -// A class for constructing the final byte code -// - -#include // fopen(), fprintf(), fclose() - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_bytecode.h" -#include "as_debug.h" // mkdir() -#include "as_array.h" -#include "as_string.h" -#include "as_scriptengine.h" -#include "as_debug.h" - -BEGIN_AS_NAMESPACE - -asCByteCode::asCByteCode(asCScriptEngine *engine) -{ - first = 0; - last = 0; - largestStackUsed = -1; - temporaryVariables = 0; - - this->engine = engine; -} - -asCByteCode::~asCByteCode() -{ - ClearAll(); -} - -void asCByteCode::Finalize(const asCArray &tempVariableOffsets) -{ - temporaryVariables = &tempVariableOffsets; - - // verify the bytecode - PostProcess(); - - // Optimize the code - Optimize(); - - // Resolve jumps - ResolveJumpAddresses(); - - // Build line numbers buffer - ExtractLineNumbers(); -} - -void asCByteCode::ClearAll() -{ - asCByteInstruction *del = first; - - while( del ) - { - first = del->next; - engine->memoryMgr.FreeByteInstruction(del); - del = first; - } - - first = 0; - last = 0; - - lineNumbers.SetLength(0); - - largestStackUsed = -1; -} - -void asCByteCode::InsertIfNotExists(asCArray &vars, int var) -{ - if( !vars.Exists(var) ) - vars.PushLast(var); -} - -void asCByteCode::GetVarsUsed(asCArray &vars) -{ - TimeIt("asCByteCode::GetVarsUsed"); - - asCByteInstruction *curr = first; - while( curr ) - { - if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ) - { - InsertIfNotExists(vars, curr->wArg[0]); - InsertIfNotExists(vars, curr->wArg[1]); - InsertIfNotExists(vars, curr->wArg[2]); - } - else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG ) - { - InsertIfNotExists(vars, curr->wArg[0]); - } - else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG ) - { - InsertIfNotExists(vars, curr->wArg[0]); - InsertIfNotExists(vars, curr->wArg[1]); - } - else if( curr->op == asBC_LoadThisR ) - { - InsertIfNotExists(vars, 0); - } - - curr = curr->next; - } -} - -bool asCByteCode::IsVarUsed(int offset) -{ - TimeIt("asCByteCode::IsVarUsed"); - - asCByteInstruction *curr = first; - while( curr ) - { - // Verify all ops that use variables - if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ) - { - if( curr->wArg[0] == offset || curr->wArg[1] == offset || curr->wArg[2] == offset ) - return true; - } - else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG ) - { - if( curr->wArg[0] == offset ) - return true; - } - else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG ) - { - if( curr->wArg[0] == offset || curr->wArg[1] == offset ) - return true; - } - else if( curr->op == asBC_LoadThisR ) - { - if( offset == 0 ) - return true; - } - - curr = curr->next; - } - - return false; -} - -void asCByteCode::ExchangeVar(int oldOffset, int newOffset) -{ - asASSERT(oldOffset != 0); - - asCByteInstruction *curr = first; - while( curr ) - { - // Verify all ops that use variables - if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ) - { - if( curr->wArg[0] == oldOffset ) - curr->wArg[0] = (short)newOffset; - if( curr->wArg[1] == oldOffset ) - curr->wArg[1] = (short)newOffset; - if( curr->wArg[2] == oldOffset ) - curr->wArg[2] = (short)newOffset; - } - else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG ) - { - if( curr->wArg[0] == oldOffset ) - curr->wArg[0] = (short)newOffset; - } - else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG ) - { - if( curr->wArg[0] == oldOffset ) - curr->wArg[0] = (short)newOffset; - if( curr->wArg[1] == oldOffset ) - curr->wArg[1] = (short)newOffset; - } - - curr = curr->next; - } -} - -void asCByteCode::AddPath(asCArray &paths, asCByteInstruction *instr, int stackSize) -{ - if( instr->marked ) - { - // Verify the size of the stack - asASSERT(instr->stackSize == stackSize); - } - else - { - // Add the destination to the code paths - instr->marked = true; - instr->stackSize = stackSize; - paths.PushLast(instr); - } -} - -asCByteInstruction *asCByteCode::ChangeFirstDeleteNext(asCByteInstruction *curr, asEBCInstr bc) -{ - curr->op = bc; - - if( curr->next ) DeleteInstruction(curr->next); - - // Continue optimization with the instruction before the altered one - if( curr->prev ) - return curr->prev; - else - return curr; -} - -asCByteInstruction *asCByteCode::DeleteFirstChangeNext(asCByteInstruction *curr, asEBCInstr bc) -{ - asASSERT( curr->next ); - - asCByteInstruction *instr = curr->next; - instr->op = bc; - - DeleteInstruction(curr); - - // Continue optimization with the instruction before the altered one - if( instr->prev ) - return instr->prev; - else - return instr; -} - -void asCByteCode::InsertBefore(asCByteInstruction *before, asCByteInstruction *instr) -{ - asASSERT(instr->next == 0); - asASSERT(instr->prev == 0); - - if( before->prev ) before->prev->next = instr; - instr->prev = before->prev; - before->prev = instr; - instr->next = before; - - if( first == before ) first = instr; -} - -void asCByteCode::RemoveInstruction(asCByteInstruction *instr) -{ - if( instr == first ) first = first->next; - if( instr == last ) last = last->prev; - - if( instr->prev ) instr->prev->next = instr->next; - if( instr->next ) instr->next->prev = instr->prev; - - instr->next = 0; - instr->prev = 0; -} - -bool asCByteCode::CanBeSwapped(asCByteInstruction *curr) -{ - asASSERT( curr->op == asBC_SwapPtr ); - - if( !curr->prev || !curr->prev->prev ) return false; - - asCByteInstruction *b = curr->prev; - asCByteInstruction *a = b->prev; - - if( a->op != asBC_PshNull && - a->op != asBC_PshVPtr && - a->op != asBC_PSF ) - return false; - - if( b->op != asBC_PshNull && - b->op != asBC_PshVPtr && - b->op != asBC_PSF ) - return false; - - return true; -} - -asCByteInstruction *asCByteCode::GoBack(asCByteInstruction *curr) -{ - // Go back 2 instructions - if( !curr ) return 0; - if( curr->prev ) curr = curr->prev; - if( curr->prev ) curr = curr->prev; - return curr; -} - -asCByteInstruction *asCByteCode::GoForward(asCByteInstruction *curr) -{ - // Go forward 2 instructions - if( !curr ) return 0; - if( curr->next ) curr = curr->next; - if( curr->next ) curr = curr->next; - return curr; -} - -bool asCByteCode::PostponeInitOfTemp(asCByteInstruction *curr, asCByteInstruction **next) -{ - TimeIt("asCByteCode::PostponeInitOfTemp"); - - // This is not done for pointers - if( (curr->op != asBC_SetV4 && curr->op != asBC_SetV8) || - !IsTemporary(curr->wArg[0]) ) return false; - - // Move the initialization to just before it's use. - // Don't move it beyond any labels or jumps. - asCByteInstruction *use = curr->next; - while( use ) - { - if( IsTempVarReadByInstr(use, curr->wArg[0]) ) - break; - - if( IsTempVarOverwrittenByInstr(use, curr->wArg[0]) ) - return false; - - if( IsInstrJmpOrLabel(use) ) - return false; - - use = use->next; - } - - if( use && use->prev != curr ) - { - asCByteInstruction *orig = curr->next; - - // Move the instruction - RemoveInstruction(curr); - InsertBefore(use, curr); - - // Try a RemoveUnusedValue to see if it can be combined with the other - if( RemoveUnusedValue(curr, 0) ) - { - // Optimizations should continue from the instruction that uses the value - *next = orig; - return true; - } - - // Return the instructions to its original position as it wasn't useful - RemoveInstruction(curr); - InsertBefore(orig, curr); - } - - return false; -} - -bool asCByteCode::RemoveUnusedValue(asCByteInstruction *curr, asCByteInstruction **next) -{ - TimeIt("asCByteCode::RemoveUnusedValue"); - - asCByteInstruction *dummy; - if( next == 0 ) - next = &dummy; - - // TODO: runtime optimize: Should work for 64bit types as well - - // TODO: runtime optimize: Need a asBCTYPE_rwW_ARG to cover the instructions that read - // and write to the same variable. Currently they are considered - // as readers only, so they are not optimized away. This includes - // NOT, BNOT, IncV, DecV, NEG, iTOf (and all other type casts) - - // The value isn't used for anything - if( curr->op != asBC_FREE && // Can't remove the FREE instruction - (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) && - IsTemporary(curr->wArg[0]) && - !IsTempVarRead(curr, curr->wArg[0]) ) - { - if( curr->op == asBC_LdGRdR4 && IsTempRegUsed(curr) ) - { - curr->op = asBC_LDG; - *next = GoForward(curr); - return true; - } - - *next = GoForward(DeleteInstruction(curr)); - return true; - } - - if( curr->op == asBC_SetV4 && curr->next ) - { - // The value is immediately used and then never again - if( (curr->next->op == asBC_CMPi || - curr->next->op == asBC_CMPf || - curr->next->op == asBC_CMPu) && - curr->wArg[0] == curr->next->wArg[1] && - IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again - !IsTempVarRead(curr->next, curr->wArg[0]) ) - { - if( curr->next->op == asBC_CMPi ) curr->next->op = asBC_CMPIi; - else if( curr->next->op == asBC_CMPf ) curr->next->op = asBC_CMPIf; - else if( curr->next->op == asBC_CMPu ) curr->next->op = asBC_CMPIu; - curr->next->size = asBCTypeSize[asBCInfo[asBC_CMPIi].type]; - curr->next->arg = curr->arg; - *next = GoForward(DeleteInstruction(curr)); - return true; - } - - // The value is immediately used and then never again - if( (curr->next->op == asBC_ADDi || - curr->next->op == asBC_SUBi || - curr->next->op == asBC_MULi || - curr->next->op == asBC_ADDf || - curr->next->op == asBC_SUBf || - curr->next->op == asBC_MULf) && - curr->wArg[0] == curr->next->wArg[2] && - (curr->next->wArg[0] == curr->wArg[0] || // The variable is overwritten - (IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again - !IsTempVarRead(curr->next, curr->wArg[0]))) ) - { - if( curr->next->op == asBC_ADDi ) curr->next->op = asBC_ADDIi; - else if( curr->next->op == asBC_SUBi ) curr->next->op = asBC_SUBIi; - else if( curr->next->op == asBC_MULi ) curr->next->op = asBC_MULIi; - else if( curr->next->op == asBC_ADDf ) curr->next->op = asBC_ADDIf; - else if( curr->next->op == asBC_SUBf ) curr->next->op = asBC_SUBIf; - else if( curr->next->op == asBC_MULf ) curr->next->op = asBC_MULIf; - curr->next->size = asBCTypeSize[asBCInfo[asBC_ADDIi].type]; - curr->next->arg = curr->arg; - *next = GoForward(DeleteInstruction(curr)); - return true; - } - - if( (curr->next->op == asBC_ADDi || - curr->next->op == asBC_MULi || - curr->next->op == asBC_ADDf || - curr->next->op == asBC_MULf) && - curr->wArg[0] == curr->next->wArg[1] && - (curr->next->wArg[0] == curr->wArg[0] || // The variable is overwritten - (IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again - !IsTempVarRead(curr->next, curr->wArg[0]))) ) - { - if( curr->next->op == asBC_ADDi ) curr->next->op = asBC_ADDIi; - else if( curr->next->op == asBC_MULi ) curr->next->op = asBC_MULIi; - else if( curr->next->op == asBC_ADDf ) curr->next->op = asBC_ADDIf; - else if( curr->next->op == asBC_MULf ) curr->next->op = asBC_MULIf; - curr->next->size = asBCTypeSize[asBCInfo[asBC_ADDIi].type]; - curr->next->arg = curr->arg; - - // The order of the operands are changed - curr->next->wArg[1] = curr->next->wArg[2]; - - *next = GoForward(DeleteInstruction(curr)); - return true; - } - - // The constant value is immediately moved to another variable and then not used again - if( curr->next->op == asBC_CpyVtoV4 && - curr->wArg[0] == curr->next->wArg[1] && - IsTemporary(curr->wArg[0]) && - !IsTempVarRead(curr->next, curr->wArg[0]) ) - { - curr->wArg[0] = curr->next->wArg[0]; - *next = GoForward(DeleteInstruction(curr->next)); - return true; - } - - // The constant is copied to a temp and then immediately pushed on the stack - if( curr->next->op == asBC_PshV4 && - curr->wArg[0] == curr->next->wArg[0] && - IsTemporary(curr->wArg[0]) && - !IsTempVarRead(curr->next, curr->wArg[0]) ) - { - curr->op = asBC_PshC4; - curr->stackInc = asBCInfo[asBC_PshC4].stackInc; - *next = GoForward(DeleteInstruction(curr->next)); - return true; - } - - // The constant is copied to a global variable and then never used again - if( curr->next->op == asBC_CpyVtoG4 && - curr->wArg[0] == curr->next->wArg[0] && - IsTemporary(curr->wArg[0]) && - !IsTempVarRead(curr->next, curr->wArg[0]) ) - { - curr->op = asBC_SetG4; - curr->size = asBCTypeSize[asBCInfo[asBC_SetG4].type]; - *(((asDWORD*)&curr->arg)+AS_PTR_SIZE) = *ARG_DW(curr->arg); - *ARG_PTR(curr->arg) = *ARG_PTR(curr->next->arg); - *next = GoForward(DeleteInstruction(curr->next)); - return true; - } - } - - // The value is immediately moved to another variable and then not used again - if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG) && - curr->next && curr->next->op == asBC_CpyVtoV4 && - curr->wArg[0] == curr->next->wArg[1] && - IsTemporary(curr->wArg[0]) && - !IsTempVarRead(curr->next, curr->wArg[0]) ) - { - curr->wArg[0] = curr->next->wArg[0]; - *next = GoForward(DeleteInstruction(curr->next)); - return true; - } - - // The register is copied to a temp variable and then back to the register again without being used afterwards - if( curr->op == asBC_CpyRtoV4 && curr->next && curr->next->op == asBC_CpyVtoR4 && - curr->wArg[0] == curr->next->wArg[0] && - IsTemporary(curr->wArg[0]) && - !IsTempVarRead(curr->next, curr->wArg[0]) ) - { - // Delete both instructions - DeleteInstruction(curr->next); - *next = GoForward(DeleteInstruction(curr)); - return true; - } - - // The global value is copied to a temp and then immediately pushed on the stack - if( curr->op == asBC_CpyGtoV4 && curr->next && curr->next->op == asBC_PshV4 && - curr->wArg[0] == curr->next->wArg[0] && - IsTemporary(curr->wArg[0]) && - !IsTempVarRead(curr->next, curr->wArg[0]) ) - { - curr->op = asBC_PshG4; - curr->size = asBCTypeSize[asBCInfo[asBC_PshG4].type]; - curr->stackInc = asBCInfo[asBC_PshG4].stackInc; - *next = GoForward(DeleteInstruction(curr->next)); - return true; - } - - // The constant is assigned to a variable, then the value of the variable - // pushed on the stack, and then the variable is never used again - if( curr->op == asBC_SetV8 && curr->next && curr->next->op == asBC_PshV8 && - curr->wArg[0] == curr->next->wArg[0] && - IsTemporary(curr->wArg[0]) && - !IsTempVarRead(curr->next, curr->wArg[0]) ) - { - curr->op = asBC_PshC8; - curr->stackInc = asBCInfo[asBC_PshC8].stackInc; - *next = GoForward(DeleteInstruction(curr->next)); - return true; - } - - return false; -} - -bool asCByteCode::IsTemporary(int offset) -{ - TimeIt("asCByteCode::IsTemporary"); - - asASSERT(temporaryVariables); - - return temporaryVariables->Exists(offset); -} - -void asCByteCode::OptimizeLocally(const asCArray &tempVariableOffsets) -{ - // This function performs the optimizations that doesn't require global knowledge of the - // entire function, e.g. replacement of sequences of bytecodes for specialized instructions. - - if( !engine->ep.optimizeByteCode ) - return; - - temporaryVariables = &tempVariableOffsets; - - // TODO: runtime optimize: VAR + GET... should be optimized if the only instructions between them are trivial, i.e. no - // function calls that can suspend the execution. - - // TODO: runtime optimize: Remove temporary copies of handles, when the temp is just copied to yet another location - - // TODO: runtime optimize: A single bytecode for incrementing a variable, comparing, and jumping can probably improve - // loops a lot. How often do these loops really occur? - - // TODO: runtime optimize: Need a bytecode BC_AddRef so that BC_CALLSYS doesn't have to be used for this trivial call - - // TODO: optimize: Should possibly do two loops. Some of the checks are best doing by iterating from - // the end to beginning, e.g. the removal of unused values. Other checks are best - // doing by iterating from the beginning to end, e.g. replacement of sequences with - // shorter ones. By doing this, we should be able to avoid backtracking with every - // change thus avoid unnecessary duplicate checks. - - // Iterate through the bytecode instructions in the reverse order. - // An optimization in an instruction may mean that another instruction before that - // can also be optimized, e.g. if an add instruction is removed because the result is not - // used, then the instructions that created the operands may potentially also be removed. - asCByteInstruction *instr = last; - while( instr ) - { - asCByteInstruction *curr = instr; - instr = instr->prev; - - // Remove instructions when the result is not used anywhere - // This will return true if the instruction is deleted, and - // false if it is not deleted. Observe that the instruction - // can be modified. - if( RemoveUnusedValue(curr, &instr) ) continue; - - // Postpone initializations so that they may be combined in the second pass. - // If the initialization is postponed, then the optimizations should continue - // from where the value was used, so instr will be updated to point to that. - if( PostponeInitOfTemp(curr, &instr) ) continue; - - // Look for sequences that can be replaced with shorter ones - const asEBCInstr currOp = curr->op; - if( currOp == asBC_SwapPtr ) - { - // XXX x, YYY y, SwapPtr -> YYY y, XXX x - if( CanBeSwapped(curr) ) - { - // Delete the SwapPtr - DeleteInstruction(curr); - - // Swap instructions - asCByteInstruction *a = instr->prev; - RemoveInstruction(instr); - InsertBefore(a, instr); - - // Continue the optimization from the second instruction - instr = GoForward(a); - continue; - } - } - else if( currOp == asBC_ClrHi ) - { - // T??, ClrHi -> T?? - if( instr && - (instr->op == asBC_TZ || - instr->op == asBC_TNZ || - instr->op == asBC_TS || - instr->op == asBC_TNS || - instr->op == asBC_TP || - instr->op == asBC_TNP) ) - { - // Remove the ClrHi instruction since the test - // instructions always clear the top bytes anyway - instr = GoForward(DeleteInstruction(curr)); - continue; - } - - // ClrHi, JZ -> JLowZ - if( curr->next && - curr->next->op == asBC_JZ ) - { - curr->next->op = asBC_JLowZ; - instr = GoForward(DeleteInstruction(curr)); - continue; - } - - // ClrHi, JNZ -> JLowNZ - if( curr->next && - curr->next->op == asBC_JNZ ) - { - curr->next->op = asBC_JLowNZ; - instr = GoForward(DeleteInstruction(curr)); - continue; - } - } - else if( currOp == asBC_LDV && curr->next ) - { - // LDV x, INCi -> IncVi x - if( curr->next->op == asBC_INCi && !IsTempRegUsed(curr->next) ) - { - curr->op = asBC_IncVi; - DeleteInstruction(curr->next); - instr = GoForward(curr); - } - // LDV x, DECi -> DecVi x - else if( curr->next->op == asBC_DECi && !IsTempRegUsed(curr->next) ) - { - curr->op = asBC_DecVi; - DeleteInstruction(curr->next); - instr = GoForward(curr); - } - } - else if( currOp == asBC_LDG && curr->next ) - { - // LDG x, WRTV4 y -> CpyVtoG4 y, x - if( curr->next->op == asBC_WRTV4 && !IsTempRegUsed(curr->next) ) - { - curr->op = asBC_CpyVtoG4; - curr->size = asBCTypeSize[asBCInfo[asBC_CpyVtoG4].type]; - curr->wArg[0] = curr->next->wArg[0]; - DeleteInstruction(curr->next); - instr = GoForward(curr); - } - // LDG x, RDR4 y -> CpyGtoV4 y, x - else if( curr->next->op == asBC_RDR4 ) - { - if( !IsTempRegUsed(curr->next) ) - curr->op = asBC_CpyGtoV4; - else - curr->op = asBC_LdGRdR4; - curr->size = asBCTypeSize[asBCInfo[asBC_CpyGtoV4].type]; - curr->wArg[0] = curr->next->wArg[0]; - DeleteInstruction(curr->next); - instr = GoForward(curr); - } - } - else if( currOp == asBC_CHKREF ) - { - // CHKREF, ADDSi -> ADDSi - // CHKREF, RDSPtr -> RDSPtr - if( curr->next && - (curr->next->op == asBC_ADDSi || curr->next->op == asBC_RDSPtr) ) - { - // As ADDSi & RDSPtr already checks the pointer the CHKREF instruction is unnecessary - instr = GoForward(DeleteInstruction(curr)); - } - // ADDSi, CHKREF -> ADDSi - // PGA, CHKREF -> PGA - // PSF, CHKREF -> PSF - else if( instr && - (instr->op == asBC_ADDSi || - instr->op == asBC_PGA || - instr->op == asBC_PSF) ) - { - // ADDSi is guaranteed to work on valid pointers so CHKREF is not necessary. - // PGA and PSF always pushes a valid address on the stack. - instr = GoForward(DeleteInstruction(curr)); - } - // PGA, ChkRefS, CHKREF -> PGA, ChkRefS - else if( instr && instr->op == asBC_ChkRefS && - instr->prev && instr->prev->op == asBC_PGA ) - { - // Delete CHKREF since PGA always pushes a valid address on the stack - instr = GoForward(DeleteInstruction(curr)); - } - } - else if( currOp == asBC_PopPtr ) - { - // RDSPtr, PopPtr -> PopPtr - if( instr && instr->op == asBC_RDSPtr ) - { - instr = GoForward(DeleteInstruction(instr)); - } - // PshNull, RefCpyV, PopPtr -> FREE - else if( instr && instr->op == asBC_RefCpyV && - instr->prev && instr->prev->op == asBC_PshNull ) - { - DeleteInstruction(curr); - DeleteInstruction(instr->prev); - instr->op = asBC_FREE; - instr = GoForward(instr); - } - // PshVPtr y, PopPtr -> nothing - // PSF y , PopPtr -> nothing - // VAR y , PopPtr -> nothing - // PshNull , PopPtr -> nothing - // PshRPtr , PopPtr -> nothing - else if( instr && - (instr->op == asBC_PshRPtr || - instr->op == asBC_PSF || - instr->op == asBC_VAR || - instr->op == asBC_PshVPtr || - instr->op == asBC_PshNull) ) - { - // A pointer is pushed on the stack then immediately removed - // Remove both instructions as they cancel each other - DeleteInstruction(curr); - instr = GoForward(DeleteInstruction(instr)); - } - // PSF, ChkRefS, PopPtr -> ChkNullV - else if( instr && instr->op == asBC_ChkRefS && - instr->prev && instr->prev->op == asBC_PSF ) - { - instr = instr->prev; - instr->op = asBC_ChkNullV; - instr->stackInc = 0; - // Delete the PopPtr instruction - DeleteInstruction(curr); - // Delete the ChkRefS instruction - DeleteInstruction(instr->next); - instr = GoForward(instr); - } - // PshVPtr, CHKREF, PopPtr -> ChkNullV - else if( instr && instr->op == asBC_CHKREF && - instr->prev && instr->prev->op == asBC_PshVPtr ) - { - instr = instr->prev; - instr->op = asBC_ChkNullV; - instr->stackInc = 0; - DeleteInstruction(curr->prev); - DeleteInstruction(curr); - instr = GoForward(instr); - } - // STOREOBJ y, PSF y, RDSPtr, PSF x, REFCPY, FREE y, PopPtr -> FREE x, STOREOBJ x - else if( instr && instr->op == asBC_FREE ) - { - asCByteInstruction *i = instr->prev; - if( !i || i->op != asBC_REFCPY ) continue; - i = i->prev; - if( !i || i->op != asBC_PSF ) continue; - short x = i->wArg[0]; - i = i->prev; - if( !i || i->op != asBC_RDSPtr ) continue; - i = i->prev; - if( !i || i->op != asBC_PSF ) continue; - short y = i->wArg[0]; - i = i->prev; - if( !i || i->op != asBC_STOREOBJ || i->wArg[0] != y ) continue; - - // Don't do the substitution if the var y is not a temporary, or if it is used after PopPtr - if( !IsTemporary(y) || IsTempVarRead(curr, y) ) continue; - - // Transform the PopPtr into STOREOBJ - curr->op = asBC_STOREOBJ; - curr->stackInc = 0; - curr->wArg[0] = x; - curr->size = i->size; - - // Change arg of the FREE to x - // TODO: runtime optimize: The FREE instruction shouldn't be necessary. STOREOBJ should free the previous value by itself - instr->wArg[0] = x; - - // Delete all other instructions - DeleteInstruction(instr->prev); // REFCPY - DeleteInstruction(instr->prev); // PSF - DeleteInstruction(instr->prev); // RDSTR - DeleteInstruction(instr->prev); // PSF - DeleteInstruction(instr->prev); // STOREOBJ - - instr = GoForward(curr); - } - } - else if( currOp == asBC_RDSPtr ) - { - // PGA, RDSPtr -> PshGPtr - if( instr && instr->op == asBC_PGA ) - { - instr->op = asBC_PshGPtr; - DeleteInstruction(curr); - instr = GoForward(instr); - } - // ChkRefS, RDSPtr -> RDSPtr, CHKREF - else if( instr && instr->op == asBC_ChkRefS ) - { - // This exchange removes one pointer dereference, and also - // makes it easier to completely remove the CHKREF instruction - curr->op = asBC_CHKREF; - instr->op = asBC_RDSPtr; - instr = GoForward(curr); - } - // PSF, RDSPtr -> PshVPtr - else if( instr && instr->op == asBC_PSF ) - { - instr->op = asBC_PshVPtr; - instr = GoForward(DeleteInstruction(curr)); - } - // PSF, ChkRefS, RDSPtr -> PshVPtr, CHKREF - else if( instr && instr->op == asBC_ChkRefS && - instr->prev && instr->prev->op == asBC_PSF ) - { - instr->prev->op = asBC_PshVPtr; - instr->op = asBC_CHKREF; - instr = GoForward(DeleteInstruction(curr)); - } - } - else if( currOp == asBC_PopRPtr ) - { - // PshVPtr 0, ADDSi, PopRPtr -> LoadThisR - if( instr && instr->op == asBC_ADDSi && - instr->prev && instr->prev->op == asBC_PshVPtr && - instr->prev->wArg[0] == 0 ) - { - DeleteInstruction(instr->prev); - ChangeFirstDeleteNext(instr, asBC_LoadThisR); - instr = GoForward(instr); - } - // TODO: runtime optimize: PshVPtr x, PopRPtr -> LoadRObjR x, 0 - // PshVPtr x, ADDSi, PopRPtr -> LoadRObjR - else if( instr && instr->op == asBC_ADDSi && - instr->prev && instr->prev->op == asBC_PshVPtr && - instr->prev->wArg[0] != 0 ) - { - instr = instr->prev; - instr->op = asBC_LoadRObjR; - instr->size = asBCTypeSize[asBCInfo[asBC_LoadRObjR].type]; - instr->stackInc = asBCInfo[asBC_LoadRObjR].stackInc; - instr->wArg[1] = instr->next->wArg[0]; - *(asDWORD*)&instr->arg = *(asDWORD*)&instr->next->arg; - DeleteInstruction(instr->next); - DeleteInstruction(curr); - instr = GoForward(instr); - } - // PSF x, ADDSi, PopRPtr -> LoadVObjR - else if( instr && instr->op == asBC_ADDSi && - instr->prev && instr->prev->op == asBC_PSF ) - { - instr = instr->prev; - instr->op = asBC_LoadVObjR; - instr->size = asBCTypeSize[asBCInfo[asBC_LoadVObjR].type]; - instr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc; - instr->wArg[1] = instr->next->wArg[0]; - *(asDWORD*)&instr->arg = *(asDWORD*)&instr->next->arg; - DeleteInstruction(instr->next); - DeleteInstruction(curr); - instr = GoForward(instr); - } - } - else if( currOp == asBC_REFCPY ) - { - // PSF x, REFCPY -> RefCpyV x - if( instr && instr->op == asBC_PSF ) - { - curr->op = asBC_RefCpyV; - curr->wArg[0] = instr->wArg[0]; - curr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc; - DeleteInstruction(instr); - instr = GoForward(curr); - } - } - else if( ((currOp >= asBC_JZ && currOp <= asBC_JNP) || currOp == asBC_JLowZ || currOp == asBC_JLowNZ) && instr ) - { - // T**; J** +x -> J** +x - if( (instr->op == asBC_TZ && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || - (instr->op == asBC_TNZ && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) - instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNZ)); - else if( (instr->op == asBC_TNZ && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || - (instr->op == asBC_TZ && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) - instr = GoForward(DeleteFirstChangeNext(instr, asBC_JZ)); - else if( (instr->op == asBC_TS && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || - (instr->op == asBC_TNS && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) - instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNS)); - else if( (instr->op == asBC_TNS && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || - (instr->op == asBC_TS && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) - instr = GoForward(DeleteFirstChangeNext(instr, asBC_JS)); - else if( (instr->op == asBC_TP && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || - (instr->op == asBC_TNP && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) - instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNP)); - else if( (instr->op == asBC_TNP && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || - (instr->op == asBC_TP && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) - instr = GoForward(DeleteFirstChangeNext(instr, asBC_JP)); - } - else if( currOp == asBC_FREE && instr ) - { - // PSF, FREE -> FREE, PSF - if( instr->op == asBC_PSF ) - { - // This pattern usually happens when a function returns an object, or handle - // and then releases a temporary variable, possibly used in one of the arguments. - // By swapping the order of these instructions, the code can be further optimized - // to combine the PSF with the following instructions - RemoveInstruction(curr); - InsertBefore(instr, curr); - instr = GoForward(instr); - } - // VAR, FREE -> FREE, VAR - else if( instr->op == asBC_VAR ) - { - // Swap the two instructions, so that the VAR instruction - // gets closer to its corresponding GET instruction and thus - // has a greater chance of getting optimized - RemoveInstruction(curr); - InsertBefore(instr, curr); - instr = GoForward(instr); - } - } - else if( currOp == asBC_VAR ) - { - // VAR, PSF, GETOBJREF {PTR_SIZE} -> PshVPtr, PSF - if( curr->next && curr->next->op == asBC_PSF && - curr->next->next && curr->next->next->op == asBC_GETOBJREF && - curr->next->next->wArg[0] == AS_PTR_SIZE ) - { - curr->op = asBC_PshVPtr; - DeleteInstruction(curr->next->next); - instr = GoForward(curr); - } - // VAR a, GETREF 0 -> PSF a - else if( curr->next && curr->next->op == asBC_GETREF && curr->next->wArg[0] == 0 ) - { - ChangeFirstDeleteNext(curr, asBC_PSF); - instr = GoForward(curr); - } - } - } - - // Optimize unnecessary refcpy for return handle. This scenario only happens for return statements - // and LOADOBJ can only be the last instruction before the RET, so doing this check after the rest of - // the optimizations have taken place saves us time. - if( last && last->op == asBC_LOADOBJ && IsTemporary(last->wArg[0]) ) - { - // A temporary handle is being loaded into the object register. - // Let's look for a trivial RefCpyV to that temporary variable, and a Free of the original - // variable. If this is found, then we can simply load the original value into the register - // and avoid both the RefCpy and the Free. - short tempVar = last->wArg[0]; - asCArray freedVars; - - asCByteInstruction *instr = last->prev; - asASSERT( instr && instr->op == asBC_Block ); - instr = instr->prev; - while( instr && instr->op == asBC_FREE ) - { - freedVars.PushLast(instr->wArg[0]); - instr = instr->prev; - } - - // If there is any non-trivial cleanups, e.g. call to destructors, then we skip this optimizations - // TODO: runtime optimize: Do we need to skip it? Is there really a chance the local variable - // will be invalidated while the destructor, or any other function for - // that matter, is being called? - if( instr && instr->op == asBC_Block ) - { - // We expect a sequence PshVPtr, RefCpyV, PopPtr just before the clean up block - instr = instr->prev; - if( instr && instr->op == asBC_PopPtr ) instr = instr->prev; - if( instr && instr->op == asBC_RefCpyV && instr->wArg[0] == tempVar ) instr = instr->prev; - if( instr && instr->op == asBC_PshVPtr && freedVars.Exists(instr->wArg[0]) ) - { - // Update the LOADOBJ to load the local variable directly - tempVar = instr->wArg[0]; - last->wArg[0] = tempVar; - - // Remove the copy of the local variable into the temp - DeleteInstruction(instr->next); // deletes RefCpyV - DeleteInstruction(instr->next); // deletes PopPtr - DeleteInstruction(instr); // deletes PshVPtr - - // Find and remove the FREE instruction for the local variable too - instr = last->prev->prev; - while( instr ) - { - asASSERT( instr->op == asBC_FREE ); - if( instr->wArg[0] == tempVar ) - { - DeleteInstruction(instr); - break; - } - instr = instr->prev; - } - } - } - } -} - -void asCByteCode::Optimize() -{ - // This function performs the optimizations that require global knowledge of the entire function - - TimeIt("asCByteCode::Optimize"); - - if( !engine->ep.optimizeByteCode ) - return; - - // TODO: runtime optimize: The optimizer should be able to inline function calls. - // If the called function has only a few instructions, the function call should be inlined. - // This is especially useful with the factory stubs used for template types and script classes. - - asCByteInstruction *instr = first; - while( instr ) - { - asCByteInstruction *curr = instr; - instr = instr->next; - - const asEBCInstr currOp = curr->op; - - // Delete JitEntry if the JIT instructions are not supposed to be included - if( currOp == asBC_JitEntry && !engine->ep.includeJitInstructions ) - { - instr = GoBack(DeleteInstruction(curr)); - continue; - } - - if( instr ) - { - const asEBCInstr instrOp = instr->op; - - // PopPtr, RET b -> RET b - if( currOp == asBC_PopPtr && instrOp == asBC_RET ) - { - // We don't combine the PopPtr+RET because RET first restores - // the previous stack pointer and then pops the arguments - - // Delete PopPtr - instr = GoBack(DeleteInstruction(curr)); - } - else if( currOp == asBC_SUSPEND ) - { - // SUSPEND, JitEntry, SUSPEND -> SUSPEND - if( instrOp == asBC_JitEntry && instr->next && instr->next->op == asBC_SUSPEND ) - { - // Delete the two first instructions - DeleteInstruction(instr); - instr = GoBack(DeleteInstruction(curr)); - } - // SUSPEND, SUSPEND -> SUSPEND - else if( instrOp == asBC_SUSPEND ) - { - // Delete the first instruction - instr = GoBack(DeleteInstruction(curr)); - } - // SUSPEND, Block, SUSPEND -> Block, SUSPEND - else if( instrOp == asBC_Block && instr->next && instr->next->op == asBC_SUSPEND ) - { - // Delete the first instruction - instr = GoBack(DeleteInstruction(curr)); - } - } - else if( currOp == asBC_LINE ) - { - // LINE, JitEntry, LINE -> LINE - if( instrOp == asBC_JitEntry && instr->next && instr->next->op == asBC_LINE ) - { - // Delete the two first instructions - DeleteInstruction(instr); - instr = GoBack(DeleteInstruction(curr)); - } - // LINE, LINE -> LINE - else if( instrOp == asBC_LINE ) - { - // Delete the first instruction - instr = GoBack(DeleteInstruction(curr)); - } - // LINE, Block, LINE -> Block, LINE - else if( instrOp == asBC_Block && instr->next && instr->next->op == asBC_LINE ) - { - // Delete the first instruction - instr = GoBack(DeleteInstruction(curr)); - } - } - // JMP +0 -> remove - else if( currOp == asBC_JMP && instrOp == asBC_LABEL && *(int*)&curr->arg == instr->wArg[0] ) - instr = GoBack(DeleteInstruction(curr)); - } - } -} - -bool asCByteCode::IsTempVarReadByInstr(asCByteInstruction *curr, int offset) -{ - // Which instructions read from variables? - if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG && - (int(curr->wArg[1]) == offset || int(curr->wArg[2]) == offset) ) - return true; - else if( (asBCInfo[curr->op].type == asBCTYPE_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_QW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG || - curr->op == asBC_FREE) && // FREE both read and write to the variable - int(curr->wArg[0]) == offset ) - return true; - else if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG) && - int(curr->wArg[1]) == offset ) - return true; - else if( asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG && - (int(curr->wArg[0]) == offset || int(curr->wArg[1]) == offset) ) - return true; - else if( curr->op == asBC_LoadThisR && offset == 0 ) - return true; - - return false; -} - -bool asCByteCode::IsInstrJmpOrLabel(asCByteInstruction *curr) -{ - if( curr->op == asBC_JS || - curr->op == asBC_JNS || - curr->op == asBC_JP || - curr->op == asBC_JNP || - curr->op == asBC_JMPP || - curr->op == asBC_JMP || - curr->op == asBC_JZ || - curr->op == asBC_JNZ || - curr->op == asBC_JLowZ || - curr->op == asBC_JLowNZ || - curr->op == asBC_LABEL ) - return true; - - return false; -} - -bool asCByteCode::IsTempVarOverwrittenByInstr(asCByteInstruction *curr, int offset) -{ - // Which instructions overwrite the variable or discard it? - if( curr->op == asBC_RET || - curr->op == asBC_SUSPEND ) - return true; - else if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || - asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) && - int(curr->wArg[0]) == offset ) - return true; - - return false; -} - -bool asCByteCode::IsTempVarRead(asCByteInstruction *curr, int offset) -{ - TimeIt("asCByteCode::IsTempVarRead"); - - asCArray openPaths; - asCArray closedPaths; - - // We're not interested in the first instruction, since it is the one that sets the variable - openPaths.PushLast(curr->next); - - while( openPaths.GetLength() ) - { - curr = openPaths.PopLast(); - - // Add the instruction to the closed paths so that we don't verify it again - closedPaths.PushLast(curr); - - while( curr ) - { - if( IsTempVarReadByInstr(curr, offset) ) - return true; - - if( IsTempVarOverwrittenByInstr(curr, offset) ) break; - - // In case of jumps, we must follow the each of the paths - if( curr->op == asBC_JMP ) - { - // Find the destination. If it cannot be found it is because we're doing a localized - // optimization and the label hasn't been added to the final bytecode yet - - int label = *((int*)ARG_DW(curr->arg)); - int r = FindLabel(label, curr, &curr, 0); - if( r >= 0 && - !closedPaths.Exists(curr) && - !openPaths.Exists(curr) ) - openPaths.PushLast(curr); - - break; - } - else if( curr->op == asBC_JZ || curr->op == asBC_JNZ || - curr->op == asBC_JS || curr->op == asBC_JNS || - curr->op == asBC_JP || curr->op == asBC_JNP || - curr->op == asBC_JLowZ || curr->op == asBC_JLowNZ ) - { - // Find the destination. If it cannot be found it is because we're doing a localized - // optimization and the label hasn't been added to the final bytecode yet - - asCByteInstruction *dest = 0; - int label = *((int*)ARG_DW(curr->arg)); - int r = FindLabel(label, curr, &dest, 0); - if( r >= 0 && - !closedPaths.Exists(dest) && - !openPaths.Exists(dest) ) - openPaths.PushLast(dest); - } - else if( curr->op == asBC_JMPP ) - { - // A JMPP instruction is always followed by a series of JMP instructions - // that give the real destination (like a look-up table). We need add all - // of these as open paths. - curr = curr->next; - while( curr->op == asBC_JMP ) - { - // Find the destination. If it cannot be found it is because we're doing a localized - // optimization and the label hasn't been added to the final bytecode yet - - asCByteInstruction *dest = 0; - int label = *((int*)ARG_DW(curr->arg)); - int r = FindLabel(label, curr, &dest, 0); - if( r >= 0 && - !closedPaths.Exists(dest) && - !openPaths.Exists(dest) ) - openPaths.PushLast(dest); - - curr = curr->next; - } - - // We should now be on a label which is the destination of the - // first JMP in the sequence and is already added in the open paths - asASSERT(curr->op == asBC_LABEL); - break; - } - - curr = curr->next; - } - } - - return false; -} - -bool asCByteCode::IsTempRegUsed(asCByteInstruction *curr) -{ - TimeIt("asCByteCode::IsTempRegUsed"); - - // We're not interested in the first instruction, since it is the one that sets the register - while( curr->next ) - { - curr = curr->next; - - // Which instructions read from the register? - if( curr->op == asBC_INCi || - curr->op == asBC_INCi16 || - curr->op == asBC_INCi8 || - curr->op == asBC_INCf || - curr->op == asBC_INCd || - curr->op == asBC_DECi || - curr->op == asBC_DECi16 || - curr->op == asBC_DECi8 || - curr->op == asBC_DECf || - curr->op == asBC_DECd || - curr->op == asBC_WRTV1 || - curr->op == asBC_WRTV2 || - curr->op == asBC_WRTV4 || - curr->op == asBC_WRTV8 || - curr->op == asBC_RDR1 || - curr->op == asBC_RDR2 || - curr->op == asBC_RDR4 || - curr->op == asBC_RDR8 || - curr->op == asBC_PshRPtr || - curr->op == asBC_CpyRtoV4 || - curr->op == asBC_CpyRtoV8 || - curr->op == asBC_TZ || - curr->op == asBC_TNZ || - curr->op == asBC_TS || - curr->op == asBC_TNS || - curr->op == asBC_TP || - curr->op == asBC_TNP || - curr->op == asBC_JZ || - curr->op == asBC_JNZ || - curr->op == asBC_JLowZ || - curr->op == asBC_JLowNZ || - curr->op == asBC_JS || - curr->op == asBC_JNS || - curr->op == asBC_JP || - curr->op == asBC_JNP ) - return true; - - // Which instructions overwrite the register or discard the value? - if( curr->op == asBC_CALL || - curr->op == asBC_PopRPtr || - curr->op == asBC_CALLSYS || - curr->op == asBC_CALLBND || - curr->op == asBC_SUSPEND || - curr->op == asBC_ALLOC || - curr->op == asBC_CpyVtoR4 || - curr->op == asBC_LdGRdR4 || - curr->op == asBC_LDG || - curr->op == asBC_LDV || - curr->op == asBC_TZ || - curr->op == asBC_TNZ || - curr->op == asBC_TS || - curr->op == asBC_TNS || - curr->op == asBC_TP || - curr->op == asBC_TNP || - curr->op == asBC_JS || - curr->op == asBC_JNS || - curr->op == asBC_JP || - curr->op == asBC_JNP || - curr->op == asBC_JMPP || - curr->op == asBC_JMP || - curr->op == asBC_JZ || - curr->op == asBC_JNZ || - curr->op == asBC_JLowZ || - curr->op == asBC_JLowNZ || - curr->op == asBC_CMPi || - curr->op == asBC_CMPu || - curr->op == asBC_CMPf || - curr->op == asBC_CMPd || - curr->op == asBC_CMPIi || - curr->op == asBC_CMPIu || - curr->op == asBC_CMPIf || - curr->op == asBC_LABEL || - curr->op == asBC_LoadThisR || - curr->op == asBC_LoadRObjR || - curr->op == asBC_LoadVObjR ) - return false; - } - - return false; -} - -bool asCByteCode::IsSimpleExpression() -{ - // A simple expression is one that cannot be suspended at any time, i.e. - // it doesn't have any calls to other routines, and doesn't have any suspend instructions - asCByteInstruction *instr = first; - while( instr ) - { - if( instr->op == asBC_ALLOC || - instr->op == asBC_CALL || - instr->op == asBC_CALLSYS || - instr->op == asBC_SUSPEND || - instr->op == asBC_LINE || - instr->op == asBC_FREE || - instr->op == asBC_CallPtr || - instr->op == asBC_CALLINTF || - instr->op == asBC_CALLBND ) - return false; - - instr = instr->next; - } - - return true; -} - -void asCByteCode::ExtractLineNumbers() -{ - // This function will extract the line number and source file for each statement by looking for LINE instructions. - // The LINE instructions will be converted to SUSPEND instructions, or removed depending on the configuration. - - TimeIt("asCByteCode::ExtractLineNumbers"); - - int lastLinePos = -1; - int pos = 0; - asCByteInstruction *instr = first; - while( instr ) - { - asCByteInstruction *curr = instr; - instr = instr->next; - - if( curr->op == asBC_LINE ) - { - if( lastLinePos == pos ) - { - lineNumbers.PopLast(); // pop position - lineNumbers.PopLast(); // pop line number - sectionIdxs.PopLast(); // pop section index - } - - lastLinePos = pos; - lineNumbers.PushLast(pos); - lineNumbers.PushLast(*(int*)ARG_DW(curr->arg)); - sectionIdxs.PushLast(*((int*)ARG_DW(curr->arg)+1)); - - if( !engine->ep.buildWithoutLineCues ) - { - // Transform BC_LINE into BC_SUSPEND - curr->op = asBC_SUSPEND; - curr->size = asBCTypeSize[asBCInfo[asBC_SUSPEND].type]; - pos += curr->size; - } - else - { - // Delete the instruction - DeleteInstruction(curr); - } - } - else - pos += curr->size; - } -} - -void asCByteCode::ExtractObjectVariableInfo(asCScriptFunction *outFunc) -{ - asASSERT( outFunc->scriptData ); - - unsigned int pos = 0; - asCByteInstruction *instr = first; - int blockLevel = 0; - while( instr ) - { - if( instr->op == asBC_Block ) - { - asSObjectVariableInfo info; - info.programPos = pos; - info.variableOffset = 0; - info.option = instr->wArg[0] ? asBLOCK_BEGIN : asBLOCK_END; - if( info.option == asBLOCK_BEGIN ) - { - blockLevel++; - outFunc->scriptData->objVariableInfo.PushLast(info); - } - else - { - blockLevel--; - asASSERT( blockLevel >= 0 ); - if( outFunc->scriptData->objVariableInfo[outFunc->scriptData->objVariableInfo.GetLength()-1].option == asBLOCK_BEGIN && - outFunc->scriptData->objVariableInfo[outFunc->scriptData->objVariableInfo.GetLength()-1].programPos == pos ) - outFunc->scriptData->objVariableInfo.PopLast(); - else - outFunc->scriptData->objVariableInfo.PushLast(info); - } - } - else if( instr->op == asBC_ObjInfo ) - { - asSObjectVariableInfo info; - info.programPos = pos; - info.variableOffset = (short)instr->wArg[0]; - info.option = *(int*)ARG_DW(instr->arg); - outFunc->scriptData->objVariableInfo.PushLast(info); - } - else if( instr->op == asBC_VarDecl ) - { - outFunc->scriptData->variables[instr->wArg[0]]->declaredAtProgramPos = pos; - } - else - pos += instr->size; - - instr = instr->next; - } - asASSERT( blockLevel == 0 ); -} - -int asCByteCode::GetSize() -{ - int size = 0; - asCByteInstruction *instr = first; - while( instr ) - { - size += instr->GetSize(); - - instr = instr->next; - } - - return size; -} - -void asCByteCode::AddCode(asCByteCode *bc) -{ - if( bc == this ) return; - if( bc->first ) - { - if( first == 0 ) - { - first = bc->first; - last = bc->last; - bc->first = 0; - bc->last = 0; - } - else - { - last->next = bc->first; - bc->first->prev = last; - last = bc->last; - bc->first = 0; - bc->last = 0; - } - } -} - -int asCByteCode::AddInstruction() -{ - void *ptr = engine->memoryMgr.AllocByteInstruction(); - if( ptr == 0 ) - { - // Out of memory - return 0; - } - - asCByteInstruction *instr = new(ptr) asCByteInstruction(); - if( first == 0 ) - { - first = last = instr; - } - else - { - last->AddAfter(instr); - last = instr; - } - - return 0; -} - -int asCByteCode::AddInstructionFirst() -{ - void *ptr = engine->memoryMgr.AllocByteInstruction(); - if( ptr == 0 ) - { - // Out of memory - return 0; - } - - asCByteInstruction *instr = new(ptr) asCByteInstruction(); - if( first == 0 ) - { - first = last = instr; - } - else - { - first->AddBefore(instr); - first = instr; - } - - return 0; -} - -void asCByteCode::Call(asEBCInstr instr, int funcID, int pop) -{ - if( AddInstruction() < 0 ) - return; - - asASSERT(asBCInfo[instr].type == asBCTYPE_DW_ARG); - - last->op = instr; - last->size = asBCTypeSize[asBCInfo[instr].type]; - last->stackInc = -pop; // BC_CALL and BC_CALLBND doesn't pop the argument but when the callee returns the arguments are already popped - *((int*)ARG_DW(last->arg)) = funcID; - - // Add a JitEntry instruction after function calls so that JIT's can resume execution - InstrPTR(asBC_JitEntry, 0); -} - -void asCByteCode::CallPtr(asEBCInstr instr, int funcPtrVar, int pop) -{ - if( AddInstruction() < 0 ) - return; - - asASSERT(asBCInfo[instr].type == asBCTYPE_rW_ARG); - - last->op = instr; - last->size = asBCTypeSize[asBCInfo[instr].type]; - last->stackInc = -pop; - last->wArg[0] = (short)funcPtrVar; - - // Add a JitEntry instruction after function calls so that JIT's can resume execution - InstrPTR(asBC_JitEntry, 0); -} - -void asCByteCode::Alloc(asEBCInstr instr, void *objID, int funcID, int pop) -{ - if( AddInstruction() < 0 ) - return; - - last->op = instr; - last->size = asBCTypeSize[asBCInfo[instr].type]; - last->stackInc = -pop; // BC_ALLOC - - asASSERT(asBCInfo[instr].type == asBCTYPE_PTR_DW_ARG); - *ARG_PTR(last->arg) = (asPWORD)objID; - *((int*)(ARG_DW(last->arg)+AS_PTR_SIZE)) = funcID; - - // Add a JitEntry instruction after function calls so that JIT's can resume execution - InstrPTR(asBC_JitEntry, 0); -} - -void asCByteCode::Ret(int pop) -{ - if( AddInstruction() < 0 ) - return; - - asASSERT(asBCInfo[asBC_RET].type == asBCTYPE_W_ARG); - - last->op = asBC_RET; - last->size = asBCTypeSize[asBCInfo[asBC_RET].type]; - last->stackInc = 0; // The instruction pops the argument, but it doesn't affect current function - last->wArg[0] = (short)pop; -} - -void asCByteCode::JmpP(int var, asDWORD max) -{ - if( AddInstruction() < 0 ) - return; - - asASSERT(asBCInfo[asBC_JMPP].type == asBCTYPE_rW_ARG); - - last->op = asBC_JMPP; - last->size = asBCTypeSize[asBCInfo[asBC_JMPP].type]; - last->stackInc = asBCInfo[asBC_JMPP].stackInc; - last->wArg[0] = (short)var; - - // Store the largest jump that is made for PostProcess() - *ARG_DW(last->arg) = max; -} - -void asCByteCode::Label(short label) -{ - if( AddInstruction() < 0 ) - return; - - last->op = asBC_LABEL; - last->size = 0; - last->stackInc = 0; - last->wArg[0] = label; -} - -void asCByteCode::Line(int line, int column, int scriptIdx) -{ - if( AddInstruction() < 0 ) - return; - - last->op = asBC_LINE; - // If the build is without line cues these instructions will be removed - // otherwise they will be transformed into SUSPEND instructions. - if( engine->ep.buildWithoutLineCues ) - last->size = 0; - else - last->size = asBCTypeSize[asBCInfo[asBC_SUSPEND].type]; - last->stackInc = 0; - *((int*)ARG_DW(last->arg)) = (line & 0xFFFFF)|((column & 0xFFF)<<20); - *((int*)ARG_DW(last->arg)+1) = scriptIdx; - - // Add a JitEntry after the line instruction to allow the JIT function to resume after a suspend - InstrPTR(asBC_JitEntry, 0); -} - -void asCByteCode::ObjInfo(int offset, int info) -{ - if( AddInstruction() < 0 ) - return; - - // Add the special instruction that will be used to tell the exception - // handler when an object is initialized and deinitialized. - last->op = asBC_ObjInfo; - last->size = 0; - last->stackInc = 0; - last->wArg[0] = (short)offset; - *((int*)ARG_DW(last->arg)) = info; -} - -void asCByteCode::Block(bool start) -{ - if( AddInstruction() < 0 ) - return; - - last->op = asBC_Block; - last->size = 0; - last->stackInc = 0; - last->wArg[0] = start ? 1 : 0; -} - -void asCByteCode::VarDecl(int varDeclIdx) -{ - if( AddInstruction() < 0 ) - return; - - last->op = asBC_VarDecl; - last->size = 0; - last->stackInc = 0; - last->wArg[0] = asWORD(varDeclIdx); -} - -int asCByteCode::FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta) -{ - TimeIt("asCByteCode::FindLabel"); - - // Search forward - int labelPos = -from->GetSize(); - - asCByteInstruction *labelInstr = from; - while( labelInstr ) - { - labelPos += labelInstr->GetSize(); - labelInstr = labelInstr->next; - - if( labelInstr && labelInstr->op == asBC_LABEL ) - { - if( labelInstr->wArg[0] == label ) - break; - } - } - - if( labelInstr == 0 ) - { - // Search backwards - labelPos = -from->GetSize(); - - labelInstr = from; - while( labelInstr ) - { - labelInstr = labelInstr->prev; - if( labelInstr ) - { - labelPos -= labelInstr->GetSize(); - - if( labelInstr->op == asBC_LABEL ) - { - if( labelInstr->wArg[0] == label ) - break; - } - } - } - } - - if( labelInstr != 0 ) - { - if( dest ) *dest = labelInstr; - if( positionDelta ) *positionDelta = labelPos; - return 0; - } - - return -1; -} - -int asCByteCode::ResolveJumpAddresses() -{ - TimeIt("asCByteCode::ResolveJumpAddresses"); - - asCByteInstruction *instr = first; - while( instr ) - { - if( instr->op == asBC_JMP || - instr->op == asBC_JZ || instr->op == asBC_JNZ || - instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ || - instr->op == asBC_JS || instr->op == asBC_JNS || - instr->op == asBC_JP || instr->op == asBC_JNP ) - { - int label = *((int*) ARG_DW(instr->arg)); - int labelPosOffset; - int r = FindLabel(label, instr, 0, &labelPosOffset); - if( r == 0 ) - *((int*) ARG_DW(instr->arg)) = labelPosOffset; - else - return -1; - } - - instr = instr->next; - } - - return 0; -} - - -asCByteInstruction *asCByteCode::DeleteInstruction(asCByteInstruction *instr) -{ - if( instr == 0 ) return 0; - - asCByteInstruction *ret = instr->prev ? instr->prev : instr->next; - - RemoveInstruction(instr); - - engine->memoryMgr.FreeByteInstruction(instr); - - return ret; -} - -void asCByteCode::Output(asDWORD *array) -{ - TimeIt("asCByteCode::Output"); - - // TODO: Receive a script function pointer instead of the bytecode array - - asDWORD *ap = array; - - asCByteInstruction *instr = first; - while( instr ) - { - if( instr->GetSize() > 0 ) - { - *(asBYTE*)ap = asBYTE(instr->op); - *(((asBYTE*)ap)+1) = 0; // Second byte is always zero - switch( asBCInfo[instr->op].type ) - { - case asBCTYPE_NO_ARG: - *(((asWORD*)ap)+1) = 0; // Clear upper bytes - break; - case asBCTYPE_wW_rW_rW_ARG: - *(((asWORD*)ap)+1) = instr->wArg[0]; - *(((asWORD*)ap)+2) = instr->wArg[1]; - *(((asWORD*)ap)+3) = instr->wArg[2]; - break; - case asBCTYPE_wW_DW_ARG: - case asBCTYPE_rW_DW_ARG: - case asBCTYPE_W_DW_ARG: - *(((asWORD*)ap)+1) = instr->wArg[0]; - *(ap+1) = *(asDWORD*)&instr->arg; - break; - case asBCTYPE_wW_rW_DW_ARG: - case asBCTYPE_rW_W_DW_ARG: - *(((asWORD*)ap)+1) = instr->wArg[0]; - *(((asWORD*)ap)+2) = instr->wArg[1]; - *(ap+2) = *(asDWORD*)&instr->arg; - break; - case asBCTYPE_wW_QW_ARG: - case asBCTYPE_rW_QW_ARG: - *(((asWORD*)ap)+1) = instr->wArg[0]; - *(asQWORD*)(ap+1) = asQWORD(instr->arg); - break; - case asBCTYPE_W_ARG: - case asBCTYPE_rW_ARG: - case asBCTYPE_wW_ARG: - *(((asWORD*)ap)+1) = instr->wArg[0]; - break; - case asBCTYPE_wW_rW_ARG: - case asBCTYPE_rW_rW_ARG: - case asBCTYPE_wW_W_ARG: - *(((asWORD *)ap)+1) = instr->wArg[0]; - *(((asWORD *)ap)+2) = instr->wArg[1]; - break; - case asBCTYPE_QW_DW_ARG: - case asBCTYPE_DW_DW_ARG: - case asBCTYPE_QW_ARG: - case asBCTYPE_DW_ARG: - *(((asWORD*)ap)+1) = 0; // Clear upper bytes - memcpy(ap+1, &instr->arg, instr->GetSize()*4-4); - break; - case asBCTYPE_rW_DW_DW_ARG: - *(((asWORD*)ap)+1) = instr->wArg[0]; - memcpy(ap+1, &instr->arg, instr->GetSize()*4-4); - break; - default: - // How did we get here? - asASSERT(false); - break; - } - } - - ap += instr->GetSize(); - instr = instr->next; - } -} - -void asCByteCode::PostProcess() -{ - TimeIt("asCByteCode::PostProcess"); - - if( first == 0 ) return; - - // This function will do the following - // - Verify if there is any code that never gets executed and remove it - // - Calculate the stack size at the position of each byte code - // - Calculate the largest stack needed - - largestStackUsed = 0; - - asCByteInstruction *instr = first; - while( instr ) - { - instr->marked = false; - instr->stackSize = -1; - instr = instr->next; - } - - // Add the first instruction to the list of unchecked code paths - asCArray paths; - AddPath(paths, first, 0); - - // Go through each of the code paths - for( asUINT p = 0; p < paths.GetLength(); ++p ) - { - instr = paths[p]; - int stackSize = instr->stackSize; - - while( instr ) - { - instr->marked = true; - instr->stackSize = stackSize; - stackSize += instr->stackInc; - if( stackSize > largestStackUsed ) - largestStackUsed = stackSize; - - if( instr->op == asBC_JMP ) - { - // Find the label that we should jump to - int label = *((int*) ARG_DW(instr->arg)); - asCByteInstruction *dest = 0; - int r = FindLabel(label, instr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r); - - AddPath(paths, dest, stackSize); - break; - } - else if( instr->op == asBC_JZ || instr->op == asBC_JNZ || - instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ || - instr->op == asBC_JS || instr->op == asBC_JNS || - instr->op == asBC_JP || instr->op == asBC_JNP ) - { - // Find the label that is being jumped to - int label = *((int*) ARG_DW(instr->arg)); - asCByteInstruction *dest = 0; - int r = FindLabel(label, instr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r); - - AddPath(paths, dest, stackSize); - - // Add both paths to the code paths - AddPath(paths, instr->next, stackSize); - - break; - } - else if( instr->op == asBC_JMPP ) - { - // I need to know the largest value possible - asDWORD max = *ARG_DW(instr->arg); - - // Add all destinations to the code paths - asCByteInstruction *dest = instr->next; - for( asDWORD n = 0; n <= max && dest != 0; ++n ) - { - AddPath(paths, dest, stackSize); - dest = dest->next; - } - - break; - } - else - { - instr = instr->next; - if( instr == 0 || instr->marked ) - break; - } - } - } - - // Are there any instructions that didn't get visited? - instr = first; - while( instr ) - { - // Don't remove asBC_Block instructions as then the start and end of blocks may become mismatched - if( instr->marked == false && instr->op != asBC_Block ) - { - // Remove it - asCByteInstruction *curr = instr; - instr = instr->next; - DeleteInstruction(curr); - } - else - instr = instr->next; - } -} - -#ifdef AS_DEBUG -void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScriptFunction *func) -{ - _mkdir("AS_DEBUG"); - - asCString str = "AS_DEBUG/"; - str += name; - -#if _MSC_VER >= 1500 && !defined(AS_MARMALADE) - FILE *file; - fopen_s(&file, str.AddressOf(), "w"); -#else - FILE *file = fopen(str.AddressOf(), "w"); -#endif - -#if !defined(AS_XENON) // XBox 360: When running in DVD Emu, no write is allowed - asASSERT( file ); -#endif - - if( file == 0 ) - return; - - asUINT n; - - fprintf(file, "%s\n\n", func->GetDeclaration()); - - fprintf(file, "Temps: "); - for( n = 0; n < temporaryVariables->GetLength(); n++ ) - { - fprintf(file, "%d", (*temporaryVariables)[n]); - if( n < temporaryVariables->GetLength()-1 ) - fprintf(file, ", "); - } - fprintf(file, "\n\n"); - - fprintf(file, "Variables: \n"); - for( n = 0; n < func->scriptData->variables.GetLength(); n++ ) - { - int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->variables[n]->stackOffset); - bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false; - fprintf(file, " %.3d: %s%s %s\n", func->scriptData->variables[n]->stackOffset, isOnHeap ? "(heap) " : "", func->scriptData->variables[n]->type.Format().AddressOf(), func->scriptData->variables[n]->name.AddressOf()); - } - asUINT offset = 0; - if( func->objectType ) - { - fprintf(file, " %.3d: %s this\n", 0, func->objectType->name.AddressOf()); - offset -= AS_PTR_SIZE; - } - for( n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - bool found = false; - for( asUINT v = 0; v < func->scriptData->variables.GetLength(); v++ ) - { - if( func->scriptData->variables[v]->stackOffset == (int)offset ) - { - found = true; - break; - } - } - if( !found ) - { - int idx = func->scriptData->objVariablePos.IndexOf(offset); - bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false; - fprintf(file, " %.3d: %s%s {noname param}\n", offset, isOnHeap ? "(heap) " : "", func->parameterTypes[n].Format().AddressOf()); - } - - offset -= func->parameterTypes[n].GetSizeOnStackDWords(); - } - for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ ) - { - bool found = false; - for( asUINT v = 0; v < func->scriptData->variables.GetLength(); v++ ) - { - if( func->scriptData->variables[v]->stackOffset == func->scriptData->objVariablePos[n] ) - { - found = true; - break; - } - } - if( !found ) - { - if( func->scriptData->objVariableTypes[n] ) - { - int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->objVariablePos[n]); - bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false; - fprintf(file, " %.3d: %s%s {noname}\n", func->scriptData->objVariablePos[n], isOnHeap ? "(heap) " : "", func->scriptData->objVariableTypes[n]->name.AddressOf()); - } - else - fprintf(file, " %.3d: null handle {noname}\n", func->scriptData->objVariablePos[n]); - } - } - fprintf(file, "\n\n"); - - int pos = 0; - asUINT lineIndex = 0; - asCByteInstruction *instr = first; - while( instr ) - { - if( lineIndex < lineNumbers.GetLength() && lineNumbers[lineIndex] == pos ) - { - asDWORD line = lineNumbers[lineIndex+1]; - fprintf(file, "- %d,%d -\n", (int)(line&0xFFFFF), (int)(line>>20)); - lineIndex += 2; - } - - fprintf(file, "%5d ", pos); - pos += instr->GetSize(); - - fprintf(file, "%3d %c ", int(instr->stackSize + func->scriptData->variableSpace), instr->marked ? '*' : ' '); - - 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]); - break; - - case asBCTYPE_wW_ARG: - case asBCTYPE_rW_ARG: - fprintf(file, " %-8s v%d\n", asBCInfo[instr->op].name, instr->wArg[0]); - break; - - case asBCTYPE_wW_rW_ARG: - case asBCTYPE_rW_rW_ARG: - fprintf(file, " %-8s v%d, v%d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1]); - break; - - case asBCTYPE_wW_W_ARG: - fprintf(file, " %-8s v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1]); - break; - - case asBCTYPE_wW_rW_DW_ARG: - case asBCTYPE_rW_W_DW_ARG: - switch( instr->op ) - { - case asBC_ADDIf: - case asBC_SUBIf: - case asBC_MULIf: - fprintf(file, " %-8s v%d, v%d, %f\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], *((float*) ARG_DW(instr->arg))); - break; - default: - fprintf(file, " %-8s v%d, v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], *((int*) ARG_DW(instr->arg))); - break; - } - break; - - case asBCTYPE_DW_ARG: - switch( instr->op ) - { - case asBC_OBJTYPE: - fprintf(file, " %-8s 0x%x\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg)); - break; - - case asBC_PshC4: - case asBC_Cast: - fprintf(file, " %-8s 0x%x (i:%d, f:%g)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), *((int*) ARG_DW(instr->arg)), *((float*) ARG_DW(instr->arg))); - break; - - case asBC_TYPEID: - fprintf(file, " %-8s 0x%x '%s'\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), engine->GetTypeDeclaration((int)*ARG_DW(instr->arg))); - break; - - case asBC_CALL: - case asBC_CALLSYS: - case asBC_CALLBND: - case asBC_CALLINTF: - { - int funcID = *(int*)ARG_DW(instr->arg); - asCString decl = engine->GetFunctionDeclaration(funcID); - - fprintf(file, " %-8s %d (%s)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), decl.AddressOf()); - } - break; - - case asBC_REFCPY: - fprintf(file, " %-8s 0x%x\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg))); - break; - - case asBC_JMP: - case asBC_JZ: - case asBC_JLowZ: - case asBC_JS: - case asBC_JP: - case asBC_JNZ: - case asBC_JLowNZ: - case asBC_JNS: - case asBC_JNP: - fprintf(file, " %-8s %+d (d:%d)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), pos+*((int*) ARG_DW(instr->arg))); - break; - - default: - fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg))); - break; - } - break; - - case asBCTYPE_QW_ARG: -#ifdef __GNUC__ -#ifdef _LP64 - fprintf(file, " %-8s 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); -#else - fprintf(file, " %-8s 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); -#endif -#else - fprintf(file, " %-8s 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); -#endif - break; - - case asBCTYPE_wW_QW_ARG: - case asBCTYPE_rW_QW_ARG: -#ifdef __GNUC__ -#ifdef _LP64 - fprintf(file, " %-8s v%d, 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); -#else - fprintf(file, " %-8s v%d, 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); -#endif -#else - fprintf(file, " %-8s v%d, 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); -#endif - break; - - case asBCTYPE_DW_DW_ARG: - if( instr->op == asBC_ALLOC ) - { - asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg); - fprintf(file, " %-8s 0x%x, %d (type:%s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName()); - } - else - fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1)); - break; - - case asBCTYPE_rW_DW_DW_ARG: - fprintf(file, " %-8s v%d, %u, %u\n", asBCInfo[instr->op].name, instr->wArg[0], *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1)); - break; - - case asBCTYPE_QW_DW_ARG: - if( instr->op == asBC_ALLOC ) - { - asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); -#ifdef __GNUC__ -#ifdef AS_64BIT_PTR - fprintf(file, " %-8s 0x%lx, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName()); -#else - fprintf(file, " %-8s 0x%llx, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName()); -#endif -#else - fprintf(file, " %-8s 0x%I64x, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName()); -#endif - } - else -#ifdef __GNUC__ -#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 - fprintf(file, " %-8s %llu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2)); -#endif -#else - fprintf(file, " %-8s %I64u, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2)); -#endif - break; - - case asBCTYPE_INFO: - if( instr->op == asBC_LABEL ) - fprintf(file, "%d:\n", instr->wArg[0]); - else if( instr->op == asBC_LINE ) - fprintf(file, " %s\n", asBCInfo[instr->op].name); - else if( instr->op == asBC_Block ) - fprintf(file, "%c\n", instr->wArg[0] ? '{' : '}'); - break; - - case asBCTYPE_rW_DW_ARG: - case asBCTYPE_wW_DW_ARG: - case asBCTYPE_W_DW_ARG: - if( instr->op == asBC_SetV1 ) - fprintf(file, " %-8s v%d, 0x%x\n", asBCInfo[instr->op].name, instr->wArg[0], *(asBYTE*)ARG_DW(instr->arg)); - else if( instr->op == asBC_SetV2 ) - fprintf(file, " %-8s v%d, 0x%x\n", asBCInfo[instr->op].name, instr->wArg[0], *(asWORD*)ARG_DW(instr->arg)); - else if( instr->op == asBC_SetV4 ) - fprintf(file, " %-8s v%d, 0x%x (i:%d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_DW(instr->arg), *((int*) ARG_DW(instr->arg)), *((float*) ARG_DW(instr->arg))); - else if( instr->op == asBC_CMPIf ) - fprintf(file, " %-8s v%d, %f\n", asBCInfo[instr->op].name, instr->wArg[0], *(float*)ARG_DW(instr->arg)); - else - fprintf(file, " %-8s v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_DW(instr->arg)); - break; - - case asBCTYPE_wW_rW_rW_ARG: - fprintf(file, " %-8s v%d, v%d, v%d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], instr->wArg[2]); - break; - - case asBCTYPE_NO_ARG: - fprintf(file, " %s\n", asBCInfo[instr->op].name); - break; - - default: - asASSERT(false); - } - - instr = instr->next; - } - - fclose(file); -} -#endif - -//============================================================================= - -int asCByteCode::InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstructionFirst() < 0 ) - return 0; - - first->op = bc; - *ARG_DW(first->arg) = param; - first->size = asBCTypeSize[asBCInfo[bc].type]; - first->stackInc = asBCInfo[bc].stackInc; - - return first->stackInc; -} - -int asCByteCode::InsertFirstInstrQWORD(asEBCInstr bc, asQWORD param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstructionFirst() < 0 ) - return 0; - - first->op = bc; - *ARG_QW(first->arg) = param; - first->size = asBCTypeSize[asBCInfo[bc].type]; - first->stackInc = asBCInfo[bc].stackInc; - - return first->stackInc; -} - -int asCByteCode::Instr(asEBCInstr bc) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_NO_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrW_W_W(asEBCInstr bc, int a, int b, int c) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_rW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = (short)a; - last->wArg[1] = (short)b; - last->wArg[2] = (short)c; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrW_W(asEBCInstr bc, int a, int b) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_ARG || - asBCInfo[bc].type == asBCTYPE_rW_rW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = (short)a; - last->wArg[1] = (short)b; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrW_PTR(asEBCInstr bc, short a, void *param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_PTR_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - *ARG_PTR(last->arg) = (asPWORD)param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrW_DW(asEBCInstr bc, asWORD a, asDWORD b) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || - asBCInfo[bc].type == asBCTYPE_rW_DW_ARG || - asBCInfo[bc].type == asBCTYPE_W_DW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - *((int*) ARG_DW(last->arg)) = b; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_rW_DW_DW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - *(int*)ARG_DW(last->arg) = b; - *(int*)(ARG_DW(last->arg)+1) = c; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrSHORT_B(asEBCInstr bc, short a, asBYTE b) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || - asBCInfo[bc].type == asBCTYPE_rW_DW_ARG || - asBCInfo[bc].type == asBCTYPE_W_DW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - - // We'll have to be careful to store the byte correctly, independent of endianess. - // Some optimizing compilers may change the order of operations, so we make sure - // the value is not overwritten even if that happens. - asBYTE *argPtr = (asBYTE*)ARG_DW(last->arg); - argPtr[0] = b; // The value is always stored in the lower byte - argPtr[1] = 0; // and clear the rest of the DWORD - argPtr[2] = 0; - argPtr[3] = 0; - - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrSHORT_W(asEBCInstr bc, short a, asWORD b) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || - asBCInfo[bc].type == asBCTYPE_rW_DW_ARG || - asBCInfo[bc].type == asBCTYPE_W_DW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - - // We'll have to be careful to store the word correctly, independent of endianess. - // Some optimizing compilers may change the order of operations, so we make sure - // the value is not overwritten even if that happens. - asWORD *argPtr = (asWORD*)ARG_DW(last->arg); - argPtr[0] = b; // The value is always stored in the lower word - argPtr[1] = 0; // and clear the rest of the DWORD - - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrSHORT_DW(asEBCInstr bc, short a, asDWORD b) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || - asBCInfo[bc].type == asBCTYPE_rW_DW_ARG || - asBCInfo[bc].type == asBCTYPE_W_DW_ARG); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - *((int*) ARG_DW(last->arg)) = b; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrW_QW(asEBCInstr bc, asWORD a, asQWORD b) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - *ARG_QW(last->arg) = b; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrSHORT_QW(asEBCInstr bc, short a, asQWORD b) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - *ARG_QW(last->arg) = b; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrW_FLOAT(asEBCInstr bc, asWORD a, float b) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG); - asASSERT(asBCInfo[bc].stackInc == 0); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = a; - *((float*) ARG_DW(last->arg)) = b; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrSHORT(asEBCInstr bc, short param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_rW_ARG || - asBCInfo[bc].type == asBCTYPE_wW_ARG || - asBCInfo[bc].type == asBCTYPE_W_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrINT(asEBCInstr bc, int param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - *((int*) ARG_DW(last->arg)) = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrDWORD(asEBCInstr bc, asDWORD param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - *ARG_DW(last->arg) = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrPTR(asEBCInstr bc, void *param) -{ - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - asASSERT(asBCInfo[bc].type == asBCTYPE_PTR_ARG); - *ARG_PTR(last->arg) = (asPWORD)param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrQWORD(asEBCInstr bc, asQWORD param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - *ARG_QW(last->arg) = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrWORD(asEBCInstr bc, asWORD param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_W_ARG || - asBCInfo[bc].type == asBCTYPE_rW_ARG || - asBCInfo[bc].type == asBCTYPE_wW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - last->wArg[0] = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrFLOAT(asEBCInstr bc, float param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - *((float*) ARG_DW(last->arg)) = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::InstrDOUBLE(asEBCInstr bc, double param) -{ - asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - - if( AddInstruction() < 0 ) - return 0; - - last->op = bc; - *((double*) ARG_QW(last->arg)) = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; - - return last->stackInc; -} - -int asCByteCode::GetLastInstr() -{ - if( last == 0 ) return -1; - - return last->op; -} - -int asCByteCode::RemoveLastInstr() -{ - if( last == 0 ) return -1; - - if( first == last ) - { - engine->memoryMgr.FreeByteInstruction(last); - first = 0; - last = 0; - } - else - { - asCByteInstruction *bc = last; - last = bc->prev; - - bc->Remove(); - engine->memoryMgr.FreeByteInstruction(bc); - } - - return 0; -} - -asDWORD asCByteCode::GetLastInstrValueDW() -{ - if( last == 0 ) return 0; - - return *ARG_DW(last->arg); -} - -//=================================================================== - -asCByteInstruction::asCByteInstruction() -{ - next = 0; - prev = 0; - - op = asBC_LABEL; - - arg = 0; - wArg[0] = 0; - wArg[1] = 0; - wArg[2] = 0; - size = 0; - stackInc = 0; - marked = false; - stackSize = 0; -} - -void asCByteInstruction::AddAfter(asCByteInstruction *nextCode) -{ - if( next ) - next->prev = nextCode; - - nextCode->next = next; - nextCode->prev = this; - next = nextCode; -} - -void asCByteInstruction::AddBefore(asCByteInstruction *prevCode) -{ - if( prev ) - prev->next = prevCode; - - prevCode->prev = prev; - prevCode->next = this; - prev = prevCode; -} - -int asCByteInstruction::GetSize() -{ - return size; -} - -int asCByteInstruction::GetStackIncrease() -{ - return stackInc; -} - -void asCByteInstruction::Remove() -{ - if( prev ) prev->next = next; - if( next ) next->prev = prev; - prev = 0; - next = 0; -} - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - diff --git a/dependencies/angelscript/source/as_bytecode.h b/dependencies/angelscript/source/as_bytecode.h deleted file mode 100644 index 240bf480..00000000 --- a/dependencies/angelscript/source/as_bytecode.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2012 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_bytecode.h -// -// A class for constructing the final byte code -// - - - -#ifndef AS_BYTECODE_H -#define AS_BYTECODE_H - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_array.h" - -BEGIN_AS_NAMESPACE - -#define BYTECODE_SIZE 4 -#define MAX_DATA_SIZE 8 -#define MAX_INSTR_SIZE (BYTECODE_SIZE+MAX_DATA_SIZE) - -class asCScriptEngine; -class asCScriptFunction; -class asCByteInstruction; - -class asCByteCode -{ -public: - asCByteCode(asCScriptEngine *engine); - ~asCByteCode(); - - void ClearAll(); - - int GetSize(); - - void Finalize(const asCArray &tempVariableOffsets); - - void Optimize(); - void OptimizeLocally(const asCArray &tempVariableOffsets); - void ExtractLineNumbers(); - void ExtractObjectVariableInfo(asCScriptFunction *outFunc); - int ResolveJumpAddresses(); - int FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta); - - void AddPath(asCArray &paths, asCByteInstruction *instr, int stackSize); - - void Output(asDWORD *array); - void AddCode(asCByteCode *bc); - - void PostProcess(); - -#ifdef AS_DEBUG - void DebugOutput(const char *name, asCScriptEngine *engine, asCScriptFunction *func); -#endif - - int GetLastInstr(); - int RemoveLastInstr(); - asDWORD GetLastInstrValueDW(); - - void InsertIfNotExists(asCArray &vars, int var); - void GetVarsUsed(asCArray &vars); - bool IsVarUsed(int offset); - void ExchangeVar(int oldOffset, int newOffset); - bool IsSimpleExpression(); - - void Label(short label); - void Line(int line, int column, int scriptIdx); - void ObjInfo(int offset, int info); - void Block(bool start); - void VarDecl(int varDeclIdx); - void Call(asEBCInstr bc, int funcID, int pop); - void CallPtr(asEBCInstr bc, int funcPtrVar, int pop); - void Alloc(asEBCInstr bc, void *objID, int funcID, int pop); - void Ret(int pop); - void JmpP(int var, asDWORD max); - - int InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param); - int InsertFirstInstrQWORD(asEBCInstr bc, asQWORD param); - int Instr(asEBCInstr bc); - int InstrQWORD(asEBCInstr bc, asQWORD param); - int InstrDOUBLE(asEBCInstr bc, double param); - int InstrPTR(asEBCInstr bc, void *param); - int InstrDWORD(asEBCInstr bc, asDWORD param); - int InstrWORD(asEBCInstr bc, asWORD param); - int InstrSHORT(asEBCInstr bc, short param); - int InstrFLOAT(asEBCInstr bc, float param); - int InstrINT(asEBCInstr bc, int param); - int InstrW_W_W(asEBCInstr bc, int a, int b, int c); - int InstrSHORT_B(asEBCInstr bc, short a, asBYTE b); - int InstrSHORT_W(asEBCInstr bc, short a, asWORD b); - int InstrSHORT_DW(asEBCInstr bc, short a, asDWORD b); - int InstrSHORT_QW(asEBCInstr bc, short a, asQWORD b); - int InstrW_DW(asEBCInstr bc, asWORD a, asDWORD b); - int InstrW_QW(asEBCInstr bc, asWORD a, asQWORD b); - int InstrW_PTR(asEBCInstr bc, short a, void *param); - int InstrW_FLOAT(asEBCInstr bc, asWORD a, float b); - int InstrW_W(asEBCInstr bc, int w, int b); - int InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c); - - asCArray lineNumbers; - asCArray sectionIdxs; - int largestStackUsed; - -protected: - // Assignments are not allowed - void operator=(const asCByteCode &) {} - - // Helpers for Optimize - bool CanBeSwapped(asCByteInstruction *curr); - asCByteInstruction *ChangeFirstDeleteNext(asCByteInstruction *curr, asEBCInstr bc); - asCByteInstruction *DeleteFirstChangeNext(asCByteInstruction *curr, asEBCInstr bc); - asCByteInstruction *DeleteInstruction(asCByteInstruction *instr); - void RemoveInstruction(asCByteInstruction *instr); - asCByteInstruction *GoBack(asCByteInstruction *curr); - asCByteInstruction *GoForward(asCByteInstruction *curr); - void InsertBefore(asCByteInstruction *before, asCByteInstruction *instr); - bool RemoveUnusedValue(asCByteInstruction *curr, asCByteInstruction **next); - bool IsTemporary(int offset); - bool IsTempRegUsed(asCByteInstruction *curr); - bool IsTempVarRead(asCByteInstruction *curr, int offset); - bool PostponeInitOfTemp(asCByteInstruction *curr, asCByteInstruction **next); - bool IsTempVarReadByInstr(asCByteInstruction *curr, int var); - bool IsTempVarOverwrittenByInstr(asCByteInstruction *curr, int var); - bool IsInstrJmpOrLabel(asCByteInstruction *curr); - - int AddInstruction(); - int AddInstructionFirst(); - - asCByteInstruction *first; - asCByteInstruction *last; - - const asCArray *temporaryVariables; - - asCScriptEngine *engine; -}; - -class asCByteInstruction -{ -public: - asCByteInstruction(); - - void AddAfter(asCByteInstruction *nextCode); - void AddBefore(asCByteInstruction *nextCode); - void Remove(); - - int GetSize(); - int GetStackIncrease(); - - asCByteInstruction *next; - asCByteInstruction *prev; - - asEBCInstr op; - asQWORD arg; - short wArg[3]; - int size; - int stackInc; - - // Testing - bool marked; - int stackSize; -}; - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - -#endif diff --git a/dependencies/angelscript/source/as_callfunc.cpp b/dependencies/angelscript/source/as_callfunc.cpp deleted file mode 100644 index 7cf2d0a3..00000000 --- a/dependencies/angelscript/source/as_callfunc.cpp +++ /dev/null @@ -1,810 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc.cpp -// -// These functions handle the actual calling of system functions -// - - - -#include "as_config.h" -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_context.h" - -BEGIN_AS_NAMESPACE - -int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal) -{ - memset(internal, 0, sizeof(asSSystemFunctionInterface)); - - internal->func = ptr.ptr.f.func; - internal->objForThiscall = 0; - - // Was a compatible calling convention specified? - if( internal->func ) - { - if( ptr.flag == 1 && callConv != asCALL_GENERIC ) - return asWRONG_CALLING_CONV; - else if( ptr.flag == 2 && (callConv == asCALL_GENERIC || callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) ) - return asWRONG_CALLING_CONV; - else if( ptr.flag == 3 && !(callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) ) - return asWRONG_CALLING_CONV; - } - - asDWORD base = callConv; - if( !isMethod ) - { - if( base == asCALL_CDECL ) - internal->callConv = ICC_CDECL; - else if( base == asCALL_STDCALL ) - internal->callConv = ICC_STDCALL; - else if( base == asCALL_THISCALL_ASGLOBAL ) - { - if( objForThiscall == 0 ) - return asINVALID_ARG; - internal->objForThiscall = objForThiscall; - 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 ) - internal->callConv = ICC_GENERIC_FUNC; - else - return asNOT_SUPPORTED; - } - - if( isMethod ) - { -#ifndef AS_NO_CLASS_METHODS - if( base == asCALL_THISCALL || base == asCALL_THISCALL_OBJFIRST || base == asCALL_THISCALL_OBJLAST ) - { - internalCallConv thisCallConv; - if( base == asCALL_THISCALL ) - { - if( callConv != asCALL_THISCALL_ASGLOBAL && objForThiscall ) - return asINVALID_ARG; - - thisCallConv = ICC_THISCALL; - } - else - { -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - return asNOT_SUPPORTED; -#endif - - if( objForThiscall == 0 ) - return asINVALID_ARG; - - internal->objForThiscall = objForThiscall; - if( base == asCALL_THISCALL_OBJFIRST ) - thisCallConv = ICC_THISCALL_OBJFIRST; - else //if( base == asCALL_THISCALL_OBJLAST ) - thisCallConv = ICC_THISCALL_OBJLAST; - } - - internal->callConv = thisCallConv; -#ifdef GNU_STYLE_VIRTUAL_METHOD - if( (size_t(ptr.ptr.f.func) & 1) ) - internal->callConv = (internalCallConv)(thisCallConv + 2); -#endif - internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr); -#if defined(AS_ARM) && defined(__GNUC__) - // As the least significant bit in func is used to switch to THUMB mode - // on ARM processors, the LSB in the __delta variable is used instead of - // the one in __pfn on ARM processors. - if( (size_t(internal->baseOffset) & 1) ) - internal->callConv = (internalCallConv)(thisCallConv + 2); -#endif - -#ifdef HAVE_VIRTUAL_BASE_OFFSET - // We don't support virtual inheritance - if( VIRTUAL_BASE_OFFSET(ptr) != 0 ) - return asNOT_SUPPORTED; -#endif - } - else -#endif - if( base == asCALL_CDECL_OBJLAST ) - internal->callConv = ICC_CDECL_OBJLAST; - else if( base == asCALL_CDECL_OBJFIRST ) - internal->callConv = ICC_CDECL_OBJFIRST; - else if( base == asCALL_GENERIC ) - internal->callConv = ICC_GENERIC_METHOD; - else - return asNOT_SUPPORTED; - } - - return 0; -} - -// This function should prepare system functions so that it will be faster to call them -int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine * /*engine*/) -{ - asASSERT(internal->callConv == ICC_GENERIC_METHOD || internal->callConv == ICC_GENERIC_FUNC); - - // Calculate the size needed for the parameters - internal->paramSize = func->GetSpaceNeededForArguments(); - - return 0; -} - -// This function should prepare system functions so that it will be faster to call them -int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine) -{ -#ifdef AS_MAX_PORTABILITY - UNUSED_VAR(func); - UNUSED_VAR(internal); - UNUSED_VAR(engine); - - // This should never happen, as when AS_MAX_PORTABILITY is on, all functions - // are asCALL_GENERIC, which are prepared by PrepareSystemFunctionGeneric - asASSERT(false); -#else - // References are always returned as primitive data - if( func->returnType.IsReference() || func->returnType.IsObjectHandle() ) - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = sizeof(void*)/4; - internal->hostReturnFloat = false; - } - // Registered types have special flags that determine how they are returned - else if( func->returnType.IsObject() ) - { - asDWORD objType = func->returnType.GetObjectType()->flags; - - // Only value types can be returned by value - asASSERT( objType & asOBJ_VALUE ); - - if( !(objType & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) ) - { - // If the return is by value then we need to know the true type - 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()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); - } - else if( objType & asOBJ_APP_ARRAY ) - { - // Array types are always returned in memory - internal->hostReturnInMemory = true; - internal->hostReturnSize = sizeof(void*)/4; - internal->hostReturnFloat = false; - } - else if( objType & asOBJ_APP_CLASS ) - { - internal->hostReturnFloat = false; - if( objType & COMPLEX_RETURN_MASK ) - { - internal->hostReturnInMemory = true; - internal->hostReturnSize = sizeof(void*)/4; - } - else - { -#ifdef HAS_128_BIT_PRIMITIVES - if( func->returnType.GetSizeInMemoryDWords() > 4 ) -#else - if( func->returnType.GetSizeInMemoryDWords() > 2 ) -#endif - { - internal->hostReturnInMemory = true; - internal->hostReturnSize = sizeof(void*)/4; - } - else - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords(); -#ifdef SPLIT_OBJS_BY_MEMBER_TYPES - if( func->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS ) - internal->hostReturnFloat = true; -#endif - } - -#ifdef THISCALL_RETURN_SIMPLE_IN_MEMORY - if((internal->callConv == ICC_THISCALL || -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - internal->callConv == ICC_VIRTUAL_THISCALL) && -#else - internal->callConv == ICC_VIRTUAL_THISCALL || - internal->callConv == ICC_THISCALL_OBJFIRST || - internal->callConv == ICC_THISCALL_OBJLAST) && -#endif - func->returnType.GetSizeInMemoryDWords() >= THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE) - { - internal->hostReturnInMemory = true; - internal->hostReturnSize = sizeof(void*)/4; - } -#endif -#ifdef CDECL_RETURN_SIMPLE_IN_MEMORY - if((internal->callConv == ICC_CDECL || - internal->callConv == ICC_CDECL_OBJLAST || - internal->callConv == ICC_CDECL_OBJFIRST) && - func->returnType.GetSizeInMemoryDWords() >= CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE) - { - internal->hostReturnInMemory = true; - internal->hostReturnSize = sizeof(void*)/4; - } -#endif -#ifdef STDCALL_RETURN_SIMPLE_IN_MEMORY - if( internal->callConv == ICC_STDCALL && - func->returnType.GetSizeInMemoryDWords() >= STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE) - { - internal->hostReturnInMemory = true; - internal->hostReturnSize = sizeof(void*)/4; - } -#endif - } - -#ifdef SPLIT_OBJS_BY_MEMBER_TYPES - // It's not safe to return objects by value because different registers - // 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 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)) ) - { - engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); - - asCString str; - str.Format(TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL, func->returnType.Format().AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); - } -#endif - } - else if( objType & asOBJ_APP_PRIMITIVE ) - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords(); - internal->hostReturnFloat = false; - } - else if( objType & asOBJ_APP_FLOAT ) - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords(); - internal->hostReturnFloat = true; - } - } - // Primitive types can easily be determined -#ifdef HAS_128_BIT_PRIMITIVES - else if( func->returnType.GetSizeInMemoryDWords() > 4 ) - { - // Shouldn't be possible to get here - asASSERT(false); - } - else if( func->returnType.GetSizeInMemoryDWords() == 4 ) - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = 4; - internal->hostReturnFloat = false; - } -#else - else if( func->returnType.GetSizeInMemoryDWords() > 2 ) - { - // Shouldn't be possible to get here - asASSERT(false); - } -#endif - else if( func->returnType.GetSizeInMemoryDWords() == 2 ) - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = 2; - internal->hostReturnFloat = func->returnType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttDouble, true)); - } - else if( func->returnType.GetSizeInMemoryDWords() == 1 ) - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = 1; - internal->hostReturnFloat = func->returnType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttFloat, true)); - } - else - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = 0; - internal->hostReturnFloat = false; - } - - // Calculate the size needed for the parameters - internal->paramSize = func->GetSpaceNeededForArguments(); - - // Verify if the function takes any objects by value - asUINT n; - internal->takesObjByVal = false; - for( n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( func->parameterTypes[n].IsObject() && !func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference() ) - { - 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)) ) - { - 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()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); - } - - -#ifdef SPLIT_OBJS_BY_MEMBER_TYPES - // It's not safe to pass objects by value because different registers - // 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( -#ifdef COMPLEX_OBJS_PASSED_BY_REF - !(func->parameterTypes[n].GetObjectType()->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)) ) - { - 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()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); - } -#endif - break; - } - } - - // Verify if the function has any registered autohandles - internal->hasAutoHandles = false; - for( n = 0; n < internal->paramAutoHandles.GetLength(); n++ ) - { - if( internal->paramAutoHandles[n] ) - { - internal->hasAutoHandles = true; - break; - } - } -#endif // !defined(AS_MAX_PORTABILITY) - return 0; -} - -#ifdef AS_MAX_PORTABILITY - -int CallSystemFunction(int id, asCContext *context, void *objectPointer) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = engine->scriptFunctions[id]->sysFuncIntf; - int callConv = sysFunc->callConv; - if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD ) - return context->CallGeneric(id, objectPointer); - - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - - return 0; -} - -#else - -// -// CallSystemFunctionNative -// -// This function is implemented for each platform where the native calling conventions is supported. -// See the various as_callfunc_xxx.cpp files for their implementation. It is responsible for preparing -// the arguments for the function call, calling the function, and then retrieving the return value. -// -// Parameters: -// -// context - This is the context that can be used to retrieve specific information from the engine -// descr - This is the script function object that holds the information on how to call the function -// obj - This is the object pointer, if the call is for a class method, otherwise it is null -// args - This is the function arguments, which are packed as in AngelScript -// retPointer - This points to a the memory buffer where the return object is to be placed, if the function returns the value in memory rather than in registers -// retQW2 - This output parameter should be used if the function returns a value larger than 64bits in registers -// -// Return value: -// -// The function should return the value that is returned in registers. -// -// When thiscall functors are enabled (!AS_NO_THISCALL_FUNCTOR_METHOD) the -// obj argument is a an array of 2 void* holding the two possible this pointers -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2); - - -int CallSystemFunction(int id, asCContext *context, void *objectPointer) -{ - asCScriptEngine *engine = context->m_engine; - asCScriptFunction *descr = engine->scriptFunctions[id]; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - - int callConv = sysFunc->callConv; - if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD ) - return context->CallGeneric(id, objectPointer); - - asQWORD retQW = 0; - asQWORD retQW2 = 0; - asDWORD *args = context->m_regs.stackPointer; - void *retPointer = 0; - int popSize = sysFunc->paramSize; - -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - void *obj = 0; - - if( callConv >= ICC_THISCALL ) - { - if( sysFunc->objForThiscall ) - { - // This class method is being called as if it is a global function - obj = sysFunc->objForThiscall; - asASSERT( objectPointer == 0 ); - } - else if( objectPointer ) - { - obj = objectPointer; - } - else - { - // The object pointer should be popped from the context stack - popSize += AS_PTR_SIZE; - - // Check for null pointer - obj = (void*)*(asPWORD*)(args); - if( obj == 0 ) - { - context->SetInternalException(TXT_NULL_POINTER_ACCESS); - return 0; - } - - // Add the base offset for multiple inheritance -#if defined(__GNUC__) && defined(AS_ARM) - // On GNUC + ARM the lsb of the offset is used to indicate a virtual function - // and the whole offset is thus shifted one bit left to keep the original - // offset resolution - obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1)); -#else - obj = (void*)(asPWORD(obj) + sysFunc->baseOffset); -#endif - - // Skip the object pointer - args += AS_PTR_SIZE; - } - } -#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* objectsPtrs[2] = { 0, 0 }; - - if( callConv >= ICC_THISCALL ) - { - bool continueCheck = true; // True if need check objectPointer or context stack for object - int continueCheckIndex = 0; // Index into objectsPtrs to save the object if continueCheck - - if( callConv >= ICC_THISCALL_OBJLAST ) - { - asASSERT( sysFunc->objForThiscall != 0 ); - // This class method is being called as object method (sysFunc->objForThiscall must be set). - objectsPtrs[0] = sysFunc->objForThiscall; - continueCheckIndex = 1; - } - else if( sysFunc->objForThiscall ) - { - // This class method is being called as if it is a global function - objectsPtrs[0] = sysFunc->objForThiscall; - continueCheck = false; - asASSERT( objectPointer == 0 ); - } - - if( continueCheck ) - { - void *tempPtr = 0; - if( objectPointer ) - { - tempPtr = objectPointer; - } - else - { - // The object pointer should be popped from the context stack - popSize += AS_PTR_SIZE; - - // Check for null pointer - tempPtr = (void*)*(asPWORD*)(args); - if( tempPtr == 0 ) - { - context->SetInternalException(TXT_NULL_POINTER_ACCESS); - return 0; - } - - // Add the base offset for multiple inheritance -#if defined(__GNUC__) && defined(AS_ARM) - // On GNUC + ARM the lsb of the offset is used to indicate a virtual function - // and the whole offset is thus shifted one bit left to keep the original - // offset resolution - tempPtr = (void*)(asPWORD(tempPtr) + (sysFunc->baseOffset>>1)); -#else - tempPtr = (void*)(asPWORD(tempPtr) + sysFunc->baseOffset); -#endif - - // Skip the object pointer - args += AS_PTR_SIZE; - } - - objectsPtrs[continueCheckIndex] = tempPtr; - } - } - void *obj = &objectsPtrs[0]; // Get the pointer to first element -#endif // AS_NO_THISCALL_FUNCTOR_METHOD - - if( descr->DoesReturnOnStack() ) - { - // Get the address of the location for the return value from the stack - retPointer = (void*)*(asPWORD*)(args); - popSize += AS_PTR_SIZE; - args += AS_PTR_SIZE; - - // 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_callingSystemFunction = descr; - bool cppException = false; -#ifdef AS_NO_EXCEPTIONS - retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2); -#else - // 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 - // executed in case of an exception. - try - { - retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2); - } - catch(...) - { - cppException = true; - - // 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); - } -#endif - context->m_callingSystemFunction = 0; - -#if defined(COMPLEX_OBJS_PASSED_BY_REF) || defined(AS_LARGE_OBJS_PASSED_BY_REF) - if( sysFunc->takesObjByVal ) - { - // Need to free the complex objects passed by value, but that the - // calling convention implicitly passes by reference behind the scene as the - // calling function is the owner of that memory. - - // args is pointing to the first real argument as used in CallSystemFunctionNative, - // i.e. hidden arguments such as the object pointer and return address have already - // been skipped. - - int spos = 0; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - bool needFree = false; - asCDataType &dt = descr->parameterTypes[n]; -#ifdef COMPLEX_OBJS_PASSED_BY_REF - if( dt.GetObjectType() && dt.GetObjectType()->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.IsReference() ) - { - void *obj = (void*)*(asPWORD*)&args[spos]; - spos += AS_PTR_SIZE; - -#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; - if( beh->destruct ) - engine->CallObjectMethod(obj, beh->destruct); -#endif - - engine->CallFree(obj); - } - else - spos += dt.GetSizeOnStackDWords(); - } - } -#endif - - // Store the returned value in our stack - if( descr->returnType.IsObject() && !descr->returnType.IsReference() ) - { - if( descr->returnType.IsObjectHandle() ) - { -#if defined(AS_BIG_ENDIAN) && AS_PTR_SIZE == 1 - // Since we're treating the system function as if it is returning a QWORD we are - // actually receiving the value in the high DWORD of retQW. - retQW >>= 32; -#endif - - context->m_regs.objectRegister = (void*)(asPWORD)retQW; - - 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); - } - } - else - { - asASSERT( retPointer ); - - if( !sysFunc->hostReturnInMemory ) - { - // Copy the returned value to the pointer sent by the script engine - if( sysFunc->hostReturnSize == 1 ) - { -#if defined(AS_BIG_ENDIAN) && AS_PTR_SIZE == 1 - // Since we're treating the system function as if it is returning a QWORD we are - // actually receiving the value in the high DWORD of retQW. - retQW >>= 32; -#endif - - *(asDWORD*)retPointer = (asDWORD)retQW; - } - else if( sysFunc->hostReturnSize == 2 ) - *(asQWORD*)retPointer = retQW; - else if( sysFunc->hostReturnSize == 3 ) - { - *(asQWORD*)retPointer = retQW; - *(((asDWORD*)retPointer) + 2) = (asDWORD)retQW2; - } - else // if( sysFunc->hostReturnSize == 4 ) - { - *(asQWORD*)retPointer = retQW; - *(((asQWORD*)retPointer) + 1) = retQW2; - } - } - - 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 - // 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); - } - } - } - else - { - // Store value in value register - if( sysFunc->hostReturnSize == 1 ) - { -#if defined(AS_BIG_ENDIAN) - // Since we're treating the system function as if it is returning a QWORD we are - // actually receiving the value in the high DWORD of retQW. - retQW >>= 32; - - // Due to endian issues we need to handle return values that are - // less than a DWORD (32 bits) in size specially - int numBytes = descr->returnType.GetSizeInMemoryBytes(); - if( descr->returnType.IsReference() ) numBytes = 4; - switch( numBytes ) - { - case 1: - { - // 8 bits - asBYTE *val = (asBYTE*)&context->m_regs.valueRegister; - val[0] = (asBYTE)retQW; - val[1] = 0; - val[2] = 0; - val[3] = 0; - val[4] = 0; - val[5] = 0; - val[6] = 0; - val[7] = 0; - } - break; - case 2: - { - // 16 bits - asWORD *val = (asWORD*)&context->m_regs.valueRegister; - val[0] = (asWORD)retQW; - val[1] = 0; - val[2] = 0; - val[3] = 0; - } - break; - default: - { - // 32 bits - asDWORD *val = (asDWORD*)&context->m_regs.valueRegister; - val[0] = (asDWORD)retQW; - val[1] = 0; - } - break; - } -#else - *(asDWORD*)&context->m_regs.valueRegister = (asDWORD)retQW; -#endif - } - else - context->m_regs.valueRegister = retQW; - } - - // Release autohandles in the arguments - if( sysFunc->hasAutoHandles ) - { - args = context->m_regs.stackPointer; - if( callConv >= ICC_THISCALL && !objectPointer ) - args += AS_PTR_SIZE; - - int spos = 0; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - if( sysFunc->paramAutoHandles[n] && *(asPWORD*)&args[spos] != 0 ) - { - // Call the release method on the type - engine->CallObjectMethod((void*)*(asPWORD*)&args[spos], descr->parameterTypes[n].GetObjectType()->beh.release); - *(asPWORD*)&args[spos] = 0; - } - - if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) - spos += AS_PTR_SIZE; - else - spos += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - } - - return popSize; -} - -#endif // AS_MAX_PORTABILITY - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_callfunc.h b/dependencies/angelscript/source/as_callfunc.h deleted file mode 100644 index 533c6837..00000000 --- a/dependencies/angelscript/source/as_callfunc.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc.h -// -// These functions handle the actual calling of system functions -// - - -#ifndef AS_CALLFUNC_H -#define AS_CALLFUNC_H - -#include "as_array.h" - -BEGIN_AS_NAMESPACE - -class asCContext; -class asCScriptEngine; -class asCScriptFunction; -struct asSSystemFunctionInterface; - -int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal); - -int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine); - -int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine); - -int CallSystemFunction(int id, asCContext *context, void *objectPointer); - -inline asPWORD FuncPtrToUInt(asFUNCTION_t func) -{ - // 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; - - return u.idx; -} - -enum internalCallConv -{ - ICC_GENERIC_FUNC, - ICC_GENERIC_FUNC_RETURNINMEM, // never used - ICC_CDECL, - ICC_CDECL_RETURNINMEM, - ICC_STDCALL, - ICC_STDCALL_RETURNINMEM, - ICC_THISCALL, - ICC_THISCALL_RETURNINMEM, - ICC_VIRTUAL_THISCALL, - ICC_VIRTUAL_THISCALL_RETURNINMEM, - ICC_CDECL_OBJLAST, - ICC_CDECL_OBJLAST_RETURNINMEM, - ICC_CDECL_OBJFIRST, - ICC_CDECL_OBJFIRST_RETURNINMEM, - ICC_GENERIC_METHOD, - ICC_GENERIC_METHOD_RETURNINMEM, // never used - ICC_THISCALL_OBJLAST, - ICC_THISCALL_OBJLAST_RETURNINMEM, - ICC_VIRTUAL_THISCALL_OBJLAST, - ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM, - ICC_THISCALL_OBJFIRST, - ICC_THISCALL_OBJFIRST_RETURNINMEM, - ICC_VIRTUAL_THISCALL_OBJFIRST, - ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM -}; - -struct asSSystemFunctionInterface -{ - asFUNCTION_t func; - int baseOffset; - internalCallConv callConv; - int scriptReturnSize; - bool hostReturnInMemory; - bool hostReturnFloat; - int hostReturnSize; - int paramSize; - bool takesObjByVal; - asCArray paramAutoHandles; - bool returnAutoHandle; - bool hasAutoHandles; - void *objForThiscall; - - asSSystemFunctionInterface() {} - - asSSystemFunctionInterface(const asSSystemFunctionInterface &in) - { - *this = in; - } - - 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; - hasAutoHandles = in.hasAutoHandles; - objForThiscall = in.objForThiscall; - return *this; - } -}; - -END_AS_NAMESPACE - -#endif - diff --git a/dependencies/angelscript/source/as_callfunc_arm.cpp b/dependencies/angelscript/source/as_callfunc_arm.cpp deleted file mode 100644 index a005c242..00000000 --- a/dependencies/angelscript/source/as_callfunc_arm.cpp +++ /dev/null @@ -1,705 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc_arm.cpp -// -// These functions handle the actual calling of system functions on the arm platform -// -// Written by Fredrik Ehnbom in June 2009, based on as_callfunc_x86.cpp -// -// The code was complemented to support Linux with ARM by Carlos Luna in December, 2012. -// -// Added support for functor methods by Jordi Oliveras Rovira in April, 2014. - - -// This code has to conform to both AAPCS and the modified ABI for iOS -// -// Reference: -// -// AAPCS: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf -// iOS: http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_ARM - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_tokendef.h" -#include "as_context.h" - -#if defined(AS_SOFTFP) - -// This code supports the soft-float ABI, i.e. g++ -mfloat-abi=softfp -// -// The code for iOS, Android, Marmalade and Windows Phone goes here - -BEGIN_AS_NAMESPACE - -extern "C" asQWORD armFunc (const asDWORD *, int, asFUNCTION_t); -extern "C" asQWORD armFuncR0 (const asDWORD *, int, asFUNCTION_t, asDWORD r0); -extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1); -extern "C" asQWORD armFuncObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD obj); -extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj); - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - int callConv = sysFunc->callConv; - - asQWORD retQW = 0; - asFUNCTION_t func = sysFunc->func; - int paramSize = sysFunc->paramSize; - asFUNCTION_t *vftable; - - if( sysFunc->hostReturnInMemory ) - { - // The return is made in memory - callConv++; - } -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - // Unpack the two object pointers - void **objectsPtrs = (void**)obj; - void *secondObject = objectsPtrs[1]; - obj = objectsPtrs[0]; - - bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; -#endif - - asDWORD paramBuffer[64+2]; - // Android & Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone - // TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this - // doesn't have to be done for functions that don't have any 64bit types -#if !defined(AS_ANDROID) && !defined(AS_LINUX) -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - if( sysFunc->takesObjByVal ) -#else - // In cases of thiscall methods, the callstack is configured as a standard thiscall - // adding the secondObject as first or last element in callstack - if( sysFunc->takesObjByVal || isThisCallMethod ) -#endif -#endif - { -#if defined(AS_ANDROID) || defined(AS_LINUX) - // mask is used as a toggler to skip uneven registers. - int mask = 1; - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - if( isThisCallMethod ) - { - mask = 0; - } - else -#endif - { - // Check for object pointer as first argument - switch( callConv ) - { - case ICC_THISCALL: - case ICC_CDECL_OBJFIRST: - case ICC_VIRTUAL_THISCALL: - case ICC_THISCALL_RETURNINMEM: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - mask = 0; - break; - default: - break; - } - } - - // Check for hidden address in case of return by value - if( sysFunc->hostReturnInMemory ) - mask = !mask; -#endif - paramSize = 0; - int spos = 0; - int dpos = 2; - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJFIRST && - callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) - { - // Add the object pointer as the first parameter - paramBuffer[dpos++] = (asDWORD)secondObject; - paramSize++; - } -#endif - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - // 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() ) - { -#ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else -#endif - { -#if defined(AS_ANDROID) || defined(AS_LINUX) - if( (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) && - ((dpos & 1) == mask) ) - { - // 64 bit value align - dpos++; - paramSize++; - } -#endif - // Copy the object's memory to the buffer - memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos++; - dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); - paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); - } - } - else - { -#if defined(AS_ANDROID) || defined(AS_LINUX) - // Should an alignment be performed? - if( !descr->parameterTypes[n].IsObjectHandle() && - !descr->parameterTypes[n].IsReference() && - descr->parameterTypes[n].GetSizeOnStackDWords() == 2 && - ((dpos & 1) == mask) ) - { - // 64 bit value align - dpos++; - paramSize++; - } -#endif - - // Copy the value directly - paramBuffer[dpos++] = args[spos++]; - if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) - paramBuffer[dpos++] = args[spos++]; - paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - } - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJLAST && - callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) ) - { - // Add the object pointer as the last parameter - paramBuffer[dpos++] = (asDWORD)secondObject; - paramSize++; - } -#endif - // Keep a free location at the beginning - args = ¶mBuffer[2]; - } - - switch( callConv ) - { - case ICC_CDECL_RETURNINMEM: // fall through - case ICC_STDCALL_RETURNINMEM: - retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer); - break; - case ICC_CDECL: // fall through - case ICC_STDCALL: - retQW = armFunc(args, paramSize<<2, func); - break; - case ICC_THISCALL: // fall through - case ICC_CDECL_OBJFIRST: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJFIRST: - case ICC_THISCALL_OBJLAST: -#endif - retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj); - break; - case ICC_THISCALL_RETURNINMEM: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_THISCALL_OBJLAST_RETURNINMEM: -#endif -#ifdef __GNUC__ - // On GNUC the address where the return value will be placed should be put in R0 - retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); -#else - // On Windows the R0 should always hold the object pointer, and the address for the return value comes after - retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)obj, (asDWORD)retPointer); -#endif - break; - case ICC_CDECL_OBJFIRST_RETURNINMEM: - retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); - break; - case ICC_VIRTUAL_THISCALL: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_VIRTUAL_THISCALL_OBJFIRST: - case ICC_VIRTUAL_THISCALL_OBJLAST: -#endif - // Get virtual function table from the object pointer - vftable = *(asFUNCTION_t**)obj; - retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj); - break; - case ICC_VIRTUAL_THISCALL_RETURNINMEM: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: -#endif - // Get virtual function table from the object pointer - vftable = *(asFUNCTION_t**)obj; -#ifdef __GNUC__ - // On GNUC the address where the return value will be placed should be put in R0 - retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj); -#else - // On Windows the R0 should always hold the object pointer, and the address for the return value comes after - retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj, (asDWORD)retPointer); -#endif - break; - case ICC_CDECL_OBJLAST: - retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj); - break; - case ICC_CDECL_OBJLAST_RETURNINMEM: - retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); - break; - default: - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - } - - return retQW; -} - -END_AS_NAMESPACE - -#elif !defined(AS_SOFTFP) - -// This code supports the hard-float ABI, i.e. g++ -mfloat-abi=hard -// The main difference is that the floating point values are passed in the fpu registers - -#define VFP_OFFSET 70 -#define STACK_OFFSET 6 -#define PARAM_BUFFER_SIZE 104 - -BEGIN_AS_NAMESPACE - -extern "C" asQWORD armFunc (const asDWORD *, int, asFUNCTION_t); -extern "C" asQWORD armFuncR0 (const asDWORD *, int, asFUNCTION_t, asDWORD r0); -extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1); -extern "C" asQWORD armFuncObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD obj); -extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj); - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - int callConv = sysFunc->callConv; - - asQWORD retQW = 0; - asFUNCTION_t func = sysFunc->func; - int paramSize = sysFunc->paramSize; - asFUNCTION_t *vftable; - - //---------------------------------------------------------------------------- RPi - int freeFloatSlot = VFP_OFFSET; - int freeDoubleSlot = VFP_OFFSET; - int stackPos = STACK_OFFSET; - int stackSize = 0; - //---------------------------------------------------------------------------- - - //---------------------------------------------------------------------------- RPi - // We´ll divide paramBuffer into several segments: - // - // 0-1 Unused - // 2-5 (+8 / +0 asm) values that should be placed in R0 - R3 - // 6-67 (+24 / +16 asm) values that should be placed on the stack - // 68 (+272 / +264 asm) number of values stored in r registers (R0 - R3) - // 69 (+276 / +268 asm) number of args stored on the stack - // 70-85 (+280 / +272 asm) values that should be placed in VFP registers (16) - // 86-87 (+344 / +336 asm) sp original value - sp final value - for debugging - // 88-103 (+352 / +344 asm) Check area for free-used VFP registers - // - // Total number of elements: 104 - // - // When passing the paramBuffer to the asm routines via the args pointer we are - // offsetting the start of the array to being at element # 2. That´s why in asm - // all addresses must have an offset of -2 words (-8 bytes). - //---------------------------------------------------------------------------- RPi - - asDWORD paramBuffer[PARAM_BUFFER_SIZE]; - memset(paramBuffer, 0, sizeof(asDWORD) * PARAM_BUFFER_SIZE); - - 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 ) && - descr->returnType.GetSizeInMemoryBytes() <= 8 ) - callConv--; - - // The return is made in memory - callConv++; - } - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - // Unpack the two object pointers - void **objectsPtrs = (void**)obj; - void *secondObject = objectsPtrs[1]; - obj = objectsPtrs[0]; - - bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; -#endif - - // Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone - // TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this - // doesn't have to be done for functions that don't have any 64bit types - { - // mask is used as a toggler to skip uneven registers. - int mask = 1; - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - if( isThisCallMethod ) - { - mask = 0; - } - else -#endif - { - // Check for object pointer as first argument - switch( callConv ) - { - case ICC_THISCALL: - case ICC_CDECL_OBJFIRST: - case ICC_VIRTUAL_THISCALL: - case ICC_THISCALL_RETURNINMEM: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - mask = 0; - break; - default: - break; - } - } - // Check for hidden address in case of return by value - if( sysFunc->hostReturnInMemory ) - mask = !mask; - - paramSize = 0; - int spos = 0; - int dpos = 2; - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJFIRST && - callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) - { - // Add the object pointer as the first parameter - paramBuffer[dpos++] = (asDWORD)secondObject; - paramSize++; - } -#endif - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - // 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() ) - { -#ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else -#endif - { - if( (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) ) - { - if ( (dpos & 1) == mask ) - { - // 64 bit value align - dpos++; - paramSize++; - } - - if ( (stackPos & 1) == mask ) - { - // 64 bit value align - stackPos++; - stackSize++; - } - } - - // Copy the object's memory to the buffer - if (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS) - { - int target = (freeFloatSlot > freeDoubleSlot) ? freeFloatSlot : freeDoubleSlot; - - if ( descr->parameterTypes[n].GetSizeInMemoryDWords() <= ( (VFP_OFFSET + 16) - target) ) - { - memcpy(¶mBuffer[target], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - memset(¶mBuffer[target + 18], (asDWORD)1, descr->parameterTypes[n].GetSizeInMemoryDWords()); - target += descr->parameterTypes[n].GetSizeInMemoryDWords(); - freeFloatSlot = freeDoubleSlot = target; - } - else - { - memcpy(¶mBuffer[stackPos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - stackPos += descr->parameterTypes[n].GetSizeInMemoryDWords(); - stackSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - } - else - { - memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); - paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); - } - - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos++; - } - - continue; - } - else if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() ) - { - // Are there any "s" registers available? - if ( freeFloatSlot < (VFP_OFFSET + 16) ) - { - if (freeFloatSlot == freeDoubleSlot) - freeDoubleSlot += 2; - - paramBuffer[freeFloatSlot + 18] = (asDWORD)1; - paramBuffer[freeFloatSlot++] = args[spos++]; - - while(freeFloatSlot < (VFP_OFFSET + 16) && paramBuffer[freeFloatSlot + 18] != 0) - freeFloatSlot++; - } - // If not, then store the float arg in the stack area - else - { - paramBuffer[stackPos++] = args[spos++]; - stackSize++; - } - - continue; - } - else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() ) - { - // Are there any "d" registers available? - if ( freeDoubleSlot < (VFP_OFFSET + 15) ) - { - if (freeFloatSlot == freeDoubleSlot) - freeFloatSlot += 2; - - // Copy two dwords for the double - paramBuffer[freeDoubleSlot + 18] = (asDWORD)1; - paramBuffer[freeDoubleSlot + 19] = (asDWORD)1; - paramBuffer[freeDoubleSlot++] = args[spos++]; - paramBuffer[freeDoubleSlot++] = args[spos++]; - - while(freeDoubleSlot < (VFP_OFFSET + 15) && paramBuffer[freeDoubleSlot + 18] != 0) - freeDoubleSlot += 2; - } - // If not, then store the double arg in the stack area - else - { - if ( (stackPos & 1) == mask ) - { - // 64 bit value align - stackPos++; - stackSize++; - } - - paramBuffer[stackPos++] = args[spos++]; - paramBuffer[stackPos++] = args[spos++]; - stackSize += 2; - } - - continue; - } - else - { - // Copy the value directly to "r" registers or the stack, checking for alignment - if (paramSize < 4) - { - // Should an alignment be performed? - if( (dpos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 && - !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() && - !descr->parameterTypes[n].IsAnyType() ) - { - // 64 bit value align - dpos++; - paramSize++; - } - - paramBuffer[dpos++] = args[spos++]; - paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - else - { - // Should an alignment be performed? - if( (stackPos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 && - !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() && - !descr->parameterTypes[n].IsAnyType() ) - { - // 64 bit value align - stackPos++; - stackSize++; - } - - paramBuffer[stackPos++] = args[spos++]; - stackSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - - if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) - { - if (paramSize < 5) - paramBuffer[dpos++] = args[spos++]; - else - paramBuffer[stackPos++] = args[spos++]; - } - }// else... - }// Loop - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJLAST && - callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) ) - { - if (paramSize < 4) - { - paramBuffer[dpos++] = (asDWORD)secondObject; - paramSize++; - } - else - { - paramBuffer[stackPos++] = (asDWORD)secondObject; - stackSize++; - } - } -#endif - // Keep a free location at the beginning - args = ¶mBuffer[2]; - } - - paramBuffer[69] = static_cast(stackSize<<2); - - switch( callConv ) - { - case ICC_CDECL_RETURNINMEM: // fall through - case ICC_STDCALL_RETURNINMEM: - retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer); - break; - case ICC_CDECL: // fall through - case ICC_STDCALL: - retQW = armFunc(args, paramSize<<2, func); - break; - case ICC_THISCALL: // fall through - case ICC_CDECL_OBJFIRST: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJFIRST: - case ICC_THISCALL_OBJLAST: -#endif - retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj); - break; - case ICC_THISCALL_RETURNINMEM: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_THISCALL_OBJLAST_RETURNINMEM: -#endif - // On GNUC the address where the return value will be placed should be put in R0 - retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); - break; - case ICC_CDECL_OBJFIRST_RETURNINMEM: - retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); - break; - case ICC_VIRTUAL_THISCALL: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_VIRTUAL_THISCALL_OBJFIRST: - case ICC_VIRTUAL_THISCALL_OBJLAST: -#endif - // Get virtual function table from the object pointer - vftable = *(asFUNCTION_t**)obj; - retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj); - break; - case ICC_VIRTUAL_THISCALL_RETURNINMEM: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: -#endif - // Get virtual function table from the object pointer - vftable = *(asFUNCTION_t**)obj; - // On GNUC the address where the return value will be placed should be put in R0 - retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj); - break; - case ICC_CDECL_OBJLAST: - retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj); - break; - case ICC_CDECL_OBJLAST_RETURNINMEM: - retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); - break; - default: - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - } - - // On Linux with arm the float and double values are returns in the - // floating point registers, s0 and s1. Objects that contain only - // float types and are not considered complex are also returned in the - // floating point registers. - if( sysFunc->hostReturnFloat ) - { - retQW = paramBuffer[VFP_OFFSET]; - - if ( sysFunc->hostReturnSize > 1 ) - retQW = *( (asQWORD*)¶mBuffer[VFP_OFFSET] ); - } - else if ( descr->returnType.IsObject() ) - { - // 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) ) - memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() ); - } - - return retQW; -} - -END_AS_NAMESPACE - -#endif // AS_LINUX - -#endif // AS_ARM -#endif // AS_MAX_PORTABILITY - - - - diff --git a/dependencies/angelscript/source/as_callfunc_arm_gcc.S b/dependencies/angelscript/source/as_callfunc_arm_gcc.S deleted file mode 100644 index e784925e..00000000 --- a/dependencies/angelscript/source/as_callfunc_arm_gcc.S +++ /dev/null @@ -1,698 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - -/* - Assembly routines for the ARM call convention - Written by Fredrik Ehnbom in June 2009 - - Adapted to GNUC by darktemplar216 in September 2009 - - Modified by Lasse Oorni for 8-byte stack alignment in May 2012 - - The assembler routines for Linux were written by Carlos Luna in December 2012 -*/ - -#if defined(__arm__) || defined(__ARM__) || defined(I3D_ARCH_ARM) - -#if !defined(__linux__) || defined(__ANDROID__) || defined(ANDROID) || defined(__SOFTFP__) - -/* iOS, Android, and Marmalade goes here */ - -.global armFunc -.global armFuncR0 -.global armFuncR0R1 -.global armFuncObjLast -.global armFuncR0ObjLast - -/* --------------------------------------------------------------------------------------------*/ -armFunc: - stmdb sp!, {r4-r8, lr} - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - mov r8, #0 - - beq nomoreargs - - /* Load the first 4 arguments into r0-r3 */ - cmp r7, #4 - ldrge r0, [r6],#4 - cmp r7, #2*4 - ldrge r1, [r6],#4 - cmp r7, #3*4 - ldrge r2, [r6],#4 - cmp r7, #4*4 - ldrge r3, [r6],#4 - ble nomoreargs - - /* Load the rest of the arguments onto the stack */ - sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */ - add r8, r7, #4 /* ensure 8-byte stack alignment */ - bic r8, r8, #4 - sub sp, sp, r8 - mov r12, sp /* copy size != frame size, so store frame start sp */ -stackargsloop: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargsloop - mov sp, r12 -nomoreargs: - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - -/* --------------------------------------------------------------------------------------------*/ -armFuncObjLast: - stmdb sp!, {r4-r8, lr} - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - mov r8, #0 - - mov r0, r3 /* objlast. might get overwritten */ - mov r5, r3 /* objlast to temp reg */ - - beq nomoreargsarmFuncObjLast - - /* Load the first 4 arguments into r0-r3 */ - cmp r7, #4 - ldrge r0, [r6],#4 - cmp r7, #2*4 - ldrge r1, [r6],#4 - movlt r1, r5 - cmp r7, #3*4 - ldrge r2, [r6],#4 - movlt r2, r5 - cmp r7, #4*4 - ldrge r3, [r6],#4 - movlt r3, r5 - blt nomoreargsarmFuncObjLast - - /* Load the rest of the arguments onto the stack */ - sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */ - add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */ - bic r8, r8, #4 - str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */ - str r5, [sp,#-8] - sub sp, sp, r8 /* adjust frame */ - cmp r7, #0 /* we may also have come here with no extra params */ - beq nomoreargsarmFuncObjLast - mov r12, sp /* copy size != frame size, so store frame start sp */ -stackargslooparmFuncObjLast: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargslooparmFuncObjLast - mov sp, r12 -nomoreargsarmFuncObjLast: - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - -/* --------------------------------------------------------------------------------------------*/ -armFuncR0ObjLast: - stmdb sp!, {r4-r8, lr} - ldr r5, [sp,#6*4] /* objlast to temp reg */ - - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - mov r8, #0 - - mov r0, r3 /* r0 explicitly set */ - mov r1, r5 /* objlast. might get overwritten */ - - beq nomoreargsarmFuncR0ObjLast - - /* Load the first 3 arguments into r1-r3 */ - cmp r7, #1*4 - ldrge r1, [r6],#4 - cmp r7, #2*4 - ldrge r2, [r6],#4 - movlt r2, r5 - cmp r7, #3*4 - ldrge r3, [r6],#4 - movlt r3, r5 - blt nomoreargsarmFuncR0ObjLast - - /* Load the rest of the arguments onto the stack */ - sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */ - add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */ - bic r8, r8, #4 - str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */ - str r5, [sp,#-8] - sub sp, sp, r8 /* adjust frame */ - cmp r7, #0 /* we may also have come here with no extra params */ - beq nomoreargsarmFuncR0ObjLast - mov r12, sp /* copy size != frame size, so store frame start sp */ -stackargslooparmFuncR0ObjLast: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargslooparmFuncR0ObjLast - mov sp, r12 -nomoreargsarmFuncR0ObjLast: - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - -/* --------------------------------------------------------------------------------------------*/ -armFuncR0: - stmdb sp!, {r4-r8, lr} - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - mov r8, #0 - - mov r0, r3 /* r0 explicitly set */ - - beq nomoreargsarmFuncR0 - - /* Load the first 3 arguments into r1-r3 */ - cmp r7, #1*4 - ldrge r1, [r6],#4 - cmp r7, #2*4 - ldrge r2, [r6],#4 - cmp r7, #3*4 - ldrge r3, [r6],#4 - ble nomoreargsarmFuncR0 - - /* Load the rest of the arguments onto the stack */ - sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */ - add r8, r7, #4 /* ensure 8-byte stack alignment */ - bic r8, r8, #4 - sub sp, sp, r8 - mov r12, sp /* copy size != frame size, so store frame start sp */ -stackargslooparmFuncR0: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargslooparmFuncR0 - mov sp, r12 -nomoreargsarmFuncR0: - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - -/* --------------------------------------------------------------------------------------------*/ -armFuncR0R1: - stmdb sp!, {r4-r8, lr} - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - mov r8, #0 - - mov r0, r3 /* r0 explicitly set */ - ldr r1, [sp, #6*4] /* r1 explicitly set too */ - - beq nomoreargsarmFuncR0R1 - - /* Load the first 2 arguments into r2-r3 */ - cmp r7, #1*4 - ldrge r2, [r6],#4 - cmp r7, #2*4 - ldrge r3, [r6],#4 - ble nomoreargsarmFuncR0R1 - - /* Load the rest of the arguments onto the stack */ - sub r7, r7, #2*4 /* skip the 2 registers already loaded into r2-r3 */ - add r8, r7, #4 /* ensure 8-byte stack alignment */ - bic r8, r8, #4 - sub sp, sp, r8 - mov r12, sp /* copy size != frame size, so store frame start sp */ -stackargslooparmFuncR0R1: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargslooparmFuncR0R1 - mov sp, r12 -nomoreargsarmFuncR0R1: - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - -/* --------------------------------------------------------------------------------------------*/ -#elif defined(__linux__) && !defined(__SOFTFP__) - -/* The Linux code goes here */ - - -/* These codes are suitable for armeabi + vfp / armeabihf */ -/* when using armeabi + vfp, please set C_FLAGS -mfloat-abi=softfp -mfpu=vfp */ -/* using armeabihf, please set C_FLAGS -mfloat-abi=hard -mfpu=vfpv3-d16 */ - -/* if you prefer to run in ARM mode, please add -marm to C_FLAGS */ -/* while using thumb mode, please add -mthumb -Wa,-mimplicit-it=thumb */ - - -/* SP is a multiple of 8 when control first enters a program.*/ -/* This places an obligation on authors of low level OS, RTOS, and runtime library code to align SP at all points */ -/* at which control first enters a body of (AAPCS-conforming) code. (please read "ARM IHI 0046B" document)*/ - - -.section .text - - .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ -#if defined(__thumb__) || defined(__thumb2__) - .thumb - .syntax unified -#else - .arm /* Use ARM instructions instead of Thumb.*/ -#endif - .globl armFunc /* Make the function globally accessible.*/ -armFunc: - push {r4-r8, r10, r11, lr} /* sp must be 8-byte alignment for ABI compliance, so the pushed registers must be even */ - - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - - /* Load float and double args into d0-d7 and s0-s15 */ - add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ - mov r8, #0 - vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ - - /* If there are no arguments to set into r0-r3 */ - /* go check if there are arguments for the stack */ - beq stackargs - - /* Load the first 4 arguments into r0-r3 */ - cmp r7, #4 - ldrge r0, [r6] - cmp r7, #8 - ldrge r1, [r6, #4] - cmp r7, #12 - ldrge r2, [r6, #8] - cmp r7, #16 - ldrge r3, [r6, #12] - -stackargs: - ldr r5, [r6, #268] /* Load stack size into r5 */ - movs r7, r5 /* Load stack size into r7, checking for 0 args */ - - /* If there are no args for the stack, branch */ - beq nomoreargs - - /* Load the rest of the arguments onto the stack */ - /* Ensure 8-byte stack alignment */ - mov r8, sp - sub sp, sp, r7 - add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ - - sub r12, sp, #8 - bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ - sub r8, r8, r12 - mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ - -stackargsloop: - ldr r5, [r6], #4 - subs r7, r7, #4 - str r5, [sp], #4 - bne stackargsloop - mov sp, r12 - -nomoreargs: -#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) - mov lr, pc /* older ARM didn't support blx */ - mov pc, r4 -#else - blx r4 -#endif - add sp, sp, r8 - vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d7 to the address stored in r10 */ - - pop {r4-r8, r10, r11, pc} - -/* --------------------------------------------------------------------------------------------*/ - .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ -#if defined(__thumb__) || defined(__thumb2__) - .thumb - .syntax unified -#else - .arm /* Use ARM instructions instead of Thumb.*/ -#endif - .globl armFuncObjLast /* Make the function globally accessible.*/ -armFuncObjLast: - push {r4-r8, r10, r11, lr} /* We´re storing r11 just to keep the stack aligned to an 8 byte boundary */ - - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - - mov r0, r3 /* objlast. might get overwritten */ - mov r5, #0 /* This will hold an offset of #4 only if objlast couldn´t be placed into an "r" register */ - - /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ - add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ - mov r8, #0 - vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ - - /* If there are no arguments to set into r0-r3 */ - /* go check if there are arguments for the stack */ - beq stackargsFuncObjLast - - mov r5, r3 /* store objlast in r5 temporarily */ - - /* Load the first 4 arguments into r0-r3 */ - cmp r7, #4 - ldrge r0, [r6] - cmp r7, #8 - ldrge r1, [r6,#4] - movlt r1, r5 - cmp r7, #12 - ldrge r2, [r6,#8] - movlt r2, r5 - cmp r7, #16 - ldrge r3, [r6,#12] - movlt r3, r5 - movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */ - blt stackargsFuncObjLast /* If objlast got placed into a register, go to stackargsFuncObjLast */ - - str r5, [r6, #12] /* Put objlast in r6 + 12 */ - mov r5, #4 /* Set r5 with an offset of #4, so objlast can be loaded into the stack */ - -stackargsFuncObjLast: - ldr r7, [r6, #268] /* Load stack size into r7 */ - add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */ - cmp r7, #0 /* Check for 0 args */ - - /* If there are no args for the stack, branch */ - beq nomoreargsarmFuncObjLast - - /* Load the rest of the arguments onto the stack */ - /* Ensure 8-byte stack alignment */ - mov r8, sp - sub sp, sp, r7 - add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ - - sub r12, sp, #8 - sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */ - bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ - sub r8, r8, r12 - mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ - -stackargslooparmFuncObjLast: - ldr r5, [r6], #4 - subs r7, r7, #4 - str r5, [sp], #4 - bne stackargslooparmFuncObjLast - mov sp, r12 - -nomoreargsarmFuncObjLast: -#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) - mov lr, pc - mov pc, r4 -#else - blx r4 -#endif - add sp, sp, r8 - vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ - - pop {r4-r8, r10,r11, pc} - -/* ------------------------------------------------------------------------------------------- */ - .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ -#if defined(__thumb__) || defined(__thumb2__) - .thumb - .syntax unified -#else - .arm /* Use ARM instructions instead of Thumb.*/ -#endif - .globl armFuncR0ObjLast /* Make the function globally accessible.*/ -armFuncR0ObjLast: - push {r4-r8, r10, r11, lr} - - ldr r5, [sp,#32] /* objlast to temp reg */ - - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - - mov r0, r3 /* r0 explicitly set */ - mov r1, r5 /* objlast. might get overwritten */ - mov r5, #0 /* This will hold an offset of #4 or #8 if objlast or one arg couldn´t be placed into an "r" register */ - - /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ - add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ - mov r8, #0 - vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ - - /* If there are no arguments to set into r0-r3 */ - /* go check if there are arguments for the stack */ - beq stackargsFuncR0ObjLast - - mov r5, r1 /* store objlast in r5 temporarily */ - - /* Load the first 3 arguments into r1-r3 */ - cmp r7, #4 - ldrge r1, [r6] - cmp r7, #8 - ldrge r2, [r6,#4] - movlt r2, r5 - cmp r7, #12 - ldrge r3, [r6,#8] - movlt r3, r5 - movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */ - blt stackargsFuncR0ObjLast /* If objlast got placed into a register, go to stackargsFuncR0ObjLast */ - - cmp r7, #16 /* Else if we have one last arg set the offset accordingly and store the arg in the array */ - ldrge r7, [r6, #12] - strge r7, [r6, #8] - - str r5, [r6, #12] /* Put objlast in r6 + 12 */ - - movge r5, #4 /* Set r5 with an offset of #4 if there´s one last arg that couldn´t be placed in r registers */ - add r5, r5, #4 /* Set r5 with an offset of + #4, so objlast can be loaded into the stack */ - -stackargsFuncR0ObjLast: - ldr r7, [r6, #268] /* Load stack size into r7 */ - add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */ - cmp r7, #0 /* Check for 0 args */ - - /* If there are no args for the stack, branch */ - beq nomoreargsarmFuncR0ObjLast - - /* Load the rest of the arguments onto the stack */ - /* Ensure 8-byte stack alignment */ - mov r8, sp - sub sp, sp, r7 - add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ - - sub r12, sp, #8 - sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */ - bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ - sub r8, r8, r12 - mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ - -stackargslooparmFuncR0ObjLast: - ldr r5, [r6], #4 - subs r7, r7, #4 - str r5, [sp], #4 - bne stackargslooparmFuncR0ObjLast - mov sp, r12 - -nomoreargsarmFuncR0ObjLast: -#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) - mov lr, pc - mov pc, r4 -#else - blx r4 -#endif - add sp, sp, r8 - vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ - - pop {r4-r8, r10, r11, pc} - -/* ------------------------------------------------------------------------------------------- */ - .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ -#if defined(__thumb__) || defined(__thumb2__) - .thumb - .syntax unified -#else - .arm /* Use ARM instructions instead of Thumb.*/ -#endif - .globl armFuncR0 /* Make the function globally accessible.*/ -armFuncR0: - push {r4-r8, r10, r11, lr} - - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - mov r11, #0 /* This will hold an offset of #4 only if the last arg that should have been placed into an "r" reg needs to go to the stack */ - mov r0, r3 /* r0 explicitly set */ - - /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ - add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ - mov r8, #0 - vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ - - /* If there are no arguments to set into r0-r3 */ - /* go check if there are arguments for the stack */ - beq stackargsarmFuncR0 - - /* Load the first 3 arguments into r1-r3 */ - cmp r7, #4 - ldrge r1, [r6] - cmp r7, #8 - ldrge r2, [r6, #4] - cmp r7, #12 - ldrge r3, [r6, #8] - cmp r7, #16 - movge r11, #4 /* If there is still one arg to be placed, set the offset in r11 to #4 */ - -stackargsarmFuncR0: - ldr r5, [r6, #268] /* Load stack size into r5 */ - add r5, r11 /* Add the offset placed in r11 (could be #0 or #4) */ - movs r7, r5 /* Load stack size into r7, checking for 0 args */ - - /* If there are no args for the stack, branch */ - beq nomoreargsarmFuncR0 - - /* Load the rest of the arguments onto the stack */ - /* Ensure 8-byte stack alignment */ - mov r8, sp - sub sp, sp, r7 - add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ - - sub r12, sp, #8 - sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4) */ - bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ - sub r8, r8, r12 - mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ - -stackargslooparmFuncR0: - ldr r5, [r6], #4 - subs r7, r7, #4 - str r5, [sp], #4 - bne stackargslooparmFuncR0 - mov sp, r12 - -nomoreargsarmFuncR0: -#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) - mov lr, pc - mov pc, r4 -#else - blx r4 -#endif - add sp, sp, r8 - vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ - - pop {r4-r8, r10, r11, pc} - -/* ------------------------------------------------------------------------------------------- */ - .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ -#if defined(__thumb__) || defined(__thumb2__) - .thumb - .syntax unified -#else - .arm /* Use ARM instructions instead of Thumb.*/ -#endif - .globl armFuncR0R1 /* Make the function globally accessible.*/ -armFuncR0R1: - push {r4-r8, r10, r11, lr} - - mov r6, r0 /* arg table */ - movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ - mov r4, r2 /* function address */ - mov r11, #0 /* This will hold an offset of #4 or #8 only if the last arg (or last 2 args) that should have been placed into "r" regs need to go to the stack */ - - mov r0, r3 /* r0 explicitly set */ - ldr r1, [sp, #32] /* r1 explicitly set too */ - - /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ - add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ - mov r8, #0 - vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ - - /* If there are no arguments to set into r2-r3 */ - /* go check if there are arguments for the stack */ - beq stackargsarmFuncR0R1 - - /* Load the first 2 arguments into r2-r3 */ - cmp r7, #4 - ldrge r2, [r6] - cmp r7, #8 - ldrge r3, [r6, #4] - cmp r7, #12 - movge r11, #4 /* If there is a third arg to be placed, set the offset in r11 to #4 */ - cmp r7, #16 - movge r11, #8 /* If there is a fourth arg to be placed, set the offset in r11 to #8 */ - ldrlt r7, [r6, #8] /* Else copy the third arg to the correct place in the array */ - strlt r7, [r6, #12] - -stackargsarmFuncR0R1: - ldr r5, [r6, #268] /* Load stack size into r5 */ - add r5, r11 /* Add the offset placed in r11 (could be #0 or #4 or #8) */ - movs r7, r5 /* Load stack size into r7, checking for 0 args */ - - /* If there are no args for the stack, branch */ - beq nomoreargsarmFuncR0R1 - - /* Load the rest of the arguments onto the stack */ - /* Ensure 8-byte stack alignment */ - mov r8, sp - sub sp, sp, r7 - add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ - - sub r12, sp, #8 - sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4 or #8) */ - bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ - sub r8, r8, r12 - mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ - -stackargslooparmFuncR0R1: - ldr r5, [r6], #4 - subs r7, r7, #4 - str r5, [sp], #4 - bne stackargslooparmFuncR0R1 - mov sp, r12 - -nomoreargsarmFuncR0R1: -#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) - mov lr, pc - mov pc, r4 -#else - blx r4 -#endif - add sp, sp, r8 - vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ - - pop {r4-r8, r10, r11, pc} - -#endif /* hard float abi */ - -#if defined(__linux__) && defined(__ELF__) -/* ref: http://hardened.gentoo.org/gnu-stack.xml */ -.section .note.GNU-stack,"",%progbits -#endif - -#endif /* arm */ - diff --git a/dependencies/angelscript/source/as_callfunc_arm_msvc.asm b/dependencies/angelscript/source/as_callfunc_arm_msvc.asm deleted file mode 100644 index 05bcddfb..00000000 --- a/dependencies/angelscript/source/as_callfunc_arm_msvc.asm +++ /dev/null @@ -1,249 +0,0 @@ -; -; AngelCode Scripting Library -; Copyright (c) 2003-2013 Andreas Jonsson -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any -; purpose, including commercial applications, and to alter it and -; redistribute it freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you -; must not claim that you wrote the original software. If you use -; this software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; -; 2. Altered source versions must be plainly marked as such, and -; must not be misrepresented as being the original software. -; -; 3. This notice may not be removed or altered from any source -; distribution. -; -; The original version of this library can be located at: -; http://www.angelcode.com/angelscript/ -; -; Andreas Jonsson -; andreas@angelcode.com -; - - -; Assembly routines for the ARM call convention -; Written by Fredrik Ehnbom in June 2009 - -; MSVC currently doesn't support inline assembly for the ARM platform -; so this separate file is needed. - -; Compile with Microsoft ARM assembler (armasm) -; http://msdn.microsoft.com/en-us/library/hh873190.aspx - - - AREA |.rdata|, DATA, READONLY - EXPORT armFunc - EXPORT armFuncR0 - EXPORT armFuncR0R1 - EXPORT armFuncObjLast - EXPORT armFuncR0ObjLast - - AREA |.text|, CODE, ARM, ALIGN=3 - - ALIGN 8 -armFunc PROC - stmdb sp!, {r4-r8, lr} - mov r6, r0 ; arg table - movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 ; function address - mov r8, #0 - - beq |nomoreargs| - - ; Load the first 4 arguments into r0-r3 - cmp r7, #4 - ldrge r0, [r6],#4 - cmp r7, #2*4 - ldrge r1, [r6],#4 - cmp r7, #3*4 - ldrge r2, [r6],#4 - cmp r7, #4*4 - ldrge r3, [r6],#4 - ble |nomoreargs| - - ; Load the rest of the arguments onto the stack - sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3 - sub sp, sp, r7 - mov r8, r7 -|stackargsloop| - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne |stackargsloop| -|nomoreargs| - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - ENDP - - ALIGN 8 -armFuncObjLast PROC - stmdb sp!, {r4-r8, lr} - mov r6, r0 ; arg table - movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 ; function address - mov r8, #0 - - mov r0, r3 ; objlast. might get overwritten - str r3, [sp, #-4]! ; objlast again. - - beq |nomoreargs@armFuncObjLast| - - ; Load the first 4 arguments into r0-r3 - cmp r7, #4 - ldrge r0, [r6],#4 - cmp r7, #2*4 - ldrge r1, [r6],#4 - ldrlt r1, [sp] - cmp r7, #3*4 - ldrge r2, [r6],#4 - ldrlt r2, [sp] - cmp r7, #4*4 - ldrge r3, [r6],#4 - ldrlt r3, [sp] - ble |nomoreargs@armFuncObjLast| - - ; Load the rest of the arguments onto the stack - sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3 - sub sp, sp, r7 - mov r8, r7 -|stackargsloop@armFuncObjLast| - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne |stackargsloop@armFuncObjLast| -|nomoreargs@armFuncObjLast| - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - add sp, sp, #4 - ldmia sp!, {r4-r8, pc} - ENDP - - ALIGN 8 -armFuncR0ObjLast PROC - stmdb sp!, {r4-r8, lr} - ldr r7, [sp,#6*4] - str r7, [sp,#-4]! - - mov r6, r0 ; arg table - movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 ; function address - mov r8, #0 - - mov r0, r3 ; r0 explicitly set - ldr r1, [sp] ; objlast. might get overwritten - - beq |nomoreargs@armFuncR0ObjLast| - - ; Load the first 3 arguments into r1-r3 - cmp r7, #1*4 - ldrge r1, [r6],#4 - cmp r7, #2*4 - ldrge r2, [r6],#4 - ldrlt r2, [sp] - cmp r7, #3*4 - ldrge r3, [r6],#4 - ldrlt r3, [sp] - ble |nomoreargs@armFuncR0ObjLast| - - ; Load the rest of the arguments onto the stack - sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3 - sub sp, sp, r7 - mov r8, r7 -|stackargsloop@armFuncR0ObjLast| - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne |stackargsloop@armFuncR0ObjLast| -|nomoreargs@armFuncR0ObjLast| - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - add sp, sp, #4 - ldmia sp!, {r4-r8, pc} - ENDP - - ALIGN 8 -armFuncR0 PROC - stmdb sp!, {r4-r8, lr} - mov r6, r0 ; arg table - movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 ; function address - mov r8, #0 - - mov r0, r3 ; r0 explicitly set - - beq |nomoreargs@armFuncR0| - - ; Load the first 3 arguments into r1-r3 - cmp r7, #1*4 - ldrge r1, [r6],#4 - cmp r7, #2*4 - ldrge r2, [r6],#4 - cmp r7, #3*4 - ldrge r3, [r6],#4 - ble |nomoreargs@armFuncR0| - - ; Load the rest of the arguments onto the stack - sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3 - sub sp, sp, r7 - mov r8, r7 -|stackargsloop@armFuncR0| - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne |stackargsloop@armFuncR0| -|nomoreargs@armFuncR0| - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - ENDP - - ALIGN 8 -armFuncR0R1 PROC - stmdb sp!, {r4-r8, lr} - mov r6, r0 ; arg table - movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 ; function address - mov r8, #0 - - mov r0, r3 ; r0 explicitly set - ldr r1, [sp, #6*4] ; r1 explicitly set too - - beq |nomoreargs@armFuncR0R1| - - ; Load the first 2 arguments into r2-r3 - cmp r7, #1*4 - ldrge r2, [r6],#4 - cmp r7, #2*4 - ldrge r3, [r6],#4 - ble |nomoreargs@armFuncR0R1| - - ; Load the rest of the arguments onto the stack - sub r7, r7, #2*4 ; skip the 2 registers already loaded into r2-r3 - sub sp, sp, r7 - mov r8, r7 -|stackargsloop@armFuncR0R1| - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne |stackargsloop@armFuncR0R1| -|nomoreargs@armFuncR0R1| - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - ENDP - - END diff --git a/dependencies/angelscript/source/as_callfunc_arm_xcode.S b/dependencies/angelscript/source/as_callfunc_arm_xcode.S deleted file mode 100644 index c3de382f..00000000 --- a/dependencies/angelscript/source/as_callfunc_arm_xcode.S +++ /dev/null @@ -1,237 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2009 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// Assembly routines for the ARM call convention -// Written by Fredrik Ehnbom in June 2009 - -// Adapted to GNUC by darktemplar216 in September 2009 -// Small fixed to work under XCode GCC by Gilad Novik in October 2009 - -#if defined(__arm__) || defined(__ARM__) - -.align 2 -.globl _armFunc -.globl _armFuncR0 -.globl _armFuncR0R1 -.globl _armFuncObjLast -.globl _armFuncR0ObjLast - -_armFunc: - stmdb sp!, {r4-r8, lr} - mov r6, r0 // arg table - movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 // function address - mov r8, #0 - - beq nomoreargs - - // Load the first 4 arguments into r0-r3 - cmp r7, #4 - ldrge r0, [r6],#4 - cmp r7, #2*4 - ldrge r1, [r6],#4 - cmp r7, #3*4 - ldrge r2, [r6],#4 - cmp r7, #4*4 - ldrge r3, [r6],#4 - ble nomoreargs - - // Load the rest of the arguments onto the stack - sub r7, r7, #4*4 // skip the 4 registers already loaded into r0-r3 - sub sp, sp, r7 - mov r8, r7 -stackargsloop: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargsloop -nomoreargs: - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - -_armFuncObjLast: - stmdb sp!, {r4-r8, lr} - mov r6, r0 // arg table - movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 // function address - mov r8, #0 - - mov r0, r3 // objlast. might get overwritten - str r3, [sp, #-4]! // objlast again. - - beq nomoreargsarmFuncObjLast - - // Load the first 4 arguments into r0-r3 - cmp r7, #4 - ldrge r0, [r6],#4 - cmp r7, #2*4 - ldrge r1, [r6],#4 - ldrlt r1, [sp] - cmp r7, #3*4 - ldrge r2, [r6],#4 - ldrlt r2, [sp] - cmp r7, #4*4 - ldrge r3, [r6],#4 - ldrlt r3, [sp] - ble nomoreargsarmFuncObjLast - - // Load the rest of the arguments onto the stack - sub r7, r7, #4*4 // skip the 4 registers already loaded into r0-r3 - sub sp, sp, r7 - mov r8, r7 -stackargslooparmFuncObjLast: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargslooparmFuncObjLast -nomoreargsarmFuncObjLast: - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - add sp, sp, #4 - ldmia sp!, {r4-r8, pc} - -_armFuncR0ObjLast: - stmdb sp!, {r4-r8, lr} - ldr r7, [sp,#6*4] - str r7, [sp,#-4]! - - mov r6, r0 // arg table - movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 // function address - mov r8, #0 - - mov r0, r3 // r0 explicitly set - ldr r1, [sp] // objlast. might get overwritten - - beq nomoreargsarmFuncR0ObjLast - - // Load the first 3 arguments into r1-r3 - cmp r7, #1*4 - ldrge r1, [r6],#4 - cmp r7, #2*4 - ldrge r2, [r6],#4 - ldrlt r2, [sp] - cmp r7, #3*4 - ldrge r3, [r6],#4 - ldrlt r3, [sp] - ble nomoreargsarmFuncR0ObjLast - - // Load the rest of the arguments onto the stack - sub r7, r7, #3*4 // skip the 3 registers already loaded into r1-r3 - sub sp, sp, r7 - mov r8, r7 -stackargslooparmFuncR0ObjLast: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargslooparmFuncR0ObjLast -nomoreargsarmFuncR0ObjLast: - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - add sp, sp, #4 - ldmia sp!, {r4-r8, pc} - - -_armFuncR0: - stmdb sp!, {r4-r8, lr} - mov r6, r0 // arg table - movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 // function address - mov r8, #0 - - mov r0, r3 // r0 explicitly set - - beq nomoreargsarmFuncR0 - - // Load the first 3 arguments into r1-r3 - cmp r7, #1*4 - ldrge r1, [r6],#4 - cmp r7, #2*4 - ldrge r2, [r6],#4 - cmp r7, #3*4 - ldrge r3, [r6],#4 - ble nomoreargsarmFuncR0 - - // Load the rest of the arguments onto the stack - sub r7, r7, #3*4 // skip the 3 registers already loaded into r1-r3 - sub sp, sp, r7 - mov r8, r7 -stackargslooparmFuncR0: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargslooparmFuncR0 -nomoreargsarmFuncR0: - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - - -_armFuncR0R1: - stmdb sp!, {r4-r8, lr} - mov r6, r0 // arg table - movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) - mov r4, r2 // function address - mov r8, #0 - - mov r0, r3 // r0 explicitly set - ldr r1, [sp, #6*4] // r1 explicitly set too - - beq nomoreargsarmFuncR0R1 - - // Load the first 2 arguments into r2-r3 - cmp r7, #1*4 - ldrge r2, [r6],#4 - cmp r7, #2*4 - ldrge r3, [r6],#4 - ble nomoreargsarmFuncR0R1 - - // Load the rest of the arguments onto the stack - sub r7, r7, #2*4 // skip the 2 registers already loaded into r2-r3 - sub sp, sp, r7 - mov r8, r7 -stackargslooparmFuncR0R1: - ldr r5, [r6], #4 - str r5, [sp], #4 - subs r7, r7, #4 - bne stackargslooparmFuncR0R1 -nomoreargsarmFuncR0R1: - sub sp, sp, r8 - blx r4 - add sp, sp, r8 - ldmia sp!, {r4-r8, pc} - -#endif diff --git a/dependencies/angelscript/source/as_callfunc_mips.cpp b/dependencies/angelscript/source/as_callfunc_mips.cpp deleted file mode 100644 index 69dfd765..00000000 --- a/dependencies/angelscript/source/as_callfunc_mips.cpp +++ /dev/null @@ -1,440 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc_mips.cpp -// -// These functions handle the actual calling of system functions -// -// This version is MIPS specific and was originally written -// by Manu Evans in April, 2006 -// - - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_MIPS - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_tokendef.h" -#include "as_context.h" - -#include -#include -#include - -BEGIN_AS_NAMESPACE - -#define AS_MIPS_MAX_ARGS 32 -#define AS_NUM_REG_FLOATS 8 -#define AS_NUM_REG_INTS 8 - -// The array used to send values to the correct places. -// first 0-8 regular values to load into the a0-a3, t0-t3 registers -// then 0-8 float values to load into the f12-f19 registers -// then (AS_MIPS_MAX_ARGS - 16) values to load onto the stack -// the +1 is for when CallThis (object methods) is used -// extra +1 when returning in memory -extern "C" { -// TODO: This array shouldn't be global. It should be a local array in CallSystemFunctionNative -asDWORD mipsArgs[AS_MIPS_MAX_ARGS + 1 + 1]; -} - -// Loads all data into the correct places and calls the function. -// intArgSize is the size in bytes for how much data to put in int registers -// floatArgSize is the size in bytes for how much data to put in float registers -// stackArgSize is the size in bytes for how much data to put on the callstack -extern "C" asQWORD mipsFunc(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func); - -// puts the arguments in the correct place in the mipsArgs-array. See comments above. -// This could be done better. -inline void splitArgs(const asDWORD *args, int argNum, int &numRegIntArgs, int &numRegFloatArgs, int &numRestArgs, int hostFlags) -{ - int i; - - int argBit = 1; - for (i = 0; i < argNum; i++) - { - if (hostFlags & argBit) - { - if (numRegFloatArgs < AS_NUM_REG_FLOATS) - { - // put in float register - mipsArgs[AS_NUM_REG_INTS + numRegFloatArgs] = args[i]; - numRegFloatArgs++; - } - else - { - // put in stack - mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + numRestArgs] = args[i]; - numRestArgs++; - } - } - else - { - if (numRegIntArgs < AS_NUM_REG_INTS) - { - // put in int register - mipsArgs[numRegIntArgs] = args[i]; - numRegIntArgs++; - } - else - { - // put in stack - mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + numRestArgs] = args[i]; - numRestArgs++; - } - } - argBit <<= 1; - } -} - -asQWORD CallCDeclFunction(const asDWORD *args, int argSize, asDWORD func, int flags) -{ - int argNum = argSize >> 2; - - int intArgs = 0; - int floatArgs = 0; - int restArgs = 0; - - // put the arguments in the correct places in the mipsArgs array - if(argNum > 0) - splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); - - return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func); -} - -// This function is identical to CallCDeclFunction, with the only difference that -// the value in the first parameter is the object -asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags) -{ - int argNum = argSize >> 2; - - int intArgs = 1; - int floatArgs = 0; - int restArgs = 0; - - mipsArgs[0] = (asDWORD) obj; - - // put the arguments in the correct places in the mipsArgs array - if (argNum > 0) - splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); - - return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func); -} - -// This function is identical to CallCDeclFunction, with the only difference that -// the value in the last parameter is the object -asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags) -{ - int argNum = argSize >> 2; - - int intArgs = 0; - int floatArgs = 0; - int restArgs = 0; - - // put the arguments in the correct places in the mipsArgs array - if(argNum > 0) - splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); - - if(intArgs < AS_NUM_REG_INTS) - { - mipsArgs[intArgs] = (asDWORD) obj; - intArgs++; - } - else - { - mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + restArgs] = (asDWORD) obj; - restArgs++; - } - - return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func); -} - -asDWORD GetReturnedFloat() -{ - asDWORD f; - - asm("swc1 $f0, %0\n" : "=m"(f)); - - return f; -} - -/* -asDWORD GetReturnedFloat(); - -asm( -" .align 4\n" -" .global GetReturnedFloat\n" -"GetReturnedFloat:\n" -" .set noreorder\n" -" .set nomacro\n" -" j $ra\n" -" mfc1 $v0, $f0\n" -" .set macro\n" -" .set reorder\n" -" .end Func\n" -*/ - - -// sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4 -// so this isn't really used... -asQWORD GetReturnedDouble() -{ - asQWORD d = 0; - - printf("Broken!!!"); -/* - asm("sw $v0, %0\n" : "=m"(d)); -*/ - return d; -} - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - int callConv = sysFunc->callConv; - - asQWORD retQW = 0; - - void *func = (void*)sysFunc->func; - int paramSize = sysFunc->paramSize; - asDWORD *vftable; - - if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() ) - { - mipsArgs[AS_MIPS_MAX_ARGS+1] = (asDWORD) retPointer; - } - - asASSERT(descr->parameterTypes.GetLength() <= AS_MIPS_MAX_ARGS); - - // mark all float arguments - int argBit = 1; - int hostFlags = 0; - int intArgs = 0; - for( size_t a = 0; a < descr->parameterTypes.GetLength(); a++ ) - { - if (descr->parameterTypes[a].IsFloatType()) - hostFlags |= argBit; - else - intArgs++; - argBit <<= 1; - } - - asDWORD paramBuffer[64]; - if( sysFunc->takesObjByVal ) - { - paramSize = 0; - int spos = 0; - int dpos = 1; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - 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 ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else -#endif - { - // Copy the object's memory to the buffer - memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos++; - dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); - paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); - } - } - else - { - // Copy the value directly - paramBuffer[dpos++] = args[spos++]; - if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) - paramBuffer[dpos++] = args[spos++]; - paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - } - // Keep a free location at the beginning - args = ¶mBuffer[1]; - } - - switch( callConv ) - { - case ICC_CDECL: - case ICC_CDECL_RETURNINMEM: - case ICC_STDCALL: - case ICC_STDCALL_RETURNINMEM: - retQW = CallCDeclFunction(args, paramSize<<2, (asDWORD)func, hostFlags); - break; - case ICC_THISCALL: - case ICC_THISCALL_RETURNINMEM: - retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags); - break; - case ICC_VIRTUAL_THISCALL: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - // Get virtual function table from the object pointer - vftable = *(asDWORD**)obj; - retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[asDWORD(func)>>2], hostFlags); - break; - case ICC_CDECL_OBJLAST: - case ICC_CDECL_OBJLAST_RETURNINMEM: - retQW = CallThisCallFunction_objLast(obj, args, paramSize<<2, (asDWORD)func, hostFlags); - break; - case ICC_CDECL_OBJFIRST: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags); - break; - default: - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - } - - // If the return is a float value we need to get the value from the FP register - if( sysFunc->hostReturnFloat ) - { - if( sysFunc->hostReturnSize == 1 ) - *(asDWORD*)&retQW = GetReturnedFloat(); - else - retQW = GetReturnedDouble(); - } - - return retQW; -} - - -asm( -" .text\n" -//" .align 2\n" -" .global mipsFunc\n" -" .ent mipsFunc\n" -"mipsFunc:\n" -//" .frame $fp,64,$31 # vars= 0, regs= 0/0, args= 0, gp= 0\n" -//" .mask 0x00000000,0\n" -//" .fmask 0x00000000,0\n" -" .set noreorder\n" -" .set nomacro\n" -// align the stack frame to 8 bytes -" addiu $12, $6, 7\n" -" li $13, -8\n" // 0xfffffffffffffffc -" and $12, $12, $13\n" // t4 holds the size of the argument block -// and add 8 bytes for the return pointer and s0 backup -" addiu $13, $12, 8\n" // t5 holds the total size of the stack frame (including return pointer) -// save the s0 register (so we can use it to remember where our return pointer is lives) -" sw $16, -4($sp)\n" // store the s0 register (so we can use it to remember how big our stack frame is) -// push the stack -" subu $sp, $sp, $13\n" -// find the return address, place in s0 -" addu $16, $sp, $12\n" -// store the return pointer -" sw $31, 0($16)\n" - -// backup our function params -" addiu $2, $7, 0\n" -" addiu $3, $6, 0\n" - -// get global mipsArgs[] array pointer -//" lui $15, %hi(mipsArgs)\n" -//" addiu $15, $15, %lo(mipsArgs)\n" -// we'll use the macro instead because SN Systems doesnt like %hi/%lo -".set macro\n" -" la $15, mipsArgs\n" -".set nomacro\n" -// load register params -" lw $4, 0($15)\n" -" lw $5, 4($15)\n" -" lw $6, 8($15)\n" -" lw $7, 12($15)\n" -" lw $8, 16($15)\n" -" lw $9, 20($15)\n" -" lw $10, 24($15)\n" -" lw $11, 28($15)\n" - -// load float params -" lwc1 $f12, 32($15)\n" -" lwc1 $f13, 36($15)\n" -" lwc1 $f14, 40($15)\n" -" lwc1 $f15, 44($15)\n" -" lwc1 $f16, 48($15)\n" -" lwc1 $f17, 52($15)\n" -" lwc1 $f18, 56($15)\n" -" lwc1 $f19, 60($15)\n" - -// skip stack paramaters if there are none -" beq $3, $0, andCall\n" - -// push stack paramaters -" addiu $15, $15, 64\n" -"pushArgs:\n" -" addiu $3, -4\n" -// load from $15 + stack bytes ($3) -" addu $14, $15, $3\n" -" lw $14, 0($14)\n" -// store to $sp + stack bytes ($3) -" addu $13, $sp, $3\n" -" sw $14, 0($13)\n" -// if there are more, loop... -" bne $3, $0, pushArgs\n" -" nop\n" - -// and call the function -"andCall:\n" -" jal $2\n" -" nop\n" - -// restore the return pointer -" lw $31, 0($16)\n" -// pop the stack pointer (remembering the return pointer was 8 bytes below the top) -" addiu $sp, $16, 8\n" -// and return from the function -" jr $31\n" -// restore the s0 register (in the branch delay slot) -" lw $16, -4($sp)\n" -" .set macro\n" -" .set reorder\n" -" .end mipsFunc\n" -" .size mipsFunc, .-mipsFunc\n" -); - -END_AS_NAMESPACE - -#endif // AS_MIPS -#endif // AS_MAX_PORTABILITY - - - - diff --git a/dependencies/angelscript/source/as_callfunc_ppc.cpp b/dependencies/angelscript/source/as_callfunc_ppc.cpp deleted file mode 100644 index 2b6c65ee..00000000 --- a/dependencies/angelscript/source/as_callfunc_ppc.cpp +++ /dev/null @@ -1,672 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc_ppc.cpp -// -// These functions handle the actual calling of system functions -// -// This version is PPC specific -// - -#include - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_PPC - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_tokendef.h" -#include "as_context.h" - -#include - -BEGIN_AS_NAMESPACE - -// This part was originally written by Pecan Heber, June 2006, for -// use on MacOS X with 32bit PPC processor. He based the code on the -// code in as_callfunc_sh4.cpp - -#define AS_PPC_MAX_ARGS 32 - -// The array used to send values to the correct places. -// Contains a byte of argTypes to indicate the register tYpe to load -// or zero if end of arguments -// The +1 is for when CallThis (object methods) is used -// Extra +1 when returning in memory -// Extra +1 in ppcArgsType to ensure zero end-of-args marker - -// TODO: multithread: We need to remove these global variables for thread-safety - -enum argTypes { ppcENDARG, ppcINTARG, ppcFLOATARG, ppcDOUBLEARG }; -static asDWORD ppcArgs[2*AS_PPC_MAX_ARGS + 1 + 1]; - -// Using extern "C" because we use this symbol name in the assembly code -extern "C" -{ - static asBYTE ppcArgsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1]; -} - -// NOTE: these values are for PowerPC 32 bit. -#define PPC_LINKAGE_SIZE (24) // how big the PPC linkage area is in a stack frame -#define PPC_NUM_REGSTORE (9) // how many registers of the PPC we need to store/restore for ppcFunc() -#define PPC_REGSTORE_SIZE (4*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore -#define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame -#define PPC_STACK_SIZE(numParams) (-( ( ((((numParams)<8)?8:(numParams))<<2) + EXTRA_STACK_SIZE + 15 ) & ~15 )) // calculates the total stack size needed for ppcFunc64, must pad to 16bytes - -// Loads all data into the correct places and calls the function. -// ppcArgsType is an array containing a byte type (enum argTypes) for each argument. -// stackArgSize is the size in bytes for how much data to put on the stack frame -extern "C" asQWORD ppcFunc(const asDWORD* argsPtr, int StackArgSize, asDWORD func); - -asm(" .text\n" - " .align 2\n" // align the code to 1 << 2 = 4 bytes - " .globl _ppcFunc\n" - "_ppcFunc:\n" - - // We're receiving the following parameters - - // r3 : argsPtr - // r4 : StackArgSize - // r5 : func - - // The following registers are used through out the function - - // r31 : the address of the label address, as reference for all other labels - // r30 : temporary variable - // r29 : arg list pointer - // r28 : number of FPR registers used by the parameters - // r27 : the function pointer that will be called - // r26 : the location of the parameters for the call - // r25 : arg type list pointer - // r24 : temporary variable - // r23 : number of GPR registers used by the parameters - // r1 : this is stack pointer - // r0 : temporary variable - // f0 : temporary variable - - // We need to store some of the registers for restoral before returning to caller - - // lr - always stored in 8(r1) - this is the return address - // cr - not required to be stored, but if it is, its place is in 4(r1) - this is the condition register - // r1 - always stored in 0(r1) - this is the stack pointer - // r11 - // r13 to r31 - // f14 to f31 - - // Store register values and setup our stack frame - " mflr r0 \n" // move the return address into r0 - " stw r0, 8(r1) \n" // Store the return address on the stack - " stmw r23, -36(r1) \n" // Store registers r23 to r31 on the stack - " stwux r1, r1, r4 \n" // Increase the stack with the needed space and store the original value in the destination - - // Obtain an address that we'll use as our position of reference when obtaining addresses of other labels - " bl address \n" - "address: \n" - " mflr r31 \n" - - // initial registers for the function - " mr r29, r3 \n" // (r29) args list - " mr r27, r5 \n" // load the function pointer to call. func actually holds the pointer to our function - " addi r26, r1, 24 \n" // setup the pointer to the parameter area to the function we're going to call - " sub r0, r0, r0 \n" // zero out r0 - " mr r23, r0 \n" // zero out r23, which holds the number of used GPR registers - " mr r28, r0 \n" // zero our r22, which holds the number of used float registers - - // load the global ppcArgsType which holds the types of arguments for each argument - " addis r25, r31, ha16(_ppcArgsType - address) \n" // load the upper 16 bits of the address to r25 - " la r25, lo16(_ppcArgsType - address)(r25) \n" // load the lower 16 bits of the address to r25 - " subi r25, r25, 1 \n" // since we increment r25 on its use, we'll pre-decrement it - - // loop through the arguments - "ppcNextArg: \n" - " addi r25, r25, 1 \n" // increment r25, our arg type pointer - // switch based on the current argument type (0:end, 1:int, 2:float 3:double) - " lbz r24, 0(r25) \n" // load the current argument type (it's a byte) - " mulli r24, r24, 4 \n" // our jump table has 4 bytes per case (1 instruction) - " addis r30, r31, ha16(ppcTypeSwitch - address) \n" // load the address of the jump table for the switch - " la r30, lo16(ppcTypeSwitch - address)(r30) \n" - - " add r0, r30, r24 \n" // offset by our argument type - " mtctr r0 \n" // load the jump address into CTR - " bctr \n" // jump into the jump table/switch - " nop \n" - - // the jump table/switch based on the current argument type - "ppcTypeSwitch: \n" - " b ppcArgsEnd \n" - " b ppcArgIsInteger \n" - " b ppcArgIsFloat \n" - " b ppcArgIsDouble \n" - - // when we get here we have finished processing all the arguments - // everything is ready to go to call the function - "ppcArgsEnd: \n" - " mtctr r27 \n" // the function pointer is stored in r27, load that into CTR - " bctrl \n" // call the function. We have to do it this way so that the LR gets the proper - " nop \n" // return value (the next instruction below). So we have to branch from CTR instead of LR. - - // Restore registers and caller's stack frame, then return to caller - " lwz r1, 0(r1) \n" // restore the caller's stack pointer - " lwz r0, 8(r1) \n" // load in the caller's LR - " mtlr r0 \n" // restore the caller's LR - " lmw r23, -36(r1) \n" // restore registers r23 to r31 from the stack - " blr \n" // return back to the caller - " nop \n" - - // Integer argument (GPR register) - "ppcArgIsInteger: \n" - " addis r30, r31, ha16(ppcLoadIntReg - address) \n" // load the address to the jump table for integer registers - " la r30, lo16(ppcLoadIntReg - address)(r30) \n" - " mulli r0, r23, 8 \n" // each item in the jump table is 2 instructions (8 bytes) - " add r0, r0, r30 \n" // calculate ppcLoadIntReg[numUsedGPRRegs] - " lwz r30, 0(r29) \n" // load the next argument from the argument list into r30 - " cmpwi r23, 8 \n" // we can only load GPR3 through GPR10 (8 registers) - " bgt ppcLoadIntRegUpd \n" // if we're beyond 8 GPR registers, we're in the stack, go there - " mtctr r0 \n" // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers) - " bctr \n" // load the argument into a GPR register - " nop \n" - // jump table for GPR registers, for the first 8 GPR arguments - "ppcLoadIntReg: \n" - " mr r3, r30 \n" // arg0 (to r3) - " b ppcLoadIntRegUpd \n" - " mr r4, r30 \n" // arg1 (to r4) - " b ppcLoadIntRegUpd \n" - " mr r5, r30 \n" // arg2 (to r5) - " b ppcLoadIntRegUpd \n" - " mr r6, r30 \n" // arg3 (to r6) - " b ppcLoadIntRegUpd \n" - " mr r7, r30 \n" // arg4 (to r7) - " b ppcLoadIntRegUpd \n" - " mr r8, r30 \n" // arg5 (to r8) - " b ppcLoadIntRegUpd \n" - " mr r9, r30 \n" // arg6 (to r9) - " b ppcLoadIntRegUpd \n" - " mr r10, r30 \n" // arg7 (to r10) - " b ppcLoadIntRegUpd \n" - // all GPR arguments still go on the stack - "ppcLoadIntRegUpd: \n" - " stw r30, 0(r26) \n" // store the argument into the next slot on the stack's argument list - " addi r23, r23, 1 \n" // count a used GPR register - " addi r29, r29, 4 \n" // move to the next argument on the list - " addi r26, r26, 4 \n" // adjust our argument stack pointer for the next - " b ppcNextArg \n" // next argument - - // single Float argument - "ppcArgIsFloat:\n" - " addis r30, r31, ha16(ppcLoadFloatReg - address) \n" // get the base address of the float register jump table - " la r30, lo16(ppcLoadFloatReg - address)(r30) \n" - " mulli r0, r28, 8 \n" // each jump table entry is 8 bytes - " add r0, r0, r30 \n" // calculate the offset to ppcLoadFloatReg[numUsedFloatReg] - " lfs f0, 0(r29) \n" // load the next argument as a float into f0 - " cmpwi r28, 13 \n" // can't load more than 13 float/double registers - " bgt ppcLoadFloatRegUpd \n" // if we're beyond 13 registers, just fall to inserting into the stack - " mtctr r0 \n" // jump into the float jump table - " bctr \n" - " nop \n" - // jump table for float registers, for the first 13 float arguments - "ppcLoadFloatReg: \n" - " fmr f1, f0 \n" // arg0 (f1) - " b ppcLoadFloatRegUpd \n" - " fmr f2, f0 \n" // arg1 (f2) - " b ppcLoadFloatRegUpd \n" - " fmr f3, f0 \n" // arg2 (f3) - " b ppcLoadFloatRegUpd \n" - " fmr f4, f0 \n" // arg3 (f4) - " b ppcLoadFloatRegUpd \n" - " fmr f5, f0 \n" // arg4 (f5) - " b ppcLoadFloatRegUpd \n" - " fmr f6, f0 \n" // arg5 (f6) - " b ppcLoadFloatRegUpd \n" - " fmr f7, f0 \n" // arg6 (f7) - " b ppcLoadFloatRegUpd \n" - " fmr f8, f0 \n" // arg7 (f8) - " b ppcLoadFloatRegUpd \n" - " fmr f9, f0 \n" // arg8 (f9) - " b ppcLoadFloatRegUpd \n" - " fmr f10, f0 \n" // arg9 (f10) - " b ppcLoadFloatRegUpd \n" - " fmr f11, f0 \n" // arg10 (f11) - " b ppcLoadFloatRegUpd \n" - " fmr f12, f0 \n" // arg11 (f12) - " b ppcLoadFloatRegUpd \n" - " fmr f13, f0 \n" // arg12 (f13) - " b ppcLoadFloatRegUpd \n" - " nop \n" - // all float arguments still go on the stack - "ppcLoadFloatRegUpd: \n" - " stfs f0, 0(r26) \n" // store, as a single float, f0 (current argument) on to the stack argument list - " addi r23, r23, 1 \n" // a float register eats up a GPR register - " addi r28, r28, 1 \n" // ...and, of course, a float register - " addi r29, r29, 4 \n" // move to the next argument in the list - " addi r26, r26, 4 \n" // move to the next stack slot - " b ppcNextArg \n" // on to the next argument - " nop \n" - - // double Float argument - "ppcArgIsDouble: \n" - " addis r30, r31, ha16(ppcLoadDoubleReg - address) \n" // load the base address of the jump table for double registers - " la r30, lo16(ppcLoadDoubleReg - address)(r30) \n" - " mulli r0, r28, 8 \n" // each slot of the jump table is 8 bytes - " add r0, r0, r30 \n" // calculate ppcLoadDoubleReg[numUsedFloatReg] - " lfd f0, 0(r29) \n" // load the next argument, as a double float, into f0 - " cmpwi r28, 13 \n" // the first 13 floats must go into float registers also - " bgt ppcLoadDoubleRegUpd \n" // if we're beyond 13, then just put on to the stack - " mtctr r0 \n" // we're under 13, first load our register - " bctr \n" // jump into the jump table - " nop \n" - // jump table for float registers, for the first 13 float arguments - "ppcLoadDoubleReg: \n" - " fmr f1, f0 \n" // arg0 (f1) - " b ppcLoadDoubleRegUpd \n" - " fmr f2, f0 \n" // arg1 (f2) - " b ppcLoadDoubleRegUpd \n" - " fmr f3, f0 \n" // arg2 (f3) - " b ppcLoadDoubleRegUpd \n" - " fmr f4, f0 \n" // arg3 (f4) - " b ppcLoadDoubleRegUpd \n" - " fmr f5, f0 \n" // arg4 (f5) - " b ppcLoadDoubleRegUpd \n" - " fmr f6, f0 \n" // arg5 (f6) - " b ppcLoadDoubleRegUpd \n" - " fmr f7, f0 \n" // arg6 (f7) - " b ppcLoadDoubleRegUpd \n" - " fmr f8, f0 \n" // arg7 (f8) - " b ppcLoadDoubleRegUpd \n" - " fmr f9, f0 \n" // arg8 (f9) - " b ppcLoadDoubleRegUpd \n" - " fmr f10, f0 \n" // arg9 (f10) - " b ppcLoadDoubleRegUpd \n" - " fmr f11, f0 \n" // arg10 (f11) - " b ppcLoadDoubleRegUpd \n" - " fmr f12, f0 \n" // arg11 (f12) - " b ppcLoadDoubleRegUpd \n" - " fmr f13, f0 \n" // arg12 (f13) - " b ppcLoadDoubleRegUpd \n" - " nop \n" - // all float arguments still go on the stack - "ppcLoadDoubleRegUpd: \n" - " stfd f0, 0(r26) \n" // store f0, as a double, into the argument list on the stack - " addi r23, r23, 2 \n" // a double float eats up two GPRs - " addi r28, r28, 1 \n" // ...and, of course, a float - " addi r29, r29, 8 \n" // increment to our next argument we need to process (8 bytes for the 64bit float) - " addi r26, r26, 8 \n" // increment to the next slot on the argument list on the stack (8 bytes) - " b ppcNextArg \n" // on to the next argument - " nop \n" -); - -asDWORD GetReturnedFloat() -{ - asDWORD f; - asm(" stfs f1, %0\n" : "=m"(f)); - return f; -} - -asQWORD GetReturnedDouble() -{ - asQWORD f; - asm(" stfd f1, %0\n" : "=m"(f)); - return f; -} - -// puts the arguments in the correct place in the stack array. See comments above. -void stackArgs(const asDWORD *args, const asBYTE *argsType, int& numIntArgs, int& numFloatArgs, int& numDoubleArgs) -{ - int i; - int argWordPos = numIntArgs + numFloatArgs + (numDoubleArgs*2); - int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs; - - int typeIndex; - for( i = 0, typeIndex = 0; ; i++, typeIndex++ ) - { - // store the type - ppcArgsType[typeOffset++] = argsType[typeIndex]; - if( argsType[typeIndex] == ppcENDARG ) - break; - - switch( argsType[typeIndex] ) - { - case ppcFLOATARG: - // stow float - ppcArgs[argWordPos] = args[i]; // it's just a bit copy - numFloatArgs++; - argWordPos++; //add one word - break; - - case ppcDOUBLEARG: - // stow double - memcpy( &ppcArgs[argWordPos], &args[i], sizeof(double) ); // we have to do this because of alignment - numDoubleArgs++; - argWordPos+=2; //add two words - i++;//doubles take up 2 argument slots - break; - - case ppcINTARG: - // stow register - ppcArgs[argWordPos] = args[i]; - numIntArgs++; - argWordPos++; - break; - } - } - - // close off the argument list (if we have max args we won't close it off until here) - ppcArgsType[typeOffset] = ppcENDARG; -} - -static asQWORD CallCDeclFunction(const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory) -{ - int baseArgCount = 0; - if( retInMemory ) - { - // the first argument is the 'return in memory' pointer - ppcArgs[0] = (asDWORD)retInMemory; - ppcArgsType[0] = ppcINTARG; - ppcArgsType[1] = ppcENDARG; - baseArgCount = 1; - } - - // put the arguments in the correct places in the ppcArgs array - int numTotalArgs = baseArgCount; - if( argSize > 0 ) - { - int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0; - stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs ); - numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots - } - else - { - // no arguments, cap the type list - ppcArgsType[baseArgCount] = ppcENDARG; - } - - // call the function with the arguments - return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func ); -} - -// This function is identical to CallCDeclFunction, with the only difference that -// the value in the first parameter is the object (unless we are returning in memory) -static asQWORD CallThisCallFunction(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory ) -{ - int baseArgCount = 0; - if( retInMemory ) - { - // the first argument is the 'return in memory' pointer - ppcArgs[0] = (asDWORD)retInMemory; - ppcArgsType[0] = ppcINTARG; - ppcArgsType[1] = ppcENDARG; - baseArgCount = 1; - } - - // the first argument is the 'this' of the object - ppcArgs[baseArgCount] = (asDWORD)obj; - ppcArgsType[baseArgCount++] = ppcINTARG; - ppcArgsType[baseArgCount] = ppcENDARG; - - // put the arguments in the correct places in the ppcArgs array - int numTotalArgs = baseArgCount; - if( argSize > 0 ) - { - int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0; - stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs ); - numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots - } - - // call the function with the arguments - return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func); -} - -// This function is identical to CallCDeclFunction, with the only difference that -// the value in the last parameter is the object -// NOTE: on PPC the order for the args is reversed -static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory) -{ - UNUSED_VAR(argSize); - int baseArgCount = 0; - if( retInMemory ) - { - // the first argument is the 'return in memory' pointer - ppcArgs[0] = (asDWORD)retInMemory; - ppcArgsType[0] = ppcINTARG; - ppcArgsType[1] = ppcENDARG; - baseArgCount = 1; - } - - // stack any of the arguments - int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0; - stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs ); - int numTotalArgs = intArgs + floatArgs + doubleArgs; - - // can we fit the object in at the end? - if( numTotalArgs < AS_PPC_MAX_ARGS ) - { - // put the object pointer at the end - int argPos = intArgs + floatArgs + (doubleArgs * 2); - ppcArgs[argPos] = (asDWORD)obj; - ppcArgsType[numTotalArgs++] = ppcINTARG; - ppcArgsType[numTotalArgs] = ppcENDARG; - } - - // call the function with the arguments - return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func ); -} - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - // use a working array of types, we'll configure the final one in stackArgs - asBYTE argsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1]; - memset( argsType, 0, sizeof(argsType)); - - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - - asQWORD retQW = 0; - void *func = (void*)sysFunc->func; - int paramSize = sysFunc->paramSize; - asDWORD *vftable = NULL; - int a, s; - - // convert the parameters that are < 4 bytes from little endian to big endian - int argDwordOffset = 0; - for( a = 0; a < (int)descr->parameterTypes.GetLength(); a++ ) - { - int numBytes = descr->parameterTypes[a].GetSizeInMemoryBytes(); - if( numBytes >= 4 || descr->parameterTypes[a].IsReference() || descr->parameterTypes[a].IsObjectHandle() ) - { - argDwordOffset += descr->parameterTypes[a].GetSizeOnStackDWords(); - continue; - } - - // flip - asASSERT( numBytes == 1 || numBytes == 2 ); - switch( numBytes ) - { - case 1: - { - volatile asBYTE *bPtr = (asBYTE*)ARG_DW(args[argDwordOffset]); - asBYTE t = bPtr[0]; - bPtr[0] = bPtr[3]; - bPtr[3] = t; - t = bPtr[1]; - bPtr[1] = bPtr[2]; - bPtr[2] = t; - } - break; - case 2: - { - volatile asWORD *wPtr = (asWORD*)ARG_DW(args[argDwordOffset]); - asWORD t = wPtr[0]; - wPtr[0] = wPtr[1]; - wPtr[1] = t; - } - break; - } - argDwordOffset++; - } - - // mark all float/double/int arguments - if( !sysFunc->takesObjByVal ) - { - for( s = 0, a = 0; s < (int)descr->parameterTypes.GetLength(); s++, a++ ) - { - if( descr->parameterTypes[s].IsFloatType() && !descr->parameterTypes[s].IsReference() ) - { - argsType[a] = ppcFLOATARG; - } - else if( descr->parameterTypes[s].IsDoubleType() && !descr->parameterTypes[s].IsReference() ) - { - argsType[a] = ppcDOUBLEARG; - } - else - { - argsType[a] = ppcINTARG; - if( descr->parameterTypes[s].GetSizeOnStackDWords() == 2 ) - { - // Add an extra integer argument for the extra size - a++; - argsType[a] = ppcINTARG; - } - } - } - } - - asDWORD paramBuffer[64]; - if( sysFunc->takesObjByVal ) - { - paramSize = 0; - int spos = 0; - int dpos = 1; - - int a = 0; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - 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 ) - { - argsType[a++] = ppcINTARG; - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else -#endif - { - // TODO: Probably have to handle asOBJ_APP_FLOAT as a primitive - - // Copy the object's memory to the buffer - memcpy( ¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes() ); - - // Delete the original memory - engine->CallFree(*(char**)(args+spos) ); - spos++; - asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords(); - dpos += dwords; - paramSize += dwords; - for( asUINT i = 0; i < dwords; i++ ) - argsType[a++] = ppcINTARG; - } - } - else - { - // Copy the value directly - paramBuffer[dpos++] = args[spos++]; - if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() ) - argsType[a++] = ppcFLOATARG; - else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() ) - argsType[a++] = ppcDOUBLEARG; - else - argsType[a++] = ppcINTARG; - if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) - { - paramBuffer[dpos++] = args[spos++]; - if( !descr->parameterTypes[n].IsDoubleType() ) // Double already knows it is 2 dwords - argsType[a++] = ppcINTARG; - } - paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - } - - // Keep a free location at the beginning - args = ¶mBuffer[1]; - } - - int callConv = sysFunc->callConv; - switch( callConv ) - { - case ICC_CDECL: - case ICC_CDECL_RETURNINMEM: - case ICC_STDCALL: - case ICC_STDCALL_RETURNINMEM: - retQW = CallCDeclFunction( args, argsType, paramSize, (asDWORD)func, retPointer ); - break; - case ICC_THISCALL: - case ICC_THISCALL_RETURNINMEM: - retQW = CallThisCallFunction(obj, args, argsType, paramSize, (asDWORD)func, retPointer ); - break; - case ICC_VIRTUAL_THISCALL: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - // Get virtual function table from the object pointer - vftable = *(asDWORD**)obj; - retQW = CallThisCallFunction( obj, args, argsType, paramSize, vftable[asDWORD(func)>>2], retPointer ); - break; - case ICC_CDECL_OBJLAST: - case ICC_CDECL_OBJLAST_RETURNINMEM: - retQW = CallThisCallFunction_objLast( obj, args, argsType, paramSize, (asDWORD)func, retPointer ); - break; - case ICC_CDECL_OBJFIRST: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - retQW = CallThisCallFunction( obj, args, argsType, paramSize, (asDWORD)func, retPointer ); - break; - default: - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - } - - // If the return is a float value we need to get the value from the FP register - if( sysFunc->hostReturnFloat ) - { - if( sysFunc->hostReturnSize == 1 ) - *(asDWORD*)&retQW = GetReturnedFloat(); - else - retQW = GetReturnedDouble(); - } - - return retQW; -} - -END_AS_NAMESPACE - -#endif // AS_PPC -#endif // AS_MAX_PORTABILITY - diff --git a/dependencies/angelscript/source/as_callfunc_ppc_64.cpp b/dependencies/angelscript/source/as_callfunc_ppc_64.cpp deleted file mode 100644 index ffd5f02e..00000000 --- a/dependencies/angelscript/source/as_callfunc_ppc_64.cpp +++ /dev/null @@ -1,765 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc_ppc_64.cpp -// -// These functions handle the actual calling of system functions -// -// This version is 64 bit PPC specific -// - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_PPC_64 - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_tokendef.h" -#include "as_context.h" - -#include -#include - -#ifdef __SNC__ -#include "ppu_asm_intrinsics.h" -#endif - - -BEGIN_AS_NAMESPACE - -// This part was written and tested by Jeff Slutter -// from Reactor Zero, Abril, 2007, for PlayStation 3, which -// is a PowerPC 64bit based architecture. Even though it is -// 64bit it seems the pointer size is still 32bit. - -// It still remains to be seen how well this code works -// on other PPC platforms, such as XBox 360, GameCube. - -#define AS_PPC_MAX_ARGS 32 - -// The array used to send values to the correct places. -// Contains a byte of argTypes to indicate the register type to load -// or zero if end of arguments -// The +1 is for when CallThis (object methods) is used -// Extra +1 when returning in memory -// Extra +1 in ppcArgsType to ensure zero end-of-args marker - -// TODO: multithread: The global variables must be removed to make the code thread safe - -extern "C" -{ - enum argTypes { ppcENDARG = 0, ppcINTARG = 1, ppcFLOATARG = 2, ppcDOUBLEARG = 3, ppcLONGARG = 4 }; - static asBYTE ppcArgsType[AS_PPC_MAX_ARGS + 1 + 1 + 1]; - static asDWORD ppcArgs[2*AS_PPC_MAX_ARGS + 1 + 1]; -} - -// NOTE: these values are for PowerPC 64 bit. I'm sure things are different for PowerPC 32bit, but I don't have one. -// I'm pretty sure that PPC 32bit sets up a stack frame slightly different (only 24 bytes for linkage area for instance) -#define PPC_LINKAGE_SIZE (0x30) // how big the PPC linkage area is in a stack frame -#define PPC_NUM_REGSTORE (10) // how many registers of the PPC we need to store/restore for ppcFunc64() -#define PPC_REGSTORE_SIZE (8*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore -#define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame -#define PPC_STACK_SIZE(numParams) ( -(( ( (((numParams)<8)?8:(numParams))<<3) + EXTRA_STACK_SIZE + 15 ) & ~15) ) // calculates the total stack size needed for ppcFunc64, must pad to 16bytes - -// This is PowerPC 64 bit specific -// Loads all data into the correct places and calls the function. -// ppcArgsType is an array containing a byte type (enum argTypes) for each argument. -// StackArgSizeInBytes is the size in bytes of the stack frame (takes into account linkage area, etc. must be multiple of 16) -extern "C" asQWORD ppcFunc64(const asDWORD* argsPtr, int StackArgSizeInBytes, asDWORD func); -asm("" - ".text\n" - ".align 4\n" - ".p2align 4,,15\n" - ".globl .ppcFunc64\n" - ".ppcFunc64:\n" - - // function prolog - "std %r22, -0x08(%r1)\n" // we need a register other than r0, to store the old stack pointer - "mr %r22, %r1\n" // store the old stack pointer, for now (to make storing registers easier) - "stdux %r1, %r1, %r4\n" // atomically store and update the stack pointer for the new stack frame (in case of a signal/interrupt) - "mflr %r0\n" // get the caller's LR register - "std %r0, 0x10(%r22)\n" // store the caller's LR register - "std %r23, -0x10(%r22)\n" // - "std %r24, -0x18(%r22)\n" // - "std %r25, -0x20(%r22)\n" // - "std %r26, -0x28(%r22)\n" // - "std %r27, -0x30(%r22)\n" // - "std %r28, -0x38(%r22)\n" // - "std %r29, -0x40(%r22)\n" // - "std %r30, -0x48(%r22)\n" // - "std %r31, -0x50(%r22)\n" // - "std %r3, 0x30(%r22)\n" // save our parameters - "std %r4, 0x38(%r22)\n" // - "std %r5, 0x40(%r22)\n" // - "mr %r31, %r1\n" // functions tend to store the stack pointer here too - - // initial registers for the function - "mr %r29, %r3\n" // (r29) args list - "lwz %r27, 0(%r5)\n" // load the function pointer to call. func actually holds the pointer to our function - "addi %r26, %r1, 0x30\n" // setup the pointer to the parameter area to the function we're going to call - "sub %r0,%r0,%r0\n" // zero out r0 - "mr %r23,%r0\n" // zero out r23, which holds the number of used GPR registers - "mr %r22,%r0\n" // zero our r22, which holds the number of used float registers - - // load the global ppcArgsType which holds the types of arguments for each argument - "lis %r25, ppcArgsType@ha\n" // load the upper 16 bits of the address to r25 - "addi %r25, %r25, ppcArgsType@l\n" // load the lower 16 bits of the address to r25 - "subi %r25, %r25, 1\n" // since we increment r25 on its use, we'll pre-decrement it - - // loop through the arguments - "ppcNextArg:\n" - "addi %r25, %r25, 1\n" // increment r25, our arg type pointer - // switch based on the current argument type (0:end, 1:int, 2:float 3:double) - "lbz %r24, 0(%r25)\n" // load the current argument type (it's a byte) - "mulli %r24, %r24, 4\n" // our jump table has 4 bytes per case (1 instruction) - "lis %r30, ppcTypeSwitch@ha\n" // load the address of the jump table for the switch - "addi %r30, %r30, ppcTypeSwitch@l\n" - "add %r0, %r30, %r24\n" // offset by our argument type - "mtctr %r0\n" // load the jump address into CTR - "bctr\n" // jump into the jump table/switch - "nop\n" - // the jump table/switch based on the current argument type - "ppcTypeSwitch:\n" - "b ppcArgsEnd\n" - "b ppcArgIsInteger\n" - "b ppcArgIsFloat\n" - "b ppcArgIsDouble\n" - "b ppcArgIsLong\n" - - // when we get here we have finished processing all the arguments - // everything is ready to go to call the function - "ppcArgsEnd:\n" - "mtctr %r27\n" // the function pointer is stored in r27, load that into CTR - "bctrl\n" // call the function. We have to do it this way so that the LR gets the proper - "nop\n" // return value (the next instruction below). So we have to branch from CTR instead of LR. - // when we get here, the function has returned, this is the function epilog - "ld %r11,0x00(%r1)\n" // load in the caller's stack pointer - "ld %r0,0x10(%r11)\n" // load in the caller's LR - "mtlr %r0\n" // restore the caller's LR - "ld %r22, -0x08(%r11)\n" // load registers - "ld %r23, -0x10(%r11)\n" // - "ld %r24, -0x18(%r11)\n" // - "ld %r25, -0x20(%r11)\n" // - "ld %r26, -0x28(%r11)\n" // - "ld %r27, -0x30(%r11)\n" // - "ld %r28, -0x38(%r11)\n" // - "ld %r29, -0x40(%r11)\n" // - "ld %r30, -0x48(%r11)\n" // - "ld %r31, -0x50(%r11)\n" // - "mr %r1, %r11\n" // restore the caller's SP - "blr\n" // return back to the caller - "nop\n" - // Integer argument (GPR register) - "ppcArgIsInteger:\n" - "lis %r30,ppcLoadIntReg@ha\n" // load the address to the jump table for integer registers - "addi %r30, %r30, ppcLoadIntReg@l\n" - "mulli %r0, %r23, 8\n" // each item in the jump table is 2 instructions (8 bytes) - "add %r0, %r0, %r30\n" // calculate ppcLoadIntReg[numUsedGPRRegs] - "lwz %r30,0(%r29)\n" // load the next argument from the argument list into r30 - "cmpwi %r23, 8\n" // we can only load GPR3 through GPR10 (8 registers) - "bgt ppcLoadIntRegUpd\n" // if we're beyond 8 GPR registers, we're in the stack, go there - "mtctr %r0\n" // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers) - "bctr\n" // load the argument into a GPR register - "nop\n" - // jump table for GPR registers, for the first 8 GPR arguments - "ppcLoadIntReg:\n" - "mr %r3,%r30\n" // arg0 (to r3) - "b ppcLoadIntRegUpd\n" - "mr %r4,%r30\n" // arg1 (to r4) - "b ppcLoadIntRegUpd\n" - "mr %r5,%r30\n" // arg2 (to r5) - "b ppcLoadIntRegUpd\n" - "mr %r6,%r30\n" // arg3 (to r6) - "b ppcLoadIntRegUpd\n" - "mr %r7,%r30\n" // arg4 (to r7) - "b ppcLoadIntRegUpd\n" - "mr %r8,%r30\n" // arg5 (to r8) - "b ppcLoadIntRegUpd\n" - "mr %r9,%r30\n" // arg6 (to r9) - "b ppcLoadIntRegUpd\n" - "mr %r10,%r30\n" // arg7 (to r10) - "b ppcLoadIntRegUpd\n" - - // all GPR arguments still go on the stack - "ppcLoadIntRegUpd:\n" - "std %r30,0(%r26)\n" // store the argument into the next slot on the stack's argument list - "addi %r23, %r23, 1\n" // count a used GPR register - "addi %r29, %r29, 4\n" // move to the next argument on the list - "addi %r26, %r26, 8\n" // adjust our argument stack pointer for the next - "b ppcNextArg\n" // next argument - - // single Float argument - "ppcArgIsFloat:\n" - "lis %r30,ppcLoadFloatReg@ha\n" // get the base address of the float register jump table - "addi %r30, %r30, ppcLoadFloatReg@l\n" - "mulli %r0, %r22 ,8\n" // each jump table entry is 8 bytes - "add %r0, %r0, %r30\n" // calculate the offset to ppcLoadFloatReg[numUsedFloatReg] - "lfs 0, 0(%r29)\n" // load the next argument as a float into f0 - "cmpwi %r22, 13\n" // can't load more than 13 float/double registers - "bgt ppcLoadFloatRegUpd\n" // if we're beyond 13 registers, just fall to inserting into the stack - "mtctr %r0\n" // jump into the float jump table - "bctr\n" - "nop\n" - // jump table for float registers, for the first 13 float arguments - "ppcLoadFloatReg:\n" - "fmr 1,0\n" // arg0 (f1) - "b ppcLoadFloatRegUpd\n" - "fmr 2,0\n" // arg1 (f2) - "b ppcLoadFloatRegUpd\n" - "fmr 3,0\n" // arg2 (f3) - "b ppcLoadFloatRegUpd\n" - "fmr 4,0\n" // arg3 (f4) - "b ppcLoadFloatRegUpd\n" - "fmr 5,0\n" // arg4 (f5) - "b ppcLoadFloatRegUpd\n" - "fmr 6,0\n" // arg5 (f6) - "b ppcLoadFloatRegUpd\n" - "fmr 7,0\n" // arg6 (f7) - "b ppcLoadFloatRegUpd\n" - "fmr 8,0\n" // arg7 (f8) - "b ppcLoadFloatRegUpd\n" - "fmr 9,0\n" // arg8 (f9) - "b ppcLoadFloatRegUpd\n" - "fmr 10,0\n" // arg9 (f10) - "b ppcLoadFloatRegUpd\n" - "fmr 11,0\n" // arg10 (f11) - "b ppcLoadFloatRegUpd\n" - "fmr 12,0\n" // arg11 (f12) - "b ppcLoadFloatRegUpd\n" - "fmr 13,0\n" // arg12 (f13) - "b ppcLoadFloatRegUpd\n" - "nop\n" - // all float arguments still go on the stack - "ppcLoadFloatRegUpd:\n" - "stfs 0, 0x04(%r26)\n" // store, as a single float, f0 (current argument) on to the stack argument list - "addi %r23, %r23, 1\n" // a float register eats up a GPR register - "addi %r22, %r22, 1\n" // ...and, of course, a float register - "addi %r29, %r29, 4\n" // move to the next argument in the list - "addi %r26, %r26, 8\n" // move to the next stack slot - "b ppcNextArg\n" // on to the next argument - "nop\n" - // double Float argument - "ppcArgIsDouble:\n" - "lis %r30, ppcLoadDoubleReg@ha\n" // load the base address of the jump table for double registers - "addi %r30, %r30, ppcLoadDoubleReg@l\n" - "mulli %r0, %r22, 8\n" // each slot of the jump table is 8 bytes - "add %r0, %r0, %r30\n" // calculate ppcLoadDoubleReg[numUsedFloatReg] - "lfd 0, 0(%r29)\n" // load the next argument, as a double float, into f0 - "cmpwi %r22,13\n" // the first 13 floats must go into float registers also - "bgt ppcLoadDoubleRegUpd\n" // if we're beyond 13, then just put on to the stack - "mtctr %r0\n" // we're under 13, first load our register - "bctr\n" // jump into the jump table - "nop\n" - // jump table for float registers, for the first 13 float arguments - "ppcLoadDoubleReg:\n" - "fmr 1,0\n" // arg0 (f1) - "b ppcLoadDoubleRegUpd\n" - "fmr 2,0\n" // arg1 (f2) - "b ppcLoadDoubleRegUpd\n" - "fmr 3,0\n" // arg2 (f3) - "b ppcLoadDoubleRegUpd\n" - "fmr 4,0\n" // arg3 (f4) - "b ppcLoadDoubleRegUpd\n" - "fmr 5,0\n" // arg4 (f5) - "b ppcLoadDoubleRegUpd\n" - "fmr 6,0\n" // arg5 (f6) - "b ppcLoadDoubleRegUpd\n" - "fmr 7,0\n" // arg6 (f7) - "b ppcLoadDoubleRegUpd\n" - "fmr 8,0\n" // arg7 (f8) - "b ppcLoadDoubleRegUpd\n" - "fmr 9,0\n" // arg8 (f9) - "b ppcLoadDoubleRegUpd\n" - "fmr 10,0\n" // arg9 (f10) - "b ppcLoadDoubleRegUpd\n" - "fmr 11,0\n" // arg10 (f11) - "b ppcLoadDoubleRegUpd\n" - "fmr 12,0\n" // arg11 (f12) - "b ppcLoadDoubleRegUpd\n" - "fmr 13,0\n" // arg12 (f13) - "b ppcLoadDoubleRegUpd\n" - "nop\n" - // all float arguments still go on the stack - "ppcLoadDoubleRegUpd:\n" - "stfd 0,0(%r26)\n" // store f0, as a double, into the argument list on the stack - "addi %r23, %r23, 1\n" // a double float eats up one GPR - "addi %r22, %r22, 1\n" // ...and, of course, a float - "addi %r29, %r29, 8\n" // increment to our next argument we need to process (8 bytes for the 64bit float) - "addi %r26, %r26, 8\n" // increment to the next slot on the argument list on the stack (8 bytes) - "b ppcNextArg\n" // on to the next argument - "nop\n" - - // Long (64 bit int) argument - "ppcArgIsLong:\n" - "lis %r30,ppcLoadLongReg@ha\n" // load the address to the jump table for integer64 - "addi %r30, %r30, ppcLoadLongReg@l\n" - "mulli %r0, %r23, 8\n" // each item in the jump table is 2 instructions (8 bytes) - "add %r0, %r0, %r30\n" // calculate ppcLoadLongReg[numUsedGPRRegs] - "ld %r30,0(%r29)\n" // load the next argument from the argument list into r30 - "cmpwi %r23, 8\n" // we can only load GPR3 through GPR10 (8 registers) - "bgt ppcLoadLongRegUpd\n" // if we're beyond 8 GPR registers, we're in the stack, go there - "mtctr %r0\n" // load the address of our ppcLoadLongReg jump table (we're below 8 GPR registers) - "bctr\n" // load the argument into a GPR register - "nop\n" - // jump table for GPR registers, for the first 8 GPR arguments - "ppcLoadLongReg:\n" - "mr %r3,%r30\n" // arg0 (to r3) - "b ppcLoadLongRegUpd\n" - "mr %r4,%r30\n" // arg1 (to r4) - "b ppcLoadLongRegUpd\n" - "mr %r5,%r30\n" // arg2 (to r5) - "b ppcLoadLongRegUpd\n" - "mr %r6,%r30\n" // arg3 (to r6) - "b ppcLoadLongRegUpd\n" - "mr %r7,%r30\n" // arg4 (to r7) - "b ppcLoadLongRegUpd\n" - "mr %r8,%r30\n" // arg5 (to r8) - "b ppcLoadLongRegUpd\n" - "mr %r9,%r30\n" // arg6 (to r9) - "b ppcLoadLongRegUpd\n" - "mr %r10,%r30\n" // arg7 (to r10) - "b ppcLoadLongRegUpd\n" - - // all GPR arguments still go on the stack - "ppcLoadLongRegUpd:\n" - "std %r30,0(%r26)\n" // store the argument into the next slot on the stack's argument list - "addi %r23, %r23, 1\n" // count a used GPR register - "addi %r29, %r29, 8\n" // move to the next argument on the list - "addi %r26, %r26, 8\n" // adjust our argument stack pointer for the next - "b ppcNextArg\n" // next argument -); - -static asDWORD GetReturnedFloat(void) -{ - asDWORD f; -#ifdef __SNC__ - __stfs( __freg(1), 0, (void*)&f); -#else - asm(" stfs 1, %0\n" : "=m"(f)); -#endif - return f; -} - -static asQWORD GetReturnedDouble(void) -{ - asQWORD f; -#ifdef __SNC__ - __stfd( __freg(1), 0, (void*)&f); -#else - asm(" stfd 1, %0\n" : "=m"(f)); -#endif - return f; -} - -// puts the arguments in the correct place in the stack array. See comments above. -static void stackArgs( const asDWORD *args, const asBYTE *argsType, int &numIntArgs, int &numFloatArgs, int &numDoubleArgs, int &numLongArgs ) -{ - // initialize our offset based on any already placed arguments - int i; - int argWordPos = numIntArgs + numFloatArgs + (numDoubleArgs*2) + (numLongArgs*2); - int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs + numLongArgs; - - int typeIndex; - for( i = 0, typeIndex = 0; ; i++, typeIndex++ ) - { - // store the type - ppcArgsType[typeOffset++] = argsType[typeIndex]; - if( argsType[typeIndex] == ppcENDARG ) - break; - - switch( argsType[typeIndex] ) - { - case ppcFLOATARG: - { - // stow float - ppcArgs[argWordPos] = args[i]; // it's just a bit copy - numFloatArgs++; - argWordPos++; //add one word - } - break; - - case ppcDOUBLEARG: - { - // stow double - memcpy( &ppcArgs[argWordPos], &args[i], sizeof(double) ); // we have to do this because of alignment - numDoubleArgs++; - argWordPos+=2; //add two words - i++;//doubles take up 2 argument slots - } - break; - - case ppcINTARG: - { - // stow register - ppcArgs[argWordPos] = args[i]; - numIntArgs++; - argWordPos++; - } - break; - - case ppcLONGARG: - { - // stow long - memcpy( &ppcArgs[argWordPos], &args[i], 8 ); // for alignment purposes, we use memcpy - numLongArgs++; - argWordPos += 2; // add two words - i++; // longs take up 2 argument slots - } - break; - } - } - - // close off the argument list (if we have max args we won't close it off until here) - ppcArgsType[typeOffset] = ppcENDARG; -} - -static asQWORD CallCDeclFunction(const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory) -{ - int baseArgCount = 0; - if( retInMemory ) - { - // the first argument is the 'return in memory' pointer - ppcArgs[0] = (asDWORD)retInMemory; - ppcArgsType[0] = ppcINTARG; - ppcArgsType[1] = ppcENDARG; - baseArgCount = 1; - } - - // put the arguments in the correct places in the ppcArgs array - int numTotalArgs = baseArgCount; - if( argSize > 0 ) - { - int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0; - stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs ); - numTotalArgs = intArgs + floatArgs + doubleArgs + longArgs; - } - else - { - // no arguments, cap the type list - ppcArgsType[baseArgCount] = ppcENDARG; - } - - // call the function with the arguments - return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func ); -} - -// This function is identical to CallCDeclFunction, with the only difference that -// the value in the first parameter is the object (unless we are returning in memory) -static asQWORD CallThisCallFunction(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory ) -{ - int baseArgCount = 0; - if( retInMemory ) - { - // the first argument is the 'return in memory' pointer - ppcArgs[0] = (asDWORD)retInMemory; - ppcArgsType[0] = ppcINTARG; - ppcArgsType[1] = ppcENDARG; - baseArgCount = 1; - } - - // the first argument is the 'this' of the object - ppcArgs[baseArgCount] = (asDWORD)obj; - ppcArgsType[baseArgCount++] = ppcINTARG; - ppcArgsType[baseArgCount] = ppcENDARG; - - // put the arguments in the correct places in the ppcArgs array - int numTotalArgs = baseArgCount; - if( argSize > 0 ) - { - int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0; - stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs ); - numTotalArgs = intArgs + floatArgs + doubleArgs + longArgs; - } - - // call the function with the arguments - return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func); -} - -// This function is identical to CallCDeclFunction, with the only difference that -// the value in the last parameter is the object -// NOTE: on PPC the order for the args is reversed -static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory) -{ - UNUSED_VAR(argSize); - int baseArgCount = 0; - if( retInMemory ) - { - // the first argument is the 'return in memory' pointer - ppcArgs[0] = (asDWORD)retInMemory; - ppcArgsType[0] = ppcINTARG; - ppcArgsType[1] = ppcENDARG; - baseArgCount = 1; - } - - // stack any of the arguments - int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0; - stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs ); - int numTotalArgs = intArgs + floatArgs + doubleArgs; - - // can we fit the object in at the end? - if( numTotalArgs < AS_PPC_MAX_ARGS ) - { - // put the object pointer at the end - int argPos = intArgs + floatArgs + (doubleArgs * 2) + (longArgs *2); - ppcArgs[argPos] = (asDWORD)obj; - ppcArgsType[numTotalArgs++] = ppcINTARG; - ppcArgsType[numTotalArgs] = ppcENDARG; - } - - // call the function with the arguments - return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func ); -} - -// returns true if the given parameter is a 'variable argument' -inline bool IsVariableArgument( asCDataType type ) -{ - return (type.GetTokenType() == ttQuestion) ? true : false; -} - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - // use a working array of types, we'll configure the final one in stackArgs - asBYTE argsType[AS_PPC_MAX_ARGS + 1 + 1 + 1]; - memset( argsType, 0, sizeof(argsType)); - - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - - int callConv = sysFunc->callConv; - - asQWORD retQW = 0; - void *func = (void*)sysFunc->func; - int paramSize = sysFunc->paramSize; - asDWORD *vftable = NULL; - int a; - - // convert the parameters that are < 4 bytes from little endian to big endian - int argDwordOffset = 0; - int totalArgumentCount = 0; - - for( a = 0; a < (int)descr->parameterTypes.GetLength(); ++a ) - { - // get the size for the parameter - int numBytes = descr->parameterTypes[a].GetSizeInMemoryBytes(); - ++totalArgumentCount; - - // is this a variable argument? - // for variable arguments, the typeID will always follow...but we know it is 4 bytes - // so we can skip that parameter automatically. - bool isVarArg = IsVariableArgument( descr->parameterTypes[a] ); - if( isVarArg ) - { - ++totalArgumentCount; - } - - if( numBytes >= 4 || descr->parameterTypes[a].IsReference() || descr->parameterTypes[a].IsObjectHandle() ) - { - // DWORD or larger parameter --- no flipping needed - argDwordOffset += descr->parameterTypes[a].GetSizeOnStackDWords(); - } - else - { - // flip - asASSERT( numBytes == 1 || numBytes == 2 ); - switch( numBytes ) - { - case 1: - { - volatile asBYTE *bPtr = (asBYTE*)ARG_DW(args[argDwordOffset]); - asBYTE t = bPtr[0]; - bPtr[0] = bPtr[3]; - bPtr[3] = t; - t = bPtr[1]; - bPtr[1] = bPtr[2]; - bPtr[2] = t; - } - break; - case 2: - { - volatile asWORD *wPtr = (asWORD*)ARG_DW(args[argDwordOffset]); - asWORD t = wPtr[0]; - wPtr[0] = wPtr[1]; - wPtr[1] = t; - } - break; - } - ++argDwordOffset; - } - - if( isVarArg ) - { - // skip the implicit typeID - ++argDwordOffset; - } - } - - asASSERT( totalArgumentCount <= AS_PPC_MAX_ARGS ); - - // mark all float/double/int arguments - int argIndex = 0; - for( a = 0; a < (int)descr->parameterTypes.GetLength(); ++a, ++argIndex ) - { - // get the base type - argsType[argIndex] = ppcINTARG; - if( descr->parameterTypes[a].IsFloatType() && !descr->parameterTypes[a].IsReference() ) - { - argsType[argIndex] = ppcFLOATARG; - } - if( descr->parameterTypes[a].IsDoubleType() && !descr->parameterTypes[a].IsReference() ) - { - argsType[argIndex] = ppcDOUBLEARG; - } - if( descr->parameterTypes[a].GetSizeOnStackDWords() == 2 && !descr->parameterTypes[a].IsDoubleType() && !descr->parameterTypes[a].IsReference() ) - { - argsType[argIndex] = ppcLONGARG; - } - - // if it is a variable argument, account for the typeID - if( IsVariableArgument(descr->parameterTypes[a]) ) - { - // implicitly add another parameter (AFTER the parameter above), for the TypeID - argsType[++argIndex] = ppcINTARG; - } - } - asASSERT( argIndex == totalArgumentCount ); - - asDWORD paramBuffer[64]; - if( sysFunc->takesObjByVal ) - { - paramSize = 0; - int spos = 0; - int dpos = 1; - - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - 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 ) - { - paramBuffer[dpos++] = args[spos++]; - ++paramSize; - } - else -#endif - { - // NOTE: we may have to do endian flipping here - - // Copy the object's memory to the buffer - memcpy( ¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes() ); - - // Delete the original memory - engine->CallFree( *(char**)(args+spos) ); - spos++; - dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); - paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); - } - } - else - { - // Copy the value directly - paramBuffer[dpos++] = args[spos++]; - if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) - { - paramBuffer[dpos++] = args[spos++]; - } - paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - - // if this was a variable argument parameter, then account for the implicit typeID - if( IsVariableArgument( descr->parameterTypes[n] ) ) - { - // the TypeID is just a DWORD - paramBuffer[dpos++] = args[spos++]; - ++paramSize; - } - } - - // Keep a free location at the beginning - args = ¶mBuffer[1]; - } - - // one last verification to make sure things are how we expect - switch( callConv ) - { - case ICC_CDECL: - case ICC_CDECL_RETURNINMEM: - case ICC_STDCALL: - case ICC_STDCALL_RETURNINMEM: - retQW = CallCDeclFunction( args, argsType, paramSize, (asDWORD)func, retPointer ); - break; - case ICC_THISCALL: - case ICC_THISCALL_RETURNINMEM: - retQW = CallThisCallFunction(obj, args, argsType, paramSize, (asDWORD)func, retPointer ); - break; - case ICC_VIRTUAL_THISCALL: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - // Get virtual function table from the object pointer - vftable = *(asDWORD**)obj; - retQW = CallThisCallFunction( obj, args, argsType, paramSize, vftable[asDWORD(func)>>2], retPointer ); - break; - case ICC_CDECL_OBJLAST: - case ICC_CDECL_OBJLAST_RETURNINMEM: - retQW = CallThisCallFunction_objLast( obj, args, argsType, paramSize, (asDWORD)func, retPointer ); - break; - case ICC_CDECL_OBJFIRST: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - retQW = CallThisCallFunction( obj, args, argsType, paramSize, (asDWORD)func, retPointer ); - break; - default: - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - } - - if( sysFunc->hostReturnFloat ) - { - // If the return is a float value we need to get the value from the FP register - if( sysFunc->hostReturnSize == 1 ) - *(asDWORD*)&retQW = GetReturnedFloat(); - else - retQW = GetReturnedDouble(); - } - else if( sysFunc->hostReturnSize == 1 ) - { - // Move the bits to the higher value to compensate for the adjustment that the caller does - retQW <<= 32; - } - - return retQW; -} - -END_AS_NAMESPACE - -#endif // AS_PPC_64 -#endif // AS_MAX_PORTABILITY - diff --git a/dependencies/angelscript/source/as_callfunc_sh4.cpp b/dependencies/angelscript/source/as_callfunc_sh4.cpp deleted file mode 100644 index 7da02613..00000000 --- a/dependencies/angelscript/source/as_callfunc_sh4.cpp +++ /dev/null @@ -1,391 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc_sh4.cpp -// -// These functions handle the actual calling of system functions -// -// This version is SH4 specific and was originally written -// by Fredrik Ehnbom in May, 2004 -// Later updated for angelscript 2.0.0 by Fredrik Ehnbom in Jan, 2005 - -// References: -// * http://www.renesas.com/avs/resource/japan/eng/pdf/mpumcu/e602156_sh4.pdf -// * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcechp40/html/_callsh4_SH_4_Calling_Standard.asp - - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_SH4 - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_tokendef.h" -#include "as_context.h" - -#include -#include - -BEGIN_AS_NAMESPACE - -#define AS_SH4_MAX_ARGS 32 -// The array used to send values to the correct places. -// first 0-4 regular values to load into the r4-r7 registers -// then 0-8 float values to load into the fr4-fr11 registers -// then (AS_SH4_MAX_ARGS - 12) values to load onto the stack -// the +1 is for when CallThis (object methods) is used -// extra +1 when returning in memory -extern "C" { -static asDWORD sh4Args[AS_SH4_MAX_ARGS + 1 + 1]; -} - -// Loads all data into the correct places and calls the function. -// intArgSize is the size in bytes for how much data to put in int registers -// floatArgSize is the size in bytes for how much data to put in float registers -// stackArgSize is the size in bytes for how much data to put on the callstack -extern "C" asQWORD sh4Func(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func); - -asm("" -" .align 4\n" -" .global _sh4Func\n" -"_sh4Func:\n" -" mov.l r14,@-r15\n" -" mov.l r13,@-r15\n" -" mov.l r12,@-r15\n" -" sts.l pr,@-r15\n" // must be saved since we call a subroutine -" mov r7, r14\n" // func -" mov r6, r13\n" // stackArgSize -" mov.l r5,@-r15\n" // floatArgSize -" mov.l sh4Args,r0\n" -" pref @r0\n" -" mov r4, r1\n" // intArgsize -" mov #33*4,r2\n" -" extu.b r2,r2\n" // make unsigned (33*4 = 132 => 128) -" mov.l @(r0,r2), r2\n" // r2 has adress for when returning in memory -"_sh4f_intarguments:\n" // copy all the int arguments to the respective registers -" mov #4*2*2,r3\n" // calculate how many bytes to skip -" sub r1,r3\n" -" braf r3\n" -" add #-4,r1\n" // we are indexing the array backwards, so subtract one (delayed slot) -" mov.l @(r0,r1),r7\n" // 4 arguments -" add #-4,r1\n" -" mov.l @(r0,r1),r6\n" // 3 arguments -" add #-4,r1\n" -" mov.l @(r0,r1),r5\n" // 2 arguments -" add #-4,r1\n" -" mov.l @(r0,r1),r4\n" // 1 argument -" nop\n" -"_sh4f_floatarguments:\n" // copy all the float arguments to the respective registers -" add #4*4, r0\n" -" mov.l @r15+,r1\n" // floatArgSize -" mov #8*2*2,r3\n" // calculate how many bytes to skip -" sub r1,r3\n" -" braf r3\n" -" add #-4,r1\n" // we are indexing the array backwards, so subtract one (delayed slot) -" fmov.s @(r0,r1),fr11\n" // 8 arguments -" add #-4,r1\n" -" fmov.s @(r0,r1),fr10\n" // 7 arguments -" add #-4,r1\n" -" fmov.s @(r0,r1),fr9\n" // 6 arguments -" add #-4,r1\n" -" fmov.s @(r0,r1),fr8\n" // 5 arguments -" add #-4,r1\n" -" fmov.s @(r0,r1),fr7\n" // 4 arguments -" add #-4,r1\n" -" fmov.s @(r0,r1),fr6\n" // 3 arguments -" add #-4,r1\n" -" fmov.s @(r0,r1),fr5\n" // 2 arguments -" add #-4,r1\n" -" fmov.s @(r0,r1),fr4\n" // 1 argument -" nop\n" -"_sh4f_stackarguments:\n" // copy all the stack argument onto the stack -" add #8*4, r0\n" -" mov r0, r1\n" -" mov #0, r0\n" // init position counter (also used as a 0-check on the line after) -" cmp/eq r0, r13\n" -" bt _sh4f_functioncall\n" // no arguments to push onto the stack -" mov r13, r3\n" // stackArgSize -" sub r3,r15\n" // "allocate" space on the stack -" shlr2 r3\n" // make into a counter -"_sh4f_stackloop:\n" -" mov.l @r1+, r12\n" -" mov.l r12, @(r0, r15)\n" -" add #4, r0\n" -" dt r3\n" -" bf _sh4f_stackloop\n" -"_sh4f_functioncall:\n" -" jsr @r14\n" // no arguments -" nop\n" -" add r13, r15\n" // restore stack position -" lds.l @r15+,pr\n" -" mov.l @r15+, r12\n" -" mov.l @r15+, r13\n" -" rts\n" -" mov.l @r15+, r14\n" // delayed slot -"\n" -" .align 4\n" -"sh4Args:\n" -" .long _sh4Args\n" -); - -// puts the arguments in the correct place in the sh4Args-array. See comments above. -// This could be done better. -inline void splitArgs(const asDWORD *args, int argNum, int &numRegIntArgs, int &numRegFloatArgs, int &numRestArgs, int hostFlags) { - int i; - - int argBit = 1; - for (i = 0; i < argNum; i++) { - if (hostFlags & argBit) { - if (numRegFloatArgs < 12 - 4) { - // put in float register - sh4Args[4 + numRegFloatArgs] = args[i]; - numRegFloatArgs++; - } else { - // put in stack - sh4Args[4 + 8 + numRestArgs] = args[i]; - numRestArgs++; - } - } else { - if (numRegIntArgs < 8 - 4) { - // put in int register - sh4Args[numRegIntArgs] = args[i]; - numRegIntArgs++; - } else { - // put in stack - sh4Args[4 + 8 + numRestArgs] = args[i]; - numRestArgs++; - } - } - argBit <<= 1; - } -} -asQWORD CallCDeclFunction(const asDWORD *args, int argSize, asDWORD func, int flags) -{ - int argNum = argSize >> 2; - - int intArgs = 0; - int floatArgs = 0; - int restArgs = 0; - - // put the arguments in the correct places in the sh4Args array - if (argNum > 0) - splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); - - return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func); -} - -// This function is identical to CallCDeclFunction, with the only difference that -// the value in the first parameter is the object -asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags) -{ - int argNum = argSize >> 2; - - int intArgs = 1; - int floatArgs = 0; - int restArgs = 0; - - sh4Args[0] = (asDWORD) obj; - - // put the arguments in the correct places in the sh4Args array - if (argNum >= 1) - splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); - - return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func); -} -// This function is identical to CallCDeclFunction, with the only difference that -// the value in the last parameter is the object -asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags) -{ - int argNum = argSize >> 2; - - int intArgs = 0; - int floatArgs = 0; - int restArgs = 0; - - - // put the arguments in the correct places in the sh4Args array - if (argNum >= 1) - splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); - - if (intArgs < 4) { - sh4Args[intArgs] = (asDWORD) obj; - intArgs++; - } else { - sh4Args[4 + 8 + restArgs] = (asDWORD) obj; - restArgs++; - } - - - return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func); -} - -asDWORD GetReturnedFloat() -{ - asDWORD f; - - asm("fmov.s fr0, %0\n" : "=m"(f)); - - return f; -} - -// sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4 -// so this isn't really used... -asQWORD GetReturnedDouble() -{ - asQWORD d; - - asm("fmov dr0, %0\n" : "=m"(d)); - - return d; -} - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - int callConv = sysFunc->callConv; - - asQWORD retQW = 0; - - void *func = (void*)sysFunc->func; - int paramSize = sysFunc->paramSize; - asDWORD *vftable; - - if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() ) - { - sh4Args[AS_SH4_MAX_ARGS+1] = (asDWORD) retPointer; - } - - asASSERT(descr->parameterTypes.GetLength() <= 32); - - // mark all float arguments - int argBit = 1; - int hostFlags = 0; - int intArgs = 0; - for( asUINT a = 0; a < descr->parameterTypes.GetLength(); a++ ) { - if (descr->parameterTypes[a].IsFloatType()) { - hostFlags |= argBit; - } else intArgs++; - argBit <<= 1; - } - - asDWORD paramBuffer[64]; - if( sysFunc->takesObjByVal ) - { - paramSize = 0; - int spos = 0; - int dpos = 1; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - 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 ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else -#endif - { - // Copy the object's memory to the buffer - memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos++; - dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); - paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); - } - } - else - { - // Copy the value directly - paramBuffer[dpos++] = args[spos++]; - if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) - paramBuffer[dpos++] = args[spos++]; - paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - } - // Keep a free location at the beginning - args = ¶mBuffer[1]; - } - - switch( callConv ) - { - case ICC_CDECL: - case ICC_CDECL_RETURNINMEM: - case ICC_STDCALL: - case ICC_STDCALL_RETURNINMEM: - retQW = CallCDeclFunction(args, paramSize<<2, (asDWORD)func, hostFlags); - break; - case ICC_THISCALL: - case ICC_THISCALL_RETURNINMEM: - retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags); - break; - case ICC_VIRTUAL_THISCALL: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - // Get virtual function table from the object pointer - vftable = *(asDWORD**)obj; - retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[asDWORD(func)>>2], hostFlags); - break; - case ICC_CDECL_OBJLAST: - case ICC_CDECL_OBJLAST_RETURNINMEM: - retQW = CallThisCallFunction_objLast(obj, args, paramSize<<2, (asDWORD)func, hostFlags); - break; - case ICC_CDECL_OBJFIRST: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags); - break; - default: - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - } - - // If the return is a float value we need to get the value from the FP register - if( sysFunc->hostReturnFloat ) - { - if( sysFunc->hostReturnSize == 1 ) - *(asDWORD*)&retQW = GetReturnedFloat(); - else - retQW = GetReturnedDouble(); - } - - return retQW; -} - -END_AS_NAMESPACE - -#endif // AS_SH4 -#endif // AS_MAX_PORTABILITY - - diff --git a/dependencies/angelscript/source/as_callfunc_x64_gcc.cpp b/dependencies/angelscript/source/as_callfunc_x64_gcc.cpp deleted file mode 100644 index 28e2d2bc..00000000 --- a/dependencies/angelscript/source/as_callfunc_x64_gcc.cpp +++ /dev/null @@ -1,479 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - -/* - * Implements the AMD64 calling convention for gcc-based 64bit Unices - * - * Author: Ionut "gargltk" Leonte - * - * Initial author: niteice - * - * Added support for functor methods by Jordi Oliveras Rovira in April, 2014. - */ - -// Useful references for the System V AMD64 ABI: -// http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ -// http://math-atlas.sourceforge.net/devel/assembly/abi_sysV_amd64.pdf - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_X64_GCC - -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_context.h" - -BEGIN_AS_NAMESPACE - -enum argTypes { x64INTARG = 0, x64FLOATARG = 1 }; -typedef asQWORD ( *funcptr_t )( void ); - -#define X64_MAX_ARGS 32 -#define MAX_CALL_INT_REGISTERS 6 -#define MAX_CALL_SSE_REGISTERS 8 -#define X64_CALLSTACK_SIZE ( X64_MAX_ARGS + MAX_CALL_SSE_REGISTERS + 3 ) - -// Note to self: Always remember to inform the used registers on the clobber line, -// so that the gcc optimizer doesn't try to use them for other things - -static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, int cnt, funcptr_t func, asQWORD &retQW2, bool returnFloat) -{ - // Need to flag the variable as volatile so the compiler doesn't optimize out the variable - volatile asQWORD retQW1 = 0; - - // Reference: http://www.x86-64.org/documentation/abi.pdf - - __asm__ __volatile__ ( - - " movq %0, %%rcx \n" // rcx = cnt - " movq %1, %%r10 \n" // r10 = args - " movq %2, %%r11 \n" // r11 = func - - // Backup stack pointer in R15 that is guaranteed to maintain its value over function calls - " movq %%rsp, %%r15 \n" - // Make sure the stack unwind logic knows we've backed up the stack pointer in register r15 - " .cfi_def_cfa_register r15 \n" - - // Skip the first 128 bytes on the stack frame, called "red zone", - // that might be used by the compiler to store temporary values - " sub $128, %%rsp \n" - - // Make sure the stack pointer will be aligned to 16 bytes when the function is called - " movq %%rcx, %%rdx \n" - " salq $3, %%rdx \n" - " movq %%rsp, %%rax \n" - " sub %%rdx, %%rax \n" - " and $15, %%rax \n" - " sub %%rax, %%rsp \n" - - // Push the stack parameters, i.e. the arguments that won't be loaded into registers - " movq %%rcx, %%rsi \n" - " testl %%esi, %%esi \n" - " jle endstack \n" - " subl $1, %%esi \n" - " xorl %%edx, %%edx \n" - " leaq 8(, %%rsi, 8), %%rcx \n" - "loopstack: \n" - " movq 112(%%r10, %%rdx), %%rax \n" - " pushq %%rax \n" - " addq $8, %%rdx \n" - " cmpq %%rcx, %%rdx \n" - " jne loopstack \n" - "endstack: \n" - - // Populate integer and floating point parameters - " movq %%r10, %%rax \n" - " mov (%%rax), %%rdi \n" - " mov 8(%%rax), %%rsi \n" - " mov 16(%%rax), %%rdx \n" - " mov 24(%%rax), %%rcx \n" - " mov 32(%%rax), %%r8 \n" - " mov 40(%%rax), %%r9 \n" - " add $48, %%rax \n" - " movsd (%%rax), %%xmm0 \n" - " movsd 8(%%rax), %%xmm1 \n" - " movsd 16(%%rax), %%xmm2 \n" - " movsd 24(%%rax), %%xmm3 \n" - " movsd 32(%%rax), %%xmm4 \n" - " movsd 40(%%rax), %%xmm5 \n" - " movsd 48(%%rax), %%xmm6 \n" - " movsd 56(%%rax), %%xmm7 \n" - - // Call the function - " call *%%r11 \n" - - // Restore stack pointer - " mov %%r15, %%rsp \n" - // Inform the stack unwind logic that the stack pointer has been restored - " .cfi_def_cfa_register rsp \n" - - // Put return value in retQW1 and retQW2, using either RAX:RDX or XMM0:XMM1 depending on type of return value - " movl %5, %%ecx \n" - " testb %%cl, %%cl \n" - " je intret \n" - " lea %3, %%rax \n" - " movq %%xmm0, (%%rax) \n" - " lea %4, %%rdx \n" - " movq %%xmm1, (%%rdx) \n" - " jmp endcall \n" - "intret: \n" - " movq %%rax, %3 \n" - " movq %%rdx, %4 \n" - "endcall: \n" - - : : "r" ((asQWORD)cnt), "r" (args), "r" (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"); - - return retQW1; -} - -// returns true if the given parameter is a 'variable argument' -static inline bool IsVariableArgument( asCDataType type ) -{ - return ( type.GetTokenType() == ttQuestion ) ? true : false; -} - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - int callConv = sysFunc->callConv; - asQWORD retQW = 0; - asDWORD *stack_pointer = args; - funcptr_t *vftable = NULL; - int totalArgumentCount = 0; - int n = 0; - int param_post = 0; - int argIndex = 0; - funcptr_t func = (funcptr_t)sysFunc->func; - - if( sysFunc->hostReturnInMemory ) - { - // The return is made in memory - callConv++; - } - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - // Unpack the two object pointers - void **objectsPtrs = (void**)obj; - void *secondObject = objectsPtrs[1]; - obj = objectsPtrs[0]; - - // param_post has value 2 if is an THISCALL_OBJLAST -#endif - - -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - // Determine the real function pointer in case of virtual method - if ( obj && ( callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) ) -#else - if ( obj && ( callConv == ICC_VIRTUAL_THISCALL || - callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) ) -#endif - { - vftable = *((funcptr_t**)obj); - func = vftable[FuncPtrToUInt(asFUNCTION_t(func)) >> 3]; - } - - // Determine the type of the arguments, and prepare the input array for the X64_CallFunction - asQWORD paramBuffer[X64_CALLSTACK_SIZE] = { 0 }; - asBYTE argsType[X64_CALLSTACK_SIZE] = { 0 }; - - switch ( callConv ) - { - case ICC_CDECL_RETURNINMEM: - case ICC_STDCALL_RETURNINMEM: - { - paramBuffer[0] = (asPWORD)retPointer; - argsType[0] = x64INTARG; - - argIndex = 1; - - break; - } -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJLAST: - case ICC_VIRTUAL_THISCALL_OBJLAST: - param_post = 2; -#endif - case ICC_THISCALL: - case ICC_VIRTUAL_THISCALL: - case ICC_CDECL_OBJFIRST: - { - paramBuffer[0] = (asPWORD)obj; - argsType[0] = x64INTARG; - - argIndex = 1; - - break; - } -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJLAST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: - param_post = 2; -#endif - case ICC_THISCALL_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - { - paramBuffer[0] = (asPWORD)retPointer; - paramBuffer[1] = (asPWORD)obj; - argsType[0] = x64INTARG; - argsType[1] = x64INTARG; - - argIndex = 2; - - break; - } -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJFIRST: - case ICC_VIRTUAL_THISCALL_OBJFIRST: - { - paramBuffer[0] = (asPWORD)obj; - paramBuffer[1] = (asPWORD)secondObject; - argsType[0] = x64INTARG; - argsType[1] = x64INTARG; - - argIndex = 2; - break; - } - case ICC_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: - { - paramBuffer[0] = (asPWORD)retPointer; - paramBuffer[1] = (asPWORD)obj; - paramBuffer[2] = (asPWORD)secondObject; - argsType[0] = x64INTARG; - argsType[1] = x64INTARG; - argsType[2] = x64INTARG; - - argIndex = 3; - break; - } -#endif - case ICC_CDECL_OBJLAST: - param_post = 1; - break; - case ICC_CDECL_OBJLAST_RETURNINMEM: - { - paramBuffer[0] = (asPWORD)retPointer; - argsType[0] = x64INTARG; - - argIndex = 1; - param_post = 1; - - break; - } - } - - int argumentCount = ( int )descr->parameterTypes.GetLength(); - for( int a = 0; a < argumentCount; ++a ) - { - const asCDataType &parmType = descr->parameterTypes[a]; - if( parmType.IsFloatType() && !parmType.IsReference() ) - { - argsType[argIndex] = x64FLOATARG; - memcpy(paramBuffer + argIndex, stack_pointer, sizeof(float)); - argIndex++; - stack_pointer++; - } - else if( parmType.IsDoubleType() && !parmType.IsReference() ) - { - argsType[argIndex] = x64FLOATARG; - memcpy(paramBuffer + argIndex, stack_pointer, sizeof(double)); - argIndex++; - stack_pointer += 2; - } - else if( IsVariableArgument( parmType ) ) - { - // The variable args are really two, one pointer and one type id - argsType[argIndex] = x64INTARG; - argsType[argIndex+1] = x64INTARG; - memcpy(paramBuffer + argIndex, stack_pointer, sizeof(void*)); - memcpy(paramBuffer + argIndex + 1, stack_pointer + 2, sizeof(asDWORD)); - argIndex += 2; - stack_pointer += 3; - } - else if( parmType.IsPrimitive() || - parmType.IsReference() || - parmType.IsObjectHandle() ) - { - argsType[argIndex] = x64INTARG; - if( parmType.GetSizeOnStackDWords() == 1 ) - { - memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asDWORD)); - stack_pointer++; - } - else - { - memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asQWORD)); - stack_pointer += 2; - } - argIndex++; - } - else - { - // An object is being passed by value - if( (parmType.GetObjectType()->flags & COMPLEX_MASK) || - parmType.GetSizeInMemoryDWords() > 4 ) - { - // Copy the address of the object - argsType[argIndex] = x64INTARG; - memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asQWORD)); - argIndex++; - } - else if( (parmType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLINTS) || - (parmType.GetObjectType()->flags & asOBJ_APP_PRIMITIVE) ) - { - // Copy the value of the object - if( parmType.GetSizeInMemoryDWords() > 2 ) - { - argsType[argIndex] = x64INTARG; - argsType[argIndex+1] = x64INTARG; - memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes()); - argIndex += 2; - } - else - { - argsType[argIndex] = x64INTARG; - memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes()); - argIndex++; - } - // Delete the original memory - engine->CallFree(*(void**)stack_pointer); - } - else if( (parmType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS) || - (parmType.GetObjectType()->flags & asOBJ_APP_FLOAT) ) - { - // Copy the value of the object - if( parmType.GetSizeInMemoryDWords() > 2 ) - { - argsType[argIndex] = x64FLOATARG; - argsType[argIndex+1] = x64FLOATARG; - memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes()); - argIndex += 2; - } - else - { - argsType[argIndex] = x64FLOATARG; - memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes()); - argIndex++; - } - // Delete the original memory - engine->CallFree(*(void**)stack_pointer); - } - stack_pointer += 2; - } - } - - // For the CDECL_OBJ_LAST calling convention we need to add the object pointer as the last argument - if( param_post ) - { -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - paramBuffer[argIndex] = (asPWORD)obj; -#else - paramBuffer[argIndex] = (asPWORD)(param_post > 1 ? secondObject : obj); -#endif - argsType[argIndex] = x64INTARG; - argIndex++; - } - - totalArgumentCount = argIndex; - - /* - * Q: WTF is going on here !? - * - * A: The idea is to pre-arange the parameters so that X64_CallFunction() can do - * it's little magic which must work regardless of how the compiler decides to - * allocate registers. Basically: - * - the first MAX_CALL_INT_REGISTERS entries in tempBuff will - * contain the values/types of the x64INTARG parameters - that is the ones who - * go into the registers. If the function has less then MAX_CALL_INT_REGISTERS - * integer parameters then the last entries will be set to 0 - * - the next MAX_CALL_SSE_REGISTERS entries will contain the float/double arguments - * that go into the floating point registers. If the function has less than - * MAX_CALL_SSE_REGISTERS floating point parameters then the last entries will - * be set to 0 - * - index MAX_CALL_INT_REGISTERS + MAX_CALL_SSE_REGISTERS marks the start of the - * parameters which will get passed on the stack. These are added to the array - * in reverse order so that X64_CallFunction() can simply push them to the stack - * without the need to perform further tests - */ - asQWORD tempBuff[X64_CALLSTACK_SIZE] = { 0 }; - asBYTE argsSet[X64_CALLSTACK_SIZE] = { 0 }; - int used_int_regs = 0; - int used_sse_regs = 0; - int used_stack_args = 0; - int idx = 0; - for ( n = 0; ( n < totalArgumentCount ) && ( used_int_regs < MAX_CALL_INT_REGISTERS ); n++ ) - { - if ( argsType[n] == x64INTARG ) - { - argsSet[n] = 1; - tempBuff[idx++] = paramBuffer[n]; - used_int_regs++; - } - } - idx = MAX_CALL_INT_REGISTERS; - for ( n = 0; ( n < totalArgumentCount ) && ( used_sse_regs < MAX_CALL_SSE_REGISTERS ); n++ ) - { - if ( argsType[n] == x64FLOATARG ) - { - argsSet[n] = 1; - tempBuff[idx++] = paramBuffer[n]; - used_sse_regs++; - } - } - idx = MAX_CALL_INT_REGISTERS + MAX_CALL_SSE_REGISTERS; - for ( n = totalArgumentCount - 1; n >= 0; n-- ) - { - if ( !argsSet[n] ) - { - tempBuff[idx++] = paramBuffer[n]; - used_stack_args++; - } - } - - retQW = X64_CallFunction( tempBuff, used_stack_args, func, retQW2, sysFunc->hostReturnFloat ); - - return retQW; -} - -END_AS_NAMESPACE - -#endif // AS_X64_GCC -#endif // AS_MAX_PORTABILITY - diff --git a/dependencies/angelscript/source/as_callfunc_x64_mingw.cpp b/dependencies/angelscript/source/as_callfunc_x64_mingw.cpp deleted file mode 100644 index 6673aeca..00000000 --- a/dependencies/angelscript/source/as_callfunc_x64_mingw.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - -// -// This code was adapted from as_callfunc_x64_msvc by _Vicious_ on August 20th, 2011. -// -// Added support for functor methods by Jordi Oliveras Rovira in April, 2014. -// - -#include - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_X64_MINGW - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_context.h" - -BEGIN_AS_NAMESPACE - -static asQWORD __attribute__((noinline)) CallX64(const asQWORD *args, const asQWORD *floatArgs, const int paramSize, asQWORD func) -{ - volatile asQWORD ret = 0; - - __asm__ __volatile__ ( - "# Move the parameters into registers before the rsp is modified\n" - "mov %1, %%r10\n" // r10 = args - "mov %2, %%r11\n" // r11 = floatArgs - "xor %%r12, %%r12\n" - "mov %3, %%r12d\n" - "mov %4, %%r14\n" // r14 = func - - "# Store the stack pointer in r15 since it is guaranteed not to change over a function call\n" - "mov %%rsp, %%r15\n" - - "# Allocate space on the stack for the arguments\n" - "# Make room for at least 4 arguments even if there are less. When\n" - "# the compiler does optimizations for speed it may use these for \n" - "# temporary storage.\n" - "mov %%r12, %%rdi\n" - "add $32,%%edi\n" - - "# Make sure the stack pointer is 16byte aligned so the\n" - "# whole program optimizations will work properly\n" - "# TODO: runtime optimize: Can this be optimized with fewer instructions?\n" - "mov %%rsp,%%rsi\n" - "sub %%rdi,%%rsi\n" - "and $0x8,%%rsi\n" - "add %%rsi,%%rdi\n" - "sub %%rdi,%%rsp\n" - - "# Jump straight to calling the function if no parameters\n" - "cmp $0,%%r12 # Compare paramSize with 0\n" - "je callfunc # Jump to call funtion if (paramSize == 0)\n" - - "# Copy arguments from script stack to application stack\n" - "# Order is (first to last):\n" - "# rcx, rdx, r8, r9 & everything else goes on stack\n" - "movq (%%r10),%%rcx\n" - "movq 8(%%r10),%%rdx\n" - "movq 16(%%r10),%%r8\n" - "movq 24(%%r10),%%r9\n" - - "# Negate the 4 params from the size to be copied\n" - "sub $32,%%r12d\n" - "js copyfloat # Jump if negative result\n" - "jz copyfloat # Jump if zero result\n" - - "# Now copy all remaining params onto stack allowing space for first four\n" - "# params to be flushed back to the stack if required by the callee.\n" - "add $32,%%r10 # Position input pointer 4 args ahead\n" - "mov %%rsp,%%r13 # Put the stack pointer into r13\n" - "add $32,%%r13 # Leave space for first 4 args on stack\n" - - "copyoverflow:\n" - "movq (%%r10),%%rdi # Read param from source stack into rdi\n" - "movq %%rdi,(%%r13) # Copy param to real stack\n" - "add $8,%%r13 # Move virtual stack pointer\n" - "add $8,%%r10 # Move source stack pointer\n" - "sub $8,%%r12d # Decrement remaining count\n" - "jnz copyoverflow # Continue if more params\n" - - "copyfloat:\n" - "# Any floating point params?\n" - "cmp $0,%%r11\n" - "je callfunc\n" - - "movlpd (%%r11),%%xmm0\n" - "movlpd 8(%%r11),%%xmm1\n" - "movlpd 16(%%r11),%%xmm2\n" - "movlpd 24(%%r11),%%xmm3\n" - - "callfunc:\n" - "call *%%r14\n" - - "# restore stack pointer\n" - "mov %%r15, %%rsp\n" - - "lea %0, %%rbx\n" // Load the address of the ret variable into rbx - "movq %%rax,(%%rbx)\n" // Copy the returned value into the ret variable - - : // no output - : "m" (ret), "r" (args), "r" (floatArgs), "r" (paramSize), "r" (func) - : "rdi", "rsi", "rsp", "rbx", "r10", "r11", "%r12", "r13", "r14", "r15" - ); - - return ret; -} - -static asDWORD GetReturnedFloat() -{ - volatile asDWORD ret = 0; - - __asm__ __volatile__ ( - "lea %0, %%rax\n" - "movss %%xmm0, (%%rax)" - : /* no output */ - : "m" (ret) - : "%rax" - ); - - return ret; -} - -static asQWORD GetReturnedDouble() -{ - volatile asQWORD ret = 0; - - __asm__ __volatile__ ( - "lea %0, %%rax\n" - "movlpd %%xmm0, (%%rax)" - : /* no optput */ - : "m" (ret) - : "%rax" - ); - - return ret; -} - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - - asQWORD retQW = 0; - void *func = (void*)sysFunc->func; - asUINT paramSize = 0; // QWords - void **vftable; - - asQWORD allArgBuffer[64]; - asQWORD floatArgBuffer[4]; - - int callConv = sysFunc->callConv; - - if( sysFunc->hostReturnInMemory ) - { - // The return is made in memory - callConv++; - - // Set the return pointer as the first argument - allArgBuffer[paramSize++] = (asQWORD)retPointer; - } - -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - if( callConv == ICC_THISCALL || - callConv == ICC_THISCALL_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL || - callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) -#else - // Unpack the two object pointers - void **objectsPtrs = (void**)obj; - void *secondObject = objectsPtrs[1]; - obj = objectsPtrs[0]; - - // Optimization to avoid check 12 values (all ICC_ that contains THISCALL) - if( (callConv >= ICC_THISCALL && callConv <= ICC_VIRTUAL_THISCALL_RETURNINMEM) || - (callConv >= ICC_THISCALL_OBJLAST && callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) -#endif - { - // Add the object pointer as the first parameter - allArgBuffer[paramSize++] = (asQWORD)obj; - } - - if( callConv == ICC_CDECL_OBJFIRST || - callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ) - { - // Add the object pointer as the first parameter - allArgBuffer[paramSize++] = (asQWORD)obj; - } -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - else if( callConv == ICC_THISCALL_OBJFIRST || - callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ) - { - // Add the object pointer as the first parameter - allArgBuffer[paramSize++] = (asQWORD)secondObject; - } -#endif - -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - if( callConv == ICC_VIRTUAL_THISCALL || - callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) -#else - if( callConv == ICC_VIRTUAL_THISCALL || - callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) -#endif - { - // Get the true function pointer from the virtual function table - vftable = *(void***)obj; - func = vftable[asPWORD(func)>>3]; - } - - // Move the arguments to the buffer - asUINT dpos = paramSize; - asUINT spos = 0; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - 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) ) - { - allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; - spos += AS_PTR_SIZE; - paramSize++; - } - else - { - // Copy the object's memory to the buffer - memcpy(&allArgBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos += AS_PTR_SIZE; - asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords(); - asUINT qwords = (dwords >> 1) + (dwords & 1); - dpos += qwords; - paramSize += qwords; - } - } - else if( descr->parameterTypes[n].GetTokenType() == ttQuestion ) - { - // Copy the reference and the type id - allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; - spos += 2; - allArgBuffer[dpos++] = args[spos++]; - paramSize += 2; - } - else - { - // Copy the value directly - asUINT dwords = descr->parameterTypes[n].GetSizeOnStackDWords(); - if( dwords > 1 ) - { - allArgBuffer[dpos] = *(asQWORD*)&args[spos]; - - // Double arguments are moved to a separate buffer in order to be placed in the XMM registers, - // though this is only done for first 4 arguments, the rest are placed on the stack - if( paramSize < 4 && descr->parameterTypes[n].IsDoubleType() ) - floatArgBuffer[dpos] = *(asQWORD*)&args[spos]; - - dpos++; - spos += 2; - } - else - { - allArgBuffer[dpos] = args[spos]; - - // Float arguments are moved to a separate buffer in order to be placed in the XMM registers, - // though this is only done for first 4 arguments, the rest are placed on the stack - if( paramSize < 4 && descr->parameterTypes[n].IsFloatType() ) - floatArgBuffer[dpos] = args[spos]; - - dpos++; - spos++; - } - - paramSize++; - } - } - - if( callConv == ICC_CDECL_OBJLAST || - callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) - { - // Add the object pointer as the last parameter - allArgBuffer[paramSize++] = (asQWORD)obj; - } -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - else if( callConv == ICC_THISCALL_OBJLAST || - callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) - { - // Add the object pointer as the last parameter - allArgBuffer[paramSize++] = (asQWORD)secondObject; - } -#endif - - retQW = CallX64(allArgBuffer, floatArgBuffer, paramSize*8, (asPWORD)func); - - // If the return is a float value we need to get the value from the FP register - if( sysFunc->hostReturnFloat ) - { - if( sysFunc->hostReturnSize == 1 ) - *(asDWORD*)&retQW = GetReturnedFloat(); - else - retQW = GetReturnedDouble(); - } - - return retQW; -} - -END_AS_NAMESPACE - -#endif // AS_X64_MSVC -#endif // AS_MAX_PORTABILITY - - diff --git a/dependencies/angelscript/source/as_callfunc_x64_msvc.cpp b/dependencies/angelscript/source/as_callfunc_x64_msvc.cpp deleted file mode 100644 index 949a988c..00000000 --- a/dependencies/angelscript/source/as_callfunc_x64_msvc.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - -// -// Added support for thiscall methods by Jordi Oliveras Rovira in April, 2014. -// - -#include - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_X64_MSVC - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_context.h" - -BEGIN_AS_NAMESPACE - -// These functions are implemented in as_callfunc_x64_msvc.asm -extern "C" asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, int paramSize, asQWORD func); -extern "C" asDWORD GetReturnedFloat(); -extern "C" asQWORD GetReturnedDouble(); - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - - asQWORD retQW = 0; - void *func = (void*)sysFunc->func; - asUINT paramSize = 0; // QWords - void **vftable; - - asQWORD allArgBuffer[64]; - asQWORD floatArgBuffer[4]; - - int callConv = sysFunc->callConv; - -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - if( callConv == ICC_THISCALL || - callConv == ICC_THISCALL_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL || - callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) -#else - // Unpack the two object pointers - void **objectsPtrs = (void**)obj; - void *secondObject = objectsPtrs[1]; - obj = objectsPtrs[0]; - - // Optimization to avoid check 12 values (all ICC_ that contains THISCALL) - if( (callConv >= ICC_THISCALL && callConv <= ICC_VIRTUAL_THISCALL_RETURNINMEM) || - (callConv >= ICC_THISCALL_OBJLAST && callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) -#endif - { - // Add the object pointer as the first parameter - allArgBuffer[paramSize++] = (asQWORD)obj; - } - - if( sysFunc->hostReturnInMemory ) - { - // The return is made in memory - callConv++; - - // Set the return pointer as the first argument - allArgBuffer[paramSize++] = (asQWORD)retPointer; - } - - if( callConv == ICC_CDECL_OBJFIRST || - callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ) - { - // Add the object pointer as the first parameter - allArgBuffer[paramSize++] = (asQWORD)obj; - } -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - else if( callConv == ICC_THISCALL_OBJFIRST || - callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ) - { - // Add the object pointer as the first parameter - allArgBuffer[paramSize++] = (asQWORD)secondObject; - } -#endif - -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - if( callConv == ICC_VIRTUAL_THISCALL || - callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) -#else - if( callConv == ICC_VIRTUAL_THISCALL || - callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || - callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) -#endif - { - // Get the true function pointer from the virtual function table - vftable = *(void***)obj; - func = vftable[asPWORD(func)>>2]; - } - - // Move the arguments to the buffer - asUINT dpos = paramSize; - asUINT spos = 0; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - 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) ) - { - allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; - spos += AS_PTR_SIZE; - paramSize++; - } - else - { - // Copy the object's memory to the buffer - memcpy(&allArgBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos += AS_PTR_SIZE; - asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords(); - asUINT qwords = (dwords >> 1) + (dwords & 1); - dpos += qwords; - paramSize += qwords; - } - } - else if( descr->parameterTypes[n].GetTokenType() == ttQuestion ) - { - // Copy the reference and the type id - allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; - spos += 2; - allArgBuffer[dpos++] = args[spos++]; - paramSize += 2; - } - else - { - // Copy the value directly - asUINT dwords = descr->parameterTypes[n].GetSizeOnStackDWords(); - if( dwords > 1 ) - { - allArgBuffer[dpos] = *(asQWORD*)&args[spos]; - - // Double arguments are moved to a separate buffer in order to be placed in the XMM registers, - // though this is only done for first 4 arguments, the rest are placed on the stack - if( paramSize < 4 && descr->parameterTypes[n].IsDoubleType() ) - floatArgBuffer[dpos] = *(asQWORD*)&args[spos]; - - dpos++; - spos += 2; - } - else - { - allArgBuffer[dpos] = args[spos]; - - // Float arguments are moved to a separate buffer in order to be placed in the XMM registers, - // though this is only done for first 4 arguments, the rest are placed on the stack - if( paramSize < 4 && descr->parameterTypes[n].IsFloatType() ) - floatArgBuffer[dpos] = args[spos]; - - dpos++; - spos++; - } - - paramSize++; - } - } - - if( callConv == ICC_CDECL_OBJLAST || - callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) - { - // Add the object pointer as the last parameter - allArgBuffer[paramSize++] = (asQWORD)obj; - } -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - else if( callConv == ICC_THISCALL_OBJLAST || - callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST || - callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) - { - // Add the object pointer as the last parameter - allArgBuffer[paramSize++] = (asQWORD)secondObject; - } -#endif - - retQW = CallX64(allArgBuffer, floatArgBuffer, paramSize*8, (asPWORD)func); - - // If the return is a float value we need to get the value from the FP register - if( sysFunc->hostReturnFloat ) - { - if( sysFunc->hostReturnSize == 1 ) - *(asDWORD*)&retQW = GetReturnedFloat(); - else - retQW = GetReturnedDouble(); - } - - return retQW; -} - -END_AS_NAMESPACE - -#endif // AS_X64_MSVC -#endif // AS_MAX_PORTABILITY - - diff --git a/dependencies/angelscript/source/as_callfunc_x64_msvc_asm.asm b/dependencies/angelscript/source/as_callfunc_x64_msvc_asm.asm deleted file mode 100644 index 80c53ed8..00000000 --- a/dependencies/angelscript/source/as_callfunc_x64_msvc_asm.asm +++ /dev/null @@ -1,208 +0,0 @@ -; -; AngelCode Scripting Library -; Copyright (c) 2003-2011 Andreas Jonsson -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any -; purpose, including commercial applications, and to alter it and -; redistribute it freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you -; must not claim that you wrote the original software. If you use -; this software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; -; 2. Altered source versions must be plainly marked as such, and -; must not be misrepresented as being the original software. -; -; 3. This notice may not be removed or altered from any source -; distribution. -; -; The original version of this library can be located at: -; http://www.angelcode.com/angelscript/ -; -; Andreas Jonsson -; andreas@angelcode.com -; - -.code -PUBLIC CallX64 - -; asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, int paramSize, asQWORD func) - -CallX64 PROC FRAME - - ; PROLOG - - ; We must save preserved registers that are used - ; TODO: No need to save unused registers - - push rbp -.pushreg rbp - push rsi -.pushreg rsi - push r11 -.pushreg r11 - push rdi -.pushreg rdi - push r12 -.pushreg r12 - push r13 -.pushreg r13 - push r14 -.pushreg r14 - push r15 -.pushreg r15 - push rbx -.pushreg rbx - sub rsp, 050h -.allocstack 050h - mov rbp, rsp -.setframe rbp, 0 -.endprolog - - ; Move function param to non-scratch register - mov r14, r9 ; r14 = function - - ; Allocate space on the stack for the arguments - ; Make room for at least 4 arguments even if there are less. When - ; the compiler does optimizations for speed it may use these for - ; temporary storage. - mov rdi, r8 - add rdi, 32 - - ; Make sure the stack pointer is 16byte aligned so the - ; whole program optimizations will work properly - ; TODO: optimize: Can this be optimized with fewer instructions? - mov rsi, rsp - sub rsi, rdi - and rsi, 8h - add rdi, rsi - sub rsp, rdi - - ; Jump straight to calling the function if no parameters - cmp r8d, 0 ; Compare paramSize with 0 - je callfunc ; Jump to call funtion if (paramSize == 0) - - ; Move params to non-scratch registers - mov rsi, rcx ; rsi = pArgs - mov r11, rdx ; r11 = pFloatArgs (can be NULL) - mov r12d, r8d ; r12 = paramSize - - ; Copy arguments from script stack to application stack - ; Order is (first to last): - ; rcx, rdx, r8, r9 & everything else goes on stack - mov rcx, qword ptr [rsi] - mov rdx, qword ptr [rsi + 8] - mov r8, qword ptr [rsi + 16] - mov r9, qword ptr [rsi + 24] - - ; Negate the 4 params from the size to be copied - sub r12d, 32 - js copyfloat ; Jump if negative result - jz copyfloat ; Jump if zero result - - ; Now copy all remaining params onto stack allowing space for first four - ; params to be flushed back to the stack if required by the callee. - - add rsi, 32 ; Position input pointer 4 args ahead - mov r13, rsp ; Put the stack pointer into r13 - add r13, 32 ; Leave space for first 4 args on stack - -copyoverflow: - mov r15, qword ptr [rsi] ; Read param from source stack into r15 - mov qword ptr [r13], r15 ; Copy param to real stack - add r13, 8 ; Move virtual stack pointer - add rsi, 8 ; Move source stack pointer - sub r12d, 8 ; Decrement remaining count - jnz copyoverflow ; Continue if more params - -copyfloat: - ; Any floating point params? - cmp r11, 0 - je callfunc - - movlpd xmm0, qword ptr [r11] - movlpd xmm1, qword ptr [r11 + 8] - movlpd xmm2, qword ptr [r11 + 16] - movlpd xmm3, qword ptr [r11 + 24] - -callfunc: - - ; Call function - call r14 - - ; Restore the stack - mov rsp, rbp - - ; EPILOG: Restore stack & preserved registers - add rsp, 050h - pop rbx - pop r15 - pop r14 - pop r13 - pop r12 - pop rdi - pop r11 - pop rsi - pop rbp - - ; return value in RAX - ret - -CallX64 ENDP - - -PUBLIC GetReturnedFloat - -; asDWORD GetReturnedFloat() - -GetReturnedFloat PROC FRAME - - ; PROLOG: Store registers and allocate stack space - - sub rsp, 8 ; We'll need 4 bytes for temporary storage (8 bytes with alignment) -.allocstack 8 -.endprolog - - ; Move the float value from the XMM0 register to RAX register - movss dword ptr [rsp], xmm0 - mov eax, dword ptr [rsp] - - ; EPILOG: Clean up - - add rsp, 8 - - ret - -GetReturnedFloat ENDP - - -PUBLIC GetReturnedDouble - -; asDWORD GetReturnedDouble() - -GetReturnedDouble PROC FRAME - - ; PROLOG: Store registers and allocate stack space - - sub rsp, 8 ; We'll need 8 bytes for temporary storage -.allocstack 8 -.endprolog - - ; Move the double value from the XMM0 register to the RAX register - movlpd qword ptr [rsp], xmm0 - mov rax, qword ptr [rsp] - - ; EPILOG: Clean up - - add rsp, 8 - - ret - -GetReturnedDouble ENDP - -END \ No newline at end of file diff --git a/dependencies/angelscript/source/as_callfunc_x86.cpp b/dependencies/angelscript/source/as_callfunc_x86.cpp deleted file mode 100644 index 57c6723a..00000000 --- a/dependencies/angelscript/source/as_callfunc_x86.cpp +++ /dev/null @@ -1,1376 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc_x86.cpp -// -// These functions handle the actual calling of system functions -// -// Added support for functor methods by Jordi Oliveras Rovira in April, 2014. -// - - - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#ifdef AS_X86 - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_tokendef.h" -#include "as_context.h" - -BEGIN_AS_NAMESPACE - -// -// With some compile level optimizations the functions don't clear the FPU -// stack themselves. So we have to do it as part of calling the native functions, -// as the compiler will not be able to predict when it is supposed to do it by -// itself due to the dynamic nature of scripts -// -// - fninit clears the FPU stack and the FPU control word -// - emms only clears the FPU stack, while preserving the FPU control word -// -// By default I use fninit as it seems to be what works for most people, -// but some may find it necessary to define this as emms instead. -// -// TODO: Figure out when one or the other must be used, and a way to -// configure this automatically in as_config.h -// -#ifndef CLEAR_FPU_STACK -#define CLEAR_FPU_STACK fninit -#endif - -// These macros are just to allow me to use the above macro in the GNUC style inline assembly -#define _S(x) _TOSTRING(x) -#define _TOSTRING(x) #x - -// Prototypes -asQWORD CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func); -asQWORD CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func); -asQWORD CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func); -asQWORD CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr); -asQWORD CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr); -asQWORD CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr); -asQWORD CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func); -asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func); -asQWORD CallThisCallFunctionRetByRef(const void *, const asDWORD *, int, asFUNCTION_t, void *retPtr); - -asDWORD GetReturnedFloat(); -asQWORD GetReturnedDouble(); - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - - asQWORD retQW = 0; - - // Prepare the parameters - asDWORD paramBuffer[64]; - int callConv = sysFunc->callConv; - -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - int paramSize = sysFunc->paramSize; - if( sysFunc->takesObjByVal ) - { - paramSize = 0; - int spos = 0; - int dpos = 1; -#else - // Unpack the two object pointers - void **objectsPtrs = (void**)obj; - void *secondObject = objectsPtrs[1]; - obj = objectsPtrs[0]; - - // Changed because need check for ICC_THISCALL_OBJFIRST or - // ICC_THISCALL_OBJLAST if sysFunc->takesObjByVal (avoid copy code) - // Check if is THISCALL_OBJ* calling convention (in this case needs to add secondObject pointer into stack). - bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; - int paramSize = isThisCallMethod || sysFunc->takesObjByVal ? 0 : sysFunc->paramSize; - - int dpos = 1; - - if( isThisCallMethod && - (callConv >= ICC_THISCALL_OBJFIRST && - callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) - { - // Add the object pointer as the first parameter - paramBuffer[dpos++] = (asDWORD)secondObject; - paramSize++; - } - - if( sysFunc->takesObjByVal || isThisCallMethod ) - { - int spos = 0; -#endif // AS_NO_THISCALL_FUNCTOR_METHOD - - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - 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 ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else -#endif - { - // Copy the object's memory to the buffer - // TODO: bug: Must call the object's copy constructor instead of doing a memcpy, - // as the object may hold a pointer to itself. It's not enough to - // change only this memcpy as the assembler routine also makes a copy - // of paramBuffer to the final stack location. To avoid the second - // copy the C++ routine should point paramBuffer to the final stack - // position and copy the values directly to that location. The assembler - // routines then don't need to copy anything, and will just be - // responsible for setting up the registers and the stack frame appropriately. - memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); - - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos++; - dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); - paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); - } - } - else - { - // Copy the value directly - paramBuffer[dpos++] = args[spos++]; - if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) - paramBuffer[dpos++] = args[spos++]; - paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - } - // Keep a free location at the beginning - args = ¶mBuffer[1]; - } - -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - if( isThisCallMethod && - (callConv >= ICC_THISCALL_OBJLAST && - callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) ) - { - // Add the object pointer as the last parameter - paramBuffer[dpos++] = (asDWORD)secondObject; - paramSize++; - } -#endif // AS_NO_THISCALL_FUNCTOR_METHOD - - // Make the actual call - asFUNCTION_t func = sysFunc->func; - if( sysFunc->hostReturnInMemory ) - callConv++; - - switch( callConv ) - { - case ICC_CDECL: - retQW = CallCDeclFunction(args, paramSize<<2, func); - break; - - case ICC_CDECL_RETURNINMEM: - retQW = CallCDeclFunctionRetByRef(args, paramSize<<2, func, retPointer); - break; - - case ICC_STDCALL: - retQW = CallSTDCallFunction(args, paramSize<<2, func); - break; - - case ICC_STDCALL_RETURNINMEM: - // Push the return pointer on the stack - paramSize++; - args--; - *(asPWORD*)args = (size_t)retPointer; - - retQW = CallSTDCallFunction(args, paramSize<<2, func); - break; - - case ICC_THISCALL: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJFIRST: - case ICC_THISCALL_OBJLAST: -#endif - retQW = CallThisCallFunction(obj, args, paramSize<<2, func); - break; - - case ICC_THISCALL_RETURNINMEM: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_THISCALL_OBJLAST_RETURNINMEM: -#endif - retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, func, retPointer); - break; - - case ICC_VIRTUAL_THISCALL: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_VIRTUAL_THISCALL_OBJFIRST: - case ICC_VIRTUAL_THISCALL_OBJLAST: -#endif - { - // Get virtual function table from the object pointer - asFUNCTION_t *vftable = *(asFUNCTION_t**)obj; - retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2]); - } - break; - - case ICC_VIRTUAL_THISCALL_RETURNINMEM: -#ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: -#endif - { - // Get virtual function table from the object pointer - asFUNCTION_t *vftable = *(asFUNCTION_t**)obj; - retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], retPointer); - } - break; - - case ICC_CDECL_OBJLAST: - retQW = CallCDeclFunctionObjLast(obj, args, paramSize<<2, func); - break; - - case ICC_CDECL_OBJLAST_RETURNINMEM: - // Call the system object method as a cdecl with the obj ref as the last parameter - retQW = CallCDeclFunctionRetByRefObjLast(obj, args, paramSize<<2, func, retPointer); - break; - - case ICC_CDECL_OBJFIRST: - // Call the system object method as a cdecl with the obj ref as the first parameter - retQW = CallCDeclFunctionObjFirst(obj, args, paramSize<<2, func); - break; - - case ICC_CDECL_OBJFIRST_RETURNINMEM: - // Call the system object method as a cdecl with the obj ref as the first parameter - retQW = CallCDeclFunctionRetByRefObjFirst(obj, args, paramSize<<2, func, retPointer); - break; - - default: - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - } - - // If the return is a float value we need to get the value from the FP register - if( sysFunc->hostReturnFloat ) - { - if( sysFunc->hostReturnSize == 1 ) - *(asDWORD*)&retQW = GetReturnedFloat(); - else - retQW = GetReturnedDouble(); - } - - return retQW; -} - -// On GCC we need to prevent the compiler from inlining these assembler routines when -// optimizing for speed (-O3), as the loop labels get duplicated which cause compile errors. - -#ifdef __GNUC__ - #define NOINLINE __attribute ((__noinline__)) -#else - #define NOINLINE -#endif - - -asQWORD NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - - // Call function - call [func] - - // Pop arguments from stack - add esp, paramSize - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - } - -#elif defined ASM_AT_N_T - - // It is not possible to rely on ESP or BSP to refer to variables or arguments on the stack - // depending on compiler settings BSP may not even be used, and the ESP is not always on the - // same offset from the local variables. Because the code adjusts the ESP register it is not - // possible to inform the arguments through symbolic names below. - - // It's not also not possible to rely on the memory layout of the function arguments, because - // on some compiler versions and settings the arguments may be copied to local variables with a - // different ordering before they are accessed by the rest of the code. - - // I'm copying the arguments into this array where I know the exact memory layout. The address - // of this array will then be passed to the inline asm in the EDX register. - volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - - asm __volatile__( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 4(%%ebx), %%eax \n" // paramSize - "addl $4, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - // Copy all arguments to the stack and call the function - "movl 4(%%ebx), %%ecx \n" // paramSize - "movl 0(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push arguments on the stack - "cmp $0, %%ecx \n" - "je endcopy \n" - "copyloop: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop \n" - "endcopy: \n" - "call *8(%%ebx) \n" - "addl 4(%%ebx), %%esp \n" // pop arguments - - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); - -#endif - - return retQW; -} - -asQWORD NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - // Push the object pointer as the last argument to the function - push obj - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - - // Call function - call [func] - - // Pop arguments from stack - add esp, paramSize - add esp, 4 - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - } - -#elif defined ASM_AT_N_T - - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - - asm __volatile__ ( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 8(%%ebx), %%eax \n" // paramSize - "addl $8, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - "pushl 0(%%ebx) \n" // obj - "movl 8(%%ebx), %%ecx \n" // paramSize - "movl 4(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push arguments on the stack - "cmp $0, %%ecx \n" - "je endcopy8 \n" - "copyloop8: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop8 \n" - "endcopy8: \n" - "call *12(%%ebx) \n" - "addl 8(%%ebx), %%esp \n" // pop arguments - "addl $4, %%esp \n" // pop obj - - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); - -#endif - - return retQW; -} - -asQWORD NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - - // push object as first parameter - push obj - - // Call function - call [func] - - // Pop arguments from stack - add esp, paramSize - add esp, 4 - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - } - -#elif defined ASM_AT_N_T - - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - - asm __volatile__ ( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 8(%%ebx), %%eax \n" // paramSize - "addl $8, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - "movl 8(%%ebx), %%ecx \n" // paramSize - "movl 4(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push arguments on the stack - "cmp $0, %%ecx \n" - "je endcopy6 \n" - "copyloop6: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop6 \n" - "endcopy6: \n" - "pushl 0(%%ebx) \n" // push obj - "call *12(%%ebx) \n" - "addl 8(%%ebx), %%esp \n" // pop arguments - "addl $4, %%esp \n" // pop obj - - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); - -#endif - - return retQW; -} - -asQWORD NOINLINE CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - - // Push the object pointer - push obj - - // Push the return pointer - push retPtr; - - // Call function - call [func] - - // Pop arguments from stack - add esp, paramSize - -#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - // Pop the return pointer - add esp, 8 -#else - add esp, 4 -#endif - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - } - -#elif defined ASM_AT_N_T - - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; - - asm __volatile__ ( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 8(%%ebx), %%eax \n" // paramSize - "addl $12, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - "movl 8(%%ebx), %%ecx \n" // paramSize - "movl 4(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push arguments on the stack - "cmp $0, %%ecx \n" - "je endcopy5 \n" - "copyloop5: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop5 \n" - "endcopy5: \n" - "pushl 0(%%ebx) \n" // push object first - "pushl 16(%%ebx) \n" // retPtr - "call *12(%%ebx) \n" // func - "addl 8(%%ebx), %%esp \n" // pop arguments -#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - "addl $8, %%esp \n" // Pop the return pointer and object pointer -#else - "addl $4, %%esp \n" // Pop the object pointer -#endif - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); -#endif - - return retQW; -} - -asQWORD NOINLINE CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - - // Push the return pointer - push retPtr; - - // Call function - call [func] - - // Pop arguments from stack - add esp, paramSize - -#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - // Pop the return pointer - add esp, 4 -#endif - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - - // return value in EAX or EAX:EDX - } - -#elif defined ASM_AT_N_T - - volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; - - asm __volatile__ ( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 4(%%ebx), %%eax \n" // paramSize - "addl $8, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - "movl 4(%%ebx), %%ecx \n" // paramSize - "movl 0(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push arguments on the stack - "cmp $0, %%ecx \n" - "je endcopy7 \n" - "copyloop7: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop7 \n" - "endcopy7: \n" - "pushl 12(%%ebx) \n" // retPtr - "call *8(%%ebx) \n" // func - "addl 4(%%ebx), %%esp \n" // pop arguments -#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - "addl $4, %%esp \n" // Pop the return pointer -#endif - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); - -#endif - - return retQW; -} - -asQWORD NOINLINE CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - push obj - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - - // Push the return pointer - push retPtr; - - // Call function - call [func] - - // Pop arguments from stack - add esp, paramSize - add esp, 4 - -#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - // Pop the return pointer - add esp, 4 -#endif - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - } - -#elif defined ASM_AT_N_T - - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; - - asm __volatile__ ( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 8(%%ebx), %%eax \n" // paramSize - "addl $12, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - "pushl 0(%%ebx) \n" // obj - "movl 8(%%ebx), %%ecx \n" // paramSize - "movl 4(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push arguments on the stack - "cmp $0, %%ecx \n" - "je endcopy4 \n" - "copyloop4: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop4 \n" - "endcopy4: \n" - "pushl 16(%%ebx) \n" // retPtr - "call *12(%%ebx) \n" // func - "addl 8(%%ebx), %%esp \n" // pop arguments -#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - "addl $8, %%esp \n" // Pop the return pointer and object pointer -#else - "addl $4, %%esp \n" // Pop the object pointer -#endif - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); - -#endif - - return retQW; -} - -asQWORD NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - - // Call function - call [func] - - // The callee already removed parameters from the stack - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - } - -#elif defined ASM_AT_N_T - - volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - - asm __volatile__ ( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 4(%%ebx), %%eax \n" // paramSize - "addl $4, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - "movl 4(%%ebx), %%ecx \n" // paramSize - "movl 0(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push arguments on the stack - "cmp $0, %%ecx \n" - "je endcopy2 \n" - "copyloop2: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop2 \n" - "endcopy2: \n" - "call *8(%%ebx) \n" // callee pops the arguments - - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); - -#endif - - return retQW; -} - - -asQWORD NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - -#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - // Push the object pointer on the stack - push obj -#else - // Move object pointer to ECX - mov ecx, obj -#endif - - // Call function - call [func] - -#ifndef THISCALL_CALLEE_POPS_ARGUMENTS - // Pop arguments - add esp, paramSize -#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - // Pop object pointer - add esp, 4 -#endif -#endif - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - } - -#elif defined ASM_AT_N_T - - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - - asm __volatile__ ( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 8(%%ebx), %%eax \n" // paramSize - "addl $8, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - "movl 8(%%ebx), %%ecx \n" // paramSize - "movl 4(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push all arguments on the stack - "cmp $0, %%ecx \n" - "je endcopy1 \n" - "copyloop1: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop1 \n" - "endcopy1: \n" - "movl 0(%%ebx), %%ecx \n" // move obj into ECX -#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - "pushl %%ecx \n" // push obj on the stack -#endif - "call *12(%%ebx) \n" -#ifndef THISCALL_CALLEE_POPS_ARGUMENTS - "addl 8(%%ebx), %%esp \n" // pop arguments -#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - "addl $4, %%esp \n" // pop obj -#endif -#endif - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); - -#endif - - return retQW; -} - -asQWORD NOINLINE CallThisCallFunctionRetByRef(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) -{ - volatile asQWORD retQW = 0; - -#if defined ASM_INTEL - - // Copy the data to the real stack. If we fail to do - // this we may run into trouble in case of exceptions. - __asm - { - // We must save registers that are used - push ecx - - // Clear the FPU stack, in case the called function doesn't do it by itself - CLEAR_FPU_STACK - - // Copy arguments from script - // stack to application stack - mov ecx, paramSize - mov eax, args - add eax, ecx - cmp ecx, 0 - je endcopy -copyloop: - sub eax, 4 - push dword ptr [eax] - sub ecx, 4 - jne copyloop -endcopy: - -#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - // Push the object pointer on the stack - push obj -#else - // Move object pointer to ECX - mov ecx, obj -#endif - - // Push the return pointer - push retPtr - - // Call function - call [func] - -#ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER - // Pop the return pointer - add esp, 4 -#endif - -#ifndef THISCALL_CALLEE_POPS_ARGUMENTS - // Pop arguments - add esp, paramSize -#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - // Pop object pointer - add esp, 4 -#endif -#endif - - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx - - // Restore registers - pop ecx - } - -#elif defined ASM_AT_N_T - - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; - - asm __volatile__ ( - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. - // It is assumed that when entering this function, the stack pointer is already aligned, so we need - // to calculate how much we will put on the stack during this call. - "movl 8(%%ebx), %%eax \n" // paramSize - "addl $12, %%eax \n" // counting esp that we will push on the stack - "movl %%esp, %%ecx \n" - "subl %%eax, %%ecx \n" - "andl $15, %%ecx \n" - "movl %%esp, %%eax \n" - "subl %%ecx, %%esp \n" - "pushl %%eax \n" // Store the original stack pointer - - "movl 8(%%ebx), %%ecx \n" // paramSize - "movl 4(%%ebx), %%eax \n" // args - "addl %%ecx, %%eax \n" // push all arguments to the stack - "cmp $0, %%ecx \n" - "je endcopy3 \n" - "copyloop3: \n" - "subl $4, %%eax \n" - "pushl (%%eax) \n" - "subl $4, %%ecx \n" - "jne copyloop3 \n" - "endcopy3: \n" -#if defined(__MINGW32__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4) - // MinGW made some strange choices with 4.7, and the thiscall calling convention - // when returning an object in memory is completely different from when not returning - // in memory - "pushl 0(%%ebx) \n" // push obj on the stack - "movl 16(%%ebx), %%ecx \n" // move the return pointer into ECX - "call *12(%%ebx) \n" // call the function -#else - "movl 0(%%ebx), %%ecx \n" // move obj into ECX -#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - "pushl %%ecx \n" // push obj on the stack -#endif - "pushl 16(%%ebx) \n" // push retPtr on the stack - "call *12(%%ebx) \n" -#ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER - "addl $4, %%esp \n" // pop return pointer -#endif -#ifndef THISCALL_CALLEE_POPS_ARGUMENTS - "addl 8(%%ebx), %%esp \n" // pop arguments -#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - "addl $4, %%esp \n" // pop the object pointer -#endif -#endif -#endif // MINGW - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" - - // 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" - "movl %%eax, 0(%%ecx) \n" - "movl %%edx, 4(%%ecx) \n" - : // output - : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument - : "%eax", "%ecx" // clobber - ); - -#endif - - return retQW; -} - -asDWORD GetReturnedFloat() -{ - asDWORD f; - -#if defined ASM_INTEL - - // Get the float value from ST0 - __asm fstp dword ptr [f] - -#elif defined ASM_AT_N_T - - asm("fstps %0 \n" : "=m" (f)); - -#endif - - return f; -} - -asQWORD GetReturnedDouble() -{ - asQWORD d; - -#if defined ASM_INTEL - - // Get the double value from ST0 - __asm fstp qword ptr [d] - -#elif defined ASM_AT_N_T - - asm("fstpl %0 \n" : "=m" (d)); - -#endif - - return d; -} - -END_AS_NAMESPACE - -#endif // AS_X86 -#endif // AS_MAX_PORTABILITY - - - - diff --git a/dependencies/angelscript/source/as_callfunc_xenon.cpp b/dependencies/angelscript/source/as_callfunc_xenon.cpp deleted file mode 100644 index 89ac230c..00000000 --- a/dependencies/angelscript/source/as_callfunc_xenon.cpp +++ /dev/null @@ -1,735 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_callfunc_xenon.cpp -// -// These functions handle the actual calling of system functions -// -// This version is Xenon specific -// Modified from as_callfunc_ppc.cpp by Laszlo Perneky February 2007 -// -// Modified by Cyril Tissier March 2010: -// various fixes in 'float' args passing / function return -// properly handling 'double' type -// various fixes in asm ppcFunc -// fix for variable arguments -// - - - -// XBox 360 calling convention -// =========================== -// I've yet to find an official document with the ABI for XBox 360, -// but I'll describe what I've gathered from the code and tests -// performed by the AngelScript community. -// -// Arguments are passed in the following registers: -// r3 - r10 : integer/pointer arguments (each register is 64bit) -// fr1 - fr13 : float/double arguments (each register is 64bit) -// -// Arguments that don't fit in the registers will be pushed on the stack. -// -// When a float or double is passed as argument, its value will be placed -// in the next available float register, but it will also reserve general -// purpose register. -// -// Example: void foo(float a, int b). a will be passed in fr1 and b in r4. -// -// For each argument passed to a function an 8byte slot is reserved on the -// stack, so that the function can offload the value there if needed. The -// first slot is at r1+20, the next at r1+28, etc. -// -// If the function is a class method, the this pointer is passed as hidden -// first argument. If the function returns an object in memory, the address -// for that memory is passed as hidden first argument. -// -// Return value are placed in the following registers: -// r3 : integer/pointer values -// fr1 : float/double values -// -// Rules for registers -// r1 : stack pointer -// r14-r31 : nonvolatile, i.e. their values must be preserved -// fr14-fr31 : nonvolatile, i.e. their values must be preserved -// r0, r2, r13 : dedicated. I'm not sure what it means, but it is probably best not to use them -// -// The stack pointer must always be aligned at 8 bytes. -// -// References: -// https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf -// -// TODO: The code doesn't handle int64 and uint64 parameters -// TODO: The code doesn't handle objects passed by value (unless they are max 4 bytes in size) - - - -#include "as_config.h" - -#ifndef AS_MAX_PORTABILITY -#if defined(AS_XENON) - -#include "as_callfunc.h" -#include "as_scriptengine.h" -#include "as_texts.h" -#include "as_tokendef.h" -#include "as_context.h" - -#include -#include -#include - -BEGIN_AS_NAMESPACE - -#define AS_PPC_MAX_ARGS 32 -#define AS_PPC_THISCALL_REG 1 -#define AS_PPC_RETURNINMEM_REG 1 -#define AS_PPC_ENDOFARGS 1 - -// The array used to send values to the correct places. -// Contains a byte of argTypes to indicate the register type to load, or zero if end of arguments -enum argTypes -{ - ppcENDARG = 0, - ppcINTARG = 1, - ppcFLOATARG = 2, - ppcDOUBLEARG = 3 -}; - -// Loads all data into the correct places and calls the function. -// pArgs is the array of the argument values -// pArgTypes is an array containing a byte indicating the type (enum argTypes) for each argument. -// dwFunc is the address of the function that will be called -asQWORD __declspec( naked ) ppcFunc(const asDWORD* pArgs, asDWORD dwFunc, const asBYTE* pArgTypes) -{ - __asm - { -_ppcFunc: - // Prologue - // Read and stack the link register (return address) - mflr r12 - stw r12,-8(r1) - - // Backup all non-volatile registers we use in this function - std r31,-10h(r1) // stack pointer for pushing arguments - std r27,-18h(r1) // dwFunc - std r26,-20h(r1) // pArgs - std r25,-28h(r1) // pArgTypes - std r24,-30h(r1) // current arg type - std r23,-38h(r1) // counter for used GPRs - std r22,-40h(r1) // counter for used float registers - - // Setup the stack frame to make room for the backup of registers - // and the arguments that will be passed to the application function. - // 512 bytes is enough for about 50 arguments plus backup of 8 - // TODO: Should perhaps make this dynamic based on number of arguments - stwu r1,-200h(r1) - -////////////////////////////////////////////////////////////////////////// -// Initialize local variables -////////////////////////////////////////////////////////////////////////// - - // r31 is our pointer into the stack where the arguments will be place - // The MSVC optimizer seems to rely on nobody copying the r1 register directly - // so we can't just do a simple 'addi r31, r1, 14h' as the optimizer may - // end up moving this instruction to before the update of r1 above. - // Instead we'll read the previous stack pointer from the stack, and then - // subtract to get the correct offset. - lwz r31, 0(r1) - subi r31, r31, 1ECh // prev r1 - 512 + 20 = curr r1 + 20 - - mr r26, r3 // pArgs - mr r27, r4 // dwFunc - mr r25, r5 // pArgTypes - - // Counting of used/assigned GPR's - sub r23, r23, r23 - // Counting of used/assigned Float Registers - sub r22, r22, r22 - - // Begin loading and stacking registers - subi r25, r25, 1 - -////////////////////////////////////////////////////////////////////////// -// Fetch the next argument -////////////////////////////////////////////////////////////////////////// -ppcNextArg: - // Increment rArgTypePtr - addi r25, r25, 1 - // Get data type - lbz r24, 0(r25) - - // r24 holds the data type - cmplwi cr6, r24, 0 - beq cr6, ppcArgsEnd - cmplwi cr6, r24, 1 - beq cr6, ppcArgIsInteger - cmplwi cr6, r24, 2 - beq cr6, ppcArgIsFloat - cmplwi cr6, r24, 3 - beq cr6, ppcArgIsDouble - -////////////////////////////////////////////////////////////////////////// -// Load and stack integer arguments -////////////////////////////////////////////////////////////////////////// -ppcArgIsInteger: - // Get the arg from the stack - lwz r12, 0(r26) - - // r23 holds the integer arg count so far - cmplwi cr6, r23, 0 - beq cr6, ppcLoadIntReg0 - cmplwi cr6, r23, 1 - beq cr6, ppcLoadIntReg1 - cmplwi cr6, r23, 2 - beq cr6, ppcLoadIntReg2 - cmplwi cr6, r23, 3 - beq cr6, ppcLoadIntReg3 - cmplwi cr6, r23, 4 - beq cr6, ppcLoadIntReg4 - cmplwi cr6, r23, 5 - beq cr6, ppcLoadIntReg5 - cmplwi cr6, r23, 6 - beq cr6, ppcLoadIntReg6 - cmplwi cr6, r23, 7 - beq cr6, ppcLoadIntReg7 - - // no more than 8 parameters - b ppcLoadIntRegUpd - - ppcLoadIntReg0: - mr r3, r12 - b ppcLoadIntRegUpd - ppcLoadIntReg1: - mr r4, r12 - b ppcLoadIntRegUpd - ppcLoadIntReg2: - mr r5, r12 - b ppcLoadIntRegUpd - ppcLoadIntReg3: - mr r6, r12 - b ppcLoadIntRegUpd - ppcLoadIntReg4: - mr r7, r12 - b ppcLoadIntRegUpd - ppcLoadIntReg5: - mr r8, r12 - b ppcLoadIntRegUpd - ppcLoadIntReg6: - mr r9, r12 - b ppcLoadIntRegUpd - ppcLoadIntReg7: - mr r10, r12 - b ppcLoadIntRegUpd - - ppcLoadIntRegUpd: - stw r12, 0(r31) // push on the stack - addi r31, r31, 8 // inc stack by 1 reg - - addi r23, r23, 1 // Increment used int register count - addi r26, r26, 4 // Increment pArgs - b ppcNextArg // Call next arg - -////////////////////////////////////////////////////////////////////////// -// Load and stack float arguments -////////////////////////////////////////////////////////////////////////// -ppcArgIsFloat: - // Get the arg from the stack - lfs fr0, 0(r26) - - // r22 holds the float arg count so far - cmplwi cr6, r22, 0 - beq cr6, ppcLoadFloatReg0 - cmplwi cr6, r22, 1 - beq cr6, ppcLoadFloatReg1 - cmplwi cr6, r22, 2 - beq cr6, ppcLoadFloatReg2 - cmplwi cr6, r22, 3 - beq cr6, ppcLoadFloatReg3 - cmplwi cr6, r22, 4 - beq cr6, ppcLoadFloatReg4 - cmplwi cr6, r22, 5 - beq cr6, ppcLoadFloatReg5 - cmplwi cr6, r22, 6 - beq cr6, ppcLoadFloatReg6 - cmplwi cr6, r22, 7 - beq cr6, ppcLoadFloatReg7 - cmplwi cr6, r22, 8 - beq cr6, ppcLoadFloatReg8 - cmplwi cr6, r22, 9 - beq cr6, ppcLoadFloatReg9 - cmplwi cr6, r22, 10 - beq cr6, ppcLoadFloatReg10 - cmplwi cr6, r22, 11 - beq cr6, ppcLoadFloatReg11 - cmplwi cr6, r22, 12 - beq cr6, ppcLoadFloatReg12 - - // no more than 12 parameters - b ppcLoadFloatRegUpd - - ppcLoadFloatReg0: - fmr fr1, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg1: - fmr fr2, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg2: - fmr fr3, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg3: - fmr fr4, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg4: - fmr fr5, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg5: - fmr fr6, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg6: - fmr fr7, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg7: - fmr fr8, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg8: - fmr fr9, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg9: - fmr fr10, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg10: - fmr fr11, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg11: - fmr fr12, fr0 - b ppcLoadFloatRegUpd - ppcLoadFloatReg12: - fmr fr13, fr0 - b ppcLoadFloatRegUpd - - ppcLoadFloatRegUpd: - stfs fr0, 0(r31) // push on the stack - addi r31, r31, 8 // inc stack by 1 reg - - addi r22, r22, 1 // Increment used float register count - addi r23, r23, 1 // Increment used int register count - a float reg eats up a GPR - addi r26, r26, 4 // Increment pArgs - b ppcNextArg // Call next arg - -////////////////////////////////////////////////////////////////////////// -// Load and stack double float arguments -////////////////////////////////////////////////////////////////////////// -ppcArgIsDouble: - // Get the arg from the stack - lfd fr0, 0(r26) - - // r22 holds the float arg count so far - cmplwi cr6, r22, 0 - beq cr6, ppcLoadDoubleReg0 - cmplwi cr6, r22, 1 - beq cr6, ppcLoadDoubleReg1 - cmplwi cr6, r22, 2 - beq cr6, ppcLoadDoubleReg2 - cmplwi cr6, r22, 3 - beq cr6, ppcLoadDoubleReg3 - cmplwi cr6, r22, 4 - beq cr6, ppcLoadDoubleReg4 - cmplwi cr6, r22, 5 - beq cr6, ppcLoadDoubleReg5 - cmplwi cr6, r22, 6 - beq cr6, ppcLoadDoubleReg6 - cmplwi cr6, r22, 7 - beq cr6, ppcLoadDoubleReg7 - cmplwi cr6, r22, 8 - beq cr6, ppcLoadDoubleReg8 - cmplwi cr6, r22, 9 - beq cr6, ppcLoadDoubleReg9 - cmplwi cr6, r22, 10 - beq cr6, ppcLoadDoubleReg10 - cmplwi cr6, r22, 11 - beq cr6, ppcLoadDoubleReg11 - cmplwi cr6, r22, 12 - beq cr6, ppcLoadDoubleReg12 - - // no more than 12 parameters - b ppcLoadDoubleRegUpd - - ppcLoadDoubleReg0: - fmr fr1, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg1: - fmr fr2, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg2: - fmr fr3, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg3: - fmr fr4, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg4: - fmr fr5, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg5: - fmr fr6, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg6: - fmr fr7, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg7: - fmr fr8, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg8: - fmr fr9, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg9: - fmr fr10, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg10: - fmr fr11, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg11: - fmr fr12, fr0 - b ppcLoadDoubleRegUpd - ppcLoadDoubleReg12: - fmr fr13, fr0 - b ppcLoadDoubleRegUpd - - ppcLoadDoubleRegUpd: - stfd fr0, 0(r31) // push on the stack - addi r31, r31, 8 // inc stack by 1 reg - - addi r22, r22, 1 // Increment used float register count - addi r23, r23, 1 // Increment used int register count - addi r26, r26, 8 // Increment pArgs - b ppcNextArg - -////////////////////////////////////////////////////////////////////////// -// Finished -////////////////////////////////////////////////////////////////////////// -ppcArgsEnd: - // Call the function - mtctr r27 - bctrl - - // Epilogue - // Restore callers stack - addi r1, r1, 200h - - // restore all registers we used in this fct - ld r22,-40h(r1) - ld r23,-38h(r1) - ld r24,-30h(r1) - ld r25,-28h(r1) - ld r26,-20h(r1) - ld r27,-18h(r1) - ld r31,-10h(r1) - - // Fetch return link to caller - lwz r12,-8(r1) - mtlr r12 - blr - } -} - -asDWORD GetReturnedFloat() -{ - // This variable must be declared volatile so that the - // compiler optimizations do not remove its initialization - // with the fr1 register due to believing the fr1 register - // isn't initialized. - volatile asDWORD f; - - __asm - { - stfs fr1, f - } - - return f; -} - -asQWORD GetReturnedDouble() -{ - // This variable must be declared volatile so that the - // compiler optimizations do not remove its initialization - // with the fr1 register due to believing the fr1 register - // isn't initialized. - volatile asQWORD f; - - __asm - { - stfd fr1, f - } - - return f; -} - -// returns true if the given parameter is a 'variable argument' -inline bool IsVariableArgument( asCDataType type ) -{ - return (type.GetTokenType() == ttQuestion) ? true : false; -} - -asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/) -{ - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - int callConv = sysFunc->callConv; - asQWORD retQW = 0; - void *func = (void*)sysFunc->func; - asDWORD *vftable; - - // Pack the arguments into an array that ppcFunc() can use to load each CPU register properly - asBYTE ppcArgsType[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG + AS_PPC_ENDOFARGS]; - asDWORD ppcArgs[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG]; - int argsCnt = 0; - - // If the function returns an object in memory, we allocate the memory and put the ptr to the front (will go to r3) - if( sysFunc->hostReturnInMemory ) - { - ppcArgs[argsCnt] = (asDWORD)retPointer; - ppcArgsType[argsCnt] = ppcINTARG; - argsCnt++; - } - - // If we have an object and it's not objectlast, then we put it as the first arg - if ( obj && - callConv != ICC_CDECL_OBJLAST && - callConv != ICC_CDECL_OBJLAST_RETURNINMEM ) - { - ppcArgs[argsCnt] = (asDWORD)obj; - ppcArgsType[argsCnt] = ppcINTARG; - argsCnt++; - } - - // If the function takes any objects by value, they must be copied - // to the stack, shifting the other arguments as necessary. paramBuffer - // will then replace the args pointer that was received from the VM. - // TODO: Is this really how XBox 360 passes objects by value? - asDWORD paramBuffer[AS_PPC_MAX_ARGS]; - if( sysFunc->takesObjByVal ) - { - int paramSize = 0; - int spos = 0; - int dpos = 1; - - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - // Parameter object by value - 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 ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else -#endif - { - // Copy the object's memory to the buffer - memcpy( ¶mBuffer[dpos], *(void**)(args + spos), descr->parameterTypes[n].GetSizeInMemoryBytes() ); - - // Delete the original memory - engine->CallFree(*(char**)(args + spos)); - - spos++; - dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); - paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); - } - } - else - { - // Copy the value directly - paramBuffer[dpos++] = args[spos++]; - if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) - paramBuffer[dpos++] = args[spos++]; - paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); - } - - // If this was a variable argument parameter, then account for the implicit typeId - if( IsVariableArgument( descr->parameterTypes[n] ) ) - { - // the TypeId is just a DWORD - paramBuffer[dpos++] = args[spos++]; - ++paramSize; - } - } - - // Keep a free location at the beginning - args = ¶mBuffer[1]; - - asASSERT( paramSize <= AS_PPC_MAX_ARGS ); - } - - - const asUINT paramCount = (asUINT)descr->parameterTypes.GetLength(); - - asBYTE * pCurArgType = (asBYTE*)&ppcArgsType[argsCnt]; - asBYTE * pCurFixedArgValue = (asBYTE*)&ppcArgs[argsCnt]; - asBYTE * pCurStackArgValue = (asBYTE*)args; - - for( asUINT n = 0; n < paramCount; n++ ) - { - argsCnt++; - - if (descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference()) - { - *pCurArgType++ = ppcFLOATARG; - - *((float*) pCurFixedArgValue) = *((float*) pCurStackArgValue); - - pCurFixedArgValue += 4; - pCurStackArgValue += 4; - } - else if (descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference()) - { - *pCurArgType++ = ppcDOUBLEARG; - - *((double*) pCurFixedArgValue) = *((double*) pCurStackArgValue); - - pCurFixedArgValue += 8; - pCurStackArgValue += 8; - } - else - { - // TODO: How should int64 and uint64 be passed natively? - // Currently the code doesn't handle these types - - // TODO: The code also ignore the fact that large objects - // passed by value has been copied to the stack - // in the above loop. - - *pCurArgType++ = ppcINTARG; - - *((int*) pCurFixedArgValue) = *((int*) pCurStackArgValue); - - if( !descr->parameterTypes[n].IsReference() ) - { - // If the arg is less that 4 bytes, then move the - // bytes to the higher bytes within the dword - asUINT numBytes = descr->parameterTypes[n].GetSizeInMemoryBytes(); - if( numBytes == 1 ) - { - pCurFixedArgValue[3] = pCurFixedArgValue[0]; - pCurFixedArgValue[0] = 0; - } - else if( numBytes == 2 ) - { - *(asWORD*)&pCurFixedArgValue[2] = *(asWORD*)&pCurFixedArgValue[0]; - *(asWORD*)&pCurFixedArgValue[0] = 0; - } - } - - pCurFixedArgValue += 4; - pCurStackArgValue += 4; - - // if it is a variable argument, account for the typeId - // implicitly add another parameter (AFTER the parameter above) for the typeId - if( IsVariableArgument(descr->parameterTypes[n]) ) - { - argsCnt++; - - *pCurArgType++ = ppcINTARG; - - *((int*) pCurFixedArgValue) = *((int*) pCurStackArgValue); - - pCurFixedArgValue += 4; - pCurStackArgValue += 4; - } - } - } - - // Add the arg list end indicator - ppcArgsType[argsCnt] = ppcENDARG; - - switch( callConv ) - { - case ICC_CDECL: - case ICC_CDECL_RETURNINMEM: - case ICC_STDCALL: - case ICC_STDCALL_RETURNINMEM: - case ICC_THISCALL: - case ICC_THISCALL_RETURNINMEM: - case ICC_CDECL_OBJFIRST: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - { - retQW = ppcFunc( ppcArgs, (asDWORD)func, ppcArgsType ); - break; - } - case ICC_VIRTUAL_THISCALL: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - { - // Get virtual function table from the object pointer - vftable = *(asDWORD**)obj; - retQW = ppcFunc( ppcArgs, vftable[asDWORD(func)>>2], ppcArgsType ); - break; - } - case ICC_CDECL_OBJLAST: - case ICC_CDECL_OBJLAST_RETURNINMEM: - { - // Add the object pointer as the last argument - ppcArgsType[argsCnt++] = ppcINTARG; - ppcArgsType[argsCnt] = ppcENDARG; - *((asPWORD*)pCurFixedArgValue) = (asPWORD)obj; - retQW = ppcFunc( ppcArgs, (asDWORD)func, ppcArgsType ); - break; - } - default: - context->SetInternalException( TXT_INVALID_CALLING_CONVENTION ); - } - - // If the return is a float value we need to get the value from the FP register - if( sysFunc->hostReturnFloat ) - { - if( sysFunc->hostReturnSize == 1 ) - *(asDWORD*)&retQW = GetReturnedFloat(); - else - retQW = GetReturnedDouble(); - } - else if( sysFunc->hostReturnSize == 1 ) - { - // Move the bits to the higher value to compensate for the adjustment that the caller does - retQW <<= 32; - } - - return retQW; -} - -END_AS_NAMESPACE - -#endif // AS_XENON -#endif // AS_MAX_PORTABILITY - - - diff --git a/dependencies/angelscript/source/as_compiler.cpp b/dependencies/angelscript/source/as_compiler.cpp deleted file mode 100644 index 9cd2751b..00000000 --- a/dependencies/angelscript/source/as_compiler.cpp +++ /dev/null @@ -1,13851 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_compiler.cpp -// -// The class that does the actual compilation of the functions -// - -#include // fmodf() pow() - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_compiler.h" -#include "as_tokendef.h" -#include "as_tokenizer.h" -#include "as_string_util.h" -#include "as_texts.h" -#include "as_parser.h" -#include "as_debug.h" -#include "as_context.h" // as_powi() - -BEGIN_AS_NAMESPACE - -// -// The calling convention rules for script functions: -// - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used -// - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done -// - The object pointer is always passed as the first argument, position 0 -// - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer -// - - - - - -// TODO: I must correct the interpretation of a references 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. -// Local variables are declared as non-references, but the expression should be a reference to the variable. -// Function parameters of called functions can also be non-references, but in that case it means the -// object will be passed by value (currently on the heap, which will be moved to the application stack). -// -// The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references. -// Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference -// is currently stored, i.e. in variable, in register, on stack, etc. - -asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine) -{ - builder = 0; - script = 0; - - variables = 0; - isProcessingDeferredParams = false; - isCompilingDefaultArg = false; - noCodeOutput = 0; -} - -asCCompiler::~asCCompiler() -{ - while( variables ) - { - asCVariableScope *var = variables; - variables = variables->parent; - - asDELETE(var,asCVariableScope); - } -} - -void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc) -{ - this->builder = builder; - this->engine = builder->engine; - this->script = script; - this->outFunc = outFunc; - - hasCompileErrors = false; - - m_isConstructor = false; - m_isConstructorCalled = false; - m_classDecl = 0; - - nextLabel = 0; - breakLabels.SetLength(0); - continueLabels.SetLength(0); - - byteCode.ClearAll(); -} - -int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl) -{ - Reset(builder, script, outFunc); - - m_classDecl = classDecl; - - // Insert a JitEntry at the start of the function for JIT compilers - byteCode.InstrPTR(asBC_JitEntry, 0); - - // Add a variable scope that might be needed to declare dummy variables - // in case the member initialization refers to undefined symbols. - AddVariableScope(); - - // Initialize the class members that have no explicit expression first. This will allow the - // base class' constructor to access these members without worry they will be uninitialized. - // This can happen if the base class' constructor calls a method that is overridden by the derived class - CompileMemberInitialization(&byteCode, true); - - // If the class is derived from another, then the base class' default constructor must be called - if( outFunc->objectType->derivedFrom ) - { - // 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); - - // Call the base class' default constructor - byteCode.InstrSHORT(asBC_PSF, 0); - byteCode.Instr(asBC_RDSPtr); - byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE); - } - - // Initialize the class members that explicit expressions afterwards. This allow the expressions - // to access the base class members without worry they will be uninitialized - CompileMemberInitialization(&byteCode, false); - byteCode.OptimizeLocally(tempVariableOffsets); - - // If there are compile errors, there is no reason to build the final code - if( hasCompileErrors ) - return -1; - - // Pop the object pointer from the stack - byteCode.Ret(AS_PTR_SIZE); - - // Count total variable size - int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1; - outFunc->scriptData->variableSpace = varSize; - - FinalizeFunction(); - -#ifdef AS_DEBUG - // DEBUG: output byte code - byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), engine, outFunc); -#endif - - return 0; -} - -int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc) -{ - Reset(builder, script, 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); - int constructor = 0; - for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ ) - { - if( dt.GetBehaviour()->factories[n] == outFunc->id ) - { - constructor = dt.GetBehaviour()->constructors[n]; - break; - } - } - - // Allocate the class and instantiate it with the constructor - int varOffset = AllocateVariable(dt, true); - - outFunc->scriptData->variableSpace = AS_PTR_SIZE; - byteCode.InstrSHORT(asBC_PSF, (short)varOffset); - - // Copy all arguments to the top of the stack - // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments - int offset = (int)outFunc->GetSpaceNeededForArguments(); - for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- ) - { - if( !outFunc->parameterTypes[a].IsPrimitive() || - outFunc->parameterTypes[a].IsReference() ) - { - offset -= AS_PTR_SIZE; - byteCode.InstrSHORT(asBC_PshVPtr, short(-offset)); - } - else - { - if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 ) - { - offset -= 2; - byteCode.InstrSHORT(asBC_PshV8, short(-offset)); - } - else - { - offset -= 1; - byteCode.InstrSHORT(asBC_PshV4, short(-offset)); - } - } - } - - int argDwords = (int)outFunc->GetSpaceNeededForArguments(); - byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE); - - // Return a handle to the newly created object - byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset); - - byteCode.Ret(argDwords); - - FinalizeFunction(); - - // Tell the virtual machine not to clean up parameters on exception - outFunc->dontCleanUpOnException = true; - -/* -#ifdef AS_DEBUG - // DEBUG: output byte code - asCString args; - args.Format("%d", outFunc->parameterTypes.GetLength()); - byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine); -#endif -*/ - return 0; -} - -void asCCompiler::FinalizeFunction() -{ - TimeIt("asCCompiler::FinalizeFunction"); - - asASSERT( outFunc->scriptData ); - asUINT n; - - // Finalize the bytecode - byteCode.Finalize(tempVariableOffsets); - - byteCode.ExtractObjectVariableInfo(outFunc); - - // Compile the list of object variables for the exception handler - // 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( variableIsOnHeap[n] ) - { - outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType()); - outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef()); - outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n)); - } - } - } - outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength()); - for( n = 0; n < variableAllocations.GetLength(); n++ ) - { - if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() ) - { - if( !variableIsOnHeap[n] ) - { - outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType()); - outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef()); - outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n)); - } - } - } - - // Copy byte code to the function - asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 ); - outFunc->scriptData->byteCode.SetLength(byteCode.GetSize()); - byteCode.Output(outFunc->scriptData->byteCode.AddressOf()); - outFunc->AddReferences(); - outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace; - outFunc->scriptData->lineNumbers = byteCode.lineNumbers; - - // Extract the script section indexes too if there are any entries that are different from the function's script section - int lastIdx = outFunc->scriptData->scriptSectionIdx; - for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ ) - { - if( byteCode.sectionIdxs[n] != lastIdx ) - { - lastIdx = byteCode.sectionIdxs[n]; - outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]); - outFunc->scriptData->sectionIdxs.PushLast(lastIdx); - } - } -} - -// internal -int asCCompiler::SetupParametersAndReturnVariable(asCArray ¶meterNames, asCScriptNode *func) -{ - int stackPos = 0; - - if( outFunc->objectType ) - stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object - - // Add the first variable scope, which the parameters and - // variables declared in the outermost statement block is - // part of. - AddVariableScope(); - - bool isDestructor = false; - asCDataType returnType; - - // Examine return type - returnType = outFunc->returnType; - - // Check if this is a constructor or destructor - if( returnType.GetTokenType() == ttVoid && outFunc->objectType ) - { - if( outFunc->name[0] == '~' ) - isDestructor = true; - else if( outFunc->objectType->name == outFunc->name ) - m_isConstructor = true; - } - - // Is the return type allowed? - if( returnType != asCDataType::CreatePrimitive(ttVoid, false) && - !returnType.CanBeInstantiated() ) - { - // TODO: Hasn't this been validated by the builder already? - asCString str; - str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf()); - Error(str, func); - } - - // If the return type is a value type returned by value the address of the - // location where the value will be stored is pushed on the stack before - // the arguments - if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() ) - stackPos -= AS_PTR_SIZE; - - asCVariableScope vs(0); - - // Declare parameters - asUINT n; - for( n = 0; n < parameterNames.GetLength(); n++ ) - { - // Get the parameter type - asCDataType &type = outFunc->parameterTypes[n]; - asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE; - - // Is the data type allowed? - // TODO: Hasn't this been validated by the builder already? - if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) || - (!type.IsReference() && !type.CanBeInstantiated()) ) - { - asCString parm = type.Format(); - if( inoutFlag == asTM_INREF ) - parm += "in"; - else if( inoutFlag == asTM_OUTREF ) - parm += "out"; - - asCString str; - str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf()); - Error(str, func); - } - - // If the parameter has a name then declare it as variable - if( parameterNames[n] != "" ) - { - asCString &name = parameterNames[n]; - if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 ) - { - // TODO: It might be an out-of-memory too - Error(TXT_PARAMETER_ALREADY_DECLARED, func); - } - - // Add marker for variable declaration - byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength()); - outFunc->AddVariable(name, type, stackPos); - } - else - vs.DeclareVariable("", type, stackPos, true); - - // Move to next parameter - stackPos -= type.GetSizeOnStackDWords(); - } - - for( n = asUINT(vs.variables.GetLength()); n-- > 0; ) - variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap); - - variables->DeclareVariable("return", returnType, stackPos, true); - - return stackPos; -} - -void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDefaults) -{ - asASSERT( m_classDecl ); - - // Initialize each member in the order they were declared - for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ ) - { - asCObjectProperty *prop = outFunc->objectType->properties[n]; - - // Check if the property has an initialization expression - asCScriptNode *declNode = 0; - asCScriptNode *initNode = 0; - asCScriptCode *initScript = 0; - for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ ) - { - if( m_classDecl->propInits[m].name == prop->name ) - { - declNode = m_classDecl->propInits[m].declNode; - initNode = m_classDecl->propInits[m].initNode; - initScript = m_classDecl->propInits[m].file; - break; - } - } - - // If declNode is null, the property was inherited in which case - // it was already initialized by the base class' constructor - if( declNode ) - { - if( initNode ) - { - if( onlyDefaults ) - continue; - -#ifdef AS_NO_MEMBER_INIT - // Give an error as the initialization in the declaration has been disabled - asCScriptCode *origScript = script; - script = initScript; - Error("Initialization of members in declaration is not supported", initNode); - script = origScript; - - // Clear the initialization node - initNode = 0; - initScript = script; -#else - // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier - asCParser parser(builder); - int r = parser.ParseVarInit(initScript, initNode); - if( r < 0 ) - continue; - - initNode = parser.GetScriptNode(); -#endif - } - else - { - if( !onlyDefaults ) - continue; - } - -#ifdef AS_NO_MEMBER_INIT - // The initialization will be done in the asCScriptObject constructor, so - // 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.GetBehaviour()->factory == 0) || - ((prop->type.GetObjectType()->flags & asOBJ_VALUE) && - prop->type.GetBehaviour()->construct == 0 && - !(prop->type.GetObjectType()->flags & asOBJ_POD))) ) - { - // Class has no default factory/constructor. - asCString str; - // TODO: funcdef: asCDataType should have a GetTypeName() - 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()); - Error(str, declNode); - } -#else - // Temporarily set the script that is being compiled to where the member initialization is declared. - // The script can be different when including mixin classes from a different script section - asCScriptCode *origScript = script; - script = initScript; - - // Add a line instruction with the position of the declaration - LineInstr(byteCode, 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); - - script = origScript; -#endif - } - } -} - -// Entry -int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray ¶meterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl) -{ - TimeIt("asCCompiler::CompileFunction"); - - Reset(builder, script, outFunc); - int buildErrors = builder->numErrors; - - int stackPos = SetupParametersAndReturnVariable(parameterNames, func); - - //-------------------------------------------- - // Compile the statement block - - if( m_isConstructor ) - m_classDecl = classDecl; - - // We need to parse the statement block now - asCScriptNode *blockBegin; - - // If the function signature was implicit, e.g. virtual property - // accessor, then the received node already is the statement block - if( func->nodeType != snStatementBlock ) - blockBegin = func->lastChild; - else - blockBegin = 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 - asCParser parser(builder); - int r = parser.ParseStatementBlock(script, blockBegin); - if( r < 0 ) return -1; - asCScriptNode *block = parser.GetScriptNode(); - - // Reserve a label for the cleanup code - nextLabel++; - - bool hasReturn; - asCByteCode bc(engine); - LineInstr(&bc, blockBegin->tokenPos); - CompileStatementBlock(block, false, &hasReturn, &bc); - LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength); - - // Make sure there is a return in all paths (if not return type is void) - // Don't bother with this check if there are compiler errors, e.g. Unreachable code - if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) ) - { - if( hasReturn == false ) - Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin); - } - - //------------------------------------------------ - // Concatenate the bytecode - - // Insert a JitEntry at the start of the function for JIT compilers - byteCode.InstrPTR(asBC_JitEntry, 0); - - if( outFunc->objectType ) - { - if( m_isConstructor ) - { - if( outFunc->objectType->derivedFrom ) - { - // Call the base class' default constructor unless called manually in the code - if( !m_isConstructorCalled ) - { - if( outFunc->objectType->derivedFrom->beh.construct ) - { - // Initialize members without explicit expression first - CompileMemberInitialization(&byteCode, true); - - // Call base class' constructor - asCByteCode tmpBC(engine); - tmpBC.InstrSHORT(asBC_PSF, 0); - tmpBC.Instr(asBC_RDSPtr); - tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE); - tmpBC.OptimizeLocally(tempVariableOffsets); - byteCode.AddCode(&tmpBC); - - // Add the initialization of the members with explicit expressions - CompileMemberInitialization(&byteCode, false); - } - else - Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin); - } - else - { - // Only initialize members that don't have an explicit expression - // The members that are explicitly initialized will be initialized after the call to base class' constructor - CompileMemberInitialization(&byteCode, true); - } - } - else - { - // Add the initialization of the members - CompileMemberInitialization(&byteCode, true); - CompileMemberInitialization(&byteCode, false); - } - } - } - - // Add the code for the statement block - byteCode.AddCode(&bc); - - // Count total variable size - int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1; - outFunc->scriptData->variableSpace = varSize; - - // Deallocate all local variables - int n; - for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- ) - { - sVariable *v = variables->variables[n]; - if( v->stackOffset > 0 ) - { - // Call variables destructors - if( v->name != "return" && v->name != "return address" ) - CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode); - - DeallocateVariable(v->stackOffset); - } - } - - // This is the label that return statements jump to - // in order to exit the function - byteCode.Label(0); - - // Call destructors for function parameters - for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- ) - { - sVariable *v = variables->variables[n]; - if( v->stackOffset <= 0 ) - { - // Call variable destructors here, for variables not yet destroyed - if( v->name != "return" && v->name != "return address" ) - CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode); - } - - // Do not deallocate parameters - } - - // 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); - - // If there are compile errors, there is no reason to build the final code - if( hasCompileErrors || builder->numErrors != buildErrors ) - return -1; - - // At this point there should be no variables allocated - asASSERT(variableAllocations.GetLength() == freeVariables.GetLength()); - - // Remove the variable scope - RemoveVariableScope(); - - byteCode.Ret(-stackPos); - - FinalizeFunction(); - -#ifdef AS_DEBUG - // DEBUG: output byte code - if( outFunc->objectType ) - byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc); - else - byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc); -#endif - - return 0; -} - -int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest) -{ - if( !type.IsObject() ) - return 0; - - // CallCopyConstructor should not be called for object handles. - asASSERT( !type.IsObjectHandle() ); - - asCArray args; - args.PushLast(arg); - - // The reference parameter must be pushed on the stack - asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() ); - - // 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 ) - { - asSExprContext ctx(engine); - - int func = 0; - asSTypeBehaviour *beh = type.GetBehaviour(); - if( beh ) func = beh->copyfactory; - - if( func > 0 ) - { - if( !isGlobalVar ) - { - // Call factory and store the handle in the given variable - PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset); - - // Pop the reference left by the function call - ctx.bc.Instr(asBC_PopPtr); - } - else - { - // Call factory - PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType()); - - // 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.Instr(asBC_PopPtr); - ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); - } - - bc->AddCode(&ctx.bc); - - return 0; - } - } - else - { - asSTypeBehaviour *beh = type.GetBehaviour(); - int func = beh ? beh->copyconstruct : 0; - if( func > 0 ) - { - // Push the address where the object will be stored on the stack, before the argument - // TODO: When the context is serializable this probably has to be changed, since this - // pointer can remain on the stack while the context is suspended. There is no - // risk the pointer becomes invalid though, there is just no easy way to serialize it. - asCByteCode tmp(engine); - if( isGlobalVar ) - tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); - else if( isObjectOnHeap ) - tmp.InstrSHORT(asBC_PSF, (short)offset); - tmp.AddCode(bc); - bc->AddCode(&tmp); - - // When the object is allocated on the stack the object pointer - // must be pushed on the stack after the arguments - if( !isObjectOnHeap ) - { - asASSERT( !isGlobalVar ); - bc->InstrSHORT(asBC_PSF, (short)offset); - if( derefDest ) - { - // The variable is a reference to the real location, so we need to dereference it - bc->Instr(asBC_RDSPtr); - } - } - - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType()); - - bc->AddCode(&ctx.bc); - - // TODO: value on stack: This probably needs to be done in PerformFunctionCall - // Mark the object as initialized - if( !isObjectOnHeap ) - bc->ObjInfo(offset, asOBJ_INIT); - - - return 0; - } - } - - // Class has no copy constructor/factory. - asCString str; - str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName()); - Error(str, node); - - return -1; -} - -int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest) -{ - if( !type.IsObject() || type.IsObjectHandle() ) - return 0; - - if( type.GetObjectType()->flags & asOBJ_REF ) - { - asSExprContext ctx(engine); - ctx.exprNode = node; - - int func = 0; - asSTypeBehaviour *beh = type.GetBehaviour(); - if( beh ) - { - func = beh->factory; - - // If no trivial default factory is found, look for a factory where all params have default args - if( func == 0 ) - { - for( asUINT n = 0; n < beh->factories.GetLength(); n++ ) - { - asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]]; - if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() && - f->defaultArgs[0] != 0 ) - { - func = beh->factories[n]; - break; - } - } - } - } - - if( func > 0 ) - { - 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()); - - PrepareFunctionCall(func, &ctx.bc, args); - - MoveArgsToStack(func, &ctx.bc, args, false); - } - - if( isVarGlobOrMem == 0 ) - { - // Call factory and store the handle in the given variable - PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset); - - // Pop the reference left by the function call - ctx.bc.Instr(asBC_PopPtr); - } - else - { - // Call factory - PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType()); - - // 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) ) - { - // Only dereference the variable if not a scoped type - ctx.bc.Instr(asBC_RDSPtr); - } - - if( isVarGlobOrMem == 1 ) - { - // Store the returned handle in the global variable - ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); - } - else - { - // 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))); - } - - if( type.GetObjectType()->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 - ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type)); - - // Clear the local variable so the reference isn't released - ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset); - } - else - { - ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType()); - } - ctx.bc.Instr(asBC_PopPtr); - ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); - } - - bc->AddCode(&ctx.bc); - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n],asSExprContext); - } - - return 0; - } - } - else - { - asSExprContext ctx(engine); - ctx.exprNode = node; - - asSTypeBehaviour *beh = type.GetBehaviour(); - - int func = 0; - if( beh ) - { - func = beh->construct; - - // If no trivial default constructor is found, look for a constructor where all params have default args - if( func == 0 ) - { - for( asUINT n = 0; n < beh->constructors.GetLength(); n++ ) - { - asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]]; - if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() && - f->defaultArgs[0] != 0 ) - { - func = beh->constructors[n]; - break; - } - } - } - } - - // Allocate and initialize with the default constructor - if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) ) - { - 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()); - - PrepareFunctionCall(func, &ctx.bc, args); - - MoveArgsToStack(func, &ctx.bc, args, false); - } - - if( !isObjectOnHeap ) - { - if( isVarGlobOrMem == 0 ) - { - // There is nothing to do if there is no function, - // as the memory is already allocated on the stack - if( func ) - { - // Call the constructor as a normal function - bc->InstrSHORT(asBC_PSF, (short)offset); - if( derefDest ) - bc->Instr(asBC_RDSPtr); - - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType()); - bc->AddCode(&ctx.bc); - - // TODO: value on stack: This probably needs to be done in PerformFunctionCall - // Mark the object as initialized - bc->ObjInfo(offset, asOBJ_INIT); - } - } - else if( isVarGlobOrMem == 2 ) - { - // Only POD types can be allocated inline in script classes - asASSERT( type.GetObjectType()->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))); - - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType()); - bc->AddCode(&ctx.bc); - } - } - else - { - asASSERT( false ); - } - } - else - { - if( isVarGlobOrMem == 0 ) - bc->InstrSHORT(asBC_PSF, (short)offset); - else if( isVarGlobOrMem == 1 ) - bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); - else - { - bc->InstrSHORT(asBC_PSF, 0); - bc->Instr(asBC_RDSPtr); - bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false))); - } - - bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE); - } - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n],asSExprContext); - } - - return 0; - } - } - - // 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()); - Error(str, node); - - return -1; -} - -void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc) -{ - if( !type.IsReference() ) - { - // Call destructor for the data type - if( type.IsObject() ) - { - // 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 ) - return; - - if( isObjectOnHeap || type.IsObjectHandle() ) - { - // Free the memory - bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType()); - } - else - { - asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE ); - - if( type.GetBehaviour()->destruct ) - { - // Call the destructor as a regular function - asSExprContext ctx(engine); - ctx.bc.InstrSHORT(asBC_PSF, (short)offset); - PerformFunctionCall(type.GetBehaviour()->destruct, &ctx); - ctx.bc.OptimizeLocally(tempVariableOffsets); - bc->AddCode(&ctx.bc); - } - - // TODO: Value on stack: This probably needs to be done in PerformFunctionCall - // Mark the object as destroyed - bc->ObjInfo(offset, asOBJ_UNINIT); - } - } - } -} - -void asCCompiler::LineInstr(asCByteCode *bc, size_t pos) -{ - int r, c; - script->ConvertPosToRowCol(pos, &r, &c); - bc->Line(r, c, script->idx); -} - -void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc) -{ - *hasReturn = false; - bool isFinished = false; - bool hasUnreachableCode = false; - bool hasReturnBefore = false; - - if( ownVariableScope ) - { - bc->Block(true); - AddVariableScope(); - } - - asCScriptNode *node = block->firstChild; - while( node ) - { -#ifdef AS_DEBUG - // Keep the current line in a variable so it will be easier - // to determine where in a script an assert is occurring. - int currentLine = 0; - script->ConvertPosToRowCol(node->tokenPos, ¤tLine, 0); -#endif - - if( !hasUnreachableCode && (*hasReturn || isFinished) ) - { - // Empty statements don't count - if( node->nodeType != snExpressionStatement || node->firstChild ) - { - hasUnreachableCode = true; - Warning(TXT_UNREACHABLE_CODE, node); - } - - if( *hasReturn ) - hasReturnBefore = true; - } - - if( node->nodeType == snBreak || node->nodeType == snContinue ) - isFinished = true; - - asCByteCode statement(engine); - if( node->nodeType == snDeclaration ) - CompileDeclaration(node, &statement); - else - CompileStatement(node, hasReturn, &statement); - - // Ignore missing returns in unreachable code paths - if( !(*hasReturn) && hasReturnBefore ) - *hasReturn = true; - - LineInstr(bc, node->tokenPos); - bc->AddCode(&statement); - - if( !hasCompileErrors ) - { - asASSERT( tempVariables.GetLength() == 0 ); - asASSERT( reservedVariables.GetLength() == 0 ); - } - - node = node->next; - } - - if( ownVariableScope ) - { - // Deallocate variables in this block, in reverse order - for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- ) - { - sVariable *v = variables->variables[n]; - - // Call variable destructors here, for variables not yet destroyed - // If the block is terminated with a break, continue, or - // return the variables are already destroyed - if( !isFinished && !*hasReturn ) - CallDestructor(v->type, v->stackOffset, v->onHeap, bc); - - // Don't deallocate function parameters - if( v->stackOffset > 0 ) - DeallocateVariable(v->stackOffset); - } - - RemoveVariableScope(); - bc->Block(false); - } -} - -// Entry -int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc) -{ - Reset(builder, script, outFunc); - - // Add a variable scope (even though variables can't be declared) - AddVariableScope(); - - gvar->isPureConstant = false; - - // Parse the initialization nodes - asCParser parser(builder); - if( node ) - { - int r = parser.ParseVarInit(script, node); - if( r < 0 ) - return r; - - node = parser.GetScriptNode(); - } - - asSExprContext compiledCtx(engine); - bool preCompiled = false; - if( gvar->datatype.IsAuto() ) - preCompiled = CompileAutoType(gvar->datatype, compiledCtx, node, gvar->declaredAtNode); - if( gvar->property == 0 ) - { - gvar->property = builder->module->AllocateGlobalProperty(gvar->name.AddressOf(), gvar->datatype, gvar->ns); - gvar->index = gvar->property->id; - } - - // Compile the expression - asSExprContext ctx(engine); - asQWORD constantValue = 0; - if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->declaredAtNode, gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) ) - { - // Should the variable be marked as pure constant? - if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() ) - { - gvar->isPureConstant = true; - gvar->constantValue = constantValue; - } - } - - // Concatenate the bytecode - int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1; - - // 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; - LineInstr(&byteCode, pos); - - // Reserve space for all local variables - outFunc->scriptData->variableSpace = varSize; - - ctx.bc.OptimizeLocally(tempVariableOffsets); - - byteCode.AddCode(&ctx.bc); - - // Deallocate variables in this block, in reverse order - for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n ) - { - sVariable *v = variables->variables[n]; - - // Call variable destructors here, for variables not yet destroyed - CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode); - - DeallocateVariable(v->stackOffset); - } - - if( hasCompileErrors ) return -1; - - // At this point there should be no variables allocated - asASSERT(variableAllocations.GetLength() == freeVariables.GetLength()); - - // Remove the variable scope again - RemoveVariableScope(); - - byteCode.Ret(0); - - FinalizeFunction(); - -#ifdef AS_DEBUG - // DEBUG: output byte code - byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc); -#endif - - return 0; -} - -void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node) -{ - // Don't do anything if this is not a deferred global function - if( !ctx->IsGlobalFunc() ) - return; - - // Determine the namespace - asSNameSpace *ns = 0; - asCString name = ""; - int pos = ctx->methodName.FindLast("::"); - if( pos >= 0 ) - { - asCString nsName = ctx->methodName.SubString(0, pos+2); - - // Cut off the :: - if( nsName.GetLength() > 2 ) - nsName.SetLength(nsName.GetLength()-2); - - ns = DetermineNameSpace(nsName); - name = ctx->methodName.SubString(pos+2); - } - else - { - DetermineNameSpace(""); - name = ctx->methodName; - } - - asCArray funcs; - if( ns ) - builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); - - // CompileVariableAccess should guarantee that at least one function is exists - asASSERT( funcs.GetLength() > 0 ); - - if( funcs.GetLength() > 1 ) - { - asCString str; - str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf()); - Error(str, node); - - // Fall through so the compiler can continue as if only one function was matching - } - - // A shared object may not access global functions unless they too are shared (e.g. registered functions) - if( !builder->GetFunctionDescription(funcs[0])->IsShared() && - outFunc->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration()); - Error(msg, node); - - // Fall through so the compiler can continue anyway - } - - // 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.dataType.MakeHandle(true); - ctx->type.isExplicitHandle = true; - ctx->methodName = ""; -} - -void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination) -{ - asASSERT( dt.GetObjectType() ); - - bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset); - - // Use copy constructor if available. - if( dt.GetObjectType()->beh.copyconstruct ) - { - PrepareForAssignment(&dt, arg, node, true); - int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination); - if( r < 0 && tempVariables.Exists(offset) ) - Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node); - } - else - { - // TODO: 2.28.1: Need to reserve variables, as the default constructor may need - // to allocate temporary variables to compute default args - - // Allocate and construct the temporary object before whatever is already in the bytecode - asCByteCode tmpBC(engine); - int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination); - if( r < 0 ) - { - if( tempVariables.Exists(offset) ) - Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node); - return; - } - - tmpBC.AddCode(bc); - bc->AddCode(&tmpBC); - - // Assign the evaluated expression to the temporary variable - PrepareForAssignment(&dt, arg, node, true); - bc->AddCode(&arg->bc); - - // Call the opAssign method to assign the value to the temporary object - dt.MakeReference(isObjectOnHeap); - asCTypeInfo type; - type.Set(dt); - type.isTemporary = true; - type.stackOffset = (short)offset; - - if( dt.IsObjectHandle() ) - type.isExplicitHandle = true; - - bc->InstrSHORT(asBC_PSF, (short)offset); - if( derefDestination ) - bc->Instr(asBC_RDSPtr); - - r = PerformAssignment(&type, &arg->type, bc, node); - if( r < 0 ) - { - if( tempVariables.Exists(offset) ) - Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node); - return; - } - - // Pop the reference that was pushed on the stack if the result is an object - if( type.dataType.IsObject() ) - bc->Instr(asBC_PopPtr); - - // If the assignment operator returned an object by value it will - // be in a temporary variable which we need to destroy now - if( type.isTemporary && type.stackOffset != (short)offset ) - ReleaseTemporaryVariable(type.stackOffset, bc); - - // Release the original value too in case it is a temporary - ReleaseTemporaryVariable(arg->type, bc); - } -} - -int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy) -{ - asCDataType param = *paramType; - if( paramType->GetTokenType() == ttQuestion ) - { - // The function is expecting a var type. If the argument is a function name, we must now decide which function it is - DetermineSingleFunc(ctx, node); - - // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else - param = ctx->type.dataType; - param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant()); - - // Treat the void expression like a null handle when working with var types - if( ctx->type.IsVoidExpression() ) - param = asCDataType::CreateNullHandle(); - - // 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) ) - { - param.MakeHandle(true); - } - - param.MakeReference(paramType->IsReference()); - param.MakeReadOnly(paramType->IsReadOnly()); - } - else - param = *paramType; - - asCDataType dt = param; - - // Need to protect arguments by reference - if( isFunction && dt.IsReference() ) - { - // Allocate a temporary variable of the same type as the argument - dt.MakeReference(false); - dt.MakeReadOnly(false); - - int offset; - if( refType == 1 ) // &in - { - ProcessPropertyGetAccessor(ctx, node); - - // Add the type id as hidden arg if the parameter is a ? type - if( paramType->GetTokenType() == ttQuestion ) - { - asCByteCode tmpBC(engine); - - // Place the type id on the stack as a hidden parameter - tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param)); - - // Insert the code before the expression code - tmpBC.AddCode(&ctx->bc); - ctx->bc.AddCode(&tmpBC); - } - - if( dt.IsPrimitive() ) - { - // If the reference is const, then it is not necessary to make a copy if the value already is a variable - // Even if the same variable is passed in another argument as non-const then there is no problem - IsVariableInitialized(&ctx->type, node); - - if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx); - ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true); - - if( !(param.IsReadOnly() && ctx->type.isVariable) ) - ConvertToTempVariable(ctx); - - PushVariableOnStack(ctx, true); - ctx->type.dataType.MakeReadOnly(param.IsReadOnly()); - } - else if( ctx->type.dataType.IsNullHandle() ) - { - // Need to initialize a local temporary variable to - // represent the null handle when passed as reference - asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull ); - ctx->bc.Instr(asBC_PopPtr); - - dt.MakeHandle(true); - offset = AllocateVariableNotIn(dt, true, false, ctx); - - // Push the reference to the variable on the stack - ctx->bc.InstrWORD(asBC_PSF, (short)offset); - - ctx->type.SetVariable(dt, offset, true); - } - else - { - IsVariableInitialized(&ctx->type, node); - - if( !isMakingCopy ) - { - // Even though the parameter expects a reference, it is only meant to be - // used as input value and doesn't have to refer to the actual object, so it - // is OK to do an implicit conversion. - ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true); - if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf()); - Error(str, node); - - ctx->type.Set(param); - return -1; - } - - // The compiler must guarantee that the object stays alive during the execution - // of the function, and it must also guarantee that the value isn't modified by - // the function. - - // If the argument is a temporary local variable then it is safe to be passed to - // 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 - // 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() ) - { - // If the object is a reference type, 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. - - // 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); - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType()); - 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 - { - // Allocate and initialize a temporary local object - offset = AllocateVariableNotIn(dt, true, false, ctx); - CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false); - - // Push the object pointer on the stack - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - if( dt.IsObject() && !dt.IsObjectHandle() ) - ctx->bc.Instr(asBC_RDSPtr); - - // Set the resulting type - ctx->type.Set(dt); - ctx->type.isTemporary = true; - ctx->type.stackOffset = short(offset); - if( dt.IsObjectHandle() ) - ctx->type.isExplicitHandle = true; - ctx->type.dataType.MakeReference(false); - if( paramType->IsReadOnly() ) - ctx->type.dataType.MakeReadOnly(true); - } - } - } - else - { - // We must guarantee that the address to the value is on the stack - if( ctx->type.dataType.IsObject() && - !ctx->type.dataType.IsObjectHandle() && - ctx->type.dataType.IsReference() ) - Dereference(ctx, true); - } - } - } - else if( refType == 2 ) // &out - { - // Add the type id as hidden arg if the parameter is a ? type - if( paramType->GetTokenType() == ttQuestion ) - { - asCByteCode tmpBC(engine); - - // Place the type id on the stack as a hidden parameter - tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param)); - - // Insert the code before the expression code - tmpBC.AddCode(&ctx->bc); - ctx->bc.AddCode(&tmpBC); - } - - // Make sure the variable is not used in the expression - offset = AllocateVariableNotIn(dt, true, false, ctx); - - if( dt.IsPrimitive() ) - { - ctx->type.SetVariable(dt, offset, true); - PushVariableOnStack(ctx, true); - } - else - { - // TODO: 2.28.1: 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); - - // Insert the code before the expression code - tmpBC.AddCode(&ctx->bc); - ctx->bc.AddCode(&tmpBC); - - dt.MakeReference(!dt.IsObject() || dt.IsObjectHandle()); - asCTypeInfo type; - type.Set(dt); - type.isTemporary = true; - type.stackOffset = (short)offset; - - ctx->type = type; - - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - if( dt.IsObject() && !dt.IsObjectHandle() ) - ctx->bc.Instr(asBC_RDSPtr); - } - - // After the function returns the temporary variable will - // be assigned to the expression, if it is a valid lvalue - } - else if( refType == asTM_INOUTREF ) - { - ProcessPropertyGetAccessor(ctx, node); - - // Add the type id as hidden arg if the parameter is a ? type - if( paramType->GetTokenType() == ttQuestion ) - { - asCByteCode tmpBC(engine); - - // Place the type id on the stack as a hidden parameter - tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param)); - - // Insert the code before the expression code - tmpBC.AddCode(&ctx->bc); - ctx->bc.AddCode(&tmpBC); - } - - // Literal constants cannot be passed to inout ref arguments - if( !ctx->type.isVariable && ctx->type.isConstant ) - { - // Unless unsafe references are turned on and the reference is const - if( param.IsReadOnly() && engine->ep.allowUnsafeReferences ) - { - // Since the parameter is a const & make a copy. - ConvertToTempVariable(ctx); - ctx->type.dataType.MakeReadOnly(true); - } - else - { - Error(TXT_NOT_VALID_REFERENCE, node); - return -1; - } - } - - // 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() ) - ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false); - - // Only objects that support object handles - // can be guaranteed to be safe. Local variables are - // already safe, so there is no need to add an extra - // references - if( !engine->ep.allowUnsafeReferences && - !ctx->type.isVariable && - ctx->type.dataType.IsObject() && - !ctx->type.dataType.IsObjectHandle() && - ((ctx->type.dataType.GetBehaviour()->addref && - ctx->type.dataType.GetBehaviour()->release) || - (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ) - { - // Store a handle to the object as local variable - asSExprContext tmp(engine); - asCDataType dt = ctx->type.dataType; - dt.MakeHandle(true); - dt.MakeReference(false); - - offset = AllocateVariableNotIn(dt, true, false, ctx); - - // Copy the handle - 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()); - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - - dt.MakeHandle(false); - dt.MakeReference(true); - - // Release previous temporary variable stored in the context (if any) - if( ctx->type.isTemporary ) - ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc); - - ctx->type.SetVariable(dt, offset, true); - } - - // 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() ) - Dereference(ctx, true); - else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() ) - ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); - else if( ctx->type.dataType.IsPrimitive() ) - ctx->bc.Instr(asBC_PshRPtr); - else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() ) - ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false); - } - } - else - { - ProcessPropertyGetAccessor(ctx, node); - - if( dt.IsPrimitive() ) - { - IsVariableInitialized(&ctx->type, node); - - if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx); - - // Implicitly convert primitives to the parameter type - ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV); - - if( ctx->type.isVariable ) - { - PushVariableOnStack(ctx, dt.IsReference()); - } - else if( ctx->type.isConstant ) - { - ConvertToVariable(ctx); - PushVariableOnStack(ctx, dt.IsReference()); - } - } - else - { - IsVariableInitialized(&ctx->type, node); - - // Implicitly convert primitives to the parameter type - ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV); - - // Was the conversion successful? - if( !ctx->type.dataType.IsEqualExceptRef(dt) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf()); - Error(str, node); - - ctx->type.Set(dt); - return -1; - } - - if( dt.IsObjectHandle() ) - ctx->type.isExplicitHandle = true; - - if( dt.IsObject() && !dt.IsNullHandle() ) - { - 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? - - // 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); - - // 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); - } - } - } - } - - // Don't put any pointer on the stack yet - if( param.IsReference() || (param.IsObject() && !param.IsNullHandle()) ) - { - // &inout parameter may leave the reference on the stack already - if( refType != 3 ) - { - asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy ); - - if( ctx->type.isVariable || ctx->type.isTemporary ) - { - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset); - - ProcessDeferredParams(ctx); - } - } - } - - return 0; -} - -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); - - // If the function being called is the opAssign or copy constructor for the same type - // as the argument, then we should avoid making temporary copy of the argument - asASSERT( descr->parameterTypes.GetLength() == args.GetLength() ); - bool makingCopy = false; - if( descr->parameterTypes.GetLength() == 1 && - descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) && - ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) || - (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) ) - makingCopy = true; - - // Add code for arguments - asSExprContext 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 - int l = int(reservedVariables.GetLength()); - for( int m = n-1; m >= 0; m-- ) - args[m]->bc.GetVarsUsed(reservedVariables); - - PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy); - reservedVariables.SetLength(l); - } - - bc->AddCode(&e.bc); -} - -void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset) -{ - asCScriptFunction *descr = builder->GetFunctionDescription(funcId); - - int offset = 0; - if( addOneToOffset ) - offset += AS_PTR_SIZE; - - // The address of where the return value should be stored is push on top of the arguments - if( descr->DoesReturnOnStack() ) - offset += AS_PTR_SIZE; - -#ifdef AS_DEBUG - // If the function being called is the opAssign or copy constructor for the same type - // as the argument, then we should avoid making temporary copy of the argument - bool makingCopy = false; - if( descr->parameterTypes.GetLength() == 1 && - descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) && - ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) || - (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) ) - makingCopy = true; -#endif - - // Move the objects that are sent by value to the stack just before the call - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - if( descr->parameterTypes[n].IsReference() ) - { - if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() ) - { - if( descr->inOutFlags[n] != asTM_INOUTREF ) - { -#ifdef AS_DEBUG - asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy ); -#endif - - if( (args[n]->type.isVariable || args[n]->type.isTemporary) ) - { - if( !IsVariableOnHeap(args[n]->type.stackOffset) ) - // TODO: runtime optimize: Actually the reference can be pushed on the stack directly - // as the value allocated on the stack is guaranteed to be safe - bc->InstrWORD(asBC_GETREF, (asWORD)offset); - else - bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); - } - } - if( args[n]->type.dataType.IsObjectHandle() ) - bc->InstrWORD(asBC_ChkNullS, (asWORD)offset); - } - else if( descr->inOutFlags[n] != asTM_INOUTREF ) - { - if( descr->parameterTypes[n].GetTokenType() == ttQuestion && - args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() ) - { - // Send the object as a reference to the object, - // and not to the variable holding the object - if( !IsVariableOnHeap(args[n]->type.stackOffset) ) - // TODO: runtime optimize: Actually the reference can be pushed on the stack directly - // as the value allocated on the stack is guaranteed to be safe - bc->InstrWORD(asBC_GETREF, (asWORD)offset); - else - bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); - } - else - { - bc->InstrWORD(asBC_GETREF, (asWORD)offset); - } - } - } - else if( descr->parameterTypes[n].IsObject() ) - { - // 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)); - - bc->InstrWORD(asBC_GETOBJ, (asWORD)offset); - - // The temporary variable must not be freed as it will no longer hold an object - DeallocateVariable(args[n]->type.stackOffset); - args[n]->type.isTemporary = false; - } - - offset += descr->parameterTypes[n].GetSizeOnStackDWords(); - } -} - -int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs) -{ - asASSERT(node->nodeType == snArgList); - - // Count arguments - asCScriptNode *arg = node->firstChild; - int argCount = 0; - while( arg ) - { - if( arg->nodeType != snNamedArgument ) - argCount++; - arg = arg->next; - } - - // Prepare the arrays - args.SetLength(argCount); - int n; - for( n = 0; n < argCount; n++ ) - args[n] = 0; - - n = argCount-1; - - // Compile the arguments in reverse order (as they will be pushed on the stack) - bool anyErrors = false, inPositionalArguments = false; - arg = node->lastChild; - while( arg ) - { - asCScriptNode *asgNode = arg, *namedNode = 0; - if( asgNode->nodeType == snNamedArgument ) - { - if( inPositionalArguments ) - { - Error(TXT_POS_ARG_AFTER_NAMED_ARG, node); - return -1; - } - - asgNode = arg->firstChild->next; - namedNode = arg->firstChild; - - asASSERT( namedNode->nodeType == snIdentifier ); - } - else - inPositionalArguments = true; - - asSExprContext expr(engine); - int r = CompileAssignment(asgNode, &expr); - if( r < 0 ) anyErrors = true; - - asSExprContext *ctx = asNEW(asSExprContext)(engine); - if( ctx == 0 ) - { - // Out of memory - return -1; - } - MergeExprBytecodeAndType(ctx, &expr); - - if( inPositionalArguments ) - { - args[n] = ctx; - n--; - } - else - { - asSNamedArgument namedArg; - namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength); - namedArg.ctx = ctx; - - // Error out when multiple arguments with the same name are passed - for( asUINT n = 0; n < namedArgs.GetLength(); ++n ) - { - if( namedArgs[n].name == namedArg.name ) - { - Error(TXT_DUPLICATE_NAMED_ARG, asgNode); - anyErrors = true; - break; - } - } - - namedArgs.PushLast(namedArg); - } - - arg = arg->prev; - } - - return anyErrors ? -1 : 0; -} - -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() ) - return 0; - - // Make sure to use the real function for virtual functions - if( func->funcType == asFUNC_VIRTUAL ) - { - asASSERT( objectType ); - func = objectType->virtualFunctionTable[func->vfTableIdx]; - } - - // Make sure none of the variables used in the previous arguments are reused in the default arguments - bool anyErrors = false; - asCArray varsUsed; - int explicitArgs = (int)args.GetLength(); - - for( int p = 0; p < explicitArgs; p++ ) - args[p]->bc.GetVarsUsed(varsUsed); - - // Make space for all the new arguments - args.SetLength(func->parameterTypes.GetLength()); - for( asUINT c = explicitArgs; c < args.GetLength(); c++ ) - args[c] = 0; - - // Add the named arguments to the argument list in the right position - if( namedArgs ) - { - for( asUINT n = 0; n < namedArgs->GetLength(); ++n ) - { - asSNamedArgument &named = (*namedArgs)[n]; - named.ctx->bc.GetVarsUsed(varsUsed); - - //Find the right spot to put it in - asUINT index = asUINT(-1); - for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j ) - { - if( func->parameterNames[j] == (*namedArgs)[n].name ) - { - index = j; - break; - } - } - - asASSERT( index < args.GetLength() ); - args[index] = named.ctx; - named.ctx = 0; - } - } - - // Compile the arguments in reverse order (as they will be pushed on the stack) - for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- ) - { - if( args[n] != 0 ) continue; - if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; } - - // Parse the default arg string - asCParser parser(builder); - asCScriptCode code; - code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false); - int r = parser.ParseExpression(&code); - if( r < 0 ) - { - asCString msg; - msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration()); - Error(msg, node); - anyErrors = true; - continue; - } - - asCScriptNode *arg = parser.GetScriptNode(); - - // Temporarily set the script code to the default arg expression - asCScriptCode *origScript = script; - script = &code; - - // Don't allow the expression to access local variables - // TODO: namespace: The default arg should see the symbols declared in the same scope as the function that is called - isCompilingDefaultArg = true; - asSExprContext expr(engine); - r = CompileExpression(arg, &expr); - - // Don't allow address of class method - if( expr.methodName != "" ) - { - // TODO: Improve error message - Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg); - r = -1; - } - - // Make sure the expression can be implicitly converted to the parameter type - if( r >= 0 ) - { - asCArray funcs; - funcs.PushLast(func->id); - asCArray matches; - if( MatchArgument(funcs, matches, &expr, n) == 0 ) - { - Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg); - r = -1; - } - } - - isCompilingDefaultArg = false; - - script = origScript; - - if( r < 0 ) - { - asCString msg; - msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration()); - Error(msg, node); - anyErrors = true; - continue; - } - - args[n] = asNEW(asSExprContext)(engine); - if( args[n] == 0 ) - { - // Out of memory - return -1; - } - - MergeExprBytecodeAndType(args[n], &expr); - - // Make sure the default arg expression doesn't end up - // with a variable that is used in a previous expression - if( args[n]->type.isVariable ) - { - int offset = args[n]->type.stackOffset; - if( varsUsed.Exists(offset) ) - { - // Release the current temporary variable - ReleaseTemporaryVariable(args[n]->type, 0); - - asCDataType dt = args[n]->type.dataType; - dt.MakeReference(false); - - // Reserve all variables already used in the expression so none of them will be used - asCArray used; - args[n]->bc.GetVarsUsed(used); - size_t prevReserved = reservedVariables.GetLength(); - reservedVariables.Concatenate(used); - - int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(offset)); - asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) ); - - reservedVariables.SetLength(prevReserved); - - // Replace the variable in the expression - args[n]->bc.ExchangeVar(offset, newOffset); - args[n]->type.stackOffset = (short)newOffset; - args[n]->type.isTemporary = true; - args[n]->type.isVariable = true; - } - } - } - - return anyErrors ? -1 : 0; -} - -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; - asUINT n; - - if( funcs.GetLength() > 0 ) - { - // Check the number of parameters in the found functions - asUINT totalArgs = (asUINT)args.GetLength(); - if( namedArgs != 0 ) - totalArgs += (asUINT)namedArgs->GetLength(); - - for( n = 0; n < funcs.GetLength(); ++n ) - { - asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]); - - if( desc->parameterTypes.GetLength() != totalArgs ) - { - bool noMatch = true; - if( totalArgs < desc->parameterTypes.GetLength() ) - { - // For virtual functions, the default args are defined in the real function of the object - if( desc->funcType == asFUNC_VIRTUAL ) - desc = objectType->virtualFunctionTable[desc->vfTableIdx]; - - // Count the number of default args - asUINT defaultArgs = 0; - for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ ) - if( desc->defaultArgs[d] ) - defaultArgs++; - - if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs ) - noMatch = false; - } - - if( noMatch ) - { - // remove it from the list - if( n == funcs.GetLength()-1 ) - funcs.PopLast(); - else - funcs[n] = funcs.PopLast(); - n--; - } - } - } - - // Match functions with the parameters, and discard those that do not match - asCArray matchingFuncs; - matchingFuncs.SetLengthNoConstruct( funcs.GetLength() ); - for ( n = 0; n < funcs.GetLength(); ++n ) - { - matchingFuncs[n].funcId = funcs[n]; - matchingFuncs[n].cost = 0; - } - - // Match positionally passed arguments - for( n = 0; n < args.GetLength(); ++n ) - { - asCArray tempFuncs; - MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct); - - // Intersect the found functions with the list of matching functions - for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ ) - { - asUINT c; - for( c = 0; c < tempFuncs.GetLength(); c++ ) - { - if( matchingFuncs[f].funcId == tempFuncs[c].funcId ) - { - // Sum argument cost - matchingFuncs[f].cost += tempFuncs[c].cost; - break; - - } // End if match - } - - // Was the function a match? - if( c == tempFuncs.GetLength() ) - { - // No, remove it from the list - if( f == matchingFuncs.GetLength()-1 ) - matchingFuncs.PopLast(); - else - matchingFuncs[f] = matchingFuncs.PopLast(); - f--; - } - } - } - - // Match named arguments - if( namedArgs != 0 ) - { - for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i ) - { - asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId); - if( desc->funcType == asFUNC_VIRTUAL ) - desc = objectType->virtualFunctionTable[desc->vfTableIdx]; - - //Match every named argument to an argument in the function - for( n = 0; n < namedArgs->GetLength(); ++n ) - (*namedArgs)[n].match = asUINT(-1); - - bool matchedAll = true; - for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j ) - { - asUINT match = asUINT(-1); - for( n = 0; n < namedArgs->GetLength(); ++n ) - { - asSNamedArgument &namedArg = (*namedArgs)[n]; - if( desc->parameterNames[j] == namedArg.name ) - { - namedArg.match = j; - match = n; - break; - } - } - - // Check that every position is filled somehow - if( j >= args.GetLength() ) - { - if( match == asUINT(-1) && !desc->defaultArgs[j] ) - { - // No argument was found for this, and there is no - // default, so it doesn't work. - matchedAll = false; - break; - } - } - else - { - if( match != asUINT(-1) ) - { - // Can't name an argument that was already passed - matchedAll = false; - break; - } - } - } - - //Check that every named argument was matched - if( matchedAll ) - { - for( n = 0; n < namedArgs->GetLength(); ++n ) - { - asSNamedArgument &named = (*namedArgs)[n]; - - if( named.match == asUINT(-1) ) - { - matchedAll = false; - break; - } - - // Add to the cost - asUINT cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct); - if( cost == asUINT(-1) ) - { - matchedAll = false; - break; - } - - matchingFuncs[i].cost += cost; - } - } - - if( !matchedAll ) - { - // Remove the function, we didn't match all the arguments. - if( i == matchingFuncs.GetLength()-1 ) - matchingFuncs.PopLast(); - else - matchingFuncs[i] = matchingFuncs.PopLast(); - i--; - } - } - } - - // Select the overload(s) with the lowest overall cost - funcs.SetLength(0); - asUINT bestCost = asUINT(-1); - for( n = 0; n < matchingFuncs.GetLength(); ++n ) - { - cost = matchingFuncs[n].cost; - if( cost < bestCost ) - { - funcs.SetLength(0); - bestCost = cost; - } - if( cost == bestCost ) - funcs.PushLast( matchingFuncs[n].funcId ); - } - - // Cost returned is equivalent to the best cost discovered - cost = bestCost; - } - - if( !isConstMethod ) - FilterConst(funcs); - - if( funcs.GetLength() != 1 && !silent ) - { - // Build a readable string of the function with parameter types - bool attemptsPassingClassMethod = false; - asCString str; - if( scope != "" ) - { - if( scope == "::" ) - str = scope; - else - str = scope + "::"; - } - str += name; - str += "("; - for( n = 0; n < args.GetLength(); n++ ) - { - if( n > 0 ) - str += ", "; - if( args[n]->methodName != "" ) - { - if( args[n]->IsClassMethod() ) - { - attemptsPassingClassMethod = true; - str += args[n]->type.dataType.GetObjectType()->GetName(); - str += "::"; - } - str += args[n]->methodName; - } - else - str += args[n]->type.dataType.Format(); - } - if( namedArgs != 0 ) - { - for( n = 0; n < namedArgs->GetLength(); n++ ) - { - if( n > 0 || args.GetLength() ) - str += ", "; - - asSNamedArgument &named = (*namedArgs)[n]; - str += named.name; - str += "="; - if( named.ctx->methodName != "" ) - str += named.ctx->methodName; - else - str += named.ctx->type.dataType.Format(); - } - } - str += ")"; - - if( isConstMethod ) - str += " const"; - - if( objectType && scope == "" ) - str = objectType->name + "::" + str; - - if( funcs.GetLength() == 0 ) - { - str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf()); - Error(str, node); - - if( attemptsPassingClassMethod ) - { - // Class methods must use delegate objects - Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node); - } - else - { - // Print the list of candidates - if( origFuncs.GetLength() > 0 ) - { - int r = 0, c = 0; - asASSERT( node ); - if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); - builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false); - PrintMatchingFuncs(origFuncs, node, objectType); - } - } - } - else - { - asASSERT( attemptsPassingClassMethod == false ); - - str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf()); - Error(str, node); - - PrintMatchingFuncs(funcs, node, objectType); - } - } - - return cost; -} - -bool asCCompiler::CompileAutoType(asCDataType &type, asSExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode) -{ - if( node && node->nodeType == snAssignment ) - { - int r = CompileAssignment(node, &compiledCtx); - if( r >= 0 ) - { - asCDataType newType = compiledCtx.type.dataType; - bool success = true; - - // Handle const qualifier on auto - if( type.IsReadOnly() ) - newType.MakeReadOnly(true); - else if( newType.IsPrimitive() ) - newType.MakeReadOnly(false); - - // Handle reference/value stuff - newType.MakeReference(false); - 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( newType.MakeHandle(true) < 0 ) - { - Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode); - success = false; - } - } - } - - if(success) - type = newType; - else - type = asCDataType::CreatePrimitive(ttInt, false); - return true; - } - - return false; - } - else - { - Error(TXT_CANNOT_RESOLVE_AUTO, errNode); - type = asCDataType::CreatePrimitive(ttInt, false); - return false; - } -} - -void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc) -{ - // Get the data type - asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace); - - // 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); - bool preCompiled = false; - if( type.IsAuto() ) - preCompiled = CompileAutoType(type, compiledCtx, node->next, node); - - // Is the type allowed? - if( !type.CanBeInstantiated() ) - { - asCString str; - if( type.IsAbstractClass() ) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format().AddressOf()); - else if( type.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format().AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf()); - Error(str, node); - - // Use int instead to avoid further problems - type = asCDataType::CreatePrimitive(ttInt, false); - } - - // A shared object may not declare variables of non-shared types - if( outFunc->IsShared() ) - { - asCObjectType *ot = type.GetObjectType(); - if( ot && !ot->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf()); - Error(msg, decl); - } - } - - // Get the name of the identifier - asCString name(&script->code[node->tokenPos], node->tokenLength); - - // 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 ) - { - asCString str; - str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf()); - Error(str, node); - } - - int offset = AllocateVariable(type, false); - if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 ) - { - // TODO: It might be an out-of-memory too - - asCString str; - str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf()); - Error(str, node); - - // Don't continue after this error, as it will just - // lead to more errors that are likely false - return; - } - else - { - // Warn if this variable hides another variable in a higher scope - if( variables->parent && variables->parent->GetVariable(name.AddressOf()) ) - { - asCString str; - str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf()); - Warning(str, node); - } - } - - // Add marker that the variable has been declared - bc->VarDecl((int)outFunc->scriptData->variables.GetLength()); - outFunc->AddVariable(name, type, offset); - - // Keep the node for the variable decl - asCScriptNode *varNode = node; - - node = node->next; - - if( node == 0 || node->nodeType == snIdentifier ) - { - // Initialize with default constructor - CompileInitialization(0, bc, type, varNode, offset, 0, 0); - } - else - { - // Compile the initialization expression - asQWORD constantValue = 0; - if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) ) - { - // Check if the variable should be marked as pure constant - if( type.IsPrimitive() && type.IsReadOnly() ) - { - sVariable *v = variables->GetVariable(name.AddressOf()); - v->isPureConstant = true; - v->constantValue = constantValue; - } - } - node = node->next; - } - } - - bc->OptimizeLocally(tempVariableOffsets); -} - -// 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 isConstantExpression = false; - if( node && node->nodeType == snArgList ) - { - // Make sure it is an object and not a handle - if( type.GetObjectType() == 0 || type.IsObjectHandle() ) - { - Error(TXT_MUST_BE_OBJECT, node); - } - else - { - // Compile the arguments - asCArray args; - asCArray namedArgs; - if( CompileArgumentList(node, args, namedArgs) >= 0 ) - { - // Find all constructors - asCArray funcs; - asSTypeBehaviour *beh = type.GetBehaviour(); - if( beh ) - { - if( type.GetObjectType()->flags & asOBJ_REF ) - funcs = beh->factories; - else - funcs = beh->constructors; - } - - asCString str = type.Format(); - MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs); - - if( funcs.GetLength() == 1 ) - { - // Add the default values for arguments not explicitly supplied - int r = CompileDefaultAndNamedArgs(node, args, funcs[0], type.GetObjectType(), &namedArgs); - - if( r == asSUCCESS ) - { - asSExprContext ctx(engine); - if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) ) - { - if( isVarGlobOrMem == 0 ) - MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset); - else - { - MakeFunctionCall(&ctx, funcs[0], 0, args, node); - ctx.bc.Instr(asBC_RDSPtr); - if( isVarGlobOrMem == 1 ) - { - // Store the returned handle in the global variable - ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); - } - else - { - // 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.InstrPTR(asBC_REFCPY, type.GetObjectType()); - ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); - } - - // Pop the reference left by the function call - ctx.bc.Instr(asBC_PopPtr); - } - else - { - bool onHeap = false; - - if( isVarGlobOrMem == 0 ) - { - // When the object is allocated on the heap, the address where the - // reference will be stored must be pushed on the stack before the - // arguments. This reference on the stack is safe, even if the script - // is suspended during the evaluation of the arguments. - onHeap = IsVariableOnHeap(offset); - if( onHeap ) - ctx.bc.InstrSHORT(asBC_PSF, (short)offset); - } - else if( isVarGlobOrMem == 1 ) - { - // Push the address of the location where the variable will be stored on the stack. - // This reference is safe, because the addresses of the global variables cannot change. - onHeap = true; - ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); - } - else - { - // Value types may be allocated inline if they are POD types - onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->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))); - } - } - - PrepareFunctionCall(funcs[0], &ctx.bc, args); - MoveArgsToStack(funcs[0], &ctx.bc, args, false); - - // When the object is allocated on the stack, the address to the - // object is pushed on the stack after the arguments as the object pointer - if( !onHeap ) - { - if( isVarGlobOrMem == 2 ) - { - 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))); - } - else - { - ctx.bc.InstrSHORT(asBC_PSF, (short)offset); - } - } - - PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType()); - - if( isVarGlobOrMem == 0 ) - { - // Mark the object in the local variable as initialized - ctx.bc.ObjInfo(offset, asOBJ_INIT); - } - } - bc->AddCode(&ctx.bc); - } - } - } - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n],asSExprContext); - } - for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) - if( namedArgs[n].ctx ) - { - asDELETE(namedArgs[n].ctx,asSExprContext); - } - } - } - else if( node && node->nodeType == snInitList ) - { - asCTypeInfo ti; - ti.Set(type); - ti.isVariable = (isVarGlobOrMem == 0); - ti.isTemporary = false; - ti.stackOffset = (short)offset; - ti.isLValue = true; - - CompileInitList(&ti, node, bc, isVarGlobOrMem); - } - else if( node && node->nodeType == snAssignment ) - { - asSExprContext ctx(engine); - - // TODO: copy: Here we should look for the best matching constructor, instead of - // just the copy constructor. Only if no appropriate constructor is - // available should the assignment operator be used. - - // Compile the expression - asSExprContext newExpr(engine); - asSExprContext* expr; - int r = 0; - - if( preCompiled ) - { - expr = preCompiled; - } - else - { - expr = &newExpr; - r = CompileAssignment(node, expr); - } - - // Call the default constructor here - if( isVarGlobOrMem == 0 ) - CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode); - else if( isVarGlobOrMem == 1 ) - CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem); - else if( isVarGlobOrMem == 2 ) - CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem); - - if( r >= 0 ) - { - if( type.IsPrimitive() ) - { - if( type.IsReadOnly() && expr->type.isConstant ) - { - ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV); - - // Tell caller that the expression is a constant so it can mark the variable as pure constant - isConstantExpression = true; - *constantValue = expr->type.qwordValue; - } - - asSExprContext lctx(engine); - if( isVarGlobOrMem == 0 ) - lctx.type.SetVariable(type, offset, false); - else if( isVarGlobOrMem == 1 ) - { - lctx.type.Set(type); - lctx.type.dataType.MakeReference(true); - - // If it is an enum value, i.e. offset is negative, that is being compiled then - // we skip this as the bytecode won't be used anyway, only the constant value - if( offset >= 0 ) - lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue()); - } - else - { - asASSERT( isVarGlobOrMem == 2 ); - lctx.type.Set(type); - lctx.type.dataType.MakeReference(true); - - // 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.Instr(asBC_PopRPtr); - } - lctx.type.dataType.MakeReadOnly(false); - lctx.type.isLValue = true; - - DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node); - ProcessDeferredParams(&ctx); - } - else - { - // TODO: runtime optimize: Here we should look for the best matching constructor, instead of - // just the copy constructor. Only if no appropriate constructor is - // available should the assignment operator be used. - - asSExprContext lexpr(engine); - lexpr.type.Set(type); - if( isVarGlobOrMem == 0 ) - lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset)); - else if( isVarGlobOrMem == 1 ) - lexpr.type.dataType.MakeReference(true); - else if( isVarGlobOrMem == 2 ) - { - if( !lexpr.type.dataType.IsObject() || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_REF) ) - lexpr.type.dataType.MakeReference(true); - } - - // Allow initialization of constant variables - lexpr.type.dataType.MakeReadOnly(false); - - if( type.IsObjectHandle() ) - lexpr.type.isExplicitHandle = true; - - if( isVarGlobOrMem == 0 ) - { - lexpr.bc.InstrSHORT(asBC_PSF, (short)offset); - lexpr.type.stackOffset = (short)offset; - lexpr.type.isVariable = true; - } - else if( isVarGlobOrMem == 1 ) - { - lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); - } - else - { - 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.type.stackOffset = -1; - } - lexpr.type.isLValue = true; - - - // If left expression resolves into a registered type - // check if the assignment operator is overloaded, and check - // the type of the right hand expression. If none is found - // the default action is a direct copy if it is the same type - // 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)) ) - { - bool useHndlAssign = lexpr.type.dataType.IsHandleToAsHandleType(); - assigned = CompileOverloadedDualOperator(node, &lexpr, expr, &ctx, useHndlAssign); - if( assigned ) - { - // Pop the resulting value - if( !ctx.type.dataType.IsPrimitive() ) - ctx.bc.Instr(asBC_PopPtr); - - // Release the argument - ProcessDeferredParams(&ctx); - - // Release temporary variable that may be allocated by the overloaded operator - ReleaseTemporaryVariable(ctx.type, &ctx.bc); - } - } - - if( !assigned ) - { - PrepareForAssignment(&lexpr.type.dataType, expr, node, false); - - // If the expression is constant and the variable also is constant - // then mark the variable as pure constant. This will allow the compiler - // to optimize expressions with this variable. - if( type.IsReadOnly() && expr->type.isConstant ) - { - isConstantExpression = true; - *constantValue = expr->type.qwordValue; - } - - // Add expression code to bytecode - MergeExprBytecode(&ctx, expr); - - // Add byte code for storing value of expression in variable - ctx.bc.AddCode(&lexpr.bc); - - PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode); - - // Release temporary variables used by expression - ReleaseTemporaryVariable(expr->type, &ctx.bc); - - ctx.bc.Instr(asBC_PopPtr); - - ProcessDeferredParams(&ctx); - } - } - } - - bc->AddCode(&ctx.bc); - } - else - { - asASSERT( node == 0 ); - - // Call the default constructor here, as no explicit initialization is done - if( isVarGlobOrMem == 0 ) - CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode); - else if( isVarGlobOrMem == 1 ) - CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem); - else if( isVarGlobOrMem == 2 ) - { - if( !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF) ) - CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem); - else - CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem); - } - } - - return isConstantExpression; -} - -void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem) -{ - // Check if the type supports initialization lists - if( var->dataType.GetObjectType() == 0 || - var->dataType.GetBehaviour()->listFactory == 0 || - var->dataType.IsObjectHandle() ) - { - asCString str; - str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf()); - Error(str, node); - return; - } - - // Construct the buffer with the elements - - // Find the list factory - int funcId = var->dataType.GetBehaviour()->listFactory; - asASSERT( engine->scriptFunctions[funcId]->listPattern ); - - // TODO: runtime optimize: A future optimization should be to use the stack space directly - // for small buffers so that the dynamic allocation is skipped - - // Create a new special object type for the lists. Both asCRestore and the - // context exception handler will need this to know how to parse the buffer. - asCObjectType *listPatternType = engine->GetListPatternType(funcId); - - // Allocate a temporary variable to hold the pointer to the buffer - int bufferVar = AllocateVariable(asCDataType::CreateObject(listPatternType, false), true); - asUINT bufferSize = 0; - - // Evaluate all elements of the list - asSExprContext 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); - asASSERT( r || patternNode == 0 ); - UNUSED_VAR(r); - - // After all values have been evaluated we know the final size of the buffer - asSExprContext allocExpr(engine); - allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize); - - // Merge the bytecode into the final sequence - bc->AddCode(&allocExpr.bc); - 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); - 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); - - if( var->isVariable ) - { - asASSERT( isVarGlobOrMem == 0 ); - - if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF ) - { - ctx.bc.AddCode(&arg1.bc); - - // Call factory and store the handle in the given variable - PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset); - ctx.bc.Instr(asBC_PopPtr); - } - else - { - // Call the constructor - - // When the object is allocated on the heap, the address where the - // reference will be stored must be pushed on the stack before the - // arguments. This reference on the stack is safe, even if the script - // is suspended during the evaluation of the arguments. - bool onHeap = IsVariableOnHeap(var->stackOffset); - if( onHeap ) - ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset); - - ctx.bc.AddCode(&arg1.bc); - - // When the object is allocated on the stack, the address to the - // object is pushed on the stack after the arguments as the object pointer - if( !onHeap ) - ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset); - - PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType()); - - // Mark the object in the local variable as initialized - ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT); - } - } - else - { - if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF ) - { - ctx.bc.AddCode(&arg1.bc); - - PerformFunctionCall(funcId, &ctx, false, &args); - - ctx.bc.Instr(asBC_RDSPtr); - if( isVarGlobOrMem == 1 ) - { - // Store the returned handle in the global variable - ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue()); - } - else - { - // 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.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType()); - ctx.bc.Instr(asBC_PopPtr); - ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); - } - else - { - bool onHeap = true; - - // Put the address where the object pointer will be placed on the stack - if( isVarGlobOrMem == 1 ) - ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue()); - else - { - onHeap = !var->dataType.IsObject() || var->dataType.IsReference() || (var->dataType.GetObjectType()->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))); - } - } - - // Add the address of the list buffer as the argument - ctx.bc.AddCode(&arg1.bc); - - 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))); - } - - // Call the ALLOC instruction to allocate memory and invoke constructor - PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType()); - } - } - - bc->AddCode(&ctx.bc); - - // Free the temporary buffer. The FREE instruction will make sure to destroy - // each element in the buffer so there is no need to do this manually - bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType); - ReleaseTemporaryVariable(bufferVar, bc); -} - -int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList) -{ - if( patternNode->type == asLPT_START ) - { - if( valueNode == 0 || valueNode->nodeType != snInitList ) - { - Error(TXT_EXPECTED_LIST, valueNode); - return -1; - } - - // Compile all values until asLPT_END - patternNode = patternNode->next; - asCScriptNode *node = valueNode->firstChild; - while( patternNode->type != asLPT_END ) - { - // Check for missing value here, else the error reporting will not have a source position to report the error for - if( node == 0 && patternNode->type == asLPT_TYPE ) - { - Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode); - return -1; - } - - int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, byteCode, elementsInSubList); - if( r < 0 ) return r; - asASSERT( patternNode ); - } - - if( node ) - { - Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode); - return -1; - } - - // Move to the next node - valueNode = valueNode->next; - patternNode = patternNode->next; - } - else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ) - { - // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area - // TODO: list: repeat_prev should make sure the list is the same size as the previous - - asEListPatternNodeType repeatType = patternNode->type; - asCScriptNode *firstValue = valueNode; - - // The following values will be repeated N times - patternNode = patternNode->next; - - // Keep track of the patternNode so it can be reset - asSListPatternNode *nextNode = patternNode; - - // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes - if( bufferSize & 0x3 ) - bufferSize += 4 - (bufferSize & 0x3); - - // The first dword will hold the number of elements in the list - asDWORD currSize = bufferSize; - bufferSize += 4; - asUINT countElements = 0; - - int elementsInSubSubList = -1; - - asSExprContext ctx(engine); - while( valueNode ) - { - patternNode = nextNode; - int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList); - if( r < 0 ) return r; - - countElements++; - } - - if( countElements == 0 ) - { - // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return - patternNode = nextNode; - if( patternNode->type == asLPT_TYPE ) - patternNode = patternNode->next; - else if( patternNode->type == asLPT_START ) - { - int subCount = 1; - do - { - patternNode = patternNode->next; - if( patternNode->type == asLPT_START ) - subCount++; - else if( patternNode->type == asLPT_END ) - subCount--; - } while( subCount > 0 ); - patternNode = patternNode->next; - } - } - - // For repeat_same each repeated sublist must have the same size to form a rectangular array - if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements ) - { - if( countElements < asUINT(elementsInSubList) ) - Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue); - else - Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue); - - return -1; - } - else - { - // Return to caller the amount of elments in this sublist - elementsInSubList = countElements; - } - - // The first dword in the buffer will hold the number of elements - byteCode.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements); - - // Add the values - byteCode.AddCode(&ctx.bc); - } - else if( patternNode->type == asLPT_TYPE ) - { - // Determine the size of the element - asUINT size = 0; - - asCDataType dt = reinterpret_cast(patternNode)->dataType; - - if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList ) - { - asSExprContext lctx(engine); - asSExprContext rctx(engine); - - if( valueNode->nodeType == snAssignment ) - { - // Compile the assignment expression - CompileAssignment(valueNode, &rctx); - - if( dt.GetTokenType() == ttQuestion ) - { - // We now know the type - dt = rctx.type.dataType; - dt.MakeReadOnly(false); - dt.MakeReference(false); - - // 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); - - // Place the type id in the buffer - byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt)); - bufferSize += 4; - } - } - else if( valueNode->nodeType == snInitList ) - { - if( dt.GetTokenType() == ttQuestion ) - { - // Can't use init lists with var type as it is not possible to determine what type should be allocated - asCString str; - str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?"); - Error(str.AddressOf(), valueNode); - rctx.type.SetDummy(); - dt = rctx.type.dataType; - } - else - { - // Allocate a temporary variable that will be initialized with the list - int offset = AllocateVariable(dt, true); - - rctx.type.Set(dt); - rctx.type.isVariable = true; - rctx.type.isTemporary = true; - rctx.type.stackOffset = (short)offset; - - CompileInitList(&rctx.type, valueNode, &rctx.bc, 0); - - // Put the object on the stack - rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset); - - // It is a reference that we place on the stack - rctx.type.dataType.MakeReference(true); - } - } - - // Determine size of the element - if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) ) - size = dt.GetSizeInMemoryBytes(); - else - size = AS_PTR_SIZE*4; - - // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. - if( size >= 4 && (bufferSize & 0x3) ) - bufferSize += 4 - (bufferSize & 0x3); - - // Compile the lvalue - lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); - lctx.type.Set(dt); - lctx.type.isLValue = true; - if( dt.IsPrimitive() ) - { - lctx.bc.Instr(asBC_PopRPtr); - lctx.type.dataType.MakeReference(true); - } - else if( dt.IsObjectHandle() || - dt.GetObjectType()->flags & asOBJ_REF ) - { - lctx.type.isExplicitHandle = true; - lctx.type.dataType.MakeReference(true); - } - else - { - asASSERT( dt.GetObjectType()->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 ) - { - 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()); - Error(str, valueNode); - } - else if( func ) - { - // Call the constructor as a normal function - byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); - - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType()); - byteCode.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. - // 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); - DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); - - if( !lctx.type.dataType.IsPrimitive() ) - ctx.bc.Instr(asBC_PopPtr); - - // Release temporary variables used by expression - ReleaseTemporaryVariable(ctx.type, &ctx.bc); - - ProcessDeferredParams(&ctx); - - byteCode.AddCode(&ctx.bc); - } - } - else - { - // There is no specific value so we need to fill it with a default value - if( dt.GetTokenType() == ttQuestion ) - { - // 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); - - // Place the type id for a null handle in the buffer - byteCode.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 ) - { - // 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 ) - { - 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()); - Error(str, valueNode); - } - else if( func ) - { - // 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); - - // Call the constructor as a normal function - byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); - - asSExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType()); - byteCode.AddCode(&ctx.bc); - } - } - else if( !dt.IsObjectHandle() && dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_REF ) - { - // For ref types (not handles) we need to call the default factory - asSTypeBehaviour *beh = dt.GetBehaviour(); - int func = 0; - if( beh ) func = beh->factory; - 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()); - Error(str, valueNode); - } - else if( func ) - { - asSExprContext rctx(engine); - PerformFunctionCall(func, &rctx, false, 0, dt.GetObjectType()); - - // 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); - 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); - DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); - - if( !lctx.type.dataType.IsPrimitive() ) - ctx.bc.Instr(asBC_PopPtr); - - // Release temporary variables used by expression - ReleaseTemporaryVariable(ctx.type, &ctx.bc); - - ProcessDeferredParams(&ctx); - - byteCode.AddCode(&ctx.bc); - } - } - } - - // Determine size of the element - if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) ) - size = dt.GetSizeInMemoryBytes(); - else - size = AS_PTR_SIZE*4; - asASSERT( size <= 4 || (size & 0x3) == 0 ); - - // Move to the next element - bufferSize += size; - patternNode = patternNode->next; - valueNode = valueNode->next; - } - else - asASSERT( false ); - - return 0; -} - -void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc) -{ - // Don't clear the hasReturn flag if this is an empty statement - // to avoid false errors of 'not all paths return' - if( statement->nodeType != snExpressionStatement || statement->firstChild ) - *hasReturn = false; - - if( statement->nodeType == snStatementBlock ) - CompileStatementBlock(statement, true, hasReturn, bc); - else if( statement->nodeType == snIf ) - CompileIfStatement(statement, hasReturn, bc); - else if( statement->nodeType == snFor ) - CompileForStatement(statement, bc); - else if( statement->nodeType == snWhile ) - CompileWhileStatement(statement, bc); - else if( statement->nodeType == snDoWhile ) - CompileDoWhileStatement(statement, bc); - else if( statement->nodeType == snExpressionStatement ) - CompileExpressionStatement(statement, bc); - else if( statement->nodeType == snBreak ) - CompileBreakStatement(statement, bc); - else if( statement->nodeType == snContinue ) - CompileContinueStatement(statement, bc); - else if( statement->nodeType == snSwitch ) - CompileSwitchStatement(statement, hasReturn, bc); - else if( statement->nodeType == snReturn ) - { - CompileReturnStatement(statement, bc); - *hasReturn = true; - } -} - -void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc) -{ - // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it. - - // Reserve label for break statements - int breakLabel = nextLabel++; - breakLabels.PushLast(breakLabel); - - // Add a variable scope that will be used by CompileBreak - // to know where to stop deallocating variables - AddVariableScope(true, false); - - //--------------------------- - // Compile the switch expression - //------------------------------- - - // Compile the switch expression - asSExprContext expr(engine); - CompileAssignment(snode->firstChild, &expr); - - // Verify that the expression is a primitive type - if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() ) - { - Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild); - return; - } - - ProcessPropertyGetAccessor(&expr, snode); - - // TODO: Need to support 64bit integers - // Convert the expression to a 32bit variable - asCDataType to; - if( expr.type.dataType.IsIntegerType() ) - to.SetTokenType(ttInt); - else if( expr.type.dataType.IsUnsignedType() ) - to.SetTokenType(ttUInt); - - // Make sure the value is in a variable - if( expr.type.dataType.IsReference() ) - ConvertToVariable(&expr); - - ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true); - - ConvertToVariable(&expr); - int offset = expr.type.stackOffset; - - ProcessDeferredParams(&expr); - - //------------------------------- - // Determine case values and labels - //-------------------------------- - - // Remember the first label so that we can later pass the - // correct label to each CompileCase() - int firstCaseLabel = nextLabel; - int defaultLabel = 0; - - asCArray caseValues; - asCArray caseLabels; - - // Compile all case comparisons and make them jump to the right label - asCScriptNode *cnode = snode->firstChild->next; - while( cnode ) - { - // Each case should have a constant expression - if( cnode->firstChild && cnode->firstChild->nodeType == snExpression ) - { - // Compile expression - asSExprContext c(engine); - CompileExpression(cnode->firstChild, &c); - - // Verify that the result is a constant - if( !c.type.isConstant ) - 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() ) - 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 ) - { - 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.intValue); - - // Reserve label for this case - caseLabels.PushLast(nextLabel++); - } - else - { - // TODO: It shouldn't be necessary for the default case to be the last one. - // Is default the last case? - if( cnode->next ) - { - Error(TXT_DEFAULT_MUST_BE_LAST, cnode); - break; - } - - // Reserve label for this case - defaultLabel = nextLabel++; - } - - cnode = cnode->next; - } - - // check for empty switch - if (caseValues.GetLength() == 0) - { - Error(TXT_EMPTY_SWITCH, snode); - return; - } - - if( defaultLabel == 0 ) - defaultLabel = breakLabel; - - //--------------------------------- - // Output the optimized case comparisons - // with jumps to the case code - //------------------------------------ - - // Sort the case values by increasing value. Do the sort together with the labels - // A simple bubble sort is sufficient since we don't expect a huge number of values - for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ ) - { - for( int bck = fwd - 1; bck >= 0; bck-- ) - { - int bckp = bck + 1; - if( caseValues[bck] > caseValues[bckp] ) - { - // Swap the values in both arrays - int swap = caseValues[bckp]; - caseValues[bckp] = caseValues[bck]; - caseValues[bck] = swap; - - swap = caseLabels[bckp]; - caseLabels[bckp] = caseLabels[bck]; - caseLabels[bck] = swap; - } - else - break; - } - } - - // Find ranges of consecutive numbers - asCArray ranges; - ranges.PushLast(0); - asUINT n; - for( n = 1; n < caseValues.GetLength(); ++n ) - { - // We can join numbers that are less than 5 numbers - // apart since the output code will still be smaller - if( caseValues[n] > caseValues[n-1] + 5 ) - ranges.PushLast(n); - } - - // If the value is larger than the largest case value, jump to default - int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); - expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]); - expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); - expr.bc.InstrDWORD(asBC_JP, defaultLabel); - ReleaseTemporaryVariable(tmpOffset, &expr.bc); - - // TODO: runtime optimize: We could possibly optimize this even more by doing a - // binary search instead of a linear search through the ranges - - // For each range - int range; - for( range = 0; range < (int)ranges.GetLength(); range++ ) - { - // Find the largest value in this range - int maxRange = caseValues[ranges[range]]; - int index = ranges[range]; - for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ ) - maxRange = caseValues[index]; - - // If there are only 2 numbers then it is better to compare them directly - if( index - ranges[range] > 2 ) - { - // If the value is smaller than the smallest case value in the range, jump to default - tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); - expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]); - expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); - expr.bc.InstrDWORD(asBC_JS, defaultLabel); - ReleaseTemporaryVariable(tmpOffset, &expr.bc); - - int nextRangeLabel = nextLabel++; - // If this is the last range we don't have to make this test - if( range < (int)ranges.GetLength() - 1 ) - { - // If the value is larger than the largest case value in the range, jump to the next range - tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); - expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange); - expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); - expr.bc.InstrDWORD(asBC_JP, nextRangeLabel); - ReleaseTemporaryVariable(tmpOffset, &expr.bc); - } - - // Jump forward according to the value - tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); - expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]); - expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset); - ReleaseTemporaryVariable(tmpOffset, &expr.bc); - expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]); - - // 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++ ) - { - if( caseValues[index] == n ) - expr.bc.InstrINT(asBC_JMP, caseLabels[index++]); - else - expr.bc.InstrINT(asBC_JMP, defaultLabel); - } - - expr.bc.Label((short)nextRangeLabel); - } - else - { - // Simply make a comparison with each value - int n; - for( n = ranges[range]; n < index; ++n ) - { - tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); - expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]); - expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); - expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]); - ReleaseTemporaryVariable(tmpOffset, &expr.bc); - } - } - } - - // Catch any value that falls trough - expr.bc.InstrINT(asBC_JMP, defaultLabel); - - // Release the temporary variable previously stored - ReleaseTemporaryVariable(expr.type, &expr.bc); - - // TODO: optimize: Should optimize each piece individually - expr.bc.OptimizeLocally(tempVariableOffsets); - - //---------------------------------- - // Output case implementations - //---------------------------------- - - // Compile case implementations, each one with the label before it - cnode = snode->firstChild->next; - while( cnode ) - { - // Each case should have a constant expression - if( cnode->firstChild && cnode->firstChild->nodeType == snExpression ) - { - expr.bc.Label((short)firstCaseLabel++); - - CompileCase(cnode->firstChild->next, &expr.bc); - } - else - { - expr.bc.Label((short)defaultLabel); - - // Is default the last case? - if( cnode->next ) - { - // We've already reported this error - break; - } - - CompileCase(cnode->firstChild, &expr.bc); - } - - cnode = cnode->next; - } - - //-------------------------------- - - bc->AddCode(&expr.bc); - - // Add break label - bc->Label((short)breakLabel); - - breakLabels.PopLast(); - RemoveVariableScope(); -} - -void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc) -{ - bool isFinished = false; - bool hasReturn = false; - bool hasUnreachableCode = false; - while( node ) - { - if( !hasUnreachableCode && (hasReturn || isFinished) ) - { - hasUnreachableCode = true; - Warning(TXT_UNREACHABLE_CODE, node); - break; - } - - if( node->nodeType == snBreak || node->nodeType == snContinue ) - isFinished = true; - - asCByteCode statement(engine); - if( node->nodeType == snDeclaration ) - { - Error(TXT_DECL_IN_SWITCH, node); - - // Compile it anyway to avoid further compiler errors - CompileDeclaration(node, &statement); - } - else - CompileStatement(node, &hasReturn, &statement); - - LineInstr(bc, node->tokenPos); - bc->AddCode(&statement); - - if( !hasCompileErrors ) - asASSERT( tempVariables.GetLength() == 0 ); - - node = node->next; - } -} - -void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc) -{ - // We will use one label for the if statement - // and possibly another for the else statement - int afterLabel = nextLabel++; - - // Compile the expression - asSExprContext expr(engine); - int r = CompileAssignment(inode->firstChild, &expr); - if( r == 0 ) - { - if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild); - else - { - if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr); - ProcessDeferredParams(&expr); - - if( !expr.type.isConstant ) - { - ProcessPropertyGetAccessor(&expr, inode); - - ConvertToVariable(&expr); - - // Add a test - expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); - expr.bc.Instr(asBC_ClrHi); - expr.bc.InstrDWORD(asBC_JZ, afterLabel); - ReleaseTemporaryVariable(expr.type, &expr.bc); - - expr.bc.OptimizeLocally(tempVariableOffsets); - bc->AddCode(&expr.bc); - } - else if( expr.type.dwordValue == 0 ) - { - // Jump to the else case - bc->InstrINT(asBC_JMP, afterLabel); - - // TODO: Should we warn that the expression will always go to the else? - } - } - } - - // Compile the if statement - bool origIsConstructorCalled = m_isConstructorCalled; - - bool hasReturn1; - asCByteCode ifBC(engine); - CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC); - - // Add the byte code - LineInstr(bc, inode->firstChild->next->tokenPos); - bc->AddCode(&ifBC); - - if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 ) - { - // Don't allow if( expr ); - Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next); - } - - // If one of the statements call the constructor, the other must as well - // otherwise it is possible the constructor is never called - bool constructorCall1 = false; - bool constructorCall2 = false; - if( !origIsConstructorCalled && m_isConstructorCalled ) - constructorCall1 = true; - - // Do we have an else statement? - if( inode->firstChild->next != inode->lastChild ) - { - // Reset the constructor called flag so the else statement can call the constructor too - m_isConstructorCalled = origIsConstructorCalled; - - int afterElse = 0; - if( !hasReturn1 ) - { - afterElse = nextLabel++; - - // Add jump to after the else statement - bc->InstrINT(asBC_JMP, afterElse); - } - - // Add label for the else statement - bc->Label((short)afterLabel); - - bool hasReturn2; - asCByteCode elseBC(engine); - CompileStatement(inode->lastChild, &hasReturn2, &elseBC); - - // Add byte code for the else statement - LineInstr(bc, inode->lastChild->tokenPos); - bc->AddCode(&elseBC); - - if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 ) - { - // Don't allow if( expr ) {} else; - Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild); - } - - if( !hasReturn1 ) - { - // Add label for the end of else statement - bc->Label((short)afterElse); - } - - // The if statement only has return if both alternatives have - *hasReturn = hasReturn1 && hasReturn2; - - if( !origIsConstructorCalled && m_isConstructorCalled ) - constructorCall2 = true; - } - else - { - // Add label for the end of if statement - bc->Label((short)afterLabel); - *hasReturn = false; - } - - // Make sure both or neither conditions call a constructor - if( (constructorCall1 && !constructorCall2) || - (constructorCall2 && !constructorCall1) ) - { - Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode); - } - - m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2; -} - -void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc) -{ - // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables - AddVariableScope(true, true); - - // We will use three labels for the for loop - int conditionLabel = nextLabel++; - int afterLabel = nextLabel++; - int continueLabel = nextLabel++; - int insideLabel = nextLabel++; - - continueLabels.PushLast(continueLabel); - breakLabels.PushLast(afterLabel); - - //--------------------------------------- - // Compile the initialization statement - asCByteCode initBC(engine); - LineInstr(&initBC, fnode->firstChild->tokenPos); - if( fnode->firstChild->nodeType == snDeclaration ) - CompileDeclaration(fnode->firstChild, &initBC); - else - CompileExpressionStatement(fnode->firstChild, &initBC); - - //----------------------------------- - // Compile the condition statement - asSExprContext expr(engine); - asCScriptNode *second = fnode->firstChild->next; - if( second->firstChild ) - { - int r = CompileAssignment(second->firstChild, &expr); - if( r >= 0 ) - { - if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - Error(TXT_EXPR_MUST_BE_BOOL, second); - else - { - if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr); - ProcessDeferredParams(&expr); - - ProcessPropertyGetAccessor(&expr, second); - - // If expression is false exit the loop - ConvertToVariable(&expr); - expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); - expr.bc.Instr(asBC_ClrHi); - expr.bc.InstrDWORD(asBC_JNZ, insideLabel); - ReleaseTemporaryVariable(expr.type, &expr.bc); - - expr.bc.OptimizeLocally(tempVariableOffsets); - - // Prepend the line instruction for the condition - asCByteCode tmp(engine); - LineInstr(&tmp, second->firstChild->tokenPos); - tmp.AddCode(&expr.bc); - expr.bc.AddCode(&tmp); - } - } - } - - //--------------------------- - // Compile the increment statement - asCByteCode nextBC(engine); - asCScriptNode *third = second->next; - if( third->nodeType == snExpressionStatement ) - { - LineInstr(&nextBC, third->tokenPos); - CompileExpressionStatement(third, &nextBC); - } - - //------------------------------ - // Compile loop statement - bool hasReturn; - asCByteCode forBC(engine); - CompileStatement(fnode->lastChild, &hasReturn, &forBC); - - //------------------------------- - // Join the code pieces - bc->AddCode(&initBC); - bc->InstrDWORD(asBC_JMP, conditionLabel); - - bc->Label((short)insideLabel); - - // Add a suspend bytecode inside the loop to guarantee - // that the application can suspend the execution - bc->Instr(asBC_SUSPEND); - bc->InstrPTR(asBC_JitEntry, 0); - - LineInstr(bc, fnode->lastChild->tokenPos); - bc->AddCode(&forBC); - - bc->Label((short)continueLabel); - bc->AddCode(&nextBC); - - bc->Label((short)conditionLabel); - if( expr.bc.GetLastInstr() == -1 ) - // There is no condition, so we just always jump - bc->InstrDWORD(asBC_JMP, insideLabel); - else - bc->AddCode(&expr.bc); - - bc->Label((short)afterLabel); - - continueLabels.PopLast(); - breakLabels.PopLast(); - - // Deallocate variables in this block, in reverse order - for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- ) - { - sVariable *v = variables->variables[n]; - - // Call variable destructors here, for variables not yet destroyed - CallDestructor(v->type, v->stackOffset, v->onHeap, bc); - - // Don't deallocate function parameters - if( v->stackOffset > 0 ) - DeallocateVariable(v->stackOffset); - } - - RemoveVariableScope(); -} - -void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc) -{ - // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables - AddVariableScope(true, true); - - // We will use two labels for the while loop - int beforeLabel = nextLabel++; - int afterLabel = nextLabel++; - - continueLabels.PushLast(beforeLabel); - breakLabels.PushLast(afterLabel); - - // Add label before the expression - bc->Label((short)beforeLabel); - - // Compile expression - asSExprContext expr(engine); - int r = CompileAssignment(wnode->firstChild, &expr); - if( r == 0 ) - { - if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild); - else - { - if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr); - ProcessDeferredParams(&expr); - - ProcessPropertyGetAccessor(&expr, wnode); - - // Add byte code for the expression - ConvertToVariable(&expr); - - // Jump to end of statement if expression is false - expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); - expr.bc.Instr(asBC_ClrHi); - expr.bc.InstrDWORD(asBC_JZ, afterLabel); - ReleaseTemporaryVariable(expr.type, &expr.bc); - - expr.bc.OptimizeLocally(tempVariableOffsets); - bc->AddCode(&expr.bc); - } - } - - // Add a suspend bytecode inside the loop to guarantee - // that the application can suspend the execution - bc->Instr(asBC_SUSPEND); - bc->InstrPTR(asBC_JitEntry, 0); - - // Compile statement - bool hasReturn; - asCByteCode whileBC(engine); - CompileStatement(wnode->lastChild, &hasReturn, &whileBC); - - // Add byte code for the statement - LineInstr(bc, wnode->lastChild->tokenPos); - bc->AddCode(&whileBC); - - // Jump to the expression - bc->InstrINT(asBC_JMP, beforeLabel); - - // Add label after the statement - bc->Label((short)afterLabel); - - continueLabels.PopLast(); - breakLabels.PopLast(); - - RemoveVariableScope(); -} - -void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc) -{ - // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables - AddVariableScope(true, true); - - // We will use two labels for the while loop - int beforeLabel = nextLabel++; - int beforeTest = nextLabel++; - int afterLabel = nextLabel++; - - continueLabels.PushLast(beforeTest); - breakLabels.PushLast(afterLabel); - - // Add label before the statement - bc->Label((short)beforeLabel); - - // Compile statement - bool hasReturn; - asCByteCode whileBC(engine); - CompileStatement(wnode->firstChild, &hasReturn, &whileBC); - - // Add byte code for the statement - LineInstr(bc, wnode->firstChild->tokenPos); - bc->AddCode(&whileBC); - - // Add label before the expression - bc->Label((short)beforeTest); - - // Add a suspend bytecode inside the loop to guarantee - // that the application can suspend the execution - bc->Instr(asBC_SUSPEND); - bc->InstrPTR(asBC_JitEntry, 0); - - // Add a line instruction - LineInstr(bc, wnode->lastChild->tokenPos); - - // Compile expression - asSExprContext expr(engine); - CompileAssignment(wnode->lastChild, &expr); - if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild); - else - { - if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr); - ProcessDeferredParams(&expr); - - ProcessPropertyGetAccessor(&expr, wnode); - - // Add byte code for the expression - ConvertToVariable(&expr); - - // Jump to next iteration if expression is true - expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); - expr.bc.Instr(asBC_ClrHi); - expr.bc.InstrDWORD(asBC_JNZ, beforeLabel); - ReleaseTemporaryVariable(expr.type, &expr.bc); - - expr.bc.OptimizeLocally(tempVariableOffsets); - bc->AddCode(&expr.bc); - } - - // Add label after the statement - bc->Label((short)afterLabel); - - continueLabels.PopLast(); - breakLabels.PopLast(); - - RemoveVariableScope(); -} - -void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc) -{ - if( breakLabels.GetLength() == 0 ) - { - Error(TXT_INVALID_BREAK, node); - return; - } - - // Add destructor calls for all variables that will go out of scope - // Put this clean up in a block to allow exception handler to understand them - bc->Block(true); - asCVariableScope *vs = variables; - while( !vs->isBreakScope ) - { - for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- ) - CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc); - - vs = vs->parent; - } - bc->Block(false); - - bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]); -} - -void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc) -{ - if( continueLabels.GetLength() == 0 ) - { - Error(TXT_INVALID_CONTINUE, node); - return; - } - - // Add destructor calls for all variables that will go out of scope - // Put this clean up in a block to allow exception handler to understand them - bc->Block(true); - asCVariableScope *vs = variables; - while( !vs->isContinueScope ) - { - for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- ) - CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc); - - vs = vs->parent; - } - bc->Block(false); - - bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]); -} - -void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc) -{ - if( enode->firstChild ) - { - // Compile the expression - asSExprContext expr(engine); - CompileAssignment(enode->firstChild, &expr); - - // Must not have unused ambiguous names - if( expr.IsClassMethod() || expr.IsGlobalFunc() ) - Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode); - - // If we get here and there is still an unprocessed property - // accessor, then process it as a get access. Don't call if there is - // already a compile error, or we might report an error that is not valid - if( !hasCompileErrors ) - ProcessPropertyGetAccessor(&expr, enode); - - // Pop the value from the stack - if( !expr.type.dataType.IsPrimitive() ) - expr.bc.Instr(asBC_PopPtr); - - // Release temporary variables used by expression - ReleaseTemporaryVariable(expr.type, &expr.bc); - - ProcessDeferredParams(&expr); - - expr.bc.OptimizeLocally(tempVariableOffsets); - bc->AddCode(&expr.bc); - } -} - -void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap) -{ - // 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. - if( ctx->type.isTemporary && ctx->type.isVariable && - !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) ) - { - // If the temporary object is currently not a reference - // the expression needs to be reevaluated to a reference - if( !ctx->type.dataType.IsReference() ) - { - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); - ctx->type.dataType.MakeReference(true); - } - - return; - } - - // Allocate temporary variable - asCDataType dt = ctx->type.dataType; - dt.MakeReference(false); - dt.MakeReadOnly(false); - - int offset = AllocateVariable(dt, true, forceOnHeap); - - // Objects stored on the stack are not considered references - dt.MakeReference(IsVariableOnHeap(offset)); - - asCTypeInfo lvalue; - lvalue.Set(dt); - lvalue.isExplicitHandle = ctx->type.isExplicitHandle; - bool isExplicitHandle = ctx->type.isExplicitHandle; - - CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false); - - // Push the reference to the temporary variable on the stack - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - - ctx->type.Set(dt); - ctx->type.isTemporary = true; - ctx->type.stackOffset = (short)offset; - ctx->type.isVariable = true; - ctx->type.isExplicitHandle = isExplicitHandle; - ctx->type.dataType.MakeReference(IsVariableOnHeap(offset)); -} - -void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc) -{ - // Get return type and location - sVariable *v = variables->GetVariable("return"); - - // Basic validations - if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild ) - { - Error(TXT_MUST_RETURN_VALUE, rnode); - return; - } - else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild ) - { - Error(TXT_CANT_RETURN_VALUE, rnode); - return; - } - - // Compile the expression - if( rnode->firstChild ) - { - // Compile the expression - asSExprContext expr(engine); - int r = CompileAssignment(rnode->firstChild, &expr); - if( r < 0 ) return; - - if( v->type.IsReference() ) - { - // The expression that gives the reference must not use any of the - // variables that must be destroyed upon exit, because then it means - // reference will stay alive while the clean-up is done, which could - // potentially mean that the reference is invalidated by the clean-up. - // - // When the function is returning a reference, the clean-up of the - // variables must be done before the evaluation of the expression. - // - // A reference to a global variable, or a class member for class methods - // should be allowed to be returned. - - if( !(expr.type.dataType.IsReference() || - (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) ) - { - // Clean up the potential deferred parameters - ProcessDeferredParams(&expr); - Error(TXT_NOT_VALID_REFERENCE, rnode); - return; - } - - // No references to local variables, temporary variables, or parameters - // are allowed to be returned, since they go out of scope when the function - // returns. Even reference parameters are disallowed, since it is not possible - // to know the scope of them. The exception is the 'this' pointer, which - // is treated by the compiler as a local variable, but isn't really so. - if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary ) - { - // Clean up the potential deferred parameters - ProcessDeferredParams(&expr); - Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode); - return; - } - - // 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.IsObjectHandle() && - v->type.IsEqualExceptRefAndConst(expr.type.dataType))) || - (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) ) - { - // Clean up the potential deferred parameters - ProcessDeferredParams(&expr); - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf()); - Error(str, rnode); - return; - } - - // The expression must not have any deferred expressions, because the evaluation - // of these cannot be done without keeping the reference which is not safe - if( expr.deferredParams.GetLength() ) - { - // Clean up the potential deferred parameters - ProcessDeferredParams(&expr); - Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode); - return; - } - - // Make sure the expression isn't using any local variables that - // will need to be cleaned up before the function completes - asCArray usedVars; - expr.bc.GetVarsUsed(usedVars); - for( asUINT n = 0; n < usedVars.GetLength(); n++ ) - { - int var = GetVariableSlot(usedVars[n]); - if( var != -1 ) - { - asCDataType dt = variableAllocations[var]; - if( dt.IsObject() ) - { - ProcessDeferredParams(&expr); - Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode); - return; - } - } - } - - // All objects in the function must be cleaned up before the expression - // is evaluated, otherwise there is a possibility that the cleanup will - // invalidate the reference. - - // Destroy the local variables before loading - // the reference into the register. This will - // be done before the expression is evaluated. - DestroyVariables(bc); - - - // For primitives the reference is already in the register, - // but for non-primitives the reference is on the stack so we - // need to load it into the register - if( !expr.type.dataType.IsPrimitive() ) - { - if( !expr.type.dataType.IsObjectHandle() && - expr.type.dataType.IsReference() ) - expr.bc.Instr(asBC_RDSPtr); - - expr.bc.Instr(asBC_PopRPtr); - } - - // There are no temporaries to release so we're done - } - else // if( !v->type.IsReference() ) - { - ProcessPropertyGetAccessor(&expr, rnode); - - // Prepare the value for assignment - IsVariableInitialized(&expr.type, rnode->firstChild); - - if( v->type.IsPrimitive() ) - { - if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr); - - // Implicitly convert the value to the return type - ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV); - - // Verify that the conversion was successful - if( expr.type.dataType != v->type ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf()); - Error(str, rnode); - return; - } - else - { - ConvertToVariable(&expr); - - // Clean up the local variables and process deferred parameters - DestroyVariables(&expr.bc); - ProcessDeferredParams(&expr); - - ReleaseTemporaryVariable(expr.type, &expr.bc); - - // Load the variable in the register - if( v->type.GetSizeOnStackDWords() == 1 ) - expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); - else - expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset); - } - } - else if( v->type.IsObject() ) - { - // Value types are returned on the stack, in a location - // that has been reserved by the calling function. - if( outFunc->DoesReturnOnStack() ) - { - // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression, - // it should be called directly instead of first converting the expression and - // then copy the value. - if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) ) - { - ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV); - if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf()); - Error(str, rnode->firstChild); - return; - } - } - - int offset = outFunc->objectType ? -AS_PTR_SIZE : 0; - CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true); - - // Clean up the local variables and process deferred parameters - DestroyVariables(&expr.bc); - ProcessDeferredParams(&expr); - } - else - { - asASSERT( v->type.GetObjectType()->flags & asOBJ_REF ); - - // Prepare the expression to be loaded into the object - // register. This will place the reference in local variable - PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0); - - // Pop the reference to the temporary variable - expr.bc.Instr(asBC_PopPtr); - - // Clean up the local variables and process deferred parameters - DestroyVariables(&expr.bc); - ProcessDeferredParams(&expr); - - // Load the object pointer into the object register - // LOADOBJ also clears the address in the variable - expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset); - - // LOADOBJ cleared the address in the variable so the object will not be freed - // here, but the temporary variable must still be freed so the slot can be reused - // By releasing without the bytecode we do just that. - ReleaseTemporaryVariable(expr.type, 0); - } - } - } - - expr.bc.OptimizeLocally(tempVariableOffsets); - bc->AddCode(&expr.bc); - } - else - { - // For functions that don't return anything - // we just detroy the local variables - DestroyVariables(bc); - } - - // Jump to the end of the function - bc->InstrINT(asBC_JMP, 0); -} - -void asCCompiler::DestroyVariables(asCByteCode *bc) -{ - // Call destructor on all variables except for the function parameters - // Put the clean-up in a block to allow exception handler to understand this - bc->Block(true); - asCVariableScope *vs = variables; - while( vs ) - { - for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- ) - if( vs->variables[n]->stackOffset > 0 ) - CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc); - - vs = vs->parent; - } - bc->Block(false); -} - -void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope) -{ - variables = asNEW(asCVariableScope)(variables); - if( variables == 0 ) - { - // Out of memory - return; - } - variables->isBreakScope = isBreakScope; - variables->isContinueScope = isContinueScope; -} - -void asCCompiler::RemoveVariableScope() -{ - if( variables ) - { - asCVariableScope *var = variables; - variables = variables->parent; - asDELETE(var,asCVariableScope); - } -} - -void asCCompiler::Error(const asCString &msg, asCScriptNode *node) -{ - asCString str; - - int r = 0, c = 0; - asASSERT( node ); - if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); - - builder->WriteError(script->name, msg, r, c); - - hasCompileErrors = true; -} - -void asCCompiler::Warning(const asCString &msg, asCScriptNode *node) -{ - asCString str; - - int r = 0, c = 0; - asASSERT( node ); - if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); - - builder->WriteWarning(script->name, msg, r, c); -} - -void asCCompiler::Information(const asCString &msg, asCScriptNode *node) -{ - asCString str; - - int r = 0, c = 0; - asASSERT( node ); - if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); - - builder->WriteInfo(script->name, msg, r, c, false); -} - -void asCCompiler::PrintMatchingFuncs(asCArray &funcs, asCScriptNode *node, asCObjectType *inType) -{ - int r = 0, c = 0; - asASSERT( node ); - if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); - - for( unsigned int n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]); - if( inType && func->funcType == asFUNC_VIRTUAL ) - func = inType->virtualFunctionTable[func->vfTableIdx]; - - builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false); - } -} - -int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx) -{ - int l = int(reservedVariables.GetLength()); - ctx->bc.GetVarsUsed(reservedVariables); - int var = AllocateVariable(type, isTemporary, forceOnHeap); - reservedVariables.SetLength(l); - return var; -} - -int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap) -{ - asCDataType t(type); - t.MakeReference(false); - - if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 ) - t.SetTokenType(ttInt); - - if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 ) - t.SetTokenType(ttDouble); - - // Only null handles have the token type unrecognized token - asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken ); - - bool isOnHeap = true; - if( t.IsPrimitive() || - (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) ) - { - // Primitives and value types (unless overridden) are allocated on the stack - isOnHeap = false; - } - - // Find a free location with the same type - for( asUINT n = 0; n < freeVariables.GetLength(); n++ ) - { - int slot = freeVariables[n]; - - if( variableAllocations[slot].IsEqualExceptConst(t) && - variableIsTemporary[slot] == isTemporary && - variableIsOnHeap[slot] == isOnHeap ) - { - // We can't return by slot, must count variable sizes - int offset = GetVariableOffset(slot); - - // Verify that it is not in the list of reserved variables - bool isUsed = false; - if( reservedVariables.GetLength() ) - isUsed = reservedVariables.Exists(offset); - - if( !isUsed ) - { - if( n != freeVariables.GetLength() - 1 ) - freeVariables[n] = freeVariables.PopLast(); - else - freeVariables.PopLast(); - - if( isTemporary ) - tempVariables.PushLast(offset); - - return offset; - } - } - } - - variableAllocations.PushLast(t); - variableIsTemporary.PushLast(isTemporary); - variableIsOnHeap.PushLast(isOnHeap); - - int offset = GetVariableOffset((int)variableAllocations.GetLength()-1); - - if( isTemporary ) - { - // Add offset to the currently allocated temporary variables - tempVariables.PushLast(offset); - - // Add offset to all known offsets to temporary variables, whether allocated or not - tempVariableOffsets.PushLast(offset); - } - - return offset; -} - -int asCCompiler::GetVariableOffset(int varIndex) -{ - // Return offset to the last dword on the stack - - // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions) - int varOffset = 1; - - // Skip lower variables - for( int n = 0; n < varIndex; n++ ) - { - if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() ) - varOffset += variableAllocations[n].GetSizeInMemoryDWords(); - else - varOffset += variableAllocations[n].GetSizeOnStackDWords(); - } - - if( varIndex < (int)variableAllocations.GetLength() ) - { - // For variables larger than 1 dword the returned offset should be to the last dword - int size; - if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() ) - size = variableAllocations[varIndex].GetSizeInMemoryDWords(); - else - size = variableAllocations[varIndex].GetSizeOnStackDWords(); - if( size > 1 ) - varOffset += size-1; - } - - return varOffset; -} - - -int asCCompiler::GetVariableSlot(int offset) -{ - int varOffset = 1; - for( asUINT n = 0; n < variableAllocations.GetLength(); n++ ) - { - if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() ) - varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords(); - else - varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords(); - - if( varOffset == offset ) - return n; - - varOffset++; - } - - return -1; -} - -bool asCCompiler::IsVariableOnHeap(int offset) -{ - int varSlot = GetVariableSlot(offset); - if( varSlot < 0 ) - { - // This happens for function arguments that are considered as on the heap - return true; - } - - return variableIsOnHeap[varSlot]; -} - -void asCCompiler::DeallocateVariable(int offset) -{ - // Remove temporary variable - int n; - for( n = 0; n < (int)tempVariables.GetLength(); n++ ) - { - if( offset == tempVariables[n] ) - { - if( n == (int)tempVariables.GetLength()-1 ) - tempVariables.PopLast(); - else - tempVariables[n] = tempVariables.PopLast(); - break; - } - } - - n = GetVariableSlot(offset); - if( n != -1 ) - { - freeVariables.PushLast(n); - return; - } - - // We might get here if the variable was implicitly declared - // because it was use before a formal declaration, in this case - // the offset is 0x7FFF - - asASSERT(offset == 0x7FFF); -} - -void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc) -{ - if( t.isTemporary ) - { - ReleaseTemporaryVariable(t.stackOffset, bc); - t.isTemporary = false; - } -} - -void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc) -{ - asASSERT( tempVariables.Exists(offset) ); - - if( bc ) - { - // We need to call the destructor on the true variable type - int n = GetVariableSlot(offset); - asASSERT( n >= 0 ); - if( n >= 0 ) - { - asCDataType dt = variableAllocations[n]; - bool isOnHeap = variableIsOnHeap[n]; - - // Call destructor - CallDestructor(dt, offset, isOnHeap, bc); - } - } - - DeallocateVariable(offset); -} - -void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode) -{ - if( ctx->type.dataType.IsReference() ) - { - if( ctx->type.dataType.IsObject() ) - { - ctx->type.dataType.MakeReference(false); - if( generateCode ) - ctx->bc.Instr(asBC_RDSPtr); - } - else - { - // This should never happen as primitives are treated differently - asASSERT(false); - } - } -} - -bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node) -{ - // No need to check if there is no variable scope - if( variables == 0 ) return true; - - // Temporary variables are assumed to be initialized - if( type->isTemporary ) return true; - - // Verify that it is a variable - if( !type->isVariable ) return true; - - // Find the variable - sVariable *v = variables->GetVariableByOffset(type->stackOffset); - - // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized - if( v == 0 ) return true; - - if( v->isInitialized ) return true; - - // Complex types don't need this test - if( v->type.IsObject() ) return true; - - // Mark as initialized so that the user will not be bothered again - v->isInitialized = true; - - // Write warning - asCString str; - str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf()); - Warning(str, node); - - return false; -} - -void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node) -{ - // Check if the variable is initialized (if it indeed is a variable) - IsVariableInitialized(&ctx->type, node); - - asCDataType to = ctx->type.dataType; - to.MakeReference(false); - - ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV); - - ProcessDeferredParams(ctx); -} - -void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *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()); - if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables); - - - ProcessPropertyGetAccessor(rctx, node); - - // Make sure the rvalue is initialized if it is a variable - IsVariableInitialized(&rctx->type, node); - - if( lvalue->IsPrimitive() ) - { - if( rctx->type.dataType.IsPrimitive() ) - { - if( rctx->type.dataType.IsReference() ) - { - // Cannot do implicit conversion of references so we first convert the reference to a variable - ConvertToVariableNotIn(rctx, lvalueExpr); - } - } - - // Implicitly convert the value to the right type - ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV); - - // Check data type - if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf()); - Error(str, node); - - rctx->type.SetDummy(); - } - - // Make sure the rvalue is a variable - if( !rctx->type.isVariable ) - ConvertToVariableNotIn(rctx, lvalueExpr); - } - else - { - asCDataType to = *lvalue; - to.MakeReference(false); - - // 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) ) - 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) ) - { - // Then convert to a reference, which will validate the handle - to.MakeHandle(false); - ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary); - } - - // Check data type - if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf()); - Error(str, node); - } - 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()); - } - } - - // Unreserve variables - reservedVariables.SetLength(l); -} - -bool asCCompiler::IsLValue(asCTypeInfo &type) -{ - if( !type.isLValue ) return false; - if( type.dataType.IsReadOnly() ) return false; - if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false; - return true; -} - -int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node) -{ - if( lvalue->dataType.IsReadOnly() ) - { - Error(TXT_REF_IS_READ_ONLY, node); - return -1; - } - - if( lvalue->dataType.IsPrimitive() ) - { - if( lvalue->isVariable ) - { - // Copy the value between the variables directly - if( lvalue->dataType.GetSizeInMemoryDWords() == 1 ) - bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset); - else - bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset); - - // Mark variable as initialized - sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset); - if( v ) v->isInitialized = true; - } - else if( lvalue->dataType.IsReference() ) - { - // Copy the value of the variable to the reference in the register - int s = lvalue->dataType.GetSizeInMemoryBytes(); - if( s == 1 ) - bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset); - else if( s == 2 ) - bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset); - else if( s == 4 ) - bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset); - else if( s == 8 ) - bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset); - } - else - { - Error(TXT_NOT_VALID_LVALUE, node); - return -1; - } - } - else if( !lvalue->isExplicitHandle ) - { - asSExprContext 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 ) - { - asSExprContext res(engine); - PerformFunctionCall(beh->copy, &res, false, 0, lvalue->dataType.GetObjectType()); - - bc->AddCode(&res.bc); - *lvalue = res.type; - } - else if( beh->copy == engine->scriptTypeBehaviours.beh.copy ) - { - // Call the default copy operator for script classes - // This is done differently because the default copy operator - // is registered as returning int&, but in reality it returns - // a reference to the object. - // TODO: Avoid this special case by implementing a copystub for - // script classes that uses the default copy operator - bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE); - bc->Instr(asBC_PshRPtr); - } - else - { - // Default copy operator - if( lvalue->dataType.GetSizeInMemoryDWords() == 0 || - !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) ) - { - asCString msg; - msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf()); - Error(msg, node); - return -1; - } - - // Copy larger data types from a reference - // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register. - bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType)); - } - } - else - { - // TODO: The object handle can be stored in a variable as well - if( !lvalue->dataType.IsReference() ) - { - Error(TXT_NOT_VALID_REFERENCE, node); - return -1; - } - - bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType()); - - // Mark variable as initialized - if( variables ) - { - sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset); - if( v ) v->isInitialized = true; - } - } - - return 0; -} - -bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode) -{ - bool conversionDone = false; - - asCArray ops; - asUINT n; - - if( ctx->type.dataType.GetObjectType()->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); - } - - if( isExplicit ) - { - // Allow dynamic cast between object handles (only for script objects). - // At run time this may result in a null handle, - // which when used will throw an exception - conversionDone = true; - if( generateCode ) - { - ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to)); - - // Allocate a temporary variable for the returned object - int returnOffset = AllocateVariable(to, true); - - // Move the pointer from the object register to the temporary variable - ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset); - - ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset); - - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - - ctx->type.SetVariable(to, returnOffset, true); - ctx->type.dataType.MakeReference(true); - } - else - { - ctx->type.dataType = to; - ctx->type.dataType.MakeReference(true); - } - } - else - { - if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) ) - { - conversionDone = true; - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - } - } - else - { - // Find a suitable registered behaviour - asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh; - for( n = 0; n < beh->operators.GetLength(); n+= 2 ) - { - if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) || - asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] ) - { - int funcId = beh->operators[n+1]; - - // Is the operator for the output type? - asCScriptFunction *func = engine->scriptFunctions[funcId]; - if( func->returnType.GetObjectType() != to.GetObjectType() ) - continue; - - ops.PushLast(funcId); - } - } - - // It shouldn't be possible to have more than one - asASSERT( ops.GetLength() <= 1 ); - - // Should only have one behaviour for each output type - if( ops.GetLength() == 1 ) - { - if( generateCode ) - { - // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is - // null, we can create a special CALLSYS instruction that checks - // if the object pointer is null and if so sets the object register - // to null directly without executing the function. - // - // Alternatively I could force the ref cast behaviours be global - // functions with 1 parameter, even though they should still be - // registered with RegisterObjectBehaviour() - - // 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 ) - { - Dereference(ctx, true); - ConvertToVariable(ctx); - } - - // The reference on the stack will not be used - ctx->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) - ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset); - ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset); - DeallocateVariable(offset); - - int afterLabel = nextLabel++; - ctx->bc.InstrDWORD(asBC_JZ, afterLabel); - - // Call the cast operator - ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); - ctx->bc.Instr(asBC_RDSPtr); - ctx->type.dataType.MakeReference(false); - - asCArray args; - MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node); - - ctx->bc.Instr(asBC_PopPtr); - - int endLabel = nextLabel++; - - ctx->bc.InstrINT(asBC_JMP, endLabel); - ctx->bc.Label((short)afterLabel); - - // Make a NULL pointer - ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset); - ctx->bc.Label((short)endLabel); - - // Push the reference to the handle on the stack - ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); - } - else - { - asCScriptFunction *func = engine->scriptFunctions[ops[0]]; - ctx->type.Set(func->returnType); - } - } - else if( ops.GetLength() == 0 ) - { - // Check for the generic ref cast behaviour - for( n = 0; n < beh->operators.GetLength(); n+= 2 ) - { - if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) || - asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] ) - { - int funcId = beh->operators[n+1]; - - // Does the operator take the ?&out parameter? - asCScriptFunction *func = engine->scriptFunctions[funcId]; - if( func->parameterTypes.GetLength() != 1 || - func->parameterTypes[0].GetTokenType() != ttQuestion || - func->inOutFlags[0] != asTM_OUTREF ) - continue; - - ops.PushLast(funcId); - } - } - - // It shouldn't be possible to have more than one - asASSERT( ops.GetLength() <= 1 ); - - if( ops.GetLength() == 1 ) - { - if( generateCode ) - { - asASSERT(to.IsObjectHandle()); - - // 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); - 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); - arg.type.isLValue = true; - arg.type.isExplicitHandle = true; - args.PushLast(&arg); - - // Call the behaviour method - MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node); - - // Use the reference to the variable as the result of the expression - // Now we can mark the variable as temporary - ctx->type.SetVariable(toRef, stackOffset, true); - ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset); - } - else - { - // All casts are legal - ctx->type.Set(to); - } - } - } - } - - return conversionDone; -} - -asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode) -{ - asCDataType to = toOrig; - to.MakeReference(false); - asASSERT( !ctx->type.dataType.IsReference() ); - - // Maybe no conversion is needed - if( to.IsEqualExceptConst(ctx->type.dataType) ) - { - // A primitive is const or not - ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); - return asCC_NO_CONV; - } - - // Is the conversion an ambiguous enum value? - if( ctx->enumValue != "" ) - { - if( to.IsEnumType() ) - { - // Attempt to resolve an ambiguous enum value - asCDataType out; - asDWORD value; - if( builder->GetEnumValueFromObjectType(to.GetObjectType(), ctx->enumValue.AddressOf(), out, value) ) - { - ctx->type.SetConstantDW(out, value); - ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); - - // Reset the enum value since we no longer need it - ctx->enumValue = ""; - - // It wasn't really a conversion. The compiler just resolved the ambiguity (or not) - return asCC_NO_CONV; - } - } - - // The enum value is ambiguous - if( node && generateCode ) - Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node); - - // Set a dummy to allow the compiler to try to continue the conversion - ctx->type.SetDummy(); - } - - // Determine the cost of this conversion - 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()) ) - cost = asCC_INT_FLOAT_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() ) - cost = asCC_PRIMITIVE_SIZE_CONV; - - // Start by implicitly converting constant values - if( ctx->type.isConstant ) - { - ImplicitConversionConstant(ctx, to, node, convType); - ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); - return cost; - } - - // Allow implicit conversion between numbers - if( generateCode ) - { - // When generating the code the decision has already been made, so we don't bother determining the cost - - // Convert smaller types to 32bit first - int s = ctx->type.dataType.GetSizeInMemoryBytes(); - if( s < 4 ) - { - ConvertToTempVariable(ctx); - if( ctx->type.dataType.IsIntegerType() ) - { - if( s == 1 ) - ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset); - else if( s == 2 ) - ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(ttInt); - } - else if( ctx->type.dataType.IsUnsignedType() ) - { - if( s == 1 ) - ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset); - else if( s == 2 ) - ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(ttUInt); - } - } - - if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) || - (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) ) - { - if( ctx->type.dataType.IsIntegerType() || - ctx->type.dataType.IsUnsignedType() ) - { - if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - else - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - } - else if( ctx->type.dataType.IsFloatType() ) - { - ConvertToTempVariable(ctx); - ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - - if( convType != asIC_EXPLICIT_VAL_CAST ) - Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); - } - else if( ctx->type.dataType.IsDoubleType() ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - - if( convType != asIC_EXPLICIT_VAL_CAST ) - Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); - } - - // Convert to smaller integer if necessary - int s = to.GetSizeInMemoryBytes(); - if( s < 4 ) - { - ConvertToTempVariable(ctx); - if( s == 1 ) - ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset); - else if( s == 2 ) - ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset); - } - } - else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 ) - { - if( ctx->type.dataType.IsIntegerType() || - ctx->type.dataType.IsUnsignedType() ) - { - if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - else - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - if( ctx->type.dataType.IsUnsignedType() ) - ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset); - else - ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - } - else if( ctx->type.dataType.IsFloatType() ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - - if( convType != asIC_EXPLICIT_VAL_CAST ) - Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); - } - else if( ctx->type.dataType.IsDoubleType() ) - { - ConvertToTempVariable(ctx); - ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - - if( convType != asIC_EXPLICIT_VAL_CAST ) - Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); - } - } - else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 ) - { - if( ctx->type.dataType.IsIntegerType() || - ctx->type.dataType.IsUnsignedType() ) - { - if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - else - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - } - else if( ctx->type.dataType.IsFloatType() ) - { - ConvertToTempVariable(ctx); - ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - - if( convType != asIC_EXPLICIT_VAL_CAST ) - Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); - } - else if( ctx->type.dataType.IsDoubleType() ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - - if( convType != asIC_EXPLICIT_VAL_CAST ) - Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); - } - - // Convert to smaller integer if necessary - int s = to.GetSizeInMemoryBytes(); - if( s < 4 ) - { - ConvertToTempVariable(ctx); - if( s == 1 ) - ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset); - else if( s == 2 ) - ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset); - } - } - else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 ) - { - if( ctx->type.dataType.IsIntegerType() || - ctx->type.dataType.IsUnsignedType() ) - { - if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - else - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - if( ctx->type.dataType.IsUnsignedType() ) - ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset); - else - ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - } - else if( ctx->type.dataType.IsFloatType() ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - - if( convType != asIC_EXPLICIT_VAL_CAST ) - Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); - } - else if( ctx->type.dataType.IsDoubleType() ) - { - ConvertToTempVariable(ctx); - ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - - if( convType != asIC_EXPLICIT_VAL_CAST ) - Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); - } - } - else if( to.IsFloatType() ) - { - if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - ConvertToTempVariable(ctx); - ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - ConvertToTempVariable(ctx); - ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - else if( ctx->type.dataType.IsDoubleType() ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - } - else if( to.IsDoubleType() ) - { - if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - ConvertToTempVariable(ctx); - ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - ConvertToTempVariable(ctx); - ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset); - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - else if( ctx->type.dataType.IsFloatType() ) - { - ConvertToTempVariable(ctx); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - int offset = AllocateVariable(to, true); - ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset); - ctx->type.SetVariable(to, offset, true); - } - } - } - else - { - if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() || - to.IsFloatType() || to.IsDoubleType() || - (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) && - (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() || - ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) ) - { - ctx->type.dataType.SetTokenType(to.GetTokenType()); - ctx->type.dataType.SetObjectType(to.GetObjectType()); - } - } - - // Primitive types on the stack, can be const or non-const - ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); - return cost; -} - -asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) -{ - asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken || - ctx->type.dataType.IsNullHandle() ); - - // No conversion from void to any other type - if( ctx->type.dataType.GetTokenType() == ttVoid ) - return asCC_NO_CONV; - - // Do we want a var type? - if( to.GetTokenType() == ttQuestion ) - { - // Any type can be converted to a var type, but only when not generating code - asASSERT( !generateCode ); - - ctx->type.dataType = to; - - return asCC_VARIABLE_CONV; - } - // Do we want a primitive? - else if( to.IsPrimitive() ) - { - if( !ctx->type.dataType.IsPrimitive() ) - return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode); - else - return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode); - } - else // The target is a complex type - { - if( ctx->type.dataType.IsPrimitive() ) - return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct); - else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() ) - 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) -{ - if( ctx->type.isExplicitHandle ) - { - // An explicit handle cannot be converted to a primitive - if( convType != asIC_IMPLICIT_CONV && node ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - } - return asCC_NO_CONV; - } - - // TODO: Must use the const cast behaviour if the object is read-only - - // 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(); - if( ot == 0 ) - { - if( convType != asIC_IMPLICIT_CONV && node ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - } - return asCC_NO_CONV; - } - - - if( convType == asIC_EXPLICIT_VAL_CAST ) - { - for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) - { - // accept both implicit and explicit cast - asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]]; - if( (mthd->name == "opConv" || mthd->name == "opImplConv") && - mthd->parameterTypes.GetLength() == 0 && - mthd->returnType.IsPrimitive() ) - funcs.PushLast(ot->methods[n]); - } - } - else - { - for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) - { - // accept only implicit cast - asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]]; - if( mthd->name == "opImplConv" && - mthd->parameterTypes.GetLength() == 0 && - mthd->returnType.IsPrimitive() ) - funcs.PushLast(ot->methods[n]); - } - } - - // This matrix describes the priorities of the types to search for, for each target type - // The first column is the target type, the priorities goes from left to right - eTokenType matchMtx[10][10] = - { - {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8}, - {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8}, - {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat}, - {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat}, - {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat}, - {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat}, - {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat}, - {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat}, - {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat}, - {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat}, - }; - - // Which row to use? - eTokenType *row = 0; - for( unsigned int type = 0; type < 10; type++ ) - { - if( to.GetTokenType() == matchMtx[type][0] ) - { - row = &matchMtx[type][0]; - break; - } - } - - // Find the best matching cast operator - int funcId = 0; - if( row ) - { - asCDataType target(to); - - // Priority goes from left to right in the matrix - for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ ) - { - target.SetTokenType(row[attempt]); - for( unsigned int n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]); - if( descr->returnType.IsEqualExceptRefAndConst(target) ) - { - funcId = funcs[n]; - break; - } - } - } - } - - // Did we find a suitable function? - if( funcId != 0 ) - { - asCScriptFunction *descr = builder->GetFunctionDescription(funcId); - if( generateCode ) - { - Dereference(ctx, true); - PerformFunctionCall(funcId, ctx); - } - else - ctx->type.Set(descr->returnType); - - // Allow one more implicit conversion to another primitive type - return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false); - } - - // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue - // If no direct conversion is found we should look for the generic form 'void opConv(?&out)' - funcs.SetLength(0); - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") || - func->name == "opImplConv" ) - { - // Does the operator take the ?&out parameter? - if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) || - func->parameterTypes.GetLength() != 1 || - func->parameterTypes[0].GetTokenType() != ttQuestion || - func->inOutFlags[0] != asTM_OUTREF ) - continue; - - funcs.PushLast(ot->methods[n]); - } - } - - // TODO: If there are multiple valid value casts, then we must choose the most appropriate one - asASSERT( funcs.GetLength() <= 1 ); - - if( funcs.GetLength() == 1 ) - { - if( generateCode ) - { - // Allocate a temporary variable of the requested type - int stackOffset = AllocateVariableNotIn(to, true, false, ctx); - CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node); - - // Pass the reference of that variable to the function as output parameter - asCDataType toRef(to); - toRef.MakeReference(true); - toRef.MakeReadOnly(false); - asCArray args; - asSExprContext 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; - arg.exprNode = node; - args.PushLast(&arg); - - // Call the behaviour method - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node); - - // Use the reference to the variable as the result of the expression - // Now we can mark the variable as temporary - toRef.MakeReference(false); - ctx->type.SetVariable(toRef, stackOffset, true); - } - else - ctx->type.Set(to); - - return asCC_OBJ_TO_PRIMITIVE_CONV; - } - - if( convType != asIC_IMPLICIT_CONV && node ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - } - - return asCC_NO_CONV; -} - - -asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *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 == "" ) - { - if( to.IsObjectHandle() ) - { - ctx->type.dataType = to; - return asCC_REF_CONV; - } - return asCC_NO_CONV; - } - - asASSERT(ctx->type.dataType.GetObjectType() || ctx->methodName != ""); - - // First attempt to convert the base type without instantiating another instance - if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && 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()) ) - { - ctx->type.dataType.SetObjectType(to.GetObjectType()); - 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()) ) - { - ctx->type.dataType.SetObjectType(to.GetObjectType()); - 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() ) - { - // A ref cast must not remove the constness - bool isConst = ctx->type.dataType.IsObjectConst(); - - // We may still be able to find an implicit ref cast behaviour - CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode); - - ctx->type.dataType.MakeHandleToConst(isConst); - - // Was the conversion done? - if( ctx->type.dataType.GetObjectType() == to.GetObjectType() ) - return asCC_REF_CONV; - } - } - - // Convert matching function types - if( to.GetFuncDef() ) - { - // 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() ) - { - asCScriptFunction *toFunc = to.GetFuncDef(); - asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef(); - if( toFunc->IsSignatureExceptNameEqual(fromFunc) ) - { - ctx->type.dataType.SetFuncDef(toFunc); - return asCC_REF_CONV; - } - } - - // If the input expression is a deferred function ref, check if there is a matching func - if( ctx->methodName != "" ) - { - // Determine the namespace - asSNameSpace *ns = 0; - asCString name = ""; - int pos = ctx->methodName.FindLast("::"); - if( pos >= 0 ) - { - asCString nsName = ctx->methodName.SubString(0, pos+2); - // Trim off the last :: - if( nsName.GetLength() > 2 ) - nsName.SetLength(nsName.GetLength()-2); - ns = DetermineNameSpace(nsName); - name = ctx->methodName.SubString(pos+2); - } - else - { - DetermineNameSpace(""); - name = ctx->methodName; - } - - asCArray funcs; - if( ns ) - builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); - - // Check if any of the functions have perfect match - for( asUINT n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]); - if( to.GetFuncDef()->IsSignatureExceptNameEqual(func) ) - { - if( generateCode ) - { - ctx->bc.InstrPTR(asBC_FuncPtr, func); - - // Make sure the identified function is shared if we're compiling a shared function - if( !func->IsShared() && outFunc->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration()); - Error(msg, node); - } - } - - ctx->type.dataType = asCDataType::CreateFuncDef(to.GetFuncDef()); - return asCC_REF_CONV; - } - } - } - } - - return asCC_NO_CONV; -} - -asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *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() ) - { - // TODO: Implement support for implicit constructor/factory - asCObjectType *ot = ctx->type.dataType.GetObjectType(); - if( ot == 0 ) - return cost; - - asCArray funcs; - if( convType == asIC_EXPLICIT_VAL_CAST ) - { - for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - - // accept both implicit and explicit cast - if( (func->name == "opConv" || - func->name == "opImplConv") && - func->returnType.GetObjectType() == to.GetObjectType() && - func->parameterTypes.GetLength() == 0 ) - funcs.PushLast(ot->methods[n]); - } - } - else - { - for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - - // accept only implicit cast - if( func->name == "opImplConv" && - func->returnType.GetObjectType() == to.GetObjectType() && - func->parameterTypes.GetLength() == 0 ) - funcs.PushLast(ot->methods[n]); - } - } - - // TODO: If there are multiple valid value casts, then we must choose the most appropriate one - asASSERT( funcs.GetLength() <= 1 ); - - if( funcs.GetLength() == 1 ) - { - asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]); - if( generateCode ) - { - Dereference(ctx, true); - - bool useVariable = false; - int stackOffset = 0; - - if( f->DoesReturnOnStack() ) - { - useVariable = true; - stackOffset = AllocateVariable(f->returnType, true); - - // Push the pointer to the pre-allocated space for the return value - ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset)); - - // The object pointer is already on the stack, but should be the top - // one, so we need to swap the pointers in order to get the correct - ctx->bc.Instr(asBC_SwapPtr); - } - - PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset); - } - else - ctx->type.Set(f->returnType); - - cost = asCC_TO_OBJECT_CONV; - } - else - { - // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive - // Look for a value cast with variable type - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") || - func->name == "opImplConv" ) - { - // Does the operator take the ?&out parameter? - if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) || - func->parameterTypes.GetLength() != 1 || - func->parameterTypes[0].GetTokenType() != ttQuestion || - func->inOutFlags[0] != asTM_OUTREF ) - continue; - - funcs.PushLast(ot->methods[n]); - } - } - - // TODO: If there are multiple valid value casts, then we must choose the most appropriate one - asASSERT( funcs.GetLength() <= 1 ); - - if( funcs.GetLength() == 1 ) - { - cost = asCC_TO_OBJECT_CONV; - if( generateCode ) - { - // Allocate a temporary variable of the requested type - int stackOffset = AllocateVariableNotIn(to, true, false, ctx); - CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node); - - // Pass the reference of that variable to the function as output parameter - asCDataType toRef(to); - toRef.MakeReference(false); - asCArray args; - asSExprContext 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); - arg.type.isLValue = true; - arg.exprNode = node; - args.PushLast(&arg); - - // Call the behaviour method - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node); - - // Use the reference to the variable as the result of the expression - // Now we can mark the variable as temporary - ctx->type.SetVariable(toRef, stackOffset, true); - ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset); - } - else - { - // All casts are legal - ctx->type.Set(to); - } - } - } - } - - return cost; -} - -asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *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 ) - { - asCArray funcs; - funcs = to.GetObjectType()->beh.constructors; - - asCArray args; - args.PushLast(ctx); - - cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false); - - // Did we find a matching constructor? - if( funcs.GetLength() == 1 ) - { - if( generateCode ) - { - // If the ASHANDLE receives a variable type parameter, then we need to - // make sure the expression is treated as a handle and not as a value - asCScriptFunction *func = engine->scriptFunctions[funcs[0]]; - if( func->parameterTypes[0].GetTokenType() == ttQuestion ) - { - if( !ctx->type.isExplicitHandle ) - { - asCDataType toHandle = ctx->type.dataType; - toHandle.MakeHandle(true); - toHandle.MakeReference(true); - toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly()); - ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false); - - asASSERT( ctx->type.dataType.IsObjectHandle() ); - } - ctx->type.isExplicitHandle = true; - } - - // TODO: This should really reuse the code from CompileConstructCall - - // Allocate the new object - asCTypeInfo tempObj; - tempObj.dataType = to; - tempObj.dataType.MakeReference(false); - tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true); - tempObj.dataType.MakeReference(true); - tempObj.isTemporary = true; - tempObj.isVariable = true; - - bool onHeap = IsVariableOnHeap(tempObj.stackOffset); - - // Push the address of the object on the stack - asSExprContext e(engine); - if( onHeap ) - e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); - - PrepareFunctionCall(funcs[0], &e.bc, args); - MoveArgsToStack(funcs[0], &e.bc, args, false); - - // If the object is allocated on the stack, then call the constructor as a normal function - if( onHeap ) - { - int offset = 0; - asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); - offset = descr->parameterTypes[0].GetSizeOnStackDWords(); - - e.bc.InstrWORD(asBC_GETREF, (asWORD)offset); - } - else - e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - - PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType()); - - // Add tag that the object has been initialized - e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); - - // The constructor doesn't return anything, - // so we have to manually inform the type of - // the return value - e.type = tempObj; - if( !onHeap ) - e.type.dataType.MakeReference(false); - - // Push the address of the object on the stack again - e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - - MergeExprBytecodeAndType(ctx, &e); - } - else - { - ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), 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 ) - { - // Attempt implicit value cast - cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode); - } - - // 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() ) - return asCC_NO_CONV; - - - if( to.IsObjectHandle() ) - { - // There is no extra cost in converting to a handle - - // reference to handle -> handle - // reference -> handle - // object -> handle - // handle -> reference to handle - // 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( convType != asIC_IMPLICIT_CONV ) - { - asASSERT(node); - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - } - } - - if( !ctx->type.dataType.IsObjectHandle() ) - { - // An object type can be directly converted to a handle of the - // same type by doing a ref copy to a new variable - if( ctx->type.dataType.SupportHandles() ) - { - asCDataType dt = ctx->type.dataType; - dt.MakeHandle(true); - dt.MakeReference(false); - - if( generateCode ) - { - // If the expression is already a local variable, then it is not - // necessary to do a ref copy, as the ref objects on the stack are - // really handles, only the handles cannot be modified. - if( ctx->type.isVariable ) - { - bool isHandleToConst = ctx->type.dataType.IsReadOnly(); - ctx->type.dataType.MakeReadOnly(false); - ctx->type.dataType.MakeHandle(true); - ctx->type.dataType.MakeReadOnly(true); - ctx->type.dataType.MakeHandleToConst(isHandleToConst); - - if( to.IsReference() && !ctx->type.dataType.IsReference() ) - { - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); - ctx->type.dataType.MakeReference(true); - } - else if( ctx->type.dataType.IsReference() ) - { - ctx->bc.Instr(asBC_RDSPtr); - ctx->type.dataType.MakeReference(false); - } - } - else - { - int offset = AllocateVariable(dt, true); - - if( ctx->type.dataType.IsReference() ) - ctx->bc.Instr(asBC_RDSPtr); - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType()); - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - - if( to.IsReference() ) - dt.MakeReference(true); - else - ctx->bc.Instr(asBC_RDSPtr); - - ctx->type.SetVariable(dt, offset, true); - } - } - else - ctx->type.dataType = dt; - - // When this conversion is done the expression is no longer an lvalue - ctx->type.isLValue = false; - } - } - - if( ctx->type.dataType.IsObjectHandle() ) - { - // A handle to non-const can be converted to a - // handle to const, but not the other way - if( to.IsHandleToConst() ) - ctx->type.dataType.MakeHandleToConst(true); - - // A const handle can be converted to a non-const - // handle and vice versa as the handle is just a value - ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); - } - - if( to.IsReference() && !ctx->type.dataType.IsReference() ) - { - if( generateCode ) - { - asASSERT( ctx->type.dataType.IsObjectHandle() ); - - // If the input type is a handle, then a simple ref copy is enough - bool isExplicitHandle = ctx->type.isExplicitHandle; - ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle(); - - // If the input type is read-only we'll need to temporarily - // remove this constness, otherwise the assignment will fail - bool typeIsReadOnly = ctx->type.dataType.IsReadOnly(); - ctx->type.dataType.MakeReadOnly(false); - - // 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); - - ctx->type.dataType.MakeReadOnly(typeIsReadOnly); - ctx->type.isExplicitHandle = isExplicitHandle; - } - - // A non-reference can be converted to a reference, - // by putting the value in a temporary variable - ctx->type.dataType.MakeReference(true); - - // Since it is a new temporary variable it doesn't have to be const - ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); - } - else if( !to.IsReference() && ctx->type.dataType.IsReference() ) - { - Dereference(ctx, generateCode); - } - } - else // if( !to.IsObjectHandle() ) - { - if( !to.IsReference() ) - { - // reference to handle -> object - // handle -> object - // reference -> object - - // An implicit handle can be converted to an object by adding a check for null pointer - if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle ) - { - if( generateCode ) - { - if( ctx->type.dataType.IsReference() ) - { - // The pointer on the stack refers to the handle - ctx->bc.Instr(asBC_ChkRefS); - } - else - { - // The pointer on the stack refers to the object - ctx->bc.Instr(asBC_CHKREF); - } - } - - ctx->type.dataType.MakeHandle(false); - } - - // A const object can be converted to a non-const object through a copy - if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() && - allowObjectConstruct ) - { - // Does the object type allow a copy to be made? - if( ctx->type.dataType.CanBeCopied() ) - { - if( generateCode ) - { - // Make a temporary object with the copy - PrepareTemporaryObject(node, ctx); - } - - // In case the object was already in a temporary variable, then the function - // didn't really do anything so we need to remove the constness here - ctx->type.dataType.MakeReadOnly(false); - - // Add the cost for the copy - cost += asCC_TO_OBJECT_CONV; - } - } - - if( ctx->type.dataType.IsReference() ) - { - // This may look strange, but a value type allocated on the stack is already - // correct, so nothing should be done other than remove the mark as reference. - // For types allocated on the heap, it is necessary to dereference the pointer - // that is currently on the stack - if( IsVariableOnHeap(ctx->type.stackOffset) ) - Dereference(ctx, generateCode); - else - ctx->type.dataType.MakeReference(false); - } - - // A non-const object can be converted to a const object directly - if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() ) - { - ctx->type.dataType.MakeReadOnly(true); - } - } - else // if( to.IsReference() ) - { - // reference to handle -> reference - // handle -> reference - // object -> reference - - if( ctx->type.dataType.IsReference() ) - { - if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ) - { - // ASHANDLE objects are really value types, so explicit handle can be removed - ctx->type.isExplicitHandle = false; - ctx->type.dataType.MakeHandle(false); - } - - // A reference to a handle can be converted to a reference to an object - // by first reading the address, then verifying that it is not null - if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle ) - { - ctx->type.dataType.MakeHandle(false); - if( generateCode ) - ctx->bc.Instr(asBC_ChkRefS); - } - - // 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() ) - { - // A reference to a const can be converted to a reference to a - // non-const by copying the object to a temporary variable - ctx->type.dataType.MakeReadOnly(false); - - if( generateCode ) - { - // 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); - } - - // Add the cost for the copy - cost += asCC_TO_OBJECT_CONV; - } - } - else // if( !ctx->type.dataType.IsReference() ) - { - // A non-reference handle can be converted to a non-handle reference by checking against null handle - if( ctx->type.dataType.IsObjectHandle() ) - { - bool readOnly = false; - if( ctx->type.dataType.IsHandleToConst() ) - readOnly = true; - - if( generateCode ) - { - if( ctx->type.isVariable ) - ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset); - else - ctx->bc.Instr(asBC_CHKREF); - } - ctx->type.dataType.MakeHandle(false); - ctx->type.dataType.MakeReference(true); - - // Make sure a handle to const isn't converted to non-const reference - if( readOnly ) - ctx->type.dataType.MakeReadOnly(true); - } - else - { - // 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) && - (ctx->type.isVariable || ctx->type.isTemporary) && - !IsVariableOnHeap(ctx->type.stackOffset) ) - { - // Actually the pointer is already pushed on the stack in - // CompileVariableAccess, so we don't need to do anything else - } - else if( generateCode ) - { - // A non-reference can be converted to a reference, - // by putting the value in a temporary variable - - // If the input type is read-only we'll need to temporarily - // remove this constness, otherwise the assignment will fail - bool typeIsReadOnly = ctx->type.dataType.IsReadOnly(); - ctx->type.dataType.MakeReadOnly(false); - - // 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); - - ctx->type.dataType.MakeReadOnly(typeIsReadOnly); - - // Add the cost for the copy - cost += asCC_TO_OBJECT_CONV; - } - - // This may look strange as the conversion was to make the expression a reference - // but a value type allocated on the stack is a reference even without the type - // being marked as such. - 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()); - } - } - } - - return cost; -} - -asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *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 ); - if( !objType || (objType->flags & asOBJ_REF) ) - return asCC_NO_CONV; - - // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference - asCArray funcs; - for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]]; - if( func->parameterTypes.GetLength() == 1 && - func->parameterTypes[0].IsPrimitive() && - !(func->inOutFlags[0] & asTM_OUTREF) ) - { - funcs.PushLast(func->id); - } - } - - if( funcs.GetLength() == 0 ) - return asCC_NO_CONV; - - // Check if it is possible to choose a best match - asSExprContext arg(engine); - arg.type = ctx->type; - arg.exprNode = ctx->exprNode; // Use the same node for compiler messages - 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 ) - return asCC_NO_CONV; - - if( !generateCode ) - { - ctx->type.Set(to); - return cost; - } - - // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function - - // Clear the type of ctx, as the type is moved to the arg - ctx->type.SetDummy(); - - // Value types and script types are allocated through the constructor - asCTypeInfo tempObj; - tempObj.dataType = to; - tempObj.stackOffset = (short)AllocateVariable(to, true); - tempObj.dataType.MakeReference(true); - tempObj.isTemporary = true; - tempObj.isVariable = true; - - bool onHeap = IsVariableOnHeap(tempObj.stackOffset); - - // Push the address of the object on the stack - if( onHeap ) - ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); - - PrepareFunctionCall(funcs[0], &ctx->bc, args); - MoveArgsToStack(funcs[0], &ctx->bc, args, false); - - if( !(objType->flags & asOBJ_REF) ) - { - // If the object is allocated on the stack, then call the constructor as a normal function - if( onHeap ) - { - int offset = 0; - asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); - for( asUINT n = 0; n < args.GetLength(); n++ ) - offset += descr->parameterTypes[n].GetSizeOnStackDWords(); - - ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset); - } - else - ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - - PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType()); - - // Add tag that the object has been initialized - ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); - - // The constructor doesn't return anything, - // so we have to manually inform the type of - // the return value - ctx->type = tempObj; - if( !onHeap ) - ctx->type.dataType.MakeReference(false); - - // Push the address of the object on the stack again - ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - } - else - { - asASSERT( objType->flags & asOBJ_SCOPED ); - - // Call the factory to create the reference type - PerformFunctionCall(funcs[0], ctx, false, &args); - } - - return cost; -} - -void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType) -{ - asASSERT(from->type.isConstant); - - // TODO: node should be the node of the value that is - // converted (not the operator that provokes the implicit - // conversion) - - // If the base type is correct there is no more to do - if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return; - - // References cannot be constants - if( from->type.dataType.IsReference() ) return; - - if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) || - (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) ) - { - if( from->type.dataType.IsFloatType() || - from->type.dataType.IsDoubleType() || - from->type.dataType.IsUnsignedType() || - from->type.dataType.IsIntegerType() ) - { - // Transform the value - // Float constants can be implicitly converted to int - if( from->type.dataType.IsFloatType() ) - { - float fc = from->type.floatValue; - int ic = int(fc); - - if( float(ic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.intValue = ic; - } - // Double constants can be implicitly converted to int - else if( from->type.dataType.IsDoubleType() ) - { - double fc = from->type.doubleValue; - int ic = int(fc); - - if( double(ic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.intValue = 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); - } - - // 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; - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - // Convert to 32bit - from->type.intValue = int(from->type.qwordValue); - } - 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; - } - - // Set the resulting type - if( to.IsEnumType() ) - from->type.dataType = to; - else - from->type.dataType = asCDataType::CreatePrimitive(ttInt, true); - } - - // Check if a downsize is necessary - if( to.IsIntegerType() && - from->type.dataType.IsIntegerType() && - from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() ) - { - // Verify if it is possible - if( to.GetSizeInMemoryBytes() == 1 ) - { - if( char(from->type.intValue) != from->type.intValue ) - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.byteValue = char(from->type.intValue); - } - else if( to.GetSizeInMemoryBytes() == 2 ) - { - if( short(from->type.intValue) != from->type.intValue ) - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.wordValue = short(from->type.intValue); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - } - } - else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 ) - { - // Float constants can be implicitly converted to int - if( from->type.dataType.IsFloatType() ) - { - float fc = from->type.floatValue; - asINT64 ic = asINT64(fc); - - if( float(ic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); - from->type.qwordValue = ic; - } - // Double constants can be implicitly converted to int - else if( from->type.dataType.IsDoubleType() ) - { - double fc = from->type.doubleValue; - asINT64 ic = asINT64(fc); - - if( double(ic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); - from->type.qwordValue = ic; - } - else if( from->type.dataType.IsUnsignedType() ) - { - // Convert to 64bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.qwordValue = from->type.byteValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.qwordValue = from->type.wordValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.qwordValue = from->type.dwordValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 8 ) - { - if( asINT64(from->type.qwordValue) < 0 ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); - } - } - - 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; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.qwordValue = (short)from->type.wordValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.qwordValue = from->type.intValue; - - from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); - } - } - else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 ) - { - if( from->type.dataType.IsFloatType() ) - { - float fc = from->type.floatValue; - // 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)); - - if( float(uic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true); - from->type.intValue = 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; - // 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)); - - if( double(uic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true); - from->type.intValue = uic; - - // Try once more, in case of a smaller type - ImplicitConversionConstant(from, to, node, convType); - } - 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( 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( 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; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.intValue = (short)from->type.wordValue; - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true); - - // Try once more, in case of a smaller type - ImplicitConversionConstant(from, to, node, convType); - } - else if( from->type.dataType.IsUnsignedType() && - from->type.dataType.GetSizeInMemoryBytes() < 4 ) - { - // Convert to 32bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.dwordValue = from->type.byteValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.dwordValue = from->type.wordValue; - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true); - - // Try once more, in case of a smaller type - ImplicitConversionConstant(from, to, node, convType); - } - else if( from->type.dataType.IsUnsignedType() && - from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() ) - { - // Verify if it is possible - if( to.GetSizeInMemoryBytes() == 1 ) - { - if( asBYTE(from->type.dwordValue) != from->type.dwordValue ) - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.byteValue = asBYTE(from->type.dwordValue); - } - else if( to.GetSizeInMemoryBytes() == 2 ) - { - if( asWORD(from->type.dwordValue) != from->type.dwordValue ) - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.wordValue = asWORD(from->type.dwordValue); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - } - } - else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 ) - { - if( from->type.dataType.IsFloatType() ) - { - float fc = from->type.floatValue; - // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers - asQWORD uic = asQWORD(asINT64(fc)); - -#if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6 - // MSVC6 doesn't support this conversion - if( float(uic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } -#endif - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); - from->type.qwordValue = uic; - } - else if( from->type.dataType.IsDoubleType() ) - { - double fc = from->type.doubleValue; - // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers - asQWORD uic = asQWORD(asINT64(fc)); - -#if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6 - // MSVC6 doesn't support this conversion - if( double(uic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } -#endif - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); - from->type.qwordValue = 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; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.qwordValue = (asINT64)(short)from->type.wordValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.qwordValue = (asINT64)from->type.intValue; - - // Verify that it is possible to convert to unsigned without loosing negative - if( asINT64(from->type.qwordValue) < 0 ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); - } - 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( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); - } - else if( from->type.dataType.IsUnsignedType() ) - { - // Convert to 64bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.qwordValue = from->type.byteValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.qwordValue = from->type.wordValue; - else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.qwordValue = from->type.dwordValue; - - from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); - } - } - else if( to.IsFloatType() ) - { - if( from->type.dataType.IsDoubleType() ) - { - double ic = from->type.doubleValue; - float fc = float(ic); - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = 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; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - ic = (short)from->type.wordValue; - else - ic = from->type.intValue; - float fc = float(ic); - - if( int(fc) != ic ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = 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) ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = 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; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - uic = from->type.wordValue; - else - uic = from->type.dwordValue; - float fc = float(uic); - - if( (unsigned int)(fc) != uic ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = fc; - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - float fc = float((asINT64)from->type.qwordValue); - - if( asQWORD(fc) != from->type.qwordValue ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.floatValue = fc; - } - } - else if( to.IsDoubleType() ) - { - if( from->type.dataType.IsFloatType() ) - { - float ic = from->type.floatValue; - double fc = double(ic); - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = 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; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - ic = (short)from->type.wordValue; - else - ic = from->type.intValue; - double fc = double(ic); - - if( int(fc) != ic ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = fc; - } - else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - double fc = double(asINT64(from->type.qwordValue)); - - if( asINT64(fc) != asINT64(from->type.qwordValue) ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = 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; - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - uic = from->type.wordValue; - else - uic = from->type.dwordValue; - double fc = double(uic); - - if( (unsigned int)(fc) != uic ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = fc; - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - double fc = double((asINT64)from->type.qwordValue); - - if( asQWORD(fc) != from->type.qwordValue ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true); - from->type.doubleValue = fc; - } - } -} - -int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int 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 - if( lctx->methodName != "" || rctx->IsClassMethod() ) - { - Error(TXT_INVALID_OP_ON_METHOD, opNode); - return -1; - } - - // Implicit handle types should always be treated as handles in assignments - if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) ) - { - lctx->type.dataType.MakeHandle(true); - lctx->type.isExplicitHandle = true; - } - - // If the left hand expression is a property accessor, then that should be used - // to do the assignment instead of the ordinary operator. The exception is when - // the property accessor is for a handle property, and the operation is a value - // assignment. - if( (lctx->property_get || lctx->property_set) && - !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) ) - { - if( op != ttAssignment ) - { - // TODO: getset: We may actually be able to support this, if we can - // guarantee that the object reference will stay valid - // between the calls to the get and set accessors. - - // Process the property to free the memory - ProcessPropertySetAccessor(lctx, rctx, opNode); - - // Compound assignments are not allowed for properties - Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode); - return -1; - } - - // It is not allowed to do a handle assignment on a property - // accessor that doesn't take a handle in the set accessor. - if( lctx->property_set && lctx->type.isExplicitHandle ) - { - // set_opIndex has 2 arguments, where as normal setters have only 1 - asCArray& parameterTypes = - builder->GetFunctionDescription(lctx->property_set)->parameterTypes; - if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() ) - { - // Process the property to free the memory - ProcessPropertySetAccessor(lctx, rctx, opNode); - - Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode); - return -1; - } - } - - MergeExprBytecodeAndType(ctx, lctx); - - return ProcessPropertySetAccessor(ctx, rctx, opNode); - } - else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle ) - { - // Get the handle to the object that will be used for the value assignment - ProcessPropertyGetAccessor(lctx, opNode); - } - - if( lctx->type.dataType.IsPrimitive() ) - { - if( !lctx->type.isLValue ) - { - Error(TXT_NOT_LVALUE, lexpr); - return -1; - } - - if( op != ttAssignment ) - { - // Compute the operator before the assignment - asCTypeInfo lvalue = lctx->type; - - if( lctx->type.isTemporary && !lctx->type.isVariable ) - { - // The temporary variable must not be freed until the - // assignment has been performed. lvalue still holds - // the information about the temporary variable - lctx->type.isTemporary = false; - } - - asSExprContext o(engine); - CompileOperator(opNode, lctx, rctx, &o); - MergeExprBytecode(rctx, &o); - rctx->type = o.type; - - // Convert the rvalue to the right type and validate it - PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false); - - MergeExprBytecode(ctx, rctx); - lctx->type = lvalue; - - // The lvalue continues the same, either it was a variable, or a reference in the register - } - else - { - // Convert the rvalue to the right type and validate it - PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx); - - MergeExprBytecode(ctx, rctx); - MergeExprBytecode(ctx, lctx); - } - - ReleaseTemporaryVariable(rctx->type, &ctx->bc); - - PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode); - - ctx->type = lctx->type; - } - else if( lctx->type.isExplicitHandle ) - { - if( !lctx->type.isLValue ) - { - Error(TXT_NOT_LVALUE, lexpr); - return -1; - } - - // Object handles don't have any compound assignment operators - if( op != ttAssignment ) - { - asCString str; - str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf()); - Error(str, lexpr); - return -1; - } - - if( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->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)) ) - { - // Function names can be considered handles already - if( rctx->methodName == "" ) - { - asCDataType dt = rctx->type.dataType; - dt.MakeHandle(true); - dt.MakeReference(false); - - PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF); - if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf()); - Error(str, rexpr); - return -1; - } - } - } - - if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx, true) ) - { - // An overloaded assignment operator was found (or a compilation error occured) - return 0; - } - - // The object must implement the opAssign method - asCString msg; - msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format().AddressOf()); - Error(msg.AddressOf(), opNode); - return -1; - } - else - { - asCDataType dt = lctx->type.dataType; - dt.MakeReference(false); - - PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF , true); - if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf()); - Error(str, rexpr); - return -1; - } - - MergeExprBytecode(ctx, rctx); - MergeExprBytecode(ctx, lctx); - - ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE); - - PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode); - - ReleaseTemporaryVariable(rctx->type, &ctx->bc); - - ctx->type = lctx->type; - - // After the handle assignment the original handle is left on the stack - ctx->type.dataType.MakeReference(false); - } - } - else // if( lctx->type.dataType.IsObject() ) - { - // The lvalue reference may be marked as a temporary, if for example - // it was originated as a handle returned from a function. In such - // cases it must be possible to assign values to it anyway. - if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle ) - { - // Convert the handle to a object reference - asCDataType to; - to = lctx->type.dataType; - to.MakeHandle(false); - ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV); - lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is - } - - // Check for overloaded assignment operator - if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) ) - { - // An overloaded assignment operator was found (or a compilation error occured) - return 0; - } - - // No registered operator was found. In case the operation is a direct - // assignment and the rvalue is the same type as the lvalue, then we can - // still use the byte-for-byte copy to do the assignment - - if( op != ttAssignment ) - { - asCString str; - str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf()); - Error(str, lexpr); - return -1; - } - - // If the left hand expression is simple, i.e. without any - // function calls or allocations of memory, then we can avoid - // doing a copy of the right hand expression (done by PrepareArgument). - // Instead the reference to the value can be placed directly on the - // stack. - // - // This optimization should only be done for value types, where - // 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(); - - // Implicitly convert the rvalue to the type of the lvalue - bool needConversion = false; - if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) ) - needConversion = true; - - if( !simpleExpr || needConversion ) - { - asCDataType dt = lctx->type.dataType; - dt.MakeReference(true); - dt.MakeReadOnly(true); - int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion); - if( r < 0 ) - return -1; - if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf()); - Error(str, rexpr); - return -1; - } - } - else - { - // Process any property accessor first, before placing the final reference on the stack - ProcessPropertyGetAccessor(rctx, rexpr); - - if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) ) - rctx->bc.Instr(asBC_RDSPtr); - } - - MergeExprBytecode(ctx, rctx); - MergeExprBytecode(ctx, lctx); - - if( !simpleExpr || needConversion ) - { - if( (rctx->type.isVariable || rctx->type.isTemporary) ) - { - if( !IsVariableOnHeap(rctx->type.stackOffset) ) - // TODO: runtime optimize: Actually the reference can be pushed on the stack directly - // as the value allocated on the stack is guaranteed to be safe. - // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF - ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE); - else - ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE); - } - } - - PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode); - - ReleaseTemporaryVariable(rctx->type, &ctx->bc); - - ctx->type = lctx->type; - } - - return 0; -} - -int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx) -{ - asCScriptNode *lexpr = expr->firstChild; - if( lexpr->next ) - { - // Compile the two expression terms - asSExprContext lctx(engine), rctx(engine); - int rr = CompileAssignment(lexpr->next->next, &rctx); - int lr = CompileCondition(lexpr, &lctx); - - if( lr >= 0 && rr >= 0 ) - return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next); - - // Since the operands failed, the assignment was not computed - ctx->type.SetDummy(); - return -1; - } - - return CompileCondition(lexpr, ctx); -} - -int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx) -{ - asCTypeInfo ctype; - - // Compile the conditional expression - asCScriptNode *cexpr = expr->firstChild; - if( cexpr->next ) - { - //------------------------------- - // Compile the condition - asSExprContext e(engine); - int r = CompileExpression(cexpr, &e); - if( r < 0 ) - e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); - if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - { - Error(TXT_EXPR_MUST_BE_BOOL, cexpr); - e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); - } - ctype = e.type; - - ProcessPropertyGetAccessor(&e, cexpr); - - if( e.type.dataType.IsReference() ) ConvertToVariable(&e); - ProcessDeferredParams(&e); - - //------------------------------- - // Compile the left expression - asSExprContext le(engine); - int lr = CompileAssignment(cexpr->next, &le); - - //------------------------------- - // Compile the right expression - asSExprContext re(engine); - int rr = CompileAssignment(cexpr->next->next, &re); - - if( lr >= 0 && rr >= 0 ) - { - // Don't allow any operators on expressions that take address of class method - if( le.IsClassMethod() || re.IsClassMethod() ) - { - Error(TXT_INVALID_OP_ON_METHOD, expr); - return -1; - } - - ProcessPropertyGetAccessor(&le, cexpr->next); - ProcessPropertyGetAccessor(&re, cexpr->next->next); - - 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() ) - { - asCDataType to = re.type.dataType; - to.MakeReference(false); - to.MakeReadOnly(true); - ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV); - } - else if( le.type.IsNullConstant() ) - { - asCDataType to = re.type.dataType; - to.MakeHandle(true); - ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV); - } - - // Allow either case to be converted to const @ if the other is const @ - if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) ) - { - le.type.dataType.MakeHandleToConst(true); - re.type.dataType.MakeHandleToConst(true); - } - - //--------------------------------- - // Output the byte code - int afterLabel = nextLabel++; - int elseLabel = nextLabel++; - - // If left expression is void, then we don't need to store the result - if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) ) - { - // Put the code for the condition expression on the output - MergeExprBytecode(ctx, &e); - - // Added the branch decision - ctx->type = e.type; - ConvertToVariable(ctx); - ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); - ctx->bc.Instr(asBC_ClrHi); - ctx->bc.InstrDWORD(asBC_JZ, elseLabel); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - - // Add the left expression - MergeExprBytecode(ctx, &le); - ctx->bc.InstrINT(asBC_JMP, afterLabel); - - // Add the right expression - ctx->bc.Label((short)elseLabel); - MergeExprBytecode(ctx, &re); - ctx->bc.Label((short)afterLabel); - - // Make sure both expressions have the same type - if( le.type.dataType != re.type.dataType ) - Error(TXT_BOTH_MUST_BE_SAME, expr); - - // Set the type of the result - ctx->type = le.type; - } - else - { - // Allocate temporary variable and copy the result to that one - asCTypeInfo temp; - temp = le.type; - temp.dataType.MakeReference(false); - temp.dataType.MakeReadOnly(false); - - // Make sure the variable isn't used in any of the expressions, - // as it would be overwritten which may cause crashes or less visible bugs - int l = int(reservedVariables.GetLength()); - e.bc.GetVarsUsed(reservedVariables); - le.bc.GetVarsUsed(reservedVariables); - re.bc.GetVarsUsed(reservedVariables); - int offset = AllocateVariable(temp.dataType, true, false); - reservedVariables.SetLength(l); - - temp.SetVariable(temp.dataType, offset, true); - - // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject() - - CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr); - - // Put the code for the condition expression on the output - MergeExprBytecode(ctx, &e); - - // Add the branch decision - ctx->type = e.type; - ConvertToVariable(ctx); - ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); - ctx->bc.Instr(asBC_ClrHi); - ctx->bc.InstrDWORD(asBC_JZ, elseLabel); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - - // Assign the result of the left expression to the temporary variable - asCTypeInfo rtemp; - rtemp = temp; - if( rtemp.dataType.IsObjectHandle() ) - rtemp.isExplicitHandle = true; - - PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true); - MergeExprBytecode(ctx, &le); - - if( !rtemp.dataType.IsPrimitive() ) - { - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - rtemp.dataType.MakeReference(IsVariableOnHeap(offset)); - } - asCTypeInfo result; - result = rtemp; - PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next); - if( !result.dataType.IsPrimitive() ) - ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer) - - // Release the old temporary variable - ReleaseTemporaryVariable(le.type, &ctx->bc); - - ctx->bc.InstrINT(asBC_JMP, afterLabel); - - // Start of the right expression - ctx->bc.Label((short)elseLabel); - - // Copy the result to the same temporary variable - PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true); - MergeExprBytecode(ctx, &re); - - if( !rtemp.dataType.IsPrimitive() ) - { - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - rtemp.dataType.MakeReference(IsVariableOnHeap(offset)); - } - result = rtemp; - PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next); - if( !result.dataType.IsPrimitive() ) - ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer) - - // Release the old temporary variable - ReleaseTemporaryVariable(re.type, &ctx->bc); - - ctx->bc.Label((short)afterLabel); - - // Make sure both expressions have the same type - if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) ) - Error(TXT_BOTH_MUST_BE_SAME, expr); - - // Set the temporary variable as output - ctx->type = rtemp; - ctx->type.isExplicitHandle = isExplicitHandle; - - if( !ctx->type.dataType.IsPrimitive() ) - { - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - ctx->type.dataType.MakeReference(IsVariableOnHeap(offset)); - } - - // Make sure the output isn't marked as being a literal constant - ctx->type.isConstant = false; - } - } - else - { - ctx->type.SetDummy(); - return -1; - } - } - else - return CompileExpression(cexpr, ctx); - - return 0; -} - -int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *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+ - - // The algorithm that I've implemented here is similar to - // Djikstra's Shunting Yard algorithm, though I didn't know it at the time. - // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm - - // Count the nodes in order to preallocate the buffers - int count = 0; - asCScriptNode *node = expr->firstChild; - while( node ) - { - count++; - node = node->next; - } - - asCArray stack(count); - asCArray stack2(count); - - node = expr->firstChild; - while( node ) - { - int precedence = GetPrecedence(node); - - while( stack.GetLength() > 0 && - precedence <= GetPrecedence(stack[stack.GetLength()-1]) ) - stack2.PushLast(stack.PopLast()); - - stack.PushLast(node); - - node = node->next; - } - - while( stack.GetLength() > 0 ) - stack2.PushLast(stack.PopLast()); - - // Compile the postfix formatted expression - return CompilePostFixExpression(&stack2, ctx); -} - -int asCCompiler::CompilePostFixExpression(asCArray *postfix, asSExprContext *ctx) -{ - // Shouldn't send any byte code - asASSERT(ctx->bc.GetLastInstr() == -1); - - // Set the context to a dummy type to avoid further - // errors in case the expression fails to compile - ctx->type.SetDummy(); - - // Evaluate the operands and operators - 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); - expr.PushLast(e); - e->exprNode = node; - ret = CompileExpressionTerm(node, e); - } - else - { - asSExprContext *r = expr.PopLast(); - asSExprContext *l = expr.PopLast(); - - // Now compile the operator - asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine); - ret = CompileOperator(node, l, r, e); - - expr.PushLast(e); - - // Free the operands - l->Clear(); - free.PushLast(l); - r->Clear(); - free.PushLast(r); - } - } - - if( ret == 0 ) - { - asASSERT(expr.GetLength() == 1); - - // The final result should be moved to the output context - MergeExprBytecodeAndType(ctx, expr[0]); - } - - // Clean up - for( asUINT e = 0; e < expr.GetLength(); e++ ) - asDELETE(expr[e], asSExprContext); - for( asUINT f = 0; f < free.GetLength(); f++ ) - asDELETE(free[f], asSExprContext); - - return ret; -} - -int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx) -{ - // Shouldn't send any byte code - asASSERT(ctx->bc.GetLastInstr() == -1); - - // Set the type as a dummy by default, in case of any compiler errors - ctx->type.SetDummy(); - - // Compile the value node - asCScriptNode *vnode = node->firstChild; - while( vnode->nodeType != snExprValue ) - vnode = vnode->next; - - asSExprContext v(engine); - int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r; - - // Compile post fix operators - asCScriptNode *pnode = vnode->next; - while( pnode ) - { - r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r; - pnode = pnode->next; - } - - // Compile pre fix operators - pnode = vnode->prev; - while( pnode ) - { - r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r; - pnode = pnode->prev; - } - - // Return the byte code and final type description - MergeExprBytecodeAndType(ctx, &v); - - return 0; -} - -int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType) -{ - bool found = false; - - // It is a local variable or parameter? - // This is not accessible by default arg expressions - sVariable *v = 0; - if( !isCompilingDefaultArg && scope == "" && !objType && variables ) - v = variables->GetVariable(name.AddressOf()); - if( v ) - { - found = true; - - if( v->isPureConstant ) - ctx->type.SetConstantQW(v->type, v->constantValue); - else if( v->type.IsPrimitive() ) - { - if( v->type.IsReference() ) - { - // Copy the reference into the register - ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset); - ctx->bc.Instr(asBC_PopRPtr); - ctx->type.Set(v->type); - } - else - ctx->type.SetVariable(v->type, v->stackOffset, false); - - ctx->type.isLValue = true; - } - else - { - ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset); - ctx->type.SetVariable(v->type, v->stackOffset, false); - - // If the variable is allocated on the heap we have a reference, - // otherwise the actual object pointer is pushed on the stack. - if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true); - - // Implicitly dereference handle parameters sent by reference - if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) ) - ctx->bc.Instr(asBC_RDSPtr); - - ctx->type.isLValue = true; - } - } - - // Is it a class member? - // This is not accessible by default arg expressions - if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) ) - { - if( name == THIS_TOKEN && !objType ) - { - asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly); - - // The object pointer is located at stack position 0 - ctx->bc.InstrSHORT(asBC_PSF, 0); - ctx->type.SetVariable(dt, 0, false); - ctx->type.dataType.MakeReference(true); - ctx->type.isLValue = true; - - found = true; - } - - if( !found ) - { - // See if there are any matching property accessors - asSExprContext access(engine); - if( objType ) - access.type.Set(asCDataType::CreateObject(objType, false)); - else - access.type.Set(asCDataType::CreateObject(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); - r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true); - } - if( r == 0 ) - { - // Normal property access - r = FindPropertyAccessor(name, &access, errNode, 0, true); - } - if( r < 0 ) return -1; - if( access.property_get || access.property_set ) - { - if( !objType ) - { - // Prepare the bytecode for the member access - // This is only done when accessing through the implicit this pointer - ctx->bc.InstrSHORT(asBC_PSF, 0); - } - MergeExprBytecodeAndType(ctx, &access); - - found = true; - } - } - - if( !found ) - { - asCDataType dt; - if( objType ) - dt = asCDataType::CreateObject(objType, false); - else - dt = asCDataType::CreateObject(outFunc->objectType, false); - asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf()); - if( prop ) - { - if( !objType ) - { - // 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(dt, 0, false); - ctx->type.dataType.MakeReference(true); - Dereference(ctx, true); - } - - // TODO: This is the same as what is in CompileExpressionPostOp - // Put the offset on the stack - ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt)); - - if( prop->type.IsReference() ) - ctx->bc.Instr(asBC_RDSPtr); - - // Reference to primitive must be stored in the temp register - if( prop->type.IsPrimitive() ) - { - // TODO: runtime optimize: The ADD offset command should store the reference in the register directly - ctx->bc.Instr(asBC_PopRPtr); - } - - // Set the new type (keeping info about temp variable) - ctx->type.dataType = prop->type; - ctx->type.dataType.MakeReference(true); - ctx->type.isVariable = false; - ctx->type.isLValue = true; - - if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() ) - { - // Objects that are members are not references - ctx->type.dataType.MakeReference(false); - } - - // If the object reference is const, the property will also be const - ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly); - - found = true; - } - else if( outFunc->objectType ) - { - // If it is not a property, it may still be the name of a method which can be used to create delegates - asCObjectType *ot = outFunc->objectType; - asCScriptFunction *func = 0; - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - if( engine->scriptFunctions[ot->methods[n]]->name == name ) - { - func = engine->scriptFunctions[ot->methods[n]]; - break; - } - } - - if( func ) - { - // An object method was found. Keep the name of the method in the expression, but - // don't actually modify the bytecode at this point since it is not yet known what - // the method will be used for, or even what overloaded method should be used. - ctx->methodName = name; - - // Place the object pointer on the stack, as if the expression was this.func - if( !objType ) - { - // 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.dataType.MakeReference(true); - Dereference(ctx, true); - } - - found = true; - } - } - } - } - - // Recursively search parent namespaces for global entities - asCString currScope = scope; - if( scope == "" ) - currScope = outFunc->nameSpace->name; - while( !found && !noGlobal && !objType ) - { - asSNameSpace *ns = DetermineNameSpace(currScope); - - // Is it a global property? - if( !found && ns ) - { - // See if there are any matching global property accessors - asSExprContext 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); - r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns); - } - if( r == 0 ) - { - // Normal property access - r = FindPropertyAccessor(name, &access, errNode, ns); - } - if( r < 0 ) return -1; - if( access.property_get || access.property_set ) - { - // Prepare the bytecode for the function call - MergeExprBytecodeAndType(ctx, &access); - - found = true; - } - - // See if there is any matching global property - if( !found ) - { - bool isCompiled = true; - bool isPureConstant = false; - bool isAppProp = false; - asQWORD constantValue = 0; - asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp); - if( prop ) - { - found = true; - - // Verify that the global property has been compiled already - if( isCompiled ) - { - if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) ) - { - ctx->type.dataType.MakeHandle(true); - ctx->type.isExplicitHandle = true; - } - - // If the global property is a pure constant - // 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); - else - { - // A shared type must not access global vars, unless they - // too are shared, e.g. application registered vars - if( outFunc->IsShared() ) - { - if( !isAppProp ) - { - asCString str; - str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf()); - Error(str, errNode); - - // Allow the compilation to continue to catch other problems - } - } - - ctx->type.Set(prop->type); - ctx->type.isLValue = true; - - if( ctx->type.dataType.IsPrimitive() ) - { - // Load the address of the variable into the register - ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue()); - - ctx->type.dataType.MakeReference(true); - } - else - { - // Push the address of the variable on the stack - ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue()); - - // If the object is a value type or a non-handle variable to a reference type, - // then we must validate the existance as it could potentially be accessed - // before it is initialized. - if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) || - !ctx->type.dataType.IsObjectHandle() ) - { - // TODO: runtime optimize: This is not necessary for application registered properties - ctx->bc.Instr(asBC_ChkRefS); - } - - // 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) || - ctx->type.dataType.IsObjectHandle() ) - { - ctx->type.dataType.MakeReference(true); - } - else - { - asASSERT( (ctx->type.dataType.GetObjectType()->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); - } - } - } - } - else - { - asCString str; - str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf()); - Error(str, errNode); - return -1; - } - } - } - } - - // Is it the name of a global function? - if( !noFunction && !found && ns ) - { - asCArray funcs; - - builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); - - if( funcs.GetLength() > 0 ) - { - found = true; - - // Defer the evaluation of which function until it is actually used - // Store the namespace and name of the function for later - ctx->type.SetUndefinedFuncHandle(engine); - ctx->methodName = ns ? ns->name + "::" + name : name; - } - } - - // Is it an enum value? - if( !found ) - { - // The enum type may be declared in a namespace too - asCObjectType *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); - } - - asDWORD value = 0; - asCDataType dt; - if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) ) - { - // scoped enum value found - found = true; - } - else if( !engine->ep.requireEnumScope ) - { - // Look for the enum value without explicitly informing the enum type - asSNameSpace *ns = DetermineNameSpace(currScope); - int e = 0; - if( ns ) - e = builder->GetEnumValue(name.AddressOf(), dt, value, ns); - if( e ) - { - found = true; - if( e == 2 ) - { - // Ambiguous enum value: Save the name for resolution later. - // The ambiguity could be resolved now, but I hesitate - // to store too much information in the context. - ctx->enumValue = name.AddressOf(); - - // We cannot set a dummy value because it will pass through - // cleanly as an integer. - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0); - return 0; - } - } - } - - if( found ) - { - // Even if the enum type is not shared, and we're compiling a shared object, - // the use of the values are still allowed, since they are treated as constants. - - // an enum value was resolved - ctx->type.SetConstantDW(dt, value); - } - else - { - // If nothing was found because the scope doesn't match a namespace or an enum - // then this should be reported as an error and the search interrupted - if( !ns && !scopeType ) - { - ctx->type.SetDummy(); - asCString str; - str.Format(TXT_UNKNOWN_SCOPE_s, currScope.AddressOf()); - Error(str, errNode); - return -1; - } - } - } - - if( !found ) - { - if( currScope == "" || currScope == "::" ) - break; - - // Move up to parent namespace - int pos = currScope.FindLast("::"); - if( pos >= 0 ) - currScope = currScope.SubString(0, pos); - else - currScope = "::"; - } - } - - // The name doesn't match any variable - if( !found ) - { - // Give dummy value - ctx->type.SetDummy(); - - if( !isOptional ) - { - // Prepend the scope to the name for the error message - asCString ename; - if( scope != "" && scope != "::" ) - ename = scope + "::"; - else - ename = scope; - ename += name; - - asCString str; - str.Format(TXT_s_NOT_DECLARED, ename.AddressOf()); - Error(str, errNode); - - // Declare the variable now so that it will not be reported again - 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()); - asASSERT(v); - if( v ) v->isInitialized = true; - } - - // Return -1 to signal that the variable wasn't found - return -1; - } - - return 0; -} - -int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx) -{ - // Shouldn't receive any byte code - asASSERT(ctx->bc.GetLastInstr() == -1); - - asCScriptNode *vnode = node->firstChild; - ctx->exprNode = vnode; - if( vnode->nodeType == snVariableAccess ) - { - // Determine the scope resolution of the variable - asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode); - - // Determine the name of the variable - asASSERT(vnode->nodeType == snIdentifier ); - asCString name(&script->code[vnode->tokenPos], vnode->tokenLength); - - return CompileVariableAccess(name, scope, ctx, node); - } - else if( vnode->nodeType == snConstant ) - { - if( vnode->tokenType == ttIntConstant ) - { - asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); - - asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0); - - // Do we need 64 bits? - // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid - // incorrect warnings about changing signs if the value is assigned to a 64bit variable - if( val>>31 ) - { - // Only if the value uses the last bit of a 64bit word do we consider the number unsigned - if( val>>63 ) - ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val); - else - ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val); - } - else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val)); - } - else if( vnode->tokenType == ttBitsConstant ) - { - 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); - - // Do we need 64 bits? - if( val>>32 ) - ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val); - else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val)); - } - else if( vnode->tokenType == ttFloatConstant ) - { - asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); - - // TODO: Check for overflow - - size_t numScanned; - float v = float(asStringScanDouble(value.AddressOf(), &numScanned)); - ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v); -#ifndef AS_USE_DOUBLE_AS_FLOAT - // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix) - asASSERT(numScanned == vnode->tokenLength - 1); -#endif - } - else if( vnode->tokenType == ttDoubleConstant ) - { - asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); - - // TODO: Check for overflow - - size_t numScanned; - double v = asStringScanDouble(value.AddressOf(), &numScanned); - ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v); - asASSERT(numScanned == vnode->tokenLength); - } - else if( vnode->tokenType == ttTrue || - vnode->tokenType == ttFalse ) - { -#if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0); -#else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0); -#endif - } - else if( vnode->tokenType == ttStringConstant || - vnode->tokenType == ttMultilineStringConstant || - vnode->tokenType == ttHeredocStringConstant ) - { - asCString str; - asCScriptNode *snode = vnode->firstChild; - if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals ) - { - // Treat the single quoted string as a single character literal - 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 ) - { - // This is the start of a UTF8 encoded character. We need to decode it - val = asStringDecodeUTF8(str.AddressOf(), 0); - if( val == (asDWORD)-1 ) - Error(TXT_INVALID_CHAR_LITERAL, vnode); - } - else - { - val = ProcessStringConstant(str, snode); - if( val == (asDWORD)-1 ) - Error(TXT_INVALID_CHAR_LITERAL, vnode); - } - - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val); - } - else - { - // Process the string constants - while( snode ) - { - asCString cat; - if( snode->tokenType == ttStringConstant ) - { - cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2); - ProcessStringConstant(cat, snode); - } - else if( snode->tokenType == ttMultilineStringConstant ) - { - if( !engine->ep.allowMultilineStrings ) - Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode); - - cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2); - ProcessStringConstant(cat, snode); - } - else if( snode->tokenType == ttHeredocStringConstant ) - { - cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6); - ProcessHeredocStringConstant(cat, snode); - } - - str += cat; - - snode = snode->next; - } - - // Call the string factory function to create a string object - asCScriptFunction *descr = engine->stringFactory; - if( descr == 0 ) - { - // Error - Error(TXT_STRINGS_NOT_RECOGNIZED, vnode); - - // Give dummy value - ctx->type.SetDummy(); - return -1; - } - 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() ) - { - useVariable = true; - stackOffset = AllocateVariable(descr->returnType, true); - ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset)); - } - - PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset); - } - } - } - else if( vnode->tokenType == ttNull ) - { - ctx->bc.Instr(asBC_PshNull); - ctx->type.SetNullConstant(); - } - else - asASSERT(false); - } - else if( vnode->nodeType == snFunctionCall ) - { - // Determine the scope resolution - asCString scope = builder->GetScopeFromNode(vnode->firstChild, script); - - return CompileFunctionCall(vnode, ctx, 0, false, scope); - } - else if( vnode->nodeType == snConstructCall ) - { - CompileConstructCall(vnode, ctx); - } - else if( vnode->nodeType == snAssignment ) - { - asSExprContext e(engine); - int r = CompileAssignment(vnode, &e); - if( r < 0 ) - { - ctx->type.SetDummy(); - return r; - } - MergeExprBytecodeAndType(ctx, &e); - } - else if( vnode->nodeType == snCast ) - { - // Implement the cast operator - CompileConversion(vnode, ctx); - } - else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid ) - { - // This is a void expression - ctx->type.SetVoidExpression(); - } - else - asASSERT(false); - - return 0; -} - -asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences) -{ - int charLiteral = -1; - - // Process escape sequences - asCArray str((int)cstr.GetLength()); - - for( asUINT n = 0; n < cstr.GetLength(); n++ ) - { -#ifdef AS_DOUBLEBYTE_CHARSET - // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings - if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 ) - { - // This is the lead character of a double byte character - // include the trail character without checking it's value. - str.PushLast(cstr[n]); - n++; - str.PushLast(cstr[n]); - continue; - } -#endif - - asUINT val; - - if( processEscapeSequences && cstr[n] == '\\' ) - { - ++n; - if( n == cstr.GetLength() ) - { - if( charLiteral == -1 ) charLiteral = 0; - return charLiteral; - } - - // Hexadecimal escape sequences will allow the construction of - // invalid unicode sequences, but the string should also work as - // a bytearray so we must support this. The code for working with - // unicode text must be prepared to handle invalid unicode sequences - if( cstr[n] == 'x' || cstr[n] == 'X' ) - { - ++n; - if( n == cstr.GetLength() ) break; - - val = 0; - int c = engine->ep.stringEncoding == 1 ? 4 : 2; - for( ; c > 0 && n < cstr.GetLength(); c--, n++ ) - { - if( cstr[n] >= '0' && cstr[n] <= '9' ) - val = val*16 + cstr[n] - '0'; - else if( cstr[n] >= 'a' && cstr[n] <= 'f' ) - val = val*16 + cstr[n] - 'a' + 10; - else if( cstr[n] >= 'A' && cstr[n] <= 'F' ) - val = val*16 + cstr[n] - 'A' + 10; - else - break; - } - - // Rewind one, since the loop will increment it again - n--; - - // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars - if( engine->ep.stringEncoding == 0 ) - { - str.PushLast((asBYTE)val); - } - else - { -#ifndef AS_BIG_ENDIAN - str.PushLast((asBYTE)val); - str.PushLast((asBYTE)(val>>8)); -#else - str.PushLast((asBYTE)(val>>8)); - str.PushLast((asBYTE)val); -#endif - } - if( charLiteral == -1 ) charLiteral = val; - continue; - } - else if( cstr[n] == 'u' || cstr[n] == 'U' ) - { - // \u expects 4 hex digits - // \U expects 8 hex digits - bool expect2 = cstr[n] == 'u'; - int c = expect2 ? 4 : 8; - - val = 0; - - for( ; c > 0; c-- ) - { - ++n; - if( n == cstr.GetLength() ) break; - - if( cstr[n] >= '0' && cstr[n] <= '9' ) - val = val*16 + cstr[n] - '0'; - else if( cstr[n] >= 'a' && cstr[n] <= 'f' ) - val = val*16 + cstr[n] - 'a' + 10; - else if( cstr[n] >= 'A' && cstr[n] <= 'F' ) - val = val*16 + cstr[n] - 'A' + 10; - else - break; - } - - if( c != 0 ) - { - // Give warning about invalid code point - // TODO: Need code position for warning - asCString msg; - msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8); - Warning(msg, node); - continue; - } - } - else - { - if( cstr[n] == '"' ) - val = '"'; - else if( cstr[n] == '\'' ) - val = '\''; - else if( cstr[n] == 'n' ) - val = '\n'; - else if( cstr[n] == 'r' ) - val = '\r'; - else if( cstr[n] == 't' ) - val = '\t'; - else if( cstr[n] == '0' ) - val = '\0'; - else if( cstr[n] == '\\' ) - val = '\\'; - else - { - // Invalid escape sequence - Warning(TXT_INVALID_ESCAPE_SEQUENCE, node); - continue; - } - } - } - else - { - if( engine->ep.scanner == 1 && (cstr[n] & 0x80) ) - { - unsigned int len; - val = asStringDecodeUTF8(&cstr[n], &len); - if( val == 0xFFFFFFFF ) - { - // Incorrect UTF8 encoding. Use only the first byte - // TODO: Need code position for warning - Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node); - val = (unsigned char)cstr[n]; - } - else - n += len-1; - } - else - val = (unsigned char)cstr[n]; - } - - // Add the character to the final string - char encodedValue[5]; - int len; - if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 ) - { - // Convert to UTF8 encoded - len = asStringEncodeUTF8(val, encodedValue); - } - else if( engine->ep.stringEncoding == 1 ) - { - // Convert to 16bit wide character string (even if the script is scanned as ASCII) - len = asStringEncodeUTF16(val, encodedValue); - } - else - { - // Do not convert ASCII characters - encodedValue[0] = (asBYTE)val; - len = 1; - } - - if( len < 0 ) - { - // Give warning about invalid code point - // TODO: Need code position for warning - Warning(TXT_INVALID_UNICODE_VALUE, node); - } - else - { - // Add the encoded value to the final string - str.Concatenate(encodedValue, len); - if( charLiteral == -1 ) charLiteral = val; - } - } - - cstr.Assign(str.AddressOf(), str.GetLength()); - return charLiteral; -} - -void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node) -{ - // Remove first line if it only contains whitespace - int start; - for( start = 0; start < (int)str.GetLength(); start++ ) - { - if( str[start] == '\n' ) - { - // Remove the linebreak as well - start++; - break; - } - - if( str[start] != ' ' && - str[start] != '\t' && - str[start] != '\r' ) - { - // Don't remove anything - start = 0; - break; - } - } - - // Remove the line after the last line break if it only contains whitespaces - int end; - for( end = (int)str.GetLength() - 1; end >= 0; end-- ) - { - if( str[end] == '\n' ) - { - // Don't remove the last line break - end++; - break; - } - - if( str[end] != ' ' && - str[end] != '\t' && - str[end] != '\r' ) - { - // Don't remove anything - end = (int)str.GetLength(); - break; - } - } - - if( end < 0 ) end = 0; - - asCString tmp; - if( end > start ) - tmp.Assign(&str[start], end-start); - - ProcessStringConstant(tmp, node, false); - - str = tmp; -} - -void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx) -{ - asSExprContext expr(engine); - asCDataType to; - bool anyErrors = false; - EImplicitConv convType; - if( node->nodeType == snConstructCall ) - { - convType = asIC_EXPLICIT_VAL_CAST; - - // Verify that there is only one argument - if( node->lastChild->firstChild == 0 || - node->lastChild->firstChild != node->lastChild->lastChild ) - { - Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild); - expr.type.SetDummy(); - anyErrors = true; - } - else - { - // Compile the expression - int r = CompileAssignment(node->lastChild->firstChild, &expr); - if( r < 0 ) - anyErrors = true; - } - - // Determine the requested type - to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); - to.MakeReadOnly(true); // Default to const - asASSERT(to.IsPrimitive()); - } - else - { - convType = asIC_EXPLICIT_REF_CAST; - - // Compile the expression - int r = CompileAssignment(node->lastChild, &expr); - if( r < 0 ) - anyErrors = true; - - // Determine the requested type - to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); - to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0); - - // If the type support object handles, then use it - if( to.SupportHandles() ) - { - to.MakeHandle(true); - } - else if( !to.IsObjectHandle() ) - { - // The cast operator can only be used for reference casts - Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild); - anyErrors = true; - } - } - - // Do not allow casting to non shared type if we're compiling a shared method - if( outFunc->IsShared() && - to.GetObjectType() && !to.GetObjectType()->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf()); - Error(msg, node); - anyErrors = true; - } - - if( anyErrors ) - { - // Assume that the error can be fixed and allow the compilation to continue - ctx->type.SetConstantDW(to, 0); - return; - } - - ProcessPropertyGetAccessor(&expr, node); - - // Don't allow any operators on expressions that take address of class method - if( expr.IsClassMethod() ) - { - Error(TXT_INVALID_OP_ON_METHOD, node); - return; - } - - // We don't want a reference for conversion casts - if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() ) - { - if( expr.type.dataType.IsObject() ) - Dereference(&expr, true); - else - ConvertToVariable(&expr); - } - - ImplicitConversion(&expr, to, node, convType); - - IsVariableInitialized(&expr.type, node); - - // If no type conversion is really tried ignore it - if( to == expr.type.dataType ) - { - // This will keep information about constant type - MergeExprBytecode(ctx, &expr); - ctx->type = expr.type; - return; - } - - if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() ) - { - MergeExprBytecode(ctx, &expr); - ctx->type = expr.type; - ctx->type.dataType.MakeReadOnly(true); - return; - } - - // The implicit conversion already does most of the conversions permitted, - // here we'll only treat those conversions that require an explicit cast. - - bool conversionOK = false; - if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) ) - { - if( !expr.type.dataType.IsObject() ) - ConvertToTempVariable(&expr); - - if( to.IsObjectHandle() && - expr.type.dataType.IsObjectHandle() && - !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) ) - { - conversionOK = CompileRefCast(&expr, to, true, node); - - MergeExprBytecode(ctx, &expr); - ctx->type = expr.type; - } - } - - if( conversionOK ) - return; - - // Conversion not available - ctx->type.SetDummy(); - - asCString strTo, strFrom; - - strTo = to.Format(); - strFrom = expr.type.dataType.Format(); - - asCString msg; - msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf()); - - Error(msg, node); -} - -void asCCompiler::AfterFunctionCall(int funcID, asCArray &args, asSExprContext *ctx, bool deferAll) -{ - // 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); - - // Parameters that are sent by reference should be assigned - // to the evaluated expression if it is an lvalue - - // Evaluate the arguments from last to first - int n = (int)descr->parameterTypes.GetLength() - 1; - for( ; n >= 0; n-- ) - { - // All &out arguments must be deferred - // If deferAll is set all objects passed by reference or handle must be deferred - if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) || - (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) ) - { - asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr ); - - // For &inout, only store the argument if it is for a temporary variable - if( engine->ep.allowUnsafeReferences || - descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary ) - { - // Store the argument for later processing - asSDeferredParam outParam; - outParam.argNode = args[n]->exprNode; - outParam.argType = args[n]->type; - outParam.argInOutFlags = descr->inOutFlags[n]; - outParam.origExpr = args[n]->origExpr; - - ctx->deferredParams.PushLast(outParam); - } - } - else - { - // Release the temporary variable now - ReleaseTemporaryVariable(args[n]->type, &ctx->bc); - } - - // Move the argument's deferred expressions over to the final expression - for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ ) - { - ctx->deferredParams.PushLast(args[n]->deferredParams[m]); - args[n]->deferredParams[m].origExpr = 0; - } - args[n]->deferredParams.SetLength(0); - } -} - -void asCCompiler::ProcessDeferredParams(asSExprContext *ctx) -{ - if( isProcessingDeferredParams ) return; - - isProcessingDeferredParams = true; - - for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ ) - { - asSDeferredParam outParam = ctx->deferredParams[n]; - if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference - { - // Just release the variable - ReleaseTemporaryVariable(outParam.argType, &ctx->bc); - } - else if( outParam.argInOutFlags == asTM_OUTREF ) - { - asSExprContext *expr = outParam.origExpr; - outParam.origExpr = 0; - - if( outParam.argType.dataType.IsObjectHandle() ) - { - // Implicitly convert the value to a handle - if( expr->type.dataType.IsObjectHandle() ) - expr->type.isExplicitHandle = true; - } - - // 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); - rctx.type = outParam.argType; - if( rctx.type.dataType.IsPrimitive() ) - rctx.type.dataType.MakeReference(false); - else - { - rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset); - rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset)); - if( expr->type.isExplicitHandle ) - rctx.type.isExplicitHandle = true; - } - - asSExprContext o(engine); - DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode); - - if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr); - - // The assignment may itself have resulted in a new temporary variable, e.g. if - // the opAssign returns a non-reference. We must release this temporary variable - // since it won't be used - ReleaseTemporaryVariable(o.type, &o.bc); - - MergeExprBytecode(ctx, &o); - } - else - { - // We must still evaluate the expression - MergeExprBytecode(ctx, expr); - if( !expr->type.IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) ) - 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->type.IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) ) - Error(TXT_ARG_NOT_LVALUE, outParam.argNode); - - ReleaseTemporaryVariable(outParam.argType, &ctx->bc); - } - - ReleaseTemporaryVariable(expr->type, &ctx->bc); - - // Delete the original expression context - asDELETE(expr,asSExprContext); - } - else // &inout - { - if( outParam.argType.isTemporary ) - ReleaseTemporaryVariable(outParam.argType, &ctx->bc); - else if( !outParam.argType.isVariable ) - { - if( outParam.argType.dataType.IsObject() && - ((outParam.argType.dataType.GetBehaviour()->addref && - outParam.argType.dataType.GetBehaviour()->release) || - (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ) - { - // Release the object handle that was taken to guarantee the reference - ReleaseTemporaryVariable(outParam.argType, &ctx->bc); - } - } - } - } - - ctx->deferredParams.SetLength(0); - isProcessingDeferredParams = false; -} - - -void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx) -{ - // The first node is a datatype node - asCString name; - asCTypeInfo tempObj; - bool onHeap = true; - asCArray funcs; - - // It is possible that the name is really a constructor - asCDataType dt; - dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); - if( dt.IsPrimitive() ) - { - // This is a cast to a primitive type - CompileConversion(node, ctx); - return; - } - - if( dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) ) - { - // Types declared as implicit handle must not attempt to construct a handle - dt.MakeHandle(false); - } - - // Don't accept syntax like object@(expr) - if( dt.IsObjectHandle() ) - { - asCString str; - str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format().AddressOf()); - Error(str, node); - ctx->type.SetDummy(); - return; - } - - if( !dt.CanBeInstantiated() ) - { - asCString str; - if( dt.IsAbstractClass() ) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format().AddressOf()); - else if( dt.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format().AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf()); - Error(str, node); - ctx->type.SetDummy(); - return; - } - - // 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, node); - } - - // Compile the arguments - asCArray args; - asCArray namedArgs; - asCArray temporaryVariables; - if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) - { - // Check for a value cast behaviour - if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() ) - { - asSExprContext 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 - if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 ) - { - 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); - - return; - } - } - - // Check for possible constructor/factory - name = dt.Format(); - - asSTypeBehaviour *beh = dt.GetBehaviour(); - - if( !(dt.GetObjectType()->flags & asOBJ_REF) ) - { - funcs = beh->constructors; - - // Value types and script types are allocated through the constructor - tempObj.dataType = dt; - tempObj.stackOffset = (short)AllocateVariable(dt, true); - tempObj.dataType.MakeReference(true); - tempObj.isTemporary = true; - tempObj.isVariable = true; - - onHeap = IsVariableOnHeap(tempObj.stackOffset); - - // Push the address of the object on the stack - if( onHeap ) - ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); - } - else - funcs = beh->factories; - - // Special case: Allow calling func(void) with a void expression. - if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) ) - { - // Evaluate the expression before the function call - MergeExprBytecode(ctx, args[0]); - asDELETE(args[0],asSExprContext); - args.SetLength(0); - } - - // Special case: If this is an object constructor and there are no arguments use the default constructor. - // 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) ) - { - // Call the default constructor - ctx->type = tempObj; - - if( onHeap ) - { - asASSERT(ctx->bc.GetLastInstr() == asBC_VAR); - ctx->bc.RemoveLastInstr(); - } - - CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node); - - // Push the reference on the stack - ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - return; - } - } - - // 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 != "" ) - { - // 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 - // In theory a simple cast would be good in this case, but this is a construct call so it - // is expected that a new object is created. - - dt.MakeHandle(true); - ctx->type.Set(dt); - - // The delegate must be able to hold on to a reference to the object - if( !args[0]->type.dataType.SupportHandles() ) - Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node); - else - { - // Filter the available object methods to find the one that matches the func def - asCObjectType *type = args[0]->type.dataType.GetObjectType(); - asCScriptFunction *bestMethod = 0; - for( asUINT n = 0; n < type->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[type->methods[n]]; - - if( func->name != args[0]->methodName ) - continue; - - // If the expression is for a const object, then only const methods should be accepted - if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() ) - continue; - - if( func->IsSignatureExceptNameAndObjectTypeEqual(dt.GetFuncDef()) ) - { - bestMethod = func; - - // If the expression is non-const the non-const overloaded method has priority - if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() ) - break; - } - } - - if( bestMethod ) - { - // The object pointer is already on the stack - MergeExprBytecode(ctx, args[0]); - - // Push the function pointer as an additional argument - 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); - - // Store the returned delegate in a temporary variable - int returnOffset = AllocateVariable(dt, true, false); - dt.MakeReference(true); - ctx->type.SetVariable(dt, returnOffset, true); - ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset); - - // Push a reference to the temporary variable on the stack - ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset); - } - else - { - asCString msg; - msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, dt.GetFuncDef()->GetDeclaration()); - Error(msg.AddressOf(), node); - } - } - - // Clean-up arg - asDELETE(args[0],asSExprContext); - return; - } - - MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false); - - if( funcs.GetLength() != 1 ) - { - // The error was reported by MatchFunctions() - - // Dummy value - ctx->type.SetDummy(); - } - else - { - // 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); - - if( r == asSUCCESS ) - { - asCByteCode objBC(engine); - - PrepareFunctionCall(funcs[0], &ctx->bc, args); - - MoveArgsToStack(funcs[0], &ctx->bc, args, false); - - if( !(dt.GetObjectType()->flags & asOBJ_REF) ) - { - // If the object is allocated on the stack, then call the constructor as a normal function - if( onHeap ) - { - int offset = 0; - asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); - for( asUINT n = 0; n < args.GetLength(); n++ ) - offset += descr->parameterTypes[n].GetSizeOnStackDWords(); - - ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset); - } - else - ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - - PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType()); - - // Add tag that the object has been initialized - ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); - - // The constructor doesn't return anything, - // so we have to manually inform the type of - // the return value - ctx->type = tempObj; - if( !onHeap ) - ctx->type.dataType.MakeReference(false); - - // Push the address of the object on the stack again - ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - } - else - { - // Call the factory to create the reference type - PerformFunctionCall(funcs[0], ctx, false, &args); - } - } - } - } - else - { - // Failed to compile the argument list, set the result to the dummy type - ctx->type.SetDummy(); - } - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n],asSExprContext); - } - for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) - if( namedArgs[n].ctx ) - { - asDELETE(namedArgs[n].ctx,asSExprContext); - } -} - - -int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope) -{ - asCTypeInfo tempObj; - asCArray funcs; - int localVar = -1; - bool initializeMembers = false; - asSExprContext funcExpr(engine); - - asCScriptNode *nm = node->lastChild->prev; - asCString name(&script->code[nm->tokenPos], nm->tokenLength); - - // First check for a local variable as it would take precedence - // Must not allow function names, nor global variables to be returned in this instance - // If objectType is set then this is a post op expression and we shouldn't look for local variables - if( objectType == 0 ) - { - localVar = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true); - if( localVar >= 0 && - !(funcExpr.type.dataType.GetFuncDef() || 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()); - Error(msg, node); - return -1; - } - - // If the name matches a method name, then reset the indicator that nothing was found - if( funcExpr.methodName != "" ) - localVar = -1; - } - - if( localVar < 0 ) - { - // If this is an expression post op, or if a class method is - // being compiled, then we should look for matching class methods - if( objectType || (outFunc && outFunc->objectType && scope != "::") ) - { - // If we're compiling a constructor and the name of the function is super then - // the constructor of the base class is being called. - // super cannot be prefixed with a scope operator - if( scope == "" && m_isConstructor && name == SUPER_TOKEN ) - { - // If the class is not derived from anyone else, calling super should give an error - if( outFunc && outFunc->objectType->derivedFrom ) - funcs = outFunc->objectType->derivedFrom->beh.constructors; - - // Must not allow calling base class' constructor multiple times - if( continueLabels.GetLength() > 0 ) - { - // If a continue label is set we are in a loop - Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node); - } - else if( breakLabels.GetLength() > 0 ) - { - // TODO: inheritance: Should eventually allow constructors in switch statements - // If a break label is set we are either in a loop or a switch statements - Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node); - } - else if( m_isConstructorCalled ) - { - Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node); - } - m_isConstructorCalled = true; - - // We need to initialize the class members, but only after all the deferred arguments have been completed - initializeMembers = true; - } - else - { - // The scope is can be used to specify the base class - builder->GetObjectMethodDescriptions(name.AddressOf(), objectType ? objectType : outFunc->objectType, funcs, objIsConst, scope); - } - - // It is still possible that there is a class member of a function type or a type with opCall methods - if( funcs.GetLength() == 0 ) - { - int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true, objectType); - if( r >= 0 && - !(funcExpr.type.dataType.GetFuncDef() || 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()); - Error(msg, node); - return -1; - } - - // If the name is an access property, make sure the original value isn't - // dereferenced when calling the access property as part a dot post operator - if( objectType && (funcExpr.property_get || funcExpr.property_set) && !ctx->type.dataType.IsReference() ) - funcExpr.property_ref = false; - } - - // If a class method is being called implicitly, then add the this pointer for the call - if( funcs.GetLength() && !objectType ) - { - objectType = outFunc->objectType; - - asCDataType dt = asCDataType::CreateObject(objectType, false); - - // The object pointer is located at stack position 0 - ctx->bc.InstrSHORT(asBC_PSF, 0); - ctx->type.SetVariable(dt, 0, false); - ctx->type.dataType.MakeReference(true); - - Dereference(ctx, true); - } - } - - // If it is not a class method or member function pointer, - // 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()) ) - { - // 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 ) - { - 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.methodName == "" ) - { - // The variable is not a function - asCString msg; - msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf()); - Error(msg, node); - return -1; - } - } - - ns = builder->GetParentNameSpace(ns); - } - } - else - { - asCString msg; - msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, scope.AddressOf()); - Error(msg, node); - return -1; - } - } - } - - if( funcs.GetLength() == 0 ) - { - if( funcExpr.type.dataType.GetFuncDef() ) - { - funcs.PushLast(funcExpr.type.dataType.GetFuncDef()->id); - } - else if( funcExpr.type.dataType.IsObject() ) - { - // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call - if( ctx->type.isTemporary ) - { - asASSERT( objectType ); - - asSDeferredParam deferred; - deferred.origExpr = 0; - deferred.argInOutFlags = asTM_INREF; - deferred.argNode = 0; - deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true); - - ctx->deferredParams.PushLast(deferred); - } - if( funcExpr.property_get == 0 ) - Dereference(ctx, true); - - // Add the bytecode for accessing the object on which opCall will be called - MergeExprBytecodeAndType(ctx, &funcExpr); - ProcessPropertyGetAccessor(ctx, node); - Dereference(ctx, true); - - objectType = funcExpr.type.dataType.GetObjectType(); - - // Get the opCall methods from the object type - if( funcExpr.type.dataType.IsObjectHandle() ) - objIsConst = funcExpr.type.dataType.IsHandleToConst(); - else - objIsConst = funcExpr.type.dataType.IsReadOnly(); - - builder->GetObjectMethodDescriptions("opCall", funcExpr.type.dataType.GetObjectType(), funcs, objIsConst); - } - } - - // Compile the arguments - asCArray args; - asCArray namedArgs; - - bool isOK = true; - if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) - { - // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void' - if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) && !args[0]->type.IsVoidExpression() ) - { - // Evaluate the expression before the function call - MergeExprBytecode(ctx, args[0]); - asDELETE(args[0],asSExprContext); - args.SetLength(0); - } - - MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope); - - if( funcs.GetLength() != 1 ) - { - // The error was reported by MatchFunctions() - - // Dummy value - ctx->type.SetDummy(); - isOK = false; - } - else - { - // Add the default values for arguments not explicitly supplied - int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &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? - - // For function pointer we must guarantee that the function is safe, i.e. - // by first storing the function pointer in a local variable (if it isn't already in one) - if( r == asSUCCESS ) - { - asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]); - if( func->funcType == asFUNC_FUNCDEF ) - { - if( objectType && funcExpr.property_get <= 0 ) - { - Dereference(ctx, true); // Dereference the object pointer to access the member - - // The actual function should be called as if a global function - objectType = 0; - } - - if( funcExpr.property_get > 0 ) - { - ProcessPropertyGetAccessor(&funcExpr, node); - Dereference(&funcExpr, true); - } - else - { - Dereference(&funcExpr, true); - ConvertToVariable(&funcExpr); - } - - // 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; - MergeExprBytecodeAndType(ctx, &funcExpr); - ReleaseTemporaryVariable(tmp, &ctx->bc); - } - - MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset); - } - else - isOK = false; - } - } - else - { - // Failed to compile the argument list, set the dummy type and continue compilation - ctx->type.SetDummy(); - isOK = false; - } - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n],asSExprContext); - } - for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) - if( namedArgs[n].ctx ) - { - asDELETE(namedArgs[n].ctx,asSExprContext); - } - - if( initializeMembers ) - { - asASSERT( m_isConstructor ); - - // Need to initialize members here, as they may use the properties of the base class - // If there are multiple paths that call super(), then there will also be multiple - // locations with initializations of the members. It is not possible to consolidate - // these in one place, as the expressions for the initialization are evaluated where - // they are compiled, which means that they may access different variables depending - // on the scope where super() is called. - // Members that don't have an explicit initialization expression will be initialized - // beginning of the constructor as they are guaranteed not to use at the any - // members of the base class. - CompileMemberInitialization(&ctx->bc, false); - } - - return isOK ? 0 : -1; -} - -asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope) -{ - asSNameSpace *ns; - - if( scope == "" ) - { - if( outFunc->nameSpace->name != "" ) - ns = outFunc->nameSpace; - else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" ) - ns = outFunc->objectType->nameSpace; - else - ns = engine->nameSpaces[0]; - } - else if( scope == "::" ) - ns = engine->nameSpaces[0]; - else - ns = engine->FindNameSpace(scope.AddressOf()); - - return ns; -} - -int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx) -{ - int op = node->tokenType; - - // Don't allow any prefix operators except handle on expressions that take address of class method - if( ctx->IsClassMethod() && op != ttHandle ) - { - Error(TXT_INVALID_OP_ON_METHOD, node); - return -1; - } - - // Don't allow any operators on void expressions - if( ctx->type.IsVoidExpression() ) - { - Error(TXT_VOID_CANT_BE_OPERAND, node); - return -1; - } - - IsVariableInitialized(&ctx->type, node); - - if( op == ttHandle ) - { - if( ctx->methodName != "" ) - { - // Don't allow taking the handle of a handle - if( ctx->type.isExplicitHandle ) - { - Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); - return -1; - } - } - else - { - // Don't allow taking handle of a handle, i.e. @@ - if( ctx->type.isExplicitHandle ) - { - Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); - return -1; - } - - // @null is allowed even though it is implicit - 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)) ) - { - Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); - return -1; - } - - // 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.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) ) - { - Error(TXT_NOT_VALID_REFERENCE, node); - return -1; - } - - // Convert the expression to a handle - if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ) - { - asCDataType to = ctx->type.dataType; - to.MakeHandle(true); - to.MakeReference(true); - to.MakeHandleToConst(ctx->type.dataType.IsReadOnly()); - ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false); - - asASSERT( ctx->type.dataType.IsObjectHandle() ); - } - else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE ) - { - // For the ASHANDLE type we'll simply set the expression as a handle - ctx->type.dataType.MakeHandle(true); - } - } - } - - // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions - ctx->type.isExplicitHandle = true; - } - else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() ) - { - // Look for the appropriate method - // There is no overloadable operator for unary plus - const char *opName = 0; - switch( op ) - { - case ttMinus: opName = "opNeg"; break; - case ttBitNot: opName = "opCom"; break; - case ttInc: opName = "opPreInc"; break; - case ttDec: opName = "opPreDec"; break; - } - - if( opName ) - { - // TODO: Should convert this to something similar to CompileOverloadedDualOperator2 - ProcessPropertyGetAccessor(ctx, node); - - // TODO: If the value isn't const, then first try to find the non const method, and if not found try to find the const method - - // Find the correct method - bool isConst = ctx->type.dataType.IsObjectConst(); - asCArray funcs; - asCObjectType *ot = ctx->type.dataType.GetObjectType(); - 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) ) - { - funcs.PushLast(func->id); - } - } - - // Did we find the method? - if( funcs.GetLength() == 1 ) - { - asCArray args; - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node); - return 0; - } - else if( funcs.GetLength() == 0 ) - { - asCString str; - str = asCString(opName) + "()"; - if( isConst ) - str += " const"; - str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf()); - Error(str, node); - ctx->type.SetDummy(); - return -1; - } - else if( funcs.GetLength() > 1 ) - { - Error(TXT_MORE_THAN_ONE_MATCHING_OP, node); - PrintMatchingFuncs(funcs, node); - - ctx->type.SetDummy(); - return -1; - } - } - else if( op == ttPlus ) - { - Error(TXT_ILLEGAL_OPERATION, node); - ctx->type.SetDummy(); - return -1; - } - } - else if( op == ttPlus || op == ttMinus ) - { - // This is only for primitives. Objects are treated in the above block - - // Make sure the type is a math type - if( !(ctx->type.dataType.IsIntegerType() || - ctx->type.dataType.IsUnsignedType() || - ctx->type.dataType.IsFloatType() || - ctx->type.dataType.IsDoubleType() ) ) - { - Error(TXT_ILLEGAL_OPERATION, node); - return -1; - } - - - ProcessPropertyGetAccessor(ctx, node); - - asCDataType to = ctx->type.dataType; - - if( ctx->type.dataType.IsUnsignedType() ) - { - if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) - to = asCDataType::CreatePrimitive(ttInt8, false); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) - to = asCDataType::CreatePrimitive(ttInt16, false); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) - to = asCDataType::CreatePrimitive(ttInt, false); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 ) - to = asCDataType::CreatePrimitive(ttInt64, false); - else - { - Error(TXT_INVALID_TYPE, node); - return -1; - } - } - - if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx); - - // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign - ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV); - - if( !ctx->type.isConstant ) - { - ConvertToTempVariable(ctx); - asASSERT(!ctx->type.isLValue); - - if( op == ttMinus ) - { - if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset); - else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset); - else if( ctx->type.dataType.IsFloatType() ) - ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset); - else if( ctx->type.dataType.IsDoubleType() ) - ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset); - else - { - Error(TXT_ILLEGAL_OPERATION, node); - return -1; - } - - return 0; - } - } - else - { - 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; - else if( ctx->type.dataType.IsFloatType() ) - ctx->type.floatValue = -ctx->type.floatValue; - else if( ctx->type.dataType.IsDoubleType() ) - ctx->type.doubleValue = -ctx->type.doubleValue; - else - { - Error(TXT_ILLEGAL_OPERATION, node); - return -1; - } - - return 0; - } - } - } - else if( op == ttNot ) - { - 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); - return 0; - } - - ProcessPropertyGetAccessor(ctx, node); - - ConvertToTempVariable(ctx); - asASSERT(!ctx->type.isLValue); - - ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset); - } - else - { - Error(TXT_ILLEGAL_OPERATION, node); - return -1; - } - } - else if( op == ttBitNot ) - { - ProcessPropertyGetAccessor(ctx, node); - - asCDataType to = ctx->type.dataType; - - if( ctx->type.dataType.IsIntegerType() ) - { - if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) - to = asCDataType::CreatePrimitive(ttUInt8, false); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) - to = asCDataType::CreatePrimitive(ttUInt16, false); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) - to = asCDataType::CreatePrimitive(ttUInt, false); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 ) - to = asCDataType::CreatePrimitive(ttUInt64, false); - else - { - Error(TXT_INVALID_TYPE, node); - return -1; - } - } - - if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx); - ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV); - - if( ctx->type.dataType.IsUnsignedType() ) - { - if( ctx->type.isConstant ) - { - ctx->type.qwordValue = ~ctx->type.qwordValue; - return 0; - } - - ConvertToTempVariable(ctx); - asASSERT(!ctx->type.isLValue); - - if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset); - else - ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset); - } - else - { - Error(TXT_ILLEGAL_OPERATION, node); - return -1; - } - } - else if( op == ttInc || op == ttDec ) - { - // Need a reference to the primitive that will be updated - // The result of this expression is the same reference as before - - // Make sure the reference isn't a temporary variable - if( ctx->type.isTemporary ) - { - Error(TXT_REF_IS_TEMP, node); - return -1; - } - if( ctx->type.dataType.IsReadOnly() ) - { - Error(TXT_REF_IS_READ_ONLY, node); - return -1; - } - if( ctx->property_get || ctx->property_set ) - { - Error(TXT_INVALID_REF_PROP_ACCESS, node); - return -1; - } - if( !ctx->type.isLValue ) - { - Error(TXT_NOT_LVALUE, node); - return -1; - } - - if( ctx->type.isVariable && !ctx->type.dataType.IsReference() ) - ConvertToReference(ctx); - else if( !ctx->type.dataType.IsReference() ) - { - Error(TXT_NOT_VALID_REFERENCE, node); - return -1; - } - - if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) || - ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) ) - { - if( op == ttInc ) - ctx->bc.Instr(asBC_INCi64); - else - ctx->bc.Instr(asBC_DECi64); - } - else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) || - ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) ) - { - if( op == ttInc ) - ctx->bc.Instr(asBC_INCi); - else - ctx->bc.Instr(asBC_DECi); - } - else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) || - ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) ) - { - if( op == ttInc ) - ctx->bc.Instr(asBC_INCi16); - else - ctx->bc.Instr(asBC_DECi16); - } - else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) || - ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) ) - { - if( op == ttInc ) - ctx->bc.Instr(asBC_INCi8); - else - ctx->bc.Instr(asBC_DECi8); - } - else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) ) - { - if( op == ttInc ) - ctx->bc.Instr(asBC_INCf); - else - ctx->bc.Instr(asBC_DECf); - } - else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) ) - { - if( op == ttInc ) - ctx->bc.Instr(asBC_INCd); - else - ctx->bc.Instr(asBC_DECd); - } - else - { - Error(TXT_ILLEGAL_OPERATION, node); - return -1; - } - } - else - { - // Unknown operator - asASSERT(false); - return -1; - } - - return 0; -} - -void asCCompiler::ConvertToReference(asSExprContext *ctx) -{ - if( ctx->type.isVariable && !ctx->type.dataType.IsReference() ) - { - ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset); - ctx->type.dataType.MakeReference(true); - ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary); - } -} - -int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *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) -{ - if( engine->ep.propertyAccessorMode == 0 ) - { - // Property accessors have been disabled by the application - return 0; - } - - int getId = 0, setId = 0; - asCString getName = "get_" + name; - asCString setName = "set_" + name; - asCArray multipleGetFuncs, multipleSetFuncs; - - if( ctx->type.dataType.IsObject() ) - { - asASSERT( ns == 0 ); - - // 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) || - engine->ep.propertyAccessorMode == 2 ) - { - // Check if the object has any methods with the corresponding accessor name(s) - asCObjectType *ot = ctx->type.dataType.GetObjectType(); - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; - // TODO: The type of the parameter should match the argument (unless the arg is a dummy) - if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) ) - { - if( getId == 0 ) - getId = ot->methods[n]; - else - { - if( multipleGetFuncs.GetLength() == 0 ) - multipleGetFuncs.PushLast(getId); - - multipleGetFuncs.PushLast(ot->methods[n]); - } - } - // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref? - if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) ) - { - if( setId == 0 ) - setId = ot->methods[n]; - else - { - if( multipleSetFuncs.GetLength() == 0 ) - multipleSetFuncs.PushLast(setId); - - multipleSetFuncs.PushLast(ot->methods[n]); - } - } - } - } - } - else - { - asASSERT( ns != 0 ); - - // Look for appropriate global functions. - asCArray funcs; - asUINT n; - builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns); - for( n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]); - // TODO: The type of the parameter should match the argument (unless the arg is a dummy) - if( (int)f->parameterTypes.GetLength() == (arg?1:0) ) - { - if( getId == 0 ) - getId = funcs[n]; - else - { - if( multipleGetFuncs.GetLength() == 0 ) - multipleGetFuncs.PushLast(getId); - - multipleGetFuncs.PushLast(funcs[n]); - } - } - } - - funcs.SetLength(0); - builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns); - for( n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]); - // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref? - if( (int)f->parameterTypes.GetLength() == (arg?2:1) ) - { - if( setId == 0 ) - setId = funcs[n]; - else - { - if( multipleSetFuncs.GetLength() == 0 ) - multipleSetFuncs.PushLast(getId); - - multipleSetFuncs.PushLast(funcs[n]); - } - } - } - } - - bool isConst = ctx->type.dataType.IsObjectConst(); - - // Check for multiple matches - if( multipleGetFuncs.GetLength() > 0 ) - { - // Filter the list by constness - FilterConst(multipleGetFuncs, !isConst); - - if( multipleGetFuncs.GetLength() > 1 ) - { - asCString str; - str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf()); - Error(str, node); - - PrintMatchingFuncs(multipleGetFuncs, node); - - return -1; - } - else - { - // The id may have changed - getId = multipleGetFuncs[0]; - } - } - - if( multipleSetFuncs.GetLength() > 0 ) - { - // Filter the list by constness - FilterConst(multipleSetFuncs, !isConst); - - if( multipleSetFuncs.GetLength() > 1 ) - { - asCString str; - str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf()); - Error(str, node); - - PrintMatchingFuncs(multipleSetFuncs, node); - - return -1; - } - else - { - // The id may have changed - setId = multipleSetFuncs[0]; - } - } - - // Check for type compatibility between get and set accessor - if( getId && setId ) - { - asCScriptFunction *getFunc = builder->GetFunctionDescription(getId); - asCScriptFunction *setFunc = builder->GetFunctionDescription(setId); - - // It is permitted for a getter to return a handle and the setter to take a reference - 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())) ) - { - asCString str; - str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf()); - Error(str, node); - - asCArray funcs; - funcs.PushLast(getId); - funcs.PushLast(setId); - - PrintMatchingFuncs(funcs, node); - - return -1; - } - } - - // Check if we are within one of the accessors - int realGetId = getId; - int realSetId = setId; - if( outFunc->objectType && isThisAccess ) - { - // The property accessors would be virtual functions, so we need to find the real implementation - asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0; - if( getFunc && - getFunc->funcType == asFUNC_VIRTUAL && - outFunc->objectType->DerivesFrom(getFunc->objectType) ) - realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id; - asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0; - if( setFunc && - setFunc->funcType == asFUNC_VIRTUAL && - outFunc->objectType->DerivesFrom(setFunc->objectType) ) - realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id; - } - - // Avoid recursive call, by not treating this as a property accessor call. - // This will also allow having the real property with the same name as the accessors. - if( (isThisAccess || outFunc->objectType == 0) && - ((realGetId && realGetId == outFunc->id) || - (realSetId && realSetId == outFunc->id)) ) - { - getId = 0; - setId = 0; - } - - // Check if the application has disabled script written property accessors - if( engine->ep.propertyAccessorMode == 1 ) - { - if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM ) - getId = 0; - if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM ) - setId = 0; - } - - if( getId || setId ) - { - // Property accessors were found, but we don't know which is to be used yet, so - // we just prepare the bytecode for the method call, and then store the function ids - // so that the right one can be used when we get there. - ctx->property_get = getId; - ctx->property_set = setId; - - if( ctx->type.dataType.IsObject() ) - { - // If the object is read-only then we need to remember that - if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) || - (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ) - ctx->property_const = true; - else - ctx->property_const = false; - - // If the object is a handle then we need to remember that - ctx->property_handle = ctx->type.dataType.IsObjectHandle(); - ctx->property_ref = ctx->type.dataType.IsReference(); - } - - // The setter's parameter type is used as the property type, - // unless only the getter is available - asCDataType dt; - if( setId ) - dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)]; - else - dt = builder->GetFunctionDescription(getId)->returnType; - - // Just change the type, the context must still maintain information - // about previous variable offset and the indicator of temporary variable. - int offset = ctx->type.stackOffset; - bool isTemp = ctx->type.isTemporary; - ctx->type.Set(dt); - ctx->type.stackOffset = (short)offset; - ctx->type.isTemporary = isTemp; - ctx->exprNode = node; - - // Store the argument for later use - if( arg ) - { - ctx->property_arg = asNEW(asSExprContext)(engine); - if( ctx->property_arg == 0 ) - { - // Out of memory - return -1; - } - - MergeExprBytecodeAndType(ctx->property_arg, arg); - } - - return 1; - } - - // No accessor was found - return 0; -} - -int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node) -{ - // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them? - - if( !ctx->property_set ) - { - Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node); - return -1; - } - - asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set); - - // Make sure the arg match the property - asCArray funcs; - funcs.PushLast(ctx->property_set); - asCArray args; - if( ctx->property_arg ) - args.PushLast(ctx->property_arg); - args.PushLast(arg); - MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const); - if( funcs.GetLength() == 0 ) - { - // MatchFunctions already reported the error - if( ctx->property_arg ) - { - asDELETE(ctx->property_arg, asSExprContext); - ctx->property_arg = 0; - } - return -1; - } - - 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); - 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 ) - { - Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); - asCArray funcs; - funcs.PushLast(ctx->property_set); - PrintMatchingFuncs(funcs, node); - } - } - - // Call the accessor - MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node); - - ctx->property_get = 0; - ctx->property_set = 0; - if( ctx->property_arg ) - { - asDELETE(ctx->property_arg, asSExprContext); - ctx->property_arg = 0; - } - - return 0; -} - -void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node) -{ - // If no property accessor has been prepared then don't do anything - if( !ctx->property_get && !ctx->property_set ) - return; - - if( !ctx->property_get ) - { - // Raise error on missing accessor - Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node); - ctx->type.SetDummy(); - return; - } - - asCTypeInfo 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; - if( ctx->property_arg ) - args.PushLast(ctx->property_arg); - MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const); - if( funcs.GetLength() == 0 ) - { - // MatchFunctions already reported the error - if( ctx->property_arg ) - { - asDELETE(ctx->property_arg, asSExprContext); - ctx->property_arg = 0; - } - ctx->type.SetDummy(); - return; - } - - 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); - 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 ) - { - Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); - asCArray funcs; - funcs.PushLast(ctx->property_get); - PrintMatchingFuncs(funcs, node); - } - } - - // Call the accessor - MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node); - - ctx->property_get = 0; - ctx->property_set = 0; - if( ctx->property_arg ) - { - asDELETE(ctx->property_arg, asSExprContext); - ctx->property_arg = 0; - } -} - -int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx) -{ - // Don't allow any postfix operators on expressions that take address of class method - if( ctx->IsClassMethod() ) - { - Error(TXT_INVALID_OP_ON_METHOD, node); - return -1; - } - - // Don't allow any operators on void expressions - if( ctx->type.IsVoidExpression() ) - { - Error(TXT_VOID_CANT_BE_OPERAND, node); - return -1; - } - - // Check if the variable is initialized (if it indeed is a variable) - IsVariableInitialized(&ctx->type, node); - - int op = node->tokenType; - if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() ) - { - const char *opName = 0; - switch( op ) - { - case ttInc: opName = "opPostInc"; break; - case ttDec: opName = "opPostDec"; break; - } - - if( opName ) - { - // TODO: Should convert this to something similar to CompileOverloadedDualOperator2 - ProcessPropertyGetAccessor(ctx, node); - - // TODO: If the value isn't const, then first try to find the non const method, and if not found try to find the const method - - // Find the correct method - bool isConst = ctx->type.dataType.IsObjectConst(); - asCArray funcs; - asCObjectType *ot = ctx->type.dataType.GetObjectType(); - 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) ) - { - funcs.PushLast(func->id); - } - } - - // Did we find the method? - if( funcs.GetLength() == 1 ) - { - asCArray args; - MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node); - return 0; - } - else if( funcs.GetLength() == 0 ) - { - asCString str; - str = asCString(opName) + "()"; - if( isConst ) - str += " const"; - str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf()); - Error(str, node); - ctx->type.SetDummy(); - return -1; - } - else if( funcs.GetLength() > 1 ) - { - Error(TXT_MORE_THAN_ONE_MATCHING_OP, node); - PrintMatchingFuncs(funcs, node); - - ctx->type.SetDummy(); - return -1; - } - } - } - else if( op == ttInc || op == ttDec ) - { - // Make sure the reference isn't a temporary variable - if( ctx->type.isTemporary ) - { - Error(TXT_REF_IS_TEMP, node); - return -1; - } - if( ctx->type.dataType.IsReadOnly() ) - { - Error(TXT_REF_IS_READ_ONLY, node); - return -1; - } - if( ctx->property_get || ctx->property_set ) - { - Error(TXT_INVALID_REF_PROP_ACCESS, node); - return -1; - } - if( !ctx->type.isLValue ) - { - Error(TXT_NOT_LVALUE, node); - return -1; - } - - if( ctx->type.isVariable && !ctx->type.dataType.IsReference() ) - ConvertToReference(ctx); - else if( !ctx->type.dataType.IsReference() ) - { - Error(TXT_NOT_VALID_REFERENCE, node); - return -1; - } - - // Copy the value to a temp before changing it - ConvertToTempVariable(ctx); - asASSERT(!ctx->type.isLValue); - - // Increment the value pointed to by the reference still in the register - asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi; - if( ctx->type.dataType.IsDoubleType() ) - { - iInc = asBC_INCd; - iDec = asBC_DECd; - } - else if( ctx->type.dataType.IsFloatType() ) - { - iInc = asBC_INCf; - iDec = asBC_DECf; - } - else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ) - { - if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) || - ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) ) - { - iInc = asBC_INCi16; - iDec = asBC_DECi16; - } - else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) || - ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) ) - { - iInc = asBC_INCi8; - iDec = asBC_DECi8; - } - else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) || - ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) ) - { - iInc = asBC_INCi64; - iDec = asBC_DECi64; - } - } - else - { - Error(TXT_ILLEGAL_OPERATION, node); - return -1; - } - - if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec); - } - else if( op == ttDot ) - { - if( node->firstChild->nodeType == snIdentifier ) - { - ProcessPropertyGetAccessor(ctx, node); - - // Get the property name - asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength); - - if( ctx->type.dataType.IsObject() ) - { - // We need to look for get/set property accessors. - // If found, the context stores information on the get/set accessors - // until it is known which is to be used. - int r = 0; - if( node->next && node->next->tokenType == ttOpenBracket ) - { - // The property accessor should take an index arg - asSExprContext dummyArg(engine); - r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0); - } - if( r == 0 ) - r = FindPropertyAccessor(name, ctx, node, 0); - if( r != 0 ) - return r; - - if( !ctx->type.dataType.IsPrimitive() ) - Dereference(ctx, true); - - if( ctx->type.dataType.IsObjectHandle() ) - { - // Convert the handle to a normal object - asCDataType dt = ctx->type.dataType; - dt.MakeHandle(false); - - ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV); - - // The handle may not have been an lvalue, but the dereferenced object is - ctx->type.isLValue = true; - } - - bool isConst = ctx->type.dataType.IsObjectConst(); - - asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf()); - if( prop ) - { - // Is the property access allowed? - if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) ) - { - asCString msg; - msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf()); - Error(msg, node); - } - - // Put the offset on the stack - ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false))); - - if( prop->type.IsReference() ) - ctx->bc.Instr(asBC_RDSPtr); - - // Reference to primitive must be stored in the temp register - if( prop->type.IsPrimitive() ) - { - ctx->bc.Instr(asBC_PopRPtr); - } - - // Keep information about temporary variables as deferred expression - if( ctx->type.isTemporary ) - { - // Add the release of this reference, as a deferred expression - asSDeferredParam deferred; - deferred.origExpr = 0; - deferred.argInOutFlags = asTM_INREF; - deferred.argNode = 0; - deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true); - - ctx->deferredParams.PushLast(deferred); - } - - // Set the new type and make sure it is not treated as a variable anymore - ctx->type.dataType = prop->type; - ctx->type.dataType.MakeReference(true); - ctx->type.isVariable = false; - ctx->type.isTemporary = false; - - if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() ) - { - // Objects that are members are not references - ctx->type.dataType.MakeReference(false); - } - - ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly()); - } - else - { - // 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(); - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - if( engine->scriptFunctions[ot->methods[n]]->name == name ) - { - func = engine->scriptFunctions[ot->methods[n]]; - break; - } - } - - if( func ) - { - // An object method was found. Keep the name of the method in the expression, but - // don't actually modify the bytecode at this point since it is not yet known what - // the method will be used for, or even what overloaded method should be used. - ctx->methodName = name; - } - else - { - asCString str; - str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf()); - Error(str, node); - return -1; - } - } - } - else - { - asCString str; - str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf()); - Error(str, node); - return -1; - } - } - else - { - // Make sure it is an object we are accessing - if( !ctx->type.dataType.IsObject() ) - { - asCString str; - str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf()); - Error(str, node); - return -1; - } - - // Process the get property accessor - ProcessPropertyGetAccessor(ctx, node); - - // Compile function call - int r = CompileFunctionCall(node->firstChild, ctx, ctx->type.dataType.GetObjectType(), ctx->type.dataType.IsObjectConst()); - if( r < 0 ) return r; - } - } - else if( op == ttOpenBracket ) - { - // If the property access takes an index arg and the argument hasn't been evaluated yet, - // then we should use that instead of processing it now. If the argument has already been - // evaluated, then we should process the property accessor as a get access now as the new - // index operator is on the result of that accessor. - asCString propertyName; - asSNameSpace *ns = 0; - if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) || - (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) && - (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) ) - { - // Determine the name of the property accessor - asCScriptFunction *func = 0; - if( ctx->property_get ) - func = builder->GetFunctionDescription(ctx->property_get); - else - func = builder->GetFunctionDescription(ctx->property_set); - propertyName = func->GetName(); - propertyName = propertyName.SubString(4); - - // 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); - if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); - if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); - } - else - { - // Store the namespace where the function is declared - // so the same function can be found later - ctx->type.SetDummy(); - ns = func->nameSpace; - } - - ctx->property_get = ctx->property_set = 0; - if( ctx->property_arg ) - { - asDELETE(ctx->property_arg, asSExprContext); - ctx->property_arg = 0; - } - } - else - { - if( !ctx->type.dataType.IsObject() ) - { - asCString str; - str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf()); - Error(str, node); - return -1; - } - - ProcessPropertyGetAccessor(ctx, node); - } - - // Compile the expression - bool isOK = true; - asCArray args; - asCArray namedArgs; - asASSERT( node->firstChild->nodeType == snArgList ); - if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 ) - { - // Check for the existence of the opIndex method - bool lookForProperty = true; - if( propertyName == "" ) - { - bool isConst = ctx->type.dataType.IsObjectConst(); - asCObjectType *objectType = ctx->type.dataType.GetObjectType(); - - asCArray funcs; - builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst); - if( funcs.GetLength() > 0 ) - { - // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors - lookForProperty = false; - - // Determine which of opIndex methods that match - MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst); - if( funcs.GetLength() != 1 ) - { - // The error has already been reported by MatchFunctions - isOK = false; - } - else - { - // Add the default values for arguments not explicitly supplied - int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType); - - if( r == 0 ) - MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset); - else - isOK = false; - } - } - } - if( lookForProperty && isOK ) - { - if( args.GetLength() != 1 ) - { - // TODO: opIndex: Implement this - Error("Property accessor with index only support 1 index argument for now", 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 ) - { - asCString str; - str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf()); - Error(str, node); - isOK = false; - } - else if( r < 0 ) - isOK = false; - - if( isOK ) - MergeExprBytecodeAndType(ctx, &lctx); - } - } - else - isOK = false; - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n],asSExprContext); - } - - if( !isOK ) - return -1; - } - else if( op == ttOpenParanthesis ) - { - // 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() ) - { - Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node); - return -1; - } - - // Compile arguments - asCArray args; - asCArray namedArgs; - if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) - { - // Match arguments with the funcdef - asCArray funcs; - if( ctx->type.dataType.GetFuncDef() ) - { - funcs.PushLast(ctx->type.dataType.GetFuncDef()->id); - MatchFunctions(funcs, args, node, ctx->type.dataType.GetFuncDef()->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); - } - - if( funcs.GetLength() != 1 ) - { - // The error was reported by MatchFunctions() - - // Dummy value - ctx->type.SetDummy(); - } - else - { - // Add the default values for arguments not explicitly supplied - int r = CompileDefaultAndNamedArgs(node, args, funcs[0], ctx->type.dataType.GetObjectType(), &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? - - // For function pointer we must guarantee that the function is safe, i.e. - // by first storing the function pointer in a local variable (if it isn't already in one) - if( r == asSUCCESS ) - { - Dereference(ctx, true); - if( ctx->type.dataType.GetFuncDef() ) - { - if( !ctx->type.isVariable ) - ConvertToVariable(ctx); - - // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument - 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); - } - } - } - else - ctx->type.SetDummy(); - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n],asSExprContext); - } - for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) - if( namedArgs[n].ctx ) - { - asDELETE(namedArgs[n].ctx,asSExprContext); - } - } - - return 0; -} - -int asCCompiler::GetPrecedence(asCScriptNode *op) -{ - // x ** y - // x * y, x / y, x % y - // x + y, x - y - // x <= y, x < y, x >= y, x > y - // x = =y, x != y, x xor y, x is y, x !is y - // x and y - // x or y - - // The following are not used in this function, - // but should have lower precedence than the above - // x ? y : z - // x = y - - // The expression term have the highest precedence - if( op->nodeType == snExprTerm ) - return 1; - - // Evaluate operators by token - int tokenType = op->tokenType; - if( tokenType == ttStarStar ) - return 0; - - if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent ) - return -1; - - if( tokenType == ttPlus || tokenType == ttMinus ) - return -2; - - if( tokenType == ttBitShiftLeft || - tokenType == ttBitShiftRight || - tokenType == ttBitShiftRightArith ) - return -3; - - if( tokenType == ttAmp ) - return -4; - - if( tokenType == ttBitXor ) - return -5; - - if( tokenType == ttBitOr ) - return -6; - - if( tokenType == ttLessThanOrEqual || - tokenType == ttLessThan || - tokenType == ttGreaterThanOrEqual || - tokenType == ttGreaterThan ) - return -7; - - if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs ) - return -8; - - if( tokenType == ttAnd ) - return -9; - - if( tokenType == ttOr ) - return -10; - - // Unknown operator - asASSERT(false); - - return 0; -} - -asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArray &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct) -{ - matches.SetLength(0); - - for( asUINT n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]); - - // Does the function have arguments enough? - if( (int)desc->parameterTypes.GetLength() <= paramNum ) - continue; - - int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct); - if( cost != -1 ) - matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost))); - } - - return (asUINT)matches.GetLength(); -} - -int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct) -{ - // void expressions can match any out parameter, but nothing else - if( argExpr->type.IsVoidExpression() ) - { - if( desc->inOutFlags[paramNum] == asTM_OUTREF ) - return 0; - return -1; - } - - // Can we make the match by implicit conversion? - asSExprContext ti(engine); - ti.type = argExpr->type; - ti.methodName = argExpr->methodName; - ti.enumValue = argExpr->enumValue; - if( argExpr->type.dataType.IsPrimitive() ) - ti.type.dataType.MakeReference(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 - // function with an incorrect argument type, even though the type can normally be converted. - if( desc->parameterTypes[paramNum].IsReference() && - desc->inOutFlags[paramNum] == asTM_INOUTREF && - desc->parameterTypes[paramNum].GetTokenType() != ttQuestion ) - { - // Observe, that the below checks are only necessary for when unsafe references have been - // enabled by the application. Without this the &inout reference form wouldn't be allowed - // for these value types. - - // Don't allow a primitive to be converted to a reference of another primitive type - if( desc->parameterTypes[paramNum].IsPrimitive() && - desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() ) - { - asASSERT( engine->ep.allowUnsafeReferences ); - return -1; - } - - // 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() ) - { - asASSERT( engine->ep.allowUnsafeReferences ); - return -1; - } - - // Don't allow a non-handle expression to be converted to a reference to a handle - if( desc->parameterTypes[paramNum].IsObjectHandle() && - !argExpr->type.dataType.IsObjectHandle() ) - { - asASSERT( engine->ep.allowUnsafeReferences ); - return -1; - } - - // 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()) ) - { - asASSERT( engine->ep.allowUnsafeReferences ); - return -1; - } - } - - // How well does the argument match the function parameter? - if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) ) - return cost; - - // No match is available - return -1; -} - -void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy) -{ - // Reference parameters whose value won't be used don't evaluate the expression - if( paramType->IsReference() && !(refType & asTM_INREF) ) - { - // Store the original bytecode so that it can be reused when processing the deferred output parameter - asSExprContext *orig = asNEW(asSExprContext)(engine); - if( orig == 0 ) - { - // Out of memory - return; - } - MergeExprBytecodeAndType(orig, arg); - arg->origExpr = orig; - } - - PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy); - - // arg still holds the original expression for output parameters - ctx->bc.AddCode(&arg->bc); -} - -bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool isHandle) -{ - DetermineSingleFunc(lctx, node); - DetermineSingleFunc(rctx, node); - - ctx->exprNode = node; - - // What type of operator is it? - int token = node->tokenType; - if( token == ttUnrecognizedToken ) - { - // This happens when the compiler is inferring an assignment - // operation from another action, for example in preparing a value - // as a function argument - token = ttAssignment; - } - - // boolean operators are not overloadable - if( token == ttAnd || - token == ttOr || - token == ttXor ) - return false; - - // Dual operators can also be implemented as class methods - if( token == ttEqual || - token == ttNotEqual ) - { - // 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)); - if( r == 0 ) - { - // Try again by switching the order of the operands - r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); - } - - if( r == 1 ) - { - if( token == ttNotEqual ) - ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset); - - // Success, don't continue - return true; - } - else if( r < 0 ) - { - // Compiler error, don't continue - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); - return true; - } - } - - if( token == ttEqual || - token == ttNotEqual || - token == ttLessThan || - token == ttLessThanOrEqual || - token == ttGreaterThan || - token == ttGreaterThanOrEqual ) - { - bool swappedOrder = false; - - // 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)); - 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)); - } - - if( r == 1 ) - { - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - - int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true); - - ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0); - - if( token == ttEqual ) - ctx->bc.Instr(asBC_TZ); - else if( token == ttNotEqual ) - ctx->bc.Instr(asBC_TNZ); - else if( (token == ttLessThan && !swappedOrder) || - (token == ttGreaterThan && swappedOrder) ) - ctx->bc.Instr(asBC_TS); - else if( (token == ttLessThanOrEqual && !swappedOrder) || - (token == ttGreaterThanOrEqual && swappedOrder) ) - ctx->bc.Instr(asBC_TNP); - else if( (token == ttGreaterThan && !swappedOrder) || - (token == ttLessThan && swappedOrder) ) - ctx->bc.Instr(asBC_TP); - else if( (token == ttGreaterThanOrEqual && !swappedOrder) || - (token == ttLessThanOrEqual && swappedOrder) ) - ctx->bc.Instr(asBC_TNS); - - ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); - - ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true); - - // Success, don't continue - return true; - } - else if( r < 0 ) - { - // Compiler error, don't continue - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); - return true; - } - } - - // The rest of the operators are not commutative, and doesn't require specific return type - const char *op = 0, *op_r = 0; - switch( token ) - { - case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break; - case ttMinus: op = "opSub"; op_r = "opSub_r"; break; - case ttStar: op = "opMul"; op_r = "opMul_r"; break; - case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break; - case ttPercent: op = "opMod"; op_r = "opMod_r"; break; - case ttStarStar: op = "opPow"; op_r = "opPow_r"; break; - case ttBitOr: op = "opOr"; op_r = "opOr_r"; break; - case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break; - case ttBitXor: op = "opXor"; op_r = "opXor_r"; break; - case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break; - case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break; - case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break; - } - - // TODO: Might be interesting to support a concatenation operator, e.g. ~ - - if( op && op_r ) - { - // 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); - 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); - } - - if( r == 1 ) - { - // Success, don't continue - return true; - } - else if( r < 0 ) - { - // Compiler error, don't continue - ctx->type.SetDummy(); - return true; - } - } - - // Assignment operators - op = 0; - if( isHandle ) - { - // Only asOBJ_ASHANDLE types can get here - asASSERT( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ); - asASSERT( token == ttAssignment ); - - if( token == ttAssignment ) - op = "opHndlAssign"; - } - else - { - switch( token ) - { - case ttAssignment: op = "opAssign"; break; - case ttAddAssign: op = "opAddAssign"; break; - case ttSubAssign: op = "opSubAssign"; break; - case ttMulAssign: op = "opMulAssign"; break; - case ttDivAssign: op = "opDivAssign"; break; - case ttModAssign: op = "opModAssign"; break; - case ttPowAssign: op = "opPowAssign"; break; - case ttOrAssign: op = "opOrAssign"; break; - case ttAndAssign: op = "opAndAssign"; break; - case ttXorAssign: op = "opXorAssign"; break; - case ttShiftLeftAssign: op = "opShlAssign"; break; - case ttShiftRightLAssign: op = "opShrAssign"; break; - case ttShiftRightAAssign: op = "opUShrAssign"; break; - } - } - - 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) ) - { - if( token == ttAssignment ) - Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node); - else - Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node); - - // Set a dummy output - ctx->type.Set(lctx->type.dataType); - return true; - } - - // TODO: Shouldn't accept const lvalue with the assignment operators - - // Find the matching operator method - int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx); - if( r == 1 ) - { - // Success, don't continue - return true; - } - else if( r < 0 ) - { - // Compiler error, don't continue - ctx->type.SetDummy(); - return true; - } - } - - // No suitable operator was found - return false; -} - -// 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) -{ - // Find the matching method - if( lctx->type.dataType.IsObject() && - (!lctx->type.isExplicitHandle || - lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ) - { - asUINT n; - - // Is the left value a const? - bool isConst = lctx->type.dataType.IsObjectConst(); - - asCArray funcs; - asCObjectType *ot = lctx->type.dataType.GetObjectType(); - for( n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - asASSERT( func ); - if( func && func->name == methodName && - (!specificReturn || func->returnType == returnType) && - func->parameterTypes.GetLength() == 1 && - (!isConst || func->isReadOnly) ) - { - // Make sure the method is accessible by the module - if( builder->module->accessMask & func->accessMask ) - { - funcs.PushLast(func->id); - } - } - } - - // Which is the best matching function? - asCArray tempFuncs; - MatchArgument(funcs, tempFuncs, rctx, 0); - - // Find the lowest cost operator(s) - asCArray ops; - asUINT bestCost = asUINT(-1); - for( n = 0; n < tempFuncs.GetLength(); ++n ) - { - asUINT cost = tempFuncs[n].cost; - if( cost < bestCost ) - { - ops.SetLength(0); - bestCost = cost; - } - if( cost == bestCost ) - ops.PushLast(tempFuncs[n].funcId); - } - - // If the object is not const, then we need to prioritize non-const methods - if( !isConst ) - FilterConst(ops); - - // Did we find an operator? - if( ops.GetLength() == 1 ) - { - // 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); - size_t oldReservedVars = reservedVariables.GetLength(); - for( asUINT n = 0; n < rctx->deferredParams.GetLength(); n++ ) - { - if( 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); - - // Merge the bytecode so that it forms lvalue.methodName(rvalue) - asCArray args; - args.PushLast(rctx); - MergeExprBytecode(ctx, lctx); - ctx->type = lctx->type; - MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node); - - // Found matching operator - return 1; - } - else if( ops.GetLength() > 1 ) - { - Error(TXT_MORE_THAN_ONE_MATCHING_OP, node); - PrintMatchingFuncs(ops, node); - - ctx->type.SetDummy(); - - // Compiler error - return -1; - } - } - - // No matching operator - return 0; -} - -void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar) -{ - if( objectType ) - { - Dereference(ctx, true); - - // This following warning was removed as there may be valid reasons - // for calling non-const methods on temporary objects, and we shouldn't - // warn when there is no way of removing the warning. -/* - // Warn if the method is non-const and the object is temporary - // since the changes will be lost when the object is destroyed. - // If the object is accessed through a handle, then it is assumed - // the object is not temporary, even though the handle is. - if( ctx->type.isTemporary && - !ctx->type.dataType.IsObjectHandle() && - !engine->scriptFunctions[funcId]->isReadOnly ) - { - Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node); - Information(engine->scriptFunctions[funcId]->GetDeclaration(), node); - } -*/ } - - asCByteCode objBC(engine); - objBC.AddCode(&ctx->bc); - - PrepareFunctionCall(funcId, &ctx->bc, args); - - // Verify if any of the args variable offsets are used in the other code. - // If they are exchange the offset for a new one - asUINT n; - for( n = 0; n < args.GetLength(); n++ ) - { - if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) ) - { - // Release the current temporary variable - ReleaseTemporaryVariable(args[n]->type, 0); - - asCDataType dt = args[n]->type.dataType; - dt.MakeReference(false); - - int l = int(reservedVariables.GetLength()); - objBC.GetVarsUsed(reservedVariables); - ctx->bc.GetVarsUsed(reservedVariables); - int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset)); - reservedVariables.SetLength(l); - - asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) ); - - ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset); - args[n]->type.stackOffset = (short)newOffset; - args[n]->type.isTemporary = true; - args[n]->type.isVariable = true; - } - } - - // If the function will return a value type on the stack, then we must allocate space - // for that here and push the address on the stack as a hidden argument to the function - asCScriptFunction *func = builder->GetFunctionDescription(funcId); - if( func->DoesReturnOnStack() ) - { - asASSERT(!useVariable); - - useVariable = true; - stackOffset = AllocateVariable(func->returnType, true); - ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset)); - } - - ctx->bc.AddCode(&objBC); - - MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false); - - PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar); -} - -int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx) -{ - // Don't allow any operators on expressions that take address of class method, but allow it on global functions - if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) ) - { - Error(TXT_INVALID_OP_ON_METHOD, node); - return -1; - } - - // Don't allow any operators on void expressions - if( lctx->type.IsVoidExpression() || rctx->type.IsVoidExpression() ) - { - Error(TXT_VOID_CANT_BE_OPERAND, node); - return -1; - } - - IsVariableInitialized(&lctx->type, node); - IsVariableInitialized(&rctx->type, node); - - if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle || - lctx->type.IsNullConstant() || rctx->type.IsNullConstant() || - node->tokenType == ttIs || node->tokenType == ttNotIs ) - { - CompileOperatorOnHandles(node, lctx, rctx, ctx); - return 0; - } - else - { - // Compile an overloaded operator for the two operands - if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) ) - return 0; - - // If both operands are objects, then we shouldn't continue - if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() ) - { - asCString str; - str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf()); - Error(str, node); - ctx->type.SetDummy(); - return -1; - } - - // Process the property get accessors (if any) - ProcessPropertyGetAccessor(lctx, node); - ProcessPropertyGetAccessor(rctx, node); - - // Make sure we have two variables or constants - if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx); - if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx); - - // Make sure lctx doesn't end up with a variable used in rctx - if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) ) - { - int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx); - rctx->bc.ExchangeVar(lctx->type.stackOffset, offset); - ReleaseTemporaryVariable(offset, 0); - } - - // Math operators - // + - * / % ** += -= *= /= %= **= - int op = node->tokenType; - if( op == ttPlus || op == ttAddAssign || - op == ttMinus || op == ttSubAssign || - op == ttStar || op == ttMulAssign || - op == ttSlash || op == ttDivAssign || - op == ttPercent || op == ttModAssign || - op == ttStarStar || op == ttPowAssign ) - { - CompileMathOperator(node, lctx, rctx, ctx); - return 0; - } - - // Bitwise operators - // << >> >>> & | ^ <<= >>= >>>= &= |= ^= - if( op == ttAmp || op == ttAndAssign || - op == ttBitOr || op == ttOrAssign || - op == ttBitXor || op == ttXorAssign || - op == ttBitShiftLeft || op == ttShiftLeftAssign || - op == ttBitShiftRight || op == ttShiftRightLAssign || - op == ttBitShiftRightArith || op == ttShiftRightAAssign ) - { - CompileBitwiseOperator(node, lctx, rctx, ctx); - return 0; - } - - // Comparison operators - // == != < > <= >= - if( op == ttEqual || op == ttNotEqual || - op == ttLessThan || op == ttLessThanOrEqual || - op == ttGreaterThan || op == ttGreaterThanOrEqual ) - { - CompileComparisonOperator(node, lctx, rctx, ctx); - return 0; - } - - // Boolean operators - // && || ^^ - if( op == ttAnd || op == ttOr || op == ttXor ) - { - CompileBooleanOperator(node, lctx, rctx, ctx); - return 0; - } - } - - asASSERT(false); - return -1; -} - -void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude) -{ - int l = int(reservedVariables.GetLength()); - if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); - ConvertToTempVariable(ctx); - reservedVariables.SetLength(l); -} - -void asCCompiler::ConvertToTempVariable(asSExprContext *ctx) -{ - // This is only used for primitive types and null handles - asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() ); - - ConvertToVariable(ctx); - if( !ctx->type.isTemporary ) - { - if( ctx->type.dataType.IsPrimitive() ) - { - // Copy the variable to a temporary variable - int offset = AllocateVariable(ctx->type.dataType, true); - if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset); - else - ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset); - ctx->type.SetVariable(ctx->type.dataType, offset, true); - } - else - { - // We should never get here - asASSERT(false); - } - } -} - -void asCCompiler::ConvertToVariable(asSExprContext *ctx) -{ - // We should never get here while the context is still an unprocessed property accessor - asASSERT(ctx->property_get == 0 && ctx->property_set == 0); - - int offset; - if( !ctx->type.isVariable && - (ctx->type.dataType.IsObjectHandle() || - (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) ) - { - offset = AllocateVariable(ctx->type.dataType, true); - if( ctx->type.IsNullConstant() ) - { - if( ctx->bc.GetLastInstr() == asBC_PshNull ) - ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack - ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset); - } - else - { - Dereference(ctx, true); - - // Copy the object handle to a variable - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType()); - ctx->bc.Instr(asBC_PopPtr); - } - - // As this is an object the reference must be placed on the stack - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - ctx->type.SetVariable(ctx->type.dataType, offset, true); - ctx->type.dataType.MakeHandle(true); - ctx->type.dataType.MakeReference(true); - } - else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) && - ctx->type.dataType.IsPrimitive() ) - { - if( ctx->type.isConstant ) - { - offset = AllocateVariable(ctx->type.dataType, true); - if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) - ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) - ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) - ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue); - else - ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue); - - ctx->type.SetVariable(ctx->type.dataType, offset, true); - return; - } - else - { - asASSERT(ctx->type.dataType.IsPrimitive()); - asASSERT(ctx->type.dataType.IsReference()); - - ctx->type.dataType.MakeReference(false); - offset = AllocateVariable(ctx->type.dataType, true); - - // Read the value from the address in the register directly into the variable - if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) - ctx->bc.InstrSHORT(asBC_RDR1, (short)offset); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) - ctx->bc.InstrSHORT(asBC_RDR2, (short)offset); - else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - ctx->bc.InstrSHORT(asBC_RDR4, (short)offset); - else - ctx->bc.InstrSHORT(asBC_RDR8, (short)offset); - } - - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - ctx->type.SetVariable(ctx->type.dataType, offset, true); - } -} - -void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude) -{ - int l = int(reservedVariables.GetLength()); - if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); - ConvertToVariable(ctx); - reservedVariables.SetLength(l); -} - -void asCCompiler::ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node) -{ - asCArray funcs; - asCObjectType *ot = ctx->type.dataType.GetObjectType(); - if( ot ) - { - for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) - { - // Consider only implicit casts - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - if( func->name == "opImplConv" && - func->returnType.IsPrimitive() && - func->parameterTypes.GetLength() == 0 ) - funcs.PushLast(ot->methods[n]); - } - - // Use the one with the highest precision - const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8}; - while( funcs.GetLength() > 1 ) - { - eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType(); - int value1 = 11, value2 = 11; - for( asUINT i = 0; i < 10; i++ ) - { - if( returnType == match[i] ) - { - value1 = i; - break; - } - } - - for( asUINT n = 1; n < funcs.GetLength(); n++ ) - { - returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType(); - for( asUINT i = 0; i < 10; i++ ) - { - if( returnType == match[i] ) - { - value2 = i; - break; - } - } - - if( value2 >= value1 ) - { - // Remove this and continue searching - funcs.RemoveIndexUnordered(n--); - } - else - { - // Remove the first, and start over - funcs.RemoveIndexUnordered(0); - break; - } - } - } - - // Do the conversion - if( funcs.GetLength() ) - ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV); - } -} - -void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx) -{ - // TODO: If a constant is only using 32bits, then a 32bit operation is preferred - - // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it - - // If either operand is a non-primitive then use the primitive type - if( !lctx->type.dataType.IsPrimitive() ) - { - int l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - ImplicitConvObjectToBestMathType(lctx, node); - reservedVariables.SetLength(l); - } - if( !rctx->type.dataType.IsPrimitive() ) - { - int l = int(reservedVariables.GetLength()); - lctx->bc.GetVarsUsed(reservedVariables); - ImplicitConvObjectToBestMathType(rctx, node); - reservedVariables.SetLength(l); - } - - // Both types must now be primitives. Implicitly convert them so they match - asCDataType to; - if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() ) - to.SetTokenType(ttDouble); - else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() ) - to.SetTokenType(ttFloat); - else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - // Convert to int64 if both are signed or if one is non-constant and signed - if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) || - (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) ) - to.SetTokenType(ttInt64); - else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() ) - to.SetTokenType(ttUInt64); - else - to.SetTokenType(ttInt64); - } - else - { - // Convert to int32 if both are signed or if one is non-constant and signed - if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) || - (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) ) - to.SetTokenType(ttInt); - else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() ) - to.SetTokenType(ttUInt); - else - to.SetTokenType(ttInt); - } - - // If doing an operation with double constant and float variable, the constant should be converted to float - if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) || - (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) ) - to.SetTokenType(ttFloat); - - // If integer division is disabled, convert to floating-point - int op = node->tokenType; - if( engine->ep.disableIntegerDivision && - (op == ttSlash || op == ttDivAssign) && - (to.IsIntegerType() || to.IsUnsignedType()) ) - { - // Use double to avoid losing precision when dividing with 32bit ints - // For 64bit ints there is unfortunately no greater type so with those - // there is still a risk of loosing precision - to.SetTokenType(ttDouble); - } - - // Do the actual conversion - int l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - lctx->bc.GetVarsUsed(reservedVariables); - - if( lctx->type.dataType.IsReference() ) - ConvertToVariable(lctx); - if( rctx->type.dataType.IsReference() ) - ConvertToVariable(rctx); - - if( to.IsPrimitive() ) - { - // ttStarStar allows an integer, right-hand operand and a double - // left-hand operand. - if( (op == ttStarStar || op == ttPowAssign) && - lctx->type.dataType.IsDoubleType() && - (rctx->type.dataType.IsIntegerType() || - rctx->type.dataType.IsUnsignedType()) ) - { - to.SetTokenType(ttInt); - ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true); - to.SetTokenType(ttDouble); - } - else - { - ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true); - ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true); - } - } - reservedVariables.SetLength(l); - - // Verify that the conversion was successful - if( !lctx->type.dataType.IsIntegerType() && - !lctx->type.dataType.IsUnsignedType() && - !lctx->type.dataType.IsFloatType() && - !lctx->type.dataType.IsDoubleType() ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf()); - Error(str, node); - - ctx->type.SetDummy(); - return; - } - - if( !rctx->type.dataType.IsIntegerType() && - !rctx->type.dataType.IsUnsignedType() && - !rctx->type.dataType.IsFloatType() && - !rctx->type.dataType.IsDoubleType() ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf()); - Error(str, node); - - ctx->type.SetDummy(); - return; - } - - 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 && - (op == ttSlash || op == ttDivAssign || - op == ttPercent || op == ttModAssign) ) - { - Error(TXT_DIVIDE_BY_ZERO, node); - } - - if( !isConstant ) - { - ConvertToVariableNotIn(lctx, rctx); - ConvertToVariableNotIn(rctx, lctx); - ReleaseTemporaryVariable(lctx->type, &lctx->bc); - ReleaseTemporaryVariable(rctx->type, &rctx->bc); - - if( op == ttAddAssign || op == ttSubAssign || - op == ttMulAssign || op == ttDivAssign || - op == ttModAssign || op == ttPowAssign ) - { - // Merge the operands in the different order so that they are evaluated correctly - MergeExprBytecode(ctx, rctx); - MergeExprBytecode(ctx, lctx); - - // We must not process the deferred parameters yet, as - // it may overwrite the lvalue kept in the register - } - else - { - MergeExprBytecode(ctx, lctx); - MergeExprBytecode(ctx, rctx); - - ProcessDeferredParams(ctx); - } - - asEBCInstr instruction = asBC_ADDi; - if( lctx->type.dataType.IsIntegerType() || - lctx->type.dataType.IsUnsignedType() ) - { - if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - if( op == ttPlus || op == ttAddAssign ) - instruction = asBC_ADDi; - else if( op == ttMinus || op == ttSubAssign ) - instruction = asBC_SUBi; - else if( op == ttStar || op == ttMulAssign ) - instruction = asBC_MULi; - else if( op == ttSlash || op == ttDivAssign ) - { - if( lctx->type.dataType.IsIntegerType() ) - instruction = asBC_DIVi; - else - instruction = asBC_DIVu; - } - else if( op == ttPercent || op == ttModAssign ) - { - if( lctx->type.dataType.IsIntegerType() ) - instruction = asBC_MODi; - else - instruction = asBC_MODu; - } - else if( op == ttStarStar || op == ttPowAssign ) - { - if( lctx->type.dataType.IsIntegerType() ) - instruction = asBC_POWi; - else - instruction = asBC_POWu; - } - } - else - { - if( op == ttPlus || op == ttAddAssign ) - instruction = asBC_ADDi64; - else if( op == ttMinus || op == ttSubAssign ) - instruction = asBC_SUBi64; - else if( op == ttStar || op == ttMulAssign ) - instruction = asBC_MULi64; - else if( op == ttSlash || op == ttDivAssign ) - { - if( lctx->type.dataType.IsIntegerType() ) - instruction = asBC_DIVi64; - else - instruction = asBC_DIVu64; - } - else if( op == ttPercent || op == ttModAssign ) - { - if( lctx->type.dataType.IsIntegerType() ) - instruction = asBC_MODi64; - else - instruction = asBC_MODu64; - } - else if( op == ttStarStar || op == ttPowAssign ) - { - if( lctx->type.dataType.IsIntegerType() ) - instruction = asBC_POWi64; - else - instruction = asBC_POWu64; - } - } - } - else if( lctx->type.dataType.IsFloatType() ) - { - if( op == ttPlus || op == ttAddAssign ) - instruction = asBC_ADDf; - else if( op == ttMinus || op == ttSubAssign ) - instruction = asBC_SUBf; - else if( op == ttStar || op == ttMulAssign ) - instruction = asBC_MULf; - else if( op == ttSlash || op == ttDivAssign ) - instruction = asBC_DIVf; - else if( op == ttPercent || op == ttModAssign ) - instruction = asBC_MODf; - else if( op == ttStarStar || op == ttPowAssign ) - instruction = asBC_POWf; - } - else if( lctx->type.dataType.IsDoubleType() ) - { - if( rctx->type.dataType.IsIntegerType() ) - { - asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1); - - if( op == ttStarStar || op == ttPowAssign ) - instruction = asBC_POWdi; - else - asASSERT(false); // Should not be possible - } - else - { - if( op == ttPlus || op == ttAddAssign ) - instruction = asBC_ADDd; - else if( op == ttMinus || op == ttSubAssign ) - instruction = asBC_SUBd; - else if( op == ttStar || op == ttMulAssign ) - instruction = asBC_MULd; - else if( op == ttSlash || op == ttDivAssign ) - instruction = asBC_DIVd; - else if( op == ttPercent || op == ttModAssign ) - instruction = asBC_MODd; - else if( op == ttStarStar || op == ttPowAssign ) - instruction = asBC_POWd; - } - } - else - { - // Shouldn't be possible - asASSERT(false); - } - - // Do the operation - int a = AllocateVariable(lctx->type.dataType, true); - int b = lctx->type.stackOffset; - int c = rctx->type.stackOffset; - - ctx->bc.InstrW_W_W(instruction, a, b, c); - - ctx->type.SetVariable(lctx->type.dataType, a, true); - } - else - { - // Both values are constants - if( lctx->type.dataType.IsIntegerType() || - lctx->type.dataType.IsUnsignedType() ) - { - if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - int v = 0; - if( op == ttPlus ) - v = lctx->type.intValue + rctx->type.intValue; - else if( op == ttMinus ) - v = lctx->type.intValue - rctx->type.intValue; - else if( op == ttStar ) - v = lctx->type.intValue * rctx->type.intValue; - 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) ) - v = 0; - else - if( lctx->type.dataType.IsIntegerType() ) - v = lctx->type.intValue / rctx->type.intValue; - else - v = lctx->type.dwordValue / rctx->type.dwordValue; - } - 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) ) - v = 0; - else - if( lctx->type.dataType.IsIntegerType() ) - v = lctx->type.intValue % rctx->type.intValue; - else - v = lctx->type.dwordValue % rctx->type.dwordValue; - } - else if( op == ttStarStar ) - { - bool isOverflow; - if( lctx->type.dataType.IsIntegerType() ) - v = as_powi(lctx->type.intValue, rctx->type.intValue, isOverflow); - else - v = as_powu(lctx->type.dwordValue, rctx->type.dwordValue, isOverflow); - } - - 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 ) - ctx->type.dataType.SetTokenType(ttInt); - } - else - { - asQWORD v = 0; - if( op == ttPlus ) - v = lctx->type.qwordValue + rctx->type.qwordValue; - else if( op == ttMinus ) - v = lctx->type.qwordValue - rctx->type.qwordValue; - else if( op == ttStar ) - v = lctx->type.qwordValue * rctx->type.qwordValue; - 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)) ) - v = 0; - else - if( lctx->type.dataType.IsIntegerType() ) - v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue); - else - v = lctx->type.qwordValue / rctx->type.qwordValue; - } - 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)) ) - v = 0; - else - if( lctx->type.dataType.IsIntegerType() ) - v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue); - else - v = lctx->type.qwordValue % rctx->type.qwordValue; - } - else if( op == ttStarStar ) - { - bool isOverflow; - if( lctx->type.dataType.IsIntegerType() ) - v = as_powi64(asINT64(lctx->type.qwordValue), asINT64(rctx->type.qwordValue), isOverflow); - else - v = as_powu64(lctx->type.qwordValue, rctx->type.qwordValue, isOverflow); - } - - 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 ) - ctx->type.dataType.SetTokenType(ttInt64); - } - } - else if( lctx->type.dataType.IsFloatType() ) - { - float v = 0.0f; - if( op == ttPlus ) - v = lctx->type.floatValue + rctx->type.floatValue; - else if( op == ttMinus ) - v = lctx->type.floatValue - rctx->type.floatValue; - else if( op == ttStar ) - v = lctx->type.floatValue * rctx->type.floatValue; - else if( op == ttSlash ) - { - if( rctx->type.floatValue == 0 ) - v = 0; - else - v = lctx->type.floatValue / rctx->type.floatValue; - } - else if( op == ttPercent ) - { - if( rctx->type.floatValue == 0 ) - v = 0; - else - v = fmodf(lctx->type.floatValue, rctx->type.floatValue); - } - else if( op == ttStarStar ) - v = pow(lctx->type.floatValue, rctx->type.floatValue); - - ctx->type.SetConstantF(lctx->type.dataType, v); - } - else if( lctx->type.dataType.IsDoubleType() ) - { - double v = 0.0; - if( rctx->type.dataType.IsIntegerType() ) - { - asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1); - - if( op == ttStarStar || op == ttPowAssign ) - v = pow(lctx->type.doubleValue, rctx->type.intValue); - else - asASSERT(false); // Should not be possible - } - else - { - if( op == ttPlus ) - v = lctx->type.doubleValue + rctx->type.doubleValue; - else if( op == ttMinus ) - v = lctx->type.doubleValue - rctx->type.doubleValue; - else if( op == ttStar ) - v = lctx->type.doubleValue * rctx->type.doubleValue; - else if( op == ttSlash ) - { - if( rctx->type.doubleValue == 0 ) - v = 0; - else - v = lctx->type.doubleValue / rctx->type.doubleValue; - } - else if( op == ttPercent ) - { - if( rctx->type.doubleValue == 0 ) - v = 0; - else - v = fmod(lctx->type.doubleValue, rctx->type.doubleValue); - } - else if( op == ttStarStar ) - v = pow(lctx->type.doubleValue, rctx->type.doubleValue); - } - - ctx->type.SetConstantD(lctx->type.dataType, v); - } - else - { - // Shouldn't be possible - asASSERT(false); - } - } -} - -void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx) -{ - // TODO: If a constant is only using 32bits, then a 32bit operation is preferred - - eTokenType op = node->tokenType; - if( op == ttAmp || op == ttAndAssign || - op == ttBitOr || op == ttOrAssign || - op == ttBitXor || op == ttXorAssign ) - { - // Convert left hand operand to integer if it's not already one - asCDataType to; - if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || - rctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - to.SetTokenType(ttInt64); - else - to.SetTokenType(ttInt); - - // Do the actual conversion (keep sign/unsigned if possible) - int l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - if( lctx->type.dataType.IsUnsignedType() ) - to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 ); - else - to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 ); - ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true); - reservedVariables.SetLength(l); - - // Verify that the conversion was successful - if( lctx->type.dataType != to ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - } - - // Convert right hand operand to same size as left hand - l = int(reservedVariables.GetLength()); - lctx->bc.GetVarsUsed(reservedVariables); - if( rctx->type.dataType.IsUnsignedType() ) - to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 ); - else - to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 ); - ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true); - reservedVariables.SetLength(l); - if( rctx->type.dataType != to ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf()); - Error(str, node); - } - - bool isConstant = lctx->type.isConstant && rctx->type.isConstant; - - if( !isConstant ) - { - ConvertToVariableNotIn(lctx, rctx); - ConvertToVariableNotIn(rctx, lctx); - ReleaseTemporaryVariable(lctx->type, &lctx->bc); - ReleaseTemporaryVariable(rctx->type, &rctx->bc); - - if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign ) - { - // Compound assignments execute the right hand value first - MergeExprBytecode(ctx, rctx); - MergeExprBytecode(ctx, lctx); - } - else - { - MergeExprBytecode(ctx, lctx); - MergeExprBytecode(ctx, rctx); - } - ProcessDeferredParams(ctx); - - asEBCInstr instruction = asBC_BAND; - if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - if( op == ttAmp || op == ttAndAssign ) - instruction = asBC_BAND; - else if( op == ttBitOr || op == ttOrAssign ) - instruction = asBC_BOR; - else if( op == ttBitXor || op == ttXorAssign ) - instruction = asBC_BXOR; - } - else - { - if( op == ttAmp || op == ttAndAssign ) - instruction = asBC_BAND64; - else if( op == ttBitOr || op == ttOrAssign ) - instruction = asBC_BOR64; - else if( op == ttBitXor || op == ttXorAssign ) - instruction = asBC_BXOR64; - } - - // Do the operation - int a = AllocateVariable(lctx->type.dataType, true); - int b = lctx->type.stackOffset; - int c = rctx->type.stackOffset; - - ctx->bc.InstrW_W_W(instruction, a, b, c); - - ctx->type.SetVariable(lctx->type.dataType, a, true); - } - else - { - if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - asQWORD v = 0; - if( op == ttAmp ) - v = lctx->type.qwordValue & rctx->type.qwordValue; - else if( op == ttBitOr ) - v = lctx->type.qwordValue | rctx->type.qwordValue; - else if( op == ttBitXor ) - v = lctx->type.qwordValue ^ rctx->type.qwordValue; - - // Remember the result - ctx->type.SetConstantQW(lctx->type.dataType, v); - } - else - { - asDWORD v = 0; - if( op == ttAmp ) - v = lctx->type.dwordValue & rctx->type.dwordValue; - else if( op == ttBitOr ) - v = lctx->type.dwordValue | rctx->type.dwordValue; - else if( op == ttBitXor ) - v = lctx->type.dwordValue ^ rctx->type.dwordValue; - - // Remember the result - ctx->type.SetConstantDW(lctx->type.dataType, v); - } - } - } - else if( op == ttBitShiftLeft || op == ttShiftLeftAssign || - op == ttBitShiftRight || op == ttShiftRightLAssign || - op == ttBitShiftRightArith || op == ttShiftRightAAssign ) - { - // Don't permit object to primitive conversion, since we don't know which integer type is the correct one - if( lctx->type.dataType.IsObject() ) - { - asCString str; - str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf()); - Error(str, node); - - // Set an integer value and allow the compiler to continue - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); - return; - } - - // Convert left hand operand to integer if it's not already one - asCDataType to = lctx->type.dataType; - if( lctx->type.dataType.IsUnsignedType() && - lctx->type.dataType.GetSizeInMemoryBytes() < 4 ) - { - to = asCDataType::CreatePrimitive(ttUInt, false); - } - else if( !lctx->type.dataType.IsUnsignedType() ) - { - asCDataType to; - if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - to.SetTokenType(ttInt64); - else - to.SetTokenType(ttInt); - } - - // Do the actual conversion - int l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true); - reservedVariables.SetLength(l); - - // Verify that the conversion was successful - if( lctx->type.dataType != to ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - } - - // Right operand must be 32bit uint - l = int(reservedVariables.GetLength()); - lctx->bc.GetVarsUsed(reservedVariables); - ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true); - reservedVariables.SetLength(l); - if( !rctx->type.dataType.IsUnsignedType() ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint"); - Error(str, node); - } - - bool isConstant = lctx->type.isConstant && rctx->type.isConstant; - - if( !isConstant ) - { - ConvertToVariableNotIn(lctx, rctx); - ConvertToVariableNotIn(rctx, lctx); - ReleaseTemporaryVariable(lctx->type, &lctx->bc); - ReleaseTemporaryVariable(rctx->type, &rctx->bc); - - if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign ) - { - // Compound assignments execute the right hand value first - MergeExprBytecode(ctx, rctx); - MergeExprBytecode(ctx, lctx); - } - else - { - MergeExprBytecode(ctx, lctx); - MergeExprBytecode(ctx, rctx); - } - ProcessDeferredParams(ctx); - - asEBCInstr instruction = asBC_BSLL; - if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - if( op == ttBitShiftLeft || op == ttShiftLeftAssign ) - instruction = asBC_BSLL; - else if( op == ttBitShiftRight || op == ttShiftRightLAssign ) - instruction = asBC_BSRL; - else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign ) - instruction = asBC_BSRA; - } - else - { - if( op == ttBitShiftLeft || op == ttShiftLeftAssign ) - instruction = asBC_BSLL64; - else if( op == ttBitShiftRight || op == ttShiftRightLAssign ) - instruction = asBC_BSRL64; - else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign ) - instruction = asBC_BSRA64; - } - - // Do the operation - int a = AllocateVariable(lctx->type.dataType, true); - int b = lctx->type.stackOffset; - int c = rctx->type.stackOffset; - - ctx->bc.InstrW_W_W(instruction, a, b, c); - - ctx->type.SetVariable(lctx->type.dataType, a, true); - } - else - { - if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - asDWORD v = 0; - if( op == ttBitShiftLeft ) - v = lctx->type.dwordValue << rctx->type.dwordValue; - else if( op == ttBitShiftRight ) - v = lctx->type.dwordValue >> rctx->type.dwordValue; - else if( op == ttBitShiftRightArith ) - v = lctx->type.intValue >> rctx->type.dwordValue; - - ctx->type.SetConstantDW(lctx->type.dataType, v); - } - else - { - asQWORD v = 0; - if( op == ttBitShiftLeft ) - v = lctx->type.qwordValue << rctx->type.dwordValue; - else if( op == ttBitShiftRight ) - v = lctx->type.qwordValue >> rctx->type.dwordValue; - else if( op == ttBitShiftRightArith ) - v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue; - - ctx->type.SetConstantQW(lctx->type.dataType, v); - } - } - } -} - -void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx) -{ - // Both operands must be of the same type - - // If either operand is a non-primitive then first convert them to the best number type - if( !lctx->type.dataType.IsPrimitive() ) - { - int l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - ImplicitConvObjectToBestMathType(lctx, node); - reservedVariables.SetLength(l); - } - if( !rctx->type.dataType.IsPrimitive() ) - { - int l = int(reservedVariables.GetLength()); - lctx->bc.GetVarsUsed(reservedVariables); - ImplicitConvObjectToBestMathType(rctx, node); - reservedVariables.SetLength(l); - } - - // Implicitly convert the operands to matching types - asCDataType to; - if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() ) - to.SetTokenType(ttDouble); - else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() ) - to.SetTokenType(ttFloat); - else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - // Convert to int64 if both are signed or if one is non-constant and signed - if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) || - (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) ) - to.SetTokenType(ttInt64); - else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() ) - to.SetTokenType(ttUInt64); - else - to.SetTokenType(ttInt64); - } - else - { - // Convert to int32 if both are signed or if one is non-constant and signed - if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) || - (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) ) - to.SetTokenType(ttInt); - else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() ) - to.SetTokenType(ttUInt); - else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() ) - to.SetTokenType(ttBool); - else - to.SetTokenType(ttInt); - } - - // If doing an operation with double constant and float variable, the constant should be converted to float - if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) || - (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) ) - to.SetTokenType(ttFloat); - - asASSERT( to.GetTokenType() != ttUnrecognizedToken ); - - // Do we have a mismatch between the sign of the operand? - bool signMismatch = false; - for( int n = 0; !signMismatch && n < 2; n++ ) - { - asSExprContext *op = n ? rctx : lctx; - - if( op->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( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 ) - { - if( !(op->type.qwordValue & (asQWORD(1)<<63)) ) - signMismatch = false; - } - else - { - if( !(op->type.dwordValue & (1<<31)) ) - signMismatch = false; - } - - // It's not necessary to check for floats or double, because if - // it was then the types for the conversion will never be unsigned - } - } - } - - // Check for signed/unsigned mismatch - if( signMismatch ) - Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node); - - // Attempt to resolve ambiguous enumerations - if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" ) - ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV); - else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" ) - ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV); - - // Do the actual conversion - int l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - - if( lctx->type.dataType.IsReference() ) - ConvertToVariable(lctx); - if( rctx->type.dataType.IsReference() ) - ConvertToVariable(rctx); - - ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); - ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV); - reservedVariables.SetLength(l); - - // Verify that the conversion was successful - bool ok = true; - if( !lctx->type.dataType.IsEqualExceptConst(to) ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - ok = false; - } - - if( !rctx->type.dataType.IsEqualExceptConst(to) ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - ok = false; - } - - if( !ok ) - { - // It wasn't possible to get two valid operands, so we just return - // a boolean result and let the compiler continue. - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); - return; - } - - bool isConstant = lctx->type.isConstant && rctx->type.isConstant; - int op = node->tokenType; - - if( !isConstant ) - { - if( to.IsBooleanType() ) - { - int op = node->tokenType; - if( op == ttEqual || op == ttNotEqual ) - { - // Must convert to temporary variable, because we are changing the value before comparison - ConvertToTempVariableNotIn(lctx, rctx); - ConvertToTempVariableNotIn(rctx, lctx); - ReleaseTemporaryVariable(lctx->type, &lctx->bc); - ReleaseTemporaryVariable(rctx->type, &rctx->bc); - - // Make sure they are equal if not false - lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset); - rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset); - - MergeExprBytecode(ctx, lctx); - MergeExprBytecode(ctx, rctx); - ProcessDeferredParams(ctx); - - int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true); - int b = lctx->type.stackOffset; - int c = rctx->type.stackOffset; - - if( op == ttEqual ) - { - ctx->bc.InstrW_W(asBC_CMPi,b,c); - ctx->bc.Instr(asBC_TZ); - ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); - } - else if( op == ttNotEqual ) - { - ctx->bc.InstrW_W(asBC_CMPi,b,c); - ctx->bc.Instr(asBC_TNZ); - ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); - } - - ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true); - } - else - { - // TODO: Use TXT_ILLEGAL_OPERATION_ON - Error(TXT_ILLEGAL_OPERATION, node); - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0); - } - } - else - { - ConvertToVariableNotIn(lctx, rctx); - ConvertToVariableNotIn(rctx, lctx); - ReleaseTemporaryVariable(lctx->type, &lctx->bc); - ReleaseTemporaryVariable(rctx->type, &rctx->bc); - - MergeExprBytecode(ctx, lctx); - MergeExprBytecode(ctx, rctx); - ProcessDeferredParams(ctx); - - asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ; - - if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - iCmp = asBC_CMPi; - else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - iCmp = asBC_CMPu; - else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - iCmp = asBC_CMPi64; - else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - iCmp = asBC_CMPu64; - else if( lctx->type.dataType.IsFloatType() ) - iCmp = asBC_CMPf; - else if( lctx->type.dataType.IsDoubleType() ) - iCmp = asBC_CMPd; - else - asASSERT(false); - - if( op == ttEqual ) - iT = asBC_TZ; - else if( op == ttNotEqual ) - iT = asBC_TNZ; - else if( op == ttLessThan ) - iT = asBC_TS; - else if( op == ttLessThanOrEqual ) - iT = asBC_TNP; - else if( op == ttGreaterThan ) - iT = asBC_TP; - else if( op == ttGreaterThanOrEqual ) - iT = asBC_TNS; - - int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true); - int b = lctx->type.stackOffset; - int c = rctx->type.stackOffset; - - ctx->bc.InstrW_W(iCmp, b, c); - ctx->bc.Instr(iT); - ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); - - ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true); - } - } - else - { - if( to.IsBooleanType() ) - { - int op = node->tokenType; - if( op == ttEqual || op == ttNotEqual ) - { - // 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; - - 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; - } - - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v); - } - else - { - // TODO: Use TXT_ILLEGAL_OPERATION_ON - Error(TXT_ILLEGAL_OPERATION, node); - } - } - else - { - int i = 0; - if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - int v = lctx->type.intValue - rctx->type.intValue; - 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; - 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); - 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; - if( v1 < v2 ) i = -1; - if( v1 > v2 ) i = 1; - } - else if( lctx->type.dataType.IsFloatType() ) - { - float v = lctx->type.floatValue - rctx->type.floatValue; - if( v < 0 ) i = -1; - if( v > 0 ) i = 1; - } - else if( lctx->type.dataType.IsDoubleType() ) - { - double v = lctx->type.doubleValue - rctx->type.doubleValue; - if( v < 0 ) i = -1; - if( v > 0 ) i = 1; - } - - - if( op == ttEqual ) - i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - else if( op == ttNotEqual ) - i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - else if( op == ttLessThan ) - i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - else if( op == ttLessThanOrEqual ) - i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - else if( op == ttGreaterThan ) - i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - else if( op == ttGreaterThanOrEqual ) - i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i); - } - } -} - -void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference) -{ - // Put the result on the stack - if( asReference ) - { - ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); - ctx->type.dataType.MakeReference(true); - } - else - { - if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset); - else - ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset); - } -} - -void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx) -{ - // Both operands must be booleans - asCDataType to; - to.SetTokenType(ttBool); - - // Do the actual conversion - int l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - lctx->bc.GetVarsUsed(reservedVariables); - ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); - ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV); - reservedVariables.SetLength(l); - - // Verify that the conversion was successful - if( !lctx->type.dataType.IsBooleanType() ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool"); - Error(str, node); - // Force the conversion to allow compilation to proceed - lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); - } - - if( !rctx->type.dataType.IsBooleanType() ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool"); - Error(str, node); - // Force the conversion to allow compilation to proceed - rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); - } - - bool isConstant = lctx->type.isConstant && rctx->type.isConstant; - - ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true)); - - // What kind of operator is it? - int op = node->tokenType; - if( op == ttXor ) - { - if( !isConstant ) - { - // Must convert to temporary variable, because we are changing the value before comparison - ConvertToTempVariableNotIn(lctx, rctx); - ConvertToTempVariableNotIn(rctx, lctx); - ReleaseTemporaryVariable(lctx->type, &lctx->bc); - ReleaseTemporaryVariable(rctx->type, &rctx->bc); - - // Make sure they are equal if not false - lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset); - rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset); - - MergeExprBytecode(ctx, lctx); - MergeExprBytecode(ctx, rctx); - ProcessDeferredParams(ctx); - - int a = AllocateVariable(ctx->type.dataType, true); - int b = lctx->type.stackOffset; - int c = rctx->type.stackOffset; - - ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c); - - ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true); - } - else - { - // 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; - - asBYTE v = 0; - v = lctx->type.byteValue - rctx->type.byteValue; - if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; - - ctx->type.isConstant = true; - ctx->type.byteValue = 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; - - asDWORD v = 0; - v = lctx->type.intValue - rctx->type.intValue; - if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; - - ctx->type.isConstant = true; - ctx->type.dwordValue = v; -#endif - } - } - else if( op == ttAnd || - op == ttOr ) - { - if( !isConstant ) - { - // If or-operator and first value is 1 the second value shouldn't be calculated - // if and-operator and first value is 0 the second value shouldn't be calculated - ConvertToVariable(lctx); - ReleaseTemporaryVariable(lctx->type, &lctx->bc); - MergeExprBytecode(ctx, lctx); - - int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true); - - int label1 = nextLabel++; - int label2 = nextLabel++; - - ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset); - ctx->bc.Instr(asBC_ClrHi); - if( op == ttAnd ) - { - ctx->bc.InstrDWORD(asBC_JNZ, label1); - ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0); - ctx->bc.InstrINT(asBC_JMP, label2); - } - else if( op == ttOr ) - { - ctx->bc.InstrDWORD(asBC_JZ, label1); -#if AS_SIZEOF_BOOL == 1 - ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE); -#else - ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE); -#endif - ctx->bc.InstrINT(asBC_JMP, label2); - } - - ctx->bc.Label((short)label1); - ConvertToVariable(rctx); - ReleaseTemporaryVariable(rctx->type, &rctx->bc); - rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset); - MergeExprBytecode(ctx, rctx); - ctx->bc.Label((short)label2); - - ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true); - } - else - { -#if AS_SIZEOF_BOOL == 1 - asBYTE v = 0; - if( op == ttAnd ) - v = lctx->type.byteValue && rctx->type.byteValue; - else if( op == ttOr ) - v = lctx->type.byteValue || rctx->type.byteValue; - - // Remember the result - ctx->type.isConstant = true; - ctx->type.byteValue = v; -#else - asDWORD v = 0; - if( op == ttAnd ) - v = lctx->type.dwordValue && rctx->type.dwordValue; - else if( op == ttOr ) - v = lctx->type.dwordValue || rctx->type.dwordValue; - - // Remember the result - ctx->type.isConstant = true; - ctx->type.dwordValue = v; -#endif - } - } -} - -void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx) -{ - // Process the property accessor as get - ProcessPropertyGetAccessor(lctx, node); - ProcessPropertyGetAccessor(rctx, node); - - DetermineSingleFunc(lctx, node); - DetermineSingleFunc(rctx, node); - - // Make sure lctx doesn't end up with a variable used in rctx - if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) ) - { - asCArray vars; - rctx->bc.GetVarsUsed(vars); - int offset = AllocateVariable(lctx->type.dataType, true); - rctx->bc.ExchangeVar(lctx->type.stackOffset, offset); - ReleaseTemporaryVariable(offset, 0); - } - - // Warn if not both operands are explicit handles or null handles - if( (node->tokenType == ttEqual || node->tokenType == 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)))) ) - { - 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))) && - (node->tokenType == ttEqual || node->tokenType == ttIs || - node->tokenType == ttNotEqual || node->tokenType == 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)); - if( r == 0 ) - { - // Try again by switching the order of the operands - r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); - } - - if( r == 1 ) - { - if( node->tokenType == ttNotEqual || node->tokenType == ttNotIs ) - ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset); - - // Success, don't continue - return; - } - else if( r == 0 ) - { - // Couldn't find opEquals method - Error(TXT_NO_APPROPRIATE_OPEQUALS, node); - } - - // Compiler error, don't continue - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); - return; - } - - - // Implicitly convert null to the other type - asCDataType to; - if( lctx->type.IsNullConstant() ) - to = rctx->type.dataType; - else if( rctx->type.IsNullConstant() ) - to = lctx->type.dataType; - else - { - // Find a common base type - asSExprContext 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() ) - to = lctx->type.dataType; - else - to = rctx->type.dataType; - } - - // Need to pop the value if it is a null constant - if( lctx->type.IsNullConstant() ) - lctx->bc.Instr(asBC_PopPtr); - if( rctx->type.IsNullConstant() ) - rctx->bc.Instr(asBC_PopPtr); - - // Convert both sides to explicit handles - to.MakeHandle(true); - to.MakeReference(false); - - if( !to.IsObjectHandle() ) - { - // Compiler error, don't continue - Error(TXT_OPERANDS_MUST_BE_HANDLES, node); - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); - return; - } - - // Do the conversion - ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); - ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV); - - // Both operands must be of the same type - - // Verify that the conversion was successful - if( !lctx->type.dataType.IsEqualExceptConst(to) ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - } - - if( !rctx->type.dataType.IsEqualExceptConst(to) ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf()); - Error(str, node); - } - - // Make sure it really is handles that are being compared - if( !lctx->type.dataType.IsObjectHandle() ) - { - Error(TXT_OPERANDS_MUST_BE_HANDLES, node); - } - - ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true)); - - int op = node->tokenType; - if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs ) - { - // 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; - if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 ) - rctx->type.isVariable = false; - - // TODO: runtime optimize: don't do REFCPY if not necessary - ConvertToVariableNotIn(lctx, rctx); - ConvertToVariable(rctx); - - // Pop the pointers from the stack as they will not be used - lctx->bc.Instr(asBC_PopPtr); - rctx->bc.Instr(asBC_PopPtr); - - MergeExprBytecode(ctx, lctx); - MergeExprBytecode(ctx, rctx); - - int a = AllocateVariable(ctx->type.dataType, true); - int b = lctx->type.stackOffset; - int c = rctx->type.stackOffset; - - ctx->bc.InstrW_W(asBC_CmpPtr, b, c); - - if( op == ttEqual || op == ttIs ) - ctx->bc.Instr(asBC_TZ); - else if( op == ttNotEqual || op == ttNotIs ) - ctx->bc.Instr(asBC_TNZ); - - ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); - - ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true); - - ReleaseTemporaryVariable(lctx->type, &ctx->bc); - ReleaseTemporaryVariable(rctx->type, &ctx->bc); - ProcessDeferredParams(ctx); - } - else - { - // TODO: Use TXT_ILLEGAL_OPERATION_ON - Error(TXT_ILLEGAL_OPERATION, node); - } -} - - -void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar) -{ - asCScriptFunction *descr = builder->GetFunctionDescription(funcId); - - // A shared object may not call non-shared functions - if( outFunc->IsShared() && !descr->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf()); - Error(msg, ctx->exprNode); - } - - // Check if the function is private - if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() ) - { - asCString msg; - msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf()); - Error(msg, ctx->exprNode); - } - - int argSize = descr->GetSpaceNeededForArguments(); - - // If we're calling a class method we must make sure the object is guaranteed to stay - // 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 && - (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) && - (descr->returnType.IsReference() || (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCRIPT_OBJECT)) && - !(ctx->type.isVariable || ctx->type.isTemporary) && - !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) && - !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) ) - { - // 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 - // 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()); - - // Add the release of this reference as a deferred expression - asSDeferredParam deferred; - deferred.origExpr = 0; - deferred.argInOutFlags = asTM_INREF; - deferred.argNode = 0; - deferred.argType.SetVariable(ctx->type.dataType, tempRef, true); - ctx->deferredParams.PushLast(deferred); - - // Forget the current type - ctx->type.SetDummy(); - } - - // Check if there is a need to add a hidden pointer for when the function returns an object by value - if( descr->DoesReturnOnStack() && !useVariable ) - { - useVariable = true; - varOffset = AllocateVariable(descr->returnType, true); - - // Push the pointer to the pre-allocated space for the return value - ctx->bc.InstrSHORT(asBC_PSF, short(varOffset)); - - if( descr->objectType ) - { - // The object pointer is already on the stack, but should be the top - // one, so we need to swap the pointers in order to get the correct - ctx->bc.Instr(asBC_SwapPtr); - } - } - - if( isConstructor ) - { - // Sometimes the value types are allocated on the heap, - // which is when this way of constructing them is used. - - asASSERT(useVariable == false); - - ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE); - - // The instruction has already moved the returned object to the variable - ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false)); - ctx->type.isLValue = false; - - // Clean up arguments - if( args ) - AfterFunctionCall(funcId, *args, ctx, false); - - ProcessDeferredParams(ctx); - - return; - } - else - { - if( descr->objectType ) - argSize += AS_PTR_SIZE; - - // If the function returns an object by value the address of the location - // where the value should be stored is passed as an argument too - if( descr->DoesReturnOnStack() ) - argSize += AS_PTR_SIZE; - - // TODO: runtime optimize: If it is known that a class method cannot be overridden the call - // should be made with asBC_CALL as it is faster. Examples where this - // is known is for example finalled methods where the class doesn't derive - // from any other, or even non-finalled methods but where it is known - // at compile time the true type of the object. The first should be - // quite easy to determine, but the latter will be quite complex and possibly - // not worth it. - if( descr->funcType == asFUNC_IMPORTED ) - ctx->bc.Call(asBC_CALLBND , descr->id, argSize); - // TODO: Maybe we need two different byte codes - else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL ) - ctx->bc.Call(asBC_CALLINTF, descr->id, argSize); - else if( descr->funcType == asFUNC_SCRIPT ) - ctx->bc.Call(asBC_CALL , descr->id, argSize); - else if( descr->funcType == asFUNC_SYSTEM ) - ctx->bc.Call(asBC_CALLSYS , descr->id, argSize); - else if( descr->funcType == asFUNC_FUNCDEF ) - ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize); - } - - if( descr->returnType.IsObject() && !descr->returnType.IsReference() ) - { - int returnOffset = 0; - - asCTypeInfo tmpExpr = ctx->type; - - if( descr->DoesReturnOnStack() ) - { - asASSERT( useVariable ); - - // The variable was allocated before the function was called - returnOffset = varOffset; - ctx->type.SetVariable(descr->returnType, returnOffset, true); - - // The variable was initialized by the function, so we need to mark it as initialized here - ctx->bc.ObjInfo(varOffset, asOBJ_INIT); - } - else - { - if( useVariable ) - { - // Use the given variable - returnOffset = varOffset; - ctx->type.SetVariable(descr->returnType, returnOffset, false); - } - else - { - // Allocate a temporary variable for the returned object - // The returned object will actually be allocated on the heap, so - // we must force the allocation of the variable to do the same - returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle()); - ctx->type.SetVariable(descr->returnType, returnOffset, true); - } - - // Move the pointer from the object register to the temporary variable - ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset); - } - - ReleaseTemporaryVariable(tmpExpr, &ctx->bc); - - ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset)); - ctx->type.isLValue = false; // It is a reference, but not an lvalue - - // Clean up arguments - if( args ) - AfterFunctionCall(funcId, *args, ctx, false); - - ProcessDeferredParams(ctx); - - ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset); - } - else if( descr->returnType.IsReference() ) - { - asASSERT(useVariable == false); - - // We cannot clean up the arguments yet, because the - // reference might be pointing to one of them. - if( args ) - AfterFunctionCall(funcId, *args, ctx, true); - - // Do not process the output parameters yet, because it - // might invalidate the returned reference - - // If the context holds a variable that needs cleanup - // store it as a deferred parameter so it will be cleaned up - // afterwards. - if( ctx->type.isTemporary ) - { - asSDeferredParam defer; - defer.argNode = 0; - defer.argType = ctx->type; - defer.argInOutFlags = asTM_INOUTREF; - defer.origExpr = 0; - ctx->deferredParams.PushLast(defer); - } - - ctx->type.Set(descr->returnType); - if( !descr->returnType.IsPrimitive() ) - { - ctx->bc.Instr(asBC_PshRPtr); - if( descr->returnType.IsObject() && - !descr->returnType.IsObjectHandle() ) - { - // We are getting the pointer to the object - // not a pointer to a object variable - ctx->type.dataType.MakeReference(false); - } - } - - // A returned reference can be used as lvalue - ctx->type.isLValue = true; - } - else - { - asASSERT(useVariable == false); - - asCTypeInfo tmpExpr = ctx->type; - - if( descr->returnType.GetSizeInMemoryBytes() ) - { - // Allocate a temporary variable to hold the value, but make sure - // the temporary variable isn't used in any of the deferred arguments - int l = int(reservedVariables.GetLength()); - for( asUINT n = 0; args && n < args->GetLength(); n++ ) - { - asSExprContext *expr = (*args)[n]->origExpr; - if( expr ) - expr->bc.GetVarsUsed(reservedVariables); - } - int offset = AllocateVariable(descr->returnType, true); - reservedVariables.SetLength(l); - - ctx->type.SetVariable(descr->returnType, offset, true); - - // Move the value from the return register to the variable - if( descr->returnType.GetSizeOnStackDWords() == 1 ) - ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset); - else if( descr->returnType.GetSizeOnStackDWords() == 2 ) - ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset); - } - else - ctx->type.Set(descr->returnType); - - ReleaseTemporaryVariable(tmpExpr, &ctx->bc); - - ctx->type.isLValue = false; - - // Clean up arguments - if( args ) - AfterFunctionCall(funcId, *args, ctx, false); - - ProcessDeferredParams(ctx); - } -} - -// This only merges the bytecode, but doesn't modify the type of the final context -void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after) -{ - before->bc.AddCode(&after->bc); - - for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ ) - { - before->deferredParams.PushLast(after->deferredParams[n]); - after->deferredParams[n].origExpr = 0; - } - - after->deferredParams.SetLength(0); -} - -// This merges both bytecode and the type of the final context -void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after) -{ - MergeExprBytecode(before, after); - - before->type = after->type; - before->property_get = after->property_get; - before->property_set = after->property_set; - before->property_const = after->property_const; - before->property_handle = after->property_handle; - before->property_ref = after->property_ref; - before->property_arg = after->property_arg; - before->exprNode = after->exprNode; - before->methodName = after->methodName; - before->enumValue = after->enumValue; - - after->property_arg = 0; - - // Do not copy the origExpr member -} - -void asCCompiler::FilterConst(asCArray &funcs, bool removeConst) -{ - if( funcs.GetLength() == 0 ) return; - - // This is only done for object methods - asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]); - if( desc->objectType == 0 ) return; - - // Check if there are any non-const matches - asUINT n; - bool foundNonConst = false; - for( n = 0; n < funcs.GetLength(); n++ ) - { - desc = builder->GetFunctionDescription(funcs[n]); - if( desc->isReadOnly != removeConst ) - { - foundNonConst = true; - break; - } - } - - if( foundNonConst ) - { - // Remove all const methods - for( n = 0; n < funcs.GetLength(); n++ ) - { - desc = builder->GetFunctionDescription(funcs[n]); - if( desc->isReadOnly == removeConst ) - { - if( n == funcs.GetLength() - 1 ) - funcs.PopLast(); - else - funcs[n] = funcs.PopLast(); - - n--; - } - } - } -} - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - - - diff --git a/dependencies/angelscript/source/as_compiler.h b/dependencies/angelscript/source/as_compiler.h deleted file mode 100644 index 3009460f..00000000 --- a/dependencies/angelscript/source/as_compiler.h +++ /dev/null @@ -1,362 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_compiler.h -// -// The class that does the actual compilation of the functions -// - - - -#ifndef AS_COMPILER_H -#define AS_COMPILER_H - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_builder.h" -#include "as_scriptfunction.h" -#include "as_variablescope.h" -#include "as_bytecode.h" -#include "as_array.h" -#include "as_datatype.h" -#include "as_typeinfo.h" - -BEGIN_AS_NAMESPACE - -struct asSExprContext; - -struct asSDeferredParam -{ - asSDeferredParam() {argNode = 0; origExpr = 0;} - - asCScriptNode *argNode; - asCTypeInfo argType; - int argInOutFlags; - asSExprContext *origExpr; -}; - -// TODO: refactor: asSExprContext 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 -{ - asSExprContext(asCScriptEngine *engine) : bc(engine) - { - exprNode = 0; - origExpr = 0; - property_get = 0; - property_set = 0; - property_const = false; - property_handle = false; - property_ref = false; - property_arg = 0; - } - ~asSExprContext() - { - if( property_arg ) - asDELETE(property_arg, asSExprContext); - } - void Clear() - { - bc.ClearAll(); - type.SetDummy(); - if( property_arg ) - asDELETE(property_arg, asSExprContext); - property_arg = 0; - deferredParams.SetLength(0); - exprNode = 0; - origExpr = 0; - property_get = 0; - property_set = 0; - property_const = false; - property_handle = false; - property_ref = false; - methodName = ""; - enumValue = ""; - } - bool IsClassMethod() - { - 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() - { - if( type.dataType.GetObjectType() == 0 ) return false; - if( methodName == "" ) return false; - if( type.dataType.GetObjectType() != &type.dataType.GetObjectType()->engine->functionBehaviours ) return false; - return true; - } - - asCByteCode bc; - asCTypeInfo type; - int property_get; - int property_set; - bool property_const; // If the object that is being accessed through property accessor is read-only - bool property_handle; // If the property accessor is called on an object stored in a handle - bool property_ref; // If the property accessor is called on a reference - asSExprContext *property_arg; - asCArray deferredParams; - asCScriptNode *exprNode; - asSExprContext *origExpr; - // TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value - asCString methodName; - asCString enumValue; -}; - -struct asSOverloadCandidate -{ - asSOverloadCandidate() : funcId(0), cost(0) {} - asSOverloadCandidate(int _id, asUINT _cost ) : funcId(_id), cost(_cost) {} - int funcId; - asUINT cost; -}; - -struct asSNamedArgument -{ - asCString name; - asSExprContext *ctx; - asUINT match; -}; - -enum EImplicitConv -{ - asIC_IMPLICIT_CONV, - asIC_EXPLICIT_REF_CAST, - asIC_EXPLICIT_VAL_CAST -}; - -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 -}; - -class asCCompiler -{ -public: - asCCompiler(asCScriptEngine *engine); - ~asCCompiler(); - - int CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray ¶meterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl); - int CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl); - int CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc); - int CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *expr, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc); - -protected: - friend class asCBuilder; - - void Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc); - - // Statements - void CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc); - void CompileDeclaration(asCScriptNode *decl, asCByteCode *bc); - void CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc); - void CompileIfStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); - void CompileSwitchStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); - void CompileCase(asCScriptNode *node, asCByteCode *bc); - void CompileForStatement(asCScriptNode *node, asCByteCode *bc); - void CompileWhileStatement(asCScriptNode *node, asCByteCode *bc); - void CompileDoWhileStatement(asCScriptNode *node, asCByteCode *bc); - void CompileBreakStatement(asCScriptNode *node, asCByteCode *bc); - void CompileContinueStatement(asCScriptNode *node, asCByteCode *bc); - void CompileReturnStatement(asCScriptNode *node, asCByteCode *bc); - 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 = ""); - void CompileConstructCall(asCScriptNode *node, asSExprContext *out); - void CompileConversion(asCScriptNode *node, asSExprContext *out); - int CompileOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out); - void CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out); - void CompileMathOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out); - void CompileBitwiseOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out); - void CompileComparisonOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out); - void CompileBooleanOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out); - bool CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, bool isHandle = false); - int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *l, asSExprContext *r, asSExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false)); - - void CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem); - int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList); - - 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); - 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); - void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults); - bool CompileAutoType(asCDataType &autoType, asSExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode); - bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asSExprContext *preCompiled = 0); - void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination); - - // Helper functions - void ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node); - int ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node); - int FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); - int FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); - void PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap = false); - void PrepareOperand(asSExprContext *ctx, asCScriptNode *node); - void PrepareForAssignment(asCDataType *lvalue, asSExprContext *rvalue, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr = 0); - int PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node); - bool IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node); - void Dereference(asSExprContext *ctx, bool generateCode); - bool CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true); - asUINT MatchArgument(asCArray &funcs, asCArray &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); - int MatchArgument(asCScriptFunction *desc, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); - void PerformFunctionCall(int funcId, asSExprContext *out, bool isConstructor = false, asCArray *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0); - void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset); - void MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0); - void PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args); - void AfterFunctionCall(int funcId, asCArray &args, asSExprContext *ctx, bool deferAll); - void ProcessDeferredParams(asSExprContext *ctx); - int PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false); - void PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false); - bool IsLValue(asCTypeInfo &type); - int DoAssignment(asSExprContext *out, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode); - void MergeExprBytecode(asSExprContext *before, asSExprContext *after); - void MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after); - void FilterConst(asCArray &funcs, bool removeConst = true); - void ConvertToVariable(asSExprContext *ctx); - void ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude); - void ConvertToTempVariable(asSExprContext *ctx); - void ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude); - void ConvertToReference(asSExprContext *ctx); - void PushVariableOnStack(asSExprContext *ctx, bool asReference); - void DestroyVariables(asCByteCode *bc); - asSNameSpace *DetermineNameSpace(const asCString &scope); - int SetupParametersAndReturnVariable(asCArray ¶meterNames, asCScriptNode *func); - - void DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node); - - // Returns the cost of the conversion (the sum of the EConvCost performed) - asUINT ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); - asUINT ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); - asUINT ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); - asUINT ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); - void ImplicitConversionConstant(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType); - void ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node); - - void LineInstr(asCByteCode *bc, size_t pos); - - asUINT ProcessStringConstant(asCString &str, asCScriptNode *node, bool processEscapeSequences = true); - void ProcessHeredocStringConstant(asCString &str, asCScriptNode *node); - int GetPrecedence(asCScriptNode *op); - void Error(const asCString &msg, asCScriptNode *node); - void Warning(const asCString &msg, asCScriptNode *node); - void Information(const asCString &msg, asCScriptNode *node); - void PrintMatchingFuncs(asCArray &funcs, asCScriptNode *node, asCObjectType *inType = 0); - void AddVariableScope(bool isBreakScope = false, bool isContinueScope = false); - void RemoveVariableScope(); - void FinalizeFunction(); - - asCByteCode byteCode; - - bool hasCompileErrors; - - int nextLabel; - - asCVariableScope *variables; - asCBuilder *builder; - asCScriptEngine *engine; - asCScriptCode *script; - asCScriptFunction *outFunc; - - bool m_isConstructor; - bool m_isConstructorCalled; - sClassDeclaration *m_classDecl; - - asCArray breakLabels; - asCArray continueLabels; - - int AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap = false); - int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx); - int GetVariableOffset(int varIndex); - int GetVariableSlot(int varOffset); - void DeallocateVariable(int pos); - void ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc); - void ReleaseTemporaryVariable(int offset, asCByteCode *bc); - bool IsVariableOnHeap(int offset); - - // This ordered array indicates the type of each variable - asCArray variableAllocations; - - // This ordered array indicates which variables are temporaries or not - asCArray variableIsTemporary; - - // This unordered array gives the offsets of all temporary variables, whether currently allocated or not - asCArray tempVariableOffsets; - - // This ordered array indicated if the variable is on the heap or not - asCArray variableIsOnHeap; - - // This unordered array gives the indexes of the currently unused variables - asCArray freeVariables; - - // This array holds the offsets of the currently allocated temporary variables - asCArray tempVariables; - - // This array holds the indices of variables that must not be used in an allocation - asCArray reservedVariables; - - bool isCompilingDefaultArg; - bool isProcessingDeferredParams; - int noCodeOutput; -}; - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - -#endif diff --git a/dependencies/angelscript/source/as_config.h b/dependencies/angelscript/source/as_config.h deleted file mode 100644 index 4a131ba2..00000000 --- a/dependencies/angelscript/source/as_config.h +++ /dev/null @@ -1,1174 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - -// -// as_config.h -// -// this file is used for configuring the compilation of the library -// - -#ifndef AS_CONFIG_H -#define AS_CONFIG_H - - - -// -// Features -//----------------------------------------- - -// AS_NO_THREADS -// Turns off support for multithreading. By turning off -// this when it's not needed a bit of performance is gained. - -// AS_WINDOWS_THREADS -// If the library should be compiled using windows threads. - -// AS_POSIX_THREADS -// If the library should be compiled using posix threads. - -// AS_NO_ATOMIC -// If the compiler/platform doesn't support atomic instructions -// then this should be defined to use critical sections instead. - -// AS_DEBUG -// This flag can be defined to make the library write some extra output when -// compiling and executing scripts. - -// AS_DEPRECATED -// If this flag is defined then some backwards compatibility is maintained. -// There is no guarantee for how well deprecated functionality will work though -// so it is best to exchange it for the new functionality as soon as possible. - -// AS_NO_CLASS_METHODS -// Disables the possibility to add class methods. Can increase the -// portability of the library. - -// AS_MAX_PORTABILITY -// Disables all platform specific code. Only the asCALL_GENERIC calling -// convention will be available in with this flag set. - -// AS_DOUBLEBYTE_CHARSET -// When this flag is defined, the parser will treat all characters in strings -// that are greater than 127 as lead characters and automatically include the -// next character in the script without checking its value. This should be -// compatible with common encoding schemes, e.g. Big5. Shift-JIS is not compatible -// though as it encodes some single byte characters above 127. -// -// If support for international text is desired, it is recommended that UTF-8 -// is used as this is supported natively by the compiler without the use for this -// preprocessor flag. - -// AS_NO_COMPILER -// Compiles the library without support for compiling scripts. This is intended -// for those applications that will load pre-compiled bytecode and wants to decrease -// the size of the executable. - -// AS_NO_EXCEPTIONS -// Define this if exception handling is turned off or not available on the target platform. - -// AS_NO_MEMBER_INIT -// Disable the support for initialization of class members directly in the declaration. -// This was as a form to maintain backwards compatibility with versions before 2.26.0 -// if the new order of the member initialization caused null pointer exceptions in older -// scripts (e.g. if a base class accessed members of a derived class through a virtual method). - -// AS_USE_NAMESPACE -// Adds the AngelScript namespace on the declarations. - - - -// -// Library usage -//------------------------------------------ - -// ANGELSCRIPT_EXPORT -// This flag should be defined when compiling the library as a lib or dll. - -// ANGELSCRIPT_DLL_LIBRARY_IMPORT -// This flag should be defined when using AngelScript as a dll with automatic -// library import. - -// ANGELSCRIPT_DLL_MANUAL_IMPORT -// This flag should be defined when using AngelScript as a dll with manual -// loading of the library. - - - - -// -// Compiler differences -//----------------------------------------- - -// asVSNPRINTF(a,b,c,d) -// Some compilers use different names for this function. You must -// define this macro to map to the proper function. - -// ASM_AT_N_T or ASM_INTEL -// You should choose what inline assembly syntax to use when compiling. - -// VALUE_OF_BOOLEAN_TRUE -// This flag allows to customize the exact value of boolean true. - -// AS_SIZEOF_BOOL -// On some target platforms the sizeof(bool) is 4, but on most it is 1. - -// STDCALL -// This is used to declare a function to use the stdcall calling convention. - -// AS_NO_MEMORY_H -// Some compilers don't come with the memory.h header file. - -// AS_NO_THISCALL_FUNCTOR_METHOD -// Defined if the support for functor methods hasn't been implemented on the platform. - - - -// -// How to identify different compilers -//----------------------------------------- - -// MS Visual C++ -// _MSC_VER is defined -// __MWERKS__ is not defined - -// Metrowerks -// _MSC_VER is defined -// __MWERKS__ is defined - -// GNU C based compilers -// __GNUC__ is defined - -// Embarcadero C++Builder -// __BORLANDC__ is defined - -// Sun CC compiler -// __SUNPRO_CC is defined - - - -// -// CPU differences -//--------------------------------------- - -// AS_USE_DOUBLE_AS_FLOAT -// If there is no 64 bit floating point type, then this constant can be defined -// to treat double like normal floats. - -// AS_X86 -// Use assembler code for the x86 CPU family - -// AS_SH4 -// Use assembler code for the SH4 CPU family - -// AS_MIPS -// Use assembler code for the MIPS CPU family - -// AS_PPC -// Use assembler code for the 32bit PowerPC CPU family - -// AS_PPC_64 -// Use assembler code for the 64bit PowerPC CPU family - -// AS_XENON -// Use assembler code for the Xenon (XBOX360) CPU family - -// AS_ARM -// Use assembler code for the ARM CPU family - -// AS_SOFTFP -// Use to tell compiler that ARM soft-float ABI -// should be used instead of ARM hard-float ABI - -// AS_X64_GCC -// Use GCC assembler code for the X64 AMD/Intel CPU family - -// AS_X64_MSVC -// Use MSVC assembler code for the X64 AMD/Intel CPU family - -// AS_64BIT_PTR -// Define this to make the engine store all pointers in 64bit words. - -// AS_BIG_ENDIAN -// Define this for CPUs that use big endian memory layout, e.g. PPC - -// AS_SPARC -// Define this for SPARC CPU family - - - -// -// Target systems -//-------------------------------- -// This group shows a few of the flags used to identify different target systems. -// Sometimes there are differences on different target systems, while both CPU and -// compiler is the same for both, when this is so these flags are used to produce the -// right code. - -// AS_WIN - Microsoft Windows -// AS_LINUX - Linux -// AS_MAC - Apple Macintosh -// AS_BSD - BSD based OS (FreeBSD, DragonFly, OpenBSD, etc) -// AS_XBOX - Microsoft XBox -// AS_XBOX360 - Microsoft XBox 360 -// AS_PSP - Sony Playstation Portable -// AS_PS2 - Sony Playstation 2 -// AS_PS3 - Sony Playstation 3 -// AS_DC - Sega Dreamcast -// AS_GC - Nintendo GameCube -// AS_WII - Nintendo Wii -// AS_WIIU - Nintendo Wii U -// AS_IPHONE - Apple IPhone -// AS_ANDROID - Android -// AS_HAIKU - Haiku -// AS_ILLUMOS - Illumos like (OpenSolaris, OpenIndiana, NCP, etc) -// AS_MARMALADE - Marmalade cross platform SDK (a layer on top of the OS) -// AS_SUN - Sun UNIX - - - - -// -// Calling conventions -//----------------------------------------- - -// GNU_STYLE_VIRTUAL_METHOD -// This constant should be defined if method pointers store index for virtual -// functions in the same location as the function pointer. In such cases the method -// is identified as virtual if the least significant bit is set. - -// MULTI_BASE_OFFSET(x) -// This macro is used to retrieve the offset added to the object pointer in order to -// implicitly cast the object to the base object. x is the method pointer received by -// the register function. - -// HAVE_VIRTUAL_BASE_OFFSET -// Define this constant if the compiler stores the virtual base offset in the method -// pointers. If it is not stored in the pointers then AngelScript have no way of -// identifying a method as coming from a class with virtual inheritance. - -// VIRTUAL_BASE_OFFSET(x) -// This macro is used to retrieve the offset added to the object pointer in order to -// find the virtual base object. x is the method pointer received by the register -// function; - -// COMPLEX_RETURN_MASK -// This constant shows what attributes determine if an object is returned in memory -// or in the registers as normal structures - -// COMPLEX_MASK -// This constant shows what attributes determine if an object is implicitly passed -// by reference or not, even if the argument is declared by value - -// THISCALL_RETURN_SIMPLE_IN_MEMORY -// CDECL_RETURN_SIMPLE_IN_MEMORY -// STDCALL_RETURN_SIMPLE_IN_MEMORY -// When these constants are defined then the corresponding calling convention always -// return classes/structs in memory regardless of size or complexity. - -// THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE -// STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE -// CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE -// Specifies the minimum size in dwords a class/struct needs to be to be passed in memory - -// CALLEE_POPS_HIDDEN_RETURN_POINTER -// This constant should be defined if the callee pops the hidden return pointer, -// used when returning an object in memory. - -// THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER -// This constant should be defined if the callee pops the hidden return pointer -// for thiscall functions; used when returning an object in memory. - -// THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK -// With this constant defined AngelScript will pass the object pointer on the stack - -// THISCALL_CALLEE_POPS_ARGUMENTS -// If the callee pops arguments for class methods then define this constant - -// COMPLEX_OBJS_PASSED_BY_REF -// Some compilers always pass certain objects by reference. GNUC for example does -// this if the the class has a defined destructor. - -// AS_LARGE_OBJS_PASSED_BY_REF -// If this is defined large objects are passed by reference, whether they are complex or not - -// AS_LARGE_OBJ_MIN_SIZE -// This is the size of objects determined as large ones - -// AS_CALLEE_DESTROY_OBJ_BY_VAL -// When an object is passed by value the called function is the one responsible -// for calling the destructor before returning. - -// HAS_128_BIT_PRIMITIVES -// 64bit processors often support 128bit primitives. These may require special -// treatment when passed in function arguments or returned by functions. - -// SPLIT_OBJS_BY_MEMBER_TYPES -// On some platforms objects with primitive members are split over different -// register types when passed by value to functions. - - - - - -// -// Detect compiler -//------------------------------------------------ - - -#define VALUE_OF_BOOLEAN_TRUE 1 -#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 -#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 -#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 -#define THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER - -// Not implemented by default. Undefined with tested platforms. -#define AS_NO_THISCALL_FUNCTOR_METHOD - - -// Embarcadero C++Builder -#if defined(__BORLANDC__) - #ifndef _Windows - #error "Configuration doesn't yet support BCC for Linux or Mac OS." - #endif - #if defined(_M_X64) - #error "Configuration doesn't yet support BCC for AMD64." - #endif - - #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) - #define HAVE_VIRTUAL_BASE_OFFSET - #define VIRTUAL_BASE_OFFSET(x) (*((asDWORD*)(&x)+2)) - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - - #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - #define COMPLEX_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR) - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR) - #define STDCALL __stdcall - #define AS_SIZEOF_BOOL 1 - #define AS_WINDOWS_THREADS - #undef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER - - #define AS_WIN - #define AS_X86 - #define ASM_INTEL - - #define asVSNPRINTF(a, b, c, d) _vsnprintf(a, b, c, d) - - #define fmodf(a,b) fmod(a,b) - - #define UNREACHABLE_RETURN -#endif - -// Microsoft Visual C++ -// Ref: http://msdn.microsoft.com/en-us/library/b0084kay.aspx -#if defined(_MSC_VER) && !defined(__MWERKS__) - - #if _MSC_VER <= 1200 // MSVC6 - // Disable the useless warnings about truncated symbol names for template instances - #pragma warning( disable : 4786 ) - #endif - - #ifdef _M_X64 - #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+2)) - #define VIRTUAL_BASE_OFFSET(x) (*((asDWORD*)(&x)+4)) - #else - #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) - #define VIRTUAL_BASE_OFFSET(x) (*((asDWORD*)(&x)+3)) - #endif - #define HAVE_VIRTUAL_BASE_OFFSET - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_PASS_OBJECT_POINTER_IN_ECX - - // http://www.madewithmarmalade.com/ - #if defined(__S3E__) - #ifndef AS_MARMALADE - // From now on we'll use the below define - #define AS_MARMALADE - #endif - - // Marmalade doesn't use the Windows libraries - #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) - - // Marmalade doesn't seem to have proper support for - // atomic instructions or read/write locks, so we turn off - // multithread support - //#define AS_POSIX_THREADS - #define AS_NO_THREADS - #define AS_NO_ATOMIC - - // Marmalade has it's own way of identifying the CPU target - // Note, when building for ARM, the gnuc compiler will always - // be used so we don't need to check for it here - #if defined(I3D_ARCH_X86) - #define AS_X86 - #endif - #else - #if _MSC_VER < 1500 // MSVC++ 9 (aka MSVC++ .NET 2008) - #define asVSNPRINTF(a, b, c, d) _vsnprintf(a, b, c, d) - #else - #define asVSNPRINTF(a, b, c, d) vsnprintf_s(a, b, _TRUNCATE, c, d) - #endif - - #define AS_WINDOWS_THREADS - #endif - - #define THISCALL_CALLEE_POPS_ARGUMENTS - #define STDCALL __stdcall - #define AS_SIZEOF_BOOL 1 - #define COMPLEX_OBJS_PASSED_BY_REF - - #define ASM_INTEL // Intel style for inline assembly on microsoft compilers - - #if defined(WIN32) || defined(_WIN32) || defined(_WIN64) - #define AS_WIN - #endif - - #if _XBOX_VER >= 200 - // 360 uses a Xenon processor (which is a modified 64bit PPC) - #define AS_XBOX360 - #define AS_XENON - #define AS_BIG_ENDIAN - #else - #if defined(_XBOX) || (defined(_M_IX86) && !defined(__LP64__)) - #define AS_X86 - #ifndef _XBOX - // Not tested with xbox (only enabled if is Windows) - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #endif - #elif defined(_M_X64) - #define AS_X64_MSVC - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #define AS_CALLEE_DESTROY_OBJ_BY_VAL - #define AS_LARGE_OBJS_PASSED_BY_REF - #define AS_LARGE_OBJ_MIN_SIZE 3 - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #define COMPLEX_MASK (asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #endif - #endif - - #if defined(_ARM_) || defined(_M_ARM) - #define AS_ARM - #define AS_CALLEE_DESTROY_OBJ_BY_VAL - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define COMPLEX_MASK (asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY) - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY) - #define AS_SOFTFP - #endif - - #ifndef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_ARRAY) - #endif - - #ifndef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY) - #endif - - #define UNREACHABLE_RETURN -#endif - -// Metrowerks CodeWarrior (experimental, let me know if something isn't working) -#if defined(__MWERKS__) && !defined(EPPC) // JWC -- If Wii DO NOT use this even when using Metrowerks Compiler. Even though they are called Freescale... - #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) - #define HAVE_VIRTUAL_BASE_OFFSET - #define VIRTUAL_BASE_OFFSET(x) (*((asDWORD*)(&x)+3)) - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_PASS_OBJECT_POINTER_IN_ECX - #define asVSNPRINTF(a, b, c, d) _vsnprintf(a, b, c, d) - #define THISCALL_CALLEE_POPS_ARGUMENTS - #define COMPLEX_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT) - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT) - #define AS_SIZEOF_BOOL 1 - #define AS_WINDOWS_THREADS - #define STDCALL __stdcall - - // Support native calling conventions on x86, but not 64bit yet - #if defined(_M_IX86) && !defined(__LP64__) - #define AS_X86 - #define ASM_INTEL // Intel style for inline assembly - #endif - - #define UNREACHABLE_RETURN -#endif - -// SN Systems ProDG -#if defined(__SNC__) || defined(SNSYS) - #define GNU_STYLE_VIRTUAL_METHOD - #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) - #define CALLEE_POPS_HIDDEN_RETURN_POINTER - #define COMPLEX_OBJS_PASSED_BY_REF - #define ASM_AT_N_T // AT&T style inline assembly - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR) - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR) - #define AS_SIZEOF_BOOL 1 - #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) - - // SN doesnt seem to like STDCALL. - // Maybe it can work with some fiddling, but I can't imagine linking to - // any STDCALL functions with a console anyway... - #define STDCALL - - // Linux specific - #ifdef __linux__ - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #endif - - // Support native calling conventions on x86, but not 64bit yet - #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) - #define AS_X86 - // PS3 - #elif (defined(__PPC__) || defined(__ppc__)) && defined(__PPU__) - // Support native calling conventions on PS3 - #define AS_PS3 - #define AS_PPC_64 - // PSP - #elif defined(__psp__) - #define AS_NO_MEMORY_H - #define AS_MIPS - #define AS_PSP - #endif - - #define UNREACHABLE_RETURN -#endif - -// GNU C (and MinGW or Cygwin on Windows) -// Use the following command to determine predefined macros: echo . | g++ -dM -E - -#if (defined(__GNUC__) && !defined(__SNC__)) || defined(EPPC) || defined(__CYGWIN__) // JWC -- use this instead for Wii - #define GNU_STYLE_VIRTUAL_METHOD -#if !defined( __amd64__ ) - #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) -#else - #define MULTI_BASE_OFFSET(x) (*((asQWORD*)(&x)+1)) -#endif - #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) - #define CALLEE_POPS_HIDDEN_RETURN_POINTER - #define COMPLEX_OBJS_PASSED_BY_REF - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_ARRAY) - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_ARRAY) - #define AS_NO_MEMORY_H - #define AS_SIZEOF_BOOL 1 - #define STDCALL __attribute__((stdcall)) - #define ASM_AT_N_T - - // WII U - #if defined(__ghs__) - #define AS_WIIU - - // Native calling conventions are not yet supported - #define AS_MAX_PORTABILITY - - // Marmalade is a cross platform SDK. It uses g++ to compile for iOS and Android - #elif defined(__S3E__) - #ifndef AS_MARMALADE - // From now on we'll use the below define - #define AS_MARMALADE - #endif - - // STDCALL is not available on Marmalade when compiled for iOS or Android - #undef STDCALL - #define STDCALL - - // Marmalade doesn't seem to have proper support for - // atomic instructions or read/write locks - #define AS_NO_THREADS - #define AS_NO_ATOMIC - - // Identify for which CPU the library is being built - #if defined(I3D_ARCH_X86) - #define AS_X86 - #elif defined(I3D_ARCH_ARM) - #define AS_ARM - - #define AS_SOFTFP - - // Marmalade appear to use the same ABI as Android when built for ARM - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - - #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - - #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - - #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - - #undef GNU_STYLE_VIRTUAL_METHOD - - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - - #define AS_CALLEE_DESTROY_OBJ_BY_VAL - #endif - - // MacOSX and IPhone - #elif defined(__APPLE__) - - #include - - // Is this a Mac or an IPhone (or other iOS device)? - #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1 - #define AS_IPHONE - #else - #define AS_MAC - #endif - - // The sizeof bool is different depending on the target CPU - #undef AS_SIZEOF_BOOL - #if defined(__ppc__) - #define AS_SIZEOF_BOOL 4 - // STDCALL is not available on PPC - #undef STDCALL - #define STDCALL - #else - #define AS_SIZEOF_BOOL 1 - #endif - - #if (defined(_ARM_) || defined(__arm__)) - // iOS use ARM processor - #define AS_ARM - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - - #undef GNU_STYLE_VIRTUAL_METHOD - - #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define COMPLEX_OBJS_PASSED_BY_REF - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - - // iOS uses soft-float ABI - #define AS_SOFTFP - - // STDCALL is not available on ARM - #undef STDCALL - #define STDCALL - - #elif (defined(__arm64__)) - // The IPhone 5S+ uses an ARM64 processor - - // AngelScript currently doesn't support native calling - // for 64bit ARM processors so it's necessary to turn on - // portability mode - #define AS_MAX_PORTABILITY - - // STDCALL is not available on ARM - #undef STDCALL - #define STDCALL - - #elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) - // Support native calling conventions on Mac OS X + Intel 32bit CPU - #define AS_X86 - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - - #elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__) && !defined(__arm64__) - // http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html#//apple_ref/doc/uid/TP40005035-SW1 - #define AS_X64_GCC - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #define HAS_128_BIT_PRIMITIVES - #define SPLIT_OBJS_BY_MEMBER_TYPES - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #define AS_LARGE_OBJS_PASSED_BY_REF - #define AS_LARGE_OBJ_MIN_SIZE 5 - // STDCALL is not available on 64bit Mac - #undef STDCALL - #define STDCALL - - #elif (defined(__ppc__) || defined(__PPC__)) && !defined(__LP64__) - // Support native calling conventions on Mac OS X + PPC 32bit CPU - #define AS_PPC - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - - #elif (defined(__ppc__) || defined(__PPC__)) && defined(__LP64__) - #define AS_PPC_64 - #else - // Unknown CPU type - #define AS_MAX_PORTABILITY - #endif - #define AS_POSIX_THREADS - - // Windows - #elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) - // On Windows the simple classes are returned in the EAX:EDX registers - //#define THISCALL_RETURN_SIMPLE_IN_MEMORY - //#define CDECL_RETURN_SIMPLE_IN_MEMORY - //#define STDCALL_RETURN_SIMPLE_IN_MEMORY - - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - - #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) - // Support native calling conventions on Intel 32bit CPU - #define AS_X86 - #undef AS_NO_THISCALL_FUNCTOR_METHOD - - // As of version 4.7 MinGW changed the ABI, presumably - // to be better aligned with how MSVC works - #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4 - #undef CALLEE_POPS_HIDDEN_RETURN_POINTER - #define THISCALL_CALLEE_POPS_ARGUMENTS - #else - // Earlier versions than 4.7 - #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - #endif - - #elif defined(__x86_64__) - #define AS_X64_MINGW - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #define AS_LARGE_OBJS_PASSED_BY_REF - #define AS_LARGE_OBJ_MIN_SIZE 3 - #define COMPLEX_OBJS_PASSED_BY_REF - #else - #define AS_MAX_PORTABILITY - #endif - #define AS_WIN - #define AS_WINDOWS_THREADS - - // Linux - #elif defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__) - - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - - #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - - // Support native calling conventions on Intel 32bit CPU - #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - #define AS_X86 - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #elif defined(__LP64__) && !defined(__arm64__) - #define AS_X64_GCC - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #define HAS_128_BIT_PRIMITIVES - #define SPLIT_OBJS_BY_MEMBER_TYPES - #define AS_LARGE_OBJS_PASSED_BY_REF - #define AS_LARGE_OBJ_MIN_SIZE 5 - // STDCALL is not available on 64bit Linux - #undef STDCALL - #define STDCALL - #elif defined(__ARMEL__) || defined(__arm__) - #define AS_ARM - - #undef STDCALL - #define STDCALL - - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - - #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - - #ifndef AS_MAX_PORTABILITY - // Make a few checks against incompatible ABI combinations - #if defined(__FAST_MATH__) && __FAST_MATH__ == 1 - #error -ffast-math is not supported with native calling conventions - #endif - #endif - - // Verify if soft-float or hard-float ABI is used - #if defined(__SOFTFP__) && __SOFTFP__ == 1 - // -ffloat-abi=softfp or -ffloat-abi=soft - #define AS_SOFTFP - #endif - - // Tested with both hard float and soft float abi - #undef AS_NO_THISCALL_FUNCTOR_METHOD - - #elif defined(__mips__) - #define AS_MIPS - #define AS_BIG_ENDIAN - #define AS_USE_DOUBLE_AS_FLOAT - - // Native calling conventions for Linux/Mips do not work yet. - #define AS_MAX_PORTABILITY - #else - #define AS_MAX_PORTABILITY - #endif - #define AS_LINUX - #define AS_POSIX_THREADS - - #if !( ( (__GNUC__ == 4) && (__GNUC_MINOR__ >= 1) || __GNUC__ > 4) ) - // Only with GCC 4.1 was the atomic instructions available - #define AS_NO_ATOMIC - #endif - - // Free BSD - #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) - #define AS_BSD - #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - #define AS_X86 - #elif defined(__LP64__) - #define AS_X64_GCC - #define HAS_128_BIT_PRIMITIVES - #define SPLIT_OBJS_BY_MEMBER_TYPES - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #define AS_LARGE_OBJS_PASSED_BY_REF - #define AS_LARGE_OBJ_MIN_SIZE 5 - #undef STDCALL - #define STDCALL - #else - #define AS_MAX_PORTABILITY - #endif - #define AS_POSIX_THREADS - #if !( ( (__GNUC__ == 4) && (__GNUC_MINOR__ >= 1) || __GNUC__ > 4) ) - // Only with GCC 4.1 was the atomic instructions available - #define AS_NO_ATOMIC - #endif - - // PSP and PS2 - #elif defined(__PSP__) || defined(__psp__) || defined(_EE_) || defined(_PSP) || defined(_PS2) - // Support native calling conventions on MIPS architecture - #if (defined(_MIPS_ARCH) || defined(_mips) || defined(__MIPSEL__)) && !defined(__LP64__) - #define AS_MIPS - #else - #define AS_MAX_PORTABILITY - #endif - - // PS3 - #elif (defined(__PPC__) || defined(__ppc__)) && defined(__PPU__) - // Support native calling conventions on PS3 - #define AS_PS3 - #define AS_PPC_64 - #define SPLIT_OBJS_BY_MEMBER_TYPES - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - // PS3 doesn't have STDCALL - #undef STDCALL - #define STDCALL - - // Dreamcast - #elif __SH4_SINGLE_ONLY__ - // Support native calling conventions on Dreamcast - #define AS_DC - #define AS_SH4 - - // Wii JWC - Close to PS3 just no PPC_64 and AS_PS3 - #elif defined(EPPC) - #define AS_WII - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #undef STDCALL - #define STDCALL - - // Android - #elif defined(ANDROID) || defined(__ANDROID__) - #define AS_ANDROID - - // Android 2.3+ supports posix threads - #define AS_POSIX_THREADS - - // Common configuration with Android arm and x86 - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - - #undef COMPLEX_MASK - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #undef COMPLEX_RETURN_MASK - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - - #if (defined(_ARM_) || defined(__arm__)) - // Android ARM - - #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - - // The stdcall calling convention is not used on the arm cpu - #undef STDCALL - #define STDCALL - - #undef GNU_STYLE_VIRTUAL_METHOD - - #define AS_ARM - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #define AS_SOFTFP - #define AS_CALLEE_DESTROY_OBJ_BY_VAL - #elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) - // Android Intel x86 (same config as Linux x86). Tested with Intel x86 Atom System Image. - - // Support native calling conventions on Intel 32bit CPU - #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - #define AS_X86 - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #endif - - // Haiku OS - #elif __HAIKU__ - #define AS_HAIKU - // Only x86-32 is currently supported by Haiku, but they do plan to support - // x86-64 and PowerPC in the future, so should go ahead and check the platform - // for future compatibility - #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) - #define AS_X86 - #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #else - #define AS_MAX_PORTABILITY - #endif - - #define AS_POSIX_THREADS - #if !( ( (__GNUC__ == 4) && (__GNUC_MINOR__ >= 1) || __GNUC__ > 4) ) - // Only with GCC 4.1 was the atomic instructions available - #define AS_NO_ATOMIC - #endif - - // Illumos - #elif defined(__sun) - #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - - // Support native calling conventions on Intel 32bit CPU - #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - #define AS_X86 - #elif defined(__LP64__) - #define AS_X64_GCC - #define HAS_128_BIT_PRIMITIVES - #define SPLIT_OBJS_BY_MEMBER_TYPES - // STDCALL is not available on 64bit Linux - #undef STDCALL - #define STDCALL - #else - #define AS_MAX_PORTABILITY - #endif - #define AS_ILLUMOS - #define AS_POSIX_THREADS - - #if !( ( (__GNUC__ == 4) && (__GNUC_MINOR__ >= 1) || __GNUC__ > 4) ) - // Only with GCC 4.1 was the atomic instructions available - #define AS_NO_ATOMIC - #endif - #endif - - #define UNREACHABLE_RETURN -#endif - -// Sun CC -// Initial information provided by Andrey Bergman -#if defined(__SUNPRO_CC) - #if defined(__sparc) - #define AS_SPARC - #endif - - #if defined(__sun) - #define AS_SUN - #endif - - // Native calling conventions is not yet supported for Sun CC - #if !defined(AS_MAX_PORTABILITY) - #define AS_MAX_PORTABILITY - #endif - - // I presume Sun CC uses a similar structure of method pointers as gnuc - #define MULTI_BASE_OFFSET(x) (*((asPWORD*)(&x)+1)) - - #if !defined(AS_SIZEOF_BOOL) - #define AS_SIZEOF_BOOL 1 // sizeof(bool) == 1 - #endif - #if !defined(UNREACHABLE_RETURN) - #define UNREACHABLE_RETURN - #endif - #if !defined(STDCALL) - #define STDCALL // There is no stdcall on Solaris/SunPro/SPARC - #endif - #if !defined(asVSNPRINTF) - #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) - #endif -#endif - - -// -// Detect target hardware -//------------------------------------------------ - -// X86, Intel, AMD, etc, i.e. most PCs -#if defined(__i386__) || defined(_M_IX86) - // Nothing special here -#endif - -// MIPS architecture (generally PS2 and PSP consoles, potentially supports N64 as well) -#if defined(_MIPS_ARCH) || defined(_mips) || defined(__MIPSEL__) || defined(__PSP__) || defined(__psp__) || defined(_EE_) || defined(_PSP) || defined(_PS2) - #define AS_USE_DOUBLE_AS_FLOAT // use 32bit floats instead of doubles -#endif - -// PowerPC, e.g. Mac, GameCube, PS3, XBox 360, Wii -#if defined(__PPC__) || defined(__ppc__) || defined(_PPC_) || defined(EPPC) - #define AS_BIG_ENDIAN - - // Gamecube - #if defined(_GC) - #define AS_USE_DOUBLE_AS_FLOAT - #endif -#endif - -// Dreamcast console -#ifdef __SH4_SINGLE_ONLY__ - #define AS_USE_DOUBLE_AS_FLOAT // use 32bit floats instead of doubles -#endif - -// If there are no current support for native calling -// conventions, then compile with AS_MAX_PORTABILITY -#if (!defined(AS_X86) && !defined(AS_SH4) && !defined(AS_MIPS) && !defined(AS_PPC) && !defined(AS_PPC_64) && !defined(AS_XENON) && !defined(AS_X64_GCC) && !defined(AS_X64_MSVC) && !defined(AS_ARM) && !defined(AS_X64_MINGW)) - #ifndef AS_MAX_PORTABILITY - #define AS_MAX_PORTABILITY - #endif -#endif - -// If the platform doesn't support atomic instructions we can't allow -// multithreading as the reference counters won't be threadsafe -#if defined(AS_NO_ATOMIC) && !defined(AS_NO_THREADS) - #define AS_NO_THREADS -#endif - -// If the form of threads to use hasn't been chosen -// then the library will be compiled without support -// for multithreading -#if !defined(AS_POSIX_THREADS) && !defined(AS_WINDOWS_THREADS) - #define AS_NO_THREADS -#endif - - -// The assert macro -#if defined(ANDROID) - #if defined(AS_DEBUG) - #include - #include - #define asASSERT(x) \ - do { \ - if (!(x)) { \ - __android_log_print(ANDROID_LOG_ERROR, "AngelScript", "Assert failed at %s:%d - %s", __FILE__, __LINE__, #x); \ - exit(1); \ - } \ - } while (0) - #else - #define asASSERT(x) - #endif -#else - #include - #define asASSERT(x) assert(x) -#endif - - - -// -// Internal defines (do not change these) -//---------------------------------------------------------------- - -#define ARG_W(b) ((asWORD*)&b) -#define ARG_DW(b) ((asDWORD*)&b) -#define ARG_QW(b) ((asQWORD*)&b) -#define ARG_PTR(b) ((asPWORD*)&b) -#define BCARG_W(b) ((asWORD*)&(b)[1]) -#define BCARG_DW(b) ((asDWORD*)&(b)[1]) -#define BCARG_QW(b) ((asQWORD*)&(b)[1]) -#define BCARG_PTR(b) ((asPWORD*)&(b)[1]) - -// This macro is used to avoid warnings about unused variables. -// Usually where the variables are only used in debug mode. -#define UNUSED_VAR(x) (void)(x) - -#include "../include/angelscript.h" -#include "as_memory.h" - -#ifdef AS_USE_NAMESPACE -using namespace AngelScript; -#endif - -#endif diff --git a/dependencies/angelscript/source/as_configgroup.cpp b/dependencies/angelscript/source/as_configgroup.cpp deleted file mode 100644 index db4e02b6..00000000 --- a/dependencies/angelscript/source/as_configgroup.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_configgroup.cpp -// -// This class holds configuration groups for the engine -// - - - -#include "as_config.h" -#include "as_configgroup.h" -#include "as_scriptengine.h" -#include "as_texts.h" - -BEGIN_AS_NAMESPACE - -asCConfigGroup::asCConfigGroup() -{ - refCount = 0; -} - -asCConfigGroup::~asCConfigGroup() -{ -} - -int asCConfigGroup::AddRef() -{ - refCount++; - return refCount; -} - -int asCConfigGroup::Release() -{ - // Don't delete the object here, the engine will delete the object when ready - refCount--; - return refCount; -} - -asCObjectType *asCConfigGroup::FindType(const char *obj) -{ - for( asUINT n = 0; n < objTypes.GetLength(); n++ ) - if( objTypes[n]->name == obj ) - return objTypes[n]; - - return 0; -} - -void asCConfigGroup::RefConfigGroup(asCConfigGroup *group) -{ - if( group == this || group == 0 ) return; - - // Verify if the group is already referenced - for( asUINT n = 0; n < referencedConfigGroups.GetLength(); n++ ) - if( referencedConfigGroups[n] == group ) - return; - - referencedConfigGroups.PushLast(group); - group->AddRef(); -} - -bool asCConfigGroup::HasLiveObjects() -{ - for( asUINT n = 0; n < objTypes.GetLength(); n++ ) - if( objTypes[n]->GetRefCount() != 0 ) - return true; - - return false; -} - -void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed) -{ - asASSERT( refCount == 0 ); - - asUINT n; - - // Remove global variables - for( n = 0; n < globalProps.GetLength(); n++ ) - { - int index = engine->registeredGlobalProps.GetIndex(globalProps[n]); - if( index >= 0 ) - { - globalProps[n]->Release(); - - // TODO: global: Should compact the registeredGlobalProps array - engine->registeredGlobalProps.Erase(index); - } - } - globalProps.SetLength(0); - - // Remove global functions - for( n = 0; n < scriptFunctions.GetLength(); n++ ) - { - int index = engine->registeredGlobalFuncs.GetIndex(scriptFunctions[n]); - if( index >= 0 ) - engine->registeredGlobalFuncs.Erase(index); - scriptFunctions[n]->Release(); - if( engine->stringFactory == scriptFunctions[n] ) - engine->stringFactory = 0; - } - scriptFunctions.SetLength(0); - - // Remove behaviours and members of object types - for( n = 0; n < objTypes.GetLength(); n++ ) - { - asCObjectType *obj = objTypes[n]; - - obj->ReleaseAllFunctions(); - } - - // Remove function definitions - for( n = 0; n < funcDefs.GetLength(); n++ ) - { - engine->registeredFuncDefs.RemoveValue(funcDefs[n]); - funcDefs[n]->Release(); - } - funcDefs.SetLength(0); - - engine->ClearUnusedTypes(); - - // Remove object types (skip this if it is possible other groups are still using the types) - if( !notUsed ) - { - for( n = asUINT(objTypes.GetLength()); n-- > 0; ) - { - asCObjectType *t = objTypes[n]; - asSMapNode *cursor; - if( engine->allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(t->nameSpace, t->name)) && - cursor->value == t ) - { -#ifdef AS_DEBUG - ValidateNoUsage(engine, t); -#endif - - engine->allRegisteredTypes.Erase(cursor); - if( engine->defaultArrayObjectType == t ) - engine->defaultArrayObjectType = 0; - - if( t->flags & asOBJ_TYPEDEF ) - engine->registeredTypeDefs.RemoveValue(t); - else if( t->flags & asOBJ_ENUM ) - engine->registeredEnums.RemoveValue(t); - else if( t->flags & asOBJ_TEMPLATE ) - engine->registeredTemplateTypes.RemoveValue(t); - else - engine->registeredObjTypes.RemoveValue(t); - - t->DropFromEngine(); - } - else - { - int idx = engine->templateInstanceTypes.IndexOf(t); - if( idx >= 0 ) - { -#ifdef AS_DEBUG - ValidateNoUsage(engine, t); -#endif - engine->templateInstanceTypes.RemoveIndexUnordered(idx); - t->DropFromEngine(); - } - } - } - objTypes.SetLength(0); - } - - // Release other config groups - for( n = 0; n < referencedConfigGroups.GetLength(); n++ ) - referencedConfigGroups[n]->refCount--; - referencedConfigGroups.SetLength(0); -} - -#ifdef AS_DEBUG -void asCConfigGroup::ValidateNoUsage(asCScriptEngine *engine, asCObjectType *type) -{ - for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[n]; - if( func == 0 ) continue; - - // Ignore factory, list factory, and members - if( func->name == "_beh_3_" || func->name == "_beh_4_" || func->objectType == type ) - continue; - - // Ignore function definitions too, as they aren't released until the engine is destroyed - if( func->funcType == asFUNC_FUNCDEF ) - continue; - - // Ignore functions whose object type has already reached refCount 0 as they are to be removed - if( func->objectType && func->objectType->GetRefCount() == 0 ) - continue; - - if( func->returnType.GetObjectType() == type ) - { - asCString msg; - // We can only use the function name here, because the types used by the function may have been deleted already - msg.Format(TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s, type->name.AddressOf(), func->GetDeclaration()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - } - else - { - for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ ) - { - if( func->parameterTypes[p].GetObjectType() == type ) - { - asCString msg; - // We can only use the function name here, because the types used by the function may have been deleted already - msg.Format(TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s, type->name.AddressOf(), func->GetDeclaration()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - break; - } - } - } - } - - // TODO: Check also usage of the type in global variables - - // TODO: Check also usage of the type in local variables in script functions - - // TODO: Check also usage of the type as members of classes - - // TODO: Check also usage of the type as sub types in other types -} -#endif - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/source/as_configgroup.h b/dependencies/angelscript/source/as_configgroup.h deleted file mode 100644 index 436ac0ca..00000000 --- a/dependencies/angelscript/source/as_configgroup.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2012 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_configgroup.h -// -// This class holds configuration groups for the engine -// - - - -#ifndef AS_CONFIGGROUP_H -#define AS_CONFIGGROUP_H - -#include "as_config.h" -#include "as_string.h" -#include "as_array.h" -#include "as_objecttype.h" - -BEGIN_AS_NAMESPACE - -class asCConfigGroup -{ -public: - asCConfigGroup(); - ~asCConfigGroup(); - - // Memory management - int AddRef(); - int Release(); - - asCObjectType *FindType(const char *obj); - void RefConfigGroup(asCConfigGroup *group); - - bool HasLiveObjects(); - void RemoveConfiguration(asCScriptEngine *engine, bool notUsed = false); - -#ifdef AS_DEBUG - void ValidateNoUsage(asCScriptEngine *engine, asCObjectType *type); -#endif - - asCString groupName; - int refCount; - - asCArray objTypes; - asCArray scriptFunctions; - asCArray globalProps; - asCArray referencedConfigGroups; - asCArray funcDefs; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_context.cpp b/dependencies/angelscript/source/as_context.cpp deleted file mode 100644 index de27d3da..00000000 --- a/dependencies/angelscript/source/as_context.cpp +++ /dev/null @@ -1,5621 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_context.cpp -// -// This class handles the execution of the byte code -// - -#include // fmodf() pow() - -#include "as_config.h" -#include "as_context.h" -#include "as_scriptengine.h" -#include "as_tokendef.h" -#include "as_texts.h" -#include "as_callfunc.h" -#include "as_generic.h" -#include "as_debug.h" // mkdir() -#include "as_bytecode.h" -#include "as_scriptobject.h" - -#ifdef _MSC_VER -#pragma warning(disable:4702) // unreachable code -#endif - -BEGIN_AS_NAMESPACE - -// We need at least 2 PTRs reserved for exception handling -// We need at least 1 PTR reserved for calling system functions -const int RESERVE_STACK = 2*AS_PTR_SIZE; - -// For each script function call we push 9 PTRs on the call stack -const int CALLSTACK_FRAME_SIZE = 9; - -#if defined(AS_DEBUG) - -class asCDebugStats -{ -public: - asCDebugStats() - { - memset(instrCount, 0, sizeof(instrCount)); - memset(instrCount2, 0, sizeof(instrCount2)); - lastBC = 255; - } - - ~asCDebugStats() - { - // This code writes out some statistics for the VM. - // It's useful for determining what needs to be optimized. - - _mkdir("AS_DEBUG"); - #if _MSC_VER >= 1500 && !defined(AS_MARMALADE) - FILE *f; - fopen_s(&f, "AS_DEBUG/stats.txt", "wt"); - #else - FILE *f = fopen("AS_DEBUG/stats.txt", "wt"); - #endif - if( f ) - { - // Output instruction statistics - fprintf(f, "\nTotal count\n"); - int n; - for( n = 0; n < asBC_MAXBYTECODE; n++ ) - { - if( asBCInfo[n].name && instrCount[n] > 0 ) - fprintf(f, "%-10.10s : %.0f\n", asBCInfo[n].name, instrCount[n]); - } - - fprintf(f, "\nNever executed\n"); - for( n = 0; n < asBC_MAXBYTECODE; n++ ) - { - if( asBCInfo[n].name && instrCount[n] == 0 ) - fprintf(f, "%-10.10s\n", asBCInfo[n].name); - } - - fprintf(f, "\nSequences\n"); - for( n = 0; n < 256; n++ ) - { - if( asBCInfo[n].name ) - { - for( int m = 0; m < 256; m++ ) - { - if( instrCount2[n][m] ) - fprintf(f, "%-10.10s, %-10.10s : %.0f\n", asBCInfo[n].name, asBCInfo[m].name, instrCount2[n][m]); - } - } - } - fclose(f); - } - } - - void Instr(asBYTE bc) - { - ++instrCount[bc]; - ++instrCount2[lastBC][bc]; - lastBC = bc; - } - - // Instruction statistics - double instrCount[256]; - double instrCount2[256][256]; - int lastBC; -} stats; - -#endif - -AS_API asIScriptContext *asGetActiveContext() -{ - asCThreadLocalData *tld = asCThreadManager::GetLocalData(); - if( tld->activeContexts.GetLength() == 0 ) - return 0; - return tld->activeContexts[tld->activeContexts.GetLength()-1]; -} - -asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx) -{ - asCThreadLocalData *tld = asCThreadManager::GetLocalData(); - tld->activeContexts.PushLast(ctx); - return tld; -} - -asCContext::asCContext(asCScriptEngine *engine, bool holdRef) -{ - m_refCount.set(1); - - m_holdEngineRef = holdRef; - if( holdRef ) - engine->AddRef(); - - m_engine = engine; - m_status = asEXECUTION_UNINITIALIZED; - m_stackBlockSize = 0; - m_originalStackPointer = 0; - m_inExceptionHandler = false; - m_isStackMemoryNotAllocated = false; - m_needToCleanupArgs = false; - m_currentFunction = 0; - m_callingSystemFunction = 0; - m_regs.objectRegister = 0; - m_initialFunction = 0; - m_lineCallback = false; - m_exceptionCallback = false; - m_regs.doProcessSuspend = false; - m_doSuspend = false; - m_userData = 0; - m_regs.ctx = this; -} - -asCContext::~asCContext() -{ - DetachEngine(); -} - -// interface -bool asCContext::IsNested(asUINT *nestCount) const -{ - if( nestCount ) - *nestCount = 0; - - asUINT c = GetCallstackSize(); - if( c == 0 ) - return false; - - // Search for a marker on the call stack - // This loop starts at 2 because the 0th entry is not stored in m_callStack, - // and then we need to subtract one more to get the base of each frame - for( asUINT n = 2; n <= c; n++ ) - { - const asPWORD *s = m_callStack.AddressOf() + (c - n)*CALLSTACK_FRAME_SIZE; - if( s && s[0] == 0 ) - { - if( nestCount ) - (*nestCount)++; - else - return true; - } - } - - if( nestCount && *nestCount > 0 ) - return true; - - return false; -} - -// interface -int asCContext::AddRef() const -{ - return m_refCount.atomicInc(); -} - -// interface -int asCContext::Release() const -{ - int r = m_refCount.atomicDec(); - - if( r == 0 ) - { - asDELETE(const_cast(this),asCContext); - return 0; - } - - return r; -} - -// internal -void asCContext::DetachEngine() -{ - if( m_engine == 0 ) return; - - // Clean up all calls, included nested ones - do - { - // Abort any execution - Abort(); - - // Free all resources - Unprepare(); - } - while( IsNested() ); - - // Free the stack blocks - for( asUINT n = 0; n < m_stackBlocks.GetLength(); n++ ) - { - if( m_stackBlocks[n] ) - { -#ifndef WIP_16BYTE_ALIGN - asDELETEARRAY(m_stackBlocks[n]); -#else - asDELETEARRAYALIGNED(m_stackBlocks[n]); -#endif - } - } - m_stackBlocks.SetLength(0); - m_stackBlockSize = 0; - - // Clean the user data - for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) - { - if( m_userData[n+1] ) - { - for( asUINT c = 0; c < m_engine->cleanContextFuncs.GetLength(); c++ ) - if( m_engine->cleanContextFuncs[c].type == m_userData[n] ) - m_engine->cleanContextFuncs[c].cleanFunc(this); - } - } - m_userData.SetLength(0); - - // Clear engine pointer - if( m_holdEngineRef ) - m_engine->Release(); - m_engine = 0; -} - -// interface -asIScriptEngine *asCContext::GetEngine() const -{ - return m_engine; -} - -// interface -void *asCContext::SetUserData(void *data, asPWORD type) -{ - // As a thread might add a new new user data at the same time as another - // it is necessary to protect both read and write access to the userData member - ACQUIREEXCLUSIVE(m_engine->engineRWLock); - - // It is not intended to store a lot of different types of userdata, - // so a more complex structure like a associative map would just have - // more overhead than a simple array. - for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) - { - if( m_userData[n] == type ) - { - void *oldData = reinterpret_cast(m_userData[n+1]); - m_userData[n+1] = reinterpret_cast(data); - - RELEASEEXCLUSIVE(m_engine->engineRWLock); - - return oldData; - } - } - - m_userData.PushLast(type); - m_userData.PushLast(reinterpret_cast(data)); - - RELEASEEXCLUSIVE(m_engine->engineRWLock); - - return 0; -} - -// interface -void *asCContext::GetUserData(asPWORD type) const -{ - // There may be multiple threads reading, but when - // setting the user data nobody must be reading. - ACQUIRESHARED(m_engine->engineRWLock); - - for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) - { - if( m_userData[n] == type ) - { - RELEASESHARED(m_engine->engineRWLock); - return reinterpret_cast(m_userData[n+1]); - } - } - - RELEASESHARED(m_engine->engineRWLock); - - return 0; -} - -// interface -asIScriptFunction *asCContext::GetSystemFunction() -{ - return m_callingSystemFunction; -} - -// interface -int asCContext::Prepare(asIScriptFunction *func) -{ - if( func == 0 ) - { - asCString str; - str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, "Prepare", "null", asNO_FUNCTION); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return asNO_FUNCTION; - } - - if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED ) - { - asCString str; - str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, "Prepare", func->GetDeclaration(true, true), asCONTEXT_ACTIVE); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return asCONTEXT_ACTIVE; - } - - // Clean the stack if not done before - if( m_status != asEXECUTION_FINISHED && m_status != asEXECUTION_UNINITIALIZED ) - CleanStack(); - - // Release the returned object (if any) - CleanReturnObject(); - - // Release the object if it is a script object - if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) - { - asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0]; - if( obj ) - obj->Release(); - - *(asPWORD*)&m_regs.stackFramePointer[0] = 0; - } - - if( m_initialFunction && m_initialFunction == func ) - { - // If the same function is executed again, we can skip a lot of the setup - m_currentFunction = m_initialFunction; - - // Reset stack pointer - m_regs.stackPointer = m_originalStackPointer; - - // Make sure the stack pointer is pointing to the original position, - // otherwise something is wrong with the way it is being updated - asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) ); - } - else - { - asASSERT( m_engine ); - - // Make sure the function is from the same engine as the context to avoid mixups - if( m_engine != func->GetEngine() ) - { - asCString str; - str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, "Prepare", func->GetDeclaration(true, true), asINVALID_ARG); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return asINVALID_ARG; - } - - if( m_initialFunction ) - { - m_initialFunction->Release(); - - // Reset stack pointer - m_regs.stackPointer = m_originalStackPointer; - - // Make sure the stack pointer is pointing to the original position, - // otherwise something is wrong with the way it is being updated - asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) ); - } - - // We trust the application not to pass anything else but a asCScriptFunction - m_initialFunction = reinterpret_cast(func); - m_initialFunction->AddRef(); - m_currentFunction = m_initialFunction; - - // TODO: runtime optimize: GetSpaceNeededForArguments() should be precomputed - m_argumentsSize = m_currentFunction->GetSpaceNeededForArguments() + (m_currentFunction->objectType ? AS_PTR_SIZE : 0); - - // Reserve space for the arguments and return value - if( m_currentFunction->DoesReturnOnStack() ) - { - m_returnValueSize = m_currentFunction->returnType.GetSizeInMemoryDWords(); - m_argumentsSize += AS_PTR_SIZE; - } - else - m_returnValueSize = 0; - - // Determine the minimum stack size needed - int stackSize = m_argumentsSize + m_returnValueSize; - if( m_currentFunction->scriptData ) - stackSize += m_currentFunction->scriptData->stackNeeded; - - // Make sure there is enough space on the stack for the arguments and return value - if( !ReserveStackSpace(stackSize) ) - return asOUT_OF_MEMORY; - } - - // Reset state - // Most of the time the previous state will be asEXECUTION_FINISHED, in which case the values are already initialized - if( m_status != asEXECUTION_FINISHED ) - { - m_exceptionLine = -1; - m_exceptionFunction = 0; - m_doAbort = false; - m_doSuspend = false; - m_regs.doProcessSuspend = m_lineCallback; - m_externalSuspendRequest = false; - } - m_status = asEXECUTION_PREPARED; - m_regs.programPointer = 0; - - // Reserve space for the arguments and return value - m_regs.stackFramePointer = m_regs.stackPointer - m_argumentsSize - m_returnValueSize; - m_originalStackPointer = m_regs.stackPointer; - m_regs.stackPointer = m_regs.stackFramePointer; - - // Set arguments to 0 - memset(m_regs.stackPointer, 0, 4*m_argumentsSize); - - if( m_returnValueSize ) - { - // Set the address of the location where the return value should be put - asDWORD *ptr = m_regs.stackFramePointer; - if( m_currentFunction->objectType ) - ptr += AS_PTR_SIZE; - - *(void**)ptr = (void*)(m_regs.stackFramePointer + m_argumentsSize); - } - - return asSUCCESS; -} - -// Free all resources -int asCContext::Unprepare() -{ - if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED ) - return asCONTEXT_ACTIVE; - - // Only clean the stack if the context was prepared but not executed until the end - if( m_status != asEXECUTION_UNINITIALIZED && - m_status != asEXECUTION_FINISHED ) - CleanStack(); - - asASSERT( m_needToCleanupArgs == false ); - - // Release the returned object (if any) - CleanReturnObject(); - - // Release the object if it is a script object - if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) - { - asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0]; - if( obj ) - obj->Release(); - } - - // Release the initial function - if( m_initialFunction ) - { - m_initialFunction->Release(); - - // Reset stack pointer - m_regs.stackPointer = m_originalStackPointer; - - // Make sure the stack pointer is pointing to the original position, - // otherwise something is wrong with the way it is being updated - asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) ); - } - - // Clear function pointers - m_initialFunction = 0; - m_currentFunction = 0; - m_exceptionFunction = 0; - m_regs.programPointer = 0; - - // Reset status - m_status = asEXECUTION_UNINITIALIZED; - - m_regs.stackFramePointer = 0; - - return 0; -} - -asBYTE asCContext::GetReturnByte() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - if( dt->IsObject() || dt->IsReference() ) return 0; - - return *(asBYTE*)&m_regs.valueRegister; -} - -asWORD asCContext::GetReturnWord() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - if( dt->IsObject() || dt->IsReference() ) return 0; - - return *(asWORD*)&m_regs.valueRegister; -} - -asDWORD asCContext::GetReturnDWord() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - if( dt->IsObject() || dt->IsReference() ) return 0; - - return *(asDWORD*)&m_regs.valueRegister; -} - -asQWORD asCContext::GetReturnQWord() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - if( dt->IsObject() || dt->IsReference() ) return 0; - - return m_regs.valueRegister; -} - -float asCContext::GetReturnFloat() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - if( dt->IsObject() || dt->IsReference() ) return 0; - - return *(float*)&m_regs.valueRegister; -} - -double asCContext::GetReturnDouble() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - if( dt->IsObject() || dt->IsReference() ) return 0; - - return *(double*)&m_regs.valueRegister; -} - -void *asCContext::GetReturnAddress() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - if( dt->IsReference() ) - return *(void**)&m_regs.valueRegister; - else if( dt->IsObject() ) - { - if( m_initialFunction->DoesReturnOnStack() ) - { - // The address of the return value was passed as the first argument, after the object pointer - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - return *(void**)(&m_regs.stackFramePointer[offset]); - } - - return m_regs.objectRegister; - } - - return 0; -} - -void *asCContext::GetReturnObject() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - if( !dt->IsObject() ) return 0; - - if( dt->IsReference() ) - return *(void**)(asPWORD)m_regs.valueRegister; - else - { - if( m_initialFunction->DoesReturnOnStack() ) - { - // The address of the return value was passed as the first argument, after the object pointer - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - return *(void**)(&m_regs.stackFramePointer[offset]); - } - - return m_regs.objectRegister; - } -} - -void *asCContext::GetAddressOfReturnValue() -{ - if( m_status != asEXECUTION_FINISHED ) return 0; - - asCDataType *dt = &m_initialFunction->returnType; - - // An object is stored in the objectRegister - if( !dt->IsReference() && dt->IsObject() ) - { - // Need to dereference objects - if( !dt->IsObjectHandle() ) - { - if( m_initialFunction->DoesReturnOnStack() ) - { - // The address of the return value was passed as the first argument, after the object pointer - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - return *(void**)(&m_regs.stackFramePointer[offset]); - } - - return *(void**)&m_regs.objectRegister; - } - return &m_regs.objectRegister; - } - - // Primitives and references are stored in valueRegister - return &m_regs.valueRegister; -} - -int asCContext::SetObject(void *obj) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( !m_initialFunction->objectType ) - { - m_status = asEXECUTION_ERROR; - return asERROR; - } - - asASSERT( *(asPWORD*)&m_regs.stackFramePointer[0] == 0 ); - - *(asPWORD*)&m_regs.stackFramePointer[0] = (asPWORD)obj; - - // TODO: This should be optional by having a flag where the application can chose whether it should be done or not - // The flag could be named something like takeOwnership and have default value of true - if( obj && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) - reinterpret_cast(obj)->AddRef(); - - return 0; -} - -int asCContext::SetArgByte(asUINT arg, asBYTE value) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_ARG; - } - - // Verify the type of the argument - asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - if( dt->GetSizeInMemoryBytes() != 1 ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Set the value - *(asBYTE*)&m_regs.stackFramePointer[offset] = value; - - return 0; -} - -int asCContext::SetArgWord(asUINT arg, asWORD value) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( arg >= m_initialFunction->parameterTypes.GetLength() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_ARG; - } - - // Verify the type of the argument - asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - if( dt->GetSizeInMemoryBytes() != 2 ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Set the value - *(asWORD*)&m_regs.stackFramePointer[offset] = value; - - return 0; -} - -int asCContext::SetArgDWord(asUINT arg, asDWORD value) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_ARG; - } - - // Verify the type of the argument - asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - if( dt->GetSizeInMemoryBytes() != 4 ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Set the value - *(asDWORD*)&m_regs.stackFramePointer[offset] = value; - - return 0; -} - -int asCContext::SetArgQWord(asUINT arg, asQWORD value) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_ARG; - } - - // Verify the type of the argument - asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - if( dt->GetSizeOnStackDWords() != 2 ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Set the value - *(asQWORD*)(&m_regs.stackFramePointer[offset]) = value; - - return 0; -} - -int asCContext::SetArgFloat(asUINT arg, float value) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_ARG; - } - - // Verify the type of the argument - asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - if( dt->GetSizeOnStackDWords() != 1 ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Set the value - *(float*)(&m_regs.stackFramePointer[offset]) = value; - - return 0; -} - -int asCContext::SetArgDouble(asUINT arg, double value) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_ARG; - } - - // Verify the type of the argument - asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - if( dt->GetSizeOnStackDWords() != 2 ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Set the value - *(double*)(&m_regs.stackFramePointer[offset]) = value; - - return 0; -} - -int asCContext::SetArgAddress(asUINT arg, void *value) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_ARG; - } - - // Verify the type of the argument - asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( !dt->IsReference() && !dt->IsObjectHandle() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Set the value - *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)value; - - return 0; -} - -int asCContext::SetArgObject(asUINT arg, void *obj) -{ - if( m_status != asEXECUTION_PREPARED ) - return asCONTEXT_NOT_PREPARED; - - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_ARG; - } - - // Verify the type of the argument - asCDataType *dt = &m_initialFunction->parameterTypes[arg]; - if( !dt->IsObject() ) - { - m_status = asEXECUTION_ERROR; - return asINVALID_TYPE; - } - - // If the object should be sent by value we must make a copy of it - if( !dt->IsReference() ) - { - if( dt->IsObjectHandle() ) - { - // Increase the reference counter - asSTypeBehaviour *beh = &dt->GetObjectType()->beh; - if( obj && beh->addref ) - m_engine->CallObjectMethod(obj, beh->addref); - } - else - { - obj = m_engine->CreateScriptObjectCopy(obj, dt->GetObjectType()); - } - } - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Set the value - *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)obj; - - return 0; -} - - -// TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead. - -// interface -void *asCContext::GetAddressOfArg(asUINT arg) -{ - if( m_status != asEXECUTION_PREPARED ) - return 0; - - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - return 0; - - // Determine the position of the argument - int offset = 0; - if( m_initialFunction->objectType ) - offset += AS_PTR_SIZE; - - // If function returns object by value an extra pointer is pushed on the stack - if( m_returnValueSize ) - offset += AS_PTR_SIZE; - - for( asUINT n = 0; n < arg; n++ ) - offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // We should return the address of the location where the argument value will be placed - - // All registered types are always sent by reference, even if - // the function is declared to receive the argument by value. - return &m_regs.stackFramePointer[offset]; -} - - -int asCContext::Abort() -{ - if( m_engine == 0 ) return asERROR; - - // TODO: multithread: Make thread safe. There is a chance that the status - // changes to something else after being set to ABORTED here. - if( m_status == asEXECUTION_SUSPENDED ) - m_status = asEXECUTION_ABORTED; - - m_doSuspend = true; - m_regs.doProcessSuspend = true; - m_externalSuspendRequest = true; - m_doAbort = true; - - return 0; -} - -// interface -int asCContext::Suspend() -{ - // This function just sets some internal flags and is safe - // to call from a secondary thread, even if the library has - // been built without multi-thread support. - - if( m_engine == 0 ) return asERROR; - - m_doSuspend = true; - m_externalSuspendRequest = true; - m_regs.doProcessSuspend = true; - - return 0; -} - -// interface -int asCContext::Execute() -{ - asASSERT( m_engine != 0 ); - - if( m_status != asEXECUTION_SUSPENDED && m_status != asEXECUTION_PREPARED ) - { - asCString str; - str.Format(TXT_FAILED_IN_FUNC_s_d, "Execute", asCONTEXT_NOT_PREPARED); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return asCONTEXT_NOT_PREPARED; - } - - m_status = asEXECUTION_ACTIVE; - - asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this); - - if( m_regs.programPointer == 0 ) - { - if( m_currentFunction->funcType == asFUNC_DELEGATE ) - { - // Push the object pointer onto the stack - asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] ); - m_regs.stackPointer -= AS_PTR_SIZE; - m_regs.stackFramePointer -= AS_PTR_SIZE; - *(asPWORD*)m_regs.stackPointer = asPWORD(m_currentFunction->objForDelegate); - - // Make the call to the delegated object method - m_currentFunction = m_currentFunction->funcForDelegate; - } - - if( m_currentFunction->funcType == asFUNC_VIRTUAL || - m_currentFunction->funcType == asFUNC_INTERFACE ) - { - // The currentFunction is a virtual method - - // Determine the true function from the object - asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackFramePointer; - if( obj == 0 ) - { - SetInternalException(TXT_NULL_POINTER_ACCESS); - } - else - { - asCObjectType *objType = obj->objType; - asCScriptFunction *realFunc = 0; - - if( m_currentFunction->funcType == asFUNC_VIRTUAL ) - { - if( objType->virtualFunctionTable.GetLength() > (asUINT)m_currentFunction->vfTableIdx ) - { - realFunc = objType->virtualFunctionTable[m_currentFunction->vfTableIdx]; - } - } - else - { - // Search the object type for a function that matches the interface function - for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) - { - asCScriptFunction *f2 = m_engine->scriptFunctions[objType->methods[n]]; - if( f2->signatureId == m_currentFunction->signatureId ) - { - if( f2->funcType == asFUNC_VIRTUAL ) - realFunc = objType->virtualFunctionTable[f2->vfTableIdx]; - else - realFunc = f2; - break; - } - } - } - - if( realFunc && realFunc->signatureId == m_currentFunction->signatureId ) - m_currentFunction = realFunc; - else - SetInternalException(TXT_NULL_POINTER_ACCESS); - } - } - else if( m_currentFunction->funcType == asFUNC_IMPORTED ) - { - int funcId = m_engine->importedFunctions[m_currentFunction->id & ~FUNC_IMPORTED]->boundFunctionId; - if( funcId > 0 ) - m_currentFunction = m_engine->scriptFunctions[funcId]; - else - SetInternalException(TXT_UNBOUND_FUNCTION); - } - - if( m_currentFunction->funcType == asFUNC_SCRIPT ) - { - m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf(); - - // Set up the internal registers for executing the script function - PrepareScriptFunction(); - } - else if( m_currentFunction->funcType == asFUNC_SYSTEM ) - { - // The current function is an application registered function - - // Call the function directly - CallSystemFunction(m_currentFunction->id, this, 0); - - // Was the call successful? - if( m_status == asEXECUTION_ACTIVE ) - { - m_status = asEXECUTION_FINISHED; - } - } - else - { - // This shouldn't happen unless there was an error in which - // case an exception should have been raised already - asASSERT( m_status == asEXECUTION_EXCEPTION ); - } - } - - asUINT gcPreObjects = 0; - if( m_engine->ep.autoGarbageCollect ) - m_engine->gc.GetStatistics(&gcPreObjects, 0, 0, 0, 0); - - while( m_status == asEXECUTION_ACTIVE ) - ExecuteNext(); - - if( m_lineCallback ) - { - // Call the line callback one last time before leaving - // so anyone listening can catch the state change - CallLineCallback(); - m_regs.doProcessSuspend = true; - } - else - m_regs.doProcessSuspend = false; - - m_doSuspend = false; - - if( m_engine->ep.autoGarbageCollect ) - { - asUINT gcPosObjects = 0; - m_engine->gc.GetStatistics(&gcPosObjects, 0, 0, 0, 0); - if( gcPosObjects > gcPreObjects ) - { - // Execute as many steps as there were new objects created - m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, gcPosObjects - gcPreObjects); - } - else if( gcPosObjects > 0 ) - { - // Execute at least one step, even if no new objects were created - m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, 1); - } - } - - // Pop the active context - asASSERT(tld->activeContexts[tld->activeContexts.GetLength()-1] == this); - tld->activeContexts.PopLast(); - - if( m_status == asEXECUTION_FINISHED ) - { - m_regs.objectType = m_initialFunction->returnType.GetObjectType(); - return asEXECUTION_FINISHED; - } - - if( m_doAbort ) - { - m_doAbort = false; - - m_status = asEXECUTION_ABORTED; - return asEXECUTION_ABORTED; - } - - if( m_status == asEXECUTION_SUSPENDED ) - return asEXECUTION_SUSPENDED; - - if( m_status == asEXECUTION_EXCEPTION ) - return asEXECUTION_EXCEPTION; - - return asERROR; -} - -int asCContext::PushState() -{ - // Only allow the state to be pushed when active - // TODO: Can we support a suspended state too? So the reuse of - // the context can be done outside the Execute() call? - if( m_status != asEXECUTION_ACTIVE ) - { - // TODO: Write message. Wrong usage - return asERROR; - } - - // Push the current script function that is calling the system function - PushCallState(); - - // Push the system function too, which will serve both as a marker and - // informing which system function that created the nested call - if( m_callStack.GetLength() == m_callStack.GetCapacity() ) - { - // Allocate space for 10 call states at a time to save time - m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true); - } - m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE); - - // Need to push m_initialFunction as it must be restored later - asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; - tmp[0] = 0; - tmp[1] = (asPWORD)m_callingSystemFunction; - tmp[2] = (asPWORD)m_initialFunction; - tmp[3] = (asPWORD)m_originalStackPointer; - tmp[4] = (asPWORD)m_argumentsSize; - - // Need to push the value of registers so they can be restored - tmp[5] = (asPWORD)asDWORD(m_regs.valueRegister); - tmp[6] = (asPWORD)asDWORD(m_regs.valueRegister>>32); - tmp[7] = (asPWORD)m_regs.objectRegister; - tmp[8] = (asPWORD)m_regs.objectType; - - // Decrease stackpointer to prevent the top value from being overwritten - m_regs.stackPointer -= 2; - - // Clear the initial function so that Prepare() knows it must do all validations - m_initialFunction = 0; - - // After this the state should appear as if uninitialized - m_callingSystemFunction = 0; - - m_regs.objectRegister = 0; - m_regs.objectType = 0; - - // Set the status to uninitialized as application - // should call Prepare() after this to reuse the context - m_status = asEXECUTION_UNINITIALIZED; - - return asSUCCESS; -} - -int asCContext::PopState() -{ - if( !IsNested() ) - return asERROR; - - // Clean up the current execution - Unprepare(); - - // The topmost state must be a marker for nested call - asASSERT( m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 ); - - // Restore the previous state - asPWORD *tmp = &m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE]; - m_callingSystemFunction = reinterpret_cast(tmp[1]); - m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE); - - // Restore the previous initial function and the associated values - m_initialFunction = reinterpret_cast(tmp[2]); - m_originalStackPointer = (asDWORD*)tmp[3]; - m_argumentsSize = (int)tmp[4]; - - m_regs.valueRegister = asQWORD(asDWORD(tmp[5])); - m_regs.valueRegister |= asQWORD(tmp[6])<<32; - m_regs.objectRegister = (void*)tmp[7]; - m_regs.objectType = (asIObjectType*)tmp[8]; - - // Calculate the returnValueSize - if( m_initialFunction->DoesReturnOnStack() ) - m_returnValueSize = m_initialFunction->returnType.GetSizeInMemoryDWords(); - else - m_returnValueSize = 0; - - // Pop the current script function. This will also restore the previous stack pointer - PopCallState(); - - m_status = asEXECUTION_ACTIVE; - - return asSUCCESS; -} - -void asCContext::PushCallState() -{ - if( m_callStack.GetLength() == m_callStack.GetCapacity() ) - { - // Allocate space for 10 call states at a time to save time - m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true); - } - m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE); - - // Separating the loads and stores limits data cache trash, and with a smart compiler - // could turn into SIMD style loading/storing if available. - // The compiler can't do this itself due to potential pointer aliasing between the pointers, - // ie writing to tmp could overwrite the data contained in registers.stackFramePointer for example - // for all the compiler knows. So introducing the local variable s, which is never referred to by - // its address we avoid this issue. - - asPWORD s[5]; - s[0] = (asPWORD)m_regs.stackFramePointer; - s[1] = (asPWORD)m_currentFunction; - s[2] = (asPWORD)m_regs.programPointer; - s[3] = (asPWORD)m_regs.stackPointer; - s[4] = m_stackIndex; - - asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; - tmp[0] = s[0]; - tmp[1] = s[1]; - tmp[2] = s[2]; - tmp[3] = s[3]; - tmp[4] = s[4]; -} - -void asCContext::PopCallState() -{ - // See comments in PushCallState about pointer aliasing and data cache trashing - asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; - asPWORD s[5]; - s[0] = tmp[0]; - s[1] = tmp[1]; - s[2] = tmp[2]; - s[3] = tmp[3]; - s[4] = tmp[4]; - - m_regs.stackFramePointer = (asDWORD*)s[0]; - m_currentFunction = (asCScriptFunction*)s[1]; - m_regs.programPointer = (asDWORD*)s[2]; - m_regs.stackPointer = (asDWORD*)s[3]; - m_stackIndex = (int)s[4]; - - m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE); -} - -// interface -asUINT asCContext::GetCallstackSize() const -{ - if( m_currentFunction == 0 ) return 0; - - // The current function is accessed at stackLevel 0 - return asUINT(1 + m_callStack.GetLength() / CALLSTACK_FRAME_SIZE); -} - -// interface -asIScriptFunction *asCContext::GetFunction(asUINT stackLevel) -{ - if( stackLevel >= GetCallstackSize() ) return 0; - - if( stackLevel == 0 ) return m_currentFunction; - - asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize() - stackLevel - 1)*CALLSTACK_FRAME_SIZE; - asCScriptFunction *func = (asCScriptFunction*)s[1]; - - return func; -} - -// interface -int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **sectionName) -{ - if( stackLevel >= GetCallstackSize() ) return asINVALID_ARG; - - asCScriptFunction *func; - asDWORD *bytePos; - if( stackLevel == 0 ) - { - func = m_currentFunction; - if( func->scriptData == 0 ) return 0; - bytePos = m_regs.programPointer; - } - else - { - asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; - func = (asCScriptFunction*)s[1]; - if( func->scriptData == 0 ) return 0; - bytePos = (asDWORD*)s[2]; - - // Subract 1 from the bytePos, because we want the line where - // the call was made, and not the instruction after the call - bytePos -= 1; - } - - // For nested calls it is possible that func is null - if( func == 0 ) - { - if( column ) *column = 0; - if( sectionName ) *sectionName = 0; - return 0; - } - - int sectionIdx; - asDWORD line = func->GetLineNumber(int(bytePos - func->scriptData->byteCode.AddressOf()), §ionIdx); - if( column ) *column = (line >> 20); - if( sectionName ) - { - asASSERT( sectionIdx < int(m_engine->scriptSectionNames.GetLength()) ); - if( sectionIdx >= 0 && asUINT(sectionIdx) < m_engine->scriptSectionNames.GetLength() ) - *sectionName = m_engine->scriptSectionNames[sectionIdx]->AddressOf(); - else - *sectionName = 0; - } - return (line & 0xFFFFF); -} - -// internal -bool asCContext::ReserveStackSpace(asUINT size) -{ -#ifdef WIP_16BYTE_ALIGN - // Pad size to a multiple of MAX_TYPE_ALIGNMENT. - const asUINT remainder = size % MAX_TYPE_ALIGNMENT; - if(remainder != 0) - { - size = size + (MAX_TYPE_ALIGNMENT - (size % MAX_TYPE_ALIGNMENT)); - } -#endif - - // Make sure the first stack block is allocated - if( m_stackBlocks.GetLength() == 0 ) - { - m_stackBlockSize = m_engine->initialContextStackSize; - asASSERT( m_stackBlockSize > 0 ); - -#ifndef WIP_16BYTE_ALIGN - asDWORD *stack = asNEWARRAY(asDWORD,m_stackBlockSize); -#else - asDWORD *stack = asNEWARRAYALIGNED(asDWORD, m_stackBlockSize, MAX_TYPE_ALIGNMENT); -#endif - if( stack == 0 ) - { - // Out of memory - return false; - } - -#ifdef WIP_16BYTE_ALIGN - asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) ); -#endif - - m_stackBlocks.PushLast(stack); - m_stackIndex = 0; - m_regs.stackPointer = m_stackBlocks[0] + m_stackBlockSize; - -#ifdef WIP_16BYTE_ALIGN - // Align the stack pointer. This is necessary as the m_stackBlockSize is not necessarily evenly divisable with the max alignment - ((asPWORD&)m_regs.stackPointer) &= ~(MAX_TYPE_ALIGNMENT-1); - - asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) ); -#endif - } - - // Check if there is enough space on the current stack block, otherwise move - // to the next one. New and larger blocks will be allocated as necessary - while( m_regs.stackPointer - (size + RESERVE_STACK) < m_stackBlocks[m_stackIndex] ) - { - // Make sure we don't allocate more space than allowed - if( m_engine->ep.maximumContextStackSize ) - { - // This test will only stop growth once it has already crossed the limit - if( m_stackBlockSize * ((1 << (m_stackIndex+1)) - 1) > m_engine->ep.maximumContextStackSize ) - { - m_isStackMemoryNotAllocated = true; - - // Set the stackFramePointer, even though the stackPointer wasn't updated - m_regs.stackFramePointer = m_regs.stackPointer; - - SetInternalException(TXT_STACK_OVERFLOW); - return false; - } - } - - m_stackIndex++; - if( m_stackBlocks.GetLength() == m_stackIndex ) - { - // Allocate the new stack block, with twice the size of the previous -#ifndef WIP_16BYTE_ALIGN - asDWORD *stack = asNEWARRAY(asDWORD, (m_stackBlockSize << m_stackIndex)); -#else - asDWORD *stack = asNEWARRAYALIGNED(asDWORD, (m_stackBlockSize << m_stackIndex), MAX_TYPE_ALIGNMENT); -#endif - if( stack == 0 ) - { - // Out of memory - m_isStackMemoryNotAllocated = true; - - // Set the stackFramePointer, even though the stackPointer wasn't updated - m_regs.stackFramePointer = m_regs.stackPointer; - - SetInternalException(TXT_STACK_OVERFLOW); - return false; - } - -#ifdef WIP_16BYTE_ALIGN - asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) ); -#endif - - m_stackBlocks.PushLast(stack); - } - - // Update the stack pointer to point to the new block. - // Leave enough room above the stackpointer to copy the arguments from the previous stackblock - m_regs.stackPointer = m_stackBlocks[m_stackIndex] + - (m_stackBlockSize<GetSpaceNeededForArguments() - - (m_currentFunction->objectType ? AS_PTR_SIZE : 0) - - (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0); - -#ifdef WIP_16BYTE_ALIGN - // Align the stack pointer - (asPWORD&)m_regs.stackPointer &= ~(MAX_TYPE_ALIGNMENT-1); - - asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) ); -#endif - } - - return true; -} - -// internal -void asCContext::CallScriptFunction(asCScriptFunction *func) -{ - asASSERT( func->scriptData ); - - // Push the framepointer, function id and programCounter on the stack - PushCallState(); - - // Update the current function and program position before increasing the stack - // so the exception handler will know what to do if there is a stack overflow - m_currentFunction = func; - m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf(); - - PrepareScriptFunction(); -} - -void asCContext::PrepareScriptFunction() -{ - asASSERT( m_currentFunction->scriptData ); - - // Make sure there is space on the stack to execute the function - asDWORD *oldStackPointer = m_regs.stackPointer; - if( !ReserveStackSpace(m_currentFunction->scriptData->stackNeeded) ) - return; - - // If a new stack block was allocated then we'll need to move - // over the function arguments to the new block. - if( m_regs.stackPointer != oldStackPointer ) - { - int numDwords = m_currentFunction->GetSpaceNeededForArguments() + - (m_currentFunction->objectType ? AS_PTR_SIZE : 0) + - (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0); - memcpy(m_regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords); - } - - // Update framepointer - m_regs.stackFramePointer = m_regs.stackPointer; - - // Set all object variables to 0 to guarantee that they are null before they are used - // Only variables on the heap should be cleared. The rest will be cleared by calling the constructor - asUINT n = m_currentFunction->scriptData->objVariablesOnHeap; - while( n-- > 0 ) - { - int pos = m_currentFunction->scriptData->objVariablePos[n]; - *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0; - } - - // Initialize the stack pointer with the space needed for local variables - m_regs.stackPointer -= m_currentFunction->scriptData->variableSpace; - - // Call the line callback for each script function, to guarantee that infinitely recursive scripts can - // be interrupted, even if the scripts have been compiled with asEP_BUILD_WITHOUT_LINE_CUES - if( m_regs.doProcessSuspend ) - { - if( m_lineCallback ) - CallLineCallback(); - if( m_doSuspend ) - m_status = asEXECUTION_SUSPENDED; - } -} - -void asCContext::CallInterfaceMethod(asCScriptFunction *func) -{ - // Resolve the interface method using the current script type - asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackPointer; - if( obj == 0 ) - { - // Tell the exception handler to clean up the arguments to this method - m_needToCleanupArgs = true; - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - - asCObjectType *objType = obj->objType; - - // Search the object type for a function that matches the interface function - asCScriptFunction *realFunc = 0; - if( func->funcType == asFUNC_INTERFACE ) - { - // Find the offset for the interface's virtual function table chunk - asUINT offset = 0; - bool found = false; - asCObjectType *findInterface = func->objectType; - - // TODO: runtime optimize: The list of interfaces should be ordered by the address - // Then a binary search pattern can be used. - asUINT intfCount = asUINT(objType->interfaces.GetLength()); - for( asUINT n = 0; n < intfCount; n++ ) - { - if( objType->interfaces[n] == findInterface ) - { - offset = objType->interfaceVFTOffsets[n]; - found = true; - break; - } - } - - if( !found ) - { - // Tell the exception handler to clean up the arguments to this method - m_needToCleanupArgs = true; - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - - // Find the real function in the virtual table chunk with the found offset - realFunc = objType->virtualFunctionTable[func->vfTableIdx + offset]; - - // Since the interface was implemented by the class, it shouldn't - // be possible that the real function isn't found - asASSERT( realFunc ); - - asASSERT( realFunc->signatureId == func->signatureId ); - } - else // if( func->funcType == asFUNC_VIRTUAL ) - { - realFunc = objType->virtualFunctionTable[func->vfTableIdx]; - } - - // Then call the true script function - CallScriptFunction(realFunc); -} - -void asCContext::ExecuteNext() -{ - asDWORD *l_bc = m_regs.programPointer; - asDWORD *l_sp = m_regs.stackPointer; - asDWORD *l_fp = m_regs.stackFramePointer; - - for(;;) - { - -#ifdef AS_DEBUG - // Gather statistics on executed bytecode - stats.Instr(*(asBYTE*)l_bc); - - // Used to verify that the size of the instructions are correct - asDWORD *old = l_bc; -#endif - - - // Remember to keep the cases in order and without - // gaps, because that will make the switch faster. - // It will be faster since only one lookup will be - // made to find the correct jump destination. If not - // in order, the switch will make two lookups. - switch( *(asBYTE*)l_bc ) - { -//-------------- -// memory access functions - - case asBC_PopPtr: - // Pop a pointer from the stack - l_sp += AS_PTR_SIZE; - l_bc++; - break; - - case asBC_PshGPtr: - // Replaces PGA + RDSPtr - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = *(asPWORD*)asBC_PTRARG(l_bc); - l_bc += 1 + AS_PTR_SIZE; - break; - - // Push a dword value on the stack - case asBC_PshC4: - --l_sp; - *l_sp = asBC_DWORDARG(l_bc); - l_bc += 2; - break; - - // Push the dword value of a variable on the stack - case asBC_PshV4: - --l_sp; - *l_sp = *(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - // Push the address of a variable on the stack - case asBC_PSF: - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = asPWORD(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - // Swap the top 2 pointers on the stack - case asBC_SwapPtr: - { - asPWORD p = *(asPWORD*)l_sp; - *(asPWORD*)l_sp = *(asPWORD*)(l_sp+AS_PTR_SIZE); - *(asPWORD*)(l_sp+AS_PTR_SIZE) = p; - l_bc++; - } - break; - - // Do a boolean not operation, modifying the value of the variable - case asBC_NOT: -#if AS_SIZEOF_BOOL == 1 - { - // Set the value to true if it is equal to 0 - - // We need to use volatile here to tell the compiler it cannot - // change the order of read and write operations on the pointer. - - volatile asBYTE *ptr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); - asBYTE val = (ptr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0; - ptr[0] = val; // The result is stored in the lower byte - ptr[1] = 0; // Make sure the rest of the DWORD is 0 - ptr[2] = 0; - ptr[3] = 0; - } -#else - *(l_fp - asBC_SWORDARG0(l_bc)) = (*(l_fp - asBC_SWORDARG0(l_bc)) == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); -#endif - l_bc++; - break; - - // Push the dword value of a global variable on the stack - case asBC_PshG4: - --l_sp; - *l_sp = *(asDWORD*)asBC_PTRARG(l_bc); - l_bc += 1 + AS_PTR_SIZE; - break; - - // Load the address of a global variable in the register, then - // copy the value of the global variable into a local variable - case asBC_LdGRdR4: - *(void**)&m_regs.valueRegister = (void*)asBC_PTRARG(l_bc); - *(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister; - l_bc += 1+AS_PTR_SIZE; - break; - -//---------------- -// path control instructions - - // Begin execution of a script function - case asBC_CALL: - { - int i = asBC_INTARG(l_bc); - l_bc += 2; - - asASSERT( i >= 0 ); - asASSERT( (i & FUNC_IMPORTED) == 0 ); - - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - CallScriptFunction(m_engine->scriptFunctions[i]); - - // Extract the values from the context again - l_bc = m_regs.programPointer; - l_sp = m_regs.stackPointer; - l_fp = m_regs.stackFramePointer; - - // If status isn't active anymore then we must stop - if( m_status != asEXECUTION_ACTIVE ) - return; - } - break; - - // Return to the caller, and remove the arguments from the stack - case asBC_RET: - { - // Return if this was the first function, or a nested execution - if( m_callStack.GetLength() == 0 || - m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 ) - { - m_status = asEXECUTION_FINISHED; - return; - } - - asWORD w = asBC_WORDARG0(l_bc); - - // Read the old framepointer, functionid, and programCounter from the call stack - PopCallState(); - - // Extract the values from the context again - l_bc = m_regs.programPointer; - l_sp = m_regs.stackPointer; - l_fp = m_regs.stackFramePointer; - - // Pop arguments from stack - l_sp += w; - } - break; - - // Jump to a relative position - case asBC_JMP: - l_bc += 2 + asBC_INTARG(l_bc); - break; - -//---------------- -// Conditional jumps - - // Jump to a relative position if the value in the register is 0 - case asBC_JZ: - if( *(int*)&m_regs.valueRegister == 0 ) - l_bc += asBC_INTARG(l_bc) + 2; - else - l_bc += 2; - break; - - // Jump to a relative position if the value in the register is not 0 - case asBC_JNZ: - if( *(int*)&m_regs.valueRegister != 0 ) - l_bc += asBC_INTARG(l_bc) + 2; - else - l_bc += 2; - break; - - // Jump to a relative position if the value in the register is negative - case asBC_JS: - if( *(int*)&m_regs.valueRegister < 0 ) - l_bc += asBC_INTARG(l_bc) + 2; - else - l_bc += 2; - break; - - // Jump to a relative position if the value in the register it not negative - case asBC_JNS: - if( *(int*)&m_regs.valueRegister >= 0 ) - l_bc += asBC_INTARG(l_bc) + 2; - else - l_bc += 2; - break; - - // Jump to a relative position if the value in the register is greater than 0 - case asBC_JP: - if( *(int*)&m_regs.valueRegister > 0 ) - l_bc += asBC_INTARG(l_bc) + 2; - else - l_bc += 2; - break; - - // Jump to a relative position if the value in the register is not greater than 0 - case asBC_JNP: - if( *(int*)&m_regs.valueRegister <= 0 ) - l_bc += asBC_INTARG(l_bc) + 2; - else - l_bc += 2; - break; -//-------------------- -// test instructions - - // If the value in the register is 0, then set the register to 1, else to 0 - case asBC_TZ: -#if AS_SIZEOF_BOOL == 1 - { - // Set the value to true if it is equal to 0 - - // We need to use volatile here to tell the compiler it cannot - // change the order of read and write operations on valueRegister. - - volatile int *regPtr = (int*)&m_regs.valueRegister; - volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; - asBYTE val = (regPtr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0; - regBptr[0] = val; // The result is stored in the lower byte - regBptr[1] = 0; // Make sure the rest of the register is 0 - regBptr[2] = 0; - regBptr[3] = 0; - regBptr[4] = 0; - regBptr[5] = 0; - regBptr[6] = 0; - regBptr[7] = 0; - } -#else - *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); -#endif - l_bc++; - break; - - // If the value in the register is not 0, then set the register to 1, else to 0 - case asBC_TNZ: -#if AS_SIZEOF_BOOL == 1 - { - // Set the value to true if it is not equal to 0 - - // We need to use volatile here to tell the compiler it cannot - // change the order of read and write operations on valueRegister. - - volatile int *regPtr = (int*)&m_regs.valueRegister; - volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; - asBYTE val = (regPtr[0] == 0) ? 0 : VALUE_OF_BOOLEAN_TRUE; - regBptr[0] = val; // The result is stored in the lower byte - regBptr[1] = 0; // Make sure the rest of the register is 0 - regBptr[2] = 0; - regBptr[3] = 0; - regBptr[4] = 0; - regBptr[5] = 0; - regBptr[6] = 0; - regBptr[7] = 0; - } -#else - *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); -#endif - l_bc++; - break; - - // If the value in the register is negative, then set the register to 1, else to 0 - case asBC_TS: -#if AS_SIZEOF_BOOL == 1 - { - // Set the value to true if it is less than 0 - - // We need to use volatile here to tell the compiler it cannot - // change the order of read and write operations on valueRegister. - - volatile int *regPtr = (int*)&m_regs.valueRegister; - volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; - asBYTE val = (regPtr[0] < 0) ? VALUE_OF_BOOLEAN_TRUE : 0; - regBptr[0] = val; // The result is stored in the lower byte - regBptr[1] = 0; // Make sure the rest of the register is 0 - regBptr[2] = 0; - regBptr[3] = 0; - regBptr[4] = 0; - regBptr[5] = 0; - regBptr[6] = 0; - regBptr[7] = 0; - } -#else - *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? VALUE_OF_BOOLEAN_TRUE : 0); -#endif - l_bc++; - break; - - // If the value in the register is not negative, then set the register to 1, else to 0 - case asBC_TNS: -#if AS_SIZEOF_BOOL == 1 - { - // Set the value to true if it is not less than 0 - - // We need to use volatile here to tell the compiler it cannot - // change the order of read and write operations on valueRegister. - - volatile int *regPtr = (int*)&m_regs.valueRegister; - volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; - asBYTE val = (regPtr[0] >= 0) ? VALUE_OF_BOOLEAN_TRUE : 0; - regBptr[0] = val; // The result is stored in the lower byte - regBptr[1] = 0; // Make sure the rest of the register is 0 - regBptr[2] = 0; - regBptr[3] = 0; - regBptr[4] = 0; - regBptr[5] = 0; - regBptr[6] = 0; - regBptr[7] = 0; - } -#else - *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); -#endif - l_bc++; - break; - - // If the value in the register is greater than 0, then set the register to 1, else to 0 - case asBC_TP: -#if AS_SIZEOF_BOOL == 1 - { - // Set the value to true if it is greater than 0 - - // We need to use volatile here to tell the compiler it cannot - // change the order of read and write operations on valueRegister. - - volatile int *regPtr = (int*)&m_regs.valueRegister; - volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; - asBYTE val = (regPtr[0] > 0) ? VALUE_OF_BOOLEAN_TRUE : 0; - regBptr[0] = val; // The result is stored in the lower byte - regBptr[1] = 0; // Make sure the rest of the register is 0 - regBptr[2] = 0; - regBptr[3] = 0; - regBptr[4] = 0; - regBptr[5] = 0; - regBptr[6] = 0; - regBptr[7] = 0; - } -#else - *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? VALUE_OF_BOOLEAN_TRUE : 0); -#endif - l_bc++; - break; - - // If the value in the register is not greater than 0, then set the register to 1, else to 0 - case asBC_TNP: -#if AS_SIZEOF_BOOL == 1 - { - // Set the value to true if it is not greater than 0 - - // We need to use volatile here to tell the compiler it cannot - // change the order of read and write operations on valueRegister. - - volatile int *regPtr = (int*)&m_regs.valueRegister; - volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; - asBYTE val = (regPtr[0] <= 0) ? VALUE_OF_BOOLEAN_TRUE : 0; - regBptr[0] = val; // The result is stored in the lower byte - regBptr[1] = 0; // Make sure the rest of the register is 0 - regBptr[2] = 0; - regBptr[3] = 0; - regBptr[4] = 0; - regBptr[5] = 0; - regBptr[6] = 0; - regBptr[7] = 0; - } -#else - *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); -#endif - l_bc++; - break; - -//-------------------- -// negate value - - // Negate the integer value in the variable - case asBC_NEGi: - *(l_fp - asBC_SWORDARG0(l_bc)) = asDWORD(-int(*(l_fp - asBC_SWORDARG0(l_bc)))); - l_bc++; - break; - - // Negate the float value in the variable - case asBC_NEGf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(float*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - // Negate the double value in the variable - case asBC_NEGd: - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(double*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - -//------------------------- -// Increment value pointed to by address in register - - // Increment the short value pointed to by the register - case asBC_INCi16: - (**(short**)&m_regs.valueRegister)++; - l_bc++; - break; - - // Increment the byte value pointed to by the register - case asBC_INCi8: - (**(char**)&m_regs.valueRegister)++; - l_bc++; - break; - - // Decrement the short value pointed to by the register - case asBC_DECi16: - (**(short**)&m_regs.valueRegister)--; - l_bc++; - break; - - // Decrement the byte value pointed to by the register - case asBC_DECi8: - (**(char**)&m_regs.valueRegister)--; - l_bc++; - break; - - // Increment the integer value pointed to by the register - case asBC_INCi: - ++(**(int**)&m_regs.valueRegister); - l_bc++; - break; - - // Decrement the integer value pointed to by the register - case asBC_DECi: - --(**(int**)&m_regs.valueRegister); - l_bc++; - break; - - // Increment the float value pointed to by the register - case asBC_INCf: - ++(**(float**)&m_regs.valueRegister); - l_bc++; - break; - - // Decrement the float value pointed to by the register - case asBC_DECf: - --(**(float**)&m_regs.valueRegister); - l_bc++; - break; - - // Increment the double value pointed to by the register - case asBC_INCd: - ++(**(double**)&m_regs.valueRegister); - l_bc++; - break; - - // Decrement the double value pointed to by the register - case asBC_DECd: - --(**(double**)&m_regs.valueRegister); - l_bc++; - break; - - // Increment the local integer variable - case asBC_IncVi: - (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))++; - l_bc++; - break; - - // Decrement the local integer variable - case asBC_DecVi: - (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))--; - l_bc++; - break; - -//-------------------- -// bits instructions - - // Do a bitwise not on the value in the variable - case asBC_BNOT: - *(l_fp - asBC_SWORDARG0(l_bc)) = ~*(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - // Do a bitwise and of two variables and store the result in a third variable - case asBC_BAND: - *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) & *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - // Do a bitwise or of two variables and store the result in a third variable - case asBC_BOR: - *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) | *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - // Do a bitwise xor of two variables and store the result in a third variable - case asBC_BXOR: - *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) ^ *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - // Do a logical shift left of two variables and store the result in a third variable - case asBC_BSLL: - *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - // Do a logical shift right of two variables and store the result in a third variable - case asBC_BSRL: - *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - // Do an arithmetic shift right of two variables and store the result in a third variable - case asBC_BSRA: - *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(l_fp - asBC_SWORDARG1(l_bc))) >> *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_COPY: - { - void *d = (void*)*(asPWORD*)l_sp; l_sp += AS_PTR_SIZE; - void *s = (void*)*(asPWORD*)l_sp; - if( s == 0 || d == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - memcpy(d, s, asBC_WORDARG0(l_bc)*4); - - // replace the pointer on the stack with the lvalue - *(asPWORD**)l_sp = (asPWORD*)d; - } - l_bc += 2; - break; - - case asBC_PshC8: - l_sp -= 2; - *(asQWORD*)l_sp = asBC_QWORDARG(l_bc); - l_bc += 3; - break; - - case asBC_PshVPtr: - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_RDSPtr: - { - // The pointer must not be null - asPWORD a = *(asPWORD*)l_sp; - if( a == 0 ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - // Pop an address from the stack, read a pointer from that address and push it on the stack - *(asPWORD*)l_sp = *(asPWORD*)a; - } - l_bc++; - break; - - //---------------------------- - // Comparisons - case asBC_CMPd: - { - // Do a comparison of the values, rather than a subtraction - // in order to get proper behaviour for infinity values. - double dbl1 = *(double*)(l_fp - asBC_SWORDARG0(l_bc)); - double dbl2 = *(double*)(l_fp - asBC_SWORDARG1(l_bc)); - if( dbl1 == dbl2 ) *(int*)&m_regs.valueRegister = 0; - else if( dbl1 < dbl2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_CMPu: - { - asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - asDWORD d2 = *(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc)); - if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0; - else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_CMPf: - { - // Do a comparison of the values, rather than a subtraction - // in order to get proper behaviour for infinity values. - float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc)); - float f2 = *(float*)(l_fp - asBC_SWORDARG1(l_bc)); - if( f1 == f2 ) *(int*)&m_regs.valueRegister = 0; - else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_CMPi: - { - int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc)); - int i2 = *(int*)(l_fp - asBC_SWORDARG1(l_bc)); - if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0; - else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - //---------------------------- - // Comparisons with constant value - case asBC_CMPIi: - { - int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc)); - int i2 = asBC_INTARG(l_bc); - if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0; - else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_CMPIf: - { - // Do a comparison of the values, rather than a subtraction - // in order to get proper behaviour for infinity values. - float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc)); - float f2 = asBC_FLOATARG(l_bc); - if( f1 == f2 ) *(int*)&m_regs.valueRegister = 0; - else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_CMPIu: - { - asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - asDWORD d2 = asBC_DWORDARG(l_bc); - if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0; - else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_JMPP: - l_bc += 1 + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))*2; - break; - - case asBC_PopRPtr: - *(asPWORD*)&m_regs.valueRegister = *(asPWORD*)l_sp; - l_sp += AS_PTR_SIZE; - l_bc++; - break; - - case asBC_PshRPtr: - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = *(asPWORD*)&m_regs.valueRegister; - l_bc++; - break; - - case asBC_STR: - { - // Get the string id from the argument - asWORD w = asBC_WORDARG0(l_bc); - // Push the string pointer on the stack - const asCString &b = m_engine->GetConstantString(w); - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = (asPWORD)b.AddressOf(); - // Push the string length on the stack - --l_sp; - *l_sp = (asDWORD)b.GetLength(); - l_bc++; - } - break; - - case asBC_CALLSYS: - { - // Get function ID from the argument - int i = asBC_INTARG(l_bc); - - // Need to move the values back to the context as the called functions - // may use the debug interface to inspect the registers - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - l_sp += CallSystemFunction(i, this, 0); - - // Update the program position after the call so that line number is correct - l_bc += 2; - - if( m_regs.doProcessSuspend ) - { - // Should the execution be suspended? - if( m_doSuspend ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - m_status = asEXECUTION_SUSPENDED; - return; - } - // An exception might have been raised - if( m_status != asEXECUTION_ACTIVE ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - return; - } - } - } - break; - - case asBC_CALLBND: - { - // TODO: Clean-up: This code is very similar to asBC_CallPtr. Create a shared method for them - // Get the function ID from the stack - int i = asBC_INTARG(l_bc); - - asASSERT( i >= 0 ); - asASSERT( i & FUNC_IMPORTED ); - - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - int funcId = m_engine->importedFunctions[i & ~FUNC_IMPORTED]->boundFunctionId; - if( funcId == -1 ) - { - // Need to update the program pointer for the exception handler - m_regs.programPointer += 2; - - // Tell the exception handler to clean up the arguments to this function - m_needToCleanupArgs = true; - SetInternalException(TXT_UNBOUND_FUNCTION); - return; - } - else - { - asCScriptFunction *func = m_engine->GetScriptFunction(funcId); - if( func->funcType == asFUNC_SCRIPT ) - { - m_regs.programPointer += 2; - CallScriptFunction(func); - } - else if( func->funcType == asFUNC_DELEGATE ) - { - // Push the object pointer on the stack. There is always a reserved space for this so - // we don't don't need to worry about overflowing the allocated memory buffer - asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] ); - m_regs.stackPointer -= AS_PTR_SIZE; - *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate); - - // Call the delegated method - if( func->funcForDelegate->funcType == asFUNC_SYSTEM ) - { - m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this, 0); - - // Update program position after the call so the line number - // is correct in case the system function queries it - m_regs.programPointer += 2; - } - else - { - m_regs.programPointer += 2; - - // TODO: run-time optimize: The true method could be figured out when creating the delegate - CallInterfaceMethod(func->funcForDelegate); - } - } - else - { - asASSERT( func->funcType == asFUNC_SYSTEM ); - - m_regs.stackPointer += CallSystemFunction(func->id, this, 0); - - // Update program position after the call so the line number - // is correct in case the system function queries it - m_regs.programPointer += 2; - } - } - - // Extract the values from the context again - l_bc = m_regs.programPointer; - l_sp = m_regs.stackPointer; - l_fp = m_regs.stackFramePointer; - - // If status isn't active anymore then we must stop - if( m_status != asEXECUTION_ACTIVE ) - return; - } - break; - - case asBC_SUSPEND: - if( m_regs.doProcessSuspend ) - { - if( m_lineCallback ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - CallLineCallback(); - } - if( m_doSuspend ) - { - l_bc++; - - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - m_status = asEXECUTION_SUSPENDED; - return; - } - } - - l_bc++; - break; - - case asBC_ALLOC: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc); - int func = asBC_INTARG(l_bc+AS_PTR_SIZE); - - if( objType->flags & asOBJ_SCRIPT_OBJECT ) - { - // Need to move the values back to the context as the construction - // of the script object may reuse the context for nested calls. - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Pre-allocate the memory - asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType); - - // Pre-initialize the memory by calling the constructor for asCScriptObject - ScriptObject_Construct(objType, (asCScriptObject*)mem); - - // Call the constructor to initalize the memory - asCScriptFunction *f = m_engine->scriptFunctions[func]; - - asDWORD **a = (asDWORD**)*(asPWORD*)(m_regs.stackPointer + f->GetSpaceNeededForArguments()); - if( a ) *a = mem; - - // Push the object pointer on the stack - m_regs.stackPointer -= AS_PTR_SIZE; - *(asPWORD*)m_regs.stackPointer = (asPWORD)mem; - - m_regs.programPointer += 2+AS_PTR_SIZE; - - CallScriptFunction(f); - - // Extract the values from the context again - l_bc = m_regs.programPointer; - l_sp = m_regs.stackPointer; - l_fp = m_regs.stackFramePointer; - - // If status isn't active anymore then we must stop - if( m_status != asEXECUTION_ACTIVE ) - return; - } - else - { - // Pre-allocate the memory - asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType); - - if( func ) - { - // Need to move the values back to the context as the called functions - // may use the debug interface to inspect the registers - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - l_sp += CallSystemFunction(func, this, mem); - } - - // Pop the variable address from the stack - asDWORD **a = (asDWORD**)*(asPWORD*)l_sp; - l_sp += AS_PTR_SIZE; - if( a ) *a = mem; - - l_bc += 2+AS_PTR_SIZE; - - if( m_regs.doProcessSuspend ) - { - // Should the execution be suspended? - if( m_doSuspend ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - m_status = asEXECUTION_SUSPENDED; - return; - } - // An exception might have been raised - if( m_status != asEXECUTION_ACTIVE ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - m_engine->CallFree(mem); - *a = 0; - - return; - } - } - } - } - break; - - case asBC_FREE: - { - // Get the variable that holds the object handle/reference - asPWORD *a = (asPWORD*)asPWORD(l_fp - asBC_SWORDARG0(l_bc)); - if( *a ) - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc); - asSTypeBehaviour *beh = &objType->beh; - - // Need to move the values back to the context as the called functions - // may use the debug interface to inspect the registers - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - if( objType->flags & asOBJ_REF ) - { - asASSERT( (objType->flags & asOBJ_NOCOUNT) || beh->release ); - if( beh->release ) - m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->release); - } - else - { - if( beh->destruct ) - m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->destruct); - else if( objType->flags & asOBJ_LIST_PATTERN ) - m_engine->DestroyList((asBYTE*)(asPWORD)*a, objType); - - m_engine->CallFree((void*)(asPWORD)*a); - } - - // Clear the variable - *a = 0; - } - } - l_bc += 1+AS_PTR_SIZE; - break; - - case asBC_LOADOBJ: - { - // Move the object pointer from the object variable into the object register - void **a = (void**)(l_fp - asBC_SWORDARG0(l_bc)); - m_regs.objectType = 0; - m_regs.objectRegister = *a; - *a = 0; - } - l_bc++; - break; - - case asBC_STOREOBJ: - // Move the object pointer from the object register to the object variable - *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asPWORD(m_regs.objectRegister); - m_regs.objectRegister = 0; - l_bc++; - break; - - case asBC_GETOBJ: - { - // Read variable index from location on stack - asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); - asDWORD offset = *(asDWORD*)a; - // Move pointer from variable to the same location on the stack - asPWORD *v = (asPWORD*)(l_fp - offset); - *a = *v; - // Clear variable - *v = 0; - } - l_bc++; - break; - - case asBC_REFCPY: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc); - asSTypeBehaviour *beh = &objType->beh; - - // Pop address of destination pointer from the stack - void **d = (void**)*(asPWORD*)l_sp; - l_sp += AS_PTR_SIZE; - - // Read wanted pointer from the stack - void *s = (void*)*(asPWORD*)l_sp; - - // Need to move the values back to the context as the called functions - // may use the debug interface to inspect the registers - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - if( !(objType->flags & asOBJ_NOCOUNT) ) - { - // Release previous object held by destination pointer - if( *d != 0 ) - m_engine->CallObjectMethod(*d, beh->release); - // Increase ref counter of wanted object - if( s != 0 ) - m_engine->CallObjectMethod(s, beh->addref); - } - - // Set the new object in the destination - *d = s; - } - l_bc += 1+AS_PTR_SIZE; - break; - - case asBC_CHKREF: - { - // Verify if the pointer on the stack is null - // This is used when validating a pointer that an operator will work on - asPWORD a = *(asPWORD*)l_sp; - if( a == 0 ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - } - l_bc++; - break; - - case asBC_GETOBJREF: - { - // Get the location on the stack where the reference will be placed - asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); - - // Replace the variable index with the object handle held in the variable - *(asPWORD**)a = *(asPWORD**)(l_fp - *a); - } - l_bc++; - break; - - case asBC_GETREF: - { - // Get the location on the stack where the reference will be placed - asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); - - // Replace the variable index with the address of the variable - *(asPWORD**)a = (asPWORD*)(l_fp - (int)*a); - } - l_bc++; - break; - - case asBC_PshNull: - // Push a null pointer on the stack - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = 0; - l_bc++; - break; - - case asBC_ClrVPtr: - // TODO: runtime optimize: Is this instruction really necessary? - // CallScriptFunction() can clear the null handles upon entry, just as is done for - // all other object variables - // Clear pointer variable - *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = 0; - l_bc++; - break; - - case asBC_OBJTYPE: - // Push the object type on the stack - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = asBC_PTRARG(l_bc); - l_bc += 1+AS_PTR_SIZE; - break; - - case asBC_TYPEID: - // Equivalent to PshC4, but kept as separate instruction for bytecode serialization - --l_sp; - *l_sp = asBC_DWORDARG(l_bc); - l_bc += 2; - break; - - case asBC_SetV4: - *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc); - l_bc += 2; - break; - - case asBC_SetV8: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asBC_QWORDARG(l_bc); - l_bc += 3; - break; - - case asBC_ADDSi: - { - // The pointer must not be null - asPWORD a = *(asPWORD*)l_sp; - if( a == 0 ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - // Add an offset to the pointer - *(asPWORD*)l_sp = a + asBC_SWORDARG0(l_bc); - } - l_bc += 2; - break; - - case asBC_CpyVtoV4: - *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)); - l_bc += 2; - break; - - case asBC_CpyVtoV8: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)); - l_bc += 2; - break; - - case asBC_CpyVtoR4: - *(asDWORD*)&m_regs.valueRegister = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_CpyVtoR8: - *(asQWORD*)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_CpyVtoG4: - *(asDWORD*)asBC_PTRARG(l_bc) = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc += 1 + AS_PTR_SIZE; - break; - - case asBC_CpyRtoV4: - *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)&m_regs.valueRegister; - l_bc++; - break; - - case asBC_CpyRtoV8: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = m_regs.valueRegister; - l_bc++; - break; - - case asBC_CpyGtoV4: - *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)asBC_PTRARG(l_bc); - l_bc += 1 + AS_PTR_SIZE; - break; - - case asBC_WRTV1: - // The pointer in the register points to a byte, and *(l_fp - offset) too - **(asBYTE**)&m_regs.valueRegister = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_WRTV2: - // The pointer in the register points to a word, and *(l_fp - offset) too - **(asWORD**)&m_regs.valueRegister = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_WRTV4: - **(asDWORD**)&m_regs.valueRegister = *(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_WRTV8: - **(asQWORD**)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_RDR1: - { - // The pointer in the register points to a byte, and *(l_fp - offset) will also point to a byte - asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); - bPtr[0] = **(asBYTE**)&m_regs.valueRegister; // read the byte - bPtr[1] = 0; // 0 the rest of the DWORD - bPtr[2] = 0; - bPtr[3] = 0; - } - l_bc++; - break; - - case asBC_RDR2: - { - // The pointer in the register points to a word, and *(l_fp - offset) will also point to a word - asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - wPtr[0] = **(asWORD**)&m_regs.valueRegister; // read the word - wPtr[1] = 0; // 0 the rest of the DWORD - } - l_bc++; - break; - - case asBC_RDR4: - *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister; - l_bc++; - break; - - case asBC_RDR8: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asQWORD**)&m_regs.valueRegister; - l_bc++; - break; - - case asBC_LDG: - *(asPWORD*)&m_regs.valueRegister = asBC_PTRARG(l_bc); - l_bc += 1+AS_PTR_SIZE; - break; - - case asBC_LDV: - *(asDWORD**)&m_regs.valueRegister = (l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_PGA: - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = asBC_PTRARG(l_bc); - l_bc += 1+AS_PTR_SIZE; - break; - - case asBC_CmpPtr: - { - // TODO: runtime optimize: This instruction should really just be an equals, and return true or false. - // The instruction is only used for is and !is tests anyway. - asPWORD p1 = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - asPWORD p2 = *(asPWORD*)(l_fp - asBC_SWORDARG1(l_bc)); - if( p1 == p2 ) *(int*)&m_regs.valueRegister = 0; - else if( p1 < p2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_VAR: - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = (asPWORD)asBC_SWORDARG0(l_bc); - l_bc++; - break; - - //---------------------------- - // Type conversions - case asBC_iTOf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(int*)(l_fp - asBC_SWORDARG0(l_bc))); - l_bc++; - break; - - case asBC_fTOi: - *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(float*)(l_fp - asBC_SWORDARG0(l_bc))); - l_bc++; - break; - - case asBC_uTOf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(l_fp - asBC_SWORDARG0(l_bc))); - l_bc++; - break; - - case asBC_fTOu: - // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0 - *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(float*)(l_fp - asBC_SWORDARG0(l_bc)))); - l_bc++; - break; - - case asBC_sbTOi: - // *(l_fp - offset) points to a char, and will point to an int afterwards - *(l_fp - asBC_SWORDARG0(l_bc)) = *(signed char*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_swTOi: - // *(l_fp - offset) points to a short, and will point to an int afterwards - *(l_fp - asBC_SWORDARG0(l_bc)) = *(short*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_ubTOi: - // (l_fp - offset) points to a byte, and will point to an int afterwards - *(l_fp - asBC_SWORDARG0(l_bc)) = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_uwTOi: - // *(l_fp - offset) points to a word, and will point to an int afterwards - *(l_fp - asBC_SWORDARG0(l_bc)) = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_dTOi: - *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(double*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_dTOu: - // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0 - *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(double*)(l_fp - asBC_SWORDARG1(l_bc)))); - l_bc += 2; - break; - - case asBC_dTOf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(double*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_iTOd: - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(int*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_uTOd: - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_fTOd: - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(float*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - //------------------------------ - // Math operations - case asBC_ADDi: - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + *(int*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_SUBi: - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - *(int*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_MULi: - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * *(int*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_DIVi: - { - int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - else if( divider == -1 ) - { - // Need to check if the value that is divided is 0x80000000 - // as dividing it with -1 will cause an overflow exception - if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_OVERFLOW); - return; - } - } - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; - } - l_bc += 2; - break; - - case asBC_MODi: - { - int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - else if( divider == -1 ) - { - // Need to check if the value that is divided is 0x80000000 - // as dividing it with -1 will cause an overflow exception - if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_OVERFLOW); - return; - } - } - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) % divider; - } - l_bc += 2; - break; - - case asBC_ADDf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + *(float*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_SUBf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - *(float*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_MULf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * *(float*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_DIVf: - { - float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; - } - l_bc += 2; - break; - - case asBC_MODf: - { - float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = fmodf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), divider); - } - l_bc += 2; - break; - - case asBC_ADDd: - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) + *(double*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_SUBd: - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) - *(double*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_MULd: - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) * *(double*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_DIVd: - { - double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; - l_bc += 2; - } - break; - - case asBC_MODd: - { - double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = fmod(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), divider); - l_bc += 2; - } - break; - - //------------------------------ - // Math operations with constant value - case asBC_ADDIi: - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_INTARG(l_bc+1); - l_bc += 3; - break; - - case asBC_SUBIi: - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_INTARG(l_bc+1); - l_bc += 3; - break; - - case asBC_MULIi: - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_INTARG(l_bc+1); - l_bc += 3; - break; - - case asBC_ADDIf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_FLOATARG(l_bc+1); - l_bc += 3; - break; - - case asBC_SUBIf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_FLOATARG(l_bc+1); - l_bc += 3; - break; - - case asBC_MULIf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_FLOATARG(l_bc+1); - l_bc += 3; - break; - - //----------------------------------- - case asBC_SetG4: - *(asDWORD*)asBC_PTRARG(l_bc) = asBC_DWORDARG(l_bc+AS_PTR_SIZE); - l_bc += 2 + AS_PTR_SIZE; - break; - - case asBC_ChkRefS: - { - // Verify if the pointer on the stack refers to a non-null value - // This is used to validate a reference to a handle - asPWORD *a = (asPWORD*)*(asPWORD*)l_sp; - if( *a == 0 ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - } - l_bc++; - break; - - case asBC_ChkNullV: - { - // Verify if variable (on the stack) is not null - asDWORD *a = *(asDWORD**)(l_fp - asBC_SWORDARG0(l_bc)); - if( a == 0 ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - } - l_bc++; - break; - - case asBC_CALLINTF: - { - int i = asBC_INTARG(l_bc); - l_bc += 2; - - asASSERT( i >= 0 ); - asASSERT( (i & FUNC_IMPORTED) == 0 ); - - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - CallInterfaceMethod(m_engine->GetScriptFunction(i)); - - // Extract the values from the context again - l_bc = m_regs.programPointer; - l_sp = m_regs.stackPointer; - l_fp = m_regs.stackFramePointer; - - // If status isn't active anymore then we must stop - if( m_status != asEXECUTION_ACTIVE ) - return; - } - break; - - case asBC_iTOb: - { - // *(l_fp - offset) points to an int, and will point to a byte afterwards - - // We need to use volatile here to tell the compiler not to rearrange - // read and write operations during optimizations. - volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc)); - volatile asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); - bPtr[0] = (asBYTE)val; // write the byte - bPtr[1] = 0; // 0 the rest of the DWORD - bPtr[2] = 0; - bPtr[3] = 0; - } - l_bc++; - break; - - case asBC_iTOw: - { - // *(l_fp - offset) points to an int, and will point to word afterwards - - // We need to use volatile here to tell the compiler not to rearrange - // read and write operations during optimizations. - volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc)); - volatile asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - wPtr[0] = (asWORD)val; // write the word - wPtr[1] = 0; // 0 the rest of the DWORD - } - l_bc++; - break; - - case asBC_SetV1: - // TODO: This is exactly the same as SetV4. This is a left over from the time - // when the bytecode instructions were more tightly packed. It can now - // be removed. When removing it, make sure the value is correctly converted - // on big-endian CPUs. - - // The byte is already stored correctly in the argument - *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc); - l_bc += 2; - break; - - case asBC_SetV2: - // TODO: This is exactly the same as SetV4. This is a left over from the time - // when the bytecode instructions were more tightly packed. It can now - // be removed. When removing it, make sure the value is correctly converted - // on big-endian CPUs. - - // The word is already stored correctly in the argument - *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc); - l_bc += 2; - break; - - case asBC_Cast: - // Cast the handle at the top of the stack to the type in the argument - { - asDWORD **a = (asDWORD**)*(asPWORD*)l_sp; - if( a && *a ) - { - asDWORD typeId = asBC_DWORDARG(l_bc); - - asCScriptObject *obj = (asCScriptObject *)* a; - asCObjectType *objType = obj->objType; - asCObjectType *to = m_engine->GetObjectTypeFromTypeId(typeId); - - // This instruction can only be used with script classes and interfaces - asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT ); - asASSERT( to->flags & asOBJ_SCRIPT_OBJECT ); - - if( objType->Implements(to) || objType->DerivesFrom(to) ) - { - m_regs.objectType = 0; - m_regs.objectRegister = obj; - obj->AddRef(); - } - else - { - // The object register should already be null, so there - // is no need to clear it if the cast is unsuccessful - asASSERT( m_regs.objectRegister == 0 ); - } - } - l_sp += AS_PTR_SIZE; - } - l_bc += 2; - break; - - case asBC_i64TOi: - *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_uTOi64: - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_iTOi64: - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(int*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_fTOi64: - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_dTOi64: - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc))); - l_bc++; - break; - - case asBC_fTOu64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc)))); - l_bc += 2; - break; - - case asBC_dTOu64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc)))); - l_bc++; - break; - - case asBC_i64TOf: - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc))); - l_bc += 2; - break; - - case asBC_u64TOf: -#if _MSC_VER <= 1200 // MSVC6 - { - // MSVC6 doesn't permit UINT64 to double - asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)); - if( v < 0 ) - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0f+float(v); - else - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(v); - } -#else - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc))); -#endif - l_bc += 2; - break; - - case asBC_i64TOd: - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc))); - l_bc++; - break; - - case asBC_u64TOd: -#if _MSC_VER <= 1200 // MSVC6 - { - // MSVC6 doesn't permit UINT64 to double - asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)); - if( v < 0 ) - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0+double(v); - else - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(v); - } -#else - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc))); -#endif - l_bc++; - break; - - case asBC_NEGi64: - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_INCi64: - ++(**(asQWORD**)&m_regs.valueRegister); - l_bc++; - break; - - case asBC_DECi64: - --(**(asQWORD**)&m_regs.valueRegister); - l_bc++; - break; - - case asBC_BNOT64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = ~*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_ADDi64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) + *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_SUBi64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) - *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_MULi64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) * *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_DIVi64: - { - asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - else if( divider == -1 ) - { - // Need to check if the value that is divided is 1<<63 - // as dividing it with -1 will cause an overflow exception - if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_OVERFLOW); - return; - } - } - - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; - } - l_bc += 2; - break; - - case asBC_MODi64: - { - asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - else if( divider == -1 ) - { - // Need to check if the value that is divided is 1<<63 - // as dividing it with -1 will cause an overflow exception - if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_OVERFLOW); - return; - } - } - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) % divider; - } - l_bc += 2; - break; - - case asBC_BAND64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) & *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_BOR64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) | *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_BXOR64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) ^ *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_BSLL64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_BSRL64: - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_BSRA64: - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc)); - l_bc += 2; - break; - - case asBC_CMPi64: - { - asINT64 i1 = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)); - asINT64 i2 = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)); - if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0; - else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_CMPu64: - { - asQWORD d1 = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - asQWORD d2 = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)); - if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0; - else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1; - else *(int*)&m_regs.valueRegister = 1; - l_bc += 2; - } - break; - - case asBC_ChkNullS: - { - // Verify if the pointer on the stack is null - // This is used for example when validating handles passed as function arguments - asPWORD a = *(asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); - if( a == 0 ) - { - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - } - l_bc++; - break; - - case asBC_ClrHi: -#if AS_SIZEOF_BOOL == 1 - { - // Clear the upper bytes, so that trash data don't interfere with boolean operations - - // We need to use volatile here to tell the compiler it cannot - // change the order of read and write operations on the pointer. - - volatile asBYTE *ptr = (asBYTE*)&m_regs.valueRegister; - ptr[1] = 0; // The boolean value is stored in the lower byte, so we clear the rest - ptr[2] = 0; - ptr[3] = 0; - } -#else - // We don't have anything to do here -#endif - l_bc++; - break; - - case asBC_JitEntry: - { - if( m_currentFunction->scriptData->jitFunction ) - { - asPWORD jitArg = asBC_PTRARG(l_bc); - - if( jitArg ) - { - // Resume JIT operation - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - (m_currentFunction->scriptData->jitFunction)(&m_regs, jitArg); - - l_bc = m_regs.programPointer; - l_sp = m_regs.stackPointer; - l_fp = m_regs.stackFramePointer; - - // If status isn't active anymore then we must stop - if( m_status != asEXECUTION_ACTIVE ) - return; - - break; - } - } - - // Not a JIT resume point, treat as nop - l_bc += 1+AS_PTR_SIZE; - } - break; - - case asBC_CallPtr: - { - // Get the function pointer from the local variable - asCScriptFunction *func = *(asCScriptFunction**)(l_fp - asBC_SWORDARG0(l_bc)); - - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - if( func == 0 ) - { - // Need to update the program pointer anyway for the exception handler - m_regs.programPointer++; - - // Tell the exception handler to clean up the arguments to this method - m_needToCleanupArgs = true; - - // TODO: funcdef: Should we have a different exception string? - SetInternalException(TXT_UNBOUND_FUNCTION); - return; - } - else - { - if( func->funcType == asFUNC_SCRIPT ) - { - m_regs.programPointer++; - CallScriptFunction(func); - } - else if( func->funcType == asFUNC_DELEGATE ) - { - // Push the object pointer on the stack. There is always a reserved space for this so - // we don't don't need to worry about overflowing the allocated memory buffer - asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] ); - m_regs.stackPointer -= AS_PTR_SIZE; - *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate); - - // Call the delegated method - if( func->funcForDelegate->funcType == asFUNC_SYSTEM ) - { - m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this, 0); - - // Update program position after the call so the line number - // is correct in case the system function queries it - m_regs.programPointer++; - } - else - { - m_regs.programPointer++; - - // TODO: run-time optimize: The true method could be figured out when creating the delegate - CallInterfaceMethod(func->funcForDelegate); - } - } - else - { - asASSERT( func->funcType == asFUNC_SYSTEM ); - - m_regs.stackPointer += CallSystemFunction(func->id, this, 0); - - // Update program position after the call so the line number - // is correct in case the system function queries it - m_regs.programPointer++; - } - } - - // Extract the values from the context again - l_bc = m_regs.programPointer; - l_sp = m_regs.stackPointer; - l_fp = m_regs.stackFramePointer; - - // If status isn't active anymore then we must stop - if( m_status != asEXECUTION_ACTIVE ) - return; - } - break; - - case asBC_FuncPtr: - // Push the function pointer on the stack. The pointer is in the argument - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = asBC_PTRARG(l_bc); - l_bc += 1+AS_PTR_SIZE; - break; - - case asBC_LoadThisR: - { - // PshVPtr 0 - asPWORD tmp = *(asPWORD*)l_fp; - - // Make sure the pointer is not null - if( tmp == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - - // ADDSi - tmp = tmp + asBC_SWORDARG0(l_bc); - - // PopRPtr - *(asPWORD*)&m_regs.valueRegister = tmp; - l_bc += 2; - } - break; - - // Push the qword value of a variable on the stack - case asBC_PshV8: - l_sp -= 2; - *(asQWORD*)l_sp = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - l_bc++; - break; - - case asBC_DIVu: - { - asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - *(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; - } - l_bc += 2; - break; - - case asBC_MODu: - { - asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - *(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) % divider; - } - l_bc += 2; - break; - - case asBC_DIVu64: - { - asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; - } - l_bc += 2; - break; - - case asBC_MODu64: - { - asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); - if( divider == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_DIVIDE_BY_ZERO); - return; - } - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) % divider; - } - l_bc += 2; - break; - - case asBC_LoadRObjR: - { - // PshVPtr x - asPWORD tmp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)); - - // Make sure the pointer is not null - if( tmp == 0 ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_NULL_POINTER_ACCESS); - return; - } - - // ADDSi y - tmp = tmp + asBC_SWORDARG1(l_bc); - - // PopRPtr - *(asPWORD*)&m_regs.valueRegister = tmp; - l_bc += 3; - } - break; - - case asBC_LoadVObjR: - { - // PSF x - asPWORD tmp = (asPWORD)(l_fp - asBC_SWORDARG0(l_bc)); - - // ADDSi y - tmp = tmp + asBC_SWORDARG1(l_bc); - - // PopRPtr - *(asPWORD*)&m_regs.valueRegister = tmp; - l_bc += 3; - } - break; - - case asBC_RefCpyV: - // Same as PSF v, REFCPY - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc); - asSTypeBehaviour *beh = &objType->beh; - - // Determine destination from argument - void **d = (void**)asPWORD(l_fp - asBC_SWORDARG0(l_bc)); - - // Read wanted pointer from the stack - void *s = (void*)*(asPWORD*)l_sp; - - // Need to move the values back to the context as the called functions - // may use the debug interface to inspect the registers - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - if( !(objType->flags & asOBJ_NOCOUNT) ) - { - // Release previous object held by destination pointer - if( *d != 0 ) - m_engine->CallObjectMethod(*d, beh->release); - // Increase ref counter of wanted object - if( s != 0 ) - m_engine->CallObjectMethod(s, beh->addref); - } - - // Set the new object in the destination - *d = s; - } - l_bc += 1+AS_PTR_SIZE; - break; - - case asBC_JLowZ: - if( *(asBYTE*)&m_regs.valueRegister == 0 ) - l_bc += asBC_INTARG(l_bc) + 2; - else - l_bc += 2; - break; - - case asBC_JLowNZ: - if( *(asBYTE*)&m_regs.valueRegister != 0 ) - l_bc += asBC_INTARG(l_bc) + 2; - else - l_bc += 2; - break; - - case asBC_AllocMem: - // Allocate a buffer and store the pointer in the local variable - { - // TODO: runtime optimize: As the list buffers are going to be short lived, it may be interesting - // to use a memory pool to avoid reallocating the memory all the time - - asUINT size = asBC_DWORDARG(l_bc); - asBYTE **var = (asBYTE**)(l_fp - asBC_SWORDARG0(l_bc)); -#ifndef WIP_16BYTE_ALIGN - *var = asNEWARRAY(asBYTE, size); -#else - *var = asNEWARRAYALIGNED(asBYTE, size, MAX_TYPE_ALIGNMENT); -#endif - - // Clear the buffer for the pointers that will be placed in it - memset(*var, 0, size); - } - l_bc += 2; - break; - - case asBC_SetListSize: - { - // Set the size element in the buffer - asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc)); - asUINT off = asBC_DWORDARG(l_bc); - asUINT size = asBC_DWORDARG(l_bc+1); - - asASSERT( var ); - - *(asUINT*)(var+off) = size; - } - l_bc += 3; - break; - - case asBC_PshListElmnt: - { - // Push the pointer to the list element on the stack - // In essence it does the same as PSF, RDSPtr, ADDSi - asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc)); - asUINT off = asBC_DWORDARG(l_bc); - - asASSERT( var ); - - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = asPWORD(var+off); - } - l_bc += 2; - break; - - case asBC_SetListType: - { - // Set the type id in the buffer - asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc)); - asUINT off = asBC_DWORDARG(l_bc); - asUINT type = asBC_DWORDARG(l_bc+1); - - asASSERT( var ); - - *(asUINT*)(var+off) = type; - } - l_bc += 3; - break; - - //------------------------------ - // Exponent operations - case asBC_POWi: - { - bool isOverflow; - *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powi(*(int*)(l_fp - asBC_SWORDARG1(l_bc)), *(int*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow); - if( isOverflow ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_POW_OVERFLOW); - return; - } - } - l_bc += 2; - break; - - case asBC_POWu: - { - bool isOverflow; - *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powu(*(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc)), *(asDWORD*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow); - if( isOverflow ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_POW_OVERFLOW); - return; - } - } - l_bc += 2; - break; - - case asBC_POWf: - { - float r = powf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), *(float*)(l_fp - asBC_SWORDARG2(l_bc))); - *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = r; - if( r == float(HUGE_VAL) ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_POW_OVERFLOW); - return; - } - } - l_bc += 2; - break; - - case asBC_POWd: - { - double r = pow(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), *(double*)(l_fp - asBC_SWORDARG2(l_bc))); - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = r; - if( r == HUGE_VAL ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_POW_OVERFLOW); - return; - } - } - l_bc += 2; - break; - - case asBC_POWdi: - { - double r = pow(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), *(int*)(l_fp - asBC_SWORDARG2(l_bc))); - *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = r; - if( r == HUGE_VAL ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_POW_OVERFLOW); - return; - } - l_bc += 2; - } - break; - - case asBC_POWi64: - { - bool isOverflow; - *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powi64(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)), *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow); - if( isOverflow ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_POW_OVERFLOW); - return; - } - } - l_bc += 2; - break; - - case asBC_POWu64: - { - bool isOverflow; - *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powu64(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)), *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow); - if( isOverflow ) - { - // Need to move the values back to the context - m_regs.programPointer = l_bc; - m_regs.stackPointer = l_sp; - m_regs.stackFramePointer = l_fp; - - // Raise exception - SetInternalException(TXT_POW_OVERFLOW); - return; - } - } - l_bc += 2; - break; - - // Don't let the optimizer optimize for size, - // since it requires extra conditions and jumps - case 201: l_bc = (asDWORD*)201; break; - case 202: l_bc = (asDWORD*)202; break; - case 203: l_bc = (asDWORD*)203; break; - case 204: l_bc = (asDWORD*)204; break; - case 205: l_bc = (asDWORD*)205; break; - case 206: l_bc = (asDWORD*)206; break; - case 207: l_bc = (asDWORD*)207; break; - case 208: l_bc = (asDWORD*)208; break; - case 209: l_bc = (asDWORD*)209; break; - case 210: l_bc = (asDWORD*)210; break; - case 211: l_bc = (asDWORD*)211; break; - case 212: l_bc = (asDWORD*)212; break; - case 213: l_bc = (asDWORD*)213; break; - case 214: l_bc = (asDWORD*)214; break; - case 215: l_bc = (asDWORD*)215; break; - case 216: l_bc = (asDWORD*)216; break; - case 217: l_bc = (asDWORD*)217; break; - case 218: l_bc = (asDWORD*)218; break; - case 219: l_bc = (asDWORD*)219; break; - case 220: l_bc = (asDWORD*)220; break; - case 221: l_bc = (asDWORD*)221; break; - case 222: l_bc = (asDWORD*)222; break; - case 223: l_bc = (asDWORD*)223; break; - case 224: l_bc = (asDWORD*)224; break; - case 225: l_bc = (asDWORD*)225; break; - case 226: l_bc = (asDWORD*)226; break; - case 227: l_bc = (asDWORD*)227; break; - case 228: l_bc = (asDWORD*)228; break; - case 229: l_bc = (asDWORD*)229; break; - case 230: l_bc = (asDWORD*)230; break; - case 231: l_bc = (asDWORD*)231; break; - case 232: l_bc = (asDWORD*)232; break; - case 233: l_bc = (asDWORD*)233; break; - case 234: l_bc = (asDWORD*)234; break; - case 235: l_bc = (asDWORD*)235; break; - case 236: l_bc = (asDWORD*)236; break; - case 237: l_bc = (asDWORD*)237; break; - case 238: l_bc = (asDWORD*)238; break; - case 239: l_bc = (asDWORD*)239; break; - case 240: l_bc = (asDWORD*)240; break; - case 241: l_bc = (asDWORD*)241; break; - case 242: l_bc = (asDWORD*)242; break; - case 243: l_bc = (asDWORD*)243; break; - case 244: l_bc = (asDWORD*)244; break; - case 245: l_bc = (asDWORD*)245; break; - case 246: l_bc = (asDWORD*)246; break; - case 247: l_bc = (asDWORD*)247; break; - case 248: l_bc = (asDWORD*)248; break; - case 249: l_bc = (asDWORD*)249; break; - case 250: l_bc = (asDWORD*)250; break; - case 251: l_bc = (asDWORD*)251; break; - case 252: l_bc = (asDWORD*)252; break; - case 253: l_bc = (asDWORD*)253; break; - case 254: l_bc = (asDWORD*)254; break; - case 255: l_bc = (asDWORD*)255; break; - -#ifdef AS_DEBUG - default: - asASSERT(false); - SetInternalException(TXT_UNRECOGNIZED_BYTE_CODE); -#endif -#if defined(_MSC_VER) && !defined(AS_DEBUG) - default: - // This Microsoft specific code allows the - // compiler to optimize the switch case as - // it will know that the code will never - // reach this point - __assume(0); -#endif - } - -#ifdef AS_DEBUG - asDWORD instr = *(asBYTE*)old; - if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) && instr != asBC_JLowZ && instr != asBC_JLowNZ && - instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr && - instr != asBC_JitEntry ) - { - asASSERT( (l_bc - old) == asBCTypeSize[asBCInfo[instr].type] ); - } -#endif - } -} - -int asCContext::SetException(const char *descr) -{ - // Only allow this if we're executing a CALL byte code - if( m_callingSystemFunction == 0 ) return asERROR; - - SetInternalException(descr); - - return 0; -} - -void asCContext::SetInternalException(const char *descr) -{ - if( m_inExceptionHandler ) - { - asASSERT(false); // Shouldn't happen - return; // but if it does, at least this will not crash the application - } - - m_status = asEXECUTION_EXCEPTION; - m_regs.doProcessSuspend = true; - - m_exceptionString = descr; - m_exceptionFunction = m_currentFunction->id; - - if( m_currentFunction->scriptData ) - { - m_exceptionLine = m_currentFunction->GetLineNumber(int(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()), &m_exceptionSectionIdx); - m_exceptionColumn = m_exceptionLine >> 20; - m_exceptionLine &= 0xFFFFF; - } - else - { - m_exceptionSectionIdx = 0; - m_exceptionLine = 0; - m_exceptionColumn = 0; - } - - if( m_exceptionCallback ) - CallExceptionCallback(); -} - -void asCContext::CleanReturnObject() -{ - if( m_initialFunction && m_initialFunction->DoesReturnOnStack() && m_status == asEXECUTION_FINISHED ) - { - // If function returns on stack we need to call the destructor on the returned object - if( m_initialFunction->returnType.GetObjectType()->beh.destruct ) - m_engine->CallObjectMethod(GetReturnObject(), m_initialFunction->returnType.GetObjectType()->beh.destruct); - - return; - } - - if( m_regs.objectRegister == 0 ) return; - - asASSERT( m_regs.objectType != 0 ); - - if( m_regs.objectType ) - { - // Call the destructor on the object - asSTypeBehaviour *beh = &((asCObjectType*)m_regs.objectType)->beh; - if( m_regs.objectType->GetFlags() & asOBJ_REF ) - { - asASSERT( beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT) ); - - if( beh->release ) - m_engine->CallObjectMethod(m_regs.objectRegister, beh->release); - - m_regs.objectRegister = 0; - } - else - { - if( beh->destruct ) - m_engine->CallObjectMethod(m_regs.objectRegister, beh->destruct); - - // Free the memory - m_engine->CallFree(m_regs.objectRegister); - m_regs.objectRegister = 0; - } - } -} - -void asCContext::CleanStack() -{ - m_inExceptionHandler = true; - - // Run the clean up code for each of the functions called - CleanStackFrame(); - - // Set the status to exception so that the stack unwind is done correctly. - // This shouldn't be done for the current function, which is why we only - // do this after the first CleanStackFrame() is done. - m_status = asEXECUTION_EXCEPTION; - - while( m_callStack.GetLength() > 0 ) - { - // Only clean up until the top most marker for a nested call - asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; - if( s[0] == 0 ) - break; - - PopCallState(); - - CleanStackFrame(); - } - - m_inExceptionHandler = false; -} - -// Interface -bool asCContext::IsVarInScope(asUINT varIndex, asUINT stackLevel) -{ - // Don't return anything if there is no bytecode, e.g. before calling Execute() - if( m_regs.programPointer == 0 ) return false; - - if( stackLevel >= GetCallstackSize() ) return false; - - asCScriptFunction *func; - asUINT pos; - - if( stackLevel == 0 ) - { - func = m_currentFunction; - if( func->scriptData == 0 ) return false; - pos = asUINT(m_regs.programPointer - func->scriptData->byteCode.AddressOf()); - } - else - { - asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; - func = (asCScriptFunction*)s[1]; - if( func->scriptData == 0 ) return false; - pos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf()); - } - - // First determine if the program position is after the variable declaration - if( func->scriptData->variables.GetLength() <= varIndex ) return false; - if( func->scriptData->variables[varIndex]->declaredAtProgramPos > pos ) return false; - - asUINT declaredAt = func->scriptData->variables[varIndex]->declaredAtProgramPos; - - // If the program position is after the variable declaration it is necessary - // determine if the program position is still inside the statement block where - // the variable was delcared. - for( int n = 0; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ ) - { - if( func->scriptData->objVariableInfo[n].programPos >= declaredAt ) - { - // If the current block ends between the declaredAt and current - // program position, then we know the variable is no longer visible - int level = 0; - for( ; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ ) - { - if( func->scriptData->objVariableInfo[n].programPos > pos ) - break; - - if( func->scriptData->objVariableInfo[n].option == asBLOCK_BEGIN ) level++; - if( func->scriptData->objVariableInfo[n].option == asBLOCK_END && --level < 0 ) - return false; - } - - break; - } - } - - // Variable is visible - return true; -} - -// Internal -void asCContext::DetermineLiveObjects(asCArray &liveObjects, asUINT stackLevel) -{ - asASSERT( stackLevel < GetCallstackSize() ); - - asCScriptFunction *func; - asUINT pos; - - if( stackLevel == 0 ) - { - func = m_currentFunction; - if( func->scriptData == 0 ) - return; - - pos = asUINT(m_regs.programPointer - func->scriptData->byteCode.AddressOf()); - - if( m_status == asEXECUTION_EXCEPTION ) - { - // Don't consider the last instruction as executed, as it failed with an exception - // It's not actually necessary to decrease the exact size of the instruction. Just - // before the current position is enough to disconsider it. - pos--; - } - } - else - { - asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; - func = (asCScriptFunction*)s[1]; - if( func->scriptData == 0 ) - return; - - pos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf()); - - // Don't consider the last instruction as executed, as the function that was called by it - // is still being executed. If we consider it as executed already, then a value object - // returned by value would be considered alive, which it is not. - pos--; - } - - // Determine which object variables that are really live ones - liveObjects.SetLength(func->scriptData->objVariablePos.GetLength()); - memset(liveObjects.AddressOf(), 0, sizeof(int)*liveObjects.GetLength()); - for( int n = 0; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ ) - { - // Find the first variable info with a larger position than the current - // As the variable info are always placed on the instruction right after the - // one that initialized or freed the object, the current position needs to be - // considered as valid. - if( func->scriptData->objVariableInfo[n].programPos > pos ) - { - // We've determined how far the execution ran, now determine which variables are alive - for( --n; n >= 0; n-- ) - { - switch( func->scriptData->objVariableInfo[n].option ) - { - case asOBJ_UNINIT: // Object was destroyed - { - // TODO: optimize: This should have been done by the compiler already - // Which variable is this? - asUINT var = 0; - for( asUINT v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) - if( func->scriptData->objVariablePos[v] == func->scriptData->objVariableInfo[n].variableOffset ) - { - var = v; - break; - } - liveObjects[var] -= 1; - } - break; - case asOBJ_INIT: // Object was created - { - // Which variable is this? - asUINT var = 0; - for( asUINT v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) - if( func->scriptData->objVariablePos[v] == func->scriptData->objVariableInfo[n].variableOffset ) - { - var = v; - break; - } - liveObjects[var] += 1; - } - break; - case asBLOCK_BEGIN: // Start block - // We should ignore start blocks, since it just means the - // program was within the block when the exception ocurred - break; - case asBLOCK_END: // End block - // We need to skip the entire block, as the objects created - // and destroyed inside this block are already out of scope - { - int nested = 1; - while( nested > 0 ) - { - int option = func->scriptData->objVariableInfo[--n].option; - if( option == 3 ) - nested++; - if( option == 2 ) - nested--; - } - } - break; - } - } - - // We're done with the investigation - break; - } - } -} - -void asCContext::CleanArgsOnStack() -{ - if( !m_needToCleanupArgs ) - return; - - asASSERT( m_currentFunction->scriptData ); - - // Find the instruction just before the current program pointer - asDWORD *instr = m_currentFunction->scriptData->byteCode.AddressOf(); - asDWORD *prevInstr = 0; - while( instr < m_regs.programPointer ) - { - prevInstr = instr; - instr += asBCTypeSize[asBCInfo[*(asBYTE*)(instr)].type]; - } - - // Determine what function was being called - asCScriptFunction *func = 0; - asBYTE bc = *(asBYTE*)prevInstr; - if( bc == asBC_CALL || bc == asBC_CALLSYS || bc == asBC_CALLINTF ) - { - int funcId = asBC_INTARG(prevInstr); - func = m_engine->scriptFunctions[funcId]; - } - else if( bc == asBC_CALLBND ) - { - int funcId = asBC_INTARG(prevInstr); - func = m_engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature; - } - else if( bc == asBC_CallPtr ) - { - asUINT v; - int var = asBC_SWORDARG0(prevInstr); - - // Find the funcdef from the local variable - for( v = 0; v < m_currentFunction->scriptData->objVariablePos.GetLength(); v++ ) - if( m_currentFunction->scriptData->objVariablePos[v] == var ) - { - func = m_currentFunction->scriptData->funcVariableTypes[v]; - break; - } - - if( func == 0 ) - { - // Look in parameters - int paramPos = 0; - if( m_currentFunction->objectType ) - paramPos -= AS_PTR_SIZE; - if( m_currentFunction->DoesReturnOnStack() ) - paramPos -= AS_PTR_SIZE; - for( v = 0; v < m_currentFunction->parameterTypes.GetLength(); v++ ) - { - if( var == paramPos ) - { - func = m_currentFunction->parameterTypes[v].GetFuncDef(); - break; - } - paramPos -= m_currentFunction->parameterTypes[v].GetSizeOnStackDWords(); - } - } - } - else - asASSERT( false ); - - asASSERT( func ); - - // Clean parameters - int offset = 0; - if( func->objectType ) - offset += AS_PTR_SIZE; - if( func->DoesReturnOnStack() ) - offset += AS_PTR_SIZE; - for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( func->parameterTypes[n].IsObject() && !func->parameterTypes[n].IsReference() ) - { - if( *(asPWORD*)&m_regs.stackPointer[offset] ) - { - // Call the object's destructor - asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour(); - if( func->parameterTypes[n].GetObjectType()->flags & asOBJ_REF ) - { - asASSERT( (func->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release ); - - if( beh->release ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release); - *(asPWORD*)&m_regs.stackPointer[offset] = 0; - } - else - { - if( beh->destruct ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->destruct); - - // Free the memory - m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackPointer[offset]); - *(asPWORD*)&m_regs.stackPointer[offset] = 0; - } - } - } - - offset += func->parameterTypes[n].GetSizeOnStackDWords(); - } - - m_needToCleanupArgs = false; -} - -void asCContext::CleanStackFrame() -{ - // Clean object variables on the stack - // If the stack memory is not allocated or the program pointer - // is not set, then there is nothing to clean up on the stack frame - if( !m_isStackMemoryNotAllocated && m_regs.programPointer ) - { - // If the exception occurred while calling a function it is necessary - // to clean up the arguments that were put on the stack. - CleanArgsOnStack(); - - // Restore the stack pointer - asASSERT( m_currentFunction->scriptData ); - m_regs.stackPointer += m_currentFunction->scriptData->variableSpace; - - // Determine which object variables that are really live ones - asCArray liveObjects; - DetermineLiveObjects(liveObjects, 0); - - for( asUINT n = 0; n < m_currentFunction->scriptData->objVariablePos.GetLength(); n++ ) - { - int pos = m_currentFunction->scriptData->objVariablePos[n]; - if( n < m_currentFunction->scriptData->objVariablesOnHeap ) - { - // Check if the pointer is initialized - if( *(asPWORD*)&m_regs.stackFramePointer[-pos] ) - { - // Call the object's destructor - asSTypeBehaviour *beh = &m_currentFunction->scriptData->objVariableTypes[n]->beh; - if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_REF ) - { - asASSERT( (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_NOCOUNT) || beh->release ); - if( beh->release ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->release); - *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0; - } - else - { - if( beh->destruct ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); - else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_LIST_PATTERN ) - m_engine->DestroyList((asBYTE*)*(asPWORD*)&m_regs.stackFramePointer[-pos], m_currentFunction->scriptData->objVariableTypes[n]); - - // Free the memory - m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos]); - *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0; - } - } - } - else - { - asASSERT( m_currentFunction->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE ); - - // Only destroy the object if it is truly alive - if( liveObjects[n] > 0 ) - { - asSTypeBehaviour *beh = &m_currentFunction->scriptData->objVariableTypes[n]->beh; - if( beh->destruct ) - m_engine->CallObjectMethod((void*)(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); - } - } - } - } - else - m_isStackMemoryNotAllocated = false; - - // Functions that do not own the object and parameters shouldn't do any clean up - if( m_currentFunction->dontCleanUpOnException ) - return; - - // Clean object and parameters - int offset = 0; - if( m_currentFunction->objectType ) - offset += AS_PTR_SIZE; - if( m_currentFunction->DoesReturnOnStack() ) - offset += AS_PTR_SIZE; - for( asUINT n = 0; n < m_currentFunction->parameterTypes.GetLength(); n++ ) - { - if( m_currentFunction->parameterTypes[n].IsObject() && !m_currentFunction->parameterTypes[n].IsReference() ) - { - if( *(asPWORD*)&m_regs.stackFramePointer[offset] ) - { - // Call the object's destructor - asSTypeBehaviour *beh = m_currentFunction->parameterTypes[n].GetBehaviour(); - if( m_currentFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_REF ) - { - asASSERT( (m_currentFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release ); - - if( beh->release ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->release); - *(asPWORD*)&m_regs.stackFramePointer[offset] = 0; - } - else - { - if( beh->destruct ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->destruct); - - // Free the memory - m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[offset]); - *(asPWORD*)&m_regs.stackFramePointer[offset] = 0; - } - } - } - - offset += m_currentFunction->parameterTypes[n].GetSizeOnStackDWords(); - } -} - -// interface -int asCContext::GetExceptionLineNumber(int *column, const char **sectionName) -{ - if( GetState() != asEXECUTION_EXCEPTION ) return asERROR; - - if( column ) *column = m_exceptionColumn; - - if( sectionName ) - { - // The section index can be -1 if the exception was raised in a generated function, e.g. factstub for templates - if( m_exceptionSectionIdx >= 0 ) - *sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf(); - else - *sectionName = 0; - } - - return m_exceptionLine; -} - -// interface -asIScriptFunction *asCContext::GetExceptionFunction() -{ - if( GetState() != asEXECUTION_EXCEPTION ) return 0; - - return m_engine->scriptFunctions[m_exceptionFunction]; -} - -// interface -const char *asCContext::GetExceptionString() -{ - if( GetState() != asEXECUTION_EXCEPTION ) return 0; - - return m_exceptionString.AddressOf(); -} - -// interface -asEContextState asCContext::GetState() const -{ - return m_status; -} - -// interface -int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv) -{ - m_lineCallback = true; - m_regs.doProcessSuspend = true; - m_lineCallbackObj = obj; - bool isObj = false; - if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST ) - { - m_lineCallback = false; - m_regs.doProcessSuspend = m_doSuspend; - return asNOT_SUPPORTED; - } - if( (unsigned)callConv >= asCALL_THISCALL ) - { - isObj = true; - if( obj == 0 ) - { - m_lineCallback = false; - m_regs.doProcessSuspend = m_doSuspend; - return asINVALID_ARG; - } - } - - int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_lineCallbackFunc); - if( r < 0 ) m_lineCallback = false; - - m_regs.doProcessSuspend = m_doSuspend || m_lineCallback; - - return r; -} - -void asCContext::CallLineCallback() -{ - if( m_lineCallbackFunc.callConv < ICC_THISCALL ) - m_engine->CallGlobalFunction(this, m_lineCallbackObj, &m_lineCallbackFunc, 0); - else - m_engine->CallObjectMethod(m_lineCallbackObj, this, &m_lineCallbackFunc, 0); -} - -// interface -int asCContext::SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv) -{ - m_exceptionCallback = true; - m_exceptionCallbackObj = obj; - bool isObj = false; - if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST ) - return asNOT_SUPPORTED; - if( (unsigned)callConv >= asCALL_THISCALL ) - { - isObj = true; - if( obj == 0 ) - { - m_exceptionCallback = false; - return asINVALID_ARG; - } - } - int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_exceptionCallbackFunc); - if( r < 0 ) m_exceptionCallback = false; - return r; -} - -void asCContext::CallExceptionCallback() -{ - if( m_exceptionCallbackFunc.callConv < ICC_THISCALL ) - m_engine->CallGlobalFunction(this, m_exceptionCallbackObj, &m_exceptionCallbackFunc, 0); - else - m_engine->CallObjectMethod(m_exceptionCallbackObj, this, &m_exceptionCallbackFunc, 0); -} - -// interface -void asCContext::ClearLineCallback() -{ - m_lineCallback = false; - m_regs.doProcessSuspend = m_doSuspend; -} - -// interface -void asCContext::ClearExceptionCallback() -{ - m_exceptionCallback = false; -} - -int asCContext::CallGeneric(int id, void *objectPointer) -{ - asCScriptFunction *sysFunction = m_engine->scriptFunctions[id]; - asSSystemFunctionInterface *sysFunc = sysFunction->sysFuncIntf; - void (*func)(asIScriptGeneric*) = (void (*)(asIScriptGeneric*))sysFunc->func; - int popSize = sysFunc->paramSize; - asDWORD *args = m_regs.stackPointer; - - // Verify the object pointer if it is a class method - void *currentObject = 0; - if( sysFunc->callConv == ICC_GENERIC_METHOD ) - { - if( objectPointer ) - { - currentObject = objectPointer; - - // Don't increase the reference of this pointer - // since it will not have been constructed yet - } - else - { - // The object pointer should be popped from the context stack - popSize += AS_PTR_SIZE; - - // Check for null pointer - currentObject = (void*)*(asPWORD*)(args); - if( currentObject == 0 ) - { - SetInternalException(TXT_NULL_POINTER_ACCESS); - return 0; - } - - // Add the base offset for multiple inheritance - currentObject = (void*)(asPWORD(currentObject) + sysFunc->baseOffset); - - // Skip object pointer - args += AS_PTR_SIZE; - } - } - - if( sysFunction->DoesReturnOnStack() ) - { - // Skip the address where the return value will be stored - args += AS_PTR_SIZE; - popSize += AS_PTR_SIZE; - } - - asCGeneric gen(m_engine, sysFunction, currentObject, args); - - m_callingSystemFunction = sysFunction; - func(&gen); - m_callingSystemFunction = 0; - - m_regs.valueRegister = gen.returnVal; - m_regs.objectRegister = gen.objectRegister; - m_regs.objectType = sysFunction->returnType.GetObjectType(); - - // Clean up function parameters - int offset = 0; - for( asUINT n = 0; n < sysFunction->parameterTypes.GetLength(); n++ ) - { - if( sysFunction->parameterTypes[n].IsObject() && !sysFunction->parameterTypes[n].IsReference() ) - { - void *obj = *(void**)&args[offset]; - if( obj ) - { - // Release the object - asSTypeBehaviour *beh = &sysFunction->parameterTypes[n].GetObjectType()->beh; - if( sysFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_REF ) - { - asASSERT( (sysFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release ); - if( beh->release ) - m_engine->CallObjectMethod(obj, beh->release); - } - else - { - // Call the destructor then free the memory - if( beh->destruct ) - m_engine->CallObjectMethod(obj, beh->destruct); - - m_engine->CallFree(obj); - } - } - } - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - } - - // Return how much should be popped from the stack - return popSize; -} - -// interface -int asCContext::GetVarCount(asUINT stackLevel) -{ - asIScriptFunction *func = GetFunction(stackLevel); - if( func == 0 ) return asINVALID_ARG; - - return func->GetVarCount(); -} - -// interface -const char *asCContext::GetVarName(asUINT varIndex, asUINT stackLevel) -{ - asIScriptFunction *func = GetFunction(stackLevel); - if( func == 0 ) return 0; - - const char *name = 0; - int r = func->GetVar(varIndex, &name); - return r >= 0 ? name : 0; -} - -// interface -const char *asCContext::GetVarDeclaration(asUINT varIndex, asUINT stackLevel, bool includeNamespace) -{ - asIScriptFunction *func = GetFunction(stackLevel); - if( func == 0 ) return 0; - - return func->GetVarDecl(varIndex, includeNamespace); -} - -// interface -int asCContext::GetVarTypeId(asUINT varIndex, asUINT stackLevel) -{ - asIScriptFunction *func = GetFunction(stackLevel); - if( func == 0 ) return asINVALID_ARG; - - int typeId; - int r = func->GetVar(varIndex, 0, &typeId); - return r < 0 ? r : typeId; -} - -// interface -void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel) -{ - // Don't return anything if there is no bytecode, e.g. before calling Execute() - if( m_regs.programPointer == 0 ) return 0; - - if( stackLevel >= GetCallstackSize() ) return 0; - - asCScriptFunction *func; - asDWORD *sf; - if( stackLevel == 0 ) - { - func = m_currentFunction; - sf = m_regs.stackFramePointer; - } - else - { - asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; - func = (asCScriptFunction*)s[1]; - sf = (asDWORD*)s[0]; - } - - if( func == 0 ) - return 0; - - if( func->scriptData == 0 ) - return 0; - - if( varIndex >= func->scriptData->variables.GetLength() ) - return 0; - - // For object variables it's necessary to dereference the pointer to get the address of the value - // Reference parameters must also be dereferenced to give the address of the value - int pos = func->scriptData->variables[varIndex]->stackOffset; - if( (func->scriptData->variables[varIndex]->type.IsObject() && !func->scriptData->variables[varIndex]->type.IsObjectHandle()) || (pos <= 0) ) - { - // Determine if the object is really on the heap - bool onHeap = false; - if( func->scriptData->variables[varIndex]->type.IsObject() && - !func->scriptData->variables[varIndex]->type.IsObjectHandle() ) - { - onHeap = true; - if( func->scriptData->variables[varIndex]->type.GetObjectType()->GetFlags() & asOBJ_VALUE ) - { - for( asUINT n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ ) - { - if( func->scriptData->objVariablePos[n] == pos ) - { - onHeap = n < func->scriptData->objVariablesOnHeap; - - if( !onHeap ) - { - // If the object on the stack is not initialized return a null pointer instead - asCArray liveObjects; - DetermineLiveObjects(liveObjects, stackLevel); - - if( liveObjects[n] <= 0 ) - return 0; - } - - break; - } - } - } - } - - // If it wasn't an object on the heap, then check if it is a reference parameter - if( !onHeap && pos <= 0 ) - { - // Determine what function argument this position matches - int stackPos = 0; - if( func->objectType ) - stackPos -= AS_PTR_SIZE; - - if( func->DoesReturnOnStack() ) - stackPos -= AS_PTR_SIZE; - - for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( stackPos == pos ) - { - // The right argument was found. Is this a reference parameter? - if( func->inOutFlags[n] != asTM_NONE ) - onHeap = true; - - break; - } - stackPos -= func->parameterTypes[n].GetSizeOnStackDWords(); - } - } - - if( onHeap ) - return *(void**)(sf - func->scriptData->variables[varIndex]->stackOffset); - } - - return sf - func->scriptData->variables[varIndex]->stackOffset; -} - -// interface -// returns the typeId of the 'this' object at the given call stack level (-1 for current) -// returns 0 if the function call at the given stack level is not a method -int asCContext::GetThisTypeId(asUINT stackLevel) -{ - asIScriptFunction *func = GetFunction(stackLevel); - if( func == 0 ) return asINVALID_ARG; - - if( func->GetObjectType() == 0 ) - return 0; // not in a method - - // create a datatype - asCDataType dt = asCDataType::CreateObject((asCObjectType*)func->GetObjectType(), false); - - // return a typeId from the data type - return m_engine->GetTypeIdFromDataType(dt); -} - -// interface -// returns the 'this' object pointer at the given call stack level (-1 for current) -// returns 0 if the function call at the given stack level is not a method -void *asCContext::GetThisPointer(asUINT stackLevel) -{ - if( stackLevel >= GetCallstackSize() ) - return 0; - - asCScriptFunction *func; - asDWORD *sf; - if( stackLevel == 0 ) - { - func = m_currentFunction; - sf = m_regs.stackFramePointer; - } - else - { - asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; - func = (asCScriptFunction*)s[1]; - sf = (asDWORD*)s[0]; - } - - if( func == 0 ) - return 0; - - if( func->objectType == 0 ) - return 0; // not in a method - - void *thisPointer = (void*)*(asPWORD*)(sf); - if( thisPointer == 0 ) - { - return 0; - } - - // NOTE: this returns the pointer to the 'this' while the GetVarPointer functions return - // a pointer to a pointer. I can't imagine someone would want to change the 'this' - return thisPointer; -} - - - - - - - -// TODO: Move these to as_utils.cpp - -struct POW_INFO -{ - asQWORD MaxBaseu64; - asDWORD MaxBasei64; - asWORD MaxBaseu32; - asWORD MaxBasei32; - char HighBit; -}; - -const POW_INFO pow_info[] = -{ - { 0ULL, 0UL, 0, 0, 0 }, // 0 is a special case - { 0ULL, 0UL, 0, 0, 1 }, // 1 is a special case - { 3037000499ULL, 2147483647UL, 65535, 46340, 2 }, // 2 - { 2097152ULL, 1664510UL, 1625, 1290, 2 }, // 3 - { 55108ULL, 46340UL, 255, 215, 3 }, // 4 - { 6208ULL, 5404UL, 84, 73, 3 }, // 5 - { 1448ULL, 1290UL, 40, 35, 3 }, // 6 - { 511ULL, 463UL, 23, 21, 3 }, // 7 - { 234ULL, 215UL, 15, 14, 4 }, // 8 - { 128ULL, 118UL, 11, 10, 4 }, // 9 - { 78ULL, 73UL, 9, 8, 4 }, // 10 - { 52ULL, 49UL, 7, 7, 4 }, // 11 - { 38ULL, 35UL, 6, 5, 4 }, // 12 - { 28ULL, 27UL, 5, 5, 4 }, // 13 - { 22ULL, 21UL, 4, 4, 4 }, // 14 - { 18ULL, 17UL, 4, 4, 4 }, // 15 - { 15ULL, 14UL, 3, 3, 5 }, // 16 - { 13ULL, 12UL, 3, 3, 5 }, // 17 - { 11ULL, 10UL, 3, 3, 5 }, // 18 - { 9ULL, 9UL, 3, 3, 5 }, // 19 - { 8ULL, 8UL, 3, 2, 5 }, // 20 - { 8ULL, 7UL, 2, 2, 5 }, // 21 - { 7ULL, 7UL, 2, 2, 5 }, // 22 - { 6ULL, 6UL, 2, 2, 5 }, // 23 - { 6ULL, 5UL, 2, 2, 5 }, // 24 - { 5ULL, 5UL, 2, 2, 5 }, // 25 - { 5ULL, 5UL, 2, 2, 5 }, // 26 - { 5ULL, 4UL, 2, 2, 5 }, // 27 - { 4ULL, 4UL, 2, 2, 5 }, // 28 - { 4ULL, 4UL, 2, 2, 5 }, // 29 - { 4ULL, 4UL, 2, 2, 5 }, // 30 - { 4ULL, 4UL, 2, 1, 5 }, // 31 - { 3ULL, 3UL, 1, 1, 6 }, // 32 - { 3ULL, 3UL, 1, 1, 6 }, // 33 - { 3ULL, 3UL, 1, 1, 6 }, // 34 - { 3ULL, 3UL, 1, 1, 6 }, // 35 - { 3ULL, 3UL, 1, 1, 6 }, // 36 - { 3ULL, 3UL, 1, 1, 6 }, // 37 - { 3ULL, 3UL, 1, 1, 6 }, // 38 - { 3ULL, 3UL, 1, 1, 6 }, // 39 - { 2ULL, 2UL, 1, 1, 6 }, // 40 - { 2ULL, 2UL, 1, 1, 6 }, // 41 - { 2ULL, 2UL, 1, 1, 6 }, // 42 - { 2ULL, 2UL, 1, 1, 6 }, // 43 - { 2ULL, 2UL, 1, 1, 6 }, // 44 - { 2ULL, 2UL, 1, 1, 6 }, // 45 - { 2ULL, 2UL, 1, 1, 6 }, // 46 - { 2ULL, 2UL, 1, 1, 6 }, // 47 - { 2ULL, 2UL, 1, 1, 6 }, // 48 - { 2ULL, 2UL, 1, 1, 6 }, // 49 - { 2ULL, 2UL, 1, 1, 6 }, // 50 - { 2ULL, 2UL, 1, 1, 6 }, // 51 - { 2ULL, 2UL, 1, 1, 6 }, // 52 - { 2ULL, 2UL, 1, 1, 6 }, // 53 - { 2ULL, 2UL, 1, 1, 6 }, // 54 - { 2ULL, 2UL, 1, 1, 6 }, // 55 - { 2ULL, 2UL, 1, 1, 6 }, // 56 - { 2ULL, 2UL, 1, 1, 6 }, // 57 - { 2ULL, 2UL, 1, 1, 6 }, // 58 - { 2ULL, 2UL, 1, 1, 6 }, // 59 - { 2ULL, 2UL, 1, 1, 6 }, // 60 - { 2ULL, 2UL, 1, 1, 6 }, // 61 - { 2ULL, 2UL, 1, 1, 6 }, // 62 - { 2ULL, 1UL, 1, 1, 6 }, // 63 -}; - -int as_powi(int base, int exponent, bool& isOverflow) -{ - if( exponent < 0 ) - { - if( base == 0 ) - // Divide by zero - isOverflow = true; - else - // Result is less than 1, so it truncates to 0 - isOverflow = false; - - return 0; - } - else if( exponent == 0 && base == 0 ) - { - // Domain error - isOverflow = true; - return 0; - } - else if( exponent >= 31 ) - { - switch( base ) - { - case -1: - isOverflow = false; - return exponent & 1 ? -1 : 1; - case 0: - isOverflow = false; - break; - case 1: - isOverflow = false; - return 1; - default: - isOverflow = true; - break; - } - return 0; - } - else - { - const asWORD max_base = pow_info[exponent].MaxBasei32; - const char high_bit = pow_info[exponent].HighBit; - if( max_base != 0 && max_base < (base < 0 ? -base : base) ) - { - isOverflow = true; - return 0; // overflow - } - - int result = 1; - switch( high_bit ) - { - case 5: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 4: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 3: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 2: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 1: - if( exponent ) result *= base; - default: - isOverflow = false; - return result; - } - } -} - -asDWORD as_powu(asDWORD base, asDWORD exponent, bool& isOverflow) -{ - if( exponent == 0 && base == 0 ) - { - // Domain error - isOverflow = true; - return 0; - } - else if( exponent >= 32 ) - { - switch( base ) - { - case 0: - isOverflow = false; - break; - case 1: - isOverflow = false; - return 1; - default: - isOverflow = true; - break; - } - return 0; - } - else - { - const asWORD max_base = pow_info[exponent].MaxBaseu32; - const char high_bit = pow_info[exponent].HighBit; - if( max_base != 0 && max_base < base ) - { - isOverflow = true; - return 0; // overflow - } - - asDWORD result = 1; - switch( high_bit ) - { - case 5: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 4: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 3: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 2: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 1: - if( exponent ) result *= base; - default: - isOverflow = false; - return result; - } - } -} - -asINT64 as_powi64(asINT64 base, asINT64 exponent, bool& isOverflow) -{ - if( exponent < 0 ) - { - if( base == 0 ) - // Divide by zero - isOverflow = true; - else - // Result is less than 1, so it truncates to 0 - isOverflow = false; - - return 0; - } - else if( exponent == 0 && base == 0 ) - { - // Domain error - isOverflow = true; - return 0; - } - else if( exponent >= 63 ) - { - switch( base ) - { - case -1: - isOverflow = false; - return exponent & 1 ? -1 : 1; - case 0: - isOverflow = false; - break; - case 1: - isOverflow = false; - return 1; - default: - isOverflow = true; - break; - } - return 0; - } - else - { - const asDWORD max_base = pow_info[exponent].MaxBasei64; - const char high_bit = pow_info[exponent].HighBit; - if( max_base != 0 && max_base < (base < 0 ? -base : base) ) - { - isOverflow = true; - return 0; // overflow - } - - asINT64 result = 1; - switch( high_bit ) - { - case 6: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 5: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 4: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 3: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 2: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 1: - if( exponent ) result *= base; - default: - isOverflow = false; - return result; - } - } -} - -asQWORD as_powu64(asQWORD base, asQWORD exponent, bool& isOverflow) -{ - if( exponent == 0 && base == 0 ) - { - // Domain error - isOverflow = true; - return 0; - } - else if( exponent >= 64 ) - { - switch( base ) - { - case 0: - isOverflow = false; - break; - case 1: - isOverflow = false; - return 1; - default: - isOverflow = true; - break; - } - return 0; - } - else - { - const asQWORD max_base = pow_info[exponent].MaxBaseu64; - const char high_bit = pow_info[exponent].HighBit; - if( max_base != 0 && max_base < base ) - { - isOverflow = true; - return 0; // overflow - } - - asQWORD result = 1; - switch( high_bit ) - { - case 6: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 5: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 4: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 3: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 2: - if( exponent & 1 ) result *= base; - exponent >>= 1; - base *= base; - case 1: - if( exponent ) result *= base; - default: - isOverflow = false; - return result; - } - } -} - -END_AS_NAMESPACE - - - diff --git a/dependencies/angelscript/source/as_context.h b/dependencies/angelscript/source/as_context.h deleted file mode 100644 index 9914b3d6..00000000 --- a/dependencies/angelscript/source/as_context.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_context.h -// -// This class handles the execution of the byte code -// - - -#ifndef AS_CONTEXT_H -#define AS_CONTEXT_H - -#include "as_config.h" -#include "as_atomic.h" -#include "as_array.h" -#include "as_string.h" -#include "as_objecttype.h" -#include "as_callfunc.h" - -BEGIN_AS_NAMESPACE - -class asCScriptFunction; -class asCScriptEngine; - -class asCContext : public asIScriptContext -{ -public: - // Memory management - int AddRef() const; - int Release() const; - - // Miscellaneous - asIScriptEngine *GetEngine() const; - - // Execution - int Prepare(asIScriptFunction *func); - int Unprepare(); - int Execute(); - int Abort(); - int Suspend(); - asEContextState GetState() const; - int PushState(); - int PopState(); - bool IsNested(asUINT *nestCount = 0) const; - - // Object pointer for calling class methods - int SetObject(void *obj); - - // Arguments - int SetArgByte(asUINT arg, asBYTE value); - int SetArgWord(asUINT arg, asWORD value); - int SetArgDWord(asUINT arg, asDWORD value); - int SetArgQWord(asUINT arg, asQWORD value); - int SetArgFloat(asUINT arg, float value); - int SetArgDouble(asUINT arg, double value); - int SetArgAddress(asUINT arg, void *addr); - int SetArgObject(asUINT arg, void *obj); - void *GetAddressOfArg(asUINT arg); - - // Return value - asBYTE GetReturnByte(); - asWORD GetReturnWord(); - asDWORD GetReturnDWord(); - asQWORD GetReturnQWord(); - float GetReturnFloat(); - double GetReturnDouble(); - void *GetReturnAddress(); - void *GetReturnObject(); - void *GetAddressOfReturnValue(); - - // Exception handling - int SetException(const char *descr); - int GetExceptionLineNumber(int *column, const char **sectionName); - asIScriptFunction *GetExceptionFunction(); - const char * GetExceptionString(); - int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv); - void ClearExceptionCallback(); - - // Debugging - int SetLineCallback(asSFuncPtr callback, void *obj, int callConv); - void ClearLineCallback(); - asUINT GetCallstackSize() const; - asIScriptFunction *GetFunction(asUINT stackLevel); - int GetLineNumber(asUINT stackLevel, int *column, const char **sectionName); - int GetVarCount(asUINT stackLevel); - const char *GetVarName(asUINT varIndex, asUINT stackLevel); - const char *GetVarDeclaration(asUINT varIndex, asUINT stackLevel, bool includeNamespace); - int GetVarTypeId(asUINT varIndex, asUINT stackLevel); - void *GetAddressOfVar(asUINT varIndex, asUINT stackLevel); - bool IsVarInScope(asUINT varIndex, asUINT stackLevel); - int GetThisTypeId(asUINT stackLevel); - void *GetThisPointer(asUINT stackLevel); - asIScriptFunction *GetSystemFunction(); - - // User data - void *SetUserData(void *data, asPWORD type); - void *GetUserData(asPWORD type) const; - -public: - // Internal public functions - asCContext(asCScriptEngine *engine, bool holdRef); - virtual ~asCContext(); - -//protected: - friend class asCScriptEngine; - - void CallLineCallback(); - void CallExceptionCallback(); - - int CallGeneric(int funcID, void *objectPointer); - - void DetachEngine(); - - void ExecuteNext(); - void CleanStack(); - void CleanStackFrame(); - void CleanArgsOnStack(); - void CleanReturnObject(); - void DetermineLiveObjects(asCArray &liveObjects, asUINT stackLevel); - - void PushCallState(); - void PopCallState(); - void CallScriptFunction(asCScriptFunction *func); - void CallInterfaceMethod(asCScriptFunction *func); - void PrepareScriptFunction(); - - bool ReserveStackSpace(asUINT size); - - void SetInternalException(const char *descr); - - // Must be protected for multiple accesses - mutable asCAtomic m_refCount; - - bool m_holdEngineRef; - asCScriptEngine *m_engine; - - asEContextState m_status; - bool m_doSuspend; - bool m_doAbort; - bool m_externalSuspendRequest; - - asCScriptFunction *m_currentFunction; - asCScriptFunction *m_callingSystemFunction; - - // The call stack holds program pointer, stack pointer, etc for caller functions - asCArray m_callStack; - - // Dynamically growing local stack - asCArray m_stackBlocks; - asUINT m_stackBlockSize; - asUINT m_stackIndex; - asDWORD *m_originalStackPointer; - - // Exception handling - bool m_isStackMemoryNotAllocated; - bool m_needToCleanupArgs; - bool m_inExceptionHandler; - asCString m_exceptionString; - int m_exceptionFunction; - int m_exceptionSectionIdx; - int m_exceptionLine; - int m_exceptionColumn; - - // The last prepared function, and some cached values related to it - asCScriptFunction *m_initialFunction; - int m_returnValueSize; - int m_argumentsSize; - - // callbacks - bool m_lineCallback; - asSSystemFunctionInterface m_lineCallbackFunc; - void * m_lineCallbackObj; - - bool m_exceptionCallback; - asSSystemFunctionInterface m_exceptionCallbackFunc; - void * m_exceptionCallbackObj; - - asCArray m_userData; - - // Registers available to JIT compiler functions - asSVMRegisters m_regs; -}; - -// TODO: Move these to as_utils.h -int as_powi(int base, int exponent, bool& isOverflow); -asDWORD as_powu(asDWORD base, asDWORD exponent, bool& isOverflow); -asINT64 as_powi64(asINT64 base, asINT64 exponent, bool& isOverflow); -asQWORD as_powu64(asQWORD base, asQWORD exponent, bool& isOverflow); - -// Optional template version of powi if overflow detection is not used. -#if 0 -template -T as_powi(T base, T exponent) -{ - // Test for sign bit (huge number is OK) - if( exponent & (T(1)<<(sizeof(T)*8-1)) ) - return 0; - else - { - int result = 1; - while( exponent ) - { - if( exponent & 1 ) - result *= base; - exponent >>= 1; - base *= base; - } - return result; - } -} -#endif - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_criticalsection.h b/dependencies/angelscript/source/as_criticalsection.h deleted file mode 100644 index 342f1384..00000000 --- a/dependencies/angelscript/source/as_criticalsection.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - -// -// as_criticalsection.h -// -// Classes for multi threading support -// - -#ifndef AS_CRITICALSECTION_H -#define AS_CRITICALSECTION_H - -#include "as_config.h" - -BEGIN_AS_NAMESPACE - -#ifdef AS_NO_THREADS - -#define DECLARECRITICALSECTION(x) -#define ENTERCRITICALSECTION(x) -#define LEAVECRITICALSECTION(x) - -inline bool tryEnter() { return true; } -#define TRYENTERCRITICALSECTION(x) tryEnter() - -#define DECLAREREADWRITELOCK(x) -#define ACQUIREEXCLUSIVE(x) -#define RELEASEEXCLUSIVE(x) -#define ACQUIRESHARED(x) -#define RELEASESHARED(x) - -#else - -#define DECLARECRITICALSECTION(x) asCThreadCriticalSection x; -#define ENTERCRITICALSECTION(x) x.Enter() -#define LEAVECRITICALSECTION(x) x.Leave() -#define TRYENTERCRITICALSECTION(x) x.TryEnter() - -#define DECLAREREADWRITELOCK(x) asCThreadReadWriteLock x; -#define ACQUIREEXCLUSIVE(x) x.AcquireExclusive() -#define RELEASEEXCLUSIVE(x) x.ReleaseExclusive() -#define ACQUIRESHARED(x) x.AcquireShared() -#define RELEASESHARED(x) x.ReleaseShared() - -#ifdef AS_POSIX_THREADS - -END_AS_NAMESPACE -#include -BEGIN_AS_NAMESPACE - -class asCThreadCriticalSection -{ -public: - asCThreadCriticalSection(); - ~asCThreadCriticalSection(); - - void Enter(); - void Leave(); - bool TryEnter(); - -protected: - pthread_mutex_t cs; -}; - -class asCThreadReadWriteLock -{ -public: - asCThreadReadWriteLock(); - ~asCThreadReadWriteLock(); - - void AcquireExclusive(); - void ReleaseExclusive(); - bool TryAcquireExclusive(); - - void AcquireShared(); - void ReleaseShared(); - bool TryAcquireShared(); - -protected: - pthread_rwlock_t lock; -}; - -#elif defined(AS_WINDOWS_THREADS) - -END_AS_NAMESPACE -#ifdef AS_XBOX360 -#include -#else -#define WIN32_LEAN_AND_MEAN -#ifndef _WIN32_WINNT - #define _WIN32_WINNT 0x0600 // We need this to get the declaration for Windows Phone compatible Ex functions -#endif -#include -#endif -BEGIN_AS_NAMESPACE - -// Undefine macros that cause problems in our code -#undef GetObject -#undef RegisterClass - -class asCThreadCriticalSection -{ -public: - asCThreadCriticalSection(); - ~asCThreadCriticalSection(); - - void Enter(); - void Leave(); - bool TryEnter(); - -protected: - CRITICAL_SECTION cs; -}; - -class asCThreadReadWriteLock -{ -public: - asCThreadReadWriteLock(); - ~asCThreadReadWriteLock(); - - void AcquireExclusive(); - void ReleaseExclusive(); - - void AcquireShared(); - void ReleaseShared(); - -protected: - // The Slim Read Write Lock object, SRWLOCK, is more efficient - // but it is only available from Windows Vista so we cannot use it and - // maintain compatibility with olders versions of Windows. - - // Critical sections and semaphores are available on Windows XP and onwards. - // Windows XP is oldest version we support with multithreading. - - // The implementation is based on the following article, that shows - // how to implement a fair read/write lock that doesn't risk starving - // the writers: - - // http://doc.qt.nokia.com/qq/qq11-mutex.html - - // TODO: Allow use of SRWLOCK through configuration in as_config.h - - CRITICAL_SECTION writeLock; - HANDLE readLocks; -}; - -// This constant really should be a member of asCThreadReadWriteLock, -// but it gives a compiler error on MSVC6 so I'm leaving it outside -static const asUINT maxReaders = 10; - -#endif - -#endif - -END_AS_NAMESPACE - -#endif - diff --git a/dependencies/angelscript/source/as_datatype.cpp b/dependencies/angelscript/source/as_datatype.cpp deleted file mode 100644 index 8e4a527d..00000000 --- a/dependencies/angelscript/source/as_datatype.cpp +++ /dev/null @@ -1,663 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_datatype.cpp -// -// This class describes the datatype for expressions during compilation -// - -#include "as_config.h" -#include "as_datatype.h" -#include "as_tokendef.h" -#include "as_objecttype.h" -#include "as_scriptengine.h" -#include "as_tokenizer.h" - -BEGIN_AS_NAMESPACE - -asCDataType::asCDataType() -{ - tokenType = ttUnrecognizedToken; - objectType = 0; - isReference = false; - isReadOnly = false; - isAuto = false; - isObjectHandle = false; - isConstHandle = false; - funcDef = 0; - isHandleToAsHandleType = false; -} - -asCDataType::asCDataType(const asCDataType &dt) -{ - tokenType = dt.tokenType; - objectType = dt.objectType; - isReference = dt.isReference; - isReadOnly = dt.isReadOnly; - isAuto = dt.isAuto; - isObjectHandle = dt.isObjectHandle; - isConstHandle = dt.isConstHandle; - funcDef = dt.funcDef; - isHandleToAsHandleType = dt.isHandleToAsHandleType; -} - -asCDataType::~asCDataType() -{ -} - -bool asCDataType::IsValid() const -{ - if( tokenType == ttUnrecognizedToken && - !isObjectHandle ) - return false; - - return true; -} - -asCDataType asCDataType::CreateObject(asCObjectType *ot, bool isConst) -{ - asCDataType dt; - - dt.tokenType = ttIdentifier; - dt.objectType = ot; - dt.isReadOnly = isConst; - - return dt; -} - -asCDataType asCDataType::CreateAuto(bool isConst) -{ - asCDataType dt; - - dt.tokenType = ttIdentifier; - dt.isReadOnly = isConst; - dt.isAuto = true; - - return dt; -} - -asCDataType asCDataType::CreateObjectHandle(asCObjectType *ot, bool isConst) -{ - asCDataType dt; - - dt.tokenType = ttIdentifier; - dt.objectType = ot; - dt.isObjectHandle = true; - dt.isConstHandle = isConst; - - return dt; -} - -asCDataType asCDataType::CreateFuncDef(asCScriptFunction *func) -{ - asCDataType dt; - dt.tokenType = ttIdentifier; - dt.funcDef = func; - dt.objectType = &func->engine->functionBehaviours; - - return dt; -} - -asCDataType asCDataType::CreatePrimitive(eTokenType tt, bool isConst) -{ - asCDataType dt; - - dt.tokenType = tt; - dt.isReadOnly = isConst; - - return dt; -} - -asCDataType asCDataType::CreateNullHandle() -{ - asCDataType dt; - - dt.tokenType = ttUnrecognizedToken; - dt.isReadOnly = true; - dt.isObjectHandle = true; - dt.isConstHandle = true; - - return dt; -} - -bool asCDataType::IsNullHandle() const -{ - if( tokenType == ttUnrecognizedToken && - objectType == 0 && - isObjectHandle ) - return true; - - return false; -} - -asCString asCDataType::Format(bool includeNamespace) const -{ - if( IsNullHandle() ) - return ""; - - asCString str; - - if( isReadOnly ) - str = "const "; - - if( includeNamespace ) - { - if( objectType ) - str += objectType->nameSpace->name + "::"; - else if( funcDef ) - str += funcDef->nameSpace->name + "::"; - } - - if( tokenType != ttIdentifier ) - { - str += asCTokenizer::GetDefinition(tokenType); - } - else if( IsArrayType() && objectType && !objectType->engine->ep.expandDefaultArrayToTemplate ) - { - asASSERT( objectType->templateSubTypes.GetLength() == 1 ); - str += objectType->templateSubTypes[0].Format(includeNamespace); - str += "[]"; - } - else if( funcDef ) - { - str += funcDef->name; - } - else if( objectType ) - { - str += objectType->name; - if( objectType->templateSubTypes.GetLength() > 0 ) - { - str += "<"; - for( asUINT subtypeIndex = 0; subtypeIndex < objectType->templateSubTypes.GetLength(); subtypeIndex++ ) - { - str += objectType->templateSubTypes[subtypeIndex].Format(includeNamespace); - if( subtypeIndex != objectType->templateSubTypes.GetLength()-1 ) - str += ","; - } - str += ">"; - } - } - else if( isAuto ) - { - if( isObjectHandle ) - str += ""; - else - str += ""; - } - else - { - str = ""; - } - - if( isObjectHandle ) - { - str += "@"; - if( isConstHandle ) - str += "const"; - } - - if( isReference ) - str += "&"; - - return str; -} - -asCDataType &asCDataType::operator =(const asCDataType &dt) -{ - tokenType = dt.tokenType; - isReference = dt.isReference; - objectType = dt.objectType; - isReadOnly = dt.isReadOnly; - isObjectHandle = dt.isObjectHandle; - isConstHandle = dt.isConstHandle; - isAuto = dt.isAuto; - funcDef = dt.funcDef; - isHandleToAsHandleType = dt.isHandleToAsHandleType; - - return (asCDataType &)*this; -} - -int asCDataType::MakeHandle(bool b, bool acceptHandleForScope) -{ - if( !b ) - { - isObjectHandle = false; - isConstHandle = false; - isHandleToAsHandleType = false; - } - else - { - if( isAuto ) - { - isObjectHandle = true; - } - else if( !isObjectHandle ) - { - // Only reference types are allowed to be handles, - // but not nohandle reference types, and not scoped references - // (except when returned from registered function) - // funcdefs are special reference types and support handles - // value types with asOBJ_ASHANDLE are treated as a handle - if( !funcDef && - (!objectType || - !((objectType->flags & asOBJ_REF) || (objectType->flags & asOBJ_TEMPLATE_SUBTYPE) || (objectType->flags & asOBJ_ASHANDLE)) || - (objectType->flags & asOBJ_NOHANDLE) || - ((objectType->flags & asOBJ_SCOPED) && !acceptHandleForScope)) ) - return -1; - - isObjectHandle = b; - isConstHandle = false; - - // ASHANDLE supports being handle, but as it really is a value type it will not be marked as a handle - if( (objectType->flags & asOBJ_ASHANDLE) ) - { - isObjectHandle = false; - isHandleToAsHandleType = true; - } - } - } - - return 0; -} - -int asCDataType::MakeArray(asCScriptEngine *engine) -{ - if( engine->defaultArrayObjectType == 0 ) - return asINVALID_TYPE; - - bool tmpIsReadOnly = isReadOnly; - isReadOnly = false; - asCArray subTypes; - subTypes.PushLast(*this); - asCObjectType *at = engine->GetTemplateInstanceType(engine->defaultArrayObjectType, subTypes); - isReadOnly = tmpIsReadOnly; - - isObjectHandle = false; - isConstHandle = false; - - objectType = at; - tokenType = ttIdentifier; - - return 0; -} - -int asCDataType::MakeReference(bool b) -{ - isReference = b; - - return 0; -} - -int asCDataType::MakeReadOnly(bool b) -{ - if( isObjectHandle ) - { - isConstHandle = b; - return 0; - } - - isReadOnly = b; - return 0; -} - -int asCDataType::MakeHandleToConst(bool b) -{ - if( !isObjectHandle ) return -1; - - isReadOnly = b; - return 0; -} - -bool asCDataType::SupportHandles() const -{ - if( objectType && - (objectType->flags & (asOBJ_REF | asOBJ_ASHANDLE)) && - !(objectType->flags & asOBJ_NOHANDLE) && - !isObjectHandle ) - return true; - - return false; -} - -bool asCDataType::CanBeInstantiated() const -{ - if( GetSizeOnStackDWords() == 0 ) // Void - return false; - - if( !IsObject() ) // Primitives - return true; - - if( IsObjectHandle() && !(objectType->flags & asOBJ_NOHANDLE) ) // Handles - return true; - - if( funcDef ) // Funcdefs can be instantiated as delegates - return true; - - if( (objectType->flags & asOBJ_REF) && objectType->beh.factories.GetLength() == 0 ) // ref types without factories - return false; - - if( (objectType->flags & asOBJ_ABSTRACT) && !IsObjectHandle() ) // Can't instantiate abstract classes - return false; - - return true; -} - -bool asCDataType::IsAbstractClass() const -{ - return objectType && (objectType->flags & asOBJ_ABSTRACT) ? true : false; -} - -bool asCDataType::IsInterface() const -{ - return objectType && objectType->IsInterface(); -} - -bool asCDataType::CanBeCopied() const -{ - // All primitives can be copied - if( IsPrimitive() ) return true; - - // Plain-old-data structures can always be copied - if( objectType->flags & asOBJ_POD ) return true; - - // It must be possible to instantiate the type - if( !CanBeInstantiated() ) return false; - - // It must have a default constructor or factory - if( objectType->beh.construct == 0 && - objectType->beh.factory == 0 ) return false; - - // It must be possible to copy the type - if( objectType->beh.copy == 0 ) return false; - - return true; -} - -bool asCDataType::IsReadOnly() const -{ - if( isObjectHandle ) - return isConstHandle; - - return isReadOnly; -} - -bool asCDataType::IsHandleToConst() const -{ - if( !isObjectHandle ) return false; - return isReadOnly; -} - -bool asCDataType::IsObjectConst() const -{ - if( IsObjectHandle() ) - return IsHandleToConst(); - - return IsReadOnly(); -} - -// TODO: 3.0.0: This should be removed -bool asCDataType::IsArrayType() const -{ - // This is only true if the type used is the default array type, i.e. the one used for the [] syntax form - if( objectType && objectType->engine->defaultArrayObjectType ) - return objectType->name == objectType->engine->defaultArrayObjectType->name; - - return false; -} - -bool asCDataType::IsTemplate() const -{ - if( objectType && (objectType->flags & asOBJ_TEMPLATE) ) - return true; - - return false; -} - -bool asCDataType::IsScriptObject() const -{ - if( objectType && (objectType->flags & asOBJ_SCRIPT_OBJECT) ) - return true; - - return false; -} - -asCDataType asCDataType::GetSubType(asUINT subtypeIndex) const -{ - asASSERT(objectType); - return objectType->templateSubTypes[subtypeIndex]; -} - - -bool asCDataType::operator !=(const asCDataType &dt) const -{ - return !(*this == dt); -} - -bool asCDataType::operator ==(const asCDataType &dt) const -{ - if( !IsEqualExceptRefAndConst(dt) ) return false; - if( isReference != dt.isReference ) return false; - if( isReadOnly != dt.isReadOnly ) return false; - if( isConstHandle != dt.isConstHandle ) return false; - - return true; -} - -bool asCDataType::IsEqualExceptRef(const asCDataType &dt) const -{ - if( !IsEqualExceptRefAndConst(dt) ) return false; - if( isReadOnly != dt.isReadOnly ) return false; - if( isConstHandle != dt.isConstHandle ) return false; - - return true; -} - -bool asCDataType::IsEqualExceptRefAndConst(const asCDataType &dt) const -{ - // Check base type - if( tokenType != dt.tokenType ) return false; - if( objectType != dt.objectType ) return false; - if( isObjectHandle != dt.isObjectHandle ) return false; - if( isObjectHandle ) - if( isReadOnly != dt.isReadOnly ) return false; - if( funcDef != dt.funcDef ) return false; - - return true; -} - -bool asCDataType::IsEqualExceptConst(const asCDataType &dt) const -{ - if( !IsEqualExceptRefAndConst(dt) ) return false; - if( isReference != dt.isReference ) return false; - - return true; -} - -bool asCDataType::IsPrimitive() const -{ - // Enumerations are primitives - if( IsEnumType() ) - return true; - - // A registered object is never a primitive neither is a pointer, nor an array - if( objectType || funcDef ) - return false; - - // Null handle doesn't have an objectType, but it is not a primitive - if( tokenType == ttUnrecognizedToken ) - return false; - - return true; -} - -bool asCDataType::IsIntegerType() const -{ - if( tokenType == ttInt || - tokenType == ttInt8 || - tokenType == ttInt16 || - tokenType == ttInt64 ) - return true; - - // Enums are also integer types - return IsEnumType(); -} - -bool asCDataType::IsUnsignedType() const -{ - if( tokenType == ttUInt || - tokenType == ttUInt8 || - tokenType == ttUInt16 || - tokenType == ttUInt64 ) - return true; - - return false; -} - -bool asCDataType::IsFloatType() const -{ - if( tokenType == ttFloat ) - return true; - - return false; -} - -bool asCDataType::IsDoubleType() const -{ - if( tokenType == ttDouble ) - return true; - - return false; -} - -bool asCDataType::IsBooleanType() const -{ - if( tokenType == ttBool ) - return true; - - return false; -} - -bool asCDataType::IsObject() const -{ - if( IsPrimitive() ) - return false; - - // Null handle doesn't have an object type but should still be considered an object - if( objectType == 0 ) - return IsNullHandle(); - - return true; -} - -int asCDataType::GetSizeInMemoryBytes() const -{ - if( objectType != 0 ) - return objectType->size; - - if( tokenType == ttVoid ) - return 0; - - if( tokenType == ttInt8 || - tokenType == ttUInt8 ) - return 1; - - if( tokenType == ttInt16 || - tokenType == ttUInt16 ) - return 2; - - if( tokenType == ttDouble || - tokenType == ttInt64 || - tokenType == ttUInt64 ) - return 8; - - if( tokenType == ttBool ) - return AS_SIZEOF_BOOL; - - // null handle - if( tokenType == ttUnrecognizedToken ) - return 4*AS_PTR_SIZE; - - return 4; -} - -int asCDataType::GetSizeInMemoryDWords() const -{ - int s = GetSizeInMemoryBytes(); - if( s == 0 ) return 0; - if( s <= 4 ) return 1; - - // Pad the size to 4 bytes - if( s & 0x3 ) - s += 4 - (s & 0x3); - - return s/4; -} - -int asCDataType::GetSizeOnStackDWords() const -{ - // If the type is the variable type then the typeid is stored on the stack too - int size = tokenType == ttQuestion ? 1 : 0; - - if( isReference ) return AS_PTR_SIZE + size; - if( objectType && !IsEnumType() ) return AS_PTR_SIZE + size; - - return GetSizeInMemoryDWords() + size; -} - -#ifdef WIP_16BYTE_ALIGN -int asCDataType::GetAlignment() const -{ - if( objectType == NULL ) - { - // TODO: Small primitives should not be aligned to 4 byte boundaries - return 4; //Default alignment - } - - return objectType->alignment; -} -#endif - -asSTypeBehaviour *asCDataType::GetBehaviour() const -{ - return objectType ? &objectType->beh : 0; -} - -bool asCDataType::IsEnumType() const -{ - if( objectType && (objectType->flags & asOBJ_ENUM) ) - return true; - - return false; -} - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_datatype.h b/dependencies/angelscript/source/as_datatype.h deleted file mode 100644 index 2515eee9..00000000 --- a/dependencies/angelscript/source/as_datatype.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_datatype.h -// -// This class describes the datatype for expressions during compilation -// - - - -#ifndef AS_DATATYPE_H -#define AS_DATATYPE_H - -#include "as_tokendef.h" -#include "as_string.h" - -BEGIN_AS_NAMESPACE - -struct asSTypeBehaviour; -class asCScriptEngine; -class asCObjectType; -class asCScriptFunction; - -// TODO: refactor: Reference should not be part of the datatype. This should be stored separately, e.g. in asCTypeInfo -// MakeReference, MakeReadOnly, IsReference, IsReadOnly should be removed - -class asCDataType -{ -public: - asCDataType(); - asCDataType(const asCDataType &); - ~asCDataType(); - - bool IsValid() const; - - asCString Format(bool includeNamespace = false) const; - - static asCDataType CreatePrimitive(eTokenType tt, bool isConst); - static asCDataType CreateObject(asCObjectType *ot, bool isConst); - static asCDataType CreateAuto(bool isConst); - static asCDataType CreateObjectHandle(asCObjectType *ot, bool isConst); - static asCDataType CreateFuncDef(asCScriptFunction *ot); - static asCDataType CreateNullHandle(); - - int MakeHandle(bool b, bool acceptHandleForScope = false); - int MakeArray(asCScriptEngine *engine); - int MakeReference(bool b); - int MakeReadOnly(bool b); - int MakeHandleToConst(bool b); - - bool IsTemplate() const; - bool IsScriptObject() const; - bool IsPrimitive() const; - bool IsObject() const; - bool IsReference() const {return isReference;} - bool IsAuto() const {return isAuto;} - bool IsReadOnly() const; - bool IsIntegerType() const; - bool IsUnsignedType() const; - bool IsFloatType() const; - bool IsDoubleType() const; - bool IsBooleanType() const; - bool IsObjectHandle() const {return isObjectHandle;} - bool IsHandleToAuto() const {return isAuto && isObjectHandle;} - bool IsHandleToConst() const; - bool IsArrayType() const; - bool IsEnumType() const; - bool IsAnyType() const {return tokenType == ttQuestion;} - bool IsHandleToAsHandleType() const {return isHandleToAsHandleType;} - bool IsAbstractClass() const; - bool IsInterface() const; - - bool IsObjectConst() const; - - bool IsEqualExceptRef(const asCDataType &) const; - bool IsEqualExceptRefAndConst(const asCDataType &) const; - bool IsEqualExceptConst(const asCDataType &) const; - bool IsNullHandle() const; - - bool SupportHandles() const; - bool CanBeInstantiated() const; - bool CanBeCopied() const; - - bool operator ==(const asCDataType &) const; - bool operator !=(const asCDataType &) const; - - asCDataType GetSubType(asUINT subtypeIndex = 0) const; - eTokenType GetTokenType() const {return tokenType;} - asCObjectType *GetObjectType() const {return objectType;} - asCScriptFunction *GetFuncDef() const {return funcDef;} - - int GetSizeOnStackDWords() const; - int GetSizeInMemoryBytes() const; - int GetSizeInMemoryDWords() const; -#ifdef WIP_16BYTE_ALIGN - int GetAlignment() const; -#endif - - void SetTokenType(eTokenType tt) {tokenType = tt;} - void SetObjectType(asCObjectType *obj) {objectType = obj;} - void SetFuncDef(asCScriptFunction *func) {asASSERT(funcDef); funcDef = func; } - - asCDataType &operator =(const asCDataType &); - - asSTypeBehaviour *GetBehaviour() const; - -protected: - // Base object type - eTokenType tokenType; - - // Behaviour type - asCObjectType *objectType; - asCScriptFunction *funcDef; - - // Top level - bool isReference:1; - bool isReadOnly:1; - bool isObjectHandle:1; - bool isConstHandle:1; - bool isAuto:1; - bool isHandleToAsHandleType:1; // Used by the compiler to know how to initialize the object - char dummy:2; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_debug.h b/dependencies/angelscript/source/as_debug.h deleted file mode 100644 index b262a88b..00000000 --- a/dependencies/angelscript/source/as_debug.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_debug.h -// - -#ifndef AS_DEBUG_H -#define AS_DEBUG_H - -#include "as_config.h" - -#if defined(AS_DEBUG) - -#ifndef AS_WII -// The Wii SDK doesn't have these, we'll survive without AS_DEBUG - -#ifndef _WIN32_WCE -// Neither does WinCE - - -#if defined(__GNUC__) || defined( AS_MARMALADE ) - -#ifdef __ghs__ -// WIIU defines __GNUC__ but types are not defined here in 'conventional' way -#include -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef signed short int16_t; -typedef unsigned short uint16_t; -typedef signed int int32_t; -typedef unsigned int uint32_t; -typedef signed long long int64_t; -typedef unsigned long long uint64_t; -typedef float float32_t; -typedef double float64_t; -#else -// Define mkdir for GNUC -#include -#include -#define _mkdir(dirname) mkdir(dirname, S_IRWXU) -#endif -#else -#include -#endif - - -#if defined(_MSC_VER) && defined(AS_PROFILE) -// Currently only do profiling with MSVC++ - -#include -#include "as_string.h" -#include "as_map.h" -#include "as_string_util.h" - -BEGIN_AS_NAMESPACE - -struct TimeCount -{ - double time; - int count; - double max; - double min; -}; - -class CProfiler -{ -public: - CProfiler() - { - // We need to know how often the clock is updated - __int64 tps; - if( !QueryPerformanceFrequency((LARGE_INTEGER *)&tps) ) - usePerformance = false; - else - { - usePerformance = true; - ticksPerSecond = double(tps); - } - - timeOffset = GetTime(); - } - - ~CProfiler() - { - WriteSummary(); - } - - double GetTime() - { - if( usePerformance ) - { - __int64 ticks; - QueryPerformanceCounter((LARGE_INTEGER *)&ticks); - - return double(ticks)/ticksPerSecond - timeOffset; - } - - return double(timeGetTime())/1000.0 - timeOffset; - } - - double Begin(const char *name) - { - double time = GetTime(); - - // Add the scope to the key - if( key.GetLength() ) - key += "|"; - key += name; - - // Compensate for the time spent writing to the file - timeOffset += GetTime() - time; - - return time; - } - - void End(const char *name, double beginTime) - { - double time = GetTime(); - - double elapsed = time - beginTime; - - // Update the profile info for this scope - asSMapNode *cursor; - if( map.MoveTo(&cursor, key) ) - { - cursor->value.time += elapsed; - cursor->value.count++; - if( cursor->value.max < elapsed ) - cursor->value.max = elapsed; - if( cursor->value.min > elapsed ) - cursor->value.min = elapsed; - } - else - { - TimeCount tc = {elapsed, 1, elapsed, elapsed}; - map.Insert(key, tc); - } - - // Remove the inner most scope from the key - int n = key.FindLast("|"); - if( n > 0 ) - key.SetLength(n); - else - key.SetLength(0); - - // Compensate for the time spent writing to the file - timeOffset += GetTime() - time; - } - -protected: - void WriteSummary() - { - // Write the analyzed info into a file for inspection - _mkdir("AS_DEBUG"); - FILE *fp; - #if _MSC_VER >= 1500 && !defined(AS_MARMALADE) - fopen_s(&fp, "AS_DEBUG/profiling_summary.txt", "wt"); - #else - fp = fopen("AS_DEBUG/profiling_summary.txt", "wt"); - #endif - if( fp == 0 ) - return; - - fprintf(fp, "%-60s %10s %15s %15s %15s %15s\n\n", "Scope", "Count", "Tot time", "Avg time", "Max time", "Min time"); - - asSMapNode *cursor; - map.MoveLast(&cursor); - while( cursor ) - { - asCString key = cursor->key; - int count; - int n = key.FindLast("|", &count); - if( count ) - { - key = asCString(" ", count) + key.SubString(n+1); - } - - fprintf(fp, "%-60s %10d %15.6f %15.6f %15.6f %15.6f\n", key.AddressOf(), cursor->value.count, cursor->value.time, cursor->value.time / cursor->value.count, cursor->value.max, cursor->value.min); - - map.MovePrev(&cursor, cursor); - } - - fclose(fp); - } - - double timeOffset; - double ticksPerSecond; - bool usePerformance; - - asCString key; - asCMap map; -}; - -extern CProfiler g_profiler; - -class CProfilerScope -{ -public: - CProfilerScope(const char *name) - { - this->name = name; - beginTime = g_profiler.Begin(name); - } - - ~CProfilerScope() - { - g_profiler.End(name, beginTime); - } - -protected: - const char *name; - double beginTime; -}; - -#define TimeIt(x) CProfilerScope profilescope(x) - -END_AS_NAMESPACE - -#else // _MSC_VER && AS_PROFILE - -// Define it so nothing is done -#define TimeIt(x) - -#endif // !(_MSC_VER && AS_PROFILE) - - - - - -#endif // _WIN32_WCE -#endif // AS_WII - -#else // !defined(AS_DEBUG) - -// Define it so nothing is done -#define TimeIt(x) - -#endif // !defined(AS_DEBUG) - -#endif - - diff --git a/dependencies/angelscript/source/as_gc.cpp b/dependencies/angelscript/source/as_gc.cpp deleted file mode 100644 index 2fe7ecd3..00000000 --- a/dependencies/angelscript/source/as_gc.cpp +++ /dev/null @@ -1,990 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_gc.cpp -// -// The implementation of the garbage collector -// - - -#include - -#include "as_gc.h" -#include "as_scriptengine.h" -#include "as_scriptobject.h" -#include "as_texts.h" - -BEGIN_AS_NAMESPACE - -asCGarbageCollector::asCGarbageCollector() -{ - engine = 0; - detectState = clearCounters_init; - destroyNewState = destroyGarbage_init; - destroyOldState = destroyGarbage_init; - numDestroyed = 0; - numNewDestroyed = 0; - numDetected = 0; - numAdded = 0; - isProcessing = false; - - seqAtSweepStart[0] = 0; - seqAtSweepStart[1] = 0; - seqAtSweepStart[2] = 0; -} - -asCGarbageCollector::~asCGarbageCollector() -{ - // This local typedef is done to workaround a compiler error on - // MSVC6 when using the typedef declared in the class definition - typedef asSMapNode_t node_t; - for( asUINT n = 0; n < freeNodes.GetLength(); n++ ) - asDELETE(freeNodes[n], node_t); - freeNodes.SetLength(0); -} - -int asCGarbageCollector::AddScriptObjectToGC(void *obj, asCObjectType *objType) -{ - if( obj == 0 || objType == 0 ) - { - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GC_RECEIVED_NULL_PTR); - return asINVALID_ARG; - } - - engine->CallObjectMethod(obj, objType->beh.addref); - asSObjTypePair ot = {obj, objType, 0}; - - // Invoke the garbage collector to destroy a little garbage as new comes in - // This will maintain the number of objects in the GC at a maintainable level without - // halting the application, and without burdening the application with manually invoking the - // garbage collector. - if( engine->ep.autoGarbageCollect && gcNewObjects.GetLength() ) - { - // If the GC is already processing in another thread, then don't try this again - if( TRYENTERCRITICALSECTION(gcCollecting) ) - { - // Skip this if the GC is already running in this thread - if( !isProcessing ) - { - isProcessing = true; - - // TODO: The number of iterations should be dynamic, and increase - // if the number of objects in the garbage collector grows high - - // Run one step of DetectGarbage - if( gcOldObjects.GetLength() ) - { - IdentifyGarbageWithCyclicRefs(); - DestroyOldGarbage(); - } - - // Run a few steps of DestroyGarbage - int iter = (int)gcNewObjects.GetLength(); - if( iter > 10 ) iter = 10; - while( iter-- > 0 ) - DestroyNewGarbage(); - - isProcessing = false; - } - - LEAVECRITICALSECTION(gcCollecting); - } - } - - // Add the data to the gcObjects array in a critical section as - // another thread might be calling this method at the same time - ENTERCRITICALSECTION(gcCritical); - ot.seqNbr = numAdded++; - gcNewObjects.PushLast(ot); - LEAVECRITICALSECTION(gcCritical); - - return ot.seqNbr; -} - -int asCGarbageCollector::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asIObjectType **type) -{ - if( seqNbr ) *seqNbr = 0; - if( obj ) *obj = 0; - if( type ) *type = 0; - - ENTERCRITICALSECTION(gcCritical); - asSObjTypePair *o = 0; - asUINT newObjs = asUINT(gcNewObjects.GetLength()); - if( idx < newObjs ) - o = &gcNewObjects[idx]; - else if( idx < gcOldObjects.GetLength() + newObjs ) - o = &gcOldObjects[idx-newObjs]; - else - { - LEAVECRITICALSECTION(gcCritical); - return asINVALID_ARG; - } - if( seqNbr ) *seqNbr = o->seqNbr; - if( obj ) *obj = o->obj; - if( type ) *type = o->type; - LEAVECRITICALSECTION(gcCritical); - - return asSUCCESS; -} - -// TODO: Should have a flag to tell the garbage collector to automatically determine how many iterations are needed -// It should then gather statistics such as how many objects has been created since last run, and how many objects -// are destroyed per iteration, and how many objects are detected as cyclic garbage per iteration. -// It should try to reach a stable number of objects, i.e. so that on average the number of objects added to -// the garbage collector is the same as the number of objects destroyed. And it should try to minimize the number -// of iterations of detections that must be executed per cycle while still identifying the cyclic garbage -// These variables should also be available for inspection through the gcstatistics. -int asCGarbageCollector::GarbageCollect(asDWORD flags, asUINT iterations) -{ - // If the GC is already processing in another thread, then don't enter here again - if( TRYENTERCRITICALSECTION(gcCollecting) ) - { - // If the GC is already processing in this thread, then don't enter here again - if( isProcessing ) - { - LEAVECRITICALSECTION(gcCollecting); - return 1; - } - - isProcessing = true; - - bool doDetect = (flags & asGC_DETECT_GARBAGE) || !(flags & asGC_DESTROY_GARBAGE); - bool doDestroy = (flags & asGC_DESTROY_GARBAGE) || !(flags & asGC_DETECT_GARBAGE); - - if( flags & asGC_FULL_CYCLE ) - { - // Reset the state - if( doDetect ) - { - // Move all new objects to the old list, so we guarantee that all is detected - MoveAllObjectsToOldList(); - detectState = clearCounters_init; - } - if( doDestroy ) - { - destroyNewState = destroyGarbage_init; - destroyOldState = destroyGarbage_init; - } - - // The full cycle only works with the objects in the old list so that the - // set of objects scanned for garbage is fixed even if new objects are added - // by other threads in parallel. - unsigned int count = (unsigned int)(gcOldObjects.GetLength()); - for(;;) - { - // Detect all garbage with cyclic references - if( doDetect ) - while( IdentifyGarbageWithCyclicRefs() == 1 ) {} - - // Now destroy all known garbage - if( doDestroy ) - { - if( !doDetect ) - while( DestroyNewGarbage() == 1 ) {} - while( DestroyOldGarbage() == 1 ) {} - } - - // Run another iteration if any garbage was destroyed - if( count != (unsigned int)(gcOldObjects.GetLength()) ) - count = (unsigned int)(gcOldObjects.GetLength()); - else - { - // Let the engine destroy the types that reached refCount 0 - // If none were destroyed, then leave the GC - // TODO: The asCObjectType should destroy its content when refCount reaches 0 - // since no-one is using them. The registered types should have their - // refcount increased by the config groups. Doing it like that will allow - // me to remove this call to ClearUnusedTypes() that the GC really - // shouldn't be calling. - if( engine->ClearUnusedTypes() == 0 ) - break; - } - } - - isProcessing = false; - LEAVECRITICALSECTION(gcCollecting); - return 0; - } - else - { - while( iterations-- > 0 ) - { - // Destroy the garbage that we know of - if( doDestroy ) - { - DestroyNewGarbage(); - DestroyOldGarbage(); - } - - // Run another incremental step of the identification of cyclic references - if( doDetect && gcOldObjects.GetLength() > 0 ) - IdentifyGarbageWithCyclicRefs(); - } - } - - isProcessing = false; - LEAVECRITICALSECTION(gcCollecting); - } - - // Return 1 to indicate that the cycle wasn't finished - return 1; -} - -// TODO: Additional statistics to gather -// -// - How many objects are added on average between each destroyed object -// - How many objects are added on average between each detected object -// - how many iterations are needed for each destroyed object -// - how many iterations are needed for each detected object -// -// The average must have a decay so that long running applications will not suffer -// from objects being created early on in the application and then never destroyed. -// -// This ought to be possible to accomplish by holding two buckets. -// Numbers will be accumulated in one bucket while the other is held fixed. -// When returning the average it should use a weighted average between the two buckets using the size as weight. -// When a bucket is filled up, the buckets are switched, and then new bucket is emptied to gather new statistics. -void asCGarbageCollector::GetStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const -{ - // It is not necessary to protect this with critical sections, however - // as it is not protected the variables can be filled in slightly different - // moments and might not match perfectly when inspected by the application - // afterwards. - - if( currentSize ) - *currentSize = (asUINT)(gcNewObjects.GetLength() + gcOldObjects.GetLength()); - - if( totalDestroyed ) - *totalDestroyed = numDestroyed; - - if( totalDetected ) - *totalDetected = numDetected; - - if( newObjects ) - *newObjects = (asUINT)gcNewObjects.GetLength(); - - if( totalNewDestroyed ) - *totalNewDestroyed = numNewDestroyed; -} - -asCGarbageCollector::asSObjTypePair asCGarbageCollector::GetNewObjectAtIdx(int idx) -{ - // We need to protect this access with a critical section as - // another thread might be appending an object at the same time - ENTERCRITICALSECTION(gcCritical); - asSObjTypePair gcObj = gcNewObjects[idx]; - LEAVECRITICALSECTION(gcCritical); - - return gcObj; -} - -asCGarbageCollector::asSObjTypePair asCGarbageCollector::GetOldObjectAtIdx(int idx) -{ - // We need to protect this access with a critical section as - // another thread might be appending an object at the same time - ENTERCRITICALSECTION(gcCritical); - asSObjTypePair gcObj = gcOldObjects[idx]; - LEAVECRITICALSECTION(gcCritical); - - return gcObj; -} - -void asCGarbageCollector::RemoveNewObjectAtIdx(int idx) -{ - // We need to protect this update with a critical section as - // another thread might be appending an object at the same time - ENTERCRITICALSECTION(gcCritical); - if( idx == (int)gcNewObjects.GetLength() - 1) - gcNewObjects.PopLast(); - else - gcNewObjects[idx] = gcNewObjects.PopLast(); - LEAVECRITICALSECTION(gcCritical); -} - -void asCGarbageCollector::RemoveOldObjectAtIdx(int idx) -{ - // We need to protect this update with a critical section as - // another thread might be appending an object at the same time - ENTERCRITICALSECTION(gcCritical); - if( idx == (int)gcOldObjects.GetLength() - 1) - gcOldObjects.PopLast(); - else - gcOldObjects[idx] = gcOldObjects.PopLast(); - LEAVECRITICALSECTION(gcCritical); -} - -void asCGarbageCollector::MoveObjectToOldList(int idx) -{ - // We need to protect this update with a critical section as - // another thread might be appending an object at the same time - ENTERCRITICALSECTION(gcCritical); - gcOldObjects.PushLast(gcNewObjects[idx]); - if( idx == (int)gcNewObjects.GetLength() - 1) - gcNewObjects.PopLast(); - else - gcNewObjects[idx] = gcNewObjects.PopLast(); - LEAVECRITICALSECTION(gcCritical); -} - -void asCGarbageCollector::MoveAllObjectsToOldList() -{ - // We need to protect this update with a critical section as - // another thread might be appending an object at the same time - ENTERCRITICALSECTION(gcCritical); - if( gcOldObjects.Concatenate(gcNewObjects) ) - gcNewObjects.SetLength(0); - LEAVECRITICALSECTION(gcCritical); -} - -int asCGarbageCollector::DestroyNewGarbage() -{ - // This function will only be called within the critical section gcCollecting - asASSERT(isProcessing); - - for(;;) - { - switch( destroyNewState ) - { - case destroyGarbage_init: - { - // If there are no objects to be freed then don't start - if( gcNewObjects.GetLength() == 0 ) - return 0; - - // Update the seqAtSweepStart which is used to determine when - // to move an object from the new set to the old set - seqAtSweepStart[0] = seqAtSweepStart[1]; - seqAtSweepStart[1] = seqAtSweepStart[2]; - seqAtSweepStart[2] = numAdded; - - destroyNewIdx = (asUINT)-1; - destroyNewState = destroyGarbage_loop; - } - break; - - case destroyGarbage_loop: - case destroyGarbage_haveMore: - { - // If the refCount has reached 1, then only the GC still holds a - // reference to the object, thus we don't need to worry about the - // application touching the objects during collection. - - // Destroy all objects that have refCount == 1. If any objects are - // destroyed, go over the list again, because it may have made more - // objects reach refCount == 1. - if( ++destroyNewIdx < gcNewObjects.GetLength() ) - { - asSObjTypePair gcObj = GetNewObjectAtIdx(destroyNewIdx); - if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 ) - { - // Release the object immediately - - // Make sure the refCount is really 0, because the - // destructor may have increased the refCount again. - bool addRef = false; - if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT ) - { - // Script objects may actually be resurrected in the destructor - int refCount = ((asCScriptObject*)gcObj.obj)->Release(); - if( refCount > 0 ) addRef = true; - } - else - engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release); - - // Was the object really destroyed? - if( !addRef ) - { - numDestroyed++; - numNewDestroyed++; - RemoveNewObjectAtIdx(destroyNewIdx); - destroyNewIdx--; - } - else - { - // Since the object was resurrected in the - // destructor, we must add our reference again - engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); - } - - destroyNewState = destroyGarbage_haveMore; - } - // Check if this object has been inspected 3 times already, and if so move it to the - // set of old objects that are less likely to become garbage in a short time - // TODO: Is 3 really a good value? Should the number of times be dynamic? - else if( gcObj.seqNbr < seqAtSweepStart[0] ) - { - // We've already verified this object multiple times. It is likely - // to live for quite a long time so we'll move it to the list if old objects - MoveObjectToOldList(destroyNewIdx); - destroyNewIdx--; - } - - // Allow the application to work a little - return 1; - } - else - { - if( destroyNewState == destroyGarbage_haveMore ) - { - // Restart the cycle - destroyNewState = destroyGarbage_init; - } - else - { - // Restart the cycle - destroyNewState = destroyGarbage_init; - - // Return 0 to tell the application that there - // is no more garbage to destroy at the moment - return 0; - } - } - } - break; - } - } - - // Shouldn't reach this point - UNREACHABLE_RETURN; -} - -int asCGarbageCollector::ReportAndReleaseUndestroyedObjects() -{ - // This function will only be called as the engine is shutting down - - int items = 0; - for( asUINT n = 0; n < gcOldObjects.GetLength(); n++ ) - { - asSObjTypePair gcObj = GetOldObjectAtIdx(n); - - int refCount = 0; - if( gcObj.type->beh.gcGetRefCount && engine->scriptFunctions[gcObj.type->beh.gcGetRefCount] ) - refCount = engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount); - - // Report the object as not being properly destroyed - asCString msg; - msg.Format(TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s_REF_COUNT_d, gcObj.seqNbr, gcObj.type->name.AddressOf(), refCount - 1); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - - // Add additional info for builtin types - if( gcObj.type->name == "_builtin_function_" ) - { - // Unfortunately we can't show the function declaration here, because the engine may have released the parameter list already so the declaration would only be misleading - // We need to show the function type too as for example delegates do not have a name - msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, reinterpret_cast(gcObj.obj)->GetName(), reinterpret_cast(gcObj.obj)->GetFuncType()); - engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); - } - else if( gcObj.type->name == "_builtin_objecttype_" ) - { - msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast(gcObj.obj)->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); - } - else if( gcObj.type->name == "_builtin_globalprop_" ) - { - msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast(gcObj.obj)->name.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); - } - - // Release the reference that the GC holds if the release functions is still available - if( gcObj.type->beh.release && engine->scriptFunctions[gcObj.type->beh.release] ) - engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release); - - items++; - } - return items; -} - -int asCGarbageCollector::DestroyOldGarbage() -{ - // This function will only be called within the critical section gcCollecting - asASSERT(isProcessing); - - for(;;) - { - switch( destroyOldState ) - { - case destroyGarbage_init: - { - // If there are no objects to be freed then don't start - if( gcOldObjects.GetLength() == 0 ) - return 0; - - destroyOldIdx = (asUINT)-1; - destroyOldState = destroyGarbage_loop; - } - break; - - case destroyGarbage_loop: - case destroyGarbage_haveMore: - { - // If the refCount has reached 1, then only the GC still holds a - // reference to the object, thus we don't need to worry about the - // application touching the objects during collection. - - // Destroy all objects that have refCount == 1. If any objects are - // destroyed, go over the list again, because it may have made more - // objects reach refCount == 1. - if( ++destroyOldIdx < gcOldObjects.GetLength() ) - { - asSObjTypePair gcObj = GetOldObjectAtIdx(destroyOldIdx); - - if( gcObj.type->beh.gcGetRefCount == 0 ) - { - // If circular references are formed with registered types that hasn't - // registered the GC behaviours, then the engine may be forced to free - // the object type before the actual object instance. In this case we - // will be forced to skip the destruction of the objects, so as not to - // crash the application. - asCString msg; - msg.Format(TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s, gcObj.seqNbr, gcObj.type->name.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - - // Just remove the object, as we will not bother to destroy it - numDestroyed++; - RemoveOldObjectAtIdx(destroyOldIdx); - destroyOldIdx--; - } - else if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 ) - { - // Release the object immediately - - // Make sure the refCount is really 0, because the - // destructor may have increased the refCount again. - bool addRef = false; - if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT ) - { - // Script objects may actually be resurrected in the destructor - int refCount = ((asCScriptObject*)gcObj.obj)->Release(); - if( refCount > 0 ) addRef = true; - } - else - engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release); - - // Was the object really destroyed? - if( !addRef ) - { - numDestroyed++; - RemoveOldObjectAtIdx(destroyOldIdx); - destroyOldIdx--; - } - else - { - // Since the object was resurrected in the - // destructor, we must add our reference again - engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); - } - - destroyOldState = destroyGarbage_haveMore; - } - - // Allow the application to work a little - return 1; - } - else - { - if( destroyOldState == destroyGarbage_haveMore ) - { - // Restart the cycle - destroyOldState = destroyGarbage_init; - } - else - { - // Restart the cycle - destroyOldState = destroyGarbage_init; - - // Return 0 to tell the application that there - // is no more garbage to destroy at the moment - return 0; - } - } - } - break; - } - } - - // Shouldn't reach this point - UNREACHABLE_RETURN; -} - -int asCGarbageCollector::IdentifyGarbageWithCyclicRefs() -{ - // This function will only be called within the critical section gcCollecting - asASSERT(isProcessing); - - for(;;) - { - switch( detectState ) - { - case clearCounters_init: - detectState = clearCounters_loop; - break; - - case clearCounters_loop: - { - // Decrease reference counter for all objects removed from the map - asSMapNode *cursor = 0; - gcMap.MoveFirst(&cursor); - if( cursor ) - { - void *obj = gcMap.GetKey(cursor); - asSIntTypePair it = gcMap.GetValue(cursor); - - engine->CallObjectMethod(obj, it.type->beh.release); - - ReturnNode(gcMap.Remove(cursor)); - - return 1; - } - - detectState = buildMap_init; - } - break; - - case buildMap_init: - detectIdx = 0; - detectState = buildMap_loop; - break; - - case buildMap_loop: - { - // Build a map of objects that will be checked, the map will - // hold the object pointer as key, and the gcCount and the - // object's type as value. As objects are added to the map the - // gcFlag must be set in the objects, so we can be verify if - // the object is accessed during the GC cycle. - - // If an object is removed from the gcObjects list during the - // iteration of this step, it is possible that an object won't - // be used during the analyzing for cyclic references. This - // isn't a problem, as the next time the GC cycle starts the - // object will be verified. - if( detectIdx < gcOldObjects.GetLength() ) - { - // Add the gc count for this object - asSObjTypePair gcObj = GetOldObjectAtIdx(detectIdx); - - int refCount = 0; - if( gcObj.type->beh.gcGetRefCount ) - refCount = engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount); - - if( refCount > 1 ) - { - asSIntTypePair it = {refCount-1, gcObj.type}; - - gcMap.Insert(GetNode(gcObj.obj, it)); - - // Increment the object's reference counter when putting it in the map - engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); - - // Mark the object so that we can - // see if it has changed since read - engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.gcSetFlag); - } - - detectIdx++; - - // Let the application work a little - return 1; - } - else - detectState = countReferences_init; - } - break; - - case countReferences_init: - { - gcMap.MoveFirst(&gcMapCursor); - detectState = countReferences_loop; - } - break; - - case countReferences_loop: - { - // Call EnumReferences on all objects in the map to count the number - // of references reachable from between objects in the map. If all - // references for an object in the map is reachable from other objects - // in the map, then we know that no outside references are held for - // this object, thus it is a potential dead object in a circular reference. - - // If the gcFlag is cleared for an object we consider the object alive - // and referenced from outside the GC, thus we don't enumerate its references. - - // Any new objects created after this step in the GC cycle won't be - // in the map, and is thus automatically considered alive. - if( gcMapCursor ) - { - void *obj = gcMap.GetKey(gcMapCursor); - asCObjectType *type = gcMap.GetValue(gcMapCursor).type; - gcMap.MoveNext(&gcMapCursor, gcMapCursor); - - if( engine->CallObjectMethodRetBool(obj, type->beh.gcGetFlag) ) - { - engine->CallObjectMethod(obj, engine, type->beh.gcEnumReferences); - } - - // Allow the application to work a little - return 1; - } - else - detectState = detectGarbage_init; - } - break; - - case detectGarbage_init: - { - gcMap.MoveFirst(&gcMapCursor); - liveObjects.SetLength(0); - detectState = detectGarbage_loop1; - } - break; - - case detectGarbage_loop1: - { - // All objects that are known not to be dead must be removed from the map, - // along with all objects they reference. What remains in the map after - // this pass is sure to be dead objects in circular references. - - // An object is considered alive if its gcFlag is cleared, or all the - // references were not found in the map. - - // Add all alive objects from the map to the liveObjects array - if( gcMapCursor ) - { - asSMapNode *cursor = gcMapCursor; - gcMap.MoveNext(&gcMapCursor, gcMapCursor); - - void *obj = gcMap.GetKey(cursor); - asSIntTypePair it = gcMap.GetValue(cursor); - - bool gcFlag = engine->CallObjectMethodRetBool(obj, it.type->beh.gcGetFlag); - if( !gcFlag || it.i > 0 ) - { - liveObjects.PushLast(obj); - } - - // Allow the application to work a little - return 1; - } - else - detectState = detectGarbage_loop2; - } - break; - - case detectGarbage_loop2: - { - // In this step we are actually removing the alive objects from the map. - // As the object is removed, all the objects it references are added to the - // liveObjects list, by calling EnumReferences. Only objects still in the map - // will be added to the liveObjects list. - if( liveObjects.GetLength() ) - { - void *gcObj = liveObjects.PopLast(); - asCObjectType *type = 0; - - // Remove the object from the map to mark it as alive - asSMapNode *cursor = 0; - if( gcMap.MoveTo(&cursor, gcObj) ) - { - type = gcMap.GetValue(cursor).type; - ReturnNode(gcMap.Remove(cursor)); - - // We need to decrease the reference count again as we remove the object from the map - engine->CallObjectMethod(gcObj, type->beh.release); - - // Enumerate all the object's references so that they too can be marked as alive - engine->CallObjectMethod(gcObj, engine, type->beh.gcEnumReferences); - } - - // Allow the application to work a little - return 1; - } - else - detectState = verifyUnmarked_init; - } - break; - - case verifyUnmarked_init: - gcMap.MoveFirst(&gcMapCursor); - detectState = verifyUnmarked_loop; - break; - - case verifyUnmarked_loop: - { - // In this step we must make sure that none of the objects still in the map - // has been touched by the application. If they have then we must run the - // detectGarbage loop once more. - if( gcMapCursor ) - { - void *gcObj = gcMap.GetKey(gcMapCursor); - asCObjectType *type = gcMap.GetValue(gcMapCursor).type; - - bool gcFlag = engine->CallObjectMethodRetBool(gcObj, type->beh.gcGetFlag); - if( !gcFlag ) - { - // The unmarked object was touched, rerun the detectGarbage loop - detectState = detectGarbage_init; - } - else - gcMap.MoveNext(&gcMapCursor, gcMapCursor); - - // Allow the application to work a little - return 1; - } - else - { - // No unmarked object was touched, we can now be sure - // that objects that have gcCount == 0 really is garbage - detectState = breakCircles_init; - } - } - break; - - case breakCircles_init: - { - gcMap.MoveFirst(&gcMapCursor); - detectState = breakCircles_loop; - } - break; - - case breakCircles_loop: - case breakCircles_haveGarbage: - { - // All objects in the map are now known to be dead objects - // kept alive through circular references. To be able to free - // these objects we need to force the breaking of the circle - // by having the objects release their references. - if( gcMapCursor ) - { - numDetected++; - void *gcObj = gcMap.GetKey(gcMapCursor); - asCObjectType *type = gcMap.GetValue(gcMapCursor).type; - if( type->flags & asOBJ_SCRIPT_OBJECT ) - { - // For script objects we must call the class destructor before - // releasing the references, otherwise the destructor may not - // be able to perform the necessary clean-up as the handles will - // be null. - reinterpret_cast(gcObj)->CallDestructor(); - } - engine->CallObjectMethod(gcObj, engine, type->beh.gcReleaseAllReferences); - - gcMap.MoveNext(&gcMapCursor, gcMapCursor); - - detectState = breakCircles_haveGarbage; - - // Allow the application to work a little - return 1; - } - else - { - // If no garbage was detected we can finish now - if( detectState != breakCircles_haveGarbage ) - { - // Restart the GC - detectState = clearCounters_init; - return 0; - } - else - { - // Restart the GC - detectState = clearCounters_init; - return 1; - } - } - } - } // switch - } - - // Shouldn't reach this point - UNREACHABLE_RETURN; -} - -asCGarbageCollector::asSMapNode_t *asCGarbageCollector::GetNode(void *obj, asSIntTypePair it) -{ - // This function will only be called within the critical section gcCollecting - asASSERT(isProcessing); - - asSMapNode_t *node; - if( freeNodes.GetLength() ) - node = freeNodes.PopLast(); - else - { - node = asNEW(asSMapNode_t); - if( !node ) - { - // Out of memory - return 0; - } - } - - node->Init(obj, it); - return node; -} - -void asCGarbageCollector::ReturnNode(asSMapNode_t *node) -{ - // This function will only be called within the critical section gcCollecting - asASSERT(isProcessing); - - if( node ) - freeNodes.PushLast(node); -} - -void asCGarbageCollector::GCEnumCallback(void *reference) -{ - // This function will only be called within the critical section gcCollecting - asASSERT(isProcessing); - - if( detectState == countReferences_loop ) - { - // Find the reference in the map - asSMapNode *cursor = 0; - if( gcMap.MoveTo(&cursor, reference) ) - { - // Decrease the counter in the map for the reference - gcMap.GetValue(cursor).i--; - } - } - else if( detectState == detectGarbage_loop2 ) - { - // Find the reference in the map - asSMapNode *cursor = 0; - if( gcMap.MoveTo(&cursor, reference) ) - { - // Add the object to the list of objects to mark as alive - liveObjects.PushLast(reference); - } - } -} - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_gc.h b/dependencies/angelscript/source/as_gc.h deleted file mode 100644 index 7d6cdd56..00000000 --- a/dependencies/angelscript/source/as_gc.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_gc.h -// -// The garbage collector is used to resolve cyclic references -// - - - -#ifndef AS_GC_H -#define AS_GC_H - -#include "as_config.h" -#include "as_array.h" -#include "as_map.h" -#include "as_thread.h" - -BEGIN_AS_NAMESPACE - -class asCScriptEngine; -class asCObjectType; - -class asCGarbageCollector -{ -public: - asCGarbageCollector(); - ~asCGarbageCollector(); - - int GarbageCollect(asDWORD flags, asUINT iterations); - void GetStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const; - void GCEnumCallback(void *reference); - int AddScriptObjectToGC(void *obj, asCObjectType *objType); - int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asIObjectType **type); - - int ReportAndReleaseUndestroyedObjects(); - - asCScriptEngine *engine; - -protected: - struct asSObjTypePair {void *obj; asCObjectType *type; asUINT seqNbr;}; - struct asSIntTypePair {int i; asCObjectType *type;}; - typedef asSMapNode asSMapNode_t; - - enum egcDestroyState - { - destroyGarbage_init = 0, - destroyGarbage_loop, - destroyGarbage_haveMore - }; - - enum egcDetectState - { - clearCounters_init = 0, - clearCounters_loop, - buildMap_init, - buildMap_loop, - countReferences_init, - countReferences_loop, - detectGarbage_init, - detectGarbage_loop1, - detectGarbage_loop2, - verifyUnmarked_init, - verifyUnmarked_loop, - breakCircles_init, - breakCircles_loop, - breakCircles_haveGarbage - }; - - int DestroyNewGarbage(); - int DestroyOldGarbage(); - int IdentifyGarbageWithCyclicRefs(); - asSObjTypePair GetNewObjectAtIdx(int idx); - asSObjTypePair GetOldObjectAtIdx(int idx); - void RemoveNewObjectAtIdx(int idx); - void RemoveOldObjectAtIdx(int idx); - void MoveObjectToOldList(int idx); - void MoveAllObjectsToOldList(); - - // Holds all the objects known by the garbage collector - asCArray gcNewObjects; - asCArray gcOldObjects; - - // This array temporarily holds references to objects known to be live objects - asCArray liveObjects; - - // This map holds objects currently being searched for cyclic references, it also holds a - // counter that gives the number of references to the object that the GC can't reach - asCMap gcMap; - - // State variables - egcDestroyState destroyNewState; - egcDestroyState destroyOldState; - asUINT destroyNewIdx; - asUINT destroyOldIdx; - asUINT numDestroyed; - asUINT numNewDestroyed; - egcDetectState detectState; - asUINT detectIdx; - asUINT numDetected; - asUINT numAdded; - asUINT seqAtSweepStart[3]; - asSMapNode_t *gcMapCursor; - bool isProcessing; - - // We'll keep a pool of nodes to avoid allocating memory all the time - asSMapNode_t *GetNode(void *obj, asSIntTypePair it); - void ReturnNode(asSMapNode_t *node); - asCArray freeNodes; - - // Critical section for multithreaded access - DECLARECRITICALSECTION(gcCritical) // Used for adding/removing objects - DECLARECRITICALSECTION(gcCollecting) // Used for processing -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_generic.cpp b/dependencies/angelscript/source/as_generic.cpp deleted file mode 100644 index 0ba432df..00000000 --- a/dependencies/angelscript/source/as_generic.cpp +++ /dev/null @@ -1,520 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_generic.cpp -// -// This class handles the call to a function registered with asCALL_GENERIC -// - -#include "as_generic.h" -#include "as_scriptfunction.h" -#include "as_objecttype.h" -#include "as_scriptengine.h" - -BEGIN_AS_NAMESPACE - -// TODO: runtime optimize: The access to the arguments should be optimized so that code -// doesn't have to count the position of the argument with every call - -// internal -asCGeneric::asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer) -{ - this->engine = engine; - this->sysFunction = sysFunction; - this->currentObject = currentObject; - this->stackPointer = stackPointer; - - objectRegister = 0; - returnVal = 0; -} - -// internal -asCGeneric::~asCGeneric() -{ -} - -// interface -asIScriptEngine *asCGeneric::GetEngine() const -{ - return (asIScriptEngine*)engine; -} - -// interface -asIScriptFunction *asCGeneric::GetFunction() const -{ - return sysFunction; -} - -// interface -void *asCGeneric::GetObject() -{ - return currentObject; -} - -// interface -int asCGeneric::GetObjectTypeId() const -{ - asCDataType dt = asCDataType::CreateObject(sysFunction->objectType, false); - return engine->GetTypeIdFromDataType(dt); -} - -// interface -int asCGeneric::GetArgCount() const -{ - return (int)sysFunction->parameterTypes.GetLength(); -} - -// interface -asBYTE asCGeneric::GetArgByte(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - return 0; - - if( dt->GetSizeInMemoryBytes() != 1 ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Get the value - return *(asBYTE*)&stackPointer[offset]; -} - -// interface -asWORD asCGeneric::GetArgWord(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - return 0; - - if( dt->GetSizeInMemoryBytes() != 2 ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Get the value - return *(asWORD*)&stackPointer[offset]; -} - -// interface -asDWORD asCGeneric::GetArgDWord(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - return 0; - - if( dt->GetSizeInMemoryBytes() != 4 ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Get the value - return *(asDWORD*)&stackPointer[offset]; -} - -// interface -asQWORD asCGeneric::GetArgQWord(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - return 0; - - if( dt->GetSizeInMemoryBytes() != 8 ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Get the value - return *(asQWORD*)(&stackPointer[offset]); -} - -// interface -float asCGeneric::GetArgFloat(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - return 0; - - if( dt->GetSizeInMemoryBytes() != 4 ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Get the value - return *(float*)(&stackPointer[offset]); -} - -// interface -double asCGeneric::GetArgDouble(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->IsObject() || dt->IsReference() ) - return 0; - - if( dt->GetSizeInMemoryBytes() != 8 ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Get the value - return *(double*)(&stackPointer[offset]); -} - -// interface -void *asCGeneric::GetArgAddress(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( !dt->IsReference() && !dt->IsObjectHandle() ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Get the value - return (void*)*(asPWORD*)(&stackPointer[offset]); -} - -// interface -void *asCGeneric::GetArgObject(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( !dt->IsObject() ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Get the value - return *(void**)(&stackPointer[offset]); -} - -// interface -void *asCGeneric::GetAddressOfArg(asUINT arg) -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // For object variables it's necessary to dereference the pointer to get the address of the value - if( !sysFunction->parameterTypes[arg].IsReference() && - sysFunction->parameterTypes[arg].IsObject() && - !sysFunction->parameterTypes[arg].IsObjectHandle() ) - return *(void**)&stackPointer[offset]; - - // Get the address of the value - return &stackPointer[offset]; -} - -// interface -int asCGeneric::GetArgTypeId(asUINT arg, asDWORD *flags) const -{ - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; - - if( flags ) - { - *flags = sysFunction->inOutFlags[arg]; - *flags |= sysFunction->parameterTypes[arg].IsReadOnly() ? asTM_CONST : 0; - } - - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( dt->GetTokenType() != ttQuestion ) - return engine->GetTypeIdFromDataType(*dt); - else - { - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); - - // Skip the actual value to get to the type id - offset += AS_PTR_SIZE; - - // Get the value - return stackPointer[offset]; - } -} - -// interface -int asCGeneric::SetReturnByte(asBYTE val) -{ - // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; - - if( sysFunction->returnType.GetSizeInMemoryBytes() != 1 ) - return asINVALID_TYPE; - - // Store the value - *(asBYTE*)&returnVal = val; - - return 0; -} - -// interface -int asCGeneric::SetReturnWord(asWORD val) -{ - // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; - - if( sysFunction->returnType.GetSizeInMemoryBytes() != 2 ) - return asINVALID_TYPE; - - // Store the value - *(asWORD*)&returnVal = val; - - return 0; -} - -// interface -int asCGeneric::SetReturnDWord(asDWORD val) -{ - // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; - - if( sysFunction->returnType.GetSizeInMemoryBytes() != 4 ) - return asINVALID_TYPE; - - // Store the value - *(asDWORD*)&returnVal = val; - - return 0; -} - -// interface -int asCGeneric::SetReturnQWord(asQWORD val) -{ - // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; - - if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) - return asINVALID_TYPE; - - // Store the value - returnVal = val; - - return 0; -} - -// interface -int asCGeneric::SetReturnFloat(float val) -{ - // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; - - if( sysFunction->returnType.GetSizeOnStackDWords() != 1 ) - return asINVALID_TYPE; - - // Store the value - *(float*)&returnVal = val; - - return 0; -} - -// interface -int asCGeneric::SetReturnDouble(double val) -{ - // Verify the type of the return value - if( sysFunction->returnType.IsObject() || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; - - if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) - return asINVALID_TYPE; - - // Store the value - *(double*)&returnVal = val; - - return 0; -} - -// interface -int asCGeneric::SetReturnAddress(void *val) -{ - // Verify the type of the return value - if( sysFunction->returnType.IsReference() ) - { - // Store the value - *(void**)&returnVal = val; - return 0; - } - else if( sysFunction->returnType.IsObjectHandle() ) - { - // Store the handle without increasing reference - objectRegister = val; - return 0; - } - - return asINVALID_TYPE; -} - -// interface -int asCGeneric::SetReturnObject(void *obj) -{ - asCDataType *dt = &sysFunction->returnType; - if( !dt->IsObject() ) - return asINVALID_TYPE; - - if( dt->IsReference() ) - { - *(void**)&returnVal = obj; - return 0; - } - - if( dt->IsObjectHandle() ) - { - // Increase the reference counter - asSTypeBehaviour *beh = &dt->GetObjectType()->beh; - if( obj && beh->addref ) - engine->CallObjectMethod(obj, beh->addref); - } - else - { - // If function returns object by value the memory is already allocated. - // Here we should just initialize that memory by calling the copy constructor - // or the default constructor followed by the assignment operator - void *mem = (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE]; - engine->ConstructScriptObjectCopy(mem, obj, dt->GetObjectType()); - return 0; - } - - objectRegister = obj; - - return 0; -} - -// internal -void *asCGeneric::GetReturnPointer() -{ - asCDataType &dt = sysFunction->returnType; - - if( dt.IsObject() && !dt.IsReference() ) - { - // This function doesn't support returning on the stack but the use of - // the function doesn't require it so we don't need to implement it here. - asASSERT( !sysFunction->DoesReturnOnStack() ); - - return &objectRegister; - } - - return &returnVal; -} - -// interface -void *asCGeneric::GetAddressOfReturnLocation() -{ - asCDataType &dt = sysFunction->returnType; - - if( dt.IsObject() && !dt.IsReference() ) - { - if( sysFunction->DoesReturnOnStack() ) - { - // The memory is already preallocated on the stack, - // and the pointer to the location is found before the first arg - return (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE]; - } - - // Reference types store the handle in the objectReference - return &objectRegister; - } - - // Primitive types and references are stored in the returnVal property - return &returnVal; -} - -// interface -int asCGeneric::GetReturnTypeId(asDWORD *flags) const -{ - return sysFunction->GetReturnTypeId(flags); -} - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/source/as_generic.h b/dependencies/angelscript/source/as_generic.h deleted file mode 100644 index d45137e9..00000000 --- a/dependencies/angelscript/source/as_generic.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_generic.h -// -// This class handles the call to a function registered with asCALL_GENERIC -// - - -#ifndef AS_GENERIC_H -#define AS_GENERIC_H - -#include "as_config.h" - -BEGIN_AS_NAMESPACE - -class asCScriptEngine; -class asCScriptFunction; - -class asCGeneric : public asIScriptGeneric -{ -public: -//------------------------------ -// asIScriptGeneric -//------------------------------ - // Miscellaneous - asIScriptEngine *GetEngine() const; - asIScriptFunction *GetFunction() const; - - // Object - void *GetObject(); - int GetObjectTypeId() const; - - // Arguments - int GetArgCount() const; - int GetArgTypeId(asUINT arg, asDWORD *flags = 0) const; - asBYTE GetArgByte(asUINT arg); - asWORD GetArgWord(asUINT arg); - asDWORD GetArgDWord(asUINT arg); - asQWORD GetArgQWord(asUINT arg); - float GetArgFloat(asUINT arg); - double GetArgDouble(asUINT arg); - void *GetArgAddress(asUINT arg); - void *GetArgObject(asUINT arg); - void *GetAddressOfArg(asUINT arg); - - // Return value - int GetReturnTypeId(asDWORD *flags = 0) const; - int SetReturnByte(asBYTE val); - int SetReturnWord(asWORD val); - int SetReturnDWord(asDWORD val); - int SetReturnQWord(asQWORD val); - int SetReturnFloat(float val); - int SetReturnDouble(double val); - int SetReturnAddress(void *addr); - int SetReturnObject(void *obj); - void *GetAddressOfReturnLocation(); - -//------------------------ -// internal -//------------------------- - asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer); - virtual ~asCGeneric(); - - void *GetReturnPointer(); - - asCScriptEngine *engine; - asCScriptFunction *sysFunction; - void *currentObject; - asDWORD *stackPointer; - void *objectRegister; - - asQWORD returnVal; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_globalproperty.cpp b/dependencies/angelscript/source/as_globalproperty.cpp deleted file mode 100644 index 92208095..00000000 --- a/dependencies/angelscript/source/as_globalproperty.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - - -#include "as_config.h" -#include "as_property.h" -#include "as_scriptengine.h" - -BEGIN_AS_NAMESPACE - -asCGlobalProperty::asCGlobalProperty() -{ - memory = &storage; - memoryAllocated = false; - realAddress = 0; - initFunc = 0; - accessMask = 0xFFFFFFFF; - - refCount.set(1); -} - -asCGlobalProperty::~asCGlobalProperty() -{ -#ifndef WIP_16BYTE_ALIGNED - if( memoryAllocated ) { asDELETEARRAY(memory); } -#else - if( memoryAllocated ) { asDELETEARRAYALIGNED(memory); } -#endif - - if( initFunc ) - initFunc->Release(); -} - -void asCGlobalProperty::AddRef() -{ - gcFlag = false; - refCount.atomicInc(); -} - -void asCGlobalProperty::Release() -{ - gcFlag = false; - - // The property doesn't delete itself. The - // engine will do that at a later time - if( refCount.atomicDec() == 2 && initFunc ) - { - // Since the initFunc holds references to the property, - // we'll release it when we reach refCount 2. This will - // break the circle and allow the engine to free the property - // without the need for the GC to attempt finding circular - // references. - initFunc->Release(); - initFunc = 0; - } -} - -void *asCGlobalProperty::GetAddressOfValue() -{ - return memory; -} - -// The global property structure is responsible for allocating the storage -// method for script declared variables. Each allocation is independent of -// other global properties, so that variables can be added and removed at -// any time. -void asCGlobalProperty::AllocateMemory() -{ - if( type.GetSizeOnStackDWords() > 2 ) - { -#ifndef WIP_16BYTE_ALIGNED - memory = asNEWARRAY(asDWORD, type.GetSizeOnStackDWords()); -#else - // TODO: Avoid aligned allocation if not needed to reduce the waste of memory for the alignment - memory = asNEWARRAYALIGNED(asDWORD, type.GetSizeOnStackDWords(), type.GetAlignment()); -#endif - memoryAllocated = true; - } -} - -void asCGlobalProperty::SetRegisteredAddress(void *p) -{ - realAddress = p; - if( type.IsObject() && !type.IsReference() && !type.IsObjectHandle() ) - { - // The global property is a pointer to a pointer - memory = &realAddress; - } - else - memory = p; -} - -void *asCGlobalProperty::GetRegisteredAddress() const -{ - return realAddress; -} - -int asCGlobalProperty::GetRefCount() -{ - return refCount.get(); -} - -void asCGlobalProperty::SetGCFlag() -{ - gcFlag = true; -} - -bool asCGlobalProperty::GetGCFlag() -{ - return gcFlag; -} - -void asCGlobalProperty::EnumReferences(asIScriptEngine *engine) -{ - engine->GCEnumCallback(initFunc); -} - -void asCGlobalProperty::ReleaseAllHandles(asIScriptEngine *) -{ - if( initFunc ) - { - initFunc->Release(); - initFunc = 0; - } -} - -void asCGlobalProperty::Orphan(asCModule *module) -{ - if( initFunc && initFunc->module == module ) - { - // The owning module is releasing the property, so we need to notify - // the GC in order to resolve any circular references that may exists - - // This will add the property - initFunc->engine->gc.AddScriptObjectToGC(this, &initFunc->engine->globalPropertyBehaviours); - - // This will add the function - initFunc->AddRef(); - initFunc->Orphan(module); - } - - Release(); -} - -void asCGlobalProperty::SetInitFunc(asCScriptFunction *initFunc) -{ - // This should only be done once - asASSERT( this->initFunc == 0 ); - - this->initFunc = initFunc; - this->initFunc->AddRef(); -} - -asCScriptFunction *asCGlobalProperty::GetInitFunc() -{ - return initFunc; -} - - -#ifdef AS_MAX_PORTABILITY - -static void GlobalProperty_AddRef_Generic(asIScriptGeneric *gen) -{ - asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject(); - self->AddRef(); -} - -static void GlobalProperty_Release_Generic(asIScriptGeneric *gen) -{ - asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject(); - self->Release(); -} - -static void GlobalProperty_GetRefCount_Generic(asIScriptGeneric *gen) -{ - asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); -} - -static void GlobalProperty_SetGCFlag_Generic(asIScriptGeneric *gen) -{ - asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject(); - self->SetGCFlag(); -} - -static void GlobalProperty_GetGCFlag_Generic(asIScriptGeneric *gen) -{ - asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag(); -} - -static void GlobalProperty_EnumReferences_Generic(asIScriptGeneric *gen) -{ - asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); -} - -static void GlobalProperty_ReleaseAllHandles_Generic(asIScriptGeneric *gen) -{ - asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllHandles(engine); -} - -#endif - - -void asCGlobalProperty::RegisterGCBehaviours(asCScriptEngine *engine) -{ - // Register the gc behaviours for the global properties - int r = 0; - UNUSED_VAR(r); // It is only used in debug mode - engine->globalPropertyBehaviours.engine = engine; - engine->globalPropertyBehaviours.flags = asOBJ_REF | asOBJ_GC; - engine->globalPropertyBehaviours.name = "_builtin_globalprop_"; -#ifndef AS_MAX_PORTABILITY - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCGlobalProperty,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCGlobalProperty,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCGlobalProperty,GetRefCount), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCGlobalProperty,SetGCFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCGlobalProperty,GetGCFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCGlobalProperty,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCGlobalProperty,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 ); -#else - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(GlobalProperty_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(GlobalProperty_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(GlobalProperty_GetRefCount_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(GlobalProperty_SetGCFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(GlobalProperty_GetGCFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(GlobalProperty_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(GlobalProperty_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); -#endif -} - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/source/as_map.h b/dependencies/angelscript/source/as_map.h deleted file mode 100644 index 6a9b919e..00000000 --- a/dependencies/angelscript/source/as_map.h +++ /dev/null @@ -1,786 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_map.h -// -// This class is used for mapping a value to another -// - - -#ifndef AS_MAP_H -#define AS_MAP_H - -template struct asSMapNode; - -template class asCMap -{ -public: - asCMap(); - ~asCMap(); - - int Insert(const KEY &key, const VAL &value); - int Insert(asSMapNode *node); - int GetCount() const; - - const KEY &GetKey(const asSMapNode *cursor) const; - const VAL &GetValue(const asSMapNode *cursor) const; - VAL &GetValue(asSMapNode *cursor); - - void Erase(asSMapNode *cursor); - asSMapNode *Remove(asSMapNode *cursor); - void EraseAll(); - - void SwapWith(asCMap &other); - - // Returns true as long as cursor is valid - - bool MoveTo(asSMapNode **out, const KEY &key) const; - bool MoveFirst(asSMapNode **out) const; - bool MoveLast(asSMapNode **out) const; - bool MoveNext(asSMapNode **out, asSMapNode *cursor) const; - bool MovePrev(asSMapNode **out, asSMapNode *cursor) const; - - // For debugging only - - int CheckIntegrity(asSMapNode *node) const; - -protected: - // Don't allow value assignment - asCMap &operator=(const asCMap &) { return *this; } - - void BalanceInsert(asSMapNode *node); - void BalanceErase(asSMapNode *child, asSMapNode *parent); - - int EraseAll(asSMapNode *node); - int RotateLeft(asSMapNode *node); - int RotateRight(asSMapNode *node); - - asSMapNode *root; - asSMapNode dummy; - - int count; -}; - -//--------------------------------------------------------------------------- -// Implementation - -// Properties of a Red-Black Tree -// -// 1. The root is always black -// 2. All single paths from the root to leafs -// contain the same amount of black nodes -// 3. No red node can have a red node as parent - -#define ISRED(x) ((x != 0) && (x)->isRed) -#define ISBLACK(x) (!ISRED(x)) - -template struct asSMapNode -{ - asSMapNode() {parent = 0; left = 0; right = 0; isRed = true;} - void Init(KEY k, VAL v) {key = k; value = v; parent = 0; left = 0; right = 0; isRed = true;} - - asSMapNode *parent; - asSMapNode *left; - asSMapNode *right; - bool isRed; - - KEY key; - VAL value; -}; - -template -asCMap::asCMap() -{ - root = 0; - count = 0; -} - -template -asCMap::~asCMap() -{ - EraseAll(); -} - -template -void asCMap::SwapWith(asCMap &other) -{ - asSMapNode *tmpRoot = root; - int tmpCount = count; - - root = other.root; - count = other.count; - - other.root = tmpRoot; - other.count = tmpCount; -} - -template -void asCMap::EraseAll() -{ - EraseAll(root); - root = 0; -} - -template -int asCMap::EraseAll(asSMapNode *p) -{ - if( p == 0 ) return -1; - - EraseAll( p->left ); - EraseAll( p->right ); - - typedef asSMapNode node_t; - asDELETE(p,node_t); - - count--; - - return 0; -} - -template -int asCMap::GetCount() const -{ - return count; -} - -template -int asCMap::Insert(const KEY &key, const VAL &value) -{ - typedef asSMapNode node_t; - asSMapNode *nnode = asNEW(node_t); - if( nnode == 0 ) - { - // Out of memory - return -1; - } - - nnode->key = key; - nnode->value = value; - - return Insert(nnode); -} - -template -int asCMap::Insert(asSMapNode *nnode) -{ - // Insert the node - if( root == 0 ) - root = nnode; - else - { - asSMapNode *p = root; - for(;;) - { - if( nnode->key < p->key ) - { - if( p->left == 0 ) - { - nnode->parent = p; - p->left = nnode; - break; - } - else - p = p->left; - } - else - { - if( p->right == 0 ) - { - nnode->parent = p; - p->right = nnode; - break; - } - else - p = p->right; - } - } - } - - BalanceInsert(nnode); - - count++; - - return 0; -} - -template -void asCMap::BalanceInsert(asSMapNode *node) -{ - // The node, that is red, can't have a red parent - while( node != root && node->parent->isRed ) - { - // Check color of uncle - if( node->parent == node->parent->parent->left ) - { - asSMapNode *uncle = node->parent->parent->right; - if( ISRED(uncle) ) - { - // B - // R R - // N - - // Change color on parent, uncle, and grand parent - node->parent->isRed = false; - uncle->isRed = false; - node->parent->parent->isRed = true; - - // Continue balancing from grand parent - node = node->parent->parent; - } - else - { - // B - // R B - // N - - if( node == node->parent->right ) - { - // Make the node a left child - node = node->parent; - RotateLeft(node); - } - - // Change color on parent and grand parent - // Then rotate grand parent to the right - node->parent->isRed = false; - node->parent->parent->isRed = true; - RotateRight(node->parent->parent); - } - } - else - { - asSMapNode *uncle = node->parent->parent->left; - if( ISRED(uncle) ) - { - // B - // R R - // N - - // Change color on parent, uncle, and grand parent - // Continue balancing from grand parent - node->parent->isRed = false; - uncle->isRed = false; - node = node->parent->parent; - node->isRed = true; - } - else - { - // B - // B R - // N - - if( node == node->parent->left ) - { - // Make the node a right child - node = node->parent; - RotateRight(node); - } - - // Change color on parent and grand parent - // Then rotate grand parent to the right - node->parent->isRed = false; - node->parent->parent->isRed = true; - RotateLeft(node->parent->parent); - } - } - } - - root->isRed = false; -} - -// For debugging purposes only -template -int asCMap::CheckIntegrity(asSMapNode *node) const -{ - if( node == 0 ) - { - if( root == 0 ) - return 0; - else if( ISRED(root) ) - return -1; - else - node = root; - } - - int left = 0, right = 0; - if( node->left ) - left = CheckIntegrity(node->left); - if( node->right ) - right = CheckIntegrity(node->right); - - if( left != right || left == -1 ) - return -1; - - if( ISBLACK(node) ) - return left+1; - - return left; -} - -// Returns true if successful -template -bool asCMap::MoveTo(asSMapNode **out, const KEY &key) const -{ - asSMapNode *p = root; - while( p ) - { - if( key < p->key ) - p = p->left; - else if( key == p->key ) - { - if( out ) *out = p; - return true; - } - else - p = p->right; - } - - if( out ) *out = 0; - return false; -} - -template -void asCMap::Erase(asSMapNode *cursor) -{ - asSMapNode *node = Remove(cursor); - asASSERT( node == cursor ); - - typedef asSMapNode node_t; - asDELETE(node,node_t); -} - -template -asSMapNode *asCMap::Remove(asSMapNode *cursor) -{ - if( cursor == 0 ) return 0; - - asSMapNode *node = cursor; - - //--------------------------------------------------- - // Choose the node that will replace the erased one - asSMapNode *remove; - if( node->left == 0 || node->right == 0 ) - remove = node; - else - { - remove = node->right; - while( remove->left ) remove = remove->left; - } - - //-------------------------------------------------- - // Remove the node - asSMapNode *child; - if( remove->left ) - child = remove->left; - else - child = remove->right; - - if( child ) child->parent = remove->parent; - if( remove->parent ) - { - if( remove == remove->parent->left ) - remove->parent->left = child; - else - remove->parent->right = child; - } - else - root = child; - - // If we remove a black node we must make sure the tree is balanced - if( ISBLACK(remove) ) - BalanceErase(child, remove->parent); - - //---------------------------------------- - // Replace the erased node with the removed one - if( remove != node ) - { - if( node->parent ) - { - if( node->parent->left == node ) - node->parent->left = remove; - else - node->parent->right = remove; - } - else - root = remove; - - remove->isRed = node->isRed; - remove->parent = node->parent; - - remove->left = node->left; - if( remove->left ) remove->left->parent = remove; - remove->right = node->right; - if( remove->right ) remove->right->parent = remove; - } - - count--; - - return node; -} - -// Call method only if removed node was black -// child is the child of the removed node -template -void asCMap::BalanceErase(asSMapNode *child, asSMapNode *parent) -{ - // If child is red - // Color child black - // Terminate - - // These tests assume brother is to the right. - - // 1. Brother is red - // Color parent red and brother black - // Rotate parent left - // Transforms to 2b - // 2a. Parent and brother is black, brother's children are black - // Color brother red - // Continue test with parent as child - // 2b. Parent is red, brother is black, brother's children are black - // Color parent black and brother red - // Terminate - // 3. Brother is black, and brother's left is red and brother's right is black - // Color brother red and brother's left black - // Rotate brother to right - // Transforms to 4. - // 4. Brother is black, brother's right is red - // Color brother's right black - // Color brother to color of parent - // Color parent black - // Rotate parent left - // Terminate - - while( child != root && ISBLACK(child) ) - { - if( child == parent->left ) - { - asSMapNode *brother = parent->right; - - // Case 1 - if( ISRED(brother) ) - { - brother->isRed = false; - parent->isRed = true; - RotateLeft(parent); - brother = parent->right; - } - - // Case 2 - if( brother == 0 ) break; - if( ISBLACK(brother->left) && ISBLACK(brother->right) ) - { - // Case 2b - if( ISRED(parent) ) - { - parent->isRed = false; - brother->isRed = true; - break; - } - - brother->isRed = true; - child = parent; - parent = child->parent; - } - else - { - // Case 3 - if( ISBLACK(brother->right) ) - { - brother->left->isRed = false; - brother->isRed = true; - RotateRight(brother); - brother = parent->right; - } - - // Case 4 - brother->isRed = parent->isRed; - parent->isRed = false; - brother->right->isRed = false; - RotateLeft(parent); - break; - } - } - else - { - asSMapNode *brother = parent->left; - - // Case 1 - if( ISRED(brother) ) - { - brother->isRed = false; - parent->isRed = true; - RotateRight(parent); - brother = parent->left; - } - - // Case 2 - if( brother == 0 ) break; - if( ISBLACK(brother->left) && ISBLACK(brother->right) ) - { - // Case 2b - if( ISRED(parent) ) - { - parent->isRed = false; - brother->isRed = true; - break; - } - - brother->isRed = true; - child = parent; - parent = child->parent; - } - else - { - // Case 3 - if( ISBLACK(brother->left) ) - { - brother->right->isRed = false; - brother->isRed = true; - RotateLeft(brother); - brother = parent->left; - } - - // Case 4 - brother->isRed = parent->isRed; - parent->isRed = false; - brother->left->isRed = false; - RotateRight(parent); - break; - } - } - } - - if( child ) - child->isRed = false; -} - -template -int asCMap::RotateRight(asSMapNode *node) -{ - // P L // - // / \ / \ // - // L R => Ll P // - // / \ / \ // - // Ll Lr Lr R // - - if( node->left == 0 ) return -1; - - asSMapNode *left = node->left; - - // Update parent - if( node->parent ) - { - asSMapNode *parent = node->parent; - if( parent->left == node ) - parent->left = left; - else - parent->right = left; - - left->parent = parent; - } - else - { - root = left; - left->parent = 0; - } - - // Move left's right child to node's left child - node->left = left->right; - if( node->left ) node->left->parent = node; - - // Put node as left's right child - left->right = node; - node->parent = left; - - return 0; -} - -template -int asCMap::RotateLeft(asSMapNode *node) -{ - // P R // - // / \ / \ // - // L R => P Rr // - // / \ / \ // - // Rl Rr L Rl // - - if( node->right == 0 ) return -1; - - asSMapNode *right = node->right; - - // Update parent - if( node->parent ) - { - asSMapNode *parent = node->parent; - if( parent->right == node ) - parent->right = right; - else - parent->left = right; - - right->parent = parent; - } - else - { - root = right; - right->parent = 0; - } - - // Move right's left child to node's right child - node->right = right->left; - if( node->right ) node->right->parent = node; - - // Put node as right's left child - right->left = node; - node->parent = right; - - return 0; -} - -template -const VAL &asCMap::GetValue(const asSMapNode *cursor) const -{ - if( cursor == 0 ) - return dummy.value; - - return cursor->value; -} - -template -VAL &asCMap::GetValue(asSMapNode *cursor) -{ - if( cursor == 0 ) - return dummy.value; - - return cursor->value; -} - -template -const KEY &asCMap::GetKey(const asSMapNode *cursor) const -{ - if( cursor == 0 ) - return dummy.key; - - return cursor->key; -} - -template -bool asCMap::MoveFirst(asSMapNode **out) const -{ - *out = root; - if( root == 0 ) return false; - - while( (*out)->left ) - *out = (*out)->left; - - return true; -} - -template -bool asCMap::MoveLast(asSMapNode **out) const -{ - *out = root; - if( root == 0 ) return false; - - while( (*out)->right ) - *out = (*out)->right; - - return true; -} - -template -bool asCMap::MoveNext(asSMapNode **out, asSMapNode *cursor) const -{ - if( cursor == 0 ) - { - *out = 0; - return false; - } - - if( cursor->right == 0 ) - { - // Move upwards until we find a parent node to the right - while( cursor->parent && cursor->parent->right == cursor ) - cursor = cursor->parent; - - cursor = cursor->parent; - *out = cursor; - if( cursor == 0 ) - return false; - - return true; - } - - cursor = cursor->right; - while( cursor->left ) - cursor = cursor->left; - - *out = cursor; - return true; -} - -template -bool asCMap::MovePrev(asSMapNode **out, asSMapNode *cursor) const -{ - if( cursor == 0 ) - { - *out = 0; - return false; - } - - if( cursor->left == 0 ) - { - // Move upwards until we find a parent node to the left - while( cursor->parent && cursor->parent->left == cursor ) - cursor = cursor->parent; - - cursor = cursor->parent; - - *out = cursor; - if( cursor == 0 ) - return false; - - return true; - } - - cursor = cursor->left; - while( cursor->right ) - cursor = cursor->right; - - *out = cursor; - return true; -} - - - - -#endif - diff --git a/dependencies/angelscript/source/as_memory.cpp b/dependencies/angelscript/source/as_memory.cpp deleted file mode 100644 index f10dffbd..00000000 --- a/dependencies/angelscript/source/as_memory.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_memory.cpp -// -// Overload the default memory management functions so that we -// can let the application decide how to do it. -// - -#include - -#if !defined(__APPLE__) && !defined( __SNC__ ) && !defined( __ghs__ ) && !defined(__FreeBSD__) -#include -#endif - -#include "as_config.h" -#include "as_memory.h" -#include "as_scriptnode.h" -#include "as_bytecode.h" - -BEGIN_AS_NAMESPACE - -#ifdef WIP_16BYTE_ALIGN - -// TODO: Add support for 16byte aligned application types (e.g. __m128). The following is a list of things that needs to be implemented: -// -// ok - The script context must make sure to always allocate the local stack memory buffer on 16byte aligned boundaries (asCContext::ReserveStackSpace) -// ok - The engine must make sure to always allocate the memory for the script objects on 16byte aligned boundaries (asCScriptEngine::CallAlloc) -// ok - The application needs to inform a new flag when registering types that require 16byte alignment, e.g. asOBJ_APP_ALIGN16 (asCScriptEngine::RegisterObjectType) -// ok - The script object type must make sure to align member properties of these types correctly (asCObjectType::AddPropertyToClass) -// ok - Script global properties must allocate memory on 16byte boundaries if holding these types (asCGlobalProperty::AllocateMemory) -// TODO - The script compiler must make sure to allocate the local variables on 16byte boundaries (asCCompiler::AllocateVariable) -// TODO - The script compiler must add pad bytes on the stack for all function calls to guarantee that the stack position is 16byte aligned on entry in the called function (asCCompiler) -// TODO - The bytecode serializer must be capable of adjusting these pad bytes to guarantee platform independent saved bytecode. Remember that the registered type may not be 16byte aligned on all platforms (asCWriter & asCReader) -// TODO - The bytecode serializer must also be prepared to adjust the position of the local variables according to the need fro 16byte alignment (asCWriter & asCReader) -// TODO - The code for the native calling conventions must be adjusted for all platforms that should support 16byte aligned types (as_callfunc...) -// ok - When the context needs to grow the local stack memory it must copy the function arguments so that the stack entry position is 16byte aligned (asCContext::CallScriptFunction) -// TODO - When the context is prepared for a new call, it must set the initial stack position so the stack entry position is 16byte aligned (asCContext::Prepare) -// -// http://www.gamedev.net/topic/650555-alignment-requirements/ - - -// TODO: Allow user to register its own aligned memory routines -// Wrappers for aligned allocations -void *debugAlignedMalloc(size_t size, size_t align, const char *file, int line) -{ - void *mem = ((asALLOCFUNCDEBUG_t)userAlloc)(size + (align-1) + sizeof(void*), file, line); - - char *amem = ((char*)mem) + sizeof(void*); - if( (uintptr_t)amem & (align - 1) ) - amem += align - ((uintptr_t)amem & (align - 1)); - - ((void**)amem)[-1] = mem; - return amem; -} - -void *alignedMalloc(size_t size, size_t align) -{ - void *mem = userAlloc(size + (align-1) + sizeof(void*)); - - char *amem = ((char*)mem) + sizeof(void*); - if( (uintptr_t)amem & (align - 1) ) - amem += align - ((uintptr_t)amem & (align - 1)); - - ((void**)amem)[-1] = mem; - return amem; -} - -void alignedFree(void *mem) -{ - userFree( ((void**)mem)[-1] ); -} - -bool isAligned(const void* const pointer, asUINT alignment) -{ - return (uintptr_t(pointer) % alignment) == 0; -} -#endif - -// By default we'll use the standard memory management functions - -// Make sure these globals are initialized first. Otherwise the -// library may crash in case the application initializes the engine -// as a global variable. - -#ifdef _MSC_VER -// MSVC let's us choose between a couple of different initialization orders. -#pragma warning(disable: 4073) -#pragma init_seg(lib) -asALLOCFUNC_t userAlloc = malloc; -asFREEFUNC_t userFree = free; -#ifdef WIP_16BYTE_ALIGN -#ifdef AS_DEBUG -asALLOCALIGNEDFUNC_t userAllocAligned = (asALLOCALIGNEDFUNC_t)debugAlignedMalloc; -#else -asALLOCALIGNEDFUNC_t userAllocAligned = alignedMalloc; -#endif -asFREEALIGNEDFUNC_t userFreeAligned = alignedFree; -#endif -#else -// Other compilers will just have to rely on luck. -asALLOCFUNC_t userAlloc = malloc; -asFREEFUNC_t userFree = free; -#ifdef WIP_16BYTE_ALIGN -asALLOCALIGNEDFUNC_t userAllocAligned = alignedMalloc; -asFREEALIGNEDFUNC_t userFreeAligned = alignedFree; -#endif -#endif - -extern "C" -{ - -// interface -int asSetGlobalMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) -{ - userAlloc = allocFunc; - userFree = freeFunc; - - return 0; -} - -// interface -int asResetGlobalMemoryFunctions() -{ - asThreadCleanup(); - - userAlloc = malloc; - userFree = free; - - return 0; -} - -// interface -void *asAllocMem(size_t size) -{ - return asNEWARRAY(asBYTE, size); -} - -// interface -void asFreeMem(void *mem) -{ - asDELETEARRAY(mem); -} - -} // extern "C" - -asCMemoryMgr::asCMemoryMgr() -{ -} - -asCMemoryMgr::~asCMemoryMgr() -{ - FreeUnusedMemory(); -} - -void asCMemoryMgr::FreeUnusedMemory() -{ - // It's necessary to protect the scriptNodePool from multiple - // simultaneous accesses, as the parser is used by several methods - // that can be executed simultaneously. - ENTERCRITICALSECTION(cs); - - int n; - for( n = 0; n < (signed)scriptNodePool.GetLength(); n++ ) - userFree(scriptNodePool[n]); - scriptNodePool.Allocate(0, false); - - LEAVECRITICALSECTION(cs); - - // The engine already protects against multiple threads - // compiling scripts simultaneously so this pool doesn't have - // to be protected again. - for( n = 0; n < (signed)byteInstructionPool.GetLength(); n++ ) - userFree(byteInstructionPool[n]); - byteInstructionPool.Allocate(0, false); -} - -void *asCMemoryMgr::AllocScriptNode() -{ - ENTERCRITICALSECTION(cs); - - if( scriptNodePool.GetLength() ) - { - void *tRet = scriptNodePool.PopLast(); - LEAVECRITICALSECTION(cs); - return tRet; - } - - LEAVECRITICALSECTION(cs); - -#if defined(AS_DEBUG) - return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCScriptNode), __FILE__, __LINE__); -#else - return userAlloc(sizeof(asCScriptNode)); -#endif -} - -void asCMemoryMgr::FreeScriptNode(void *ptr) -{ - ENTERCRITICALSECTION(cs); - - // Pre allocate memory for the array to avoid slow growth - if( scriptNodePool.GetLength() == 0 ) - scriptNodePool.Allocate(100, 0); - - scriptNodePool.PushLast(ptr); - - LEAVECRITICALSECTION(cs); -} - -#ifndef AS_NO_COMPILER - -void *asCMemoryMgr::AllocByteInstruction() -{ - if( byteInstructionPool.GetLength() ) - return byteInstructionPool.PopLast(); - -#if defined(AS_DEBUG) - return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCByteInstruction), __FILE__, __LINE__); -#else - return userAlloc(sizeof(asCByteInstruction)); -#endif -} - -void asCMemoryMgr::FreeByteInstruction(void *ptr) -{ - // Pre allocate memory for the array to avoid slow growth - if( byteInstructionPool.GetLength() == 0 ) - byteInstructionPool.Allocate(100, 0); - - byteInstructionPool.PushLast(ptr); -} - -#endif // AS_NO_COMPILER - -END_AS_NAMESPACE - - - diff --git a/dependencies/angelscript/source/as_memory.h b/dependencies/angelscript/source/as_memory.h deleted file mode 100644 index 04740855..00000000 --- a/dependencies/angelscript/source/as_memory.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_memory.h -// -// Overload the default memory management functions so that we -// can let the application decide how to do it. -// - - - -#ifndef AS_MEMORY_H -#define AS_MEMORY_H - -#include "as_config.h" - -BEGIN_AS_NAMESPACE - -extern asALLOCFUNC_t userAlloc; -extern asFREEFUNC_t userFree; - -#ifdef WIP_16BYTE_ALIGN - -// TODO: This declaration should be in angelscript.h -// when the application can register it's own -// aligned memory routines -typedef void *(*asALLOCALIGNEDFUNC_t)(size_t, size_t); -typedef void (*asFREEALIGNEDFUNC_t)(void *); -extern asALLOCALIGNEDFUNC_t userAllocAligned; -extern asFREEALIGNEDFUNC_t userFreeAligned; -typedef void *(*asALLOCALIGNEDFUNCDEBUG_t)(size_t, size_t, const char *, unsigned int); - -// The maximum type alignment supported. -const int MAX_TYPE_ALIGNMENT = 16; - -// Utility function used for assertions. -bool isAligned(const void* const pointer, asUINT alignment); - -#endif // WIP_16BYTE_ALIGN - -// We don't overload the new operator as that would affect the application as well - -#ifndef AS_DEBUG - - #define asNEW(x) new(userAlloc(sizeof(x))) x - #define asDELETE(ptr,x) {void *tmp = ptr; (ptr)->~x(); userFree(tmp);} - - #define asNEWARRAY(x,cnt) (x*)userAlloc(sizeof(x)*cnt) - #define asDELETEARRAY(ptr) userFree(ptr) - -#ifdef WIP_16BYTE_ALIGN - #define asNEWARRAYALIGNED(x,cnt, alignment) (x*)userAllocAligned(sizeof(x)*cnt, alignment) - #define asDELETEARRAYALIGNED(ptr) userFreeAligned(ptr) -#endif - -#else - - typedef void *(*asALLOCFUNCDEBUG_t)(size_t, const char *, unsigned int); - - #define asNEW(x) new(((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(x), __FILE__, __LINE__)) x - #define asDELETE(ptr,x) {void *tmp = ptr; (ptr)->~x(); userFree(tmp);} - - #define asNEWARRAY(x,cnt) (x*)((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(x)*cnt, __FILE__, __LINE__) - #define asDELETEARRAY(ptr) userFree(ptr) - -#ifdef WIP_16BYTE_ALIGN - //TODO: Equivalent of debug allocation function with alignment? - #define asNEWARRAYALIGNED(x,cnt, alignment) (x*)userAllocAligned(sizeof(x)*cnt, alignment) - #define asDELETEARRAYALIGNED(ptr) userFreeAligned(ptr) -#endif - -#endif - -END_AS_NAMESPACE - -#include -#include "as_criticalsection.h" -#include "as_array.h" - -BEGIN_AS_NAMESPACE - -class asCMemoryMgr -{ -public: - asCMemoryMgr(); - ~asCMemoryMgr(); - - void FreeUnusedMemory(); - - void *AllocScriptNode(); - void FreeScriptNode(void *ptr); - -#ifndef AS_NO_COMPILER - void *AllocByteInstruction(); - void FreeByteInstruction(void *ptr); -#endif - -protected: - DECLARECRITICALSECTION(cs) - asCArray scriptNodePool; - asCArray byteInstructionPool; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_module.cpp b/dependencies/angelscript/source/as_module.cpp deleted file mode 100644 index ace42fc3..00000000 --- a/dependencies/angelscript/source/as_module.cpp +++ /dev/null @@ -1,1431 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - -// -// as_module.cpp -// -// A class that holds a script module -// - -#include "as_config.h" -#include "as_module.h" -#include "as_builder.h" -#include "as_context.h" -#include "as_texts.h" -#include "as_debug.h" -#include "as_restore.h" - -BEGIN_AS_NAMESPACE - -// internal -asCModule::asCModule(const char *name, asCScriptEngine *engine) -{ - this->name = name; - this->engine = engine; - - userData = 0; - builder = 0; - isGlobalVarInitialized = false; - - accessMask = 1; - - defaultNamespace = engine->nameSpaces[0]; -} - -// internal -asCModule::~asCModule() -{ - InternalReset(); - - if( builder ) - { - asDELETE(builder,asCBuilder); - builder = 0; - } - - if( engine ) - { - // Clean the user data - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n+1] ) - { - for( asUINT c = 0; c < engine->cleanModuleFuncs.GetLength(); c++ ) - if( engine->cleanModuleFuncs[c].type == userData[n] ) - engine->cleanModuleFuncs[c].cleanFunc(this); - } - } - - // Remove the module from the engine - if( engine->lastModule == this ) - engine->lastModule = 0; - engine->scriptModules.RemoveValue(this); - } -} - -// interface -void asCModule::Discard() -{ - asDELETE(this,asCModule); -} - -// interface -void *asCModule::SetUserData(void *data, asPWORD type) -{ - // As a thread might add a new new user data at the same time as another - // it is necessary to protect both read and write access to the userData member - ACQUIREEXCLUSIVE(engine->engineRWLock); - - // It is not intended to store a lot of different types of userdata, - // so a more complex structure like a associative map would just have - // more overhead than a simple array. - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - void *oldData = reinterpret_cast(userData[n+1]); - userData[n+1] = reinterpret_cast(data); - - RELEASEEXCLUSIVE(engine->engineRWLock); - - return oldData; - } - } - - userData.PushLast(type); - userData.PushLast(reinterpret_cast(data)); - - RELEASEEXCLUSIVE(engine->engineRWLock); - - return 0; -} - -// interface -void *asCModule::GetUserData(asPWORD type) const -{ - // There may be multiple threads reading, but when - // setting the user data nobody must be reading. - ACQUIRESHARED(engine->engineRWLock); - - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - RELEASESHARED(engine->engineRWLock); - return reinterpret_cast(userData[n+1]); - } - } - - RELEASESHARED(engine->engineRWLock); - - return 0; -} - -// interface -asIScriptEngine *asCModule::GetEngine() const -{ - return engine; -} - -// interface -void asCModule::SetName(const char *name) -{ - this->name = name; -} - -// interface -const char *asCModule::GetName() const -{ - return name.AddressOf(); -} - -// interface -const char *asCModule::GetDefaultNamespace() const -{ - return defaultNamespace->name.AddressOf(); -} - -// interface -int asCModule::SetDefaultNamespace(const char *nameSpace) -{ - // TODO: cleanup: This function is similar to asCScriptEngine::SetDefaultNamespace. Can we reuse the code? - if( nameSpace == 0 ) - return asINVALID_ARG; - - asCString ns = nameSpace; - if( ns != "" ) - { - // Make sure the namespace is composed of alternating identifier and :: - size_t pos = 0; - bool expectIdentifier = true; - size_t len; - eTokenType t = ttIdentifier; - - for( ; pos < ns.GetLength(); pos += len ) - { - t = engine->tok.GetToken(ns.AddressOf() + pos, ns.GetLength() - pos, &len); - if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) ) - return asINVALID_DECLARATION; - - expectIdentifier = !expectIdentifier; - } - - // If the namespace ends with :: then strip it off - if( t == ttScope ) - ns.SetLength(ns.GetLength()-2); - } - - defaultNamespace = engine->AddNameSpace(ns.AddressOf()); - - return 0; -} - -// interface -int asCModule::AddScriptSection(const char *name, const char *code, size_t codeLength, int lineOffset) -{ -#ifdef AS_NO_COMPILER - UNUSED_VAR(name); - UNUSED_VAR(code); - UNUSED_VAR(codeLength); - UNUSED_VAR(lineOffset); - return asNOT_SUPPORTED; -#else - if( !builder ) - { - builder = asNEW(asCBuilder)(engine, this); - if( builder == 0 ) - return asOUT_OF_MEMORY; - } - - return builder->AddCode(name, code, (int)codeLength, lineOffset, (int)engine->GetScriptSectionNameIndex(name ? name : ""), engine->ep.copyScriptSections); -#endif -} - -// internal -void asCModule::JITCompile() -{ - asIJITCompiler *jit = engine->GetJITCompiler(); - if( !jit ) - return; - - for (unsigned int i = 0; i < scriptFunctions.GetLength(); i++) - scriptFunctions[i]->JITCompile(); -} - -// interface -int asCModule::Build() -{ -#ifdef AS_NO_COMPILER - return asNOT_SUPPORTED; -#else - TimeIt("asCModule::Build"); - - // Only one thread may build at one time - // TODO: It should be possible to have multiple threads perform compilations - int r = engine->RequestBuild(); - if( r < 0 ) - return r; - - engine->PrepareEngine(); - if( engine->configFailed ) - { - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); - engine->BuildCompleted(); - return asINVALID_CONFIGURATION; - } - - InternalReset(); - - if( !builder ) - { - engine->BuildCompleted(); - return asSUCCESS; - } - - // Compile the script - r = builder->Build(); - asDELETE(builder,asCBuilder); - builder = 0; - - if( r < 0 ) - { - // Reset module again - InternalReset(); - - engine->BuildCompleted(); - return r; - } - - JITCompile(); - - engine->PrepareEngine(); - -#ifdef AS_DEBUG - // Verify that there are no unwanted gaps in the scriptFunctions array. - for( asUINT n = 1; n < engine->scriptFunctions.GetLength(); n++ ) - { - int id = n; - if( engine->scriptFunctions[n] == 0 && !engine->freeScriptFunctionIds.Exists(id) ) - asASSERT( false ); - } -#endif - - engine->BuildCompleted(); - - // Initialize global variables - if( r >= 0 && engine->ep.initGlobalVarsAfterBuild ) - r = ResetGlobalVars(0); - - return r; -#endif -} - -// interface -int asCModule::ResetGlobalVars(asIScriptContext *ctx) -{ - if( isGlobalVarInitialized ) - CallExit(); - - return CallInit(ctx); -} - -// interface -asIScriptFunction *asCModule::GetFunctionByIndex(asUINT index) const -{ - return const_cast(globalFunctions.Get(index)); -} - -// internal -int asCModule::CallInit(asIScriptContext *myCtx) -{ - if( isGlobalVarInitialized ) - return asERROR; - - // Each global variable needs to be cleared individually - asCSymbolTableIterator it = scriptGlobals.List(); - while( it ) - { - asCGlobalProperty *desc = *it; - memset(desc->GetAddressOfValue(), 0, sizeof(asDWORD)*desc->type.GetSizeOnStackDWords()); - it++; - } - - // Call the init function for each of the global variables - asIScriptContext *ctx = myCtx; - int r = asEXECUTION_FINISHED; - it = scriptGlobals.List(); - while( it && r == asEXECUTION_FINISHED ) - { - asCGlobalProperty *desc = *it; - it++; - if( desc->GetInitFunc() ) - { - if( ctx == 0 ) - { - ctx = engine->RequestContext(); - if( ctx == 0 ) - break; - } - - r = ctx->Prepare(desc->GetInitFunc()); - if( r >= 0 ) - { - r = ctx->Execute(); - if( r != asEXECUTION_FINISHED ) - { - asCString msg; - msg.Format(TXT_FAILED_TO_INITIALIZE_s, desc->name.AddressOf()); - asCScriptFunction *func = desc->GetInitFunc(); - - engine->WriteMessage(func->scriptData->scriptSectionIdx >= 0 ? engine->scriptSectionNames[func->scriptData->scriptSectionIdx]->AddressOf() : "", - func->GetLineNumber(0, 0) & 0xFFFFF, - func->GetLineNumber(0, 0) >> 20, - asMSGTYPE_ERROR, - msg.AddressOf()); - - if( r == asEXECUTION_EXCEPTION ) - { - const asIScriptFunction *function = ctx->GetExceptionFunction(); - - msg.Format(TXT_EXCEPTION_s_IN_s, ctx->GetExceptionString(), function->GetDeclaration()); - - engine->WriteMessage(function->GetScriptSectionName(), - ctx->GetExceptionLineNumber(), - 0, - asMSGTYPE_INFORMATION, - msg.AddressOf()); - } - } - } - } - } - - if( ctx && !myCtx ) - { - engine->ReturnContext(ctx); - ctx = 0; - } - - // Even if the initialization failed we need to set the - // flag that the variables have been initialized, otherwise - // the module won't free those variables that really were - // initialized. - isGlobalVarInitialized = true; - - if( r != asEXECUTION_FINISHED ) - return asINIT_GLOBAL_VARS_FAILED; - - return asSUCCESS; -} - -// internal -void asCModule::CallExit() -{ - if( !isGlobalVarInitialized ) return; - - asCSymbolTableIterator it = scriptGlobals.List(); - while( it ) - { - if( (*it)->type.IsObject() ) - { - void **obj = (void**)(*it)->GetAddressOfValue(); - if( *obj ) - { - asCObjectType *ot = (*it)->type.GetObjectType(); - - if( ot->flags & asOBJ_REF ) - { - asASSERT( (ot->flags & asOBJ_NOCOUNT) || ot->beh.release ); - if( ot->beh.release ) - engine->CallObjectMethod(*obj, ot->beh.release); - } - else - { - if( ot->beh.destruct ) - engine->CallObjectMethod(*obj, ot->beh.destruct); - - engine->CallFree(*obj); - } - - // Set the address to 0 as someone might try to access the variable afterwards - *obj = 0; - } - } - it++; - } - - isGlobalVarInitialized = false; -} - -// internal -void asCModule::InternalReset() -{ - CallExit(); - - size_t n; - - // Release all global functions - asCSymbolTable::iterator funcIt = globalFunctions.List(); - for( ; funcIt; funcIt++ ) - (*funcIt)->Release(); - globalFunctions.Clear(); - - // First release all compiled functions - for( n = 0; n < scriptFunctions.GetLength(); n++ ) - if( scriptFunctions[n] ) - scriptFunctions[n]->Orphan(this); - scriptFunctions.SetLength(0); - - // Release the global properties declared in the module - asCSymbolTableIterator globIt = scriptGlobals.List(); - while( globIt ) - { - (*globIt)->Orphan(this); - globIt++; - } - scriptGlobals.Clear(); - - UnbindAllImportedFunctions(); - - // Free bind information - for( n = 0; n < bindInformations.GetLength(); n++ ) - { - if( bindInformations[n] ) - { - asUINT id = bindInformations[n]->importedFunctionSignature->id & ~FUNC_IMPORTED; - engine->importedFunctions[id] = 0; - engine->freeImportedFunctionIdxs.PushLast(id); - - bindInformations[n]->importedFunctionSignature->Orphan(this); - - asDELETE(bindInformations[n], sBindInfo); - } - } - bindInformations.SetLength(0); - - // Free declared types, including classes, typedefs, and enums - // TODO: optimize: Check if it is possible to destroy the object directly without notifying the GC - for( n = 0; n < classTypes.GetLength(); n++ ) - classTypes[n]->Orphan(this); - classTypes.SetLength(0); - for( n = 0; n < enumTypes.GetLength(); n++ ) - enumTypes[n]->Orphan(this); - enumTypes.SetLength(0); - for( n = 0; n < typeDefs.GetLength(); n++ ) - typeDefs[n]->Release(); - typeDefs.SetLength(0); - - // Free funcdefs - for( n = 0; n < funcDefs.GetLength(); n++ ) - { - // The funcdefs are not removed from the engine at this moment as they may still be referred - // to by other types. The engine's ClearUnusedTypes will take care of the clean up. - funcDefs[n]->Release(); - } - funcDefs.SetLength(0); - - // Allow the engine to clean up what is not used - engine->CleanupAfterDiscardModule(); - - asASSERT( IsEmpty() ); -} - -// interface -asIScriptFunction *asCModule::GetFunctionByName(const char *name) const -{ - const asCArray &idxs = globalFunctions.GetIndexes(defaultNamespace, name); - if( idxs.GetLength() != 1 ) - return 0; - - const asIScriptFunction *func = globalFunctions.Get(idxs[0]); - return const_cast(func); -} - -// interface -asUINT asCModule::GetImportedFunctionCount() const -{ - return (asUINT)bindInformations.GetLength(); -} - -// interface -int asCModule::GetImportedFunctionIndexByDecl(const char *decl) const -{ - asCBuilder bld(engine, const_cast(this)); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCScriptFunction func(engine, const_cast(this), asFUNC_DUMMY); - bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, defaultNamespace); - - // TODO: optimize: Improve linear search - // Search script functions for matching interface - int id = -1; - for( asUINT n = 0; n < bindInformations.GetLength(); ++n ) - { - if( func.name == bindInformations[n]->importedFunctionSignature->name && - func.returnType == bindInformations[n]->importedFunctionSignature->returnType && - func.parameterTypes.GetLength() == bindInformations[n]->importedFunctionSignature->parameterTypes.GetLength() ) - { - bool match = true; - for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p ) - { - if( func.parameterTypes[p] != bindInformations[n]->importedFunctionSignature->parameterTypes[p] ) - { - match = false; - break; - } - } - - if( match ) - { - if( id == -1 ) - id = n; - else - return asMULTIPLE_FUNCTIONS; - } - } - } - - if( id == -1 ) return asNO_FUNCTION; - - return id; -} - -// interface -asUINT asCModule::GetFunctionCount() const -{ - return (asUINT)globalFunctions.GetSize(); -} - -// interface -asIScriptFunction *asCModule::GetFunctionByDecl(const char *decl) const -{ - asCBuilder bld(engine, const_cast(this)); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCScriptFunction func(engine, const_cast(this), asFUNC_DUMMY); - int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, defaultNamespace); - if( r < 0 ) - { - // Invalid declaration - // TODO: Write error to message stream - return 0; - } - - // Use the defaultNamespace implicitly unless an explicit namespace has been provided - asSNameSpace *ns = func.nameSpace == engine->nameSpaces[0] ? defaultNamespace : func.nameSpace; - - // Search script functions for matching interface - asIScriptFunction *f = 0; - const asCArray &idxs = globalFunctions.GetIndexes(ns, func.name); - for( unsigned int n = 0; n < idxs.GetLength(); n++ ) - { - const asCScriptFunction *funcPtr = globalFunctions.Get(idxs[n]); - if( funcPtr->objectType == 0 && - func.returnType == funcPtr->returnType && - func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength() - ) - { - bool match = true; - for( size_t p = 0; p < func.parameterTypes.GetLength(); ++p ) - { - if( func.parameterTypes[p] != funcPtr->parameterTypes[p] ) - { - match = false; - break; - } - } - - if( match ) - { - if( f == 0 ) - f = const_cast(funcPtr); - else - // Multiple functions - return 0; - } - } - } - - return f; -} - -// interface -asUINT asCModule::GetGlobalVarCount() const -{ - return (asUINT)scriptGlobals.GetSize(); -} - -// interface -int asCModule::GetGlobalVarIndexByName(const char *name) const -{ - // Find the global var id - int id = scriptGlobals.GetFirstIndex(defaultNamespace, name); - - if( id == -1 ) return asNO_GLOBAL_VAR; - - return id; -} - -// interface -int asCModule::RemoveGlobalVar(asUINT index) -{ - asCGlobalProperty *prop = scriptGlobals.Get(index); - if( !prop ) - return asINVALID_ARG; - prop->Orphan(this); - scriptGlobals.Erase(index); - - return 0; -} - -// interface -int asCModule::GetGlobalVarIndexByDecl(const char *decl) const -{ - asCBuilder bld(engine, const_cast(this)); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCString name; - asSNameSpace *nameSpace; - asCDataType dt; - int r = bld.ParseVariableDeclaration(decl, defaultNamespace, name, nameSpace, dt); - if( r < 0 ) - return r; - - // Search global variables for a match - int id = scriptGlobals.GetFirstIndex(nameSpace, name, asCCompGlobPropType(dt)); - if( id != -1 ) - return id; - - return asNO_GLOBAL_VAR; -} - -// interface -void *asCModule::GetAddressOfGlobalVar(asUINT index) -{ - asCGlobalProperty *prop = scriptGlobals.Get(index); - if( !prop ) - return 0; - - // For object variables it's necessary to dereference the pointer to get the address of the value - if( prop->type.IsObject() && - !prop->type.IsObjectHandle() ) - return *(void**)(prop->GetAddressOfValue()); - - return (void*)(prop->GetAddressOfValue()); -} - -// interface -const char *asCModule::GetGlobalVarDeclaration(asUINT index, bool includeNamespace) const -{ - const asCGlobalProperty *prop = scriptGlobals.Get(index); - if (!prop) return 0; - - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = prop->type.Format(); - *tempString += " "; - if( includeNamespace ) - *tempString += prop->nameSpace->name + "::"; - *tempString += prop->name; - - return tempString->AddressOf(); -} - -// interface -int asCModule::GetGlobalVar(asUINT index, const char **name, const char **nameSpace, int *typeId, bool *isConst) const -{ - const asCGlobalProperty *prop = scriptGlobals.Get(index); - if (!prop) return 0; - - if( name ) - *name = prop->name.AddressOf(); - if( nameSpace ) - *nameSpace = prop->nameSpace->name.AddressOf(); - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(prop->type); - if( isConst ) - *isConst = prop->type.IsReadOnly(); - - return asSUCCESS; -} - -// interface -asUINT asCModule::GetObjectTypeCount() const -{ - return (asUINT)classTypes.GetLength(); -} - -// interface -asIObjectType *asCModule::GetObjectTypeByIndex(asUINT index) const -{ - if( index >= classTypes.GetLength() ) - return 0; - - return classTypes[index]; -} - -// interface -asIObjectType *asCModule::GetObjectTypeByName(const char *name) const -{ - for( asUINT n = 0; n < classTypes.GetLength(); n++ ) - { - if( classTypes[n] && - classTypes[n]->name == name && - classTypes[n]->nameSpace == defaultNamespace ) - return classTypes[n]; - } - - return 0; -} - -// interface -int asCModule::GetTypeIdByDecl(const char *decl) const -{ - asCDataType dt; - - // This const cast is safe since we know the engine won't be modified - asCBuilder bld(engine, const_cast(this)); - - // Don't write parser errors to the message callback - bld.silent = true; - - int r = bld.ParseDataType(decl, &dt, defaultNamespace); - if( r < 0 ) - return asINVALID_TYPE; - - return engine->GetTypeIdFromDataType(dt); -} - -// interface -asIObjectType *asCModule::GetObjectTypeByDecl(const char *decl) const -{ - asCDataType dt; - - // This const cast is safe since we know the engine won't be modified - asCBuilder bld(engine, const_cast(this)); - - // Don't write parser errors to the message callback - bld.silent = true; - - int r = bld.ParseDataType(decl, &dt, defaultNamespace); - if( r < 0 ) - return 0; - - return dt.GetObjectType(); -} - -// interface -asUINT asCModule::GetEnumCount() const -{ - return (asUINT)enumTypes.GetLength(); -} - -// interface -const char *asCModule::GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace) const -{ - if( index >= enumTypes.GetLength() ) - return 0; - - if( enumTypeId ) - *enumTypeId = engine->GetTypeIdFromDataType(asCDataType::CreateObject(enumTypes[index], false)); - - if( nameSpace ) - *nameSpace = enumTypes[index]->nameSpace->name.AddressOf(); - - return enumTypes[index]->name.AddressOf(); -} - -// interface -int asCModule::GetEnumValueCount(int enumTypeId) const -{ - asCDataType dt = engine->GetDataTypeFromTypeId(enumTypeId); - asCObjectType *t = dt.GetObjectType(); - if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) ) - return asINVALID_TYPE; - - return (int)t->enumValues.GetLength(); -} - -// interface -const char *asCModule::GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const -{ - asCDataType dt = engine->GetDataTypeFromTypeId(enumTypeId); - asCObjectType *t = dt.GetObjectType(); - if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) ) - return 0; - - if( index >= t->enumValues.GetLength() ) - return 0; - - if( outValue ) - *outValue = t->enumValues[index]->value; - - return t->enumValues[index]->name.AddressOf(); -} - -// interface -asUINT asCModule::GetTypedefCount() const -{ - return (asUINT)typeDefs.GetLength(); -} - -// interface -const char *asCModule::GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace) const -{ - if( index >= typeDefs.GetLength() ) - return 0; - - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(typeDefs[index]->templateSubTypes[0]); - - if( nameSpace ) - *nameSpace = typeDefs[index]->nameSpace->name.AddressOf(); - - return typeDefs[index]->name.AddressOf(); -} - - -// internal -int asCModule::GetNextImportedFunctionId() -{ - // TODO: multithread: This will break if one thread if freeing a module, while another is being compiled - if( engine->freeImportedFunctionIdxs.GetLength() ) - return FUNC_IMPORTED | (asUINT)engine->freeImportedFunctionIdxs[engine->freeImportedFunctionIdxs.GetLength()-1]; - - return FUNC_IMPORTED | (asUINT)engine->importedFunctions.GetLength(); -} - -#ifndef AS_NO_COMPILER -// internal -int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType, bool isConstMethod, bool isGlobalFunction, bool isPrivate, bool isFinal, bool isOverride, bool isShared, asSNameSpace *ns) -{ - asASSERT(id >= 0); - - // Store the function information - asCScriptFunction *func = asNEW(asCScriptFunction)(engine, this, isInterface ? asFUNC_INTERFACE : asFUNC_SCRIPT); - if( func == 0 ) - { - // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - return asOUT_OF_MEMORY; - } - - if( ns == 0 ) - ns = engine->nameSpaces[0]; - - // All methods of shared objects are also shared - if( objType && objType->IsShared() ) - isShared = true; - - func->name = name; - func->nameSpace = ns; - func->id = id; - func->returnType = returnType; - if( func->funcType == asFUNC_SCRIPT ) - { - func->scriptData->scriptSectionIdx = sectionIdx; - func->scriptData->declaredAt = declaredAt; - } - func->parameterTypes = params; - func->parameterNames = paramNames; - func->inOutFlags = inOutFlags; - func->defaultArgs = defaultArgs; - func->objectType = objType; - func->isReadOnly = isConstMethod; - func->isPrivate = isPrivate; - func->isFinal = isFinal; - func->isOverride = isOverride; - func->isShared = isShared; - - asASSERT( params.GetLength() == inOutFlags.GetLength() && params.GetLength() == defaultArgs.GetLength() ); - - // Verify that we are not assigning either the final or override specifier(s) if we are registering a non-member function - asASSERT( !(!objType && isFinal) ); - asASSERT( !(!objType && isOverride) ); - - // The script function's refCount was initialized to 1 - scriptFunctions.PushLast(func); - engine->SetScriptFunction(func); - - // Compute the signature id - if( objType ) - func->ComputeSignatureId(); - - // Add reference - if( isGlobalFunction ) - { - globalFunctions.Put(func); - func->AddRef(); - } - - return 0; -} - -// internal -int asCModule::AddScriptFunction(asCScriptFunction *func) -{ - scriptFunctions.PushLast(func); - func->AddRef(); - engine->SetScriptFunction(func); - - return 0; -} - -// internal -int asCModule::AddImportedFunction(int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSNameSpace *ns, const asCString &moduleName) -{ - asASSERT(id >= 0); - - // Store the function information - asCScriptFunction *func = asNEW(asCScriptFunction)(engine, this, asFUNC_IMPORTED); - if( func == 0 ) - { - // Free the default args - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - return asOUT_OF_MEMORY; - } - - func->name = name; - func->id = id; - func->returnType = returnType; - func->nameSpace = ns; - func->parameterTypes = params; - func->inOutFlags = inOutFlags; - func->defaultArgs = defaultArgs; - func->objectType = 0; - - sBindInfo *info = asNEW(sBindInfo); - if( info == 0 ) - { - asDELETE(func, asCScriptFunction); - return asOUT_OF_MEMORY; - } - - info->importedFunctionSignature = func; - info->boundFunctionId = -1; - info->importFromModule = moduleName; - bindInformations.PushLast(info); - - // Add the info to the array in the engine - if( engine->freeImportedFunctionIdxs.GetLength() ) - engine->importedFunctions[engine->freeImportedFunctionIdxs.PopLast()] = info; - else - engine->importedFunctions.PushLast(info); - - return 0; -} -#endif - -// internal -asCScriptFunction *asCModule::GetImportedFunction(int index) const -{ - return bindInformations[index]->importedFunctionSignature; -} - -// interface -int asCModule::BindImportedFunction(asUINT index, asIScriptFunction *func) -{ - // First unbind the old function - int r = UnbindImportedFunction(index); - if( r < 0 ) return r; - - // Must verify that the interfaces are equal - asCScriptFunction *dst = GetImportedFunction(index); - if( dst == 0 ) return asNO_FUNCTION; - - if( func == 0 ) - return asINVALID_ARG; - - asCScriptFunction *src = engine->GetScriptFunction(func->GetId()); - if( src == 0 ) - return asNO_FUNCTION; - - // Verify return type - if( dst->returnType != src->returnType ) - return asINVALID_INTERFACE; - - if( dst->parameterTypes.GetLength() != src->parameterTypes.GetLength() ) - return asINVALID_INTERFACE; - - for( size_t n = 0; n < dst->parameterTypes.GetLength(); ++n ) - { - if( dst->parameterTypes[n] != src->parameterTypes[n] ) - return asINVALID_INTERFACE; - } - - bindInformations[index]->boundFunctionId = src->GetId(); - src->AddRef(); - - return asSUCCESS; -} - -// interface -int asCModule::UnbindImportedFunction(asUINT index) -{ - if( index >= bindInformations.GetLength() ) - return asINVALID_ARG; - - // Remove reference to old module - if( bindInformations[index] ) - { - int oldFuncID = bindInformations[index]->boundFunctionId; - if( oldFuncID != -1 ) - { - bindInformations[index]->boundFunctionId = -1; - engine->scriptFunctions[oldFuncID]->Release(); - } - } - - return asSUCCESS; -} - -// interface -const char *asCModule::GetImportedFunctionDeclaration(asUINT index) const -{ - asCScriptFunction *func = GetImportedFunction(index); - if( func == 0 ) return 0; - - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = func->GetDeclarationStr(); - - return tempString->AddressOf(); -} - -// interface -const char *asCModule::GetImportedFunctionSourceModule(asUINT index) const -{ - if( index >= bindInformations.GetLength() ) - return 0; - - return bindInformations[index]->importFromModule.AddressOf(); -} - -// inteface -int asCModule::BindAllImportedFunctions() -{ - bool notAllFunctionsWereBound = false; - - // Bind imported functions - int c = GetImportedFunctionCount(); - for( int n = 0; n < c; ++n ) - { - asCScriptFunction *importFunc = GetImportedFunction(n); - if( importFunc == 0 ) return asERROR; - - asCString str = importFunc->GetDeclarationStr(); - - // Get module name from where the function should be imported - const char *moduleName = GetImportedFunctionSourceModule(n); - if( moduleName == 0 ) return asERROR; - - asCModule *srcMod = engine->GetModule(moduleName, false); - asIScriptFunction *func = 0; - if( srcMod ) - func = srcMod->GetFunctionByDecl(str.AddressOf()); - - if( func == 0 ) - notAllFunctionsWereBound = true; - else - { - if( BindImportedFunction(n, func) < 0 ) - notAllFunctionsWereBound = true; - } - } - - if( notAllFunctionsWereBound ) - return asCANT_BIND_ALL_FUNCTIONS; - - return asSUCCESS; -} - -// interface -int asCModule::UnbindAllImportedFunctions() -{ - asUINT c = GetImportedFunctionCount(); - for( asUINT n = 0; n < c; ++n ) - UnbindImportedFunction(n); - - return asSUCCESS; -} - -// internal -asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) -{ - size_t n; - - // TODO: optimize: Improve linear search - for( n = 0; n < classTypes.GetLength(); n++ ) - if( classTypes[n]->name == type && - classTypes[n]->nameSpace == ns ) - return classTypes[n]; - - for( n = 0; n < enumTypes.GetLength(); n++ ) - if( enumTypes[n]->name == type && - enumTypes[n]->nameSpace == ns ) - return enumTypes[n]; - - for( n = 0; n < typeDefs.GetLength(); n++ ) - if( typeDefs[n]->name == type && - typeDefs[n]->nameSpace == ns ) - return typeDefs[n]; - - return 0; -} - -// internal -asCGlobalProperty *asCModule::AllocateGlobalProperty(const char *name, const asCDataType &dt, asSNameSpace *ns) -{ - asCGlobalProperty *prop = engine->AllocateGlobalProperty(); - prop->name = name; - prop->nameSpace = ns; - - // Allocate the memory for this property based on its type - prop->type = dt; - prop->AllocateMemory(); - - // Make an entry in the address to variable map - engine->varAddressMap.Insert(prop->GetAddressOfValue(), prop); - - // Store the variable in the module scope (the reference count is already set to 1) - scriptGlobals.Put(prop); - - return prop; -} - -// internal -bool asCModule::IsEmpty() const -{ - if( scriptFunctions.GetLength() ) return false; - if( globalFunctions.GetSize() ) return false; - if( bindInformations.GetLength() ) return false; - if( scriptGlobals.GetSize() ) return false; - if( classTypes.GetLength() ) return false; - if( enumTypes.GetLength() ) return false; - if( typeDefs.GetLength() ) return false; - if( funcDefs.GetLength() ) return false; - - return true; -} - -// interface -int asCModule::SaveByteCode(asIBinaryStream *out, bool stripDebugInfo) const -{ -#ifdef AS_NO_COMPILER - UNUSED_VAR(out); - UNUSED_VAR(stripDebugInfo); - return asNOT_SUPPORTED; -#else - if( out == 0 ) return asINVALID_ARG; - - // Make sure there is actually something to save - if( IsEmpty() ) - return asERROR; - - asCWriter write(const_cast(this), out, engine, stripDebugInfo); - return write.Write(); -#endif -} - -// interface -int asCModule::LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped) -{ - if( in == 0 ) return asINVALID_ARG; - - // Only permit loading bytecode if no other thread is currently compiling - // TODO: It should be possible to have multiple threads perform compilations - int r = engine->RequestBuild(); - if( r < 0 ) - return r; - - asCReader read(this, in, engine); - r = read.Read(wasDebugInfoStripped); - - JITCompile(); - -#ifdef AS_DEBUG - // Verify that there are no unwanted gaps in the scriptFunctions array. - for( asUINT n = 1; n < engine->scriptFunctions.GetLength(); n++ ) - { - int id = n; - if( engine->scriptFunctions[n] == 0 && !engine->freeScriptFunctionIds.Exists(id) ) - asASSERT( false ); - } -#endif - - engine->BuildCompleted(); - - return r; -} - -// interface -int asCModule::CompileGlobalVar(const char *sectionName, const char *code, int lineOffset) -{ -#ifdef AS_NO_COMPILER - UNUSED_VAR(sectionName); - UNUSED_VAR(code); - UNUSED_VAR(lineOffset); - return asNOT_SUPPORTED; -#else - // Validate arguments - if( code == 0 ) - return asINVALID_ARG; - - // Only one thread may build at one time - // TODO: It should be possible to have multiple threads perform compilations - int r = engine->RequestBuild(); - if( r < 0 ) - return r; - - // Prepare the engine - engine->PrepareEngine(); - if( engine->configFailed ) - { - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); - engine->BuildCompleted(); - return asINVALID_CONFIGURATION; - } - - // Compile the global variable and add it to the module scope - asCBuilder builder(engine, this); - asCString str = code; - r = builder.CompileGlobalVar(sectionName, str.AddressOf(), lineOffset); - - engine->BuildCompleted(); - - // Initialize the variable - if( r >= 0 && engine->ep.initGlobalVarsAfterBuild ) - { - // Clear the memory - asCGlobalProperty *prop = scriptGlobals.GetLast(); - if( prop ) - { - memset(prop->GetAddressOfValue(), 0, sizeof(asDWORD)*prop->type.GetSizeOnStackDWords()); - - if( prop->GetInitFunc() ) - { - // Call the init function for the global variable - asIScriptContext *ctx = 0; - int r = engine->CreateContext(&ctx, true); - if( r < 0 ) - return r; - - r = ctx->Prepare(prop->GetInitFunc()); - if( r >= 0 ) - r = ctx->Execute(); - - ctx->Release(); - } - } - } - - return r; -#endif -} - -// interface -int asCModule::CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asIScriptFunction **outFunc) -{ - // Make sure the outFunc is null if the function fails, so the - // application doesn't attempt to release a non-existent function - if( outFunc ) - *outFunc = 0; - -#ifdef AS_NO_COMPILER - UNUSED_VAR(sectionName); - UNUSED_VAR(code); - UNUSED_VAR(lineOffset); - UNUSED_VAR(compileFlags); - return asNOT_SUPPORTED; -#else - // Validate arguments - if( code == 0 || - (compileFlags != 0 && compileFlags != asCOMP_ADD_TO_MODULE) ) - return asINVALID_ARG; - - // Only one thread may build at one time - // TODO: It should be possible to have multiple threads perform compilations - int r = engine->RequestBuild(); - if( r < 0 ) - return r; - - // Prepare the engine - engine->PrepareEngine(); - if( engine->configFailed ) - { - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); - engine->BuildCompleted(); - return asINVALID_CONFIGURATION; - } - - // Compile the single function - asCBuilder builder(engine, this); - asCString str = code; - asCScriptFunction *func = 0; - r = builder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func); - - engine->BuildCompleted(); - - if( r >= 0 && outFunc && func ) - { - // Return the function to the caller - *outFunc = func; - func->AddRef(); - } - - // Release our reference to the function - if( func ) - func->Release(); - - return r; -#endif -} - -// interface -int asCModule::RemoveFunction(asIScriptFunction *func) -{ - // Find the global function - asCScriptFunction *f = static_cast(func); - int idx = globalFunctions.GetIndex(f); - if( idx >= 0 ) - { - globalFunctions.Erase(idx); - f->Release(); - scriptFunctions.RemoveValue(f); - f->Orphan(this); - return 0; - } - - return asNO_FUNCTION; -} - -#ifndef AS_NO_COMPILER -// internal -int asCModule::AddFuncDef(const asCString &name, asSNameSpace *ns) -{ - asCScriptFunction *func = asNEW(asCScriptFunction)(engine, 0, asFUNC_FUNCDEF); - if( func == 0 ) - return asOUT_OF_MEMORY; - - func->name = name; - func->nameSpace = ns; - - funcDefs.PushLast(func); - - engine->funcDefs.PushLast(func); - func->id = engine->GetNextScriptFunctionId(); - engine->SetScriptFunction(func); - - return (int)funcDefs.GetLength()-1; -} -#endif - -// interface -asDWORD asCModule::SetAccessMask(asDWORD mask) -{ - asDWORD old = accessMask; - accessMask = mask; - return old; -} - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_module.h b/dependencies/angelscript/source/as_module.h deleted file mode 100644 index aca7bc57..00000000 --- a/dependencies/angelscript/source/as_module.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - -// -// as_module.h -// -// A class that holds a script module -// - -#ifndef AS_MODULE_H -#define AS_MODULE_H - -#include "as_config.h" -#include "as_symboltable.h" -#include "as_atomic.h" -#include "as_string.h" -#include "as_array.h" -#include "as_datatype.h" -#include "as_scriptfunction.h" -#include "as_property.h" - -BEGIN_AS_NAMESPACE - -// TODO: import: Remove this when the imported functions are removed -const int FUNC_IMPORTED = 0x40000000; - -class asCScriptEngine; -class asCCompiler; -class asCBuilder; -class asCContext; -class asCConfigGroup; -struct asSNameSpace; - -struct sBindInfo -{ - asCScriptFunction *importedFunctionSignature; - asCString importFromModule; - int boundFunctionId; -}; - -struct sObjectTypePair -{ - asCObjectType *a; - asCObjectType *b; -}; - - -// TODO: import: Remove function imports. When I have implemented function -// pointers the function imports should be deprecated. - -// TODO: Need a separate interface for compiling scripts. The asIScriptCompiler -// will have a target module, and will allow the compilation of an entire -// script or just individual functions within the scope of the module -// -// With this separation it will be possible to compile the library without -// the compiler, thus giving a much smaller binary executable. - -// TODO: There should be an special compile option that will let the application -// recompile an already compiled script. The compiler should check if no -// destructive changes have been made (changing function signatures, etc) -// then it should simply replace the bytecode within the functions without -// changing the values of existing global properties, etc. - -class asCModule : public asIScriptModule -{ -//------------------------------------------- -// Public interface -//-------------------------------------------- -public: - virtual asIScriptEngine *GetEngine() const; - virtual void SetName(const char *name); - virtual const char *GetName() const; - virtual void Discard(); - - // Compilation - virtual int AddScriptSection(const char *name, const char *code, size_t codeLength, int lineOffset); - virtual int Build(); - virtual int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD reserved, asIScriptFunction **outFunc); - virtual int CompileGlobalVar(const char *sectionName, const char *code, int lineOffset); - virtual asDWORD SetAccessMask(asDWORD accessMask); - virtual int SetDefaultNamespace(const char *nameSpace); - virtual const char *GetDefaultNamespace() const; - - // Script functions - virtual asUINT GetFunctionCount() const; - virtual asIScriptFunction *GetFunctionByIndex(asUINT index) const; - virtual asIScriptFunction *GetFunctionByDecl(const char *decl) const; - virtual asIScriptFunction *GetFunctionByName(const char *name) const; - virtual int RemoveFunction(asIScriptFunction *func); - - // Script global variables - // TODO: interface: Should be called InitGlobalVars, and should have a bool to reset in case already initialized - virtual int ResetGlobalVars(asIScriptContext *ctx); - virtual asUINT GetGlobalVarCount() const; - virtual int GetGlobalVarIndexByName(const char *name) const; - virtual int GetGlobalVarIndexByDecl(const char *decl) const; - virtual const char *GetGlobalVarDeclaration(asUINT index, bool includeNamespace) const; - virtual int GetGlobalVar(asUINT index, const char **name, const char **nameSpace, int *typeId, bool *isConst) const; - virtual void *GetAddressOfGlobalVar(asUINT index); - virtual int RemoveGlobalVar(asUINT index); - - // Type identification - virtual asUINT GetObjectTypeCount() const; - virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const; - virtual asIObjectType *GetObjectTypeByName(const char *name) const; - virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const; - virtual int GetTypeIdByDecl(const char *decl) const; - - // Enums - virtual asUINT GetEnumCount() const; - virtual const char *GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace) const; - virtual int GetEnumValueCount(int enumTypeId) const; - virtual const char *GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const; - - // Typedefs - virtual asUINT GetTypedefCount() const; - virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace) const; - - // Dynamic binding between modules - virtual asUINT GetImportedFunctionCount() const; - virtual int GetImportedFunctionIndexByDecl(const char *decl) const; - virtual const char *GetImportedFunctionDeclaration(asUINT importIndex) const; - virtual const char *GetImportedFunctionSourceModule(asUINT importIndex) const; - virtual int BindImportedFunction(asUINT index, asIScriptFunction *func); - virtual int UnbindImportedFunction(asUINT importIndex); - virtual int BindAllImportedFunctions(); - virtual int UnbindAllImportedFunctions(); - - // Bytecode Saving/Loading - virtual int SaveByteCode(asIBinaryStream *out, bool stripDebugInfo) const; - virtual int LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped); - - // User data - virtual void *SetUserData(void *data, asPWORD type); - virtual void *GetUserData(asPWORD type) const; - -//----------------------------------------------- -// Internal -//----------------------------------------------- - asCModule(const char *name, asCScriptEngine *engine); - ~asCModule(); - -//protected: - friend class asCScriptEngine; - friend class asCBuilder; - friend class asCCompiler; - friend class asCContext; - friend class asCRestore; - - void InternalReset(); - bool IsEmpty() const; - - int CallInit(asIScriptContext *ctx); - void CallExit(); - - void JITCompile(); - -#ifndef AS_NO_COMPILER - int AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType = 0, bool isConstMethod = false, bool isGlobalFunction = false, bool isPrivate = false, bool isFinal = false, bool isOverride = false, bool isShared = false, asSNameSpace *ns = 0); - int AddScriptFunction(asCScriptFunction *func); - int AddImportedFunction(int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSNameSpace *ns, const asCString &moduleName); - int AddFuncDef(const asCString &name, asSNameSpace *ns); -#endif - - int GetNextImportedFunctionId(); - asCScriptFunction *GetImportedFunction(int funcId) const; - asCObjectType *GetObjectType(const char *type, asSNameSpace *ns); - asCGlobalProperty *AllocateGlobalProperty(const char *name, const asCDataType &dt, asSNameSpace *ns); - - asCString name; - - asCScriptEngine *engine; - asCBuilder *builder; - asCArray userData; - asDWORD accessMask; - asSNameSpace *defaultNamespace; - - // This array holds all functions, class members, factories, etc that were compiled with the module - asCArray scriptFunctions; - // This array holds global functions declared in the module - asCSymbolTable globalFunctions; - // This array holds imported functions in the module - asCArray bindInformations; - - // This array holds the global variables declared in the script - asCSymbolTable scriptGlobals; - bool isGlobalVarInitialized; - - // This array holds class and interface types - asCArray classTypes; - // This array holds enum types - asCArray enumTypes; - // This array holds typedefs - asCArray typeDefs; - // This array holds the funcdefs declared in the module - asCArray funcDefs; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_namespace.h b/dependencies/angelscript/source/as_namespace.h deleted file mode 100644 index a155801e..00000000 --- a/dependencies/angelscript/source/as_namespace.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2013-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -#ifndef AS_NAMESPACE_H -#define AS_NAMESPACE_H - -#include "as_string.h" - -BEGIN_AS_NAMESPACE - -struct asSNameSpace -{ - asCString name; - - // TODO: namespace: A namespace should have access masks. The application should be - // able to restrict specific namespaces from access to specific modules -}; - - -struct asSNameSpaceNamePair -{ - const asSNameSpace *ns; - asCString name; - - asSNameSpaceNamePair() : ns(0) {} - asSNameSpaceNamePair(const asSNameSpace *_ns, const asCString &_name) : ns(_ns), name(_name) {} - - asSNameSpaceNamePair &operator=(const asSNameSpaceNamePair &other) - { - ns = other.ns; - name = other.name; - return *this; - } - - bool operator==(const asSNameSpaceNamePair &other) const - { - return (ns == other.ns && name == other.name); - } - - bool operator<(const asSNameSpaceNamePair &other) const - { - return (ns < other.ns || (ns == other.ns && name < other.name)); - } -}; - -END_AS_NAMESPACE - -#endif - diff --git a/dependencies/angelscript/source/as_objecttype.cpp b/dependencies/angelscript/source/as_objecttype.cpp deleted file mode 100644 index 4d209b37..00000000 --- a/dependencies/angelscript/source/as_objecttype.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_objecttype.cpp -// -// A class for storing object type information -// - - -#include - -#include "as_config.h" -#include "as_objecttype.h" -#include "as_configgroup.h" -#include "as_scriptengine.h" - -BEGIN_AS_NAMESPACE - -#ifdef AS_MAX_PORTABILITY - -static void ObjectType_AddRef_Generic(asIScriptGeneric *gen) -{ - asCObjectType *self = (asCObjectType*)gen->GetObject(); - self->AddRef(); -} - -static void ObjectType_Release_Generic(asIScriptGeneric *gen) -{ - asCObjectType *self = (asCObjectType*)gen->GetObject(); - self->Release(); -} - -static void ObjectType_GetRefCount_Generic(asIScriptGeneric *gen) -{ - asCObjectType *self = (asCObjectType*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); -} - -static void ObjectType_SetGCFlag_Generic(asIScriptGeneric *gen) -{ - asCObjectType *self = (asCObjectType*)gen->GetObject(); - self->SetGCFlag(); -} - -static void ObjectType_GetGCFlag_Generic(asIScriptGeneric *gen) -{ - asCObjectType *self = (asCObjectType*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag(); -} - -static void ObjectType_EnumReferences_Generic(asIScriptGeneric *gen) -{ - asCObjectType *self = (asCObjectType*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); -} - -static void ObjectType_ReleaseAllHandles_Generic(asIScriptGeneric *gen) -{ - asCObjectType *self = (asCObjectType*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllHandles(engine); -} - -#endif - - -void RegisterObjectTypeGCBehaviours(asCScriptEngine *engine) -{ - // Register the gc behaviours for the object types - int r = 0; - UNUSED_VAR(r); // It is only used in debug mode - engine->objectTypeBehaviours.engine = engine; - engine->objectTypeBehaviours.flags = asOBJ_REF | asOBJ_GC; - engine->objectTypeBehaviours.name = "_builtin_objecttype_"; -#ifndef AS_MAX_PORTABILITY - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCObjectType,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCObjectType,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCObjectType,GetRefCount), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCObjectType,SetGCFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCObjectType,GetGCFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCObjectType,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCObjectType,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 ); -#else - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ObjectType_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ObjectType_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ObjectType_GetRefCount_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ObjectType_SetGCFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ObjectType_GetGCFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ObjectType_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ObjectType_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); -#endif -} - -asCObjectType::asCObjectType() -{ - engine = 0; - module = 0; - refCount.set(0); - derivedFrom = 0; - - acceptValueSubType = true; - acceptRefSubType = true; - - accessMask = 0xFFFFFFFF; - nameSpace = 0; -#ifdef WIP_16BYTE_ALIGN - alignment = 4; -#endif -} - -asCObjectType::asCObjectType(asCScriptEngine *engine) -{ - this->engine = engine; - module = 0; - refCount.set(0); - derivedFrom = 0; - - acceptValueSubType = true; - acceptRefSubType = true; - - accessMask = 0xFFFFFFFF; - nameSpace = engine->nameSpaces[0]; -#ifdef WIP_16BYTE_ALIGN - alignment = 4; -#endif -} - -int asCObjectType::AddRef() const -{ - gcFlag = false; - return refCount.atomicInc(); -} - -int asCObjectType::Release() const -{ - gcFlag = false; - int r = refCount.atomicDec(); - - if( r == 0 && engine == 0 ) - { - // If the engine is no longer set, then it has already been - // released and we must take care of the deletion ourselves - asDELETE(const_cast(this), asCObjectType); - } - - return r; -} - -void asCObjectType::Orphan(asCModule *mod) -{ - if( mod && mod == module ) - { - module = 0; - if( flags & asOBJ_SCRIPT_OBJECT ) - { - // Tell the GC that this type exists so it can resolve potential circular references - engine->gc.AddScriptObjectToGC(this, &engine->objectTypeBehaviours); - } - - // It's necessary to orphan the template instance types that refer to this object type, - // otherwise the garbage collector cannot identify the circular references that involve - // the type and the template type - engine->OrphanTemplateInstances(this); - } - - Release(); -} - -// interface -asIScriptModule *asCObjectType::GetModule() const -{ - return module; -} - -void *asCObjectType::SetUserData(void *data, asPWORD type) -{ - // As a thread might add a new new user data at the same time as another - // it is necessary to protect both read and write access to the userData member - ACQUIREEXCLUSIVE(engine->engineRWLock); - - // It is not intended to store a lot of different types of userdata, - // so a more complex structure like a associative map would just have - // more overhead than a simple array. - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - void *oldData = reinterpret_cast(userData[n+1]); - userData[n+1] = reinterpret_cast(data); - - RELEASEEXCLUSIVE(engine->engineRWLock); - - return oldData; - } - } - - userData.PushLast(type); - userData.PushLast(reinterpret_cast(data)); - - RELEASEEXCLUSIVE(engine->engineRWLock); - - return 0; -} - -void *asCObjectType::GetUserData(asPWORD type) const -{ - // There may be multiple threads reading, but when - // setting the user data nobody must be reading. - ACQUIRESHARED(engine->engineRWLock); - - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - RELEASESHARED(engine->engineRWLock); - return reinterpret_cast(userData[n+1]); - } - } - - RELEASESHARED(engine->engineRWLock); - - return 0; -} - -int asCObjectType::GetRefCount() -{ - return refCount.get(); -} - -bool asCObjectType::GetGCFlag() -{ - return gcFlag; -} - -void asCObjectType::SetGCFlag() -{ - gcFlag = true; -} - -void asCObjectType::DropFromEngine() -{ - DestroyInternal(); - - // If the ref counter reached zero while doing the above clean-up then we must delete the object now - if( refCount.get() == 0 ) - asDELETE(this, asCObjectType); -} - -void asCObjectType::DestroyInternal() -{ - if( engine == 0 ) return; - - // Skip this for list patterns as they do not increase the references - if( flags & asOBJ_LIST_PATTERN ) - { - // Clear the engine pointer to mark the object type as invalid - engine = 0; - return; - } - - // Release the object types held by the templateSubTypes - for( asUINT subtypeIndex = 0; subtypeIndex < templateSubTypes.GetLength(); subtypeIndex++ ) - { - if( templateSubTypes[subtypeIndex].GetObjectType() ) - templateSubTypes[subtypeIndex].GetObjectType()->Release(); - } - templateSubTypes.SetLength(0); - - if( derivedFrom ) - derivedFrom->Release(); - derivedFrom = 0; - - ReleaseAllProperties(); - - ReleaseAllFunctions(); - - asUINT n; - for( n = 0; n < enumValues.GetLength(); n++ ) - { - if( enumValues[n] ) - asDELETE(enumValues[n],asSEnumValue); - } - enumValues.SetLength(0); - - // Clean the user data - for( n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n+1] ) - { - for( asUINT c = 0; c < engine->cleanObjectTypeFuncs.GetLength(); c++ ) - if( engine->cleanObjectTypeFuncs[c].type == userData[n] ) - engine->cleanObjectTypeFuncs[c].cleanFunc(this); - } - } - userData.SetLength(0); - - // Clear the engine pointer to mark the object type as invalid - engine = 0; -} - -asCObjectType::~asCObjectType() -{ - DestroyInternal(); -} - -// interface -bool asCObjectType::Implements(const asIObjectType *objType) const -{ - if( this == objType ) - return true; - - for( asUINT n = 0; n < interfaces.GetLength(); n++ ) - if( interfaces[n] == objType ) return true; - - return false; -} - -// interface -bool asCObjectType::DerivesFrom(const asIObjectType *objType) const -{ - if( this == objType ) - return true; - - asCObjectType *base = derivedFrom; - while( base ) - { - if( base == objType ) - return true; - - base = base->derivedFrom; - } - - return false; -} - -bool asCObjectType::IsShared() const -{ - // Objects that can be declared by scripts need to have the explicit flag asOBJ_SHARED - if( flags & (asOBJ_SCRIPT_OBJECT|asOBJ_ENUM) ) return flags & asOBJ_SHARED ? true : false; - - // Otherwise we assume the object to be shared - return true; -} - -// interface -const char *asCObjectType::GetName() const -{ - return name.AddressOf(); -} - -// interface -const char *asCObjectType::GetNamespace() const -{ - return nameSpace->name.AddressOf(); -} - -// interface -asDWORD asCObjectType::GetFlags() const -{ - return flags; -} - -// interface -asUINT asCObjectType::GetSize() const -{ - return size; -} - -// interface -int asCObjectType::GetTypeId() const -{ - // We need a non const pointer to create the asCDataType object. - // We're not breaking anything here because this function is not - // modifying the object, so this const cast is safe. - asCObjectType *ot = const_cast(this); - - return engine->GetTypeIdFromDataType(asCDataType::CreateObject(ot, false)); -} - -// interface -int asCObjectType::GetSubTypeId(asUINT subtypeIndex) const -{ - // This method is only supported for templates and template specializations - if( templateSubTypes.GetLength() == 0 ) - return asERROR; - - if( subtypeIndex >= templateSubTypes.GetLength() ) - return asINVALID_ARG; - - return engine->GetTypeIdFromDataType(templateSubTypes[subtypeIndex]); -} - -// interface -asIObjectType *asCObjectType::GetSubType(asUINT subtypeIndex) const -{ - if( subtypeIndex >= templateSubTypes.GetLength() ) - return 0; - - return templateSubTypes[subtypeIndex].GetObjectType(); -} - -asUINT asCObjectType::GetSubTypeCount() const -{ - return asUINT(templateSubTypes.GetLength()); -} - -asUINT asCObjectType::GetInterfaceCount() const -{ - return asUINT(interfaces.GetLength()); -} - -asIObjectType *asCObjectType::GetInterface(asUINT index) const -{ - return interfaces[index]; -} - -// internal -bool asCObjectType::IsInterface() const -{ - if( (flags & asOBJ_SCRIPT_OBJECT) && size == 0 ) - return true; - - return false; -} - -asIScriptEngine *asCObjectType::GetEngine() const -{ - return engine; -} - -// interface -asUINT asCObjectType::GetFactoryCount() const -{ - return (asUINT)beh.factories.GetLength(); -} - -// interface -asIScriptFunction *asCObjectType::GetFactoryByIndex(asUINT index) const -{ - if( index >= beh.factories.GetLength() ) - return 0; - - return engine->GetFunctionById(beh.factories[index]); -} - -// interface -asIScriptFunction *asCObjectType::GetFactoryByDecl(const char *decl) const -{ - if( beh.factories.GetLength() == 0 ) - return 0; - - // Let the engine parse the string and find the appropriate factory function - return engine->GetFunctionById(engine->GetFactoryIdByDecl(this, decl)); -} - -// interface -asUINT asCObjectType::GetMethodCount() const -{ - return (asUINT)methods.GetLength(); -} - -// interface -asIScriptFunction *asCObjectType::GetMethodByIndex(asUINT index, bool getVirtual) const -{ - if( index >= methods.GetLength() ) - return 0; - - asCScriptFunction *func = engine->scriptFunctions[methods[index]]; - if( !getVirtual ) - { - if( func && func->funcType == asFUNC_VIRTUAL ) - return virtualFunctionTable[func->vfTableIdx]; - } - - return func; -} - -// interface -asIScriptFunction *asCObjectType::GetMethodByName(const char *name, bool getVirtual) const -{ - int id = -1; - for( size_t n = 0; n < methods.GetLength(); n++ ) - { - if( engine->scriptFunctions[methods[n]]->name == name ) - { - if( id == -1 ) - id = methods[n]; - else - return 0; - } - } - - if( id == -1 ) return 0; - - asCScriptFunction *func = engine->scriptFunctions[id]; - if( !getVirtual ) - { - if( func && func->funcType == asFUNC_VIRTUAL ) - return virtualFunctionTable[func->vfTableIdx]; - } - - return func; -} - -// interface -asIScriptFunction *asCObjectType::GetMethodByDecl(const char *decl, bool getVirtual) const -{ - if( methods.GetLength() == 0 ) - return 0; - - // Get the module from one of the methods, but it will only be - // used to allow the parsing of types not already known by the object. - // It is possible for object types to be orphaned, e.g. by discarding - // the module that created it. In this case it is still possible to - // find the methods, but any type not known by the object will result in - // an invalid declaration. - asCModule *mod = engine->scriptFunctions[methods[0]]->module; - int id = engine->GetMethodIdByDecl(this, decl, mod); - if( id <= 0 ) - return 0; - - if( !getVirtual ) - { - asCScriptFunction *func = engine->scriptFunctions[id]; - if( func && func->funcType == asFUNC_VIRTUAL ) - return virtualFunctionTable[func->vfTableIdx]; - } - - return engine->scriptFunctions[id]; -} - -// interface -asUINT asCObjectType::GetPropertyCount() const -{ - return (asUINT)properties.GetLength(); -} - -// interface -int asCObjectType::GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, int *offset, bool *isReference, asDWORD *accessMask) const -{ - if( index >= properties.GetLength() ) - return asINVALID_ARG; - - if( name ) - *name = properties[index]->name.AddressOf(); - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(properties[index]->type); - if( isPrivate ) - *isPrivate = properties[index]->isPrivate; - if( offset ) - *offset = properties[index]->byteOffset; - if( isReference ) - *isReference = properties[index]->type.IsReference(); - if( accessMask ) - *accessMask = properties[index]->accessMask; - - return 0; -} - -// interface -const char *asCObjectType::GetPropertyDeclaration(asUINT index, bool includeNamespace) const -{ - if( index >= properties.GetLength() ) - return 0; - - asCString *tempString = &asCThreadManager::GetLocalData()->string; - if( properties[index]->isPrivate ) - *tempString = "private "; - else - *tempString = ""; - *tempString += properties[index]->type.Format(includeNamespace); - *tempString += " "; - *tempString += properties[index]->name; - - return tempString->AddressOf(); -} - -asIObjectType *asCObjectType::GetBaseType() const -{ - return derivedFrom; -} - -asUINT asCObjectType::GetBehaviourCount() const -{ - // Count the number of behaviours (except factory functions) - asUINT count = 0; - - if( beh.destruct ) count++; - if( beh.addref ) count++; - if( beh.release ) count++; - if( beh.gcGetRefCount ) count++; - if( beh.gcSetFlag ) count++; - if( beh.gcGetFlag ) count++; - if( beh.gcEnumReferences ) count++; - if( beh.gcReleaseAllReferences ) count++; - if( beh.templateCallback ) count++; - if( beh.listFactory ) count++; - if( beh.getWeakRefFlag ) count++; - - // For reference types, the factories are also stored in the constructor - // list, so it is sufficient to enumerate only those - count += (asUINT)beh.constructors.GetLength(); - count += (asUINT)beh.operators.GetLength() / 2; - - return count; -} - -asIScriptFunction *asCObjectType::GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const -{ - // Find the correct behaviour - asUINT count = 0; - - if( beh.destruct && count++ == index ) // only increase count if the behaviour is registered - { - if( outBehaviour ) *outBehaviour = asBEHAVE_DESTRUCT; - return engine->scriptFunctions[beh.destruct]; - } - - if( beh.addref && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_ADDREF; - return engine->scriptFunctions[beh.addref]; - } - - if( beh.release && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_RELEASE; - return engine->scriptFunctions[beh.release]; - } - - if( beh.gcGetRefCount && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_GETREFCOUNT; - return engine->scriptFunctions[beh.gcGetRefCount]; - } - - if( beh.gcSetFlag && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_SETGCFLAG; - return engine->scriptFunctions[beh.gcSetFlag]; - } - - if( beh.gcGetFlag && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_GETGCFLAG; - return engine->scriptFunctions[beh.gcGetFlag]; - } - - if( beh.gcEnumReferences && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_ENUMREFS; - return engine->scriptFunctions[beh.gcEnumReferences]; - } - - if( beh.gcReleaseAllReferences && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_RELEASEREFS; - return engine->scriptFunctions[beh.gcReleaseAllReferences]; - } - - if( beh.templateCallback && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_TEMPLATE_CALLBACK; - return engine->scriptFunctions[beh.templateCallback]; - } - - if( beh.listFactory && count++ == index ) - { - if( outBehaviour ) - { - if( flags & asOBJ_VALUE ) - *outBehaviour = asBEHAVE_LIST_CONSTRUCT; - else - *outBehaviour = asBEHAVE_LIST_FACTORY; - } - - return engine->scriptFunctions[beh.listFactory]; - } - - if( beh.getWeakRefFlag && count++ == index ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_GET_WEAKREF_FLAG; - return engine->scriptFunctions[beh.getWeakRefFlag]; - } - - // For reference types, the factories are also stored in the constructor - // list, so it is sufficient to enumerate only those - if( index - count < beh.constructors.GetLength() ) - { - if( outBehaviour ) *outBehaviour = asBEHAVE_CONSTRUCT; - return engine->scriptFunctions[beh.constructors[index - count]]; - } - else - count += (asUINT)beh.constructors.GetLength(); - - if( index - count < beh.operators.GetLength() / 2 ) - { - index = 2*(index - count); - - if( outBehaviour ) *outBehaviour = static_cast(beh.operators[index]); - return engine->scriptFunctions[beh.operators[index + 1]]; - } - - return 0; -} - -// interface -const char *asCObjectType::GetConfigGroup() const -{ - asCConfigGroup *group = engine->FindConfigGroupForObjectType(this); - if( group == 0 ) - return 0; - - return group->groupName.AddressOf(); -} - -// interface -asDWORD asCObjectType::GetAccessMask() const -{ - return accessMask; -} - -// internal -asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate) -{ - asASSERT( flags & asOBJ_SCRIPT_OBJECT ); - asASSERT( dt.CanBeInstantiated() ); - asASSERT( !IsInterface() ); - - // Store the properties in the object type descriptor - asCObjectProperty *prop = asNEW(asCObjectProperty); - if( prop == 0 ) - { - // Out of memory - return 0; - } - - prop->name = name; - prop->type = dt; - prop->isPrivate = isPrivate; - - int propSize; - if( dt.IsObject() ) - { - // Non-POD value types can't be allocated inline, - // because there is a risk that the script might - // try to access the content without knowing that - // it hasn't been initialized yet. - if( dt.GetObjectType()->flags & asOBJ_POD ) - propSize = dt.GetSizeInMemoryBytes(); - else - { - propSize = dt.GetSizeOnStackDWords()*4; - if( !dt.IsObjectHandle() ) - prop->type.MakeReference(true); - } - } - else - propSize = dt.GetSizeInMemoryBytes(); - - // Add extra bytes so that the property will be properly aligned -#ifndef WIP_16BYTE_ALIGN - if( propSize == 2 && (size & 1) ) size += 1; - if( propSize > 2 && (size & 3) ) size += 4 - (size & 3); -#else - asUINT alignment = dt.GetAlignment(); - const asUINT propSizeAlignmentDifference = size & (alignment-1); - if( propSizeAlignmentDifference != 0 ) - { - size += (alignment - propSizeAlignmentDifference); - } - - asASSERT((size % alignment) == 0); -#endif - - prop->byteOffset = size; - size += propSize; - - properties.PushLast(prop); - - // Make sure the struct holds a reference to the config group where the object is registered - asCConfigGroup *group = engine->FindConfigGroupForObjectType(prop->type.GetObjectType()); - if( group != 0 ) group->AddRef(); - - // Add reference to object types - asCObjectType *type = prop->type.GetObjectType(); - if( type ) - type->AddRef(); - - return prop; -} - -// internal -void asCObjectType::ReleaseAllProperties() -{ - for( asUINT n = 0; n < properties.GetLength(); n++ ) - { - if( properties[n] ) - { - if( flags & asOBJ_SCRIPT_OBJECT ) - { - // Release the config group for script classes that are being destroyed - asCConfigGroup *group = engine->FindConfigGroupForObjectType(properties[n]->type.GetObjectType()); - if( group != 0 ) group->Release(); - - // Release references to objects types - asCObjectType *type = properties[n]->type.GetObjectType(); - if( type ) - type->Release(); - } - else - { - // Release template instance types (ref increased by RegisterObjectProperty) - asCObjectType *type = properties[n]->type.GetObjectType(); - if( type ) - type->Release(); - } - - asDELETE(properties[n],asCObjectProperty); - } - } - - properties.SetLength(0); -} - -// internal -void asCObjectType::ReleaseAllHandles(asIScriptEngine *) -{ - ReleaseAllFunctions(); - ReleaseAllProperties(); -} - -// internal -void asCObjectType::ReleaseAllFunctions() -{ - beh.factory = 0; - beh.copyfactory = 0; - for( asUINT a = 0; a < beh.factories.GetLength(); a++ ) - { - if( engine->scriptFunctions[beh.factories[a]] ) - engine->scriptFunctions[beh.factories[a]]->Release(); - } - beh.factories.SetLength(0); - - beh.construct = 0; - beh.copyconstruct = 0; - for( asUINT b = 0; b < beh.constructors.GetLength(); b++ ) - { - if( engine->scriptFunctions[beh.constructors[b]] ) - engine->scriptFunctions[beh.constructors[b]]->Release(); - } - beh.constructors.SetLength(0); - - if( beh.templateCallback ) - engine->scriptFunctions[beh.templateCallback]->Release(); - beh.templateCallback = 0; - - if( beh.listFactory ) - engine->scriptFunctions[beh.listFactory]->Release(); - beh.listFactory = 0; - - if( beh.destruct ) - engine->scriptFunctions[beh.destruct]->Release(); - beh.destruct = 0; - - if( beh.copy ) - engine->scriptFunctions[beh.copy]->Release(); - beh.copy = 0; - - for( asUINT e = 1; e < beh.operators.GetLength(); e += 2 ) - { - if( engine->scriptFunctions[beh.operators[e]] ) - engine->scriptFunctions[beh.operators[e]]->Release(); - } - beh.operators.SetLength(0); - - for( asUINT c = 0; c < methods.GetLength(); c++ ) - { - if( engine->scriptFunctions[methods[c]] ) - engine->scriptFunctions[methods[c]]->Release(); - } - methods.SetLength(0); - - for( asUINT d = 0; d < virtualFunctionTable.GetLength(); d++ ) - { - if( virtualFunctionTable[d] ) - virtualFunctionTable[d]->Release(); - } - virtualFunctionTable.SetLength(0); - - // GC behaviours - if( beh.addref ) - engine->scriptFunctions[beh.addref]->Release(); - beh.addref = 0; - - if( beh.release ) - engine->scriptFunctions[beh.release]->Release(); - beh.release = 0; - - if( beh.gcEnumReferences ) - engine->scriptFunctions[beh.gcEnumReferences]->Release(); - beh.gcEnumReferences = 0; - - if( beh.gcGetFlag ) - engine->scriptFunctions[beh.gcGetFlag]->Release(); - beh.gcGetFlag = 0; - - if( beh.gcGetRefCount ) - engine->scriptFunctions[beh.gcGetRefCount]->Release(); - beh.gcGetRefCount = 0; - - if( beh.gcReleaseAllReferences ) - engine->scriptFunctions[beh.gcReleaseAllReferences]->Release(); - beh.gcReleaseAllReferences = 0; - - if( beh.gcSetFlag ) - engine->scriptFunctions[beh.gcSetFlag]->Release(); - beh.gcSetFlag = 0; - - if ( beh.getWeakRefFlag ) - engine->scriptFunctions[beh.getWeakRefFlag]->Release(); - beh.getWeakRefFlag = 0; -} - -// internal -void asCObjectType::EnumReferences(asIScriptEngine *) -{ - for( asUINT a = 0; a < beh.factories.GetLength(); a++ ) - if( engine->scriptFunctions[beh.factories[a]] ) - engine->GCEnumCallback(engine->scriptFunctions[beh.factories[a]]); - - for( asUINT b = 0; b < beh.constructors.GetLength(); b++ ) - if( engine->scriptFunctions[beh.constructors[b]] ) - engine->GCEnumCallback(engine->scriptFunctions[beh.constructors[b]]); - - if( beh.templateCallback ) - engine->GCEnumCallback(engine->scriptFunctions[beh.templateCallback]); - - if( beh.listFactory ) - engine->GCEnumCallback(engine->scriptFunctions[beh.listFactory]); - - if( beh.destruct ) - engine->GCEnumCallback(engine->scriptFunctions[beh.destruct]); - - if( beh.addref ) - engine->GCEnumCallback(engine->scriptFunctions[beh.addref]); - - if( beh.release ) - engine->GCEnumCallback(engine->scriptFunctions[beh.release]); - - if( beh.copy ) - engine->GCEnumCallback(engine->scriptFunctions[beh.copy]); - - if( beh.gcEnumReferences ) - engine->GCEnumCallback(engine->scriptFunctions[beh.gcEnumReferences]); - - if( beh.gcGetFlag ) - engine->GCEnumCallback(engine->scriptFunctions[beh.gcGetFlag]); - - if( beh.gcGetRefCount ) - engine->GCEnumCallback(engine->scriptFunctions[beh.gcGetRefCount]); - - if( beh.gcReleaseAllReferences ) - engine->GCEnumCallback(engine->scriptFunctions[beh.gcReleaseAllReferences]); - - if( beh.gcSetFlag ) - engine->GCEnumCallback(engine->scriptFunctions[beh.gcSetFlag]); - - for( asUINT e = 1; e < beh.operators.GetLength(); e += 2 ) - if( engine->scriptFunctions[beh.operators[e]] ) - engine->GCEnumCallback(engine->scriptFunctions[beh.operators[e]]); - - for( asUINT c = 0; c < methods.GetLength(); c++ ) - if( engine->scriptFunctions[methods[c]] ) - engine->GCEnumCallback(engine->scriptFunctions[methods[c]]); - - for( asUINT d = 0; d < virtualFunctionTable.GetLength(); d++ ) - if( virtualFunctionTable[d] ) - engine->GCEnumCallback(virtualFunctionTable[d]); - - for( asUINT p = 0; p < properties.GetLength(); p++ ) - { - asCObjectType *type = properties[p]->type.GetObjectType(); - if( type ) - engine->GCEnumCallback(type); - } - - for( asUINT t = 0; t < templateSubTypes.GetLength(); t++ ) - if( templateSubTypes[t].GetObjectType() ) - engine->GCEnumCallback(templateSubTypes[t].GetObjectType()); - - if( beh.getWeakRefFlag ) - engine->GCEnumCallback(engine->scriptFunctions[beh.getWeakRefFlag]); - - if( derivedFrom ) - engine->GCEnumCallback(derivedFrom); -} - -END_AS_NAMESPACE - - - diff --git a/dependencies/angelscript/source/as_objecttype.h b/dependencies/angelscript/source/as_objecttype.h deleted file mode 100644 index e3c4fc25..00000000 --- a/dependencies/angelscript/source/as_objecttype.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - -// -// as_objecttype.h -// -// A class for storing object type information -// - - - -#ifndef AS_OBJECTTYPE_H -#define AS_OBJECTTYPE_H - -#include "as_atomic.h" -#include "as_string.h" -#include "as_property.h" -#include "as_array.h" -#include "as_scriptfunction.h" - -BEGIN_AS_NAMESPACE - -// TODO: memory: Need to minimize used memory here, because not all types use all properties of the class - - -struct asSTypeBehaviour -{ - asSTypeBehaviour() - { - factory = 0; - listFactory = 0; - copyfactory = 0; - construct = 0; - copyconstruct = 0; - destruct = 0; - copy = 0; - addref = 0; - release = 0; - gcGetRefCount = 0; - gcSetFlag = 0; - gcGetFlag = 0; - gcEnumReferences = 0; - gcReleaseAllReferences = 0; - templateCallback = 0; - getWeakRefFlag = 0; - } - - int factory; - int listFactory; // Used for initialization lists only - int copyfactory; - int construct; - int copyconstruct; - int destruct; - int copy; - int addref; - int release; - int templateCallback; - - // GC behaviours - int gcGetRefCount; - int gcSetFlag; - int gcGetFlag; - int gcEnumReferences; - int gcReleaseAllReferences; - - // Weakref behaviours - int getWeakRefFlag; - - asCArray factories; - asCArray constructors; - asCArray operators; -}; - -struct asSEnumValue -{ - asCString name; - int value; -}; - -class asCScriptEngine; -struct asSNameSpace; - -void RegisterObjectTypeGCBehaviours(asCScriptEngine *engine); - -class asCObjectType : public asIObjectType -{ -public: -//===================================== -// From asIObjectType -//===================================== - asIScriptEngine *GetEngine() const; - const char *GetConfigGroup() const; - asDWORD GetAccessMask() const; - asIScriptModule *GetModule() const; - - // Memory management - int AddRef() const; - int Release() const; - - // Type info - const char *GetName() const; - const char *GetNamespace() const; - asIObjectType *GetBaseType() const; - bool DerivesFrom(const asIObjectType *objType) const; - asDWORD GetFlags() const; - asUINT GetSize() const; - int GetTypeId() const; - int GetSubTypeId(asUINT subtypeIndex = 0) const; - asIObjectType *GetSubType(asUINT subtypeIndex = 0) const; - asUINT GetSubTypeCount() const; - - // Interfaces - asUINT GetInterfaceCount() const; - asIObjectType *GetInterface(asUINT index) const; - bool Implements(const asIObjectType *objType) const; - - // Factories - asUINT GetFactoryCount() const; - asIScriptFunction *GetFactoryByIndex(asUINT index) const; - asIScriptFunction *GetFactoryByDecl(const char *decl) const; - - // Methods - asUINT GetMethodCount() const; - asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const; - asIScriptFunction *GetMethodByName(const char *name, bool getVirtual) const; - asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const; - - // Properties - asUINT GetPropertyCount() const; - int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, int *offset, bool *isReference, asDWORD *accessMask) const; - const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const; - - // Behaviours - asUINT GetBehaviourCount() const; - asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const; - - // User data - void *SetUserData(void *data, asPWORD type); - void *GetUserData(asPWORD type) const; - -//=========================================== -// Internal -//=========================================== -public: - asCObjectType(asCScriptEngine *engine); - ~asCObjectType(); - void DropFromEngine(); - void DestroyInternal(); - - void Orphan(asCModule *module); - int GetRefCount(); - void SetGCFlag(); - bool GetGCFlag(); - void EnumReferences(asIScriptEngine *); - void ReleaseAllHandles(asIScriptEngine *); - - void ReleaseAllFunctions(); - - bool IsInterface() const; - bool IsShared() const; - - asCObjectProperty *AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate); - void ReleaseAllProperties(); - - asCString name; - asSNameSpace *nameSpace; - int size; -#ifdef WIP_16BYTE_ALIGN - int alignment; -#endif - asCArray properties; - asCArray methods; - asCArray interfaces; - asCArray interfaceVFTOffsets; - asCArray enumValues; - asCObjectType * derivedFrom; - asCArray virtualFunctionTable; - - asDWORD flags; - asDWORD accessMask; - - asSTypeBehaviour beh; - - // Used for template types - asCArray templateSubTypes; - bool acceptValueSubType; - bool acceptRefSubType; - - asCScriptEngine *engine; - asCModule *module; - asCArray userData; - -protected: - friend class asCScriptEngine; - asCObjectType(); - - mutable asCAtomic refCount; - mutable bool gcFlag; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_outputbuffer.cpp b/dependencies/angelscript/source/as_outputbuffer.cpp deleted file mode 100644 index a5e09fbf..00000000 --- a/dependencies/angelscript/source/as_outputbuffer.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2012 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_outputbuffer.cpp -// -// This class appends strings to one large buffer that can later -// be sent to the real output stream -// - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_outputbuffer.h" -#include "as_scriptengine.h" - -BEGIN_AS_NAMESPACE - -asCOutputBuffer::~asCOutputBuffer() -{ - Clear(); -} - -void asCOutputBuffer::Clear() -{ - for( asUINT n = 0; n < messages.GetLength(); n++ ) - { - if( messages[n] ) - { - asDELETE(messages[n],message_t); - } - } - messages.SetLength(0); -} - -void asCOutputBuffer::Callback(asSMessageInfo *msg) -{ - message_t *msgInfo = asNEW(message_t); - if( msgInfo == 0 ) - return; - - msgInfo->section = msg->section; - msgInfo->row = msg->row; - msgInfo->col = msg->col; - msgInfo->type = msg->type; - msgInfo->msg = msg->message; - - messages.PushLast(msgInfo); -} - -void asCOutputBuffer::Append(asCOutputBuffer &in) -{ - for( asUINT n = 0; n < in.messages.GetLength(); n++ ) - messages.PushLast(in.messages[n]); - in.messages.SetLength(0); -} - -void asCOutputBuffer::SendToCallback(asCScriptEngine *engine, asSSystemFunctionInterface *func, void *obj) -{ - for( asUINT n = 0; n < messages.GetLength(); n++ ) - { - asSMessageInfo msg; - msg.section = messages[n]->section.AddressOf(); - msg.row = messages[n]->row; - msg.col = messages[n]->col; - msg.type = messages[n]->type; - msg.message = messages[n]->msg.AddressOf(); - - if( func->callConv < ICC_THISCALL ) - engine->CallGlobalFunction(&msg, obj, func, 0); - else - engine->CallObjectMethod(obj, &msg, func, 0); - } - Clear(); -} - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - diff --git a/dependencies/angelscript/source/as_outputbuffer.h b/dependencies/angelscript/source/as_outputbuffer.h deleted file mode 100644 index 0e00f488..00000000 --- a/dependencies/angelscript/source/as_outputbuffer.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2012 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_outputbuffer.h -// -// This class appends strings to one large buffer that can later -// be sent to the real output stream -// - - -#ifndef AS_OUTPUTBUFFER_H -#define AS_OUTPUTBUFFER_H - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_string.h" -#include "as_array.h" - -BEGIN_AS_NAMESPACE - -struct asSSystemFunctionInterface; -class asCScriptEngine; - -class asCOutputBuffer -{ -public: - ~asCOutputBuffer (); - void Clear(); - void Callback(asSMessageInfo *msg); - void Append(asCOutputBuffer &in); - void SendToCallback(asCScriptEngine *engine, asSSystemFunctionInterface *func, void *obj); - - struct message_t - { - asCString section; - int row; - int col; - asEMsgType type; - asCString msg; - }; - - asCArray messages; -}; - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - -#endif diff --git a/dependencies/angelscript/source/as_parser.cpp b/dependencies/angelscript/source/as_parser.cpp deleted file mode 100644 index 8a9db566..00000000 --- a/dependencies/angelscript/source/as_parser.cpp +++ /dev/null @@ -1,4130 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_parser.cpp -// -// This class parses the script code and builds a tree for compilation -// - - - -#include "as_config.h" -#include "as_parser.h" -#include "as_tokendef.h" -#include "as_texts.h" -#include "as_debug.h" - -#ifdef _MSC_VER -#pragma warning(disable:4702) // unreachable code -#endif - -BEGIN_AS_NAMESPACE - -asCParser::asCParser(asCBuilder *builder) -{ - this->builder = builder; - this->engine = builder->engine; - - script = 0; - scriptNode = 0; - checkValidTypes = false; - isParsingAppInterface = false; -} - -asCParser::~asCParser() -{ - Reset(); -} - -void asCParser::Reset() -{ - errorWhileParsing = false; - isSyntaxError = false; - checkValidTypes = false; - isParsingAppInterface = false; - - sourcePos = 0; - - if( scriptNode ) - { - scriptNode->Destroy(engine); - } - - scriptNode = 0; - - script = 0; - - lastToken.pos = size_t(-1); -} - -asCScriptNode *asCParser::GetScriptNode() -{ - return scriptNode; -} - -int asCParser::ParseFunctionDefinition(asCScriptCode *script, bool expectListPattern) -{ - Reset(); - - // Set flag that permits ? as datatype for parameters - isParsingAppInterface = true; - - this->script = script; - - scriptNode = ParseFunctionDefinition(); - - if( expectListPattern ) - scriptNode->AddChildLast(ParseListPattern()); - - // The declaration should end after the definition - if( !isSyntaxError ) - { - sToken t; - GetToken(&t); - if( t.type != ttEnd ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); - Error(InsteadFound(t), &t); - return -1; - } - } - - if( errorWhileParsing ) - return -1; - - return 0; -} - -asCScriptNode *asCParser::CreateNode(eScriptNode type) -{ - void *ptr = engine->memoryMgr.AllocScriptNode(); - if( ptr == 0 ) - { - // Out of memory - errorWhileParsing = true; - return 0; - } - - return new(ptr) asCScriptNode(type); -} - -int asCParser::ParseDataType(asCScriptCode *script, bool isReturnType) -{ - Reset(); - - this->script = script; - - scriptNode = CreateNode(snDataType); - if( scriptNode == 0 ) return -1; - - scriptNode->AddChildLast(ParseType(true)); - if( isSyntaxError ) return -1; - - if( isReturnType ) - { - scriptNode->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return -1; - } - - // The declaration should end after the type - sToken t; - GetToken(&t); - if( t.type != ttEnd ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); - Error(InsteadFound(t), &t); - return -1; - } - - if( errorWhileParsing ) - return -1; - - return 0; -} - - -// Parse a template declaration: IDENTIFIER '<' 'class'? IDENTIFIER '>' -int asCParser::ParseTemplateDecl(asCScriptCode *script) -{ - Reset(); - - this->script = script; - scriptNode = CreateNode(snUndefined); - if( scriptNode == 0 ) return -1; - - scriptNode->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return -1; - - sToken t; - GetToken(&t); - if( t.type != ttLessThan ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t); - Error(InsteadFound(t), &t); - return -1; - } - - // The class token is optional - GetToken(&t); - if( t.type != ttClass ) - RewindTo(&t); - - scriptNode->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return -1; - - // There can be multiple sub types - GetToken(&t); - - // Parse template types by list separator - while(t.type == ttListSeparator) - { - GetToken(&t); - if( t.type != ttClass ) - RewindTo(&t); - scriptNode->AddChildLast(ParseIdentifier()); - - if( isSyntaxError ) return -1; - GetToken(&t); - } - - if( t.type != ttGreaterThan ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t); - Error(InsteadFound(t), &t); - return -1; - } - - GetToken(&t); - if( t.type != ttEnd ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); - Error(InsteadFound(t), &t); - return -1; - } - - if( errorWhileParsing ) - return -1; - - return 0; -} - -int asCParser::ParsePropertyDeclaration(asCScriptCode *script) -{ - Reset(); - - this->script = script; - - scriptNode = CreateNode(snDeclaration); - if( scriptNode == 0 ) return -1; - - scriptNode->AddChildLast(ParseType(true)); - if( isSyntaxError ) return -1; - - // Allow optional namespace to be defined before the identifier in case - // the declaration is to be used for searching for an existing property - ParseOptionalScope(scriptNode); - - scriptNode->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return -1; - - // The declaration should end after the identifier - sToken t; - GetToken(&t); - if( t.type != ttEnd ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); - Error(InsteadFound(t), &t); - return -1; - } - - return 0; -} - -void asCParser::ParseOptionalScope(asCScriptNode *node) -{ - sToken t1, t2; - GetToken(&t1); - GetToken(&t2); - if( t1.type == ttScope ) - { - RewindTo(&t1); - node->AddChildLast(ParseToken(ttScope)); - GetToken(&t1); - GetToken(&t2); - } - while( t1.type == ttIdentifier && t2.type == ttScope ) - { - RewindTo(&t1); - node->AddChildLast(ParseIdentifier()); - node->AddChildLast(ParseToken(ttScope)); - GetToken(&t1); - GetToken(&t2); - } - RewindTo(&t1); -} - -asCScriptNode *asCParser::ParseFunctionDefinition() -{ - asCScriptNode *node = CreateNode(snFunction); - if( node == 0 ) return 0; - - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; - - ParseOptionalScope(node); - - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseParameterList()); - if( isSyntaxError ) return node; - - // Parse an optional const after the function definition (used for object methods) - sToken t1; - GetToken(&t1); - RewindTo(&t1); - if( t1.type == ttConst ) - node->AddChildLast(ParseToken(ttConst)); - - return node; -} - -asCScriptNode *asCParser::ParseTypeMod(bool isParam) -{ - asCScriptNode *node = CreateNode(snDataType); - if( node == 0 ) return 0; - - sToken t; - - // Parse possible & token - GetToken(&t); - RewindTo(&t); - if( t.type == ttAmp ) - { - node->AddChildLast(ParseToken(ttAmp)); - if( isSyntaxError ) return node; - - if( isParam ) - { - GetToken(&t); - RewindTo(&t); - - if( t.type == ttIn || t.type == ttOut || t.type == ttInOut ) - { - int tokens[3] = {ttIn, ttOut, ttInOut}; - node->AddChildLast(ParseOneOf(tokens, 3)); - } - } - } - - // Parse possible + token - GetToken(&t); - RewindTo(&t); - if( t.type == ttPlus ) - { - node->AddChildLast(ParseToken(ttPlus)); - if( isSyntaxError ) return node; - } - - return node; -} - -asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType, bool allowAuto) -{ - asCScriptNode *node = CreateNode(snDataType); - if( node == 0 ) return 0; - - sToken t; - - if( allowConst ) - { - GetToken(&t); - RewindTo(&t); - if( t.type == ttConst ) - { - node->AddChildLast(ParseToken(ttConst)); - if( isSyntaxError ) return node; - } - } - - // Parse scope prefix - ParseOptionalScope(node); - - // Parse the actual type - node->AddChildLast(ParseDataType(allowVariableType, allowAuto)); - if( isSyntaxError ) return node; - - // If the datatype is a template type, then parse the subtype within the < > - asCScriptNode *type = node->lastChild; - tempString.Assign(&script->code[type->tokenPos], type->tokenLength); - if( engine->IsTemplateType(tempString.AddressOf()) ) - { - GetToken(&t); - if( t.type != ttLessThan ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseType(true, false)); - if( isSyntaxError ) return node; - - GetToken(&t); - - // Parse template types by list separator - while(t.type == ttListSeparator) - { - node->AddChildLast(ParseType(true, false)); - - if( isSyntaxError ) return node; - GetToken(&t); - } - - // Accept >> and >>> tokens too. But then force the tokenizer to move - // only 1 character ahead (thus splitting the token in two). - if( script->code[t.pos] != '>' ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t); - Error(InsteadFound(t), &t); - return node; - } - else - { - // Break the token so that only the first > is parsed - SetPos(t.pos + 1); - } - } - - // Parse [] and @ - GetToken(&t); - RewindTo(&t); - while( t.type == ttOpenBracket || t.type == ttHandle) - { - if( t.type == ttOpenBracket ) - { - node->AddChildLast(ParseToken(ttOpenBracket)); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttCloseBracket ) - { - Error(ExpectedToken("]"), &t); - Error(InsteadFound(t), &t); - return node; - } - } - else - { - node->AddChildLast(ParseToken(ttHandle)); - if( isSyntaxError ) return node; - } - - GetToken(&t); - RewindTo(&t); - } - - return node; -} - -asCScriptNode *asCParser::ParseToken(int token) -{ - asCScriptNode *node = CreateNode(snUndefined); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - if( t1.type != token ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(token)), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->SetToken(&t1); - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -asCScriptNode *asCParser::ParseOneOf(int *tokens, int count) -{ - asCScriptNode *node = CreateNode(snUndefined); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - int n; - for( n = 0; n < count; n++ ) - { - if( tokens[n] == t1.type ) - break; - } - if( n == count ) - { - Error(ExpectedOneOf(tokens, count), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->SetToken(&t1); - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - - -asCScriptNode *asCParser::ParseDataType(bool allowVariableType, bool allowAuto) -{ - asCScriptNode *node = CreateNode(snDataType); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - if( !IsDataType(t1) && !(allowVariableType && t1.type == ttQuestion) && !(allowAuto && t1.type == ttAuto) ) - { - if( t1.type == ttIdentifier ) - { - asCString errMsg; - tempString.Assign(&script->code[t1.pos], t1.length); - errMsg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, tempString.AddressOf()); - Error(errMsg, &t1); - } - else if( t1.type == ttAuto ) - { - Error(TXT_AUTO_NOT_ALLOWED, &t1); - } - else - { - Error(TXT_EXPECTED_DATA_TYPE, &t1); - Error(InsteadFound(t1), &t1); - } - return node; - } - - node->SetToken(&t1); - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -asCScriptNode *asCParser::ParseRealType() -{ - asCScriptNode *node = CreateNode(snDataType); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - if( !IsRealType(t1.type) ) - { - Error(TXT_EXPECTED_DATA_TYPE, &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->SetToken(&t1); - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -asCScriptNode *asCParser::ParseIdentifier() -{ - asCScriptNode *node = CreateNode(snIdentifier); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - if( t1.type != ttIdentifier ) - { - Error(TXT_EXPECTED_IDENTIFIER, &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->SetToken(&t1); - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -asCScriptNode *asCParser::ParseParameterList() -{ - asCScriptNode *node = CreateNode(snParameterList); - if( node == 0 ) return 0; - - sToken t1; - GetToken(&t1); - if( t1.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - GetToken(&t1); - if( t1.type == ttCloseParanthesis ) - { - node->UpdateSourcePos(t1.pos, t1.length); - - // Statement block is finished - return node; - } - else - { - // If the parameter list is just (void) then the void token should be ignored - if( t1.type == ttVoid ) - { - sToken t2; - GetToken(&t2); - if( t2.type == ttCloseParanthesis ) - { - node->UpdateSourcePos(t2.pos, t2.length); - return node; - } - } - - RewindTo(&t1); - - for(;;) - { - // Parse data type - node->AddChildLast(ParseType(true, isParsingAppInterface)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseTypeMod(true)); - if( isSyntaxError ) return node; - - // Parse optional identifier - GetToken(&t1); - if( t1.type == ttIdentifier ) - { - RewindTo(&t1); - - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - GetToken(&t1); - } - - // Parse optional expression for the default arg - if( t1.type == ttAssignment ) - { - // Do a superficial parsing of the default argument - // The actual parsing will be done when the argument is compiled for a function call - node->AddChildLast(SuperficiallyParseExpression()); - if( isSyntaxError ) return node; - - GetToken(&t1); - } - - // Check if list continues - if( t1.type == ttCloseParanthesis ) - { - node->UpdateSourcePos(t1.pos, t1.length); - - return node; - } - else if( t1.type == ttListSeparator ) - continue; - else - { - Error(ExpectedTokens(")", ","), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - } - } - UNREACHABLE_RETURN; -} - -asCScriptNode *asCParser::SuperficiallyParseExpression() -{ - asCScriptNode *node = CreateNode(snExpression); - if( node == 0 ) return 0; - - // Simply parse everything until the first , or ), whichever comes first. - // Keeping in mind that () and {} can group expressions. - - sToken start; - GetToken(&start); - RewindTo(&start); - - asCString stack; - sToken t; - for(;;) - { - GetToken(&t); - - if( t.type == ttOpenParanthesis ) - stack += "("; - else if( t.type == ttCloseParanthesis ) - { - if( stack == "" ) - { - // Expression has ended. This token is not part of expression - RewindTo(&t); - break; - } - else if( stack[stack.GetLength()-1] == '(' ) - { - // Group has ended - stack.SetLength(stack.GetLength()-1); - } - else - { - // Wrong syntax - RewindTo(&t); - asCString str; - str.Format(TXT_UNEXPECTED_TOKEN_s, ")"); - Error(str, &t); - return node; - } - } - else if( t.type == ttListSeparator ) - { - if( stack == "" ) - { - // Expression has ended. This token is not part of expression - RewindTo(&t); - break; - } - } - else if( t.type == ttStartStatementBlock ) - stack += "{"; - else if( t.type == ttEndStatementBlock ) - { - if( stack == "" || stack[stack.GetLength()-1] != '{' ) - { - // Wrong syntax - RewindTo(&t); - asCString str; - str.Format(TXT_UNEXPECTED_TOKEN_s, "}"); - Error(str, &t); - return node; - } - else - { - // Group has ended - stack.SetLength(stack.GetLength()-1); - } - } - else if( t.type == ttEndStatement ) - { - // Wrong syntax (since we're parsing a default arg expression) - RewindTo(&t); - asCString str; - str.Format(TXT_UNEXPECTED_TOKEN_s, ";"); - Error(str, &t); - return node; - } - else if( t.type == ttNonTerminatedStringConstant ) - { - RewindTo(&t); - Error(TXT_NONTERMINATED_STRING, &t); - return node; - } - else if( t.type == ttEnd ) - { - // Wrong syntax - RewindTo(&t); - Error(TXT_UNEXPECTED_END_OF_FILE, &t); - Info(TXT_WHILE_PARSING_EXPRESSION, &start); - return node; - } - - // Include the token in the node - node->UpdateSourcePos(t.pos, t.length); - } - - return node; -} - -void asCParser::GetToken(sToken *token) -{ - // Check if the token has already been parsed - if( lastToken.pos == sourcePos ) - { - *token = lastToken; - sourcePos += token->length; - - if( token->type == ttWhiteSpace || - token->type == ttOnelineComment || - token->type == ttMultilineComment ) - GetToken(token); - - return; - } - - // Parse new token - size_t sourceLength = script->codeLength; - do - { - if( sourcePos >= sourceLength ) - { - token->type = ttEnd; - token->length = 0; - } - else - token->type = engine->tok.GetToken(&script->code[sourcePos], sourceLength - sourcePos, &token->length); - - token->pos = sourcePos; - - // Update state - sourcePos += token->length; - } - // Filter out whitespace and comments - while( token->type == ttWhiteSpace || - token->type == ttOnelineComment || - token->type == ttMultilineComment ); -} - -void asCParser::SetPos(size_t pos) -{ - lastToken.pos = size_t(-1); - sourcePos = pos; -} - -void asCParser::RewindTo(const sToken *token) -{ - // TODO: optimize: Perhaps we can optimize this further by having the parser - // set an explicit return point, after which each token will - // be stored. That way not just one token will be reused but - // no token will have to be tokenized more than once. - - // Store the token so it doesn't have to be tokenized again - lastToken = *token; - - sourcePos = token->pos; -} - -void asCParser::Error(const asCString &text, sToken *token) -{ - RewindTo(token); - - isSyntaxError = true; - errorWhileParsing = true; - - int row, col; - script->ConvertPosToRowCol(token->pos, &row, &col); - - if( builder ) - builder->WriteError(script->name, text, row, col); -} - -void asCParser::Warning(const asCString &text, sToken *token) -{ - int row, col; - script->ConvertPosToRowCol(token->pos, &row, &col); - - if( builder ) - builder->WriteWarning(script->name, text, row, col); -} - -void asCParser::Info(const asCString &text, sToken *token) -{ - RewindTo(token); - - isSyntaxError = true; - errorWhileParsing = true; - - int row, col; - script->ConvertPosToRowCol(token->pos, &row, &col); - - if( builder ) - builder->WriteInfo(script->name, text, row, col, false); -} - -bool asCParser::IsRealType(int tokenType) -{ - if( tokenType == ttVoid || - tokenType == ttInt || - tokenType == ttInt8 || - tokenType == ttInt16 || - tokenType == ttInt64 || - tokenType == ttUInt || - tokenType == ttUInt8 || - tokenType == ttUInt16 || - tokenType == ttUInt64 || - tokenType == ttFloat || - tokenType == ttBool || - tokenType == ttDouble ) - return true; - - return false; -} - -bool asCParser::IsDataType(const sToken &token) -{ - if( token.type == ttIdentifier ) - { -#ifndef AS_NO_COMPILER - if( checkValidTypes ) - { - // Check if this is an existing type, regardless of namespace - tempString.Assign(&script->code[token.pos], token.length); - if( !builder->DoesTypeExist(tempString.AddressOf()) ) - return false; - } -#endif - return true; - } - - if( IsRealType(token.type) ) - return true; - - return false; -} - -asCString asCParser::ExpectedToken(const char *token) -{ - asCString str; - - str.Format(TXT_EXPECTED_s, token); - - return str; -} - -asCString asCParser::ExpectedTokens(const char *t1, const char *t2) -{ - asCString str; - - str.Format(TXT_EXPECTED_s_OR_s, t1, t2); - - return str; -} - -asCString asCParser::ExpectedOneOf(int *tokens, int count) -{ - asCString str; - - str = TXT_EXPECTED_ONE_OF; - for( int n = 0; n < count; n++ ) - { - str += asCTokenizer::GetDefinition(tokens[n]); - if( n < count-1 ) - str += ", "; - } - - return str; -} - -asCString asCParser::ExpectedOneOf(const char **tokens, int count) -{ - asCString str; - - str = TXT_EXPECTED_ONE_OF; - for( int n = 0; n < count; n++ ) - { - str += tokens[n]; - if( n < count-1 ) - str += ", "; - } - - return str; -} - -asCString asCParser::InsteadFound(sToken &t) -{ - asCString str; - if( t.type == ttIdentifier ) - { - asCString id(&script->code[t.pos], t.length); - str.Format(TXT_INSTEAD_FOUND_s, id.AddressOf()); - } - else - str.Format(TXT_INSTEAD_FOUND_s, asCTokenizer::GetDefinition(t.type)); - return str; -} - -asCScriptNode *asCParser::ParseListPattern() -{ - asCScriptNode *node = CreateNode(snListPattern); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - if( t1.type != ttStartStatementBlock ) - { - Error(ExpectedToken("{"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - sToken start = t1; - - bool isBeginning = true; - bool afterType = false; - while( !isSyntaxError ) - { - GetToken(&t1); - if( t1.type == ttEndStatementBlock ) - { - if( !afterType ) - { - Error(TXT_EXPECTED_DATA_TYPE, &t1); - Error(InsteadFound(t1), &t1); - } - break; - } - else if( t1.type == ttStartStatementBlock ) - { - if( afterType ) - { - Error(ExpectedTokens(",","}"), &t1); - Error(InsteadFound(t1), &t1); - } - RewindTo(&t1); - node->AddChildLast(ParseListPattern()); - afterType = true; - } - else if( t1.type == ttIdentifier && (IdentifierIs(t1, "repeat") || IdentifierIs(t1, "repeat_same")) ) - { - if( !isBeginning ) - { - asCString msg; - asCString token(&script->code[t1.pos], t1.length); - msg.Format(TXT_UNEXPECTED_TOKEN_s, token.AddressOf()); - Error(msg.AddressOf(), &t1); - } - RewindTo(&t1); - node->AddChildLast(ParseIdentifier()); - } - else if( t1.type == ttEnd ) - { - Error(TXT_UNEXPECTED_END_OF_FILE, &t1); - Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start); - break; - } - else if( t1.type == ttListSeparator ) - { - if( !afterType ) - { - Error(TXT_EXPECTED_DATA_TYPE, &t1); - Error(InsteadFound(t1), &t1); - } - afterType = false; - } - else - { - if( afterType ) - { - Error(ExpectedTokens(",", "}"), &t1); - Error(InsteadFound(t1), &t1); - } - RewindTo(&t1); - node->AddChildLast(ParseType(true, true)); - afterType = true; - } - - isBeginning = false; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -bool asCParser::IdentifierIs(const sToken &t, const char *str) -{ - if( t.type != ttIdentifier ) - return false; - - return script->TokenEquals(t.pos, t.length, str); -} - -#ifndef AS_NO_COMPILER - -// This function will return true if the current token is not a template, or if it is and -// the following has a valid syntax for a template type. The source position will be left -// at the first token after the type in case of success -bool asCParser::CheckTemplateType(sToken &t) -{ - // Is this a template type? - tempString.Assign(&script->code[t.pos], t.length); - if( engine->IsTemplateType(tempString.AddressOf()) ) - { - // Expect the sub type within < > - GetToken(&t); - if( t.type != ttLessThan ) - return false; - - for(;;) - { - // There might optionally be a 'const' - GetToken(&t); - if( t.type == ttConst ) - GetToken(&t); - - // The type may be initiated with the scope operator - if( t.type == ttScope ) - GetToken(&t); - - // There may be multiple levels of scope operators - sToken t2; - GetToken(&t2); - while( t.type == ttIdentifier && t2.type == ttScope ) - { - GetToken(&t); - GetToken(&t2); - } - RewindTo(&t2); - - // Now there must be a data type - if( !IsDataType(t) ) - return false; - - if( !CheckTemplateType(t) ) - return false; - - GetToken(&t); - - // Is it a handle or array? - while( t.type == ttHandle || t.type == ttOpenBracket ) - { - if( t.type == ttOpenBracket ) - { - GetToken(&t); - if( t.type != ttCloseBracket ) - return false; - } - - GetToken(&t); - } - - // Was this the last template subtype? - if( t.type != ttListSeparator ) - break; - } - - // Accept >> and >>> tokens too. But then force the tokenizer to move - // only 1 character ahead (thus splitting the token in two). - if( script->code[t.pos] != '>' ) - return false; - else if( t.length != 1 ) - { - // We need to break the token, so that only the first character is parsed - SetPos(t.pos + 1); - } - } - - return true; -} - -asCScriptNode *asCParser::ParseCast() -{ - asCScriptNode *node = CreateNode(snCast); - if( node == 0 ) return 0; - - sToken t1; - GetToken(&t1); - if( t1.type != ttCast ) - { - Error(ExpectedToken("cast"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - GetToken(&t1); - if( t1.type != ttLessThan ) - { - Error(ExpectedToken("<"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - // Parse the data type - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; - - GetToken(&t1); - if( t1.type != ttGreaterThan ) - { - Error(ExpectedToken(">"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - GetToken(&t1); - if( t1.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t1); - if( t1.type != ttCloseParanthesis ) - { - Error(ExpectedToken(")"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -asCScriptNode *asCParser::ParseExprValue() -{ - asCScriptNode *node = CreateNode(snExprValue); - if( node == 0 ) return 0; - - sToken t1, t2; - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); - - // 'void' is a special expression that doesn't do anything (normally used for skipping output arguments) - if( t1.type == ttVoid ) - node->AddChildLast(ParseToken(ttVoid)); - else if( IsRealType(t1.type) ) - node->AddChildLast(ParseConstructCall()); - else if( t1.type == ttIdentifier || t1.type == ttScope ) - { - // Determine the last identifier in order to check if it is a type - sToken t; - if( t1.type == ttScope ) t = t2; else t = t1; - RewindTo(&t); - GetToken(&t2); - while( t.type == ttIdentifier ) - { - t2 = t; - GetToken(&t); - if( t.type == ttScope ) - GetToken(&t); - else - break; - } - - bool isDataType = IsDataType(t2); - bool isTemplateType = false; - if( isDataType ) - { - // Is this a template type? - tempString.Assign(&script->code[t2.pos], t2.length); - if( engine->IsTemplateType(tempString.AddressOf()) ) - isTemplateType = true; - } - - // Rewind so the real parsing can be done, after deciding what to parse - RewindTo(&t1); - - // Check if this is a construct call - if( isDataType && (t.type == ttOpenParanthesis || // type() - t.type == ttOpenBracket) ) // type[]() - node->AddChildLast(ParseConstructCall()); - else if( isTemplateType && t.type == ttLessThan ) // type() - node->AddChildLast(ParseConstructCall()); - else if( IsFunctionCall() ) - node->AddChildLast(ParseFunctionCall()); - else - node->AddChildLast(ParseVariableAccess()); - } - else if( t1.type == ttCast ) - node->AddChildLast(ParseCast()); - else if( IsConstant(t1.type) ) - node->AddChildLast(ParseConstant()); - else if( t1.type == ttOpenParanthesis ) - { - GetToken(&t1); - node->UpdateSourcePos(t1.pos, t1.length); - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t1); - if( t1.type != ttCloseParanthesis ) - { - Error(ExpectedToken(")"), &t1); - Error(InsteadFound(t1), &t1); - } - - node->UpdateSourcePos(t1.pos, t1.length); - } - else - { - Error(TXT_EXPECTED_EXPRESSION_VALUE, &t1); - Error(InsteadFound(t1), &t1); - } - - return node; -} - -asCScriptNode *asCParser::ParseConstant() -{ - asCScriptNode *node = CreateNode(snConstant); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( !IsConstant(t.type) ) - { - Error(TXT_EXPECTED_CONSTANT, &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - node->UpdateSourcePos(t.pos, t.length); - - // We want to gather a list of string constants to concatenate as children - if( t.type == ttStringConstant || t.type == ttMultilineStringConstant || t.type == ttHeredocStringConstant ) - RewindTo(&t); - - while( t.type == ttStringConstant || t.type == ttMultilineStringConstant || t.type == ttHeredocStringConstant ) - { - node->AddChildLast(ParseStringConstant()); - - GetToken(&t); - RewindTo(&t); - } - - return node; -} - -asCScriptNode *asCParser::ParseStringConstant() -{ - asCScriptNode *node = CreateNode(snConstant); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttStringConstant && t.type != ttMultilineStringConstant && t.type != ttHeredocStringConstant ) - { - Error(TXT_EXPECTED_STRING, &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseFunctionCall() -{ - asCScriptNode *node = CreateNode(snFunctionCall); - if( node == 0 ) return 0; - - // Parse scope prefix - ParseOptionalScope(node); - - // Parse the function name followed by the argument list - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseArgList()); - - return node; -} - -asCScriptNode *asCParser::ParseVariableAccess() -{ - asCScriptNode *node = CreateNode(snVariableAccess); - if( node == 0 ) return 0; - - // Parse scope prefix - ParseOptionalScope(node); - - // Parse the variable name - node->AddChildLast(ParseIdentifier()); - - return node; -} - -asCScriptNode *asCParser::ParseConstructCall() -{ - asCScriptNode *node = CreateNode(snConstructCall); - if( node == 0 ) return 0; - - node->AddChildLast(ParseType(false)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseArgList()); - - return node; -} - -asCScriptNode *asCParser::ParseArgList(bool withParenthesis) -{ - asCScriptNode *node = CreateNode(snArgList); - if( node == 0 ) return 0; - - sToken t1; - if( withParenthesis ) - { - GetToken(&t1); - if( t1.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - } - - GetToken(&t1); - if( t1.type == ttCloseParanthesis || t1.type == ttCloseBracket ) - { - if( withParenthesis ) - { - if( t1.type == ttCloseParanthesis ) - node->UpdateSourcePos(t1.pos, t1.length); - else - { - asCString str; - str.Format(TXT_UNEXPECTED_TOKEN_s, asCTokenizer::GetDefinition(ttCloseBracket)); - - Error(str.AddressOf(), &t1); - } - } - else - RewindTo(&t1); - - // Argument list has ended - return node; - } - else - { - RewindTo(&t1); - - for(;;) - { - // Determine if this is a named argument - sToken tl, t2; - GetToken(&tl); - GetToken(&t2); - RewindTo(&tl); - - // Named arguments uses the syntax: arg : expr - // This avoids confusion when the argument has the same name as a local variable, i.e. var = expr - // It also avoids conflict with expressions to that creates anonymous objects initialized with lists, i.e. type = {...} - // The alternate syntax: arg = expr, is supported to provide backwards compatibility with 2.29.0 - // TODO: 3.0.0: Remove the alternate syntax - if( tl.type == ttIdentifier && (t2.type == ttColon || (engine->ep.alterSyntaxNamedArgs && t2.type == ttAssignment)) ) - { - asCScriptNode *named = CreateNode(snNamedArgument); - if( named == 0 ) return 0; - node->AddChildLast(named); - - named->AddChildLast(ParseIdentifier()); - GetToken(&t2); - - if( engine->ep.alterSyntaxNamedArgs == 1 && t2.type == ttAssignment ) - Warning(TXT_NAMED_ARGS_WITH_OLD_SYNTAX, &t2); - - named->AddChildLast(ParseAssignment()); - } - else - node->AddChildLast(ParseAssignment()); - - if( isSyntaxError ) return node; - - // Check if list continues - GetToken(&t1); - if( t1.type == ttListSeparator ) - continue; - else - { - if( withParenthesis ) - { - if( t1.type == ttCloseParanthesis ) - node->UpdateSourcePos(t1.pos, t1.length); - else - { - Error(ExpectedTokens(")", ","), &t1); - Error(InsteadFound(t1), &t1); - } - } - else - RewindTo(&t1); - - return node; - } - } - } -} - -bool asCParser::IsFunctionCall() -{ - sToken s; - sToken t1, t2; - - GetToken(&s); - t1 = s; - - // A function call may be prefixed with scope resolution - if( t1.type == ttScope ) - GetToken(&t1); - GetToken(&t2); - - while( t1.type == ttIdentifier && t2.type == ttScope ) - { - GetToken(&t1); - GetToken(&t2); - } - - // A function call starts with an identifier followed by an argument list - if( t1.type != ttIdentifier || IsDataType(t1) ) - { - RewindTo(&s); - return false; - } - - if( t2.type == ttOpenParanthesis ) - { - RewindTo(&s); - return true; - } - - RewindTo(&s); - return false; -} - -asCScriptNode *asCParser::ParseAssignment() -{ - asCScriptNode *node = CreateNode(snAssignment); - if( node == 0 ) return 0; - - node->AddChildLast(ParseCondition()); - if( isSyntaxError ) return node; - - sToken t; - GetToken(&t); - RewindTo(&t); - - if( IsAssignOperator(t.type) ) - { - node->AddChildLast(ParseAssignOperator()); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - } - - return node; -} - -asCScriptNode *asCParser::ParseCondition() -{ - asCScriptNode *node = CreateNode(snCondition); - if( node == 0 ) return 0; - - node->AddChildLast(ParseExpression()); - if( isSyntaxError ) return node; - - sToken t; - GetToken(&t); - if( t.type == ttQuestion ) - { - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttColon ) - { - Error(ExpectedToken(":"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - } - else - RewindTo(&t); - - return node; -} - -asCScriptNode *asCParser::ParseExpression() -{ - asCScriptNode *node = CreateNode(snExpression); - if( node == 0 ) return 0; - - // Check if the expression is a initialization of a temp object with init list, i.e. type = {...} - sToken t; - GetToken(&t); - sToken t2 = t, t3; - if( IsDataType(t2) && CheckTemplateType(t2) ) - { - // The next token must be a = followed by a { - GetToken(&t2); - GetToken(&t3); - if( t2.type == ttAssignment && t3.type == ttStartStatementBlock ) - { - // It is an initialization, now parse it for real - RewindTo(&t); - node->AddChildLast(ParseType(false)); - GetToken(&t2); - node->AddChildLast(ParseInitList()); - return node; - } - } - - // It wasn't an initialization, so it must be an ordinary expression - RewindTo(&t); - - node->AddChildLast(ParseExprTerm()); - if( isSyntaxError ) return node; - - for(;;) - { - sToken t; - GetToken(&t); - RewindTo(&t); - - if( !IsOperator(t.type) ) - return node; - - node->AddChildLast(ParseExprOperator()); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseExprTerm()); - if( isSyntaxError ) return node; - } - UNREACHABLE_RETURN; -} - -asCScriptNode *asCParser::ParseExprTerm() -{ - asCScriptNode *node = CreateNode(snExprTerm); - if( node == 0 ) return 0; - - for(;;) - { - sToken t; - GetToken(&t); - RewindTo(&t); - if( !IsPreOperator(t.type) ) - break; - - node->AddChildLast(ParseExprPreOp()); - if( isSyntaxError ) return node; - } - - node->AddChildLast(ParseExprValue()); - if( isSyntaxError ) return node; - - - for(;;) - { - sToken t; - GetToken(&t); - RewindTo(&t); - if( !IsPostOperator(t.type) ) - return node; - - node->AddChildLast(ParseExprPostOp()); - if( isSyntaxError ) return node; - } - UNREACHABLE_RETURN; -} - -asCScriptNode *asCParser::ParseExprPreOp() -{ - asCScriptNode *node = CreateNode(snExprPreOp); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( !IsPreOperator(t.type) ) - { - Error(TXT_EXPECTED_PRE_OPERATOR, &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseExprPostOp() -{ - asCScriptNode *node = CreateNode(snExprPostOp); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( !IsPostOperator(t.type) ) - { - Error(TXT_EXPECTED_POST_OPERATOR, &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - node->UpdateSourcePos(t.pos, t.length); - - if( t.type == ttDot ) - { - sToken t1, t2; - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); - if( t2.type == ttOpenParanthesis ) - node->AddChildLast(ParseFunctionCall()); - else - node->AddChildLast(ParseIdentifier()); - } - else if( t.type == ttOpenBracket ) - { - node->AddChildLast(ParseArgList(false)); - - GetToken(&t); - if( t.type != ttCloseBracket ) - { - Error(ExpectedToken("]"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - } - else if( t.type == ttOpenParanthesis ) - { - RewindTo(&t); - node->AddChildLast(ParseArgList()); - } - - return node; -} - -asCScriptNode *asCParser::ParseExprOperator() -{ - asCScriptNode *node = CreateNode(snExprOperator); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( !IsOperator(t.type) ) - { - Error(TXT_EXPECTED_OPERATOR, &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseAssignOperator() -{ - asCScriptNode *node = CreateNode(snExprOperator); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( !IsAssignOperator(t.type) ) - { - Error(TXT_EXPECTED_OPERATOR, &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -bool asCParser::IsOperator(int tokenType) -{ - if( tokenType == ttPlus || - tokenType == ttMinus || - tokenType == ttStar || - tokenType == ttSlash || - tokenType == ttPercent || - tokenType == ttStarStar || - tokenType == ttAnd || - tokenType == ttOr || - tokenType == ttXor || - tokenType == ttEqual || - tokenType == ttNotEqual || - tokenType == ttLessThan || - tokenType == ttLessThanOrEqual || - tokenType == ttGreaterThan || - tokenType == ttGreaterThanOrEqual || - tokenType == ttAmp || - tokenType == ttBitOr || - tokenType == ttBitXor || - tokenType == ttBitShiftLeft || - tokenType == ttBitShiftRight || - tokenType == ttBitShiftRightArith || - tokenType == ttIs || - tokenType == ttNotIs ) - return true; - - return false; -} - -bool asCParser::IsAssignOperator(int tokenType) -{ - if( tokenType == ttAssignment || - tokenType == ttAddAssign || - tokenType == ttSubAssign || - tokenType == ttMulAssign || - tokenType == ttDivAssign || - tokenType == ttModAssign || - tokenType == ttPowAssign || - tokenType == ttAndAssign || - tokenType == ttOrAssign || - tokenType == ttXorAssign || - tokenType == ttShiftLeftAssign || - tokenType == ttShiftRightLAssign || - tokenType == ttShiftRightAAssign ) - return true; - - return false; -} - -bool asCParser::IsPreOperator(int tokenType) -{ - if( tokenType == ttMinus || - tokenType == ttPlus || - tokenType == ttNot || - tokenType == ttInc || - tokenType == ttDec || - tokenType == ttBitNot || - tokenType == ttHandle ) - return true; - return false; -} - -bool asCParser::IsPostOperator(int tokenType) -{ - if( tokenType == ttInc || // post increment - tokenType == ttDec || // post decrement - tokenType == ttDot || // member access - tokenType == ttOpenBracket || // index operator - tokenType == ttOpenParanthesis ) // argument list for call on function pointer - return true; - return false; -} - -bool asCParser::IsConstant(int tokenType) -{ - if( tokenType == ttIntConstant || - tokenType == ttFloatConstant || - tokenType == ttDoubleConstant || - tokenType == ttStringConstant || - tokenType == ttMultilineStringConstant || - tokenType == ttHeredocStringConstant || - tokenType == ttTrue || - tokenType == ttFalse || - tokenType == ttBitsConstant || - tokenType == ttNull ) - return true; - - return false; -} - -int asCParser::ParseScript(asCScriptCode *script) -{ - Reset(); - - this->script = script; - - scriptNode = ParseScript(false); - - if( errorWhileParsing ) - return -1; - - // Warn in case there isn't anything in the script - if( scriptNode->firstChild == 0 ) - { - if( builder ) - builder->WriteWarning(script->name, TXT_SECTION_IS_EMPTY, 1, 1); - } - - return 0; -} - -int asCParser::ParseExpression(asCScriptCode *script) -{ - Reset(); - - this->script = script; - - checkValidTypes = true; - - scriptNode = ParseExpression(); - if( errorWhileParsing ) - return -1; - - return 0; -} - -asCScriptNode *asCParser::ParseImport() -{ - asCScriptNode *node = CreateNode(snImport); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttImport ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttImport)), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - node->UpdateSourcePos(t.pos, t.length); - - node->AddChildLast(ParseFunctionDefinition()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttIdentifier ) - { - Error(ExpectedToken(FROM_TOKEN), &t); - Error(InsteadFound(t), &t); - return node; - } - - tempString.Assign(&script->code[t.pos], t.length); - if( tempString != FROM_TOKEN ) - { - Error(ExpectedToken(FROM_TOKEN), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type != ttStringConstant ) - { - Error(TXT_EXPECTED_STRING, &t); - Error(InsteadFound(t), &t); - return node; - } - - asCScriptNode *mod = CreateNode(snConstant); - if( mod == 0 ) return 0; - - node->AddChildLast(mod); - - mod->SetToken(&t); - mod->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type != ttEndStatement ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatement)), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseScript(bool inBlock) -{ - asCScriptNode *node = CreateNode(snScript); - if( node == 0 ) return 0; - - // Determine type of node - sToken t1, t2; - - for(;;) - { - while( !isSyntaxError ) - { - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); - - if( t1.type == ttImport ) - node->AddChildLast(ParseImport()); - else if( t1.type == ttEnum || (IdentifierIs(t1, SHARED_TOKEN) && t2.type == ttEnum) ) - node->AddChildLast(ParseEnumeration()); // Handle enumerations - else if( t1.type == ttTypedef ) - node->AddChildLast(ParseTypedef()); // Handle primitive typedefs - else if( t1.type == ttClass || - ((IdentifierIs(t1, SHARED_TOKEN) || IdentifierIs(t1, FINAL_TOKEN) || IdentifierIs(t1, ABSTRACT_TOKEN)) && t2.type == ttClass) || - (IdentifierIs(t1, SHARED_TOKEN) && (IdentifierIs(t2, FINAL_TOKEN) || IdentifierIs(t2, ABSTRACT_TOKEN))) ) - node->AddChildLast(ParseClass()); - else if( t1.type == ttMixin ) - node->AddChildLast(ParseMixin()); - else if( t1.type == ttInterface || (t1.type == ttIdentifier && t2.type == ttInterface) ) - node->AddChildLast(ParseInterface()); - else if( t1.type == ttFuncDef ) - node->AddChildLast(ParseFuncDef()); - else if( t1.type == ttConst || t1.type == ttScope || t1.type == ttAuto || IsDataType(t1) ) - { - if( IsVirtualPropertyDecl() ) - node->AddChildLast(ParseVirtualPropertyDecl(false, false)); - else if( IsVarDecl() ) - node->AddChildLast(ParseDeclaration(false, true)); - else - node->AddChildLast(ParseFunction()); - } - else if( t1.type == ttEndStatement ) - { - // Ignore a semicolon by itself - GetToken(&t1); - } - else if( t1.type == ttNamespace ) - node->AddChildLast(ParseNamespace()); - else if( t1.type == ttEnd ) - return node; - else if( inBlock && t1.type == ttEndStatementBlock ) - return node; - else - { - asCString str; - const char *t = asCTokenizer::GetDefinition(t1.type); - if( t == 0 ) t = ""; - - str.Format(TXT_UNEXPECTED_TOKEN_s, t); - - Error(str, &t1); - } - } - - if( isSyntaxError ) - { - // Search for either ';' or '{' or end - GetToken(&t1); - while( t1.type != ttEndStatement && t1.type != ttEnd && - t1.type != ttStartStatementBlock ) - GetToken(&t1); - - if( t1.type == ttStartStatementBlock ) - { - // Find the end of the block and skip nested blocks - int level = 1; - while( level > 0 ) - { - GetToken(&t1); - if( t1.type == ttStartStatementBlock ) level++; - if( t1.type == ttEndStatementBlock ) level--; - if( t1.type == ttEnd ) break; - } - } - - isSyntaxError = false; - } - } - UNREACHABLE_RETURN; -} - -asCScriptNode *asCParser::ParseNamespace() -{ - asCScriptNode *node = CreateNode(snNamespace); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - if( t1.type == ttNamespace ) - node->UpdateSourcePos(t1.pos, t1.length); - else - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttNamespace)), &t1); - Error(InsteadFound(t1), &t1); - } - - // TODO: namespace: Allow declaration of multiple nested namespace with namespace A::B::C { } - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - GetToken(&t1); - if( t1.type == ttStartStatementBlock ) - node->UpdateSourcePos(t1.pos, t1.length); - else - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttStartStatementBlock)), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - sToken start = t1; - - node->AddChildLast(ParseScript(true)); - - if( !isSyntaxError ) - { - GetToken(&t1); - if( t1.type == ttEndStatementBlock ) - node->UpdateSourcePos(t1.pos, t1.length); - else - { - if( t1.type == ttEnd ) - Error(TXT_UNEXPECTED_END_OF_FILE, &t1); - else - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatementBlock)), &t1); - Error(InsteadFound(t1), &t1); - } - Info(TXT_WHILE_PARSING_NAMESPACE, &start); - return node; - } - } - - return node; -} - -int asCParser::ParseStatementBlock(asCScriptCode *script, asCScriptNode *block) -{ - TimeIt("asCParser::ParseStatementBlock"); - - Reset(); - - // Tell the parser to validate the identifiers as valid types - checkValidTypes = true; - - this->script = script; - sourcePos = block->tokenPos; - - scriptNode = ParseStatementBlock(); - - if( isSyntaxError || errorWhileParsing ) - return -1; - - return 0; -} - -asCScriptNode *asCParser::ParseEnumeration() -{ - asCScriptNode *ident; - asCScriptNode *dataType; - - asCScriptNode *node = CreateNode(snEnum); - if( node == 0 ) return 0; - - sToken token; - - // Optional 'shared' token - GetToken(&token); - if( IdentifierIs(token, SHARED_TOKEN) ) - { - RewindTo(&token); - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - GetToken(&token); - } - - // Check for enum - if( token.type != ttEnum ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnum)), &token); - Error(InsteadFound(token), &token); - return node; - } - - node->SetToken(&token); - node->UpdateSourcePos(token.pos, token.length); - - // Get the identifier - GetToken(&token); - if(ttIdentifier != token.type) - { - Error(TXT_EXPECTED_IDENTIFIER, &token); - Error(InsteadFound(token), &token); - return node; - } - - dataType = CreateNode(snDataType); - if( dataType == 0 ) return 0; - - node->AddChildLast(dataType); - - ident = CreateNode(snIdentifier); - if( ident == 0 ) return 0; - - ident->SetToken(&token); - ident->UpdateSourcePos(token.pos, token.length); - dataType->AddChildLast(ident); - - // check for the start of the declaration block - GetToken(&token); - if( token.type != ttStartStatementBlock ) - { - RewindTo(&token); - Error(ExpectedToken(asCTokenizer::GetDefinition(token.type)), &token); - Error(InsteadFound(token), &token); - return node; - } - - while(ttEnd != token.type) - { - GetToken(&token); - - if( ttEndStatementBlock == token.type ) - { - RewindTo(&token); - break; - } - - if(ttIdentifier != token.type) - { - Error(TXT_EXPECTED_IDENTIFIER, &token); - Error(InsteadFound(token), &token); - return node; - } - - // Add the enum element - ident = CreateNode(snIdentifier); - if( ident == 0 ) return 0; - - ident->SetToken(&token); - ident->UpdateSourcePos(token.pos, token.length); - node->AddChildLast(ident); - - GetToken(&token); - - if( token.type == ttAssignment ) - { - asCScriptNode *tmp; - - RewindTo(&token); - - tmp = SuperficiallyParseVarInit(); - - node->AddChildLast(tmp); - if( isSyntaxError ) return node; - GetToken(&token); - } - - if(ttListSeparator != token.type) - { - RewindTo(&token); - break; - } - } - - // check for the end of the declaration block - GetToken(&token); - if( token.type != ttEndStatementBlock ) - { - RewindTo(&token); - Error(ExpectedToken(asCTokenizer::GetDefinition(token.type)), &token); - Error(InsteadFound(token), &token); - return node; - } - - // Parse the declarations - return node; -} - -bool asCParser::IsVarDecl() -{ - // Set start point so that we can rewind - sToken t; - GetToken(&t); - RewindTo(&t); - - // A class property decl can be preceded by 'private' - sToken t1; - GetToken(&t1); - if( t1.type != ttPrivate ) - RewindTo(&t1); - - // A variable decl can start with a const - GetToken(&t1); - if( t1.type == ttConst ) - GetToken(&t1); - - sToken t2; - if( t1.type != ttAuto ) - { - // The type may be initiated with the scope operator - if( t1.type == ttScope ) - GetToken(&t1); - - // The type may be preceeded with a multilevel scope - GetToken(&t2); - while( t1.type == ttIdentifier && t2.type == ttScope ) - { - GetToken(&t1); - GetToken(&t2); - } - RewindTo(&t2); - } - - // We don't validate if the identifier is an actual declared type at this moment - // as it may wrongly identify the statement as a non-declaration if the user typed - // the name incorrectly. The real type is validated in ParseDeclaration where a - // proper error message can be given. - if( !IsRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto ) - { - RewindTo(&t); - return false; - } - - if( !CheckTemplateType(t1) ) - { - RewindTo(&t); - return false; - } - - // Object handles can be interleaved with the array brackets - // Even though declaring variables with & is invalid we'll accept - // it here to give an appropriate error message later - GetToken(&t2); - while( t2.type == ttHandle || t2.type == ttAmp || t2.type == ttOpenBracket ) - { - if( t2.type == ttOpenBracket ) - { - GetToken(&t2); - if( t2.type != ttCloseBracket ) - { - RewindTo(&t); - return false; - } - } - - GetToken(&t2); - } - - if( t2.type != ttIdentifier ) - { - RewindTo(&t); - return false; - } - - GetToken(&t2); - if( t2.type == ttEndStatement || t2.type == ttAssignment || t2.type == ttListSeparator ) - { - RewindTo(&t); - return true; - } - if( t2.type == ttOpenParanthesis ) - { - // If the closing paranthesis is followed by a statement - // block or end-of-file, then treat it as a function. A - // function decl may have nested paranthesis so we need to - // check for this too. - int nest = 0; - while( t2.type != ttEnd ) - { - if( t2.type == ttOpenParanthesis ) - nest++; - else if( t2.type == ttCloseParanthesis ) - { - nest--; - if( nest == 0 ) - break; - } - GetToken(&t2); - } - - if( t2.type == ttEnd ) - return false; - else - { - GetToken(&t1); - RewindTo(&t); - if( t1.type == ttStartStatementBlock || t1.type == ttEnd ) - return false; - } - - RewindTo(&t); - - return true; - } - - RewindTo(&t); - return false; -} - -bool asCParser::IsVirtualPropertyDecl() -{ - // Set start point so that we can rewind - sToken t; - GetToken(&t); - RewindTo(&t); - - // A class property decl can be preceded by 'private' - sToken t1; - GetToken(&t1); - if( t1.type != ttPrivate ) - RewindTo(&t1); - - // A variable decl can start with a const - GetToken(&t1); - if( t1.type == ttConst ) - GetToken(&t1); - - // We don't validate if the identifier is an actual declared type at this moment - // as it may wrongly identify the statement as a non-declaration if the user typed - // the name incorrectly. The real type is validated in ParseDeclaration where a - // proper error message can be given. - if( !IsRealType(t1.type) && t1.type != ttIdentifier ) - { - RewindTo(&t); - return false; - } - - if( !CheckTemplateType(t1) ) - { - RewindTo(&t); - return false; - } - - // Object handles can be interleaved with the array brackets - sToken t2; - GetToken(&t2); - while( t2.type == ttHandle || t2.type == ttOpenBracket ) - { - if( t2.type == ttOpenBracket ) - { - GetToken(&t2); - if( t2.type != ttCloseBracket ) - { - RewindTo(&t); - return false; - } - } - - GetToken(&t2); - } - - if( t2.type != ttIdentifier ) - { - RewindTo(&t); - return false; - } - - GetToken(&t2); - if( t2.type == ttStartStatementBlock ) - { - RewindTo(&t); - return true; - } - - RewindTo(&t); - return false; -} - -bool asCParser::IsFuncDecl(bool isMethod) -{ - // Set start point so that we can rewind - sToken t; - GetToken(&t); - RewindTo(&t); - - if( isMethod ) - { - // A class method decl can be preceded by 'private' - sToken t1, t2; - GetToken(&t1); - if( t1.type != ttPrivate ) - RewindTo(&t1); - - // A class constructor starts with identifier followed by parenthesis - // A class destructor starts with the ~ token - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); - if( (t1.type == ttIdentifier && t2.type == ttOpenParanthesis) || t1.type == ttBitNot ) - { - RewindTo(&t); - return true; - } - } - - // A function decl can start with a const - sToken t1; - GetToken(&t1); - if( t1.type == ttConst ) - GetToken(&t1); - - // The return type can be optionally preceeded by a scope - if( t1.type == ttScope ) - GetToken(&t1); - while( t1.type == ttIdentifier ) - { - sToken t2; - GetToken(&t2); - if( t2.type == ttScope ) - GetToken(&t1); - else - { - RewindTo(&t2); - break; - } - } - - if( !IsDataType(t1) ) - { - RewindTo(&t); - return false; - } - - // If the type is a template type, then skip the angle brackets holding the subtype - if( !CheckTemplateType(t1) ) - { - RewindTo(&t); - return false; - } - - // Object handles can be interleaved with the array brackets - sToken t2; - GetToken(&t2); - while( t2.type == ttHandle || t2.type == ttOpenBracket ) - { - if( t2.type == ttOpenBracket ) - { - GetToken(&t2); - if( t2.type != ttCloseBracket ) - { - RewindTo(&t); - return false; - } - } - - GetToken(&t2); - } - - // There can be an ampersand if the function returns a reference - if( t2.type == ttAmp ) - { - RewindTo(&t); - return true; - } - - if( t2.type != ttIdentifier ) - { - RewindTo(&t); - return false; - } - - GetToken(&t2); - if( t2.type == ttOpenParanthesis ) - { - // If the closing parenthesis is not followed by a - // statement block then it is not a function. - // It's possible that there are nested parenthesis due to default - // arguments so this should be checked for. - int nest = 0; - GetToken(&t2); - while( (nest || t2.type != ttCloseParanthesis) && t2.type != ttEnd ) - { - if( t2.type == ttOpenParanthesis ) - nest++; - if( t2.type == ttCloseParanthesis ) - nest--; - - GetToken(&t2); - } - - if( t2.type == ttEnd ) - return false; - else - { - if( isMethod ) - { - // A class method can have a 'const' token after the parameter list - GetToken(&t1); - if( t1.type != ttConst ) - RewindTo(&t1); - - // A class method may also have any number of additional inheritance behavior specifiers - for( ; ; ) - { - GetToken(&t2); - if( !IdentifierIs(t2, FINAL_TOKEN) && !IdentifierIs(t2, OVERRIDE_TOKEN) ) - { - RewindTo(&t2); - break; - } - } - } - - GetToken(&t1); - RewindTo(&t); - if( t1.type == ttStartStatementBlock ) - return true; - } - - RewindTo(&t); - return false; - } - - RewindTo(&t); - return false; -} - -asCScriptNode *asCParser::ParseFuncDef() -{ - asCScriptNode *node = CreateNode(snFuncDef); - if( node == 0 ) return 0; - - sToken t1; - GetToken(&t1); - if( t1.type != ttFuncDef ) - { - Error(asCTokenizer::GetDefinition(ttFuncDef), &t1); - return node; - } - - node->SetToken(&t1); - - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseParameterList()); - if( isSyntaxError ) return node; - - GetToken(&t1); - if( t1.type != ttEndStatement ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatement)), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -asCScriptNode *asCParser::ParseFunction(bool isMethod) -{ - asCScriptNode *node = CreateNode(snFunction); - if( node == 0 ) return 0; - - sToken t1,t2; - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); - - // A class method can start with private - if( isMethod && t1.type == ttPrivate ) - { - node->AddChildLast(ParseToken(ttPrivate)); - if( isSyntaxError ) return node; - } - - // A global function can be marked as shared - if( !isMethod && IdentifierIs(t1, SHARED_TOKEN) ) - { - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - } - - // If it is a global function, or a method, except constructor and destructor, then the return type is parsed - if( !isMethod || (t1.type != ttBitNot && t2.type != ttOpenParanthesis) ) - { - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; - } - - // If this is a class destructor then it starts with ~, and no return type is declared - if( isMethod && t1.type == ttBitNot ) - { - node->AddChildLast(ParseToken(ttBitNot)); - if( isSyntaxError ) return node; - } - - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseParameterList()); - if( isSyntaxError ) return node; - - if( isMethod ) - { - GetToken(&t1); - RewindTo(&t1); - - // Is the method a const? - if( t1.type == ttConst ) - node->AddChildLast(ParseToken(ttConst)); - - // TODO: Should support abstract methods, in which case no statement block should be provided - ParseMethodOverrideBehaviors(node); - if( isSyntaxError ) return node; - } - - // We should just find the end of the statement block here. The statements - // will be parsed on request by the compiler once it starts the compilation. - node->AddChildLast(SuperficiallyParseStatementBlock()); - - return node; -} - -asCScriptNode *asCParser::ParseInterfaceMethod() -{ - asCScriptNode *node = CreateNode(snFunction); - if( node == 0 ) return 0; - - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseParameterList()); - if( isSyntaxError ) return node; - - // Parse an optional const after the method definition - sToken t1; - GetToken(&t1); - RewindTo(&t1); - if( t1.type == ttConst ) - node->AddChildLast(ParseToken(ttConst)); - - GetToken(&t1); - if( t1.type != ttEndStatement ) - { - Error(ExpectedToken(";"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -asCScriptNode *asCParser::ParseVirtualPropertyDecl(bool isMethod, bool isInterface) -{ - asCScriptNode *node = CreateNode(snVirtualProperty); - if( node == 0 ) return 0; - - sToken t1,t2; - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); - - // A class method can start with private - if( isMethod && t1.type == ttPrivate ) - { - node->AddChildLast(ParseToken(ttPrivate)); - if( isSyntaxError ) return node; - } - - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - GetToken(&t1); - if( t1.type != ttStartStatementBlock ) - { - Error(ExpectedToken("{"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - for(;;) - { - GetToken(&t1); - asCScriptNode *accessorNode = 0; - - if( IdentifierIs(t1, GET_TOKEN) || IdentifierIs(t1, SET_TOKEN) ) - { - accessorNode = CreateNode(snVirtualProperty); - if( accessorNode == 0 ) return 0; - - node->AddChildLast(accessorNode); - - RewindTo(&t1); - accessorNode->AddChildLast(ParseIdentifier()); - - if( isMethod ) - { - GetToken(&t1); - RewindTo(&t1); - if( t1.type == ttConst ) - accessorNode->AddChildLast(ParseToken(ttConst)); - - if( !isInterface ) - { - ParseMethodOverrideBehaviors(accessorNode); - if( isSyntaxError ) return node; - } - } - - if( !isInterface ) - { - GetToken(&t1); - if( t1.type == ttStartStatementBlock ) - { - RewindTo(&t1); - accessorNode->AddChildLast(SuperficiallyParseStatementBlock()); - if( isSyntaxError ) return node; - } - else if( t1.type != ttEndStatement ) - { - Error(ExpectedTokens(";", "{"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - } - else - { - GetToken(&t1); - if( t1.type != ttEndStatement ) - { - Error(ExpectedToken(";"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - } - } - else if( t1.type == ttEndStatementBlock ) - break; - else - { - const char *tokens[] = { GET_TOKEN, SET_TOKEN, asCTokenizer::GetDefinition(ttEndStatementBlock) }; - Error(ExpectedOneOf(tokens, 3), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - } - - return node; -} - -asCScriptNode *asCParser::ParseInterface() -{ - asCScriptNode *node = CreateNode(snInterface); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - - // Allow keyword 'shared' before 'interface' - if( t.type == ttIdentifier ) - { - tempString.Assign(&script->code[t.pos], t.length); - if( tempString != SHARED_TOKEN ) - { - Error(ExpectedToken(SHARED_TOKEN), &t); - Error(InsteadFound(t), &t); - return node; - } - - RewindTo(&t); - node->AddChildLast(ParseIdentifier()); - GetToken(&t); - } - - if( t.type != ttInterface ) - { - Error(ExpectedToken("interface"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - - node->AddChildLast(ParseIdentifier()); - - // Can optionally have a list of interfaces that are inherited - GetToken(&t); - if( t.type == ttColon ) - { - asCScriptNode *inherit = CreateNode(snIdentifier); - node->AddChildLast(inherit); - - ParseOptionalScope(inherit); - inherit->AddChildLast(ParseIdentifier()); - GetToken(&t); - while( t.type == ttListSeparator ) - { - inherit = CreateNode(snIdentifier); - node->AddChildLast(inherit); - - ParseOptionalScope(inherit); - inherit->AddChildLast(ParseIdentifier()); - GetToken(&t); - } - } - - if( t.type != ttStartStatementBlock ) - { - Error(ExpectedToken("{"), &t); - Error(InsteadFound(t), &t); - return node; - } - - // Parse interface methods - GetToken(&t); - RewindTo(&t); - while( t.type != ttEndStatementBlock && t.type != ttEnd ) - { - if( IsVirtualPropertyDecl() ) - node->AddChildLast(ParseVirtualPropertyDecl(true, true)); - else if( t.type == ttEndStatement ) - // Skip empty declarations - GetToken(&t); - else - // Parse the method signature - node->AddChildLast(ParseInterfaceMethod()); - - if( isSyntaxError ) return node; - - GetToken(&t); - RewindTo(&t); - } - - GetToken(&t); - if( t.type != ttEndStatementBlock ) - { - Error(ExpectedToken("}"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseMixin() -{ - asCScriptNode *node = CreateNode(snMixin); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - - if( t.type != ttMixin ) - { - Error(ExpectedToken("mixin"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - - // A mixin token must be followed by a class declaration - node->AddChildLast(ParseClass()); - - return node; -} - -asCScriptNode *asCParser::ParseClass() -{ - asCScriptNode *node = CreateNode(snClass); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - - // Allow the keywords 'shared', 'abstract', and 'final' before 'class' - while( IdentifierIs(t, SHARED_TOKEN) || - IdentifierIs(t, ABSTRACT_TOKEN) || - IdentifierIs(t, FINAL_TOKEN) ) - { - RewindTo(&t); - node->AddChildLast(ParseIdentifier()); - GetToken(&t); - } - - if( t.type != ttClass ) - { - Error(ExpectedToken("class"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - - if( engine->ep.allowImplicitHandleTypes ) - { - // Parse 'implicit handle class' construct - GetToken(&t); - - if ( t.type == ttHandle ) - node->SetToken(&t); - else - RewindTo(&t); - } - - node->AddChildLast(ParseIdentifier()); - - GetToken(&t); - - // Optional list of interfaces that are being implemented and classes that are being inherited - if( t.type == ttColon ) - { - asCScriptNode *inherit = CreateNode(snIdentifier); - node->AddChildLast(inherit); - - ParseOptionalScope(inherit); - inherit->AddChildLast(ParseIdentifier()); - GetToken(&t); - while( t.type == ttListSeparator ) - { - inherit = CreateNode(snIdentifier); - node->AddChildLast(inherit); - - ParseOptionalScope(inherit); - inherit->AddChildLast(ParseIdentifier()); - GetToken(&t); - } - } - - if( t.type != ttStartStatementBlock ) - { - Error(ExpectedToken("{"), &t); - Error(InsteadFound(t), &t); - return node; - } - - // Parse properties - GetToken(&t); - RewindTo(&t); - while( t.type != ttEndStatementBlock && t.type != ttEnd ) - { - // Is it a property or a method? - if( IsFuncDecl(true) ) - node->AddChildLast(ParseFunction(true)); - else if( IsVirtualPropertyDecl() ) - node->AddChildLast(ParseVirtualPropertyDecl(true, false)); - else if( IsVarDecl() ) - node->AddChildLast(ParseDeclaration(true)); - else if( t.type == ttEndStatement ) - // Skip empty declarations - GetToken(&t); - else - { - Error(TXT_EXPECTED_METHOD_OR_PROPERTY, &t); - Error(InsteadFound(t), &t); - return node; - } - - if( isSyntaxError ) - return node; - - GetToken(&t); - RewindTo(&t); - } - - GetToken(&t); - if( t.type != ttEndStatementBlock ) - { - Error(ExpectedToken("}"), &t); - Error(InsteadFound(t), &t); - return node; - } - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -int asCParser::ParseVarInit(asCScriptCode *script, asCScriptNode *init) -{ - Reset(); - - // Tell the parser to validate the identifiers as valid types - checkValidTypes = true; - - this->script = script; - sourcePos = init->tokenPos; - - // If next token is assignment, parse expression - sToken t; - GetToken(&t); - if( t.type == ttAssignment ) - { - GetToken(&t); - RewindTo(&t); - if( t.type == ttStartStatementBlock ) - scriptNode = ParseInitList(); - else - scriptNode = ParseAssignment(); - } - else if( t.type == ttOpenParanthesis ) - { - RewindTo(&t); - scriptNode = ParseArgList(); - } - else - { - int tokens[] = {ttAssignment, ttOpenParanthesis}; - Error(ExpectedOneOf(tokens, 2), &t); - Error(InsteadFound(t), &t); - } - - // Don't allow any more tokens after the expression - GetToken(&t); - if( t.type != ttEnd && t.type != ttEndStatement && t.type != ttListSeparator && t.type != ttEndStatementBlock ) - { - asCString msg; - msg.Format(TXT_UNEXPECTED_TOKEN_s, asCTokenizer::GetDefinition(t.type)); - Error(msg, &t); - } - - if( isSyntaxError || errorWhileParsing ) - return -1; - - return 0; -} - -asCScriptNode *asCParser::SuperficiallyParseVarInit() -{ - asCScriptNode *node = CreateNode(snAssignment); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - node->UpdateSourcePos(t.pos, t.length); - - if( t.type == ttAssignment ) - { - GetToken(&t); - if( t.type == ttStartStatementBlock ) - { - sToken start = t; - - // Find the end of the initialization list - int indent = 1; - while( indent ) - { - GetToken(&t); - if( t.type == ttStartStatementBlock ) - indent++; - else if( t.type == ttEndStatementBlock ) - indent--; - else if( t.type == ttNonTerminatedStringConstant ) - { - Error(TXT_NONTERMINATED_STRING, &t); - break; - } - else if( t.type == ttEnd ) - { - Error(TXT_UNEXPECTED_END_OF_FILE, &t); - Info(TXT_WHILE_PARSING_INIT_LIST, &start); - break; - } - } - } - else - { - sToken start = t; - - // Find the end of the expression - int indent = 0; - while( indent || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) ) - { - if( t.type == ttOpenParanthesis ) - indent++; - else if( t.type == ttCloseParanthesis ) - indent--; - else if( t.type == ttNonTerminatedStringConstant ) - { - Error(TXT_NONTERMINATED_STRING, &t); - break; - } - else if( t.type == ttEnd ) - { - Error(TXT_UNEXPECTED_END_OF_FILE, &t); - Info(TXT_WHILE_PARSING_EXPRESSION, &start); - break; - } - GetToken(&t); - } - - // Rewind so that the next token read is the list separator, end statement, or end statement block - RewindTo(&t); - } - } - else if( t.type == ttOpenParanthesis ) - { - sToken start = t; - - // Find the end of the argument list - int indent = 1; - while( indent ) - { - GetToken(&t); - if( t.type == ttOpenParanthesis ) - indent++; - else if( t.type == ttCloseParanthesis ) - indent--; - else if( t.type == ttNonTerminatedStringConstant ) - { - Error(TXT_NONTERMINATED_STRING, &t); - break; - } - else if( t.type == ttEnd ) - { - Error(TXT_UNEXPECTED_END_OF_FILE, &t); - Info(TXT_WHILE_PARSING_ARG_LIST, &start); - break; - } - } - } - else - { - int tokens[] = {ttAssignment, ttOpenParanthesis}; - Error(ExpectedOneOf(tokens, 2), &t); - Error(InsteadFound(t), &t); - } - - return node; -} - -asCScriptNode *asCParser::SuperficiallyParseStatementBlock() -{ - asCScriptNode *node = CreateNode(snStatementBlock); - if( node == 0 ) return 0; - - // This function will only superficially parse the statement block in order to find the end of it - sToken t1; - - GetToken(&t1); - if( t1.type != ttStartStatementBlock ) - { - Error(ExpectedToken("{"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - sToken start = t1; - - int level = 1; - while( level > 0 && !isSyntaxError ) - { - GetToken(&t1); - if( t1.type == ttEndStatementBlock ) - level--; - else if( t1.type == ttStartStatementBlock ) - level++; - else if( t1.type == ttNonTerminatedStringConstant ) - { - Error(TXT_NONTERMINATED_STRING, &t1); - break; - } - else if( t1.type == ttEnd ) - { - Error(TXT_UNEXPECTED_END_OF_FILE, &t1); - Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start); - break; - } - } - - node->UpdateSourcePos(t1.pos, t1.length); - - return node; -} - -asCScriptNode *asCParser::ParseStatementBlock() -{ - asCScriptNode *node = CreateNode(snStatementBlock); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - if( t1.type != ttStartStatementBlock ) - { - Error(ExpectedToken("{"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - sToken start = t1; - - node->UpdateSourcePos(t1.pos, t1.length); - - for(;;) - { - while( !isSyntaxError ) - { - GetToken(&t1); - if( t1.type == ttEndStatementBlock ) - { - node->UpdateSourcePos(t1.pos, t1.length); - - // Statement block is finished - return node; - } - else - { - RewindTo(&t1); - - if( IsVarDecl() ) - node->AddChildLast(ParseDeclaration()); - else - node->AddChildLast(ParseStatement()); - } - } - - if( isSyntaxError ) - { - // Search for either ';', '{', '}', or end - GetToken(&t1); - while( t1.type != ttEndStatement && t1.type != ttEnd && - t1.type != ttStartStatementBlock && t1.type != ttEndStatementBlock ) - { - GetToken(&t1); - } - - // Skip this statement block - if( t1.type == ttStartStatementBlock ) - { - // Find the end of the block and skip nested blocks - int level = 1; - while( level > 0 ) - { - GetToken(&t1); - if( t1.type == ttStartStatementBlock ) level++; - if( t1.type == ttEndStatementBlock ) level--; - if( t1.type == ttEnd ) break; - } - } - else if( t1.type == ttEndStatementBlock ) - { - RewindTo(&t1); - } - else if( t1.type == ttEnd ) - { - Error(TXT_UNEXPECTED_END_OF_FILE, &t1); - Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start); - return node; - } - - isSyntaxError = false; - } - } - UNREACHABLE_RETURN; -} - -asCScriptNode *asCParser::ParseInitList() -{ - asCScriptNode *node = CreateNode(snInitList); - if( node == 0 ) return 0; - - sToken t1; - - GetToken(&t1); - if( t1.type != ttStartStatementBlock ) - { - Error(ExpectedToken("{"), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - - node->UpdateSourcePos(t1.pos, t1.length); - - GetToken(&t1); - if( t1.type == ttEndStatementBlock ) - { - node->UpdateSourcePos(t1.pos, t1.length); - - // Statement block is finished - return node; - } - else - { - RewindTo(&t1); - for(;;) - { - GetToken(&t1); - if( t1.type == ttListSeparator ) - { - // No expression - node->AddChildLast(CreateNode(snUndefined)); - - GetToken(&t1); - if( t1.type == ttEndStatementBlock ) - { - // No expression - node->AddChildLast(CreateNode(snUndefined)); - node->UpdateSourcePos(t1.pos, t1.length); - return node; - } - RewindTo(&t1); - } - else if( t1.type == ttEndStatementBlock ) - { - // No expression - node->AddChildLast(CreateNode(snUndefined)); - - node->UpdateSourcePos(t1.pos, t1.length); - - // Statement block is finished - return node; - } - else if( t1.type == ttStartStatementBlock ) - { - RewindTo(&t1); - node->AddChildLast(ParseInitList()); - if( isSyntaxError ) return node; - - GetToken(&t1); - if( t1.type == ttListSeparator ) - continue; - else if( t1.type == ttEndStatementBlock ) - { - node->UpdateSourcePos(t1.pos, t1.length); - - // Statement block is finished - return node; - } - else - { - Error(ExpectedTokens("}", ","), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - } - else - { - RewindTo(&t1); - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - - GetToken(&t1); - if( t1.type == ttListSeparator ) - continue; - else if( t1.type == ttEndStatementBlock ) - { - node->UpdateSourcePos(t1.pos, t1.length); - - // Statement block is finished - return node; - } - else - { - Error(ExpectedTokens("}", ","), &t1); - Error(InsteadFound(t1), &t1); - return node; - } - } - } - } - UNREACHABLE_RETURN; -} - -asCScriptNode *asCParser::ParseDeclaration(bool isClassProp, bool isGlobalVar) -{ - asCScriptNode *node = CreateNode(snDeclaration); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - RewindTo(&t); - - // A class property can be preceeded by private - if( t.type == ttPrivate && isClassProp ) - node->AddChildLast(ParseToken(ttPrivate)); - - // Parse data type - node->AddChildLast(ParseType(true, false, !isClassProp)); - if( isSyntaxError ) return node; - - for(;;) - { - // Parse identifier - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - if( isClassProp || isGlobalVar ) - { - // Only superficially parse the initialization info for the class property - GetToken(&t); - RewindTo(&t); - if( t.type == ttAssignment || t.type == ttOpenParanthesis ) - { - node->AddChildLast(SuperficiallyParseVarInit()); - if( isSyntaxError ) return node; - } - } - else - { - // If next token is assignment, parse expression - GetToken(&t); - if( t.type == ttOpenParanthesis ) - { - RewindTo(&t); - node->AddChildLast(ParseArgList()); - if( isSyntaxError ) return node; - } - else if( t.type == ttAssignment ) - { - GetToken(&t); - RewindTo(&t); - if( t.type == ttStartStatementBlock ) - { - node->AddChildLast(ParseInitList()); - if( isSyntaxError ) return node; - } - else - { - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - } - } - else - RewindTo(&t); - } - - // continue if list separator, else terminate with end statement - GetToken(&t); - if( t.type == ttListSeparator ) - continue; - else if( t.type == ttEndStatement ) - { - node->UpdateSourcePos(t.pos, t.length); - - return node; - } - else - { - Error(ExpectedTokens(",", ";"), &t); - Error(InsteadFound(t), &t); - return node; - } - } - UNREACHABLE_RETURN; -} - -asCScriptNode *asCParser::ParseStatement() -{ - sToken t1; - - GetToken(&t1); - RewindTo(&t1); - - if( t1.type == ttIf ) - return ParseIf(); - else if( t1.type == ttFor ) - return ParseFor(); - else if( t1.type == ttWhile ) - return ParseWhile(); - else if( t1.type == ttReturn ) - return ParseReturn(); - else if( t1.type == ttStartStatementBlock ) - return ParseStatementBlock(); - else if( t1.type == ttBreak ) - return ParseBreak(); - else if( t1.type == ttContinue ) - return ParseContinue(); - else if( t1.type == ttDo ) - return ParseDoWhile(); - else if( t1.type == ttSwitch ) - return ParseSwitch(); - else - { - if( IsVarDecl() ) - { - Error(TXT_UNEXPECTED_VAR_DECL, &t1); - return 0; - } - return ParseExpressionStatement(); - } -} - -asCScriptNode *asCParser::ParseExpressionStatement() -{ - asCScriptNode *node = CreateNode(snExpressionStatement); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type == ttEndStatement ) - { - node->UpdateSourcePos(t.pos, t.length); - - return node; - } - - RewindTo(&t); - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttEndStatement ) - { - Error(ExpectedToken(";"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseSwitch() -{ - asCScriptNode *node = CreateNode(snSwitch); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttSwitch ) - { - Error(ExpectedToken("switch"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttCloseParanthesis ) - { - Error(ExpectedToken(")"), &t); - Error(InsteadFound(t), &t); - return node; - } - - GetToken(&t); - if( t.type != ttStartStatementBlock ) - { - Error(ExpectedToken("{"), &t); - Error(InsteadFound(t), &t); - return node; - } - - while( !isSyntaxError ) - { - GetToken(&t); - - if( t.type == ttEndStatementBlock ) - break; - - RewindTo(&t); - - if( t.type != ttCase && t.type != ttDefault ) - { - const char *tokens[] = {"case", "default"}; - Error(ExpectedOneOf(tokens, 2), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseCase()); - if( isSyntaxError ) return node; - } - - if( t.type != ttEndStatementBlock ) - { - Error(ExpectedToken("}"), &t); - Error(InsteadFound(t), &t); - return node; - } - - return node; -} - -asCScriptNode *asCParser::ParseCase() -{ - asCScriptNode *node = CreateNode(snCase); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttCase && t.type != ttDefault ) - { - Error(ExpectedTokens("case", "default"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - if(t.type == ttCase) - { - node->AddChildLast(ParseExpression()); - } - - GetToken(&t); - if( t.type != ttColon ) - { - Error(ExpectedToken(":"), &t); - Error(InsteadFound(t), &t); - return node; - } - - // Parse statements until we find either of }, case, default, and break - GetToken(&t); - RewindTo(&t); - while( t.type != ttCase && - t.type != ttDefault && - t.type != ttEndStatementBlock && - t.type != ttBreak ) - { - if( IsVarDecl() ) - // Variable declarations are not allowed, but we parse it anyway to give a good error message - node->AddChildLast(ParseDeclaration()); - else - node->AddChildLast(ParseStatement()); - if( isSyntaxError ) return node; - - GetToken(&t); - RewindTo(&t); - } - - // If the case was ended with a break statement, add it to the node - if( t.type == ttBreak ) - node->AddChildLast(ParseBreak()); - - return node; -} - -asCScriptNode *asCParser::ParseIf() -{ - asCScriptNode *node = CreateNode(snIf); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttIf ) - { - Error(ExpectedToken("if"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttCloseParanthesis ) - { - Error(ExpectedToken(")"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseStatement()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttElse ) - { - // No else statement return already - RewindTo(&t); - return node; - } - - node->AddChildLast(ParseStatement()); - - return node; -} - -asCScriptNode *asCParser::ParseFor() -{ - asCScriptNode *node = CreateNode(snFor); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttFor ) - { - Error(ExpectedToken("for"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t); - Error(InsteadFound(t), &t); - return node; - } - - if( IsVarDecl() ) - node->AddChildLast(ParseDeclaration()); - else - node->AddChildLast(ParseExpressionStatement()); - if( isSyntaxError ) return node; - - node->AddChildLast(ParseExpressionStatement()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttCloseParanthesis ) - { - RewindTo(&t); - - asCScriptNode *n = CreateNode(snExpressionStatement); - if( n == 0 ) return 0; - node->AddChildLast(n); - n->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttCloseParanthesis ) - { - Error(ExpectedToken(")"), &t); - Error(InsteadFound(t), &t); - return node; - } - } - - node->AddChildLast(ParseStatement()); - - return node; -} - -asCScriptNode *asCParser::ParseWhile() -{ - asCScriptNode *node = CreateNode(snWhile); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttWhile ) - { - Error(ExpectedToken("while"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttCloseParanthesis ) - { - Error(ExpectedToken(")"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseStatement()); - - return node; -} - -asCScriptNode *asCParser::ParseDoWhile() -{ - asCScriptNode *node = CreateNode(snDoWhile); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttDo ) - { - Error(ExpectedToken("do"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - node->AddChildLast(ParseStatement()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttWhile ) - { - Error(ExpectedToken("while"), &t); - Error(InsteadFound(t), &t); - return node; - } - - GetToken(&t); - if( t.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttCloseParanthesis ) - { - Error(ExpectedToken(")"), &t); - Error(InsteadFound(t), &t); - return node; - } - - GetToken(&t); - if( t.type != ttEndStatement ) - { - Error(ExpectedToken(";"), &t); - Error(InsteadFound(t), &t); - return node; - } - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseReturn() -{ - asCScriptNode *node = CreateNode(snReturn); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttReturn ) - { - Error(ExpectedToken("return"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type == ttEndStatement ) - { - node->UpdateSourcePos(t.pos, t.length); - return node; - } - - RewindTo(&t); - - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type != ttEndStatement ) - { - Error(ExpectedToken(";"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseBreak() -{ - asCScriptNode *node = CreateNode(snBreak); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttBreak ) - { - Error(ExpectedToken("break"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type != ttEndStatement ) - { - Error(ExpectedToken(";"), &t); - Error(InsteadFound(t), &t); - } - - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -asCScriptNode *asCParser::ParseContinue() -{ - asCScriptNode *node = CreateNode(snContinue); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - if( t.type != ttContinue ) - { - Error(ExpectedToken("continue"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - GetToken(&t); - if( t.type != ttEndStatement ) - { - Error(ExpectedToken(";"), &t); - Error(InsteadFound(t), &t); - } - - node->UpdateSourcePos(t.pos, t.length); - - return node; -} - -// TODO: typedef: Typedefs should accept complex types as well -asCScriptNode *asCParser::ParseTypedef() -{ - // Create the typedef node - asCScriptNode *node = CreateNode(snTypedef); - if( node == 0 ) return 0; - - sToken token; - - GetToken(&token); - if( token.type != ttTypedef) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(token.type)), &token); - Error(InsteadFound(token), &token); - return node; - } - - node->SetToken(&token); - node->UpdateSourcePos(token.pos, token.length); - - // Parse the base type - GetToken(&token); - RewindTo(&token); - - // Make sure it is a primitive type (except ttVoid) - if( !IsRealType(token.type) || token.type == ttVoid ) - { - asCString str; - str.Format(TXT_UNEXPECTED_TOKEN_s, asCTokenizer::GetDefinition(token.type)); - Error(str, &token); - return node; - } - - node->AddChildLast(ParseRealType()); - node->AddChildLast(ParseIdentifier()); - - // Check for the end of the typedef - GetToken(&token); - if( token.type != ttEndStatement ) - { - RewindTo(&token); - Error(ExpectedToken(asCTokenizer::GetDefinition(token.type)), &token); - Error(InsteadFound(token), &token); - } - - return node; -} - -void asCParser::ParseMethodOverrideBehaviors(asCScriptNode *funcNode) -{ - sToken t1; - - for(;;) - { - GetToken(&t1); - RewindTo(&t1); - - if( IdentifierIs(t1, FINAL_TOKEN) || IdentifierIs(t1, OVERRIDE_TOKEN) ) - funcNode->AddChildLast(ParseIdentifier()); - else - break; - } -} -#endif - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_parser.h b/dependencies/angelscript/source/as_parser.h deleted file mode 100644 index 5cc7dc9b..00000000 --- a/dependencies/angelscript/source/as_parser.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_parser.h -// -// This class parses the script code and builds a tree for compilation -// - - - -#ifndef AS_PARSER_H -#define AS_PARSER_H - -#include "as_scriptnode.h" -#include "as_scriptcode.h" -#include "as_builder.h" -#include "as_tokenizer.h" - -BEGIN_AS_NAMESPACE - -class asCParser -{ -public: - asCParser(asCBuilder *builder); - ~asCParser(); - - int ParseFunctionDefinition(asCScriptCode *script, bool expectListPattern); - int ParsePropertyDeclaration(asCScriptCode *script); - int ParseDataType(asCScriptCode *script, bool isReturnType); - int ParseTemplateDecl(asCScriptCode *script); - -#ifndef AS_NO_COMPILER - int ParseScript(asCScriptCode *script); - - // Called from compiler - int ParseStatementBlock(asCScriptCode *script, asCScriptNode *block); - int ParseVarInit(asCScriptCode *script, asCScriptNode *init); - int ParseExpression(asCScriptCode *script); -#endif - - asCScriptNode *GetScriptNode(); - -protected: - void Reset(); - - void GetToken(sToken *token); - void RewindTo(const sToken *token); - void SetPos(size_t pos); - void Error(const asCString &text, sToken *token); - void Warning(const asCString &text, sToken *token); - void Info(const asCString &text, sToken *token); - - asCScriptNode *CreateNode(eScriptNode type); - - asCScriptNode *ParseFunctionDefinition(); - asCScriptNode *ParseParameterList(); - asCScriptNode *SuperficiallyParseExpression(); - asCScriptNode *ParseType(bool allowConst, bool allowVariableType = false, bool allowAuto = false); - asCScriptNode *ParseTypeMod(bool isParam); - void ParseOptionalScope(asCScriptNode *node); - asCScriptNode *ParseRealType(); - asCScriptNode *ParseDataType(bool allowVariableType = false, bool allowAuto = false); - asCScriptNode *ParseIdentifier(); - - asCScriptNode *ParseListPattern(); - - bool IsRealType(int tokenType); - bool IsDataType(const sToken &token); - bool IdentifierIs(const sToken &t, const char *str); - -#ifndef AS_NO_COMPILER - // Statements - asCScriptNode *SuperficiallyParseStatementBlock(); - asCScriptNode *SuperficiallyParseVarInit(); - asCScriptNode *ParseStatementBlock(); - asCScriptNode *ParseStatement(); - asCScriptNode *ParseExpressionStatement(); - asCScriptNode *ParseSwitch(); - asCScriptNode *ParseCase(); - asCScriptNode *ParseIf(); - asCScriptNode *ParseFor(); - asCScriptNode *ParseWhile(); - asCScriptNode *ParseDoWhile(); - asCScriptNode *ParseReturn(); - asCScriptNode *ParseBreak(); - asCScriptNode *ParseContinue(); - - // Declarations - asCScriptNode *ParseDeclaration(bool isClassProp = false, bool isGlobalVar = false); - asCScriptNode *ParseImport(); - asCScriptNode *ParseScript(bool inBlock); - asCScriptNode *ParseNamespace(); - asCScriptNode *ParseFunction(bool isMethod = false); - asCScriptNode *ParseFuncDef(); - asCScriptNode *ParseClass(); - asCScriptNode *ParseMixin(); - asCScriptNode *ParseInitList(); - asCScriptNode *ParseInterface(); - asCScriptNode *ParseInterfaceMethod(); - asCScriptNode *ParseVirtualPropertyDecl(bool isMethod, bool isInterface); - asCScriptNode *ParseEnumeration(); - asCScriptNode *ParseTypedef(); - void ParseMethodOverrideBehaviors(asCScriptNode *funcNode); - bool IsVarDecl(); - bool IsVirtualPropertyDecl(); - bool IsFuncDecl(bool isMethod); - - // Expressions - asCScriptNode *ParseAssignment(); - asCScriptNode *ParseAssignOperator(); - asCScriptNode *ParseCondition(); - asCScriptNode *ParseExpression(); - asCScriptNode *ParseExprTerm(); - asCScriptNode *ParseExprOperator(); - asCScriptNode *ParseExprPreOp(); - asCScriptNode *ParseExprPostOp(); - asCScriptNode *ParseExprValue(); - asCScriptNode *ParseArgList(bool withParenthesis = true); - asCScriptNode *ParseFunctionCall(); - asCScriptNode *ParseVariableAccess(); - asCScriptNode *ParseConstructCall(); - asCScriptNode *ParseCast(); - asCScriptNode *ParseConstant(); - asCScriptNode *ParseStringConstant(); - - bool IsConstant(int tokenType); - bool IsOperator(int tokenType); - bool IsPreOperator(int tokenType); - bool IsPostOperator(int tokenType); - bool IsAssignOperator(int tokenType); - bool IsFunctionCall(); - - bool CheckTemplateType(sToken &t); -#endif - - asCScriptNode *ParseToken(int token); - asCScriptNode *ParseOneOf(int *tokens, int num); - - asCString ExpectedToken(const char *token); - asCString ExpectedTokens(const char *token1, const char *token2); - asCString ExpectedOneOf(int *tokens, int count); - asCString ExpectedOneOf(const char **tokens, int count); - asCString InsteadFound(sToken &t); - - bool errorWhileParsing; - bool isSyntaxError; - bool checkValidTypes; - bool isParsingAppInterface; - - asCScriptEngine *engine; - asCBuilder *builder; - asCScriptCode *script; - asCScriptNode *scriptNode; - - asCString tempString; // Used for reduzing amount of dynamic allocations - - sToken lastToken; - size_t sourcePos; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_property.h b/dependencies/angelscript/source/as_property.h deleted file mode 100644 index 1670e6ac..00000000 --- a/dependencies/angelscript/source/as_property.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_property.h -// -// A class for storing object property information -// - - - -#ifndef AS_PROPERTY_H -#define AS_PROPERTY_H - -#include "as_string.h" -#include "as_datatype.h" -#include "as_atomic.h" -#include "as_scriptfunction.h" -#include "as_symboltable.h" - -BEGIN_AS_NAMESPACE - -struct asSNameSpace; - -class asCObjectProperty -{ -public: - asCObjectProperty() {accessMask = 0xFFFFFFFF;} - asCObjectProperty(const asCObjectProperty &o) : name(o.name), type(o.type), byteOffset(o.byteOffset), isPrivate(o.isPrivate), accessMask(o.accessMask) {} - asCString name; - asCDataType type; - int byteOffset; - bool isPrivate; - asDWORD accessMask; -}; - -class asCGlobalProperty -{ -public: - asCGlobalProperty(); - ~asCGlobalProperty(); - - void AddRef(); - void Release(); - int GetRefCount(); - - void *GetAddressOfValue(); - void AllocateMemory(); - void SetRegisteredAddress(void *p); - void *GetRegisteredAddress() const; - - asCString name; - asCDataType type; - asUINT id; - asSNameSpace *nameSpace; - - void SetInitFunc(asCScriptFunction *initFunc); - asCScriptFunction *GetInitFunc(); - - static void RegisterGCBehaviours(asCScriptEngine *engine); - -//protected: - void SetGCFlag(); - bool GetGCFlag(); - void EnumReferences(asIScriptEngine *); - void ReleaseAllHandles(asIScriptEngine *); - - void Orphan(asCModule *module); - - // This is only stored for registered properties, and keeps the pointer given by the application - void *realAddress; - - bool memoryAllocated; - void *memory; - asQWORD storage; - - asCScriptFunction *initFunc; - - asDWORD accessMask; - - // The global property structure is reference counted, so that the - // engine can keep track of how many references to the property there are. - asCAtomic refCount; - bool gcFlag; -}; - -class asCCompGlobPropType : public asIFilter -{ -public: - const asCDataType &m_type; - - asCCompGlobPropType(const asCDataType &type) : m_type(type) {} - - bool operator()(const void *p) const - { - const asCGlobalProperty* prop = reinterpret_cast(p); - return prop->type == m_type; - } - -private: - // The assignment operator is required for MSVC9, otherwise it will complain that it is not possible to auto generate the operator - asCCompGlobPropType &operator=(const asCCompGlobPropType &) {return *this;} -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_restore.cpp b/dependencies/angelscript/source/as_restore.cpp deleted file mode 100644 index 519765ab..00000000 --- a/dependencies/angelscript/source/as_restore.cpp +++ /dev/null @@ -1,4906 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_restore.cpp -// -// Functions for saving and restoring module bytecode -// asCRestore was originally written by Dennis Bollyn, dennis@gyrbo.be - -#include "as_config.h" -#include "as_restore.h" -#include "as_bytecode.h" -#include "as_scriptobject.h" -#include "as_texts.h" - -BEGIN_AS_NAMESPACE - -asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine) - : module(_module), stream(_stream), engine(_engine) -{ - error = false; - bytesRead = 0; -} - -void asCReader::ReadData(void *data, asUINT size) -{ - asASSERT(size == 1 || size == 2 || size == 4 || size == 8); -#if defined(AS_BIG_ENDIAN) - for( asUINT n = 0; n < size; n++ ) - stream->Read(((asBYTE*)data)+n, 1); -#else - for( int n = size-1; n >= 0; n-- ) - stream->Read(((asBYTE*)data)+n, 1); -#endif - bytesRead += size; -} - -int asCReader::Read(bool *wasDebugInfoStripped) -{ - // Before starting the load, make sure that - // any existing resources have been freed - module->InternalReset(); - - // Call the inner method to do the actual loading - int r = ReadInner(); - if( r < 0 ) - { - // Something went wrong while loading the bytecode, so we need - // to clean-up whatever has been created during the process. - - // Make sure none of the loaded functions attempt to release - // references that have not yet been increased - asUINT i; - for( i = 0; i < module->scriptFunctions.GetLength(); i++ ) - if( !dontTranslate.MoveTo(0, module->scriptFunctions[i]) ) - if( module->scriptFunctions[i]->scriptData ) - module->scriptFunctions[i]->scriptData->byteCode.SetLength(0); - - asCSymbolTable::iterator it = module->scriptGlobals.List(); - for( ; it; it++ ) - if( (*it)->GetInitFunc() ) - if( (*it)->GetInitFunc()->scriptData ) - (*it)->GetInitFunc()->scriptData->byteCode.SetLength(0); - - module->InternalReset(); - } - else - { - // Init system functions properly - engine->PrepareEngine(); - - // Initialize the global variables (unless requested not to) - if( engine->ep.initGlobalVarsAfterBuild ) - r = module->ResetGlobalVars(0); - - if( wasDebugInfoStripped ) - *wasDebugInfoStripped = noDebugInfo; - } - - return r; -} - -int asCReader::Error(const char *msg) -{ - // Don't write if it has already been reported an error earlier - if( !error ) - { - asCString str; - str.Format(msg, bytesRead); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - error = true; - } - - return asERROR; -} - -int asCReader::ReadInner() -{ - // This function will load each entity one by one from the stream. - // If any error occurs, it will return to the caller who is - // responsible for cleaning up the partially loaded entities. - - engine->deferValidationOfTemplateTypes = true; - - unsigned long i, count; - asCScriptFunction* func; - - ReadData(&noDebugInfo, 1); - - // Read enums - count = ReadEncodedUInt(); - module->enumTypes.Allocate(count, false); - for( i = 0; i < count && !error; i++ ) - { - asCObjectType *ot = asNEW(asCObjectType)(engine); - if( ot == 0 ) - { - error = true; - return asOUT_OF_MEMORY; - } - - ReadObjectTypeDeclaration(ot, 1); - - // If the type is shared then we should use the original if it exists - bool sharedExists = false; - if( ot->IsShared() ) - { - for( asUINT n = 0; n < engine->scriptTypes.GetLength(); n++ ) - { - asCObjectType *t = engine->scriptTypes[n]; - if( t && - t->IsShared() && - t->name == ot->name && - t->nameSpace == ot->nameSpace && - (t->flags & asOBJ_ENUM) ) - { - asDELETE(ot, asCObjectType); - ot = t; - sharedExists = true; - break; - } - } - } - - if( sharedExists ) - existingShared.Insert(ot, true); - else - { - engine->scriptTypes.PushLast(ot); - - // Set this module as the owner - ot->module = module; - } - module->enumTypes.PushLast(ot); - ot->AddRef(); - ReadObjectTypeDeclaration(ot, 2); - } - - if( error ) return asERROR; - - // classTypes[] - // First restore the structure names, then the properties - count = ReadEncodedUInt(); - module->classTypes.Allocate(count, false); - for( i = 0; i < count && !error; ++i ) - { - asCObjectType *ot = asNEW(asCObjectType)(engine); - if( ot == 0 ) - { - error = true; - return asOUT_OF_MEMORY; - } - - ReadObjectTypeDeclaration(ot, 1); - - // If the type is shared, then we should use the original if it exists - bool sharedExists = false; - if( ot->IsShared() ) - { - for( asUINT n = 0; n < engine->scriptTypes.GetLength(); n++ ) - { - asCObjectType *t = engine->scriptTypes[n]; - if( t && - t->IsShared() && - t->name == ot->name && - t->nameSpace == ot->nameSpace && - t->IsInterface() == ot->IsInterface() ) - { - asDELETE(ot, asCObjectType); - ot = t; - sharedExists = true; - break; - } - } - } - - if( sharedExists ) - existingShared.Insert(ot, true); - else - { - engine->scriptTypes.PushLast(ot); - - // Set this module as the owner - ot->module = module; - } - module->classTypes.PushLast(ot); - ot->AddRef(); - } - - if( error ) return asERROR; - - // Read func defs - count = ReadEncodedUInt(); - module->funcDefs.Allocate(count, false); - for( i = 0; i < count && !error; i++ ) - { - bool isNew; - asCScriptFunction *func = ReadFunction(isNew, false, true); - if( func ) - { - module->funcDefs.PushLast(func); - engine->funcDefs.PushLast(func); - - // TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module - // Check if there is another identical funcdef from another module and if so reuse that instead - for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) - { - asCScriptFunction *f2 = engine->funcDefs[n]; - if( f2 == 0 || func == f2 ) - continue; - - if( f2->name == func->name && - f2->nameSpace == func->nameSpace && - f2->IsSignatureExceptNameEqual(func) ) - { - // Replace our funcdef for the existing one - module->funcDefs[module->funcDefs.IndexOf(func)] = f2; - f2->AddRef(); - - engine->funcDefs.RemoveValue(func); - - savedFunctions[savedFunctions.IndexOf(func)] = f2; - - func->Release(); - - // Funcdefs aren't deleted when the ref count reaches zero so we must manually delete it here - asDELETE(func,asCScriptFunction); - break; - } - } - } - else - Error(TXT_INVALID_BYTECODE_d); - } - - // Read interface methods - for( i = 0; i < module->classTypes.GetLength() && !error; i++ ) - { - if( module->classTypes[i]->IsInterface() ) - ReadObjectTypeDeclaration(module->classTypes[i], 2); - } - - // Read class methods and behaviours - for( i = 0; i < module->classTypes.GetLength() && !error; ++i ) - { - if( !module->classTypes[i]->IsInterface() ) - ReadObjectTypeDeclaration(module->classTypes[i], 2); - } - - // Read class properties - for( i = 0; i < module->classTypes.GetLength() && !error; ++i ) - { - if( !module->classTypes[i]->IsInterface() ) - ReadObjectTypeDeclaration(module->classTypes[i], 3); - } - - if( error ) return asERROR; - - // Read typedefs - count = ReadEncodedUInt(); - module->typeDefs.Allocate(count, false); - for( i = 0; i < count && !error; i++ ) - { - asCObjectType *ot = asNEW(asCObjectType)(engine); - if( ot == 0 ) - { - error = true; - return asOUT_OF_MEMORY; - } - - ReadObjectTypeDeclaration(ot, 1); - ot->module = module; - engine->scriptTypes.PushLast(ot); - module->typeDefs.PushLast(ot); - ot->AddRef(); - ReadObjectTypeDeclaration(ot, 2); - } - - if( error ) return asERROR; - - // scriptGlobals[] - count = ReadEncodedUInt(); - if( count && engine->ep.disallowGlobalVars ) - { - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GLOBAL_VARS_NOT_ALLOWED); - Error(TXT_INVALID_BYTECODE_d); - } - module->scriptGlobals.Allocate(count, false); - for( i = 0; i < count && !error; ++i ) - { - ReadGlobalProperty(); - } - - // scriptFunctions[] - count = ReadEncodedUInt(); - for( i = 0; i < count && !error; ++i ) - { - size_t len = module->scriptFunctions.GetLength(); - bool isNew; - func = ReadFunction(isNew); - if( func == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - break; - } - - // Is the function shared and was it created now? - if( func->isShared && len != module->scriptFunctions.GetLength() ) - { - // If the function already existed in another module, then - // we need to replace it with previously existing one - for( asUINT n = 0; n < engine->scriptFunctions.GetLength() && !error; n++ ) - { - asCScriptFunction *realFunc = engine->scriptFunctions[n]; - if( realFunc && - realFunc != func && - realFunc->IsShared() && - realFunc->IsSignatureEqual(func) ) - { - // Replace the recently created function with the pre-existing function - module->scriptFunctions[module->scriptFunctions.GetLength()-1] = realFunc; - realFunc->AddRef(); - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - engine->FreeScriptFunctionId(func->id); - - // Insert the function in the dontTranslate array - dontTranslate.Insert(realFunc, true); - - // Release the function, but make sure nothing else is released - func->id = 0; - func->scriptData->byteCode.SetLength(0); - func->Release(); - break; - } - } - } - } - - // globalFunctions[] - count = ReadEncodedUInt(); - for( i = 0; i < count && !error; ++i ) - { - bool isNew; - func = ReadFunction(isNew, false, false); - if( func ) - { - // All the global functions were already loaded while loading the scriptFunctions, here - // we're just re-reading the refernces to know which goes into the globalFunctions array - asASSERT( !isNew ); - - module->globalFunctions.Put(func); - func->AddRef(); - } - else - Error(TXT_INVALID_BYTECODE_d); - } - - if( error ) return asERROR; - - // bindInformations[] - count = ReadEncodedUInt(); - module->bindInformations.Allocate(count, false); - for( i = 0; i < count && !error; ++i ) - { - sBindInfo *info = asNEW(sBindInfo); - if( info == 0 ) - { - error = true; - return asOUT_OF_MEMORY; - } - - bool isNew; - info->importedFunctionSignature = ReadFunction(isNew, false, false); - if( info->importedFunctionSignature == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - break; - } - - if( engine->freeImportedFunctionIdxs.GetLength() ) - { - int id = engine->freeImportedFunctionIdxs.PopLast(); - info->importedFunctionSignature->id = int(FUNC_IMPORTED + id); - engine->importedFunctions[id] = info; - } - else - { - info->importedFunctionSignature->id = int(FUNC_IMPORTED + engine->importedFunctions.GetLength()); - engine->importedFunctions.PushLast(info); - } - ReadString(&info->importFromModule); - info->boundFunctionId = -1; - module->bindInformations.PushLast(info); - } - - if( error ) return asERROR; - - // usedTypes[] - count = ReadEncodedUInt(); - usedTypes.Allocate(count, false); - for( i = 0; i < count && !error; ++i ) - { - asCObjectType *ot = ReadObjectType(); - usedTypes.PushLast(ot); - } - - // usedTypeIds[] - if( !error ) - ReadUsedTypeIds(); - - // usedFunctions[] - if( !error ) - ReadUsedFunctions(); - - // usedGlobalProperties[] - if( !error ) - ReadUsedGlobalProps(); - - // usedStringConstants[] - if( !error ) - ReadUsedStringConstants(); - - // usedObjectProperties - if( !error ) - ReadUsedObjectProps(); - - // Validate the template types - if( !error ) - { - for( i = 0; i < usedTypes.GetLength() && !error; i++ ) - { - if( !(usedTypes[i]->flags & asOBJ_TEMPLATE) || - !usedTypes[i]->beh.templateCallback ) - continue; - - bool dontGarbageCollect = false; - asCScriptFunction *callback = engine->scriptFunctions[usedTypes[i]->beh.templateCallback]; - if( !engine->CallGlobalFunctionRetBool(usedTypes[i], &dontGarbageCollect, callback->sysFuncIntf, callback) ) - { - asCString sub = usedTypes[i]->templateSubTypes[0].Format(); - for( asUINT n = 1; n < usedTypes[i]->templateSubTypes.GetLength(); n++ ) - { - sub += ","; - sub += usedTypes[i]->templateSubTypes[n].Format(); - } - asCString str; - str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, usedTypes[i]->name.AddressOf(), sub.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - else - { - // If the callback said this template instance won't be garbage collected then remove the flag - if( dontGarbageCollect ) - usedTypes[i]->flags &= ~asOBJ_GC; - } - } - } - engine->deferValidationOfTemplateTypes = false; - - if( error ) return asERROR; - - // Update the loaded bytecode to point to the correct types, property offsets, - // function ids, etc. This is basically a linking stage. - for( i = 0; i < module->scriptFunctions.GetLength() && !error; i++ ) - if( module->scriptFunctions[i]->funcType == asFUNC_SCRIPT ) - TranslateFunction(module->scriptFunctions[i]); - - asCSymbolTable::iterator globIt = module->scriptGlobals.List(); - while( globIt && !error ) - { - asCScriptFunction *initFunc = (*globIt)->GetInitFunc(); - if( initFunc ) - TranslateFunction(initFunc); - globIt++; - } - - if( error ) return asERROR; - - // Add references for all functions (except for the pre-existing shared code) - for( i = 0; i < module->scriptFunctions.GetLength(); i++ ) - if( !dontTranslate.MoveTo(0, module->scriptFunctions[i]) ) - module->scriptFunctions[i]->AddReferences(); - - globIt = module->scriptGlobals.List(); - while( globIt ) - { - asCScriptFunction *initFunc = (*globIt)->GetInitFunc(); - if( initFunc ) - initFunc->AddReferences(); - globIt++; - } - return error ? asERROR : asSUCCESS; -} - -void asCReader::ReadUsedStringConstants() -{ - asCString str; - - asUINT count; - count = ReadEncodedUInt(); - usedStringConstants.Allocate(count, false); - for( asUINT i = 0; i < count; ++i ) - { - ReadString(&str); - usedStringConstants.PushLast(engine->AddConstantString(str.AddressOf(), str.GetLength())); - } -} - -void asCReader::ReadUsedFunctions() -{ - asUINT count; - count = ReadEncodedUInt(); - usedFunctions.SetLength(count); - if( usedFunctions.GetLength() != count ) - { - // Out of memory - error = true; - return; - } - memset(usedFunctions.AddressOf(), 0, sizeof(asCScriptFunction *)*count); - - for( asUINT n = 0; n < usedFunctions.GetLength(); n++ ) - { - char c; - - // Read the data to be able to uniquely identify the function - - // Is the function from the module or the application? - ReadData(&c, 1); - - if( c == 'n' ) - { - // Null function pointer - usedFunctions[n] = 0; - } - else - { - asCScriptFunction func(engine, c == 'm' ? module : 0, asFUNC_DUMMY); - ReadFunctionSignature(&func); - if( error ) - { - func.funcType = asFUNC_DUMMY; - return; - } - - // Find the correct function - if( c == 'm' ) - { - if( func.funcType == asFUNC_IMPORTED ) - { - for( asUINT i = 0; i < module->bindInformations.GetLength(); i++ ) - { - asCScriptFunction *f = module->bindInformations[i]->importedFunctionSignature; - if( !func.IsSignatureEqual(f) || - func.objectType != f->objectType || - func.funcType != f->funcType || - func.nameSpace != f->nameSpace ) - continue; - - usedFunctions[n] = f; - break; - } - } - else - { - for( asUINT i = 0; i < module->scriptFunctions.GetLength(); i++ ) - { - asCScriptFunction *f = module->scriptFunctions[i]; - if( !func.IsSignatureEqual(f) || - func.objectType != f->objectType || - func.funcType != f->funcType || - func.nameSpace != f->nameSpace ) - continue; - - usedFunctions[n] = f; - break; - } - } - } - else - { - for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ ) - { - asCScriptFunction *f = engine->scriptFunctions[i]; - if( f == 0 || - !func.IsSignatureEqual(f) || - func.objectType != f->objectType || - func.nameSpace != f->nameSpace ) - continue; - - usedFunctions[n] = f; - break; - } - } - - // Set the type to dummy so it won't try to release the id - func.funcType = asFUNC_DUMMY; - - if( usedFunctions[n] == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - } -} - -void asCReader::ReadFunctionSignature(asCScriptFunction *func) -{ - asUINT i, count; - asCDataType dt; - int num; - - ReadString(&func->name); - if( func->name == DELEGATE_FACTORY ) - { - // It's not necessary to read anymore, everything is known - asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY); - asASSERT( f ); - func->returnType = f->returnType; - func->parameterTypes = f->parameterTypes; - func->inOutFlags = f->inOutFlags; - func->funcType = f->funcType; - func->defaultArgs = f->defaultArgs; - func->nameSpace = f->nameSpace; - return; - } - - ReadDataType(&func->returnType); - - count = ReadEncodedUInt(); - if( count > 256 ) - { - // Too many arguments, must be something wrong in the file - Error(TXT_INVALID_BYTECODE_d); - return; - } - func->parameterTypes.Allocate(count, false); - for( i = 0; i < count; ++i ) - { - ReadDataType(&dt); - func->parameterTypes.PushLast(dt); - } - - func->inOutFlags.SetLength(func->parameterTypes.GetLength()); - if( func->inOutFlags.GetLength() != func->parameterTypes.GetLength() ) - { - // Out of memory - error = true; - return; - } - memset(func->inOutFlags.AddressOf(), 0, sizeof(asETypeModifiers)*func->inOutFlags.GetLength()); - count = ReadEncodedUInt(); - if( count > func->parameterTypes.GetLength() ) - { - // Cannot be more than the number of arguments - Error(TXT_INVALID_BYTECODE_d); - return; - } - for( i = 0; i < count; ++i ) - { - num = ReadEncodedUInt(); - func->inOutFlags[i] = static_cast(num); - } - - func->funcType = (asEFuncType)ReadEncodedUInt(); - - // Read the default args, from last to first - count = ReadEncodedUInt(); - if( count > func->parameterTypes.GetLength() ) - { - // Cannot be more than the number of arguments - Error(TXT_INVALID_BYTECODE_d); - return; - } - if( count ) - { - func->defaultArgs.SetLength(func->parameterTypes.GetLength()); - if( func->defaultArgs.GetLength() != func->parameterTypes.GetLength() ) - { - // Out of memory - error = true; - return; - } - memset(func->defaultArgs.AddressOf(), 0, sizeof(asCString*)*func->defaultArgs.GetLength()); - for( i = 0; i < count; i++ ) - { - asCString *str = asNEW(asCString); - if( str == 0 ) - { - // Out of memory - error = true; - return; - } - func->defaultArgs[func->defaultArgs.GetLength()-1-i] = str; - ReadString(str); - } - } - - func->objectType = ReadObjectType(); - if( func->objectType ) - { - asBYTE b; - ReadData(&b, 1); - func->isReadOnly = (b & 1) ? true : false; - func->isPrivate = (b & 2) ? true : false; - func->nameSpace = engine->nameSpaces[0]; - } - else - { - asCString ns; - ReadString(&ns); - func->nameSpace = engine->AddNameSpace(ns.AddressOf()); - } -} - -asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC) -{ - isNew = false; - if( error ) return 0; - - char c; - ReadData(&c, 1); - - if( c == '\0' ) - { - // There is no function, so return a null pointer - return 0; - } - - if( c == 'r' ) - { - // This is a reference to a previously saved function - asUINT index = ReadEncodedUInt(); - if( index < savedFunctions.GetLength() ) - return savedFunctions[index]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - } - - // Load the new function - isNew = true; - asCScriptFunction *func = asNEW(asCScriptFunction)(engine,0,asFUNC_DUMMY); - if( func == 0 ) - { - // Out of memory - error = true; - return 0; - } - savedFunctions.PushLast(func); - - int i, count; - asCDataType dt; - int num; - - ReadFunctionSignature(func); - if( error ) - { - func->DestroyHalfCreated(); - return 0; - } - - if( func->funcType == asFUNC_SCRIPT ) - { - func->AllocateScriptFunctionData(); - if( func->scriptData == 0 ) - { - // Out of memory - error = true; - func->DestroyHalfCreated(); - return 0; - } - - if( addToGC && !addToModule ) - engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours); - - ReadByteCode(func); - - func->scriptData->variableSpace = ReadEncodedUInt(); - - count = ReadEncodedUInt(); - func->scriptData->objVariablePos.Allocate(count, false); - func->scriptData->objVariableTypes.Allocate(count, false); - func->scriptData->funcVariableTypes.Allocate(count, false); - for( i = 0; i < count; ++i ) - { - func->scriptData->objVariableTypes.PushLast(ReadObjectType()); - asUINT idx = ReadEncodedUInt(); - func->scriptData->funcVariableTypes.PushLast((asCScriptFunction*)(asPWORD)idx); - num = ReadEncodedUInt(); - func->scriptData->objVariablePos.PushLast(num); - - if( error ) - { - // No need to continue (the error has already been reported before) - func->DestroyHalfCreated(); - return 0; - } - } - if( count > 0 ) - func->scriptData->objVariablesOnHeap = ReadEncodedUInt(); - else - func->scriptData->objVariablesOnHeap = 0; - - int length = ReadEncodedUInt(); - func->scriptData->objVariableInfo.SetLength(length); - for( i = 0; i < length; ++i ) - { - func->scriptData->objVariableInfo[i].programPos = ReadEncodedUInt(); - func->scriptData->objVariableInfo[i].variableOffset = ReadEncodedUInt(); - func->scriptData->objVariableInfo[i].option = ReadEncodedUInt(); - } - - if( !noDebugInfo ) - { - length = ReadEncodedUInt(); - func->scriptData->lineNumbers.SetLength(length); - if( int(func->scriptData->lineNumbers.GetLength()) != length ) - { - // Out of memory - error = true; - func->DestroyHalfCreated(); - return 0; - } - for( i = 0; i < length; ++i ) - func->scriptData->lineNumbers[i] = ReadEncodedUInt(); - - // Read the array of script sections - length = ReadEncodedUInt(); - func->scriptData->sectionIdxs.SetLength(length); - if( int(func->scriptData->sectionIdxs.GetLength()) != length ) - { - // Out of memory - error = true; - func->DestroyHalfCreated(); - return 0; - } - for( i = 0; i < length; ++i ) - { - if( (i & 1) == 0 ) - func->scriptData->sectionIdxs[i] = ReadEncodedUInt(); - else - { - asCString str; - ReadString(&str); - func->scriptData->sectionIdxs[i] = engine->GetScriptSectionNameIndex(str.AddressOf()); - } - } - } - - // Read the variable information - if( !noDebugInfo ) - { - length = ReadEncodedUInt(); - func->scriptData->variables.Allocate(length, false); - for( i = 0; i < length; i++ ) - { - asSScriptVariable *var = asNEW(asSScriptVariable); - if( var == 0 ) - { - // Out of memory - error = true; - func->DestroyHalfCreated(); - return 0; - } - func->scriptData->variables.PushLast(var); - - var->declaredAtProgramPos = ReadEncodedUInt(); - var->stackOffset = ReadEncodedUInt(); - ReadString(&var->name); - ReadDataType(&var->type); - - if( error ) - { - // No need to continue (the error has already been reported before) - func->DestroyHalfCreated(); - return 0; - } - } - } - - char bits; - ReadData(&bits, 1); - func->isShared = bits & 1 ? true : false; - func->dontCleanUpOnException = bits & 2 ? true : false; - - // Read script section name - if( !noDebugInfo ) - { - asCString name; - ReadString(&name); - func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf()); - func->scriptData->declaredAt = ReadEncodedUInt(); - } - - // Read parameter names - if( !noDebugInfo ) - { - asUINT count = asUINT(ReadEncodedUInt64()); - if( count > func->parameterTypes.GetLength() ) - { - error = true; - func->DestroyHalfCreated(); - return 0; - } - func->parameterNames.SetLength(count); - for( asUINT n = 0; n < count; n++ ) - ReadString(&func->parameterNames[n]); - } - } - else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) - { - func->vfTableIdx = ReadEncodedUInt(); - } - - if( addToModule ) - { - // The refCount is already 1 - module->scriptFunctions.PushLast(func); - func->module = module; - } - if( addToEngine ) - { - func->id = engine->GetNextScriptFunctionId(); - engine->SetScriptFunction(func); - } - if( func->objectType ) - func->ComputeSignatureId(); - - return func; -} - -void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase) -{ - if( phase == 1 ) - { - // Read the initial attributes - ReadString(&ot->name); - ReadData(&ot->flags, 4); - ot->size = ReadEncodedUInt(); - asCString ns; - ReadString(&ns); - ot->nameSpace = engine->AddNameSpace(ns.AddressOf()); - - // Reset the size of script classes, since it will be recalculated as properties are added - if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size != 0 ) - ot->size = sizeof(asCScriptObject); - - // Use the default script class behaviours - ot->beh = engine->scriptTypeBehaviours.beh; - ot->beh.construct = 0; - ot->beh.factory = 0; - ot->beh.constructors.PopLast(); // These will be read from the file - ot->beh.factories.PopLast(); // These will be read from the file - engine->scriptFunctions[ot->beh.addref]->AddRef(); - engine->scriptFunctions[ot->beh.release]->AddRef(); - engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRef(); - engine->scriptFunctions[ot->beh.gcGetFlag]->AddRef(); - engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRef(); - engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRef(); - engine->scriptFunctions[ot->beh.gcSetFlag]->AddRef(); - engine->scriptFunctions[ot->beh.copy]->AddRef(); - // TODO: weak: Should not do this if the class has been declared with 'noweak' - engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRef(); - for( asUINT i = 1; i < ot->beh.operators.GetLength(); i += 2 ) - engine->scriptFunctions[ot->beh.operators[i]]->AddRef(); - } - else if( phase == 2 ) - { - if( ot->flags & asOBJ_ENUM ) - { - int count = ReadEncodedUInt(); - bool sharedExists = existingShared.MoveTo(0, ot); - if( !sharedExists ) - { - ot->enumValues.Allocate(count, false); - for( int n = 0; n < count; n++ ) - { - asSEnumValue *e = asNEW(asSEnumValue); - if( e == 0 ) - { - // Out of memory - error = true; - return; - } - ReadString(&e->name); - ReadData(&e->value, 4); // TODO: Should be encoded - ot->enumValues.PushLast(e); - } - } - else - { - // Verify that the enum values exists in the original - asCString name; - int value; - for( int n = 0; n < count; n++ ) - { - ReadString(&name); - ReadData(&value, 4); // TODO: Should be encoded - bool found = false; - for( asUINT e = 0; e < ot->enumValues.GetLength(); e++ ) - { - if( ot->enumValues[e]->name == name && - ot->enumValues[e]->value == value ) - { - found = true; - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - } - } - } - else if( ot->flags & asOBJ_TYPEDEF ) - { - eTokenType t = (eTokenType)ReadEncodedUInt(); - ot->templateSubTypes.PushLast(asCDataType::CreatePrimitive(t, false)); - } - else - { - // If the type is shared and pre-existing, we should just - // validate that the loaded methods match the original - bool sharedExists = existingShared.MoveTo(0, ot); - if( sharedExists ) - { - asCObjectType *dt = ReadObjectType(); - if( ot->derivedFrom != dt ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - } - else - { - ot->derivedFrom = ReadObjectType(); - if( ot->derivedFrom ) - ot->derivedFrom->AddRef(); - } - - // interfaces[] / interfaceVFTOffsets[] - int size = ReadEncodedUInt(); - if( sharedExists ) - { - for( int n = 0; n < size; n++ ) - { - asCObjectType *intf = ReadObjectType(); - ReadEncodedUInt(); - - if( !ot->Implements(intf) ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - } - } - else - { - ot->interfaces.Allocate(size, false); - ot->interfaceVFTOffsets.Allocate(size, false); - for( int n = 0; n < size; n++ ) - { - asCObjectType *intf = ReadObjectType(); - ot->interfaces.PushLast(intf); - - asUINT offset = ReadEncodedUInt(); - ot->interfaceVFTOffsets.PushLast(offset); - } - } - - // behaviours - if( !ot->IsInterface() && ot->flags != asOBJ_TYPEDEF && ot->flags != asOBJ_ENUM ) - { - bool isNew; - asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); - if( sharedExists ) - { - // Find the real function in the object, and update the savedFunctions array - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.destruct); - if( (realFunc == 0 && func == 0) || realFunc->IsSignatureEqual(func) ) - { - // If the function is not the last, then the substitution has already occurred before - if( func && savedFunctions[savedFunctions.GetLength()-1] == func ) - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - } - else - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - if( func ) - { - if( isNew ) - { - // Destroy the function without releasing any references - func->id = 0; - func->scriptData->byteCode.SetLength(0); - func->Release(); - } - module->scriptFunctions.PushLast(realFunc); - realFunc->AddRef(); - dontTranslate.Insert(realFunc, true); - } - } - else - { - if( func ) - { - ot->beh.destruct = func->id; - func->AddRef(); - } - else - ot->beh.destruct = 0; - } - - size = ReadEncodedUInt(); - for( int n = 0; n < size; n++ ) - { - bool isNew; - asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); - if( func ) - { - if( sharedExists ) - { - // Find the real function in the object, and update the savedFunctions array - bool found = false; - for( asUINT n = 0; n < ot->beh.constructors.GetLength(); n++ ) - { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[n]); - if( realFunc->IsSignatureEqual(func) ) - { - // If the function is not the last, then the substitution has already occurred before - if( savedFunctions[savedFunctions.GetLength()-1] == func ) - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - found = true; - module->scriptFunctions.PushLast(realFunc); - realFunc->AddRef(); - dontTranslate.Insert(realFunc, true); - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - if( isNew ) - { - // Destroy the function without releasing any references - func->id = 0; - func->scriptData->byteCode.SetLength(0); - func->Release(); - } - } - else - { - ot->beh.constructors.PushLast(func->id); - func->AddRef(); - - if( func->parameterTypes.GetLength() == 0 ) - ot->beh.construct = func->id; - } - } - else - { - Error(TXT_INVALID_BYTECODE_d); - } - - func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); - if( func ) - { - if( sharedExists ) - { - // Find the real function in the object, and update the savedFunctions array - bool found = false; - for( asUINT n = 0; n < ot->beh.factories.GetLength(); n++ ) - { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[n]); - if( realFunc->IsSignatureEqual(func) ) - { - // If the function is not the last, then the substitution has already occurred before - if( savedFunctions[savedFunctions.GetLength()-1] == func ) - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - found = true; - module->scriptFunctions.PushLast(realFunc); - realFunc->AddRef(); - dontTranslate.Insert(realFunc, true); - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - if( isNew ) - { - // Destroy the function without releasing any references - func->id = 0; - func->scriptData->byteCode.SetLength(0); - func->Release(); - } - } - else - { - ot->beh.factories.PushLast(func->id); - func->AddRef(); - - if( func->parameterTypes.GetLength() == 0 ) - ot->beh.factory = func->id; - } - } - else - { - Error(TXT_INVALID_BYTECODE_d); - } - } - } - - // methods[] - size = ReadEncodedUInt(); - int n; - for( n = 0; n < size; n++ ) - { - bool isNew; - asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); - if( func ) - { - if( sharedExists ) - { - // Find the real function in the object, and update the savedFunctions array - bool found = false; - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[n]); - if( realFunc->IsSignatureEqual(func) ) - { - // If the function is not the last, then the substitution has already occurred before - if( savedFunctions[savedFunctions.GetLength()-1] == func ) - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - found = true; - module->scriptFunctions.PushLast(realFunc); - realFunc->AddRef(); - dontTranslate.Insert(realFunc, true); - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - if( isNew ) - { - // Destroy the function without releasing any references - func->id = 0; - if( func->scriptData ) - func->scriptData->byteCode.SetLength(0); - func->Release(); - } - } - else - { - // If the method is the assignment operator we need to replace the default implementation - if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && - func->parameterTypes[0].GetObjectType() == func->objectType && - (func->inOutFlags[0] & asTM_INREF) ) - { - engine->scriptFunctions[ot->beh.copy]->Release(); - ot->beh.copy = func->id; - func->AddRef(); - } - - ot->methods.PushLast(func->id); - func->AddRef(); - } - } - else - { - Error(TXT_INVALID_BYTECODE_d); - } - } - - // virtualFunctionTable[] - size = ReadEncodedUInt(); - for( n = 0; n < size; n++ ) - { - bool isNew; - asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); - if( func ) - { - if( sharedExists ) - { - // Find the real function in the object, and update the savedFunctions array - bool found = false; - for( asUINT n = 0; n < ot->virtualFunctionTable.GetLength(); n++ ) - { - asCScriptFunction *realFunc = ot->virtualFunctionTable[n]; - if( realFunc->IsSignatureEqual(func) ) - { - // If the function is not the last, then the substitution has already occurred before - if( savedFunctions[savedFunctions.GetLength()-1] == func ) - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - found = true; - module->scriptFunctions.PushLast(realFunc); - realFunc->AddRef(); - dontTranslate.Insert(realFunc, true); - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - if( isNew ) - { - // Destroy the function without releasing any references - func->id = 0; - if( func->scriptData ) - func->scriptData->byteCode.SetLength(0); - func->Release(); - } - } - else - { - ot->virtualFunctionTable.PushLast(func); - func->AddRef(); - } - } - else - { - Error(TXT_INVALID_BYTECODE_d); - } - } - } - } - else if( phase == 3 ) - { - // properties[] - asUINT size = ReadEncodedUInt(); - for( asUINT n = 0; n < size; n++ ) - ReadObjectProperty(ot); - } -} - -asWORD asCReader::ReadEncodedUInt16() -{ - asDWORD dw = ReadEncodedUInt(); - if( (dw>>16) != 0 && (dw>>16) != 0xFFFF ) - { - Error(TXT_INVALID_BYTECODE_d); - } - - return asWORD(dw & 0xFFFF); -} - -asUINT asCReader::ReadEncodedUInt() -{ - asQWORD qw = ReadEncodedUInt64(); - if( (qw>>32) != 0 && (qw>>32) != 0xFFFFFFFF ) - { - Error(TXT_INVALID_BYTECODE_d); - } - - return asUINT(qw & 0xFFFFFFFFu); -} - -asQWORD asCReader::ReadEncodedUInt64() -{ - asQWORD i = 0; - asBYTE b; - ReadData(&b, 1); - bool isNegative = ( b & 0x80 ) ? true : false; - b &= 0x7F; - - if( (b & 0x7F) == 0x7F ) - { - ReadData(&b, 1); i = asQWORD(b) << 56; - ReadData(&b, 1); i += asQWORD(b) << 48; - ReadData(&b, 1); i += asQWORD(b) << 40; - ReadData(&b, 1); i += asQWORD(b) << 32; - ReadData(&b, 1); i += asUINT(b) << 24; - ReadData(&b, 1); i += asUINT(b) << 16; - ReadData(&b, 1); i += asUINT(b) << 8; - ReadData(&b, 1); i += b; - } - else if( (b & 0x7E) == 0x7E ) - { - i = asQWORD(b & 0x01) << 48; - ReadData(&b, 1); i += asQWORD(b) << 40; - ReadData(&b, 1); i += asQWORD(b) << 32; - ReadData(&b, 1); i += asUINT(b) << 24; - ReadData(&b, 1); i += asUINT(b) << 16; - ReadData(&b, 1); i += asUINT(b) << 8; - ReadData(&b, 1); i += b; - } - else if( (b & 0x7C) == 0x7C ) - { - i = asQWORD(b & 0x03) << 40; - ReadData(&b, 1); i += asQWORD(b) << 32; - ReadData(&b, 1); i += asUINT(b) << 24; - ReadData(&b, 1); i += asUINT(b) << 16; - ReadData(&b, 1); i += asUINT(b) << 8; - ReadData(&b, 1); i += b; - } - else if( (b & 0x78) == 0x78 ) - { - i = asQWORD(b & 0x07) << 32; - ReadData(&b, 1); i += asUINT(b) << 24; - ReadData(&b, 1); i += asUINT(b) << 16; - ReadData(&b, 1); i += asUINT(b) << 8; - ReadData(&b, 1); i += b; - } - else if( (b & 0x70) == 0x70 ) - { - i = asUINT(b & 0x0F) << 24; - ReadData(&b, 1); i += asUINT(b) << 16; - ReadData(&b, 1); i += asUINT(b) << 8; - ReadData(&b, 1); i += b; - } - else if( (b & 0x60) == 0x60 ) - { - i = asUINT(b & 0x1F) << 16; - ReadData(&b, 1); i += asUINT(b) << 8; - ReadData(&b, 1); i += b; - } - else if( (b & 0x40) == 0x40 ) - { - i = asUINT(b & 0x3F) << 8; - ReadData(&b, 1); i += b; - } - else - { - i = b; - } - if( isNegative ) - i = (asQWORD)(-asINT64(i)); - - return i; -} - -void asCReader::ReadString(asCString* str) -{ - char b; - ReadData(&b, 1); - if( b == '\0' ) - { - str->SetLength(0); - } - else if( b == 'n' ) - { - asUINT len = ReadEncodedUInt(); - str->SetLength(len); - stream->Read(str->AddressOf(), len); - - savedStrings.PushLast(*str); - } - else - { - asUINT n = ReadEncodedUInt(); - if( n < savedStrings.GetLength() ) - *str = savedStrings[n]; - else - Error(TXT_INVALID_BYTECODE_d); - } -} - -void asCReader::ReadGlobalProperty() -{ - asCString name; - asCDataType type; - - ReadString(&name); - - asCString ns; - ReadString(&ns); - asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); - - ReadDataType(&type); - - asCGlobalProperty *prop = module->AllocateGlobalProperty(name.AddressOf(), type, nameSpace); - - // Read the initialization function - bool isNew; - // Do not add the function to the GC at this time. It will - // only be added to the GC when the module releases the property - asCScriptFunction *func = ReadFunction(isNew, false, true, false); - if( func ) - { - // Make sure the function knows it is owned by the module - func->module = module; - - prop->SetInitFunc(func); - func->Release(); - } -} - -void asCReader::ReadObjectProperty(asCObjectType *ot) -{ - asCString name; - ReadString(&name); - asCDataType dt; - ReadDataType(&dt); - bool isPrivate; - ReadData(&isPrivate, 1); - - // TODO: shared: If the type is shared and pre-existing, we should just - // validate that the loaded methods match the original - if( !existingShared.MoveTo(0, ot) ) - ot->AddPropertyToClass(name, dt, isPrivate); -} - -void asCReader::ReadDataType(asCDataType *dt) -{ - // Check if this is a previously used type - asUINT n = ReadEncodedUInt(); - if( n != 0 ) - { - // Get the datatype from the cache - *dt = savedDataTypes[n-1]; - return; - } - - // Read the type definition - eTokenType tokenType = (eTokenType)ReadEncodedUInt(); - - // Reserve a spot in the savedDataTypes - size_t saveSlot = savedDataTypes.GetLength(); - savedDataTypes.PushLast(asCDataType()); - - // Read the datatype for the first time - asCObjectType *objType = 0; - if( tokenType == ttIdentifier ) - objType = ReadObjectType(); - - struct - { - char isObjectHandle :1; - char isHandleToConst:1; - char isReference :1; - char isReadOnly :1; - } bits = {0}; - asASSERT( sizeof(bits) == 1 ); - ReadData(&bits, 1); - - asCScriptFunction *funcDef = 0; - if( tokenType == ttIdentifier && objType && objType->name == "_builtin_function_" ) - { - asCScriptFunction func(engine, module, asFUNC_DUMMY); - ReadFunctionSignature(&func); - if( error ) return; - for( asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++ ) - { - // TODO: access: Only return the definitions that the module has access to - if( engine->registeredFuncDefs[n]->name == func.name && - engine->registeredFuncDefs[n]->nameSpace == func.nameSpace ) - { - funcDef = engine->registeredFuncDefs[n]; - break; - } - } - - if( !funcDef && module ) - { - for( asUINT n = 0; n < module->funcDefs.GetLength(); n++ ) - { - if( module->funcDefs[n]->name == func.name && - module->funcDefs[n]->nameSpace == func.nameSpace ) - { - funcDef = module->funcDefs[n]; - break; - } - } - } - - // Set to dummy to avoid unwanted release of resources - func.funcType = asFUNC_DUMMY; - } - - if( funcDef ) - *dt = asCDataType::CreateFuncDef(funcDef); - else if( tokenType == ttIdentifier ) - *dt = asCDataType::CreateObject(objType, false); - else - *dt = asCDataType::CreatePrimitive(tokenType, false); - if( bits.isObjectHandle ) - { - dt->MakeReadOnly(bits.isHandleToConst ? true : false); - - // Here we must allow a scoped type to be a handle - // e.g. if the datatype is for a system function - dt->MakeHandle(true, true); - } - dt->MakeReadOnly(bits.isReadOnly ? true : false); - dt->MakeReference(bits.isReference ? true : false); - - // Update the previously saved slot - savedDataTypes[saveSlot] = *dt; -} - -asCObjectType* asCReader::ReadObjectType() -{ - asCObjectType *ot = 0; - char ch; - ReadData(&ch, 1); - if( ch == 'a' ) - { - // Read the name of the template type - asCString typeName, ns; - ReadString(&typeName); - ReadString(&ns); - asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); - - asCObjectType *tmpl = engine->GetRegisteredObjectType(typeName.AddressOf(), nameSpace); - if( tmpl == 0 ) - { - asCString str; - str.Format(TXT_TEMPLATE_TYPE_s_DOESNT_EXIST, typeName.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - asUINT numSubTypes = ReadEncodedUInt(); - asCArray subTypes; - for( asUINT n = 0; n < numSubTypes; n++ ) - { - ReadData(&ch, 1); - if( ch == 's' ) - { - asCDataType dt; - ReadDataType(&dt); - subTypes.PushLast(dt); - } - else - { - eTokenType tokenType = (eTokenType)ReadEncodedUInt(); - asCDataType dt = asCDataType::CreatePrimitive(tokenType, false); - subTypes.PushLast(dt); - } - } - - // Return the actual template if the subtypes are the template's dummy types - if( tmpl->templateSubTypes == subTypes ) - ot = tmpl; - else - { - // Get the template instance type based on the loaded subtypes - ot = engine->GetTemplateInstanceType(tmpl, subTypes); - } - - if( ot == 0 ) - { - // Show all subtypes in error message - asCString sub = subTypes[0].Format(); - for( asUINT n = 1; n < subTypes.GetLength(); n++ ) - { - sub += ","; - sub += subTypes[n].Format(); - } - asCString str; - str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, typeName.AddressOf(), sub.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - } - else if( ch == 'l' ) - { - asCObjectType *st = ReadObjectType(); - if( st == 0 || st->beh.listFactory == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - ot = engine->GetListPatternType(st->beh.listFactory); - } - else if( ch == 's' ) - { - // Read the name of the template subtype - asCString typeName; - ReadString(&typeName); - - // Find the template subtype - ot = 0; - for( asUINT n = 0; n < engine->templateSubTypes.GetLength(); n++ ) - { - if( engine->templateSubTypes[n] && engine->templateSubTypes[n]->name == typeName ) - { - ot = engine->templateSubTypes[n]; - break; - } - } - - if( ot == 0 ) - { - asCString str; - str.Format(TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST, typeName.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - } - else if( ch == 'o' ) - { - // Read the object type name - asCString typeName, ns; - ReadString(&typeName); - ReadString(&ns); - asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); - - if( typeName.GetLength() && typeName != "_builtin_object_" && typeName != "_builtin_function_" ) - { - // Find the object type - ot = module->GetObjectType(typeName.AddressOf(), nameSpace); - if( !ot ) - ot = engine->GetRegisteredObjectType(typeName.AddressOf(), nameSpace); - - if( ot == 0 ) - { - asCString str; - str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - } - else if( typeName == "_builtin_object_" ) - { - ot = &engine->scriptTypeBehaviours; - } - else if( typeName == "_builtin_function_" ) - { - ot = &engine->functionBehaviours; - } - else - asASSERT( false ); - } - else - { - // No object type - asASSERT( ch == '\0' || error ); - ot = 0; - } - - return ot; -} - -void asCReader::ReadByteCode(asCScriptFunction *func) -{ - asASSERT( func->scriptData ); - - // Read number of instructions - asUINT total, numInstructions; - total = numInstructions = ReadEncodedUInt(); - - // Reserve some space for the instructions - func->scriptData->byteCode.AllocateNoConstruct(numInstructions, false); - - asUINT pos = 0; - while( numInstructions ) - { - asBYTE b; - ReadData(&b, 1); - - // Allocate the space for the instruction - asUINT len = asBCTypeSize[asBCInfo[b].type]; - asUINT newSize = asUINT(func->scriptData->byteCode.GetLength()) + len; - if( func->scriptData->byteCode.GetCapacity() < newSize ) - { - // Determine the average size of the loaded instructions and re-estimate the final size - asUINT size = asUINT(float(newSize) / (total - numInstructions) * total) + 1; - func->scriptData->byteCode.AllocateNoConstruct(size, true); - } - if( !func->scriptData->byteCode.SetLengthNoConstruct(newSize) ) - { - // Out of memory - error = true; - return; - } - - asDWORD *bc = func->scriptData->byteCode.AddressOf() + pos; - pos += len; - - switch( asBCInfo[b].type ) - { - case asBCTYPE_NO_ARG: - { - *(asBYTE*)(bc) = b; - bc++; - } - break; - case asBCTYPE_W_ARG: - case asBCTYPE_wW_ARG: - case asBCTYPE_rW_ARG: - { - *(asBYTE*)(bc) = b; - - // Read the argument - asWORD w = ReadEncodedUInt16(); - *(((asWORD*)bc)+1) = w; - - bc++; - } - break; - case asBCTYPE_rW_DW_ARG: - case asBCTYPE_wW_DW_ARG: - case asBCTYPE_W_DW_ARG: - { - *(asBYTE*)(bc) = b; - - // Read the word argument - asWORD w = ReadEncodedUInt16(); - *(((asWORD*)bc)+1) = w; - bc++; - - // Read the dword argument - *bc++ = ReadEncodedUInt(); - } - break; - case asBCTYPE_DW_ARG: - { - *(asBYTE*)(bc) = b; - bc++; - - // Read the argument - *bc++ = ReadEncodedUInt(); - } - break; - case asBCTYPE_DW_DW_ARG: - { - *(asBYTE*)(bc) = b; - bc++; - - // Read the first argument - *bc++ = ReadEncodedUInt(); - - // Read the second argument - *bc++ = ReadEncodedUInt(); - } - break; - case asBCTYPE_wW_rW_rW_ARG: - { - *(asBYTE*)(bc) = b; - - // Read the first argument - asWORD w = ReadEncodedUInt16(); - *(((asWORD*)bc)+1) = w; - bc++; - - // Read the second argument - w = ReadEncodedUInt16(); - *(asWORD*)bc = w; - - // Read the third argument - w = ReadEncodedUInt16(); - *(((asWORD*)bc)+1) = w; - - bc++; - } - break; - case asBCTYPE_wW_rW_ARG: - case asBCTYPE_rW_rW_ARG: - case asBCTYPE_wW_W_ARG: - { - *(asBYTE*)(bc) = b; - - // Read the first argument - asWORD w = ReadEncodedUInt16(); - *(((asWORD*)bc)+1) = w; - bc++; - - // Read the second argument - w = ReadEncodedUInt16(); - *(asWORD*)bc = w; - - bc++; - } - break; - case asBCTYPE_wW_rW_DW_ARG: - case asBCTYPE_rW_W_DW_ARG: - { - *(asBYTE*)(bc) = b; - - // Read the first argument - asWORD w = ReadEncodedUInt16(); - *(((asWORD*)bc)+1) = w; - bc++; - - // Read the second argument - w = ReadEncodedUInt16(); - *(asWORD*)bc = w; - bc++; - - // Read the third argument - asDWORD dw = ReadEncodedUInt(); - *bc++ = dw; - } - break; - case asBCTYPE_QW_ARG: - { - *(asBYTE*)(bc) = b; - bc++; - - // Read the argument - asQWORD qw = ReadEncodedUInt64(); - *(asQWORD*)bc = qw; - bc += 2; - } - break; - case asBCTYPE_QW_DW_ARG: - { - *(asBYTE*)(bc) = b; - bc++; - - // Read the first argument - asQWORD qw = ReadEncodedUInt64(); - *(asQWORD*)bc = qw; - bc += 2; - - // Read the second argument - asDWORD dw = ReadEncodedUInt(); - *bc++ = dw; - } - break; - case asBCTYPE_rW_QW_ARG: - case asBCTYPE_wW_QW_ARG: - { - *(asBYTE*)(bc) = b; - - // Read the first argument - asWORD w = ReadEncodedUInt16(); - *(((asWORD*)bc)+1) = w; - bc++; - - // Read the argument - asQWORD qw = ReadEncodedUInt64(); - *(asQWORD*)bc = qw; - bc += 2; - } - break; - case asBCTYPE_rW_DW_DW_ARG: - { - *(asBYTE*)(bc) = b; - - // Read the 1st argument - asWORD w = ReadEncodedUInt16(); - *(((asWORD*)bc)+1) = w; - bc++; - - // Read the 2nd argument - *bc++ = ReadEncodedUInt(); - - // Read the 3rd argument - *bc++ = ReadEncodedUInt(); - } - break; - default: - { - // This should never happen - asASSERT(false); - - // Read the next 3 bytes - asDWORD c; asBYTE t; -#if defined(AS_BIG_ENDIAN) - c = b << 24; - ReadData(&t, 1); c += t << 16; - ReadData(&t, 1); c += t << 8; - ReadData(&t, 1); c += t; -#else - c = b; - ReadData(&t, 1); c += t << 8; - ReadData(&t, 1); c += t << 16; - ReadData(&t, 1); c += t << 24; -#endif - - *bc++ = c; - c = *(asBYTE*)&c; - - // Read the bc as is - for( int n = 1; n < asBCTypeSize[asBCInfo[c].type]; n++ ) - ReadData(&*bc++, 4); - } - } - - numInstructions--; - } - - // Correct the final size in case we over-estimated it - func->scriptData->byteCode.SetLengthNoConstruct(pos); -} - -void asCReader::ReadUsedTypeIds() -{ - asUINT count = ReadEncodedUInt(); - usedTypeIds.Allocate(count, false); - for( asUINT n = 0; n < count; n++ ) - { - asCDataType dt; - ReadDataType(&dt); - usedTypeIds.PushLast(engine->GetTypeIdFromDataType(dt)); - } -} - -void asCReader::ReadUsedGlobalProps() -{ - int c = ReadEncodedUInt(); - - usedGlobalProperties.Allocate(c, false); - - for( int n = 0; n < c; n++ ) - { - asCString name, ns; - asCDataType type; - char moduleProp; - - ReadString(&name); - ReadString(&ns); - ReadDataType(&type); - ReadData(&moduleProp, 1); - - asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); - - // Find the real property - asCGlobalProperty *globProp = 0; - if( moduleProp ) - globProp = module->scriptGlobals.GetFirst(nameSpace, name); - else - globProp = engine->registeredGlobalProps.GetFirst(nameSpace, name); - - void *prop = 0; - if( globProp && globProp->type == type ) - prop = globProp->GetAddressOfValue(); - - usedGlobalProperties.PushLast(prop); - - if( prop == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - } - } -} - -void asCReader::ReadUsedObjectProps() -{ - asUINT c = ReadEncodedUInt(); - - usedObjectProperties.SetLength(c); - for( asUINT n = 0; n < c; n++ ) - { - asCObjectType *objType = ReadObjectType(); - if( objType == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - break; - } - - asCString name; - ReadString(&name); - - // Find the property offset - bool found = false; - for( asUINT p = 0; p < objType->properties.GetLength(); p++ ) - { - if( objType->properties[p]->name == name ) - { - usedObjectProperties[n].objType = objType; - usedObjectProperties[n].offset = objType->properties[p]->byteOffset; - found = true; - break; - } - } - - if( !found ) - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } -} - -short asCReader::FindObjectPropOffset(asWORD index) -{ - if( index >= usedObjectProperties.GetLength() ) - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - return (short)usedObjectProperties[index].offset; -} - -asCScriptFunction *asCReader::FindFunction(int idx) -{ - if( idx >= 0 && idx < (int)usedFunctions.GetLength() ) - return usedFunctions[idx]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } -} - -void asCReader::TranslateFunction(asCScriptFunction *func) -{ - // Skip this if the function is part of an pre-existing shared object - if( dontTranslate.MoveTo(0, func) ) return; - - asASSERT( func->scriptData ); - - // Pre-compute the size of each instruction in order to translate jump offsets - asUINT n; - asDWORD *bc = func->scriptData->byteCode.AddressOf(); - asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength(); - asCArray bcSizes(bcLength); - asCArray instructionNbrToPos(bcLength); - for( n = 0; n < bcLength; ) - { - int c = *(asBYTE*)&bc[n]; - asUINT size = asBCTypeSize[asBCInfo[c].type]; - if( size == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - bcSizes.PushLast(size); - instructionNbrToPos.PushLast(n); - n += size; - } - - asUINT bcNum = 0; - for( n = 0; n < bcLength; bcNum++ ) - { - int c = *(asBYTE*)&bc[n]; - if( c == asBC_REFCPY || - c == asBC_RefCpyV || - c == asBC_OBJTYPE ) - { - // Translate the index to the true object type - asPWORD *ot = (asPWORD*)&bc[n+1]; - *(asCObjectType**)ot = FindObjectType(*(int*)ot); - } - else if( c == asBC_TYPEID || - c == asBC_Cast ) - { - // Translate the index to the type id - int *tid = (int*)&bc[n+1]; - *tid = FindTypeId(*tid); - } - else if( c == asBC_ADDSi || - c == asBC_LoadThisR ) - { - // Translate the index to the type id - int *tid = (int*)&bc[n+1]; - *tid = FindTypeId(*tid); - - // Translate the prop index into the property offset - *(((short*)&bc[n])+1) = FindObjectPropOffset(*(((short*)&bc[n])+1)); - } - else if( c == asBC_LoadRObjR || - c == asBC_LoadVObjR ) - { - // Translate the index to the type id - int *tid = (int*)&bc[n+2]; - *tid = FindTypeId(*tid); - - asCObjectType *ot = engine->GetObjectTypeFromTypeId(*tid); - if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) - { - // List patterns have a different way of adjusting the offsets - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - *(((short*)&bc[n])+2) = (short)listAdj->AdjustOffset(*(((short*)&bc[n])+2)); - } - else - { - // Translate the prop index into the property offset - *(((short*)&bc[n])+2) = FindObjectPropOffset(*(((short*)&bc[n])+2)); - } - } - else if( c == asBC_COPY ) - { - // Translate the index to the type id - int *tid = (int*)&bc[n+1]; - *tid = FindTypeId(*tid); - - // COPY is used to copy POD types that don't have the opAssign method. It is - // also used to copy references to scoped types during variable initializations. - // Update the number of dwords to copy as it may be different on the target platform - if( (*tid) & asTYPEID_OBJHANDLE ) - { - // It is the actual reference that is being copied, not the object itself - asBC_SWORDARG0(&bc[n]) = AS_PTR_SIZE; - } - else - { - asCDataType dt = engine->GetDataTypeFromTypeId(*tid); - if( !dt.IsValid() ) - { - Error(TXT_INVALID_BYTECODE_d); - } - else - asBC_SWORDARG0(&bc[n]) = (short)dt.GetSizeInMemoryDWords(); - } - } - else if( c == asBC_RET ) - { - // Determine the correct amount of DWORDs to pop - asWORD dw = (asWORD)func->GetSpaceNeededForArguments(); - if( func->DoesReturnOnStack() ) dw += AS_PTR_SIZE; - if( func->objectType ) dw += AS_PTR_SIZE; - asBC_WORDARG0(&bc[n]) = dw; - } - else if( c == asBC_CALL || - c == asBC_CALLINTF || - c == asBC_CALLSYS ) - { - // Translate the index to the func id - int *fid = (int*)&bc[n+1]; - asCScriptFunction *f = FindFunction(*fid); - if( f ) - *fid = f->id; - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - else if( c == asBC_FuncPtr ) - { - // Translate the index to the func pointer - asPWORD *fid = (asPWORD*)&bc[n+1]; - *fid = (asPWORD)FindFunction((int)*fid); - } - else if( c == asBC_ALLOC ) - { - // Translate the index to the true object type - asPWORD *arg = (asPWORD*)&bc[n+1]; - *(asCObjectType**)arg = FindObjectType(*(int*)arg); - - // The constructor function id must be translated, unless it is zero - int *fid = (int*)&bc[n+1+AS_PTR_SIZE]; - if( *fid != 0 ) - { - // Subtract 1 from the id, as it was incremented during the writing - asCScriptFunction *f = FindFunction(*fid-1); - if( f ) - *fid = f->id; - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - } - else if( c == asBC_STR ) - { - // Translate the index to the true string id - asWORD *arg = ((asWORD*)&bc[n])+1; - - if( *arg < usedStringConstants.GetLength() ) - *arg = (asWORD)usedStringConstants[*arg]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - else if( c == asBC_CALLBND ) - { - // Translate the function id - asUINT *fid = (asUINT*)&bc[n+1]; - if( *fid < module->bindInformations.GetLength() ) - { - sBindInfo *bi = module->bindInformations[*fid]; - if( bi ) - *fid = bi->importedFunctionSignature->id; - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - else if( c == asBC_PGA || - c == asBC_PshGPtr || - c == asBC_LDG || - c == asBC_PshG4 || - c == asBC_LdGRdR4 || - c == asBC_CpyGtoV4 || - c == asBC_CpyVtoG4 || - c == asBC_SetG4 ) - { - // Translate the global var index to pointer - asPWORD *index = (asPWORD*)&bc[n+1]; - if( *(asUINT*)index < usedGlobalProperties.GetLength() ) - *(void**)index = usedGlobalProperties[*(asUINT*)index]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - else if( c == asBC_JMP || - c == asBC_JZ || - c == asBC_JNZ || - c == asBC_JLowZ || - c == asBC_JLowNZ || - c == asBC_JS || - c == asBC_JNS || - c == asBC_JP || - c == asBC_JNP ) // The JMPP instruction doesn't need modification - { - // Get the offset - int offset = int(bc[n+1]); - - // Count the instruction sizes to the destination instruction - int size = 0; - if( offset >= 0 ) - // If moving ahead, then start from next instruction - for( asUINT num = bcNum+1; offset-- > 0; num++ ) - size += bcSizes[num]; - else - // If moving backwards, then start at current instruction - for( asUINT num = bcNum; offset++ < 0; num-- ) - size -= bcSizes[num]; - - // The size is dword offset - bc[n+1] = size; - } - else if( c == asBC_AllocMem ) - { - // The size of the allocated memory is only known after all the elements has been seen. - // This helper class will collect this information and adjust the size when the - // corresponding asBC_FREE is encountered - - // The adjuster also needs to know the list type so it can know the type of the elements - asCObjectType *ot = func->GetObjectTypeOfLocalVar(asBC_SWORDARG0(&bc[n])); - listAdjusters.PushLast(asNEW(SListAdjuster)(this, &bc[n], ot)); - } - else if( c == asBC_FREE ) - { - // Translate the index to the true object type - asPWORD *pot = (asPWORD*)&bc[n+1]; - *(asCObjectType**)pot = FindObjectType(*(int*)pot); - - asCObjectType *ot = *(asCObjectType**)pot; - if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) - { - if( listAdjusters.GetLength() == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - - // Finalize the adjustment of the list buffer that was initiated with asBC_AllocMem - SListAdjuster *list = listAdjusters.PopLast(); - list->AdjustAllocMem(); - asDELETE(list, SListAdjuster); - } - } - else if( c == asBC_SetListSize ) - { - // Adjust the offset in the list where the size is informed - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - bc[n+1] = listAdj->AdjustOffset(bc[n+1]); - - // Inform the list adjuster how many values will be repeated - listAdj->SetRepeatCount(bc[n+2]); - } - else if( c == asBC_PshListElmnt ) - { - // Adjust the offset in the list where the size is informed - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - bc[n+1] = listAdj->AdjustOffset(bc[n+1]); - } - else if( c == asBC_SetListType ) - { - // Adjust the offset in the list where the typeid is informed - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - bc[n+1] = listAdj->AdjustOffset(bc[n+1]); - - // Translate the type id - bc[n+2] = FindTypeId(bc[n+2]); - - // Inform the list adjuster the type id of the next element - listAdj->SetNextType(bc[n+2]); - } - - n += asBCTypeSize[asBCInfo[c].type]; - } - - // Calculate the stack adjustments - CalculateAdjustmentByPos(func); - - // Adjust all variable positions in the bytecode - bc = func->scriptData->byteCode.AddressOf(); - for( n = 0; n < bcLength; ) - { - int c = *(asBYTE*)&bc[n]; - switch( asBCInfo[c].type ) - { - case asBCTYPE_wW_ARG: - case asBCTYPE_rW_DW_ARG: - case asBCTYPE_wW_QW_ARG: - case asBCTYPE_rW_ARG: - case asBCTYPE_wW_DW_ARG: - case asBCTYPE_wW_W_ARG: - case asBCTYPE_rW_QW_ARG: - case asBCTYPE_rW_W_DW_ARG: - case asBCTYPE_rW_DW_DW_ARG: - { - asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n])); - } - break; - - case asBCTYPE_wW_rW_ARG: - case asBCTYPE_wW_rW_DW_ARG: - case asBCTYPE_rW_rW_ARG: - { - asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n])); - asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n])); - } - break; - - case asBCTYPE_wW_rW_rW_ARG: - { - asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n])); - asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n])); - asBC_SWORDARG2(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG2(&bc[n])); - } - break; - - default: - // The other types don't treat variables so won't be modified - break; - } - - n += asBCTypeSize[asBCInfo[c].type]; - } - - // Adjust the space needed for local variables - func->scriptData->variableSpace = AdjustStackPosition(func->scriptData->variableSpace); - - // Adjust the variable information. This will be used during the adjustment below - for( n = 0; n < func->scriptData->variables.GetLength(); n++ ) - { - func->scriptData->variables[n]->declaredAtProgramPos = instructionNbrToPos[func->scriptData->variables[n]->declaredAtProgramPos]; - func->scriptData->variables[n]->stackOffset = AdjustStackPosition(func->scriptData->variables[n]->stackOffset); - } - - // objVariablePos - for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ ) - { - func->scriptData->objVariablePos[n] = AdjustStackPosition(func->scriptData->objVariablePos[n]); - func->scriptData->funcVariableTypes[n] = FindFunction((int)(asPWORD)func->scriptData->funcVariableTypes[n]); - } - - // Adjust the get offsets. This must be done in the second iteration because - // it relies on the function ids and variable position already being correct in the - // bytecodes that come after the GET instructions. - // TODO: optimize: Instead of doing a full extra loop. We can push the GET instructions - // on a stack, and then when a call instruction is found update all of them. - // This will also make the AdjustGetOffset() function quicker as it can - // receive the called function directly instead of having to search for it. - bc = func->scriptData->byteCode.AddressOf(); - for( n = 0; n < bcLength; ) - { - int c = *(asBYTE*)&bc[n]; - - if( c == asBC_GETREF || - c == asBC_GETOBJ || - c == asBC_GETOBJREF ) - { - asBC_WORDARG0(&bc[n]) = (asWORD)AdjustGetOffset(asBC_WORDARG0(&bc[n]), func, n); - } - - n += asBCTypeSize[asBCInfo[c].type]; - } - - for( n = 0; n < func->scriptData->objVariableInfo.GetLength(); n++ ) - { - // The program position must be adjusted as it is stored in number of instructions - func->scriptData->objVariableInfo[n].programPos = instructionNbrToPos[func->scriptData->objVariableInfo[n].programPos]; - func->scriptData->objVariableInfo[n].variableOffset = AdjustStackPosition(func->scriptData->objVariableInfo[n].variableOffset); - } - - // The program position (every even number) needs to be adjusted - // for the line numbers to be in number of dwords instead of number of instructions - for( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 ) - func->scriptData->lineNumbers[n] = instructionNbrToPos[func->scriptData->lineNumbers[n]]; - for( n = 0; n < func->scriptData->sectionIdxs.GetLength(); n += 2 ) - func->scriptData->sectionIdxs[n] = instructionNbrToPos[func->scriptData->sectionIdxs[n]]; - - CalculateStackNeeded(func); -} - -asCReader::SListAdjuster::SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *listType) : - reader(rd), allocMemBC(bc), maxOffset(0), patternType(listType), repeatCount(0), lastOffset(-1), nextOffset(0), nextTypeId(-1) -{ - asASSERT( patternType && (patternType->flags & asOBJ_LIST_PATTERN) ); - - // Find the first expected value in the list - asSListPatternNode *node = patternType->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; - asASSERT( node && node->type == asLPT_START ); - patternNode = node->next; -} - -int asCReader::SListAdjuster::AdjustOffset(int offset) -{ - if( offset < lastOffset ) - { - reader->Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - // If it is the same offset being accessed again, just return the same adjusted value - if( lastOffset == offset ) - return lastAdjustedOffset; - - lastOffset = offset; - lastAdjustedOffset = maxOffset; - - // What is being expected at this position? - if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ) - { - // Align the offset to 4 bytes boundary - if( maxOffset & 0x3 ) - { - maxOffset += 4 - (maxOffset & 0x3); - lastAdjustedOffset = maxOffset; - } - - // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too - maxOffset += 4; - nextOffset = offset+1; - return lastAdjustedOffset; - } - else if( patternNode->type == asLPT_TYPE ) - { - const asCDataType &dt = reinterpret_cast(patternNode)->dataType; - if( dt.GetTokenType() == ttQuestion ) - { - if( nextTypeId != -1 ) - { - if( repeatCount > 0 ) - repeatCount--; - - asCDataType dt = patternType->engine->GetDataTypeFromTypeId(nextTypeId); - asUINT size; - if( dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_REF)) ) - size = AS_PTR_SIZE*4; - else - size = dt.GetSizeInMemoryBytes(); - - // Align the offset to 4 bytes boundary - if( size >= 4 && (maxOffset & 0x3) ) - { - maxOffset += 4 - (maxOffset & 0x3); - lastAdjustedOffset = maxOffset; - } - - // Only move the patternNode if we're not expecting any more repeated entries - if( repeatCount == 0 ) - patternNode = patternNode->next; - - nextTypeId = -1; - - maxOffset += size; - nextOffset = offset+1; - return lastAdjustedOffset; - } - else - { - // Align the offset to 4 bytes boundary - if( maxOffset & 0x3 ) - { - maxOffset += 4 - (maxOffset & 0x3); - lastAdjustedOffset = maxOffset; - } - - // The first adjustment is for the typeId - maxOffset += 4; - nextOffset = offset+1; - return lastAdjustedOffset; - } - } - else - { - // Determine the size of the element - asUINT size; - asCDataType dt = reinterpret_cast(patternNode)->dataType; - if( dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_REF)) ) - size = AS_PTR_SIZE*4; - else - size = dt.GetSizeInMemoryBytes(); - - // If values are skipped, the offset needs to be incremented - while( nextOffset <= offset ) - { - if( repeatCount > 0 ) - repeatCount--; - - // Align the offset to 4 bytes boundary - if( size >= 4 && (maxOffset & 0x3) ) - maxOffset += 4 - (maxOffset & 0x3); - - lastAdjustedOffset = maxOffset; - nextOffset += 1; - maxOffset += size; - } - - // Only move the patternNode if we're not expecting any more repeated entries - if( repeatCount == 0 ) - patternNode = patternNode->next; - - nextOffset = offset+1; - return lastAdjustedOffset; - } - } - else if( patternNode->type == asLPT_START ) - { - if( repeatCount > 0 ) - repeatCount--; - SInfo info = {repeatCount, patternNode}; - stack.PushLast(info); - - repeatCount = 0; - patternNode = patternNode->next; - - lastOffset--; - return AdjustOffset(offset); - } - else if( patternNode->type == asLPT_END ) - { - if( stack.GetLength() == 0 ) - { - reader->Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - SInfo info = stack.PopLast(); - repeatCount = info.repeatCount; - if( repeatCount ) - patternNode = info.startNode; - else - patternNode = patternNode->next; - - lastOffset--; - return AdjustOffset(offset); - } - else - { - // Something is wrong with the pattern list declaration - reader->Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - UNREACHABLE_RETURN; -} - -void asCReader::SListAdjuster::SetRepeatCount(asUINT rc) -{ - // Make sure the list is expecting a repeat at this location - asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ); - - // Now move to the next patternNode - patternNode = patternNode->next; - - repeatCount = rc; -} - -void asCReader::SListAdjuster::AdjustAllocMem() -{ - allocMemBC[1] = maxOffset; -} - -void asCReader::SListAdjuster::SetNextType(int typeId) -{ - asASSERT( nextTypeId == -1 ); - - nextTypeId = typeId; -} - -void asCReader::CalculateStackNeeded(asCScriptFunction *func) -{ - asASSERT( func->scriptData ); - - int largestStackUsed = 0; - - // Clear the known stack size for each bytecode - asCArray stackSize; - stackSize.SetLength(func->scriptData->byteCode.GetLength()); - memset(&stackSize[0], -1, stackSize.GetLength()*4); - - // Add the first instruction to the list of unchecked code - // paths and set the stack size at that instruction to variableSpace - asCArray paths; - paths.PushLast(0); - stackSize[0] = func->scriptData->variableSpace; - - // Go through each of the code paths - for( asUINT p = 0; p < paths.GetLength(); ++p ) - { - asUINT pos = paths[p]; - int currStackSize = stackSize[pos]; - - asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[pos]; - if( bc == asBC_RET ) - continue; - - // Determine the change in stack size for this instruction - int stackInc = asBCInfo[bc].stackInc; - if( stackInc == 0xFFFF ) - { - // Determine the true delta from the instruction arguments - if( bc == asBC_CALL || - bc == asBC_CALLSYS || - bc == asBC_CALLBND || - bc == asBC_ALLOC || - bc == asBC_CALLINTF || - bc == asBC_CallPtr ) - { - asCScriptFunction *called = GetCalledFunction(func, pos); - if( called ) - { - stackInc = -called->GetSpaceNeededForArguments(); - if( called->objectType ) - stackInc -= AS_PTR_SIZE; - if( called->DoesReturnOnStack() ) - stackInc -= AS_PTR_SIZE; - } - else - { - // It is an allocation for an object without a constructor - asASSERT( bc == asBC_ALLOC ); - stackInc = -AS_PTR_SIZE; - } - } - } - - currStackSize += stackInc; - asASSERT( currStackSize >= 0 ); - - if( currStackSize > largestStackUsed ) - largestStackUsed = currStackSize; - - if( bc == asBC_JMP ) - { - // Find the label that we should jump to - int offset = asBC_INTARG(&func->scriptData->byteCode[pos]); - pos += 2 + offset; - - // Add the destination as a new path - if( stackSize[pos] == -1 ) - { - stackSize[pos] = currStackSize; - paths.PushLast(pos); - } - else - asASSERT(stackSize[pos] == currStackSize); - continue; - } - else if( bc == asBC_JZ || bc == asBC_JNZ || - bc == asBC_JLowZ || bc == asBC_JLowNZ || - bc == asBC_JS || bc == asBC_JNS || - bc == asBC_JP || bc == asBC_JNP ) - { - // Find the label that is being jumped to - int offset = asBC_INTARG(&func->scriptData->byteCode[pos]); - - // Add both paths to the code paths - pos += 2; - if( stackSize[pos] == -1 ) - { - stackSize[pos] = currStackSize; - paths.PushLast(pos); - } - else - asASSERT(stackSize[pos] == currStackSize); - - pos += offset; - if( stackSize[pos] == -1 ) - { - stackSize[pos] = currStackSize; - paths.PushLast(pos); - } - else - asASSERT(stackSize[pos] == currStackSize); - - continue; - } - else if( bc == asBC_JMPP ) - { - pos++; - - // Add all subsequent JMP instructions to the path - while( *(asBYTE*)&func->scriptData->byteCode[pos] == asBC_JMP ) - { - if( stackSize[pos] == -1 ) - { - stackSize[pos] = currStackSize; - paths.PushLast(pos); - } - else - asASSERT(stackSize[pos] == currStackSize); - pos += 2; - } - continue; - } - else - { - // Add next instruction to the paths - pos += asBCTypeSize[asBCInfo[bc].type]; - if( stackSize[pos] == -1 ) - { - stackSize[pos] = currStackSize; - paths.PushLast(pos); - } - else - asASSERT(stackSize[pos] == currStackSize); - - continue; - } - } - - func->scriptData->stackNeeded = largestStackUsed; -} - -void asCReader::CalculateAdjustmentByPos(asCScriptFunction *func) -{ - // Adjust the offset of all negative variables (parameters) as - // all pointers have been stored as having a size of 1 dword - asUINT n; - asCArray adjustments; - asUINT offset = 0; - if( func->objectType ) - { - adjustments.PushLast(offset); - adjustments.PushLast(1-AS_PTR_SIZE); - offset += 1; - } - if( func->DoesReturnOnStack() ) - { - adjustments.PushLast(offset); - adjustments.PushLast(1-AS_PTR_SIZE); - offset += 1; - } - for( n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( !func->parameterTypes[n].IsPrimitive() || - func->parameterTypes[n].IsReference() ) - { - adjustments.PushLast(offset); - adjustments.PushLast(1-AS_PTR_SIZE); - offset += 1; - } - else - { - asASSERT( func->parameterTypes[n].IsPrimitive() ); - offset += func->parameterTypes[n].GetSizeOnStackDWords(); - } - } - - // Build look-up table with the adjustments for each stack position - adjustNegativeStackByPos.SetLength(offset); - memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int)); - for( n = 0; n < adjustments.GetLength(); n+=2 ) - { - int pos = adjustments[n]; - int adjust = adjustments[n+1]; - - for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ ) - adjustNegativeStackByPos[i] += adjust; - } - - // The bytecode has been stored as if all object variables take up only 1 dword. - // It is necessary to adjust to the size according to the current platform. - adjustments.SetLength(0); - int highestPos = 0; - for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ ) - { - if( func->scriptData->objVariableTypes[n] ) - { - // Determine the size the variable currently occupies on the stack - int size = AS_PTR_SIZE; - if( (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && - n >= func->scriptData->objVariablesOnHeap ) - { - size = func->scriptData->objVariableTypes[n]->GetSize(); - if( size < 4 ) - size = 1; - else - size /= 4; - } - - // Check if type has a different size than stored - if( size > 1 ) - { - if( func->scriptData->objVariablePos[n] > highestPos ) - highestPos = func->scriptData->objVariablePos[n]; - - adjustments.PushLast(func->scriptData->objVariablePos[n]); - adjustments.PushLast(size-1); - } - } - } - - // Count position 0 too - adjustByPos.SetLength(highestPos+1); - memset(adjustByPos.AddressOf(), 0, adjustByPos.GetLength()*sizeof(int)); - - // Build look-up table with the adjustments for each stack position - for( n = 0; n < adjustments.GetLength(); n+=2 ) - { - int pos = adjustments[n]; - int adjust = adjustments[n+1]; - - for( asUINT i = pos; i < adjustByPos.GetLength(); i++ ) - adjustByPos[i] += adjust; - } -} - -int asCReader::AdjustStackPosition(int pos) -{ - if( pos >= (int)adjustByPos.GetLength() ) - { - // It can be higher for primitives allocated on top of highest object variable - if( adjustByPos.GetLength() ) - pos += (short)adjustByPos[adjustByPos.GetLength()-1]; - } - else if( pos >= 0 ) - pos += (short)adjustByPos[pos]; - else if( -pos >= (int)adjustNegativeStackByPos.GetLength() ) - Error(TXT_INVALID_BYTECODE_d); - else - pos += (short)adjustNegativeStackByPos[-pos]; - - return pos; -} - -asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD programPos) -{ - asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[programPos]; - - if( bc == asBC_CALL || - bc == asBC_CALLSYS || - bc == asBC_CALLINTF ) - { - // Find the function from the function id in bytecode - int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]); - return engine->scriptFunctions[funcId]; - } - else if( bc == asBC_ALLOC ) - { - // Find the function from the function id in the bytecode - int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos+AS_PTR_SIZE]); - return engine->scriptFunctions[funcId]; - } - else if( bc == asBC_CALLBND ) - { - // Find the function from the engine's bind array - int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]); - return engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature; - } - else if( bc == asBC_CallPtr ) - { - asUINT v; - int var = asBC_SWORDARG0(&func->scriptData->byteCode[programPos]); - - // Find the funcdef from the local variable - for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) - if( func->scriptData->objVariablePos[v] == var ) - return func->scriptData->funcVariableTypes[v]; - - // Look in parameters - int paramPos = 0; - if( func->objectType ) - paramPos -= AS_PTR_SIZE; - if( func->DoesReturnOnStack() ) - paramPos -= AS_PTR_SIZE; - for( v = 0; v < func->parameterTypes.GetLength(); v++ ) - { - if( var == paramPos ) - return func->parameterTypes[v].GetFuncDef(); - paramPos -= func->parameterTypes[v].GetSizeOnStackDWords(); - } - } - - return 0; -} - -int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos) -{ - // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime - // the function can remember where it found the function and check if the programPos is still valid - - // Get offset 0 doesn't need adjustment - if( offset == 0 ) return 0; - - // Find out which function that will be called - asCScriptFunction *calledFunc = 0; - for( asUINT n = programPos; func->scriptData->byteCode.GetLength(); ) - { - asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n]; - if( bc == asBC_CALL || - bc == asBC_CALLSYS || - bc == asBC_CALLINTF || - bc == asBC_ALLOC || - bc == asBC_CALLBND || - bc == asBC_CallPtr ) - { - calledFunc = GetCalledFunction(func, n); - break; - } - else if( bc == asBC_REFCPY || - bc == asBC_COPY ) - { - // In this case we know there is only 1 pointer on the stack above - asASSERT( offset == 1 ); - return offset - (1 - AS_PTR_SIZE); - } - - n += asBCTypeSize[asBCInfo[bc].type]; - } - - if( calledFunc == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - return offset; - } - - // Count the number of pointers pushed on the stack above the - // current offset, and then adjust the offset accordingly - asUINT numPtrs = 0; - int currOffset = 0; - if( offset > currOffset && calledFunc->GetObjectType() ) - { - numPtrs++; - currOffset++; - } - if( offset > currOffset && calledFunc->DoesReturnOnStack() ) - { - numPtrs++; - currOffset++; - } - for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ ) - { - if( offset <= currOffset ) break; - - if( !calledFunc->parameterTypes[p].IsPrimitive() || - calledFunc->parameterTypes[p].IsReference() ) - { - numPtrs++; - currOffset++; - - // The variable arg ? has an additiona 32bit integer with the typeid - if( calledFunc->parameterTypes[p].IsAnyType() ) - currOffset += 1; - } - else - { - // Enums or built-in primitives are passed by value - asASSERT( calledFunc->parameterTypes[p].IsPrimitive() ); - currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords(); - } - } - - return offset - numPtrs * (1 - AS_PTR_SIZE); -} - -int asCReader::FindTypeId(int idx) -{ - if( idx >= 0 && idx < (int)usedTypeIds.GetLength() ) - return usedTypeIds[idx]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } -} - -asCObjectType *asCReader::FindObjectType(int idx) -{ - if( idx < 0 || idx >= (int)usedTypes.GetLength() ) - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - return usedTypes[idx]; -} - -#ifndef AS_NO_COMPILER - -asCWriter::asCWriter(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine, bool _stripDebug) - : module(_module), stream(_stream), engine(_engine), stripDebugInfo(_stripDebug) -{ -} - -void asCWriter::WriteData(const void *data, asUINT size) -{ - asASSERT(size == 1 || size == 2 || size == 4 || size == 8); -#if defined(AS_BIG_ENDIAN) - for( asUINT n = 0; n < size; n++ ) - stream->Write(((asBYTE*)data)+n, 1); -#else - for( int n = size-1; n >= 0; n-- ) - stream->Write(((asBYTE*)data)+n, 1); -#endif -} - -int asCWriter::Write() -{ - unsigned long i, count; - - // Store everything in the same order that the builder parses scripts - - // TODO: Should be possible to skip saving the enum values. They are usually not needed after the script is compiled anyway - // TODO: Should be possible to skip saving the typedefs. They are usually not needed after the script is compiled anyway - // TODO: Should be possible to skip saving constants. They are usually not needed after the script is compiled anyway - WriteData(&stripDebugInfo, sizeof(stripDebugInfo)); - - // Store enums - count = (asUINT)module->enumTypes.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; i++ ) - { - WriteObjectTypeDeclaration(module->enumTypes[i], 1); - WriteObjectTypeDeclaration(module->enumTypes[i], 2); - } - - // Store type declarations first - count = (asUINT)module->classTypes.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; i++ ) - { - // Store only the name of the class/interface types - WriteObjectTypeDeclaration(module->classTypes[i], 1); - } - - // Store func defs - count = (asUINT)module->funcDefs.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; i++ ) - WriteFunction(module->funcDefs[i]); - - // Now store all interface methods - count = (asUINT)module->classTypes.GetLength(); - for( i = 0; i < count; i++ ) - { - if( module->classTypes[i]->IsInterface() ) - WriteObjectTypeDeclaration(module->classTypes[i], 2); - } - - // Then store the class methods and behaviours - for( i = 0; i < count; ++i ) - { - if( !module->classTypes[i]->IsInterface() ) - WriteObjectTypeDeclaration(module->classTypes[i], 2); - } - - // Then store the class properties - for( i = 0; i < count; ++i ) - { - if( !module->classTypes[i]->IsInterface() ) - WriteObjectTypeDeclaration(module->classTypes[i], 3); - } - - // Store typedefs - count = (asUINT)module->typeDefs.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; i++ ) - { - WriteObjectTypeDeclaration(module->typeDefs[i], 1); - WriteObjectTypeDeclaration(module->typeDefs[i], 2); - } - - // scriptGlobals[] - count = (asUINT)module->scriptGlobals.GetSize(); - WriteEncodedInt64(count); - asCSymbolTable::iterator it = module->scriptGlobals.List(); - for( ; it; it++ ) - WriteGlobalProperty(*it); - - // scriptFunctions[] - count = 0; - for( i = 0; i < module->scriptFunctions.GetLength(); i++ ) - if( module->scriptFunctions[i]->objectType == 0 ) - count++; - WriteEncodedInt64(count); - for( i = 0; i < module->scriptFunctions.GetLength(); ++i ) - if( module->scriptFunctions[i]->objectType == 0 ) - WriteFunction(module->scriptFunctions[i]); - - // globalFunctions[] - count = (int)module->globalFunctions.GetSize(); - asCSymbolTable::iterator funcIt = module->globalFunctions.List(); - WriteEncodedInt64(count); - while( funcIt ) - { - WriteFunction(*funcIt); - funcIt++; - } - - // bindInformations[] - count = (asUINT)module->bindInformations.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; ++i ) - { - WriteFunction(module->bindInformations[i]->importedFunctionSignature); - WriteString(&module->bindInformations[i]->importFromModule); - } - - // usedTypes[] - count = (asUINT)usedTypes.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; ++i ) - WriteObjectType(usedTypes[i]); - - // usedTypeIds[] - WriteUsedTypeIds(); - - // usedFunctions[] - WriteUsedFunctions(); - - // usedGlobalProperties[] - WriteUsedGlobalProps(); - - // usedStringConstants[] - WriteUsedStringConstants(); - - // usedObjectProperties[] - WriteUsedObjectProps(); - - return asSUCCESS; -} - -int asCWriter::FindStringConstantIndex(int id) -{ - asSMapNode *cursor = 0; - if (stringIdToIndexMap.MoveTo(&cursor, id)) - return cursor->value; - - usedStringConstants.PushLast(id); - int index = int(usedStringConstants.GetLength() - 1); - stringIdToIndexMap.Insert(id, index); - return index; -} - -void asCWriter::WriteUsedStringConstants() -{ - asUINT count = (asUINT)usedStringConstants.GetLength(); - WriteEncodedInt64(count); - for( asUINT i = 0; i < count; ++i ) - WriteString(engine->stringConstants[usedStringConstants[i]]); -} - -void asCWriter::WriteUsedFunctions() -{ - asUINT count = (asUINT)usedFunctions.GetLength(); - WriteEncodedInt64(count); - - for( asUINT n = 0; n < usedFunctions.GetLength(); n++ ) - { - char c; - - // Write enough data to be able to uniquely identify the function upon load - - if( usedFunctions[n] ) - { - // Is the function from the module or the application? - c = usedFunctions[n]->module ? 'm' : 'a'; - WriteData(&c, 1); - WriteFunctionSignature(usedFunctions[n]); - } - else - { - // null function pointer - c = 'n'; - WriteData(&c, 1); - } - } -} - -void asCWriter::WriteFunctionSignature(asCScriptFunction *func) -{ - asUINT i, count; - - WriteString(&func->name); - if( func->name == DELEGATE_FACTORY ) - { - // It's not necessary to write anything else - return; - } - - WriteDataType(&func->returnType); - - count = (asUINT)func->parameterTypes.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; ++i ) - WriteDataType(&func->parameterTypes[i]); - - // Only write the inout flags if any of them are set - count = 0; - for( i = asUINT(func->inOutFlags.GetLength()); i > 0; i-- ) - if( func->inOutFlags[i-1] != asTM_NONE ) - { - count = i; - break; - } - WriteEncodedInt64(count); - for( i = 0; i < count; ++i ) - WriteEncodedInt64(func->inOutFlags[i]); - - WriteEncodedInt64(func->funcType); - - // Write the default args, from last to first - count = 0; - for( i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; ) - if( func->defaultArgs[i] ) - count++; - WriteEncodedInt64(count); - for( i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; ) - if( func->defaultArgs[i] ) - WriteString(func->defaultArgs[i]); - - WriteObjectType(func->objectType); - - if( func->objectType ) - { - asBYTE b = 0; - b += func->isReadOnly ? 1 : 0; - b += func->isPrivate ? 2 : 0; - WriteData(&b, 1); - } - else - { - WriteString(&func->nameSpace->name); - } -} - -void asCWriter::WriteFunction(asCScriptFunction* func) -{ - char c; - - // If there is no function, then store a null char - if( func == 0 ) - { - c = '\0'; - WriteData(&c, 1); - return; - } - - // First check if the function has been saved already - for( asUINT f = 0; f < savedFunctions.GetLength(); f++ ) - { - if( savedFunctions[f] == func ) - { - c = 'r'; - WriteData(&c, 1); - WriteEncodedInt64(f); - return; - } - } - - // Keep a reference to the function in the list - savedFunctions.PushLast(func); - - c = 'f'; - WriteData(&c, 1); - - asUINT i, count; - - WriteFunctionSignature(func); - - if( func->funcType == asFUNC_SCRIPT ) - { - // Calculate the adjustment by position lookup table - CalculateAdjustmentByPos(func); - - WriteByteCode(func); - - asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace); - WriteEncodedInt64(varSpace); - - count = (asUINT)func->scriptData->objVariablePos.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; ++i ) - { - WriteObjectType(func->scriptData->objVariableTypes[i]); - // TODO: Only write this if the object type is the builtin function type - WriteEncodedInt64(FindFunctionIndex(func->scriptData->funcVariableTypes[i])); - WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i])); - } - if( count > 0 ) - WriteEncodedInt64(func->scriptData->objVariablesOnHeap); - - WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength()); - for( i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i ) - { - // The program position must be adjusted to be in number of instructions - WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]); - WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset)); - WriteEncodedInt64(func->scriptData->objVariableInfo[i].option); - } - - // The program position (every even number) needs to be adjusted - // to be in number of instructions instead of DWORD offset - if( !stripDebugInfo ) - { - asUINT length = (asUINT)func->scriptData->lineNumbers.GetLength(); - WriteEncodedInt64(length); - for( i = 0; i < length; ++i ) - { - if( (i & 1) == 0 ) - WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->lineNumbers[i]]); - else - WriteEncodedInt64(func->scriptData->lineNumbers[i]); - } - - // Write the array of script sections - length = (asUINT)func->scriptData->sectionIdxs.GetLength(); - WriteEncodedInt64(length); - for( i = 0; i < length; ++i ) - { - if( (i & 1) == 0 ) - WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->sectionIdxs[i]]); - else - { - if( func->scriptData->sectionIdxs[i] >= 0 ) - WriteString(engine->scriptSectionNames[func->scriptData->sectionIdxs[i]]); - else - { - char c = 0; - WriteData(&c, 1); - } - } - } - } - - // Write the variable information - if( !stripDebugInfo ) - { - WriteEncodedInt64((asUINT)func->scriptData->variables.GetLength()); - for( i = 0; i < func->scriptData->variables.GetLength(); i++ ) - { - // The program position must be adjusted to be in number of instructions - WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->variables[i]->declaredAtProgramPos]); - // The stack position must be adjusted according to the pointer sizes - WriteEncodedInt64(AdjustStackPosition(func->scriptData->variables[i]->stackOffset)); - WriteString(&func->scriptData->variables[i]->name); - WriteDataType(&func->scriptData->variables[i]->type); - } - } - - char bits = 0; - bits += func->isShared ? 1 : 0; - bits += func->dontCleanUpOnException ? 2 : 0; - WriteData(&bits,1); - - // Store script section name - if( !stripDebugInfo ) - { - if( func->scriptData->scriptSectionIdx >= 0 ) - WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]); - else - { - char c = 0; - WriteData(&c, 1); - } - WriteEncodedInt64(func->scriptData->declaredAt); - } - - // Store the parameter names - if( !stripDebugInfo ) - { - asUINT count = asUINT(func->parameterNames.GetLength()); - WriteEncodedInt64(count); - for( asUINT n = 0; n < count; n++ ) - WriteString(&func->parameterNames[n]); - } - } - else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) - { - // TODO: Do we really need to store this? It can probably be reconstructed by the reader - WriteEncodedInt64(func->vfTableIdx); - } -} - -void asCWriter::WriteObjectTypeDeclaration(asCObjectType *ot, int phase) -{ - if( phase == 1 ) - { - // name - WriteString(&ot->name); - // flags - WriteData(&ot->flags, 4); - - // size - // TODO: Do we really need to store this? The reader should be able to - // determine the correct size from the object type's flags - if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size > 0 ) - { - // The size for script objects may vary from platform to platform so - // only store 1 to diferentiate from interfaces that have size 0. - WriteEncodedInt64(1); - } - else - { - // Enums, typedefs, and interfaces have fixed sizes independently - // of platform so it is safe to serialize the size directly. - WriteEncodedInt64(ot->size); - } - - // namespace - WriteString(&ot->nameSpace->name); - } - else if( phase == 2 ) - { - if( ot->flags & asOBJ_ENUM ) - { - // enumValues[] - int size = (int)ot->enumValues.GetLength(); - WriteEncodedInt64(size); - - for( int n = 0; n < size; n++ ) - { - WriteString(&ot->enumValues[n]->name); - WriteData(&ot->enumValues[n]->value, 4); - } - } - else if( ot->flags & asOBJ_TYPEDEF ) - { - eTokenType t = ot->templateSubTypes[0].GetTokenType(); - WriteEncodedInt64(t); - } - else - { - WriteObjectType(ot->derivedFrom); - - // interfaces[] / interfaceVFTOffsets[] - // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those? - int size = (asUINT)ot->interfaces.GetLength(); - WriteEncodedInt64(size); - asUINT n; - asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() ); - for( n = 0; n < ot->interfaces.GetLength(); n++ ) - { - WriteObjectType(ot->interfaces[n]); - WriteEncodedInt64(ot->interfaceVFTOffsets[n]); - } - - // behaviours - // TODO: Default behaviours should just be stored as a indicator - // to avoid storing the actual function object - if( !ot->IsInterface() && ot->flags != asOBJ_TYPEDEF && ot->flags != asOBJ_ENUM ) - { - WriteFunction(engine->scriptFunctions[ot->beh.destruct]); - size = (int)ot->beh.constructors.GetLength(); - WriteEncodedInt64(size); - for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) - { - WriteFunction(engine->scriptFunctions[ot->beh.constructors[n]]); - WriteFunction(engine->scriptFunctions[ot->beh.factories[n]]); - } - } - - // methods[] - // TODO: Avoid storing inherited methods in interfaces, as the reader - // can add those directly from the base interface - size = (int)ot->methods.GetLength(); - WriteEncodedInt64(size); - for( n = 0; n < ot->methods.GetLength(); n++ ) - { - WriteFunction(engine->scriptFunctions[ot->methods[n]]); - } - - // virtualFunctionTable[] - // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader - size = (int)ot->virtualFunctionTable.GetLength(); - WriteEncodedInt64(size); - for( n = 0; n < (asUINT)size; n++ ) - { - WriteFunction(ot->virtualFunctionTable[n]); - } - } - } - else if( phase == 3 ) - { - // properties[] - asUINT size = (asUINT)ot->properties.GetLength(); - WriteEncodedInt64(size); - for( asUINT n = 0; n < ot->properties.GetLength(); n++ ) - { - WriteObjectProperty(ot->properties[n]); - } - } -} - -void asCWriter::WriteEncodedInt64(asINT64 i) -{ - asBYTE signBit = ( i & asINT64(1)<<63 ) ? 0x80 : 0; - if( signBit ) i = -i; - - asBYTE b; - if( i < (1<<6) ) - { - b = (asBYTE)(signBit + i); WriteData(&b, 1); - } - else if( i < (1<<13) ) - { - b = asBYTE(0x40 + signBit + (i >> 8)); WriteData(&b, 1); - b = asBYTE(i & 0xFF); WriteData(&b, 1); - } - else if( i < (1<<20) ) - { - b = asBYTE(0x60 + signBit + (i >> 16)); WriteData(&b, 1); - b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); - b = asBYTE(i & 0xFF); WriteData(&b, 1); - } - else if( i < (1<<27) ) - { - b = asBYTE(0x70 + signBit + (i >> 24)); WriteData(&b, 1); - b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); - b = asBYTE(i & 0xFF); WriteData(&b, 1); - } - else if( i < (asINT64(1)<<34) ) - { - b = asBYTE(0x78 + signBit + (i >> 32)); WriteData(&b, 1); - b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); - b = asBYTE(i & 0xFF); WriteData(&b, 1); - } - else if( i < (asINT64(1)<<41) ) - { - b = asBYTE(0x7C + signBit + (i >> 40)); WriteData(&b, 1); - b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); - b = asBYTE(i & 0xFF); WriteData(&b, 1); - } - else if( i < (asINT64(1)<<48) ) - { - b = asBYTE(0x7E + signBit + (i >> 48)); WriteData(&b, 1); - b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); - b = asBYTE(i & 0xFF); WriteData(&b, 1); - } - else - { - b = asBYTE(0x7F + signBit); WriteData(&b, 1); - b = asBYTE((i >> 56) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 48) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); - b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); - b = asBYTE(i & 0xFF); WriteData(&b, 1); - } -} - -void asCWriter::WriteString(asCString* str) -{ - // TODO: All strings should be stored in a separate section, and when - // they are used an offset into that section should be stored. - // This will make it unnecessary to store the extra byte to - // identify new versus old strings. - - if( str->GetLength() == 0 ) - { - char z = '\0'; - WriteData(&z, 1); - return; - } - - // First check if the string hasn't been saved already - asSMapNode *cursor = 0; - if (stringToIdMap.MoveTo(&cursor, asCStringPointer(str))) - { - // Save a reference to the existing string - char b = 'r'; - WriteData(&b, 1); - WriteEncodedInt64(cursor->value); - return; - } - - // Save a new string - char b = 'n'; - WriteData(&b, 1); - - asUINT len = (asUINT)str->GetLength(); - WriteEncodedInt64(len); - stream->Write(str->AddressOf(), (asUINT)len); - - savedStrings.PushLast(*str); - stringToIdMap.Insert(asCStringPointer(str), int(savedStrings.GetLength()) - 1); -} - -void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop) -{ - // TODO: We might be able to avoid storing the name and type of the global - // properties twice if we merge this with the WriteUsedGlobalProperties. - WriteString(&prop->name); - WriteString(&prop->nameSpace->name); - WriteDataType(&prop->type); - - // Store the initialization function - WriteFunction(prop->GetInitFunc()); -} - -void asCWriter::WriteObjectProperty(asCObjectProperty* prop) -{ - WriteString(&prop->name); - WriteDataType(&prop->type); - WriteData(&prop->isPrivate, 1); -} - -void asCWriter::WriteDataType(const asCDataType *dt) -{ - // First check if the datatype has already been saved - for( asUINT n = 0; n < savedDataTypes.GetLength(); n++ ) - { - if( *dt == savedDataTypes[n] ) - { - WriteEncodedInt64(n+1); - return; - } - } - - // Indicate a new type with a null byte - asUINT c = 0; - WriteEncodedInt64(c); - - // Save the new datatype - savedDataTypes.PushLast(*dt); - - int t = dt->GetTokenType(); - WriteEncodedInt64(t); - if( t == ttIdentifier ) - WriteObjectType(dt->GetObjectType()); - - struct - { - char isObjectHandle :1; - char isHandleToConst:1; - char isReference :1; - char isReadOnly :1; - } bits = {0}; - - bits.isObjectHandle = dt->IsObjectHandle(); - bits.isHandleToConst = dt->IsHandleToConst(); - bits.isReference = dt->IsReference(); - bits.isReadOnly = dt->IsReadOnly(); - WriteData(&bits, 1); - - if( t == ttIdentifier && dt->GetObjectType()->name == "_builtin_function_" ) - { - WriteFunctionSignature(dt->GetFuncDef()); - } -} - -void asCWriter::WriteObjectType(asCObjectType* ot) -{ - char ch; - - if( ot ) - { - // Check for template instances/specializations - if( ot->templateSubTypes.GetLength() ) - { - // Check for list pattern type or template type - if( ot->flags & asOBJ_LIST_PATTERN ) - { - ch = 'l'; - WriteData(&ch, 1); - WriteObjectType(ot->templateSubTypes[0].GetObjectType()); - } - else - { - ch = 'a'; - WriteData(&ch, 1); - WriteString(&ot->name); - WriteString(&ot->nameSpace->name); - - WriteEncodedInt64(ot->templateSubTypes.GetLength()); - for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) - { - if( ot->templateSubTypes[0].IsObject() || ot->templateSubTypes[0].IsEnumType() ) - { - ch = 's'; - WriteData(&ch, 1); - WriteDataType(&ot->templateSubTypes[0]); - } - else - { - ch = 't'; - WriteData(&ch, 1); - eTokenType t = ot->templateSubTypes[0].GetTokenType(); - WriteEncodedInt64(t); - } - } - } - } - else if( ot->flags & asOBJ_TEMPLATE_SUBTYPE ) - { - ch = 's'; - WriteData(&ch, 1); - WriteString(&ot->name); - } - else - { - ch = 'o'; - WriteData(&ch, 1); - WriteString(&ot->name); - WriteString(&ot->nameSpace->name); - } - } - else - { - ch = '\0'; - WriteData(&ch, 1); - } -} - -void asCWriter::CalculateAdjustmentByPos(asCScriptFunction *func) -{ - // Adjust the offset of all negative variables (parameters) so all pointers will have a size of 1 dword - asUINT n; - asCArray adjustments; - asUINT offset = 0; - if( func->objectType ) - { - adjustments.PushLast(offset); - adjustments.PushLast(1-AS_PTR_SIZE); - offset += AS_PTR_SIZE; - } - if( func->DoesReturnOnStack() ) - { - adjustments.PushLast(offset); - adjustments.PushLast(1-AS_PTR_SIZE); - offset += AS_PTR_SIZE; - } - for( n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( !func->parameterTypes[n].IsPrimitive() || - func->parameterTypes[n].IsReference() ) - { - adjustments.PushLast(offset); - adjustments.PushLast(1-AS_PTR_SIZE); - offset += AS_PTR_SIZE; - } - else - { - asASSERT( func->parameterTypes[n].IsPrimitive() ); - offset += func->parameterTypes[n].GetSizeOnStackDWords(); - } - } - - // Build look-up table with the adjustments for each stack position - adjustNegativeStackByPos.SetLength(offset); - memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int)); - for( n = 0; n < adjustments.GetLength(); n+=2 ) - { - int pos = adjustments[n]; - int adjust = adjustments[n+1]; - - for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ ) - adjustNegativeStackByPos[i] += adjust; - } - - // Adjust the offset of all positive variables so that all object types and handles have a size of 1 dword - // This is similar to how the adjustment is done in the asCReader::TranslateFunction, only the reverse - adjustments.SetLength(0); - for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ ) - { - if( func->scriptData->objVariableTypes[n] ) - { - // Determine the size the variable currently occupies on the stack - int size = AS_PTR_SIZE; - if( (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && - n >= func->scriptData->objVariablesOnHeap ) - { - size = func->scriptData->objVariableTypes[n]->GetSize(); - if( size < 4 ) - size = 1; - else - size /= 4; - } - - // If larger than 1 dword, adjust the offsets accordingly - if( size > 1 ) - { - // How much needs to be adjusted? - adjustments.PushLast(func->scriptData->objVariablePos[n]); - adjustments.PushLast(-(size-1)); - } - } - } - - // Build look-up table with the adjustments for each stack position - adjustStackByPos.SetLength(func->scriptData->stackNeeded); - memset(adjustStackByPos.AddressOf(), 0, adjustStackByPos.GetLength()*sizeof(int)); - for( n = 0; n < adjustments.GetLength(); n+=2 ) - { - int pos = adjustments[n]; - int adjust = adjustments[n+1]; - - for( asUINT i = pos; i < adjustStackByPos.GetLength(); i++ ) - adjustStackByPos[i] += adjust; - } - - // Compute the sequence number of each bytecode instruction in order to update the jump offsets - size_t length = func->scriptData->byteCode.GetLength(); - asDWORD *bc = func->scriptData->byteCode.AddressOf(); - bytecodeNbrByPos.SetLength(length); - asUINT num; - for( offset = 0, num = 0; offset < length; ) - { - bytecodeNbrByPos[offset] = num; - offset += asBCTypeSize[asBCInfo[*(asBYTE*)(bc+offset)].type]; - num++; - } - // The last instruction is always a BC_RET. This make it possible to query - // the number of instructions by checking the last entry in bytecodeNbrByPos - asASSERT(*(asBYTE*)(bc+length-1) == asBC_RET); -} - -int asCWriter::AdjustStackPosition(int pos) -{ - if( pos >= (int)adjustStackByPos.GetLength() ) - { - // This happens for example if the function only have temporary variables - // The adjustByPos can also be empty if the function doesn't have any variables at all, but receive a handle by parameter - if( adjustStackByPos.GetLength() > 0 ) - pos += adjustStackByPos[adjustStackByPos.GetLength()-1]; - } - else if( pos >= 0 ) - pos += adjustStackByPos[pos]; - else - { - asASSERT( -pos < (int)adjustNegativeStackByPos.GetLength() ); - pos -= (short)adjustNegativeStackByPos[-pos]; - } - - return pos; -} - -int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos) -{ - // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime - // the function can remember where it found the function and check if the programPos is still valid - - // Get offset 0 doesn't need adjustment - if( offset == 0 ) return 0; - - // Find out which function that will be called - asCScriptFunction *calledFunc = 0; - for( asUINT n = programPos; n < func->scriptData->byteCode.GetLength(); ) - { - asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n]; - if( bc == asBC_CALL || - bc == asBC_CALLSYS || - bc == asBC_CALLINTF ) - { - // Find the function from the function id in bytecode - int funcId = asBC_INTARG(&func->scriptData->byteCode[n]); - calledFunc = engine->scriptFunctions[funcId]; - break; - } - else if( bc == asBC_ALLOC ) - { - // Find the function from the function id in the bytecode - int funcId = asBC_INTARG(&func->scriptData->byteCode[n+AS_PTR_SIZE]); - calledFunc = engine->scriptFunctions[funcId]; - break; - } - else if( bc == asBC_CALLBND ) - { - // Find the function from the engine's bind array - int funcId = asBC_INTARG(&func->scriptData->byteCode[n]); - calledFunc = engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature; - break; - } - else if( bc == asBC_CallPtr ) - { - int var = asBC_SWORDARG0(&func->scriptData->byteCode[n]); - asUINT v; - // Find the funcdef from the local variable - for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) - { - if( func->scriptData->objVariablePos[v] == var ) - { - calledFunc = func->scriptData->funcVariableTypes[v]; - break; - } - } - if( !calledFunc ) - { - // Look in parameters - int paramPos = 0; - if( func->objectType ) - paramPos -= AS_PTR_SIZE; - if( func->DoesReturnOnStack() ) - paramPos -= AS_PTR_SIZE; - for( v = 0; v < func->parameterTypes.GetLength(); v++ ) - { - if( var == paramPos ) - { - calledFunc = func->parameterTypes[v].GetFuncDef(); - break; - } - paramPos -= func->parameterTypes[v].GetSizeOnStackDWords(); - } - } - break; - } - else if( bc == asBC_REFCPY || - bc == asBC_COPY ) - { - // In this case we know there is only 1 pointer on the stack above - asASSERT( offset == AS_PTR_SIZE ); - return offset + (1 - AS_PTR_SIZE); - } - - n += asBCTypeSize[asBCInfo[bc].type]; - } - - asASSERT( calledFunc ); - - // Count the number of pointers pushed on the stack above the - // current offset, and then adjust the offset accordingly - asUINT numPtrs = 0; - int currOffset = 0; - if( offset > currOffset && calledFunc->GetObjectType() ) - { - numPtrs++; - currOffset += AS_PTR_SIZE; - } - if( offset > currOffset && calledFunc->DoesReturnOnStack() ) - { - numPtrs++; - currOffset += AS_PTR_SIZE; - } - for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ ) - { - if( offset <= currOffset ) break; - - if( !calledFunc->parameterTypes[p].IsPrimitive() || - calledFunc->parameterTypes[p].IsReference() ) - { - // objects and references are passed by pointer - numPtrs++; - currOffset += AS_PTR_SIZE; - - // The variable arg ? has an additional 32bit int with the typeid - if( calledFunc->parameterTypes[p].IsAnyType() ) - currOffset += 1; - } - else - { - // built-in primitives or enums are passed by value - asASSERT( calledFunc->parameterTypes[p].IsPrimitive() ); - currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords(); - } - } - - // The get offset must match one of the parameter offsets - asASSERT( offset == currOffset ); - - return offset + numPtrs * (1 - AS_PTR_SIZE); -} - -void asCWriter::WriteByteCode(asCScriptFunction *func) -{ - asDWORD *bc = func->scriptData->byteCode.AddressOf(); - size_t length = func->scriptData->byteCode.GetLength(); - - // The length cannot be stored, because it is platform dependent, - // instead we store the number of instructions - asUINT count = bytecodeNbrByPos[bytecodeNbrByPos.GetLength()-1] + 1; - WriteEncodedInt64(count); - - asDWORD *startBC = bc; - while( length ) - { - asDWORD tmp[4]; // The biggest instructions take up 4 DWORDs - asDWORD c = *(asBYTE*)bc; - - // Copy the instruction to a temp buffer so we can work on it before saving - memcpy(tmp, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD)); - - if( c == asBC_ALLOC ) // PTR_DW_ARG - { - // Translate the object type - asCObjectType *ot = *(asCObjectType**)(tmp+1); - *(asPWORD*)(tmp+1) = FindObjectTypeIdx(ot); - - // Translate the constructor func id, unless it is 0 - if( *(int*)&tmp[1+AS_PTR_SIZE] != 0 ) - { - // Increment 1 to the translated function id, as 0 will be reserved for no function - *(int*)&tmp[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmp[1+AS_PTR_SIZE]]); - } - } - else if( c == asBC_REFCPY || // PTR_ARG - c == asBC_RefCpyV || // wW_PTR_ARG - c == asBC_OBJTYPE ) // PTR_ARG - { - // Translate object type pointers into indices - *(asPWORD*)(tmp+1) = FindObjectTypeIdx(*(asCObjectType**)(tmp+1)); - } - else if( c == asBC_JitEntry ) // PTR_ARG - { - // We don't store the JIT argument - *(asPWORD*)(tmp+1) = 0; - } - else if( c == asBC_TYPEID || // DW_ARG - c == asBC_Cast ) // DW_ARG - { - // Translate type ids into indices - *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1)); - } - else if( c == asBC_ADDSi || // W_DW_ARG - c == asBC_LoadThisR ) // W_DW_ARG - { - // Translate property offsets into indices - *(((short*)tmp)+1) = (short)FindObjectPropIndex(*(((short*)tmp)+1), *(int*)(tmp+1)); - - // Translate type ids into indices - *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1)); - } - else if( c == asBC_LoadRObjR || // rW_W_DW_ARG - c == asBC_LoadVObjR ) // rW_W_DW_ARG - { - asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmp+2)); - if( ot->flags & asOBJ_LIST_PATTERN ) - { - // List patterns have a different way of translating the offsets - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - *(((short*)tmp)+2) = (short)listAdj->AdjustOffset(*(((short*)tmp)+2), ot); - } - else - { - // Translate property offsets into indices - // TODO: optimize: Pass the object type directly to the method instead of the type id - *(((short*)tmp)+2) = (short)FindObjectPropIndex(*(((short*)tmp)+2), *(int*)(tmp+2)); - } - - // Translate type ids into indices - *(int*)(tmp+2) = FindTypeIdIdx(*(int*)(tmp+2)); - } - else if( c == asBC_COPY ) // W_DW_ARG - { - // Translate type ids into indices - *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1)); - - // Update the WORDARG0 to 0, as this will be recalculated on the target platform - asBC_WORDARG0(tmp) = 0; - } - else if( c == asBC_RET ) // W_ARG - { - // Save with arg 0, as this will be recalculated on the target platform - asBC_WORDARG0(tmp) = 0; - } - else if( c == asBC_CALL || // DW_ARG - c == asBC_CALLINTF || // DW_ARG - c == asBC_CALLSYS ) // DW_ARG - { - // Translate the function id - *(int*)(tmp+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmp+1)]); - } - else if( c == asBC_FuncPtr ) // PTR_ARG - { - // Translate the function pointer - *(asPWORD*)(tmp+1) = FindFunctionIndex(*(asCScriptFunction**)(tmp+1)); - } - else if( c == asBC_STR ) // W_ARG - { - // Translate the string constant id - asWORD *arg = ((asWORD*)tmp)+1; - *arg = (asWORD)FindStringConstantIndex(*arg); - } - else if( c == asBC_CALLBND ) // DW_ARG - { - // Translate the function id - int funcId = tmp[1]; - for( asUINT n = 0; n < module->bindInformations.GetLength(); n++ ) - if( module->bindInformations[n]->importedFunctionSignature->id == funcId ) - { - funcId = n; - break; - } - - tmp[1] = funcId; - } - else if( c == asBC_PGA || // PTR_ARG - c == asBC_PshGPtr || // PTR_ARG - c == asBC_LDG || // PTR_ARG - c == asBC_PshG4 || // PTR_ARG - c == asBC_LdGRdR4 || // wW_PTR_ARG - c == asBC_CpyGtoV4 || // wW_PTR_ARG - c == asBC_CpyVtoG4 || // rW_PTR_ARG - c == asBC_SetG4 ) // PTR_DW_ARG - { - // Translate global variable pointers into indices - *(asPWORD*)(tmp+1) = FindGlobalPropPtrIndex(*(void**)(tmp+1)); - } - else if( c == asBC_JMP || // DW_ARG - c == asBC_JZ || - c == asBC_JNZ || - c == asBC_JLowZ || - c == asBC_JLowNZ || - c == asBC_JS || - c == asBC_JNS || - c == asBC_JP || - c == asBC_JNP ) // The JMPP instruction doesn't need modification - { - // Get the DWORD offset from arg - int offset = *(int*)(tmp+1); - - // Determine instruction number for next instruction and destination - int bcSeqNum = bytecodeNbrByPos[bc - startBC] + 1; - asDWORD *targetBC = bc + 2 + offset; - int targetBcSeqNum = bytecodeNbrByPos[targetBC - startBC]; - - // Set the offset in number of instructions - *(int*)(tmp+1) = targetBcSeqNum - bcSeqNum; - } - else if( c == asBC_GETOBJ || // W_ARG - c == asBC_GETOBJREF || - c == asBC_GETREF ) - { - // Adjust the offset according to the function call that comes after - asBC_WORDARG0(tmp) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmp), func, asDWORD(bc - startBC)); - } - else if( c == asBC_AllocMem ) - { - // It's not necessary to store the size of the list buffer, as it will be recalculated in the reader - asBC_DWORDARG(tmp) = 0; - - // Determine the type of the list pattern from the variable - short var = asBC_WORDARG0(tmp); - asCObjectType *ot = func->GetObjectTypeOfLocalVar(var); - - // Create this helper object to adjust the offset of the elements accessed in the buffer - listAdjusters.PushLast(asNEW(SListAdjuster)(ot)); - } - else if( c == asBC_FREE ) // wW_PTR_ARG - { - // Translate object type pointers into indices - asCObjectType *ot = *(asCObjectType**)(tmp+1); - *(asPWORD*)(tmp+1) = FindObjectTypeIdx(ot); - - // Pop and destroy the list adjuster helper that was created with asBC_AllocMem - if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) - { - SListAdjuster *list = listAdjusters.PopLast(); - asDELETE(list, SListAdjuster); - } - } - else if( c == asBC_SetListSize ) - { - // Adjust the offset in the initialization list - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType); - - // Tell the adjuster how many repeated values there are - listAdj->SetRepeatCount(tmp[2]); - } - else if( c == asBC_PshListElmnt ) // W_DW_ARG - { - // Adjust the offset in the initialization list - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType); - } - else if( c == asBC_SetListType ) - { - // Adjust the offset in the initialization list - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType); - - // Inform the adjuster of the type id of the next element - listAdj->SetNextType(tmp[2]); - - // Translate the type id - tmp[2] = FindTypeIdIdx(tmp[2]); - } - // Adjust the variable offsets - switch( asBCInfo[c].type ) - { - case asBCTYPE_wW_ARG: - case asBCTYPE_rW_DW_ARG: - case asBCTYPE_wW_QW_ARG: - case asBCTYPE_rW_ARG: - case asBCTYPE_wW_DW_ARG: - case asBCTYPE_wW_W_ARG: - case asBCTYPE_rW_QW_ARG: - case asBCTYPE_rW_W_DW_ARG: - case asBCTYPE_rW_DW_DW_ARG: - { - asBC_SWORDARG0(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp)); - } - break; - - case asBCTYPE_wW_rW_ARG: - case asBCTYPE_wW_rW_DW_ARG: - case asBCTYPE_rW_rW_ARG: - { - asBC_SWORDARG0(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp)); - asBC_SWORDARG1(tmp) = (short)AdjustStackPosition(asBC_SWORDARG1(tmp)); - } - break; - - case asBCTYPE_wW_rW_rW_ARG: - { - asBC_SWORDARG0(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp)); - asBC_SWORDARG1(tmp) = (short)AdjustStackPosition(asBC_SWORDARG1(tmp)); - asBC_SWORDARG2(tmp) = (short)AdjustStackPosition(asBC_SWORDARG2(tmp)); - } - break; - - default: - // The other types don't treat variables so won't be modified - break; - } - - // TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform. - // Some platforms may not use the IEEE 754 standard, in which case it is necessary to encode the values - - // Now store the instruction in the smallest possible way - switch( asBCInfo[c].type ) - { - case asBCTYPE_NO_ARG: - { - // Just write 1 byte - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - } - break; - case asBCTYPE_W_ARG: - case asBCTYPE_wW_ARG: - case asBCTYPE_rW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the argument - short w = *(((short*)tmp)+1); - WriteEncodedInt64(w); - } - break; - case asBCTYPE_rW_DW_ARG: - case asBCTYPE_wW_DW_ARG: - case asBCTYPE_W_DW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the word argument - short w = *(((short*)tmp)+1); - WriteEncodedInt64(w); - - // Write the dword argument - WriteEncodedInt64((int)tmp[1]); - } - break; - case asBCTYPE_DW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the argument - WriteEncodedInt64((int)tmp[1]); - } - break; - case asBCTYPE_DW_DW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the dword argument - WriteEncodedInt64((int)tmp[1]); - - // Write the dword argument - WriteEncodedInt64((int)tmp[2]); - } - break; - case asBCTYPE_wW_rW_rW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the first argument - short w = *(((short*)tmp)+1); - WriteEncodedInt64(w); - - // Write the second argument - w = *(((short*)tmp)+2); - WriteEncodedInt64(w); - - // Write the third argument - w = *(((short*)tmp)+3); - WriteEncodedInt64(w); - } - break; - case asBCTYPE_wW_rW_ARG: - case asBCTYPE_rW_rW_ARG: - case asBCTYPE_wW_W_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the first argument - short w = *(((short*)tmp)+1); - WriteEncodedInt64(w); - - // Write the second argument - w = *(((short*)tmp)+2); - WriteEncodedInt64(w); - } - break; - case asBCTYPE_wW_rW_DW_ARG: - case asBCTYPE_rW_W_DW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the first argument - short w = *(((short*)tmp)+1); - WriteEncodedInt64(w); - - // Write the second argument - w = *(((short*)tmp)+2); - WriteEncodedInt64(w); - - // Write the third argument - int dw = tmp[2]; - WriteEncodedInt64(dw); - } - break; - case asBCTYPE_QW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the argument - asQWORD qw = *(asQWORD*)&tmp[1]; - WriteEncodedInt64(qw); - } - break; - case asBCTYPE_QW_DW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the argument - asQWORD qw = *(asQWORD*)&tmp[1]; - WriteEncodedInt64(qw); - - // Write the second argument - int dw = tmp[3]; - WriteEncodedInt64(dw); - } - break; - case asBCTYPE_rW_QW_ARG: - case asBCTYPE_wW_QW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the first argument - short w = *(((short*)tmp)+1); - WriteEncodedInt64(w); - - // Write the argument - asQWORD qw = *(asQWORD*)&tmp[1]; - WriteEncodedInt64(qw); - } - break; - case asBCTYPE_rW_DW_DW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the short argument - short w = *(((short*)tmp)+1); - WriteEncodedInt64(w); - - // Write the dword argument - WriteEncodedInt64((int)tmp[1]); - - // Write the dword argument - WriteEncodedInt64((int)tmp[2]); - } - break; - default: - { - // This should never happen - asASSERT(false); - - // Store the bc as is - for( int n = 0; n < asBCTypeSize[asBCInfo[c].type]; n++ ) - WriteData(&tmp[n], 4); - } - } - - // Move to the next instruction - bc += asBCTypeSize[asBCInfo[c].type]; - length -= asBCTypeSize[asBCInfo[c].type]; - } -} - -asCWriter::SListAdjuster::SListAdjuster(asCObjectType *ot) : patternType(ot), repeatCount(0), entries(0), lastOffset(-1), nextOffset(0), nextTypeId(-1) -{ - asASSERT( ot && (ot->flags & asOBJ_LIST_PATTERN) ); - - // Find the first expected value in the list - asSListPatternNode *node = ot->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; - asASSERT( node && node->type == asLPT_START ); - patternNode = node->next; -} - -int asCWriter::SListAdjuster::AdjustOffset(int offset, asCObjectType *listPatternType) -{ - // TODO: cleanup: The listPatternType parameter is not needed - asASSERT( patternType == listPatternType ); - UNUSED_VAR(listPatternType); - - asASSERT( offset >= lastOffset ); - - // If it is the same offset being accessed again, just return the same adjusted value - if( offset == lastOffset ) - return entries-1; - - asASSERT( offset >= nextOffset ); - - // Update last offset for next call - lastOffset = offset; - - // What is being expected at this position? - if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ) - { - // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too - nextOffset = offset + 4; - return entries++; - } - else if( patternNode->type == asLPT_TYPE ) - { - const asCDataType &dt = reinterpret_cast(patternNode)->dataType; - if( dt.GetTokenType() == ttQuestion ) - { - // The bytecode need to inform the type that will - // come next and then adjust that position too before - // we can move to the next node - if( nextTypeId != -1 ) - { - nextOffset = offset + 4; - - if( repeatCount > 0 ) - repeatCount--; - - // Only move the patternNode if we're not expecting any more repeated entries - if( repeatCount == 0 ) - patternNode = patternNode->next; - - nextTypeId = -1; - } - } - else - { - if( repeatCount > 0 ) - { - // Was any value skipped? - asUINT size; - if( dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_REF)) ) - size = AS_PTR_SIZE*4; - else - size = dt.GetSizeInMemoryBytes(); - - int count = 0; - while( nextOffset <= offset ) - { - count++; - nextOffset += size; - - // Align the offset on 4 byte boundaries - if( size >= 4 && (nextOffset & 0x3) ) - nextOffset += 4 - (nextOffset & 0x3); - } - - if( --count > 0 ) - { - // Skip these values - repeatCount -= count; - entries += count; - } - - nextOffset = offset + size; - repeatCount--; - } - - // Only move the patternNode if we're not expecting any more repeated entries - if( repeatCount == 0 ) - patternNode = patternNode->next; - } - - return entries++; - } - else if( patternNode->type == asLPT_START ) - { - if( repeatCount > 0 ) - repeatCount--; - SInfo info = {repeatCount, patternNode}; - stack.PushLast(info); - - repeatCount = 0; - patternNode = patternNode->next; - - lastOffset--; - return AdjustOffset(offset, listPatternType); - } - else if( patternNode->type == asLPT_END ) - { - SInfo info = stack.PopLast(); - repeatCount = info.repeatCount; - if( repeatCount ) - patternNode = info.startNode; - else - patternNode = patternNode->next; - - lastOffset--; - return AdjustOffset(offset, listPatternType); - } - else - { - // Something is wrong with the pattern list declaration - asASSERT( false ); - } - - return 0; -} - -void asCWriter::SListAdjuster::SetRepeatCount(asUINT rc) -{ - // Make sure the list is expecting a repeat at this location - asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ); - - // Now move to the next patternNode - patternNode = patternNode->next; - - repeatCount = rc; -} - -void asCWriter::SListAdjuster::SetNextType(int typeId) -{ - // Make sure the list is expecting a type at this location - asASSERT( patternNode->type == asLPT_TYPE && - reinterpret_cast(patternNode)->dataType.GetTokenType() == ttQuestion ); - - // Inform the type id for the next adjustment - nextTypeId = typeId; -} - -void asCWriter::WriteUsedTypeIds() -{ - asUINT count = (asUINT)usedTypeIds.GetLength(); - WriteEncodedInt64(count); - for( asUINT n = 0; n < count; n++ ) - { - asCDataType dt = engine->GetDataTypeFromTypeId(usedTypeIds[n]); - WriteDataType(&dt); - } -} - -int asCWriter::FindGlobalPropPtrIndex(void *ptr) -{ - int i = usedGlobalProperties.IndexOf(ptr); - if( i >= 0 ) return i; - - usedGlobalProperties.PushLast(ptr); - return (int)usedGlobalProperties.GetLength()-1; -} - -void asCWriter::WriteUsedGlobalProps() -{ - int c = (int)usedGlobalProperties.GetLength(); - WriteEncodedInt64(c); - - for( int n = 0; n < c; n++ ) - { - asPWORD *p = (asPWORD*)usedGlobalProperties[n]; - - // First search for the global in the module - char moduleProp = 0; - asCGlobalProperty *prop = 0; - asCSymbolTable::iterator it = module->scriptGlobals.List(); - for( ; it; it++ ) - { - if( p == (*it)->GetAddressOfValue() ) - { - prop = (*it); - moduleProp = 1; - break; - } - } - - // If it is not in the module, it must be an application registered property - if( !prop ) - { - asCSymbolTable::iterator it = engine->registeredGlobalProps.List(); - for( ; it; it++ ) - { - if( it->GetAddressOfValue() == p ) - { - prop = *it; - break; - } - } - } - - asASSERT(prop); - - // Store the name and type of the property so we can find it again on loading - WriteString(&prop->name); - WriteString(&prop->nameSpace->name); - WriteDataType(&prop->type); - - // Also store whether the property is a module property or a registered property - WriteData(&moduleProp, 1); - } -} - -void asCWriter::WriteUsedObjectProps() -{ - int c = (int)usedObjectProperties.GetLength(); - WriteEncodedInt64(c); - - for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) - { - asCObjectType *objType = usedObjectProperties[n].objType; - WriteObjectType(objType); - - // Find the property name - for( asUINT p = 0; p < objType->properties.GetLength(); p++ ) - { - if( objType->properties[p]->byteOffset == usedObjectProperties[n].offset ) - { - WriteString(&objType->properties[p]->name); - break; - } - } - } -} - -int asCWriter::FindObjectPropIndex(short offset, int typeId) -{ - asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId); - for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) - { - if( usedObjectProperties[n].objType == objType && - usedObjectProperties[n].offset == offset ) - return n; - } - - SObjProp prop = {objType, offset}; - usedObjectProperties.PushLast(prop); - return (int)usedObjectProperties.GetLength() - 1; -} - -int asCWriter::FindFunctionIndex(asCScriptFunction *func) -{ - for( asUINT n = 0; n < usedFunctions.GetLength(); n++ ) - { - if( usedFunctions[n] == func ) - return n; - } - - usedFunctions.PushLast(func); - return (int)usedFunctions.GetLength() - 1; -} - -int asCWriter::FindTypeIdIdx(int typeId) -{ - asUINT n; - for( n = 0; n < usedTypeIds.GetLength(); n++ ) - { - if( usedTypeIds[n] == typeId ) - return n; - } - - usedTypeIds.PushLast(typeId); - return (int)usedTypeIds.GetLength() - 1; -} - -int asCWriter::FindObjectTypeIdx(asCObjectType *obj) -{ - asUINT n; - for( n = 0; n < usedTypes.GetLength(); n++ ) - { - if( usedTypes[n] == obj ) - return n; - } - - usedTypes.PushLast(obj); - return (int)usedTypes.GetLength() - 1; -} - -#endif // AS_NO_COMPILER - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_restore.h b/dependencies/angelscript/source/as_restore.h deleted file mode 100644 index 70bbb3d1..00000000 --- a/dependencies/angelscript/source/as_restore.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_restore.h -// -// Functions for saving and restoring module bytecode -// asCRestore was originally written by Dennis Bollyn, dennis@gyrbo.be -// It was later split in two classes asCReader and asCWriter by me - -#ifndef AS_RESTORE_H -#define AS_RESTORE_H - -#include "as_scriptengine.h" -#include "as_context.h" -#include "as_map.h" - -BEGIN_AS_NAMESPACE - -class asCReader -{ -public: - asCReader(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine); - - int Read(bool *wasDebugInfoStripped); - -protected: - asCModule *module; - asIBinaryStream *stream; - asCScriptEngine *engine; - bool noDebugInfo; - bool error; - asUINT bytesRead; - - int Error(const char *msg); - - int ReadInner(); - - void ReadData(void *data, asUINT size); - void ReadString(asCString *str); - asCScriptFunction *ReadFunction(bool &isNew, bool addToModule = true, bool addToEngine = true, bool addToGC = true); - void ReadFunctionSignature(asCScriptFunction *func); - void ReadGlobalProperty(); - void ReadObjectProperty(asCObjectType *ot); - void ReadDataType(asCDataType *dt); - asCObjectType * ReadObjectType(); - void ReadObjectTypeDeclaration(asCObjectType *ot, int phase); - void ReadByteCode(asCScriptFunction *func); - asWORD ReadEncodedUInt16(); - asUINT ReadEncodedUInt(); - asQWORD ReadEncodedUInt64(); - - void ReadUsedTypeIds(); - void ReadUsedFunctions(); - void ReadUsedGlobalProps(); - void ReadUsedStringConstants(); - void ReadUsedObjectProps(); - - asCObjectType * FindObjectType(int idx); - int FindTypeId(int idx); - short FindObjectPropOffset(asWORD index); - asCScriptFunction *FindFunction(int idx); - - // After loading, each function needs to be translated to update pointers, function ids, etc - void TranslateFunction(asCScriptFunction *func); - void CalculateAdjustmentByPos(asCScriptFunction *func); - int AdjustStackPosition(int pos); - int AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos); - void CalculateStackNeeded(asCScriptFunction *func); - asCScriptFunction *GetCalledFunction(asCScriptFunction *func, asDWORD programPos); - - // Temporary storage for persisting variable data - asCArray usedTypeIds; - asCArray usedTypes; - asCArray usedFunctions; - asCArray usedGlobalProperties; - asCArray usedStringConstants; - - asCArray savedFunctions; - asCArray savedDataTypes; - asCArray savedStrings; - - asCArray adjustByPos; - asCArray adjustNegativeStackByPos; - - struct SObjProp - { - asCObjectType *objType; - int offset; - }; - asCArray usedObjectProperties; - - asCMap existingShared; - asCMap dontTranslate; - - // Helper class for adjusting offsets within initialization list buffers - struct SListAdjuster - { - SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *ot); - void AdjustAllocMem(); - int AdjustOffset(int offset); - void SetRepeatCount(asUINT rc); - void SetNextType(int typeId); - - struct SInfo - { - asUINT repeatCount; - asSListPatternNode *startNode; - }; - asCArray stack; - - asCReader *reader; - asDWORD *allocMemBC; - asUINT maxOffset; - asCObjectType *patternType; - asUINT repeatCount; - int lastOffset; - int nextOffset; - asUINT lastAdjustedOffset; - asSListPatternNode *patternNode; - int nextTypeId; - }; - asCArray listAdjusters; -}; - -#ifndef AS_NO_COMPILER - -class asCWriter -{ -public: - asCWriter(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine, bool stripDebugInfo); - - int Write(); - -protected: - asCModule *module; - asIBinaryStream *stream; - asCScriptEngine *engine; - bool stripDebugInfo; - - void WriteData(const void *data, asUINT size); - - void WriteString(asCString *str); - void WriteFunction(asCScriptFunction *func); - void WriteFunctionSignature(asCScriptFunction *func); - void WriteGlobalProperty(asCGlobalProperty *prop); - void WriteObjectProperty(asCObjectProperty *prop); - void WriteDataType(const asCDataType *dt); - void WriteObjectType(asCObjectType *ot); - void WriteObjectTypeDeclaration(asCObjectType *ot, int phase); - void WriteByteCode(asCScriptFunction *func); - void WriteEncodedInt64(asINT64 i); - - // Helper functions for storing variable data - int FindObjectTypeIdx(asCObjectType*); - int FindTypeIdIdx(int typeId); - int FindFunctionIndex(asCScriptFunction *func); - int FindGlobalPropPtrIndex(void *); - int FindStringConstantIndex(int id); - int FindObjectPropIndex(short offset, int typeId); - - void CalculateAdjustmentByPos(asCScriptFunction *func); - int AdjustStackPosition(int pos); - int AdjustProgramPosition(int pos); - int AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos); - - // Intermediate data used for storing that which isn't constant, function id's, pointers, etc - void WriteUsedTypeIds(); - void WriteUsedFunctions(); - void WriteUsedGlobalProps(); - void WriteUsedStringConstants(); - void WriteUsedObjectProps(); - - // Temporary storage for persisting variable data - asCArray usedTypeIds; - asCArray usedTypes; - asCArray usedFunctions; - asCArray usedGlobalProperties; - asCArray usedStringConstants; - asCMap stringIdToIndexMap; - - asCArray savedFunctions; - asCArray savedDataTypes; - asCArray savedStrings; - asCMap stringToIdMap; - asCArray adjustStackByPos; - asCArray adjustNegativeStackByPos; - asCArray bytecodeNbrByPos; - - struct SObjProp - { - asCObjectType *objType; - int offset; - }; - asCArray usedObjectProperties; - - // Helper class for adjusting offsets within initialization list buffers - struct SListAdjuster - { - SListAdjuster(asCObjectType *ot); - int AdjustOffset(int offset, asCObjectType *listPatternType); - void SetRepeatCount(asUINT rc); - void SetNextType(int typeId); - - struct SInfo - { - asUINT repeatCount; - asSListPatternNode *startNode; - }; - asCArray stack; - - asCObjectType *patternType; - asUINT repeatCount; - asSListPatternNode *patternNode; - asUINT entries; - int lastOffset; // Last offset adjusted - int nextOffset; // next expected offset to be adjusted - int nextTypeId; - }; - asCArray listAdjusters; -}; - -#endif - -END_AS_NAMESPACE - -#endif // AS_RESTORE_H diff --git a/dependencies/angelscript/source/as_scriptcode.cpp b/dependencies/angelscript/source/as_scriptcode.cpp deleted file mode 100644 index 256ca5c8..00000000 --- a/dependencies/angelscript/source/as_scriptcode.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_scriptcode.cpp -// -// A container class for the script code to be compiled -// - - - -#include "as_config.h" -#include "as_scriptcode.h" - -BEGIN_AS_NAMESPACE - -asCScriptCode::asCScriptCode() -{ - lineOffset = 0; - code = 0; - codeLength = 0; - sharedCode = false; -} - -asCScriptCode::~asCScriptCode() -{ - if( !sharedCode && code ) - { - asDELETEARRAY(code); - } -} - -int asCScriptCode::SetCode(const char *name, const char *code, bool makeCopy) -{ - return SetCode(name, code, 0, makeCopy); -} - -int asCScriptCode::SetCode(const char *name, const char *code, size_t length, bool makeCopy) -{ - if( !code ) return asINVALID_ARG; - this->name = name ? name : ""; - if( !sharedCode && this->code ) - asDELETEARRAY(this->code); - - if( length == 0 ) - length = strlen(code); - if( makeCopy ) - { - codeLength = length; - sharedCode = false; - this->code = asNEWARRAY(char,length); - if( this->code == 0 ) - return asOUT_OF_MEMORY; - memcpy((char*)this->code, code, length); - } - else - { - codeLength = length; - this->code = const_cast(code); - sharedCode = true; - } - - // Find the positions of each line - linePositions.PushLast(0); - for( size_t n = 0; n < length; n++ ) - if( code[n] == '\n' ) linePositions.PushLast(n+1); - linePositions.PushLast(length); - - return asSUCCESS; -} - -void asCScriptCode::ConvertPosToRowCol(size_t pos, int *row, int *col) -{ - if( linePositions.GetLength() == 0 ) - { - if( row ) *row = lineOffset; - if( col ) *col = 1; - return; - } - - // Do a binary search in the buffer - int max = (int)linePositions.GetLength() - 1; - int min = 0; - int i = max/2; - - for(;;) - { - if( linePositions[i] < pos ) - { - // Have we found the largest number < programPosition? - if( min == i ) break; - - min = i; - i = (max + min)/2; - } - else if( linePositions[i] > pos ) - { - // Have we found the smallest number > programPoisition? - if( max == i ) break; - - max = i; - i = (max + min)/2; - } - else - { - // We found the exact position - break; - } - } - - if( row ) *row = i + 1 + lineOffset; - if( col ) *col = (int)(pos - linePositions[i]) + 1; -} - -bool asCScriptCode::TokenEquals(size_t pos, size_t len, const char *str) -{ - if( pos + len > codeLength ) return false; - if( strncmp(code + pos, str, len) == 0 && strlen(str) == len ) - return true; - return false; -} - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/source/as_scriptcode.h b/dependencies/angelscript/source/as_scriptcode.h deleted file mode 100644 index 3e31cc47..00000000 --- a/dependencies/angelscript/source/as_scriptcode.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2011 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_scriptcode.h -// -// A container class for the script code to be compiled -// - - - -#ifndef AS_SCRIPTCODE_H -#define AS_SCRIPTCODE_H - -#include "as_array.h" -#include "as_string.h" - -BEGIN_AS_NAMESPACE - -class asCScriptCode -{ -public: - asCScriptCode(); - ~asCScriptCode(); - - int SetCode(const char *name, const char *code, bool makeCopy); - int SetCode(const char *name, const char *code, size_t length, bool makeCopy); - - void ConvertPosToRowCol(size_t pos, int *row, int *col); - - bool TokenEquals(size_t pos, size_t len, const char *str); - - asCString name; - char *code; - size_t codeLength; - bool sharedCode; - int idx; - int lineOffset; - asCArray linePositions; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_scriptengine.cpp b/dependencies/angelscript/source/as_scriptengine.cpp deleted file mode 100644 index b7482bef..00000000 --- a/dependencies/angelscript/source/as_scriptengine.cpp +++ /dev/null @@ -1,6049 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_scriptengine.cpp -// -// The implementation of the script engine interface -// - - -#include - -#include "as_config.h" -#include "as_scriptengine.h" -#include "as_builder.h" -#include "as_context.h" -#include "as_string_util.h" -#include "as_tokenizer.h" -#include "as_texts.h" -#include "as_module.h" -#include "as_callfunc.h" -#include "as_generic.h" -#include "as_scriptobject.h" -#include "as_compiler.h" -#include "as_bytecode.h" -#include "as_debug.h" - -BEGIN_AS_NAMESPACE - - - -#ifdef AS_PROFILE -// Instantiate the profiler once -CProfiler g_profiler; -#endif - - - - -extern "C" -{ - -AS_API const char * asGetLibraryVersion() -{ -#ifdef _DEBUG - return ANGELSCRIPT_VERSION_STRING " DEBUG"; -#else - return ANGELSCRIPT_VERSION_STRING; -#endif -} - -AS_API const char * asGetLibraryOptions() -{ - const char *string = " " - - // Options -#ifdef AS_MAX_PORTABILITY - "AS_MAX_PORTABILITY " -#endif -#ifdef AS_DEBUG - "AS_DEBUG " -#endif -#ifdef AS_NO_CLASS_METHODS - "AS_NO_CLASS_METHODS " -#endif -#ifdef AS_USE_DOUBLE_AS_FLOAT - "AS_USE_DOUBLE_AS_FLOAT " -#endif -#ifdef AS_64BIT_PTR - "AS_64BIT_PTR " -#endif -#ifdef AS_NO_THREADS - "AS_NO_THREADS " -#endif -#ifdef AS_NO_ATOMIC - "AS_NO_ATOMIC " -#endif -#ifdef AS_NO_COMPILER - "AS_NO_COMPILER " -#endif -#ifdef AS_NO_MEMBER_INIT - "AS_NO_MEMBER_INIT " -#endif -#ifdef AS_NO_THISCALL_FUNCTOR_METHOD - "AS_NO_THISCALL_FUNCTOR_METHOD " -#endif -#ifdef WIP_16BYTE_ALIGN - "WIP_16BYTE_ALIGN " -#endif - - // Target system -#ifdef AS_WIN - "AS_WIN " -#endif -#ifdef AS_LINUX - "AS_LINUX " -#endif -#ifdef AS_MAC - "AS_MAC " -#endif -#ifdef AS_SUN - "AS_SUN " -#endif -#ifdef AS_BSD - "AS_BSD " -#endif -#ifdef AS_XBOX - "AS_XBOX " -#endif -#ifdef AS_XBOX360 - "AS_XBOX360 " -#endif -#ifdef AS_PSP - "AS_PSP " -#endif -#ifdef AS_PS2 - "AS_PS2 " -#endif -#ifdef AS_PS3 - "AS_PS3 " -#endif -#ifdef AS_DC - "AS_DC " -#endif -#ifdef AS_GC - "AS_GC " -#endif -#ifdef AS_WII - "AS_WII " -#endif -#ifdef AS_WIIU - "AS_WIIU " -#endif -#ifdef AS_IPHONE - "AS_IPHONE " -#endif -#ifdef AS_ANDROID - "AS_ANDROID " -#endif -#ifdef AS_HAIKU - "AS_HAIKU " -#endif -#ifdef AS_ILLUMOS - "AS_ILLUMOS " -#endif -#ifdef AS_MARMALADE - "AS_MARMALADE " -#endif - - - // CPU family -#ifdef AS_PPC - "AS_PPC " -#endif -#ifdef AS_PPC_64 - "AS_PPC_64 " -#endif -#ifdef AS_X86 - "AS_X86 " -#endif -#ifdef AS_MIPS - "AS_MIPS " -#endif -#ifdef AS_SH4 - "AS_SH4 " -#endif -#ifdef AS_XENON - "AS_XENON " -#endif -#ifdef AS_ARM - "AS_ARM " -#endif -#ifdef AS_SOFTFP - "AS_SOFTFP " -#endif -#ifdef AS_X64_GCC - "AS_X64_GCC " -#endif -#ifdef AS_X64_MSVC - "AS_X64_MSVC " -#endif -#ifdef AS_SPARC - "AS_SPARC " -#endif - ; - - return string; -} - -AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version) -{ - // Verify the version that the application expects - if( (version/10000) != (ANGELSCRIPT_VERSION/10000) ) - return 0; - - if( (version/100)%100 != (ANGELSCRIPT_VERSION/100)%100 ) - return 0; - - if( (version%100) > (ANGELSCRIPT_VERSION%100) ) - return 0; - - // Verify the size of the types - asASSERT( sizeof(asBYTE) == 1 ); - asASSERT( sizeof(asWORD) == 2 ); - asASSERT( sizeof(asDWORD) == 4 ); - asASSERT( sizeof(asQWORD) == 8 ); - asASSERT( sizeof(asPWORD) == sizeof(void*) ); - - // Verify the boolean type - asASSERT( sizeof(bool) == AS_SIZEOF_BOOL ); - asASSERT( true == VALUE_OF_BOOLEAN_TRUE ); - - // Verify endianess -#ifdef AS_BIG_ENDIAN - asDWORD dw = 0x00010203; - asQWORD qw = ((asQWORD(0x00010203)<<32)|asQWORD(0x04050607)); -#else - asDWORD dw = 0x03020100; - // C++ didn't have a standard way of declaring 64bit literal constants until C++11, so - // I'm forced to do it like this to avoid compilers warnings when compiling with the full - // C++ compliance. - asQWORD qw = ((asQWORD(0x07060504)<<32)|asQWORD(0x03020100)); -#endif - asASSERT( memcmp("\x00\x01\x02\x03", &dw, 4) == 0 ); - asASSERT( memcmp("\x00\x01\x02\x03\x04\x05\x06\x07", &qw, 8) == 0 ); - UNUSED_VAR(dw); - UNUSED_VAR(qw); - - return asNEW(asCScriptEngine)(); -} - -} // extern "C" - - -// interface -int asCScriptEngine::SetEngineProperty(asEEngineProp property, asPWORD value) -{ - switch( property ) - { - case asEP_ALLOW_UNSAFE_REFERENCES: - ep.allowUnsafeReferences = value ? true : false; - break; - - case asEP_OPTIMIZE_BYTECODE: - ep.optimizeByteCode = value ? true : false; - break; - - case asEP_COPY_SCRIPT_SECTIONS: - ep.copyScriptSections = value ? true : false; - break; - - case asEP_MAX_STACK_SIZE: - if( value == 0 ) - { - // Restore default: no limit and initially size 4KB - ep.maximumContextStackSize = 0; - initialContextStackSize = 1024; - } - else - { - // The size is given in bytes, but we only store dwords - ep.maximumContextStackSize = (asUINT)value/4; - if( initialContextStackSize > ep.maximumContextStackSize ) - { - initialContextStackSize = ep.maximumContextStackSize; - if( initialContextStackSize == 0 ) - initialContextStackSize = 1; - } - } - break; - - case asEP_USE_CHARACTER_LITERALS: - ep.useCharacterLiterals = value ? true : false; - break; - - case asEP_ALLOW_MULTILINE_STRINGS: - ep.allowMultilineStrings = value ? true : false; - break; - - case asEP_ALLOW_IMPLICIT_HANDLE_TYPES: - ep.allowImplicitHandleTypes = value ? true : false; - break; - - case asEP_BUILD_WITHOUT_LINE_CUES: - ep.buildWithoutLineCues = value ? true : false; - break; - - case asEP_INIT_GLOBAL_VARS_AFTER_BUILD: - ep.initGlobalVarsAfterBuild = value ? true : false; - break; - - case asEP_REQUIRE_ENUM_SCOPE: - ep.requireEnumScope = value ? true : false; - break; - - case asEP_SCRIPT_SCANNER: - if( value <= 1 ) - ep.scanner = (int)value; - else - return asINVALID_ARG; - break; - - case asEP_INCLUDE_JIT_INSTRUCTIONS: - ep.includeJitInstructions = value ? true : false; - break; - - case asEP_STRING_ENCODING: - if( value <= 1 ) - ep.stringEncoding = (int)value; - else - return asINVALID_ARG; - break; - - case asEP_PROPERTY_ACCESSOR_MODE: - if( value <= 2 ) - ep.propertyAccessorMode = (int)value; - else - return asINVALID_ARG; - break; - - case asEP_EXPAND_DEF_ARRAY_TO_TMPL: - ep.expandDefaultArrayToTemplate = value ? true : false; - break; - - case asEP_AUTO_GARBAGE_COLLECT: - ep.autoGarbageCollect = value ? true : false; - break; - - case asEP_DISALLOW_GLOBAL_VARS: - ep.disallowGlobalVars = value ? true : false; - break; - - case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT: - ep.alwaysImplDefaultConstruct = value ? true : false; - break; - - case asEP_COMPILER_WARNINGS: - if( value <= 2 ) - ep.compilerWarnings = (int)value; - else - return asINVALID_ARG; - break; - - case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE: - ep.disallowValueAssignForRefType = value ? true : false; - break; - - case asEP_ALTER_SYNTAX_NAMED_ARGS: - if( value <= 2 ) - ep.alterSyntaxNamedArgs = (int)value; - else - return asINVALID_ARG; - break; - - case asEP_DISABLE_INTEGER_DIVISION: - ep.disableIntegerDivision = value ? true : false; - break; - - default: - return asINVALID_ARG; - } - - return asSUCCESS; -} - -// interface -asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const -{ - switch( property ) - { - case asEP_ALLOW_UNSAFE_REFERENCES: - return ep.allowUnsafeReferences; - - case asEP_OPTIMIZE_BYTECODE: - return ep.optimizeByteCode; - - case asEP_COPY_SCRIPT_SECTIONS: - return ep.copyScriptSections; - - case asEP_MAX_STACK_SIZE: - return ep.maximumContextStackSize*4; - - case asEP_USE_CHARACTER_LITERALS: - return ep.useCharacterLiterals; - - case asEP_ALLOW_MULTILINE_STRINGS: - return ep.allowMultilineStrings; - - case asEP_ALLOW_IMPLICIT_HANDLE_TYPES: - return ep.allowImplicitHandleTypes; - - case asEP_BUILD_WITHOUT_LINE_CUES: - return ep.buildWithoutLineCues; - - case asEP_INIT_GLOBAL_VARS_AFTER_BUILD: - return ep.initGlobalVarsAfterBuild; - - case asEP_REQUIRE_ENUM_SCOPE: - return ep.requireEnumScope; - - case asEP_SCRIPT_SCANNER: - return ep.scanner; - - case asEP_INCLUDE_JIT_INSTRUCTIONS: - return ep.includeJitInstructions; - - case asEP_STRING_ENCODING: - return ep.stringEncoding; - - case asEP_PROPERTY_ACCESSOR_MODE: - return ep.propertyAccessorMode; - - case asEP_EXPAND_DEF_ARRAY_TO_TMPL: - return ep.expandDefaultArrayToTemplate; - - case asEP_AUTO_GARBAGE_COLLECT: - return ep.autoGarbageCollect; - - case asEP_DISALLOW_GLOBAL_VARS: - return ep.disallowGlobalVars; - - case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT: - return ep.alwaysImplDefaultConstruct; - - case asEP_COMPILER_WARNINGS: - return ep.compilerWarnings; - - case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE: - return ep.disallowValueAssignForRefType; - - case asEP_ALTER_SYNTAX_NAMED_ARGS: - return ep.alterSyntaxNamedArgs; - - case asEP_DISABLE_INTEGER_DIVISION: - return ep.disableIntegerDivision; - - default: - return 0; - } - - UNREACHABLE_RETURN; -} - -// interface -asIScriptFunction *asCScriptEngine::CreateDelegate(asIScriptFunction *func, void *obj) -{ - if( func == 0 || obj == 0 ) - return 0; - - // The function must be a class method - asIObjectType *type = func->GetObjectType(); - if( type == 0 ) - return 0; - - // The object type must allow handles - if( (type->GetFlags() & asOBJ_REF) == 0 || (type->GetFlags() & (asOBJ_SCOPED | asOBJ_NOHANDLE)) ) - return 0; - - // Create the delegate the same way it would be created by the scripts - return AS_NAMESPACE_QUALIFIER CreateDelegate(reinterpret_cast(func), obj); -} - -asCScriptEngine::asCScriptEngine() -{ - asCThreadManager::Prepare(0); - - shuttingDown = false; - - // Engine properties - { - ep.allowUnsafeReferences = false; - ep.optimizeByteCode = true; - ep.copyScriptSections = true; - ep.maximumContextStackSize = 0; // no limit - ep.useCharacterLiterals = false; - ep.allowMultilineStrings = false; - ep.allowImplicitHandleTypes = false; - // TODO: optimize: Maybe this should be turned off by default? If a debugger is not used - // then this is just slowing down the execution. - ep.buildWithoutLineCues = false; - ep.initGlobalVarsAfterBuild = true; - ep.requireEnumScope = false; - ep.scanner = 1; // utf8. 0 = ascii - ep.includeJitInstructions = false; - ep.stringEncoding = 0; // utf8. 1 = utf16 - ep.propertyAccessorMode = 2; // 0 = disable, 1 = app registered only, 2 = app and script created - ep.expandDefaultArrayToTemplate = false; - ep.autoGarbageCollect = true; - ep.disallowGlobalVars = false; - ep.alwaysImplDefaultConstruct = false; - ep.compilerWarnings = 1; // 0 = no warnings, 1 = warning, 2 = treat as error - // TODO: 3.0.0: disallowValueAssignForRefType should be true by default - ep.disallowValueAssignForRefType = false; - ep.alterSyntaxNamedArgs = 0; // 0 = no alternate syntax, 1 = accept alternate syntax but warn, 2 = accept without warning - ep.disableIntegerDivision = false; - } - - gc.engine = this; - tok.engine = this; - - refCount.set(1); - stringFactory = 0; - configFailed = false; - isPrepared = false; - isBuilding = false; - deferValidationOfTemplateTypes = false; - lastModule = 0; - - - initialContextStackSize = 1024; // 4 KB (1024 * sizeof(asDWORD) - - - typeIdSeqNbr = 0; - currentGroup = &defaultGroup; - defaultAccessMask = 1; - - msgCallback = 0; - jitCompiler = 0; - - // Create the global namespace - defaultNamespace = AddNameSpace(""); - - requestCtxFunc = 0; - returnCtxFunc = 0; - ctxCallbackParam = 0; - - // We must set the namespace in the built-in types explicitly as - // this wasn't done by the default constructor. If we do not do - // this we will get null pointer access in other parts of the code - scriptTypeBehaviours.nameSpace = defaultNamespace; - functionBehaviours.nameSpace = defaultNamespace; - objectTypeBehaviours.nameSpace = defaultNamespace; - globalPropertyBehaviours.nameSpace = defaultNamespace; - - // Reserve function id 0 for no function - scriptFunctions.PushLast(0); - - // Make sure typeId for the built-in primitives are defined according to asETypeIdFlags - int id = 0; - UNUSED_VAR(id); // It is only used in debug mode - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)); asASSERT( id == asTYPEID_VOID ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)); asASSERT( id == asTYPEID_BOOL ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)); asASSERT( id == asTYPEID_INT8 ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)); asASSERT( id == asTYPEID_INT16 ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)); asASSERT( id == asTYPEID_INT32 ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)); asASSERT( id == asTYPEID_INT64 ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)); asASSERT( id == asTYPEID_UINT8 ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)); asASSERT( id == asTYPEID_UINT16 ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)); asASSERT( id == asTYPEID_UINT32 ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)); asASSERT( id == asTYPEID_UINT64 ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)); asASSERT( id == asTYPEID_FLOAT ); - id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)); asASSERT( id == asTYPEID_DOUBLE ); - - defaultArrayObjectType = 0; - - RegisterScriptObject(this); - RegisterScriptFunction(this); - RegisterObjectTypeGCBehaviours(this); - asCGlobalProperty::RegisterGCBehaviours(this); -} - -asCScriptEngine::~asCScriptEngine() -{ - shuttingDown = true; - - asASSERT(refCount.get() == 0); - asUINT n; - - // Clear the context callbacks. If new context's are needed for the clean-up the engine will take care of this itself. - // Context callbacks are normally used for pooling contexts, and if we allow new contexts to be created without being - // immediately destroyed afterwards it means the engine's refcount will increase. This is turn may cause memory access - // violations later on when the pool releases its contexts. - SetContextCallbacks(0, 0, 0); - - // The modules must be deleted first, as they may use - // object types from the config groups - for( n = (asUINT)scriptModules.GetLength(); n-- > 0; ) - if( scriptModules[n] ) - scriptModules[n]->Discard(); - scriptModules.SetLength(0); - - GarbageCollect(); - - if( defaultArrayObjectType ) - { - defaultArrayObjectType->Release(); - defaultArrayObjectType = 0; - } - - // Delete the functions for template types that may references object types - for( n = 0; n < templateInstanceTypes.GetLength(); n++ ) - { - if( templateInstanceTypes[n] ) - { - asUINT f; - asCObjectType *templateType = templateInstanceTypes[n]; - - // Delete the factory stubs first - for( f = 0; f < templateType->beh.factories.GetLength(); f++ ) - scriptFunctions[templateType->beh.factories[f]]->Release(); - templateType->beh.factories.Allocate(0, false); - - // The list factory is not stored in the list with the rest of the factories - if( templateType->beh.listFactory ) - { - scriptFunctions[templateType->beh.listFactory]->Release(); - templateType->beh.listFactory = 0; - } - - // Delete the specialized functions - for( f = 1; f < templateType->beh.operators.GetLength(); f += 2 ) - { - if( scriptFunctions[templateType->beh.operators[f]]->objectType == templateType ) - { - scriptFunctions[templateType->beh.operators[f]]->Release(); - templateType->beh.operators[f] = 0; - } - } - for( f = 0; f < templateType->methods.GetLength(); f++ ) - { - if( scriptFunctions[templateType->methods[f]]->objectType == templateType ) - { - scriptFunctions[templateType->methods[f]]->Release(); - templateType->methods[f] = 0; - } - } - } - } - - // Do one more garbage collect to free gc objects that were global variables - GarbageCollect(); - FreeUnusedGlobalProperties(); - ClearUnusedTypes(); - - // Break all relationship between remaining class types and functions - for( n = 0; n < scriptTypes.GetLength(); n++ ) - { - if( scriptTypes[n] ) - scriptTypes[n]->ReleaseAllFunctions(); - - if( scriptTypes[n]->derivedFrom ) - { - scriptTypes[n]->derivedFrom->Release(); - scriptTypes[n]->derivedFrom = 0; - } - } - - GarbageCollect(); - FreeUnusedGlobalProperties(); - ClearUnusedTypes(); - - // Destroy internals of script functions that may still be kept alive outside of engine - for( n = 0; n < scriptFunctions.GetLength(); n++ ) - if( scriptFunctions[n] && scriptFunctions[n]->funcType == asFUNC_SCRIPT ) - scriptFunctions[n]->DestroyInternal(); - - // There may be instances where one more gc cycle must be run - GarbageCollect(); - ClearUnusedTypes(); - - // It is allowed to create new references to the engine temporarily while destroying objects - // but these references must be release immediately or else something is can go wrong later on - if( refCount.get() > 0 ) - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN); - - // If the application hasn't registered GC behaviours for all types - // that can form circular references with script types, then there - // may still be objects in the GC. - if( gc.ReportAndReleaseUndestroyedObjects() > 0 ) - { - // Some items cannot be destroyed because the application is still holding on to them - - // Make sure the script functions won't attempt to access the engine if they are destroyed later on - for( n = 0; n < scriptFunctions.GetLength(); n++ ) - if( scriptFunctions[n] && scriptFunctions[n]->funcType == asFUNC_SCRIPT ) - scriptFunctions[n]->engine = 0; - } - - asSMapNode *cursor = 0; - while( mapTypeIdToDataType.MoveFirst(&cursor) ) - { - asDELETE(mapTypeIdToDataType.GetValue(cursor),asCDataType); - mapTypeIdToDataType.Erase(cursor); - } - - // First remove what is not used, so that other groups can be deleted safely - defaultGroup.RemoveConfiguration(this, true); - while( configGroups.GetLength() ) - { - // Delete config groups in the right order - asCConfigGroup *grp = configGroups.PopLast(); - if( grp ) - { - grp->RemoveConfiguration(this); - asDELETE(grp,asCConfigGroup); - } - } - // Remove what is remaining - defaultGroup.RemoveConfiguration(this); - - asCSymbolTable::iterator it = registeredGlobalProps.List(); - for( ; it; it++ ) - (*it)->Release(); - registeredGlobalProps.Clear(); - FreeUnusedGlobalProperties(); - - for( n = 0; n < templateInstanceTypes.GetLength(); n++ ) - { - if( templateInstanceTypes[n] ) - templateInstanceTypes[n]->DropFromEngine(); - } - templateInstanceTypes.SetLength(0); - - asSMapNode *cursor2; - allRegisteredTypes.MoveFirst(&cursor2); - while( cursor2 ) - { - // Clear the sub types before deleting the template type so that the sub types aren't freed to soon - cursor2->value->templateSubTypes.SetLength(0); - cursor2->value->DropFromEngine(); - - allRegisteredTypes.MoveNext(&cursor2, cursor2); - } - allRegisteredTypes.EraseAll(); - for( n = 0; n < templateSubTypes.GetLength(); n++ ) - { - if( templateSubTypes[n] ) - asDELETE(templateSubTypes[n], asCObjectType); - } - templateSubTypes.SetLength(0); - registeredTypeDefs.SetLength(0); - registeredEnums.SetLength(0); - registeredObjTypes.SetLength(0); - - asCSymbolTable::iterator funcIt = registeredGlobalFuncs.List(); - for( ; funcIt; funcIt++ ) - (*funcIt)->Release(); - registeredGlobalFuncs.Clear(); - - scriptTypeBehaviours.ReleaseAllFunctions(); - functionBehaviours.ReleaseAllFunctions(); - objectTypeBehaviours.ReleaseAllFunctions(); - globalPropertyBehaviours.ReleaseAllFunctions(); - - // Destroy the funcdefs - // As funcdefs are shared between modules it shouldn't be a problem to keep the objects until the engine is released - // TODO: refactor: This really should be done by ClearUnusedTypes() as soon as the funcdef is no longer is use. - // Perhaps to make it easier to manage the memory for funcdefs each function definition should - // have it's own object type. That would make the funcdef much more similar to the other types - // and could then be handled in much the same way. When this is done the funcdef should also be - // changed so that it doesn't take up a function id, i.e. don't keep a reference to it in scriptFunctions. - for( n = 0; n < funcDefs.GetLength(); n++ ) - if( funcDefs[n] ) - { - asASSERT( funcDefs[n]->GetRefCount() == 0 ); - asDELETE(funcDefs[n], asCScriptFunction); - } - funcDefs.SetLength(0); - - // Free string constants - for( n = 0; n < stringConstants.GetLength(); n++ ) - asDELETE(stringConstants[n],asCString); - stringConstants.SetLength(0); - stringToIdMap.EraseAll(); - - // Free the script section names - for( n = 0; n < scriptSectionNames.GetLength(); n++ ) - asDELETE(scriptSectionNames[n],asCString); - scriptSectionNames.SetLength(0); - - // Clean the user data - for( n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n+1] ) - { - for( asUINT c = 0; c < cleanEngineFuncs.GetLength(); c++ ) - if( cleanEngineFuncs[c].type == userData[n] ) - cleanEngineFuncs[c].cleanFunc(this); - } - } - - // Free namespaces - for( n = 0; n < nameSpaces.GetLength(); n++ ) - asDELETE(nameSpaces[n], asSNameSpace); - nameSpaces.SetLength(0); - - asCThreadManager::Unprepare(); -} - -// internal -void asCScriptEngine::CleanupAfterDiscardModule() -{ - // Skip this when shutting down as it will be done anyway by the engine destructor - if( shuttingDown ) return; - - if( ep.autoGarbageCollect ) - GarbageCollect(); - - FreeUnusedGlobalProperties(); - ClearUnusedTypes(); -} - -// interface -int asCScriptEngine::SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param) -{ - // Both callbacks or neither must be set - if( (requestCtx == 0 && returnCtx != 0) || (requestCtx != 0 && returnCtx == 0) ) - return asINVALID_ARG; - - requestCtxFunc = requestCtx; - returnCtxFunc = returnCtx; - ctxCallbackParam = param; - - return 0; -} - -// interface -asIScriptContext *asCScriptEngine::RequestContext() -{ - if( requestCtxFunc ) - { - // The return callback must also exist - asASSERT( returnCtxFunc ); - - asIScriptContext *ctx = requestCtxFunc(this, ctxCallbackParam); - return ctx; - } - - // As fallback we create a new context - return CreateContext(); -} - -// interface -void asCScriptEngine::ReturnContext(asIScriptContext *ctx) -{ - if( returnCtxFunc ) - { - returnCtxFunc(this, ctx, ctxCallbackParam); - return; - } - - // As fallback we just release the context - if( ctx ) - ctx->Release(); -} - -// interface -int asCScriptEngine::AddRef() const -{ - asASSERT( refCount.get() > 0 || shuttingDown ); - return refCount.atomicInc(); -} - -// interface -int asCScriptEngine::Release() const -{ - int r = refCount.atomicDec(); - - if( r == 0 ) - { - // It is possible that some function will temporarily increment the engine ref count - // during clean-up for example while destroying the objects in the garbage collector. - if( !shuttingDown ) - asDELETE(const_cast(this),asCScriptEngine); - return 0; - } - - return r; -} - -// internal -asSNameSpace *asCScriptEngine::AddNameSpace(const char *name) -{ - // First check if it doesn't exist already - asSNameSpace *ns = FindNameSpace(name); - if( ns ) return ns; - - ns = asNEW(asSNameSpace); - if( ns == 0 ) - { - // Out of memory - return 0; - } - ns->name = name; - - nameSpaces.PushLast(ns); - - return ns; -} - -// internal -asSNameSpace *asCScriptEngine::FindNameSpace(const char *name) -{ - // TODO: optimize: Improve linear search - for( asUINT n = 0; n < nameSpaces.GetLength(); n++ ) - if( nameSpaces[n]->name == name ) - return nameSpaces[n]; - - return 0; -} - -// interface -const char *asCScriptEngine::GetDefaultNamespace() const -{ - return defaultNamespace->name.AddressOf(); -} - -// interface -int asCScriptEngine::SetDefaultNamespace(const char *nameSpace) -{ - if( nameSpace == 0 ) - return ConfigError(asINVALID_ARG, "SetDefaultNamespace", nameSpace, 0); - - asCString ns = nameSpace; - if( ns != "" ) - { - // Make sure the namespace is composed of alternating identifier and :: - size_t pos = 0; - bool expectIdentifier = true; - size_t len; - eTokenType t = ttIdentifier; - - for( ; pos < ns.GetLength(); pos += len) - { - t = tok.GetToken(ns.AddressOf() + pos, ns.GetLength() - pos, &len); - if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) ) - return ConfigError(asINVALID_DECLARATION, "SetDefaultNamespace", nameSpace, 0); - - expectIdentifier = !expectIdentifier; - } - - // If the namespace ends with :: then strip it off - if( t == ttScope ) - ns.SetLength(ns.GetLength()-2); - } - - defaultNamespace = AddNameSpace(ns.AddressOf()); - - return 0; -} - -// interface -void *asCScriptEngine::SetUserData(void *data, asPWORD type) -{ - // As a thread might add a new new user data at the same time as another - // it is necessary to protect both read and write access to the userData member - ACQUIREEXCLUSIVE(engineRWLock); - - // It is not intended to store a lot of different types of userdata, - // so a more complex structure like a associative map would just have - // more overhead than a simple array. - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - void *oldData = reinterpret_cast(userData[n+1]); - userData[n+1] = reinterpret_cast(data); - - RELEASEEXCLUSIVE(engineRWLock); - - return oldData; - } - } - - userData.PushLast(type); - userData.PushLast(reinterpret_cast(data)); - - RELEASEEXCLUSIVE(engineRWLock); - - return 0; -} - -// interface -void *asCScriptEngine::GetUserData(asPWORD type) const -{ - // There may be multiple threads reading, but when - // setting the user data nobody must be reading. - ACQUIRESHARED(engineRWLock); - - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - RELEASESHARED(engineRWLock); - return reinterpret_cast(userData[n+1]); - } - } - - RELEASESHARED(engineRWLock); - - return 0; -} - -// interface -int asCScriptEngine::SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv) -{ - msgCallback = true; - msgCallbackObj = obj; - bool isObj = false; - if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST ) - { - msgCallback = false; - return asNOT_SUPPORTED; - } - if( (unsigned)callConv >= asCALL_THISCALL ) - { - isObj = true; - if( obj == 0 ) - { - msgCallback = false; - return asINVALID_ARG; - } - } - int r = DetectCallingConvention(isObj, callback, callConv, 0, &msgCallbackFunc); - if( r < 0 ) msgCallback = false; - return r; -} - -// interface -int asCScriptEngine::ClearMessageCallback() -{ - msgCallback = false; - return 0; -} - -// interface -int asCScriptEngine::WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message) -{ - // Validate input parameters - if( section == 0 || - message == 0 ) - return asINVALID_ARG; - - // If there is no callback then there's nothing to do - if( !msgCallback ) - return 0; - - // If a pre-message has been set, then write that first - if( preMessage.isSet ) - { - asSMessageInfo msg; - msg.section = preMessage.scriptname.AddressOf(); - msg.row = preMessage.r; - msg.col = preMessage.c; - msg.type = asMSGTYPE_INFORMATION; - msg.message = preMessage.message.AddressOf(); - - if( msgCallbackFunc.callConv < ICC_THISCALL ) - CallGlobalFunction(&msg, msgCallbackObj, &msgCallbackFunc, 0); - else - CallObjectMethod(msgCallbackObj, &msg, &msgCallbackFunc, 0); - - preMessage.isSet = false; - } - - // Write the message to the callback - asSMessageInfo msg; - msg.section = section; - msg.row = row; - msg.col = col; - msg.type = type; - msg.message = message; - - if( msgCallbackFunc.callConv < ICC_THISCALL ) - CallGlobalFunction(&msg, msgCallbackObj, &msgCallbackFunc, 0); - else - CallObjectMethod(msgCallbackObj, &msg, &msgCallbackFunc, 0); - - return 0; -} - -int asCScriptEngine::SetJITCompiler(asIJITCompiler *compiler) -{ - jitCompiler = compiler; - return asSUCCESS; -} - -asIJITCompiler *asCScriptEngine::GetJITCompiler() const -{ - return jitCompiler; -} - -// interface -// TODO: interface: tokenLength should be asUINT -asETokenClass asCScriptEngine::ParseToken(const char *string, size_t stringLength, int *tokenLength) const -{ - if( stringLength == 0 ) - stringLength = strlen(string); - - size_t len; - asETokenClass tc; - tok.GetToken(string, stringLength, &len, &tc); - - if( tokenLength ) - *tokenLength = (int)len; - - return tc; -} - -// interface -asIScriptModule *asCScriptEngine::GetModule(const char *module, asEGMFlags flag) -{ - asCModule *mod = GetModule(module, false); - - if( flag == asGM_ALWAYS_CREATE ) - { - if( mod != 0 ) - mod->Discard(); - - return GetModule(module, true); - } - - if( mod == 0 && flag == asGM_CREATE_IF_NOT_EXISTS ) - return GetModule(module, true); - - return mod; -} - -// interface -int asCScriptEngine::DiscardModule(const char *module) -{ - asCModule *mod = GetModule(module, false); - if( mod == 0 ) return asNO_MODULE; - - mod->Discard(); - - return 0; -} - -// interface -asUINT asCScriptEngine::GetModuleCount() const -{ - return asUINT(scriptModules.GetLength()); -} - -// interface -asIScriptModule *asCScriptEngine::GetModuleByIndex(asUINT index) const -{ - if( index >= scriptModules.GetLength() ) - return 0; - - return scriptModules[index]; -} - -// internal -int asCScriptEngine::ClearUnusedTypes() -{ - int clearCount = 0; - - // Build a list of all types to check for - // Use a set instead of an array to allow quicker searches - // TODO: optimize: Only orphaned types should be checked, since non-orphaned types are still owned by the modules - asCMap types; - for( asUINT n = 0; n < scriptTypes.GetLength(); n++ ) - { - if( !types.MoveTo(0, scriptTypes[n]) ) - types.Insert(scriptTypes[n], 0); - } - for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) - { - if( !types.MoveTo(0, generatedTemplateTypes[n]) ) - types.Insert(generatedTemplateTypes[n], 0); - } - - // Go through all modules - // TODO: optimize: If only the orphaned types was inserted in the types map, then this step is not necessary - asUINT n; - for( n = 0; n < scriptModules.GetLength() && types.GetCount(); n++ ) - { - asCModule *mod = scriptModules[n]; - if( mod ) - { - // Functions/Methods/Globals are handled after this - - // Go through all type declarations - asUINT m; - for( m = 0; m < mod->classTypes.GetLength() && types.GetCount(); m++ ) - RemoveTypeAndRelatedFromList(types, mod->classTypes[m]); - for( m = 0; m < mod->enumTypes.GetLength() && types.GetCount(); m++ ) - RemoveTypeAndRelatedFromList(types, mod->enumTypes[m]); - for( m = 0; m < mod->typeDefs.GetLength() && types.GetCount(); m++ ) - RemoveTypeAndRelatedFromList(types, mod->typeDefs[m]); - } - } - - // Go through all function parameters and remove used types - for( n = 0; n < scriptFunctions.GetLength() && types.GetCount(); n++ ) - { - asCScriptFunction *func = scriptFunctions[n]; - if( func ) - { - // Ignore factory stubs - if( func->name == "factstub" ) - continue; - - // Ignore funcdefs because these will only be destroyed when the engine is released - if( func->funcType == asFUNC_FUNCDEF ) - continue; - - asCObjectType *ot = func->returnType.GetObjectType(); - if( ot != 0 && ot != func->objectType ) - if( func->name != ot->name ) - RemoveTypeAndRelatedFromList(types, ot); - - for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ ) - { - ot = func->parameterTypes[p].GetObjectType(); - if( ot != 0 && ot != func->objectType ) - if( func->name != ot->name ) - RemoveTypeAndRelatedFromList(types, ot); - } - } - } - - // Go through all global properties - for( n = 0; n < globalProperties.GetLength() && types.GetCount(); n++ ) - { - if( globalProperties[n] && globalProperties[n]->type.GetObjectType() ) - RemoveTypeAndRelatedFromList(types, globalProperties[n]->type.GetObjectType()); - } - - // All that remains in the list after this can be discarded, since they are no longer used - for(;;) - { - bool didClearTemplateInstanceType = false; - - asSMapNode* node; - types.MoveFirst(&node); - - while( node ) - { - int typeRefCount = 0; - asCObjectType *type = node->key; - - // Template types and script classes will have two references for each factory stub - if( (type->flags & asOBJ_TEMPLATE) ) - { - typeRefCount = 2*(int)type->beh.factories.GetLength(); - if( type->beh.listFactory ) - typeRefCount += 2; - - // If it is an orphaned script type, then the gc holds 1 reference too - bool isScriptTemplate = false; - for( asUINT s = 0; s < type->templateSubTypes.GetLength(); s++ ) - { - if( type->templateSubTypes[s].GetObjectType() && (type->templateSubTypes[s].GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ) - { - isScriptTemplate = true; - break; - } - } - - if( isScriptTemplate && type->module == 0 ) - typeRefCount++; - } - - if( type->GetRefCount() == typeRefCount || type->GetRefCount() == 0 ) - { - if( type->flags & asOBJ_TEMPLATE ) - { - didClearTemplateInstanceType = true; - RemoveTemplateInstanceType(type); - clearCount++; - } - else - { - RemoveFromTypeIdMap(type); - type->DropFromEngine(); - clearCount++; - - scriptTypes.RemoveIndexUnordered(scriptTypes.IndexOf(type)); - } - - // Remove the type from the set - asSMapNode* cur = node; - types.MoveNext(&node, node); - types.Erase(cur); - continue; - } - - types.MoveNext(&node, node); - } - - if( didClearTemplateInstanceType == false ) - break; - } - - // Clear the list pattern types that are no longer used - for( n = 0; n < listPatternTypes.GetLength(); n++ ) - { - if( listPatternTypes[n]->refCount.get() == 0 ) - { - asDELETE(listPatternTypes[n], asCObjectType); - listPatternTypes.RemoveIndexUnordered(n); - n--; - } - } - - return clearCount; -} - -// Internal -void asCScriptEngine::RemoveTypeAndRelatedFromList(asCMap &types, asCObjectType *ot) -{ - // Remove the type from the list - asSMapNode* node; - if( !types.MoveTo(&node, ot) ) - return; - - types.Erase(node); - - // If the type is an template type then remove all sub types as well - for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) - { - if( ot->templateSubTypes[n].GetObjectType() ) - RemoveTypeAndRelatedFromList(types, ot->templateSubTypes[n].GetObjectType()); - } - - // If the type is a class then remove all properties types as well - if( ot->properties.GetLength() ) - { - for( asUINT n = 0; n < ot->properties.GetLength(); n++ ) - RemoveTypeAndRelatedFromList(types, ot->properties[n]->type.GetObjectType()); - } -} - -// internal -int asCScriptEngine::GetFactoryIdByDecl(const asCObjectType *ot, const char *decl) -{ - asCModule *mod = 0; - - // Is this a script class? - if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size > 0 ) - mod = scriptFunctions[ot->beh.factories[0]]->module; - - asCBuilder bld(this, mod); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCScriptFunction func(this, mod, asFUNC_DUMMY); - int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, defaultNamespace); - if( r < 0 ) - return asINVALID_DECLARATION; - - // Search for matching factory function - int id = -1; - for( size_t n = 0; n < ot->beh.factories.GetLength(); n++ ) - { - asCScriptFunction *f = scriptFunctions[ot->beh.factories[n]]; - if( f->IsSignatureEqual(&func) ) - { - id = ot->beh.factories[n]; - break; - } - } - - if( id == -1 ) return asNO_FUNCTION; - - return id; -} - - -// internal -int asCScriptEngine::GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod) -{ - asCBuilder bld(this, mod); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCScriptFunction func(this, mod, asFUNC_DUMMY); - - // Set the object type so that the signature can be properly compared - // This cast is OK, it will only be used for comparison - func.objectType = const_cast(ot); - - int r = bld.ParseFunctionDeclaration(func.objectType, decl, &func, false); - if( r < 0 ) - return asINVALID_DECLARATION; - - // Search script functions for matching interface - int id = -1; - for( size_t n = 0; n < ot->methods.GetLength(); ++n ) - { - if( func.IsSignatureEqual(scriptFunctions[ot->methods[n]]) ) - { - if( id == -1 ) - id = ot->methods[n]; - else - return asMULTIPLE_FUNCTIONS; - } - } - - if( id == -1 ) return asNO_FUNCTION; - - return id; -} - - -// internal -asCString asCScriptEngine::GetFunctionDeclaration(int funcId) -{ - asCString str; - asCScriptFunction *func = GetScriptFunction(funcId); - if( func ) - str = func->GetDeclarationStr(); - - return str; -} - -// internal -asCScriptFunction *asCScriptEngine::GetScriptFunction(int funcId) const -{ - if( funcId < 0 || funcId >= (int)scriptFunctions.GetLength() ) - return 0; - - return scriptFunctions[funcId]; -} - - -// interface -asIScriptContext *asCScriptEngine::CreateContext() -{ - asIScriptContext *ctx = 0; - CreateContext(&ctx, false); - return ctx; -} - -// internal -int asCScriptEngine::CreateContext(asIScriptContext **context, bool isInternal) -{ - *context = asNEW(asCContext)(this, !isInternal); - if( *context == 0 ) - return asOUT_OF_MEMORY; - - // We need to make sure the engine has been - // prepared before any context is executed - PrepareEngine(); - - return 0; -} - -// interface -int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset) -{ - int r; - asCDataType dt; - asCBuilder bld(this, 0); - r = bld.ParseDataType(obj, &dt, defaultNamespace); - if( r < 0 ) - return ConfigError(r, "RegisterObjectProperty", obj, declaration); - - // Verify that the correct config group is used - if( currentGroup->FindType(dt.GetObjectType()->name.AddressOf()) == 0 ) - return ConfigError(asWRONG_CONFIG_GROUP, "RegisterObjectProperty", obj, declaration); - - asCDataType type; - asCString name; - - if( (r = bld.VerifyProperty(&dt, declaration, name, type, 0)) < 0 ) - return ConfigError(r, "RegisterObjectProperty", obj, declaration); - - // Store the property info - if( dt.GetObjectType() == 0 || dt.IsObjectHandle() ) - return ConfigError(asINVALID_OBJECT, "RegisterObjectProperty", obj, declaration); - - // The VM currently only supports 16bit offsets - // TODO: The VM needs to have support for 32bit offsets. Probably with a second ADDSi instruction - // However, when implementing this it is necessary for the bytecode serialization to support - // the switch between the instructions upon loading bytecode as the offset may not be the - // same on all platforms - if( byteOffset > 32767 || byteOffset < -32768 ) - return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration); - - asCObjectProperty *prop = asNEW(asCObjectProperty); - if( prop == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectProperty", obj, declaration); - - prop->name = name; - prop->type = type; - prop->byteOffset = byteOffset; - prop->isPrivate = false; - prop->accessMask = defaultAccessMask; - - dt.GetObjectType()->properties.PushLast(prop); - - // Add references to types so they are not released too early - if( type.GetObjectType() ) - { - type.GetObjectType()->AddRef(); - - // Add template instances to the config group - if( (type.GetObjectType()->flags & asOBJ_TEMPLATE) && !currentGroup->objTypes.Exists(type.GetObjectType()) ) - currentGroup->objTypes.PushLast(type.GetObjectType()); - } - - currentGroup->RefConfigGroup(FindConfigGroupForObjectType(type.GetObjectType())); - - return asSUCCESS; -} - -// interface -int asCScriptEngine::RegisterInterface(const char *name) -{ - if( name == 0 ) return ConfigError(asINVALID_NAME, "RegisterInterface", 0, 0); - - // Verify if the name has been registered as a type already - // TODO: Must check against registered funcdefs too - if( GetRegisteredObjectType(name, defaultNamespace) ) - return asALREADY_REGISTERED; - - // Use builder to parse the datatype - asCDataType dt; - asCBuilder bld(this, 0); - bool oldMsgCallback = msgCallback; msgCallback = false; - int r = bld.ParseDataType(name, &dt, defaultNamespace); - msgCallback = oldMsgCallback; - if( r >= 0 ) return ConfigError(asERROR, "RegisterInterface", name, 0); - - // Make sure the name is not a reserved keyword - size_t tokenLen; - int token = tok.GetToken(name, strlen(name), &tokenLen); - if( token != ttIdentifier || strlen(name) != tokenLen ) - return ConfigError(asINVALID_NAME, "RegisterInterface", name, 0); - - r = bld.CheckNameConflict(name, 0, 0, defaultNamespace); - if( r < 0 ) - return ConfigError(asNAME_TAKEN, "RegisterInterface", name, 0); - - // Don't have to check against members of object - // types as they are allowed to use the names - - // Register the object type for the interface - asCObjectType *st = asNEW(asCObjectType)(this); - if( st == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterInterface", name, 0); - - st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_SHARED; - st->size = 0; // Cannot be instantiated - st->name = name; - st->nameSpace = defaultNamespace; - - // Use the default script class behaviours - st->beh.factory = 0; - st->beh.addref = scriptTypeBehaviours.beh.addref; - scriptFunctions[st->beh.addref]->AddRef(); - st->beh.release = scriptTypeBehaviours.beh.release; - scriptFunctions[st->beh.release]->AddRef(); - st->beh.copy = 0; - - allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); - registeredObjTypes.PushLast(st); - - currentGroup->objTypes.PushLast(st); - - return asSUCCESS; -} - -// interface -int asCScriptEngine::RegisterInterfaceMethod(const char *intf, const char *declaration) -{ - // Verify that the correct config group is set. - if( currentGroup->FindType(intf) == 0 ) - return ConfigError(asWRONG_CONFIG_GROUP, "RegisterInterfaceMethod", intf, declaration); - - asCDataType dt; - asCBuilder bld(this, 0); - int r = bld.ParseDataType(intf, &dt, defaultNamespace); - if( r < 0 ) - return ConfigError(r, "RegisterInterfaceMethod", intf, declaration); - - asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_INTERFACE); - if( func == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterInterfaceMethod", intf, declaration); - - func->objectType = dt.GetObjectType(); - - r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, false); - if( r < 0 ) - { - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asINVALID_DECLARATION, "RegisterInterfaceMethod", intf, declaration); - } - - // Check name conflicts - r = bld.CheckNameConflictMember(dt.GetObjectType(), func->name.AddressOf(), 0, 0, false); - if( r < 0 ) - { - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asNAME_TAKEN, "RegisterInterfaceMethod", intf, declaration); - } - - func->id = GetNextScriptFunctionId(); - SetScriptFunction(func); - - // The index into the interface's vftable chunk should be - // its index in the methods array. - func->vfTableIdx = int(func->objectType->methods.GetLength()); - - func->objectType->methods.PushLast(func->id); - - func->ComputeSignatureId(); - - // If parameter type from other groups are used, add references - // TODO: The code for adding references to config groups is repeated in a lot of places - if( func->returnType.GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType()); - currentGroup->RefConfigGroup(group); - } - for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( func->parameterTypes[n].GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->parameterTypes[n].GetObjectType()); - currentGroup->RefConfigGroup(group); - } - } - - // Return function id as success - return func->id; -} - -int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD flags) -{ - int r; - - isPrepared = false; - - // Verify flags - // Must have either asOBJ_REF or asOBJ_VALUE - if( flags & asOBJ_REF ) - { - // Can optionally have the asOBJ_GC, asOBJ_NOHANDLE, asOBJ_SCOPED, or asOBJ_TEMPLATE flag set, but nothing else - if( flags & ~(asOBJ_REF | asOBJ_GC | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_TEMPLATE | asOBJ_NOCOUNT) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - - // flags are exclusive - if( (flags & asOBJ_GC) && (flags & (asOBJ_NOHANDLE|asOBJ_SCOPED|asOBJ_NOCOUNT)) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - if( (flags & asOBJ_NOHANDLE) && (flags & (asOBJ_GC|asOBJ_SCOPED|asOBJ_NOCOUNT)) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - if( (flags & asOBJ_SCOPED) && (flags & (asOBJ_GC|asOBJ_NOHANDLE|asOBJ_NOCOUNT)) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - if( (flags & asOBJ_NOCOUNT) && (flags & (asOBJ_GC|asOBJ_NOHANDLE|asOBJ_SCOPED)) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - } - else if( flags & asOBJ_VALUE ) - { - // Cannot use reference flags - if( flags & (asOBJ_REF | asOBJ_GC | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_NOCOUNT) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - - // Flags are exclusive - if( (flags & asOBJ_POD) && (flags & (asOBJ_ASHANDLE | asOBJ_TEMPLATE)) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - - // If the app type is given, we must validate the flags - if( flags & asOBJ_APP_CLASS ) - { - // Must not set the primitive or float flag - if( flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - } - else - { - // Must not set the class properties, without the class flag - if( flags & (asOBJ_APP_CLASS_CONSTRUCTOR | - asOBJ_APP_CLASS_DESTRUCTOR | - asOBJ_APP_CLASS_ASSIGNMENT | - asOBJ_APP_CLASS_COPY_CONSTRUCTOR | - asOBJ_APP_CLASS_ALLINTS | - asOBJ_APP_CLASS_ALLFLOATS) ) - { - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - } - } - - if( flags & asOBJ_APP_PRIMITIVE ) - { - if( flags & (asOBJ_APP_CLASS | - asOBJ_APP_FLOAT | - asOBJ_APP_ARRAY) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - } - else if( flags & asOBJ_APP_FLOAT ) - { - if( flags & (asOBJ_APP_CLASS | - asOBJ_APP_PRIMITIVE | - asOBJ_APP_ARRAY) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - } - else if( flags & asOBJ_APP_ARRAY ) - { - if( flags & (asOBJ_APP_CLASS | - asOBJ_APP_PRIMITIVE | - asOBJ_APP_FLOAT) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - } - } - else - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - - // Don't allow anything else than the defined flags -#ifndef WIP_16BYTE_ALIGN - if( flags - (flags & asOBJ_MASK_VALID_FLAGS) ) -#else - if( flags - (flags & (asOBJ_MASK_VALID_FLAGS | asOBJ_APP_ALIGN16)) ) -#endif - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - - // Value types must have a defined size - if( (flags & asOBJ_VALUE) && byteSize == 0 ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_VALUE_TYPE_MUST_HAVE_SIZE); - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - } - - // Verify type name - if( name == 0 ) - return ConfigError(asINVALID_NAME, "RegisterObjectType", name, 0); - - asCString typeName; - asCBuilder bld(this, 0); - if( flags & asOBJ_TEMPLATE ) - { - asCArray subtypeNames; - r = bld.ParseTemplateDecl(name, &typeName, subtypeNames); - if( r < 0 ) - return ConfigError(r, "RegisterObjectType", name, 0); - - // Verify that the template name hasn't been registered as a type already - // TODO: Must check against registered funcdefs too - if( GetRegisteredObjectType(typeName, defaultNamespace) ) - // This is not an irrepairable error, as it may just be that the same type is registered twice - return asALREADY_REGISTERED; - - asCObjectType *type = asNEW(asCObjectType)(this); - if( type == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); - - type->name = typeName; - type->nameSpace = defaultNamespace; - type->size = byteSize; -#ifdef WIP_16BYTE_ALIGN - // TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries - type->alignment = (flags & asOBJ_APP_ALIGN16) ? 16 : 4; -#endif - type->flags = flags; - type->accessMask = defaultAccessMask; - - // Store it in the object types - allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); - currentGroup->objTypes.PushLast(type); - registeredObjTypes.PushLast(type); - registeredTemplateTypes.PushLast(type); - - // Define the template subtypes - for( asUINT subTypeIdx = 0; subTypeIdx < subtypeNames.GetLength(); subTypeIdx++ ) - { - asCObjectType *subtype = 0; - for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ ) - { - if( templateSubTypes[n]->name == subtypeNames[subTypeIdx] ) - { - subtype = templateSubTypes[n]; - break; - } - } - if( subtype == 0 ) - { - // Create the new subtype if not already existing - subtype = asNEW(asCObjectType)(this); - if( subtype == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); - - subtype->name = subtypeNames[subTypeIdx]; - subtype->size = 0; -#ifdef WIP_16BYTE_ALIGN - type->alignment = 0; // template subtypes cannot be instantiated and don't need alignment -#endif - subtype->flags = asOBJ_TEMPLATE_SUBTYPE; - templateSubTypes.PushLast(subtype); - subtype->AddRef(); - } - type->templateSubTypes.PushLast(asCDataType::CreateObject(subtype, false)); - subtype->AddRef(); - } - } - else - { - typeName = name; - - // Verify if the name has been registered as a type already - // TODO: Must check against registered funcdefs too - if( GetRegisteredObjectType(typeName, defaultNamespace) ) - // This is not an irrepairable error, as it may just be that the same type is registered twice - return asALREADY_REGISTERED; - - // TODO: clean up: Is it really necessary to check here? - for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ ) - { - if( templateInstanceTypes[n] && - templateInstanceTypes[n]->name == typeName && - templateInstanceTypes[n]->nameSpace == defaultNamespace ) - // This is not an irrepairable error, as it may just be that the same type is registered twice - return asALREADY_REGISTERED; - } - - // Keep the most recent template generated instance type, so we know what it was before parsing the datatype - asCObjectType *mostRecentTemplateInstanceType = 0; - if( generatedTemplateTypes.GetLength() ) - mostRecentTemplateInstanceType = generatedTemplateTypes[generatedTemplateTypes.GetLength()-1]; - - // Use builder to parse the datatype - asCDataType dt; - bool oldMsgCallback = msgCallback; msgCallback = false; - r = bld.ParseDataType(name, &dt, defaultNamespace); - msgCallback = oldMsgCallback; - - // If the builder fails or the namespace is different than the default - // namespace, then the type name is new and it should be registered - if( r < 0 || dt.GetObjectType()->nameSpace != defaultNamespace ) - { - // Make sure the name is not a reserved keyword - size_t tokenLen; - int token = tok.GetToken(name, typeName.GetLength(), &tokenLen); - if( token != ttIdentifier || typeName.GetLength() != tokenLen ) - return ConfigError(asINVALID_NAME, "RegisterObjectType", name, 0); - - int r = bld.CheckNameConflict(name, 0, 0, defaultNamespace); - if( r < 0 ) - return ConfigError(asNAME_TAKEN, "RegisterObjectType", name, 0); - - // Don't have to check against members of object - // types as they are allowed to use the names - - // Put the data type in the list - asCObjectType *type = asNEW(asCObjectType)(this); - if( type == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); - - type->name = typeName; - type->nameSpace = defaultNamespace; - type->size = byteSize; -#ifdef WIP_16BYTE_ALIGN - // TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries - type->alignment = (flags & asOBJ_APP_ALIGN16) ? 16 : 4; -#endif - type->flags = flags; - type->accessMask = defaultAccessMask; - - allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); - registeredObjTypes.PushLast(type); - - currentGroup->objTypes.PushLast(type); - } - else - { - // The application is registering a template specialization so we - // need to replace the template instance type with the new type. - - // TODO: Template: We don't require the lower dimensions to be registered first for registered template types - // int[][] must not be allowed to be registered - // if int[] hasn't been registered first - if( dt.GetSubType().IsTemplate() ) - return ConfigError(asLOWER_ARRAY_DIMENSION_NOT_REGISTERED, "RegisterObjectType", name, 0); - - if( dt.IsReadOnly() || - dt.IsReference() ) - return ConfigError(asINVALID_TYPE, "RegisterObjectType", name, 0); - - // Was the template instance type created before? - if( (generatedTemplateTypes.GetLength() && - generatedTemplateTypes[generatedTemplateTypes.GetLength()-1] == mostRecentTemplateInstanceType) || - mostRecentTemplateInstanceType == dt.GetObjectType() ) - // TODO: Should have a better error message - return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0); - - // If this is not a template instance type, then it means it is an - // already registered template specialization - if( !generatedTemplateTypes.Exists(dt.GetObjectType()) ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectType", name, 0); - - // TODO: Add this again. The type is used by the factory stubs so we need to discount that - // Is the template instance type already being used? -// if( dt.GetObjectType()->GetRefCount() > 1 ) -// return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0); - - // Put the data type in the list - asCObjectType *type = asNEW(asCObjectType)(this); - if( type == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); - - type->name = dt.GetObjectType()->name; - // The namespace will be the same as the original template type - type->nameSpace = dt.GetObjectType()->nameSpace; - type->templateSubTypes.PushLast(dt.GetSubType()); - for( asUINT s = 0; s < type->templateSubTypes.GetLength(); s++ ) - if( type->templateSubTypes[s].GetObjectType() ) - type->templateSubTypes[s].GetObjectType()->AddRef(); - type->size = byteSize; -#ifdef WIP_16BYTE_ALIGN - // TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries - type->alignment = (flags & asOBJ_APP_ALIGN16) ? 16 : 4; -#endif - type->flags = flags; - type->accessMask = defaultAccessMask; - - templateInstanceTypes.PushLast(type); - - currentGroup->objTypes.PushLast(type); - - // Remove the template instance type, which will no longer be used. - RemoveTemplateInstanceType(dt.GetObjectType()); - } - } - - // Return the type id as the success (except for template types) - if( flags & asOBJ_TEMPLATE ) - return asSUCCESS; - - return GetTypeIdByDecl(name); -} - -// interface -int asCScriptEngine::RegisterObjectBehaviour(const char *datatype, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) -{ - if( datatype == 0 ) return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", datatype, decl); - - // Determine the object type - asCBuilder bld(this, 0); - asCDataType type; - int r = bld.ParseDataType(datatype, &type, defaultNamespace); - if( r < 0 ) - return ConfigError(r, "RegisterObjectBehaviour", datatype, decl); - - if( type.GetObjectType() == 0 || type.IsObjectHandle() ) - return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); - - // Don't allow application to modify built-in types - if( type.GetObjectType() == &functionBehaviours || - type.GetObjectType() == &objectTypeBehaviours || - type.GetObjectType() == &globalPropertyBehaviours || - type.GetObjectType() == &scriptTypeBehaviours ) - return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); - - if( type.IsReadOnly() || type.IsReference() ) - return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); - - return RegisterBehaviourToObjectType(type.GetObjectType(), behaviour, decl, funcPointer, callConv, objForThiscall); -} - -// internal -int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) -{ -#ifdef AS_MAX_PORTABILITY - if( callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); -#endif - - asSSystemFunctionInterface internal; - bool isMethod = !(behaviour == asBEHAVE_FACTORY || - behaviour == asBEHAVE_LIST_FACTORY || - behaviour == asBEHAVE_TEMPLATE_CALLBACK); - int r = DetectCallingConvention(isMethod, funcPointer, callConv, objForThiscall, &internal); - if( r < 0 ) - return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - isPrepared = false; - - asSTypeBehaviour *beh = &objectType->beh; - - // Verify function declaration - asCScriptFunction func(this, 0, asFUNC_DUMMY); - - bool expectListPattern = behaviour == asBEHAVE_LIST_FACTORY || behaviour == asBEHAVE_LIST_CONSTRUCT; - asCScriptNode *listPattern = 0; - asCBuilder bld(this, 0); - r = bld.ParseFunctionDeclaration(objectType, decl, &func, true, &internal.paramAutoHandles, &internal.returnAutoHandle, 0, expectListPattern ? &listPattern : 0); - if( r < 0 ) - { - if( listPattern ) - listPattern->Destroy(this); - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - func.name.Format("_beh_%d_", behaviour); - - if( behaviour != asBEHAVE_FACTORY && behaviour != asBEHAVE_LIST_FACTORY ) - func.objectType = objectType; - - // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType - // Check if the method restricts that use of the template to value types or reference types - if( objectType->flags & asOBJ_TEMPLATE ) - { - for( asUINT subTypeIdx = 0; subTypeIdx < objectType->templateSubTypes.GetLength(); subTypeIdx++ ) - { - if( func.returnType.GetObjectType() == objectType->templateSubTypes[subTypeIdx].GetObjectType() ) - { - if( func.returnType.IsObjectHandle() ) - objectType->acceptValueSubType = false; - else if( !func.returnType.IsReference() ) - objectType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if( !func.returnType.IsObjectHandle() && !func.returnType.IsReference() ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), decl); - } - - for( asUINT n = 0; n < func.parameterTypes.GetLength(); n++ ) - { - if( func.parameterTypes[n].GetObjectType() == objectType->templateSubTypes[subTypeIdx].GetObjectType() ) - { - // TODO: If unsafe references are allowed, then inout references allow value types - if( func.parameterTypes[n].IsObjectHandle() || (func.parameterTypes[n].IsReference() && func.inOutFlags[n] == asTM_INOUTREF) ) - objectType->acceptValueSubType = false; - else if( !func.parameterTypes[n].IsReference() ) - objectType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if( !func.parameterTypes[n].IsObjectHandle() && !func.parameterTypes[n].IsReference() ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), decl); - } - } - } - } - - if( behaviour == asBEHAVE_CONSTRUCT ) - { - // Verify that the return type is void - if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - if( objectType->flags & asOBJ_SCRIPT_OBJECT ) - { - // The script object is a special case - asASSERT(func.parameterTypes.GetLength() == 1); - - beh->construct = AddBehaviourFunction(func, internal); - beh->factory = beh->construct; - scriptFunctions[beh->factory]->AddRef(); - beh->constructors.PushLast(beh->construct); - beh->factories.PushLast(beh->factory); - func.id = beh->construct; - } - else - { - // Verify that it is a value type - if( !(func.objectType->flags & asOBJ_VALUE) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // The templates take a hidden parameter with the object type - if( (objectType->flags & asOBJ_TEMPLATE) && - (func.parameterTypes.GetLength() == 0 || - !func.parameterTypes[0].IsReference()) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY); - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // TODO: Verify that the same constructor hasn't been registered already - - // Store all constructors in a list - func.id = AddBehaviourFunction(func, internal); - beh->constructors.PushLast(func.id); - if( func.parameterTypes.GetLength() == 0 || - (func.parameterTypes.GetLength() == 1 && (objectType->flags & asOBJ_TEMPLATE)) ) - { - beh->construct = func.id; - } - else if( func.parameterTypes.GetLength() == 1 ) - { - // Is this the copy constructor? - asCDataType paramType = func.parameterTypes[0]; - - // If the parameter is object, and const reference for input or inout, - // and same type as this class, then this is a copy constructor. - if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() && - (func.inOutFlags[0] & asTM_INREF) && paramType.GetObjectType() == objectType ) - beh->copyconstruct = func.id; - } - } - } - else if( behaviour == asBEHAVE_DESTRUCT ) - { - // Must be a value type - if( !(func.objectType->flags & asOBJ_VALUE) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - if( beh->destruct ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that the return type is void - if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that there are no parameters - if( func.parameterTypes.GetLength() > 0 ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - func.id = beh->destruct = AddBehaviourFunction(func, internal); - } - else if( behaviour == asBEHAVE_LIST_CONSTRUCT ) - { - // Verify that the return type is void - if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) - { - if( listPattern ) - listPattern->Destroy(this); - - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Verify that it is a value type - if( !(func.objectType->flags & asOBJ_VALUE) ) - { - if( listPattern ) - listPattern->Destroy(this); - - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Verify the parameters - if( func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference() ) - { - if( listPattern ) - listPattern->Destroy(this); - - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM); - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Don't accept duplicates - if( beh->listFactory ) - { - if( listPattern ) - listPattern->Destroy(this); - - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Add the function - func.id = AddBehaviourFunction(func, internal); - - // Re-use the listFactory member, as it is not possible to have both anyway - beh->listFactory = func.id; - - // Store the list pattern for this function - int r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern); - - if( listPattern ) - listPattern->Destroy(this); - - if( r < 0 ) - return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - else if( behaviour == asBEHAVE_FACTORY || behaviour == asBEHAVE_LIST_FACTORY ) - { - // Must be a ref type and must not have asOBJ_NOHANDLE - if( !(objectType->flags & asOBJ_REF) || (objectType->flags & asOBJ_NOHANDLE) ) - { - if( listPattern ) - listPattern->Destroy(this); - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Verify that the return type is a handle to the type - if( func.returnType != asCDataType::CreateObjectHandle(objectType, false) ) - { - if( listPattern ) - listPattern->Destroy(this); - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // The templates take a hidden parameter with the object type - if( (objectType->flags & asOBJ_TEMPLATE) && - (func.parameterTypes.GetLength() == 0 || - !func.parameterTypes[0].IsReference()) ) - { - if( listPattern ) - listPattern->Destroy(this); - - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY); - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - if( behaviour == asBEHAVE_LIST_FACTORY ) - { - // Make sure the factory takes a reference as its last parameter - if( objectType->flags & asOBJ_TEMPLATE ) - { - if( func.parameterTypes.GetLength() != 2 || !func.parameterTypes[1].IsReference() ) - { - if( listPattern ) - listPattern->Destroy(this); - - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_TEMPLATE_LIST_FACTORY_EXPECTS_2_REF_PARAMS); - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - } - else - { - if( func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference() ) - { - if( listPattern ) - listPattern->Destroy(this); - - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM); - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - } - } - - // TODO: Verify that the same factory function hasn't been registered already - - // Don't accept duplicates - if( behaviour == asBEHAVE_LIST_FACTORY && beh->listFactory ) - { - if( listPattern ) - listPattern->Destroy(this); - - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Store all factory functions in a list - func.id = AddBehaviourFunction(func, internal); - - // The list factory is a special factory and isn't stored together with the rest - if( behaviour != asBEHAVE_LIST_FACTORY ) - beh->factories.PushLast(func.id); - - if( (func.parameterTypes.GetLength() == 0) || - (func.parameterTypes.GetLength() == 1 && (objectType->flags & asOBJ_TEMPLATE)) ) - { - beh->factory = func.id; - } - else if( (func.parameterTypes.GetLength() == 1) || - (func.parameterTypes.GetLength() == 2 && (objectType->flags & asOBJ_TEMPLATE)) ) - { - if( behaviour == asBEHAVE_LIST_FACTORY ) - { - beh->listFactory = func.id; - - // Store the list pattern for this function - int r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern); - - if( listPattern ) - listPattern->Destroy(this); - - if( r < 0 ) - return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - else - { - // Is this the copy factory? - asCDataType paramType = func.parameterTypes[func.parameterTypes.GetLength()-1]; - - // If the parameter is object, and const reference for input, - // and same type as this class, then this is a copy constructor. - if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() && func.inOutFlags[func.parameterTypes.GetLength()-1] == asTM_INREF && paramType.GetObjectType() == objectType ) - beh->copyfactory = func.id; - } - } - } - else if( behaviour == asBEHAVE_ADDREF ) - { - // Must be a ref type and must not have asOBJ_NOHANDLE, nor asOBJ_SCOPED - if( !(func.objectType->flags & asOBJ_REF) || - (func.objectType->flags & asOBJ_NOHANDLE) || - (func.objectType->flags & asOBJ_SCOPED) || - (func.objectType->flags & asOBJ_NOCOUNT) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - if( beh->addref ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that the return type is void - if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that there are no parameters - if( func.parameterTypes.GetLength() > 0 ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - func.id = beh->addref = AddBehaviourFunction(func, internal); - } - else if( behaviour == asBEHAVE_RELEASE ) - { - // Must be a ref type and must not have asOBJ_NOHANDLE - if( !(func.objectType->flags & asOBJ_REF) || - (func.objectType->flags & asOBJ_NOHANDLE) || - (func.objectType->flags & asOBJ_NOCOUNT) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - if( beh->release ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that the return type is void - if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that there are no parameters - if( func.parameterTypes.GetLength() > 0 ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - func.id = beh->release = AddBehaviourFunction(func, internal); - } - else if( behaviour == asBEHAVE_TEMPLATE_CALLBACK ) - { - // Must be a template type - if( !(func.objectType->flags & asOBJ_TEMPLATE) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - if( beh->templateCallback ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that the return type is bool - if( func.returnType != asCDataType::CreatePrimitive(ttBool, false) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that there are two parameters - if( func.parameterTypes.GetLength() != 2 ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // The first parameter must be an inref (to receive the object type), and - // the second must be a bool out ref (to return if the type should or shouldn't be garbage collected) - if( func.inOutFlags[0] != asTM_INREF || func.inOutFlags[1] != asTM_OUTREF || !func.parameterTypes[1].IsEqualExceptRef(asCDataType::CreatePrimitive(ttBool, false)) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - func.id = beh->templateCallback = AddBehaviourFunction(func, internal); - } - else if( behaviour >= asBEHAVE_FIRST_GC && - behaviour <= asBEHAVE_LAST_GC ) - { - // Only allow GC behaviours for types registered to be garbage collected - if( !(func.objectType->flags & asOBJ_GC) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Verify parameter count - if( (behaviour == asBEHAVE_GETREFCOUNT || - behaviour == asBEHAVE_SETGCFLAG || - behaviour == asBEHAVE_GETGCFLAG) && - func.parameterTypes.GetLength() != 0 ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - if( (behaviour == asBEHAVE_ENUMREFS || - behaviour == asBEHAVE_RELEASEREFS) && - func.parameterTypes.GetLength() != 1 ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify return type - if( behaviour == asBEHAVE_GETREFCOUNT && - func.returnType != asCDataType::CreatePrimitive(ttInt, false) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - if( behaviour == asBEHAVE_GETGCFLAG && - func.returnType != asCDataType::CreatePrimitive(ttBool, false) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - if( (behaviour == asBEHAVE_SETGCFLAG || - behaviour == asBEHAVE_ENUMREFS || - behaviour == asBEHAVE_RELEASEREFS) && - func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - if( behaviour == asBEHAVE_GETREFCOUNT ) - func.id = beh->gcGetRefCount = AddBehaviourFunction(func, internal); - else if( behaviour == asBEHAVE_SETGCFLAG ) - func.id = beh->gcSetFlag = AddBehaviourFunction(func, internal); - else if( behaviour == asBEHAVE_GETGCFLAG ) - func.id = beh->gcGetFlag = AddBehaviourFunction(func, internal); - else if( behaviour == asBEHAVE_ENUMREFS ) - func.id = beh->gcEnumReferences = AddBehaviourFunction(func, internal); - else if( behaviour == asBEHAVE_RELEASEREFS ) - func.id = beh->gcReleaseAllReferences = AddBehaviourFunction(func, internal); - } - else if( behaviour == asBEHAVE_IMPLICIT_VALUE_CAST || - behaviour == asBEHAVE_VALUE_CAST ) - { - // TODO: 2.30.0: Deprecate these behaviours, the application should register - // them directly as methods with opConv or opImplConv names - - // There are two allowed signatures - // 1. type f() - // 2. void f(?&out) - - if( !(func.parameterTypes.GetLength() == 1 && func.parameterTypes[0].GetTokenType() == ttQuestion && func.inOutFlags[0] == asTM_OUTREF && func.returnType.GetTokenType() == ttVoid) && - !(func.parameterTypes.GetLength() == 0 && func.returnType.GetTokenType() != ttVoid) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // It is not allowed to implement a value cast to bool - if( func.returnType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, false)) ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - asCString decl; - decl += func.returnType.Format(); - decl += behaviour == asBEHAVE_VALUE_CAST ? " opConv(" : " opImplConv("; - if( func.parameterTypes.GetLength() ) - decl += "?&out"; - decl += ")"; - func.id = RegisterMethodToObjectType(objectType, decl.AddressOf(), funcPointer, callConv, objForThiscall); - } - else if( behaviour == asBEHAVE_REF_CAST || - behaviour == asBEHAVE_IMPLICIT_REF_CAST ) - { - // There are two allowed signatures - // 1. obj @f() - // 2. void f(?&out) - - if( !(func.parameterTypes.GetLength() == 0 && func.returnType.IsObjectHandle()) && - !(func.parameterTypes.GetLength() == 1 && func.parameterTypes[0].GetTokenType() == ttQuestion && func.inOutFlags[0] == asTM_OUTREF && func.returnType.GetTokenType() == ttVoid) ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Currently it is not supported to register const overloads for the ref cast behaviour - if( func.IsReadOnly() ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that the same cast is not registered already - // (const or non-const is treated the same for the return type) - if( func.parameterTypes.GetLength() == 1 ) - { - // Check for existing behaviour with ?&out - for( asUINT n = 0; n < beh->operators.GetLength(); n+= 2 ) - { - if( beh->operators[n] == asBEHAVE_REF_CAST || - beh->operators[n] == asBEHAVE_IMPLICIT_REF_CAST ) - { - asCScriptFunction *f = scriptFunctions[beh->operators[n+1]]; - if( f->parameterTypes.GetLength() == 1 ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - } - } - else - { - // Check for existing behaviour with same return type - for( asUINT n = 0; n < beh->operators.GetLength(); n+= 2 ) - { - if( beh->operators[n] == asBEHAVE_REF_CAST || - beh->operators[n] == asBEHAVE_IMPLICIT_REF_CAST ) - { - asCScriptFunction *f = scriptFunctions[beh->operators[n+1]]; - if( f->returnType.GetObjectType() == func.returnType.GetObjectType() ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - } - } - - beh->operators.PushLast(behaviour); - func.id = AddBehaviourFunction(func, internal); - beh->operators.PushLast(func.id); - } - else if ( behaviour == asBEHAVE_GET_WEAKREF_FLAG ) - { - // This behaviour is only allowed for reference types - if( !(func.objectType->flags & asOBJ_REF) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Don't allow it if the type is registered with nohandle or scoped - if( func.objectType->flags & (asOBJ_NOHANDLE|asOBJ_SCOPED) ) - { - WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); - return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - // Verify that the return type is a reference since it needs to return a pointer to an asISharedBool - if( !func.returnType.IsReference() ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Verify that there are no parameters - if( func.parameterTypes.GetLength() != 0 ) - return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - if( beh->getWeakRefFlag ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - func.id = beh->getWeakRefFlag = AddBehaviourFunction(func, internal); - } - else - { - asASSERT(false); - - return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - - if( func.id < 0 ) - return ConfigError(func.id, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // Return function id as success - return func.id; -} - - -int asCScriptEngine::VerifyVarTypeNotInFunction(asCScriptFunction *func) -{ - // Don't allow var type in this function - if( func->returnType.GetTokenType() == ttQuestion ) - return asINVALID_DECLARATION; - - for( unsigned int n = 0; n < func->parameterTypes.GetLength(); n++ ) - if( func->parameterTypes[n].GetTokenType() == ttQuestion ) - return asINVALID_DECLARATION; - - return 0; -} - -int asCScriptEngine::AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal) -{ - asUINT n; - - int id = GetNextScriptFunctionId(); - - asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal); - if( newInterface == 0 ) - return asOUT_OF_MEMORY; - - asCScriptFunction *f = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM); - if( f == 0 ) - { - asDELETE(newInterface, asSSystemFunctionInterface); - return asOUT_OF_MEMORY; - } - - asASSERT(func.name != "" && func.name != "f"); - f->name = func.name; - f->sysFuncIntf = newInterface; - f->returnType = func.returnType; - f->objectType = func.objectType; - f->id = id; - f->isReadOnly = func.isReadOnly; - f->accessMask = defaultAccessMask; - f->parameterTypes = func.parameterTypes; - f->inOutFlags = func.inOutFlags; - for( n = 0; n < func.defaultArgs.GetLength(); n++ ) - if( func.defaultArgs[n] ) - f->defaultArgs.PushLast(asNEW(asCString)(*func.defaultArgs[n])); - else - f->defaultArgs.PushLast(0); - - SetScriptFunction(f); - - // If parameter type from other groups are used, add references - if( f->returnType.GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(f->returnType.GetObjectType()); - currentGroup->RefConfigGroup(group); - } - for( n = 0; n < f->parameterTypes.GetLength(); n++ ) - { - if( f->parameterTypes[n].GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(f->parameterTypes[n].GetObjectType()); - currentGroup->RefConfigGroup(group); - } - } - - return id; -} - -// interface -int asCScriptEngine::RegisterGlobalProperty(const char *declaration, void *pointer) -{ - // Don't accept a null pointer - if( pointer == 0 ) - return ConfigError(asINVALID_ARG, "RegisterGlobalProperty", declaration, 0); - - asCDataType type; - asCString name; - - int r; - asCBuilder bld(this, 0); - if( (r = bld.VerifyProperty(0, declaration, name, type, defaultNamespace)) < 0 ) - return ConfigError(r, "RegisterGlobalProperty", declaration, 0); - - // Don't allow registering references as global properties - if( type.IsReference() ) - return ConfigError(asINVALID_TYPE, "RegisterGlobalProperty", declaration, 0); - - // Store the property info - asCGlobalProperty *prop = AllocateGlobalProperty(); - prop->name = name; - prop->nameSpace = defaultNamespace; - prop->type = type; - prop->accessMask = defaultAccessMask; - - prop->SetRegisteredAddress(pointer); - varAddressMap.Insert(prop->GetAddressOfValue(), prop); - - registeredGlobalProps.Put(prop); - currentGroup->globalProps.PushLast(prop); - - // If from another group add reference - if( type.GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(type.GetObjectType()); - currentGroup->RefConfigGroup(group); - } - - return asSUCCESS; -} - -// internal -asCGlobalProperty *asCScriptEngine::AllocateGlobalProperty() -{ - asCGlobalProperty *prop = asNEW(asCGlobalProperty); - if( prop == 0 ) - { - // Out of memory - return 0; - } - - // First check the availability of a free slot - if( freeGlobalPropertyIds.GetLength() ) - { - prop->id = freeGlobalPropertyIds.PopLast(); - globalProperties[prop->id] = prop; - return prop; - } - - prop->id = (asUINT)globalProperties.GetLength(); - globalProperties.PushLast(prop); - return prop; -} - -// internal -void asCScriptEngine::FreeUnusedGlobalProperties() -{ - for( asUINT n = 0; n < globalProperties.GetLength(); n++ ) - { - if( globalProperties[n] && globalProperties[n]->GetRefCount() == 0 ) - { - freeGlobalPropertyIds.PushLast(n); - - asSMapNode *node; - varAddressMap.MoveTo(&node, globalProperties[n]->GetAddressOfValue()); - asASSERT(node); - if( node ) - varAddressMap.Erase(node); - - asDELETE(globalProperties[n], asCGlobalProperty); - globalProperties[n] = 0; - } - } -} - -// interface -asUINT asCScriptEngine::GetGlobalPropertyCount() const -{ - return asUINT(registeredGlobalProps.GetSize()); -} - -// interface -// TODO: If the typeId ever encodes the const flag, then the isConst parameter should be removed -int asCScriptEngine::GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace, int *typeId, bool *isConst, const char **configGroup, void **pointer, asDWORD *accessMask) const -{ - const asCGlobalProperty *prop = registeredGlobalProps.Get(index); - if( !prop ) - return asINVALID_ARG; - - if( name ) *name = prop->name.AddressOf(); - if( nameSpace ) *nameSpace = prop->nameSpace->name.AddressOf(); - if( typeId ) *typeId = GetTypeIdFromDataType(prop->type); - if( isConst ) *isConst = prop->type.IsReadOnly(); - if( pointer ) *pointer = prop->GetRegisteredAddress(); - if( accessMask ) *accessMask = prop->accessMask; - - if( configGroup ) - { - asCConfigGroup *group = FindConfigGroupForGlobalVar(index); - if( group ) - *configGroup = group->groupName.AddressOf(); - else - *configGroup = 0; - } - - return asSUCCESS; -} - -// interface -int asCScriptEngine::GetGlobalPropertyIndexByName(const char *name) const -{ - // Find the global var id - int id = registeredGlobalProps.GetFirstIndex(defaultNamespace, name); - if( id == -1 ) return asNO_GLOBAL_VAR; - - return id; -} - -// interface -int asCScriptEngine::GetGlobalPropertyIndexByDecl(const char *decl) const -{ - // This const cast is OK. The builder won't modify the engine - asCBuilder bld(const_cast(this), 0); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCString name; - asSNameSpace *ns; - asCDataType dt; - int r = bld.ParseVariableDeclaration(decl, defaultNamespace, name, ns, dt); - if( r < 0 ) - return r; - - // Search for a match - int id = registeredGlobalProps.GetFirstIndex(ns, name, asCCompGlobPropType(dt)); - if (id < 0) - return asNO_GLOBAL_VAR; - - return id; -} - -// interface -int asCScriptEngine::RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) -{ - if( obj == 0 ) - return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); - - // Determine the object type - asCDataType dt; - asCBuilder bld(this, 0); - int r = bld.ParseDataType(obj, &dt, defaultNamespace); - if( r < 0 ) - return ConfigError(r, "RegisterObjectMethod", obj, declaration); - - if( dt.GetObjectType() == 0 || dt.IsObjectHandle() ) - return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); - - // Don't allow application to modify built-in types - if( dt.GetObjectType() == &functionBehaviours || - dt.GetObjectType() == &objectTypeBehaviours || - dt.GetObjectType() == &globalPropertyBehaviours || - dt.GetObjectType() == &scriptTypeBehaviours ) - return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); - - return RegisterMethodToObjectType(dt.GetObjectType(), declaration, funcPointer, callConv, objForThiscall); -} - -// internal -int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) -{ -#ifdef AS_MAX_PORTABILITY - if( callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); -#endif - - asSSystemFunctionInterface internal; - int r = DetectCallingConvention(true, funcPointer, callConv, objForThiscall, &internal); - if( r < 0 ) - return ConfigError(r, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - - isPrepared = false; - - // Put the system function in the list of system functions - asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal); - if( newInterface == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - - asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM); - if( func == 0 ) - { - asDELETE(newInterface, asSSystemFunctionInterface); - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - - func->sysFuncIntf = newInterface; - func->objectType = objectType; - - asCBuilder bld(this, 0); - r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, true, &newInterface->paramAutoHandles, &newInterface->returnAutoHandle); - if( r < 0 ) - { - // Set as dummy function before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asINVALID_DECLARATION, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - - // Check name conflicts - r = bld.CheckNameConflictMember(objectType, func->name.AddressOf(), 0, 0, false); - if( r < 0 ) - { - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asNAME_TAKEN, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - - // Check against duplicate methods - asUINT n; - if( func->name == "opConv" || func->name == "opImplConv" ) - { - // opConv and opImplConv are special methods that the compiler differentiates between by the return type - for( n = 0; n < func->objectType->methods.GetLength(); n++ ) - { - asCScriptFunction *f = scriptFunctions[func->objectType->methods[n]]; - if( f->name == func->name && - f->IsSignatureExceptNameEqual(func) ) - { - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - } - } - else - { - for( n = 0; n < func->objectType->methods.GetLength(); n++ ) - { - asCScriptFunction *f = scriptFunctions[func->objectType->methods[n]]; - if( f->name == func->name && - f->IsSignatureExceptNameAndReturnTypeEqual(func) ) - { - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - } - } - - func->id = GetNextScriptFunctionId(); - func->objectType->methods.PushLast(func->id); - func->accessMask = defaultAccessMask; - SetScriptFunction(func); - - // TODO: This code is repeated in many places - // If parameter type from other groups are used, add references - if( func->returnType.GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType()); - currentGroup->RefConfigGroup(group); - } - for( n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( func->parameterTypes[n].GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->parameterTypes[n].GetObjectType()); - currentGroup->RefConfigGroup(group); - } - } - - // Check if the method restricts that use of the template to value types or reference types - if( func->objectType->flags & asOBJ_TEMPLATE ) - { - for( asUINT subTypeIdx = 0; subTypeIdx < func->objectType->templateSubTypes.GetLength(); subTypeIdx++ ) - { - if( func->returnType.GetObjectType() == func->objectType->templateSubTypes[subTypeIdx].GetObjectType() ) - { - if( func->returnType.IsObjectHandle() ) - func->objectType->acceptValueSubType = false; - else if( !func->returnType.IsReference() ) - func->objectType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if( !func->returnType.IsObjectHandle() && !func->returnType.IsReference() ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - - for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( func->parameterTypes[n].GetObjectType() == func->objectType->templateSubTypes[subTypeIdx].GetObjectType() ) - { - // TODO: If unsafe references are allowed, then inout references allow value types - if( func->parameterTypes[n].IsObjectHandle() || (func->parameterTypes[n].IsReference() && func->inOutFlags[n] == asTM_INOUTREF) ) - func->objectType->acceptValueSubType = false; - else if( !func->parameterTypes[n].IsReference() ) - func->objectType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if( !func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference() ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - } - } - } - - // TODO: beh.copy member will be removed, so this is not necessary - // Is this the default copy behaviour? - if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && func->isReadOnly == false && - ((objectType->flags & asOBJ_SCRIPT_OBJECT) || func->parameterTypes[0].IsEqualExceptRefAndConst(asCDataType::CreateObject(func->objectType, false))) ) - { - if( func->objectType->beh.copy != 0 ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - - func->objectType->beh.copy = func->id; - func->AddRef(); - } - - // Return the function id as success - return func->id; -} - -// interface -int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) -{ -#ifdef AS_MAX_PORTABILITY - if( callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterGlobalFunction", declaration, 0); -#endif - - asSSystemFunctionInterface internal; - int r = DetectCallingConvention(false, funcPointer, callConv, objForThiscall, &internal); - if( r < 0 ) - return ConfigError(r, "RegisterGlobalFunction", declaration, 0); - - isPrepared = false; - - // Put the system function in the list of system functions - asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal); - if( newInterface == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterGlobalFunction", declaration, 0); - - asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM); - if( func == 0 ) - { - asDELETE(newInterface, asSSystemFunctionInterface); - return ConfigError(asOUT_OF_MEMORY, "RegisterGlobalFunction", declaration, 0); - } - - func->sysFuncIntf = newInterface; - - asCBuilder bld(this, 0); - r = bld.ParseFunctionDeclaration(0, declaration, func, true, &newInterface->paramAutoHandles, &newInterface->returnAutoHandle, defaultNamespace); - if( r < 0 ) - { - // Set as dummy function before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asINVALID_DECLARATION, "RegisterGlobalFunction", declaration, 0); - } - - // TODO: namespace: What if the declaration defined an explicit namespace? - func->nameSpace = defaultNamespace; - - // Check name conflicts - r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace); - if( r < 0 ) - { - // Set as dummy function before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asNAME_TAKEN, "RegisterGlobalFunction", declaration, 0); - } - - // Make sure the function is not identical to a previously registered function - asUINT n; - const asCArray &idxs = registeredGlobalFuncs.GetIndexes(func->nameSpace, func->name); - for( n = 0; n < idxs.GetLength(); n++ ) - { - asCScriptFunction *f = registeredGlobalFuncs.Get(idxs[n]); - if( f->IsSignatureExceptNameAndReturnTypeEqual(func) ) - { - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asALREADY_REGISTERED, "RegisterGlobalFunction", declaration, 0); - } - } - - func->id = GetNextScriptFunctionId(); - SetScriptFunction(func); - - currentGroup->scriptFunctions.PushLast(func); - func->accessMask = defaultAccessMask; - registeredGlobalFuncs.Put(func); - - // If parameter type from other groups are used, add references - if( func->returnType.GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType()); - currentGroup->RefConfigGroup(group); - } - for( n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( func->parameterTypes[n].GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->parameterTypes[n].GetObjectType()); - currentGroup->RefConfigGroup(group); - } - } - - // Return the function id as success - return func->id; -} - -// interface -asUINT asCScriptEngine::GetGlobalFunctionCount() const -{ - // Don't count the builtin delegate factory - return asUINT(registeredGlobalFuncs.GetSize()-1); -} - -// interface -asIScriptFunction *asCScriptEngine::GetGlobalFunctionByIndex(asUINT index) const -{ - // Don't count the builtin delegate factory - index++; - - if( index >= registeredGlobalFuncs.GetSize() ) - return 0; - - return static_cast(const_cast(registeredGlobalFuncs.Get(index))); -} - -// interface -asIScriptFunction *asCScriptEngine::GetGlobalFunctionByDecl(const char *decl) const -{ - asCBuilder bld(const_cast(this), 0); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCScriptFunction func(const_cast(this), 0, asFUNC_DUMMY); - int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, defaultNamespace); - if( r < 0 ) - return 0; - - // Search script functions for matching interface - asIScriptFunction *f = 0; - const asCArray &idxs = registeredGlobalFuncs.GetIndexes(defaultNamespace, func.name); - for( unsigned int n = 0; n < idxs.GetLength(); n++ ) - { - const asCScriptFunction *funcPtr = registeredGlobalFuncs.Get(idxs[n]); - if( funcPtr->objectType == 0 && - func.returnType == funcPtr->returnType && - func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength() - ) - { - bool match = true; - for( size_t p = 0; p < func.parameterTypes.GetLength(); ++p ) - { - if( func.parameterTypes[p] != funcPtr->parameterTypes[p] ) - { - match = false; - break; - } - } - - if( match ) - { - if( f == 0 ) - f = const_cast(funcPtr); - else - // Multiple functions - return 0; - } - } - } - - return f; -} - - -asCObjectType *asCScriptEngine::GetRegisteredObjectType(const asCString &type, asSNameSpace *ns) const -{ - asSMapNode *cursor; - if( allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(ns, type)) ) - return cursor->value; - - return 0; -} - - - - -void asCScriptEngine::PrepareEngine() -{ - if( isPrepared ) return; - if( configFailed ) return; - - asUINT n; - for( n = 0; n < scriptFunctions.GetLength(); n++ ) - { - // Determine the host application interface - if( scriptFunctions[n] && scriptFunctions[n]->funcType == asFUNC_SYSTEM ) - { - if( scriptFunctions[n]->sysFuncIntf->callConv == ICC_GENERIC_FUNC || - scriptFunctions[n]->sysFuncIntf->callConv == ICC_GENERIC_METHOD ) - PrepareSystemFunctionGeneric(scriptFunctions[n], scriptFunctions[n]->sysFuncIntf, this); - else - PrepareSystemFunction(scriptFunctions[n], scriptFunctions[n]->sysFuncIntf, this); - } - } - - // Validate object type registrations - for( n = 0; n < registeredObjTypes.GetLength(); n++ ) - { - asCObjectType *type = registeredObjTypes[n]; - if( type && !(type->flags & asOBJ_SCRIPT_OBJECT) ) - { - bool missingBehaviour = false; - const char *infoMsg = 0; - - // Verify that GC types have all behaviours - if( type->flags & asOBJ_GC ) - { - if( type->beh.addref == 0 || - type->beh.release == 0 || - type->beh.gcGetRefCount == 0 || - type->beh.gcSetFlag == 0 || - type->beh.gcGetFlag == 0 || - type->beh.gcEnumReferences == 0 || - type->beh.gcReleaseAllReferences == 0 ) - { - infoMsg = TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR; - missingBehaviour = true; - } - } - // Verify that scoped ref types have the release behaviour - else if( type->flags & asOBJ_SCOPED ) - { - if( type->beh.release == 0 ) - { - infoMsg = TXT_SCOPE_REQUIRE_REL_BEHAVIOUR; - missingBehaviour = true; - } - } - // Verify that ref types have add ref and release behaviours - else if( (type->flags & asOBJ_REF) && - !(type->flags & asOBJ_NOHANDLE) && - !(type->flags & asOBJ_NOCOUNT) ) - { - if( type->beh.addref == 0 || - type->beh.release == 0 ) - { - infoMsg = TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR; - missingBehaviour = true; - } - } - // Verify that non-pod value types have the constructor and destructor registered - else if( (type->flags & asOBJ_VALUE) && - !(type->flags & asOBJ_POD) ) - { - if( type->beh.construct == 0 || - type->beh.destruct == 0 ) - { - infoMsg = TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR; - missingBehaviour = true; - } - } - - if( missingBehaviour ) - { - asCString str; - str.Format(TXT_TYPE_s_IS_MISSING_BEHAVIOURS, type->name.AddressOf()); - WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, infoMsg); - ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); - } - } - } - - isPrepared = true; -} - -int asCScriptEngine::ConfigError(int err, const char *funcName, const char *arg1, const char *arg2) -{ - configFailed = true; - if( funcName ) - { - asCString str; - if( arg1 ) - { - if( arg2 ) - str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_d, funcName, arg1, arg2, err); - else - str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, funcName, arg1, err); - } - else - str.Format(TXT_FAILED_IN_FUNC_s_d, funcName, err); - - WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - } - return err; -} - -// interface -int asCScriptEngine::RegisterDefaultArrayType(const char *type) -{ - asCBuilder bld(this, 0); - asCDataType dt; - int r = bld.ParseDataType(type, &dt, defaultNamespace); - if( r < 0 ) return r; - - if( dt.GetObjectType() == 0 || - !(dt.GetObjectType()->GetFlags() & asOBJ_TEMPLATE) ) - return asINVALID_TYPE; - - defaultArrayObjectType = dt.GetObjectType(); - defaultArrayObjectType->AddRef(); - - return 0; -} - -// interface -int asCScriptEngine::GetDefaultArrayTypeId() const -{ - if( defaultArrayObjectType ) - return GetTypeIdFromDataType(asCDataType::CreateObject(defaultArrayObjectType, false)); - - return asINVALID_TYPE; -} - -// interface -int asCScriptEngine::RegisterStringFactory(const char *datatype, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall) -{ - asSSystemFunctionInterface internal; - int r = DetectCallingConvention(false, funcPointer, callConv, objForThiscall, &internal); - if( r < 0 ) - return ConfigError(r, "RegisterStringFactory", datatype, 0); - -#ifdef AS_MAX_PORTABILITY - if( callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterStringFactory", datatype, 0); -#else - if( callConv != asCALL_CDECL && - callConv != asCALL_STDCALL && - callConv != asCALL_THISCALL_ASGLOBAL && - callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterStringFactory", datatype, 0); -#endif - - // Put the system function in the list of system functions - asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal); - if( newInterface == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterStringFactory", datatype, 0); - - asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM); - if( func == 0 ) - { - asDELETE(newInterface, asSSystemFunctionInterface); - return ConfigError(asOUT_OF_MEMORY, "RegisterStringFactory", datatype, 0); - } - - func->name = "_string_factory_"; - func->sysFuncIntf = newInterface; - - asCBuilder bld(this, 0); - - asCDataType dt; - r = bld.ParseDataType(datatype, &dt, defaultNamespace, true); - if( r < 0 ) - { - // Set as dummy before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); - } - - func->returnType = dt; - func->parameterTypes.PushLast(asCDataType::CreatePrimitive(ttInt, true)); - func->inOutFlags.PushLast(asTM_NONE); - asCDataType parm1 = asCDataType::CreatePrimitive(ttUInt8, true); - parm1.MakeReference(true); - func->parameterTypes.PushLast(parm1); - func->inOutFlags.PushLast(asTM_INREF); - func->id = GetNextScriptFunctionId(); - SetScriptFunction(func); - - stringFactory = func; - - if( func->returnType.GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType()); - if( group == 0 ) group = &defaultGroup; - group->scriptFunctions.PushLast(func); - } - - // Register function id as success - return func->id; -} - -// interface -int asCScriptEngine::GetStringFactoryReturnTypeId(asDWORD *flags) const -{ - if( stringFactory == 0 ) - return asNO_FUNCTION; - - return stringFactory->GetReturnTypeId(flags); -} - -// interface -asCModule *asCScriptEngine::GetModule(const char *_name, bool create) -{ - // Accept null as well as zero-length string - const char *name = ""; - if( _name != 0 ) name = _name; - - if( lastModule && lastModule->name == name ) - return lastModule; - - // TODO: optimize: Improve linear search - for( asUINT n = 0; n < scriptModules.GetLength(); ++n ) - if( scriptModules[n] && scriptModules[n]->name == name ) - { - lastModule = scriptModules[n]; - return lastModule; - } - - if( create ) - { - asCModule *module = asNEW(asCModule)(name, this); - if( module == 0 ) - { - // Out of memory - return 0; - } - - scriptModules.PushLast(module); - - lastModule = module; - - return lastModule; - } - - return 0; -} - -asCModule *asCScriptEngine::GetModuleFromFuncId(int id) -{ - if( id < 0 ) return 0; - if( id >= (int)scriptFunctions.GetLength() ) return 0; - asCScriptFunction *func = scriptFunctions[id]; - if( func == 0 ) return 0; - return func->module; -} - -// internal -int asCScriptEngine::RequestBuild() -{ - ACQUIREEXCLUSIVE(engineRWLock); - if( isBuilding ) - { - RELEASEEXCLUSIVE(engineRWLock); - return asBUILD_IN_PROGRESS; - } - isBuilding = true; - RELEASEEXCLUSIVE(engineRWLock); - - return 0; -} - -// internal -void asCScriptEngine::BuildCompleted() -{ - // Always free up pooled memory after a completed build - memoryMgr.FreeUnusedMemory(); - - isBuilding = false; -} - -void asCScriptEngine::RemoveTemplateInstanceType(asCObjectType *t) -{ - int n; - - RemoveFromTypeIdMap(t); - - // Destroy the factory stubs - for( n = 0; n < (int)t->beh.factories.GetLength(); n++ ) - { - // Make sure the factory stub isn't referencing this object anymore - scriptFunctions[t->beh.factories[n]]->ReleaseAllHandles(this); - scriptFunctions[t->beh.factories[n]]->Release(); - } - t->beh.factories.SetLength(0); - - // Destroy the stub for the list factory too - if( t->beh.listFactory ) - { - scriptFunctions[t->beh.listFactory]->ReleaseAllHandles(this); - scriptFunctions[t->beh.listFactory]->Release(); - t->beh.listFactory = 0; - } - - // Destroy the specialized functions - for( n = 1; n < (int)t->beh.operators.GetLength(); n += 2 ) - { - if( t->beh.operators[n] ) - scriptFunctions[t->beh.operators[n]]->Release(); - } - t->beh.operators.SetLength(0); - - // Start searching from the end of the list, as most of - // the time it will be the last two types - for( n = (int)templateInstanceTypes.GetLength()-1; n >= 0; n-- ) - { - if( templateInstanceTypes[n] == t ) - { - if( n == (signed)templateInstanceTypes.GetLength()-1 ) - templateInstanceTypes.PopLast(); - else - templateInstanceTypes[n] = templateInstanceTypes.PopLast(); - } - } - - // Only delete it if the refCount is 0 - if( t->refCount.get() == 0 ) - { - for( n = (int)generatedTemplateTypes.GetLength()-1; n >= 0; n-- ) - { - if( generatedTemplateTypes[n] == t ) - { - if( n == (signed)generatedTemplateTypes.GetLength()-1 ) - generatedTemplateTypes.PopLast(); - else - generatedTemplateTypes[n] = generatedTemplateTypes.PopLast(); - } - } - - asDELETE(t,asCObjectType); - } -} - -// internal -void asCScriptEngine::OrphanTemplateInstances(asCObjectType *subType) -{ - for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ ) - { - asCObjectType *type = templateInstanceTypes[n]; - - if( type == 0 ) - continue; - - // If the template type isn't owned by any module it can't be orphaned - if( type->module == 0 ) - continue; - - for( asUINT subTypeIdx = 0; subTypeIdx < type->templateSubTypes.GetLength(); subTypeIdx++ ) - { - if( type->templateSubTypes[subTypeIdx].GetObjectType() == subType ) - { - // Tell the GC that the template type exists so it can resolve potential circular references - gc.AddScriptObjectToGC(type, &objectTypeBehaviours); - - // Clear the module - type->module = 0; - type->Release(); - - // Do a recursive check for other template instances - OrphanTemplateInstances(type); - - // Break out so we don't add the same template to - // the gc again if another subtype matches this one - break; - } - } - } -} - -// internal -asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateType, asCArray &subTypes) -{ - asUINT n; - - // Is there any template instance type or template specialization already with this subtype? - for( n = 0; n < templateInstanceTypes.GetLength(); n++ ) - { - if( templateInstanceTypes[n] && - templateInstanceTypes[n]->name == templateType->name && - templateInstanceTypes[n]->templateSubTypes == subTypes ) - return templateInstanceTypes[n]; - } - - // No previous template instance exists - - // Make sure this template supports the subtype - for( n = 0; n < subTypes.GetLength(); n++ ) - { - if( !templateType->acceptValueSubType && (subTypes[n].IsPrimitive() || (subTypes[n].GetObjectType()->flags & asOBJ_VALUE)) ) - return 0; - - if( !templateType->acceptRefSubType && (subTypes[n].IsObject() && (subTypes[n].GetObjectType()->flags & asOBJ_REF)) ) - return 0; - } - - // Create a new template instance type based on the templateType - asCObjectType *ot = asNEW(asCObjectType)(this); - if( ot == 0 ) - { - // Out of memory - return 0; - } - - ot->templateSubTypes = subTypes; - ot->flags = templateType->flags; - ot->size = templateType->size; - ot->name = templateType->name; - ot->nameSpace = templateType->nameSpace; - - // The template instance type will inherit the same module as the subType - // This will allow the module to orphan the template instance types afterwards - for( n = 0; n < subTypes.GetLength(); n++ ) - { - if( subTypes[n].GetObjectType() ) - { - ot->module = subTypes[n].GetObjectType()->module; - if( ot->module ) - { - ot->AddRef(); - break; - } - } - } - - // Before filling in the methods, call the template instance callback behaviour to validate the type - if( templateType->beh.templateCallback ) - { - // If the validation is deferred then the validation will be done later, - // so it is necessary to continue the preparation of the template instance type - if( !deferValidationOfTemplateTypes ) - { - asCScriptFunction *callback = scriptFunctions[templateType->beh.templateCallback]; - - bool dontGarbageCollect = false; - if( !CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) ) - { - // The type cannot be instantiated - ot->templateSubTypes.SetLength(0); - asDELETE(ot, asCObjectType); - return 0; - } - - // If the callback said this template instance won't be garbage collected then remove the flag - if( dontGarbageCollect ) - ot->flags &= ~asOBJ_GC; - } - - ot->beh.templateCallback = templateType->beh.templateCallback; - scriptFunctions[ot->beh.templateCallback]->AddRef(); - } - - ot->methods = templateType->methods; - for( n = 0; n < ot->methods.GetLength(); n++ ) - scriptFunctions[ot->methods[n]]->AddRef(); - - if( templateType->flags & asOBJ_REF ) - { - // Store the real factory in the constructor. This is used by the CreateScriptObject function. - // Otherwise it wouldn't be necessary to store the real factory ids. - ot->beh.construct = templateType->beh.factory; - ot->beh.constructors = templateType->beh.factories; - } - else - { - ot->beh.construct = templateType->beh.construct; - ot->beh.constructors = templateType->beh.constructors; - } - for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) - scriptFunctions[ot->beh.constructors[n]]->AddRef(); - - - // Before proceeding with the generation of the template functions for the template instance it is necessary - // to include the new template instance type in the list of known types, otherwise it is possible that we get - // a infinite recursive loop as the template instance type is requested again during the generation of the - // template functions. - templateInstanceTypes.PushLast(ot); - - // Store the template instance types that have been created automatically by the engine from a template type - // The object types in templateInstanceTypes that are not also in generatedTemplateTypes are registered template specializations - generatedTemplateTypes.PushLast(ot); - - - // As the new template type is instantiated the engine should - // generate new functions to substitute the ones with the template subtype. - for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) - { - int funcId = ot->beh.constructors[n]; - asCScriptFunction *func = scriptFunctions[funcId]; - - if( GenerateNewTemplateFunction(templateType, ot, func, &func) ) - { - // Release the old function, the new one already has its ref count set to 1 - scriptFunctions[funcId]->Release(); - ot->beh.constructors[n] = func->id; - - if( ot->beh.construct == funcId ) - ot->beh.construct = func->id; - } - } - - ot->beh.factory = 0; - - if( templateType->flags & asOBJ_REF ) - { - // Generate factory stubs for each of the factories - for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) - { - asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, ot->beh.constructors[n]); - - // The function's refCount was already initialized to 1 - ot->beh.factories.PushLast(func->id); - - // Set the default factory as well - if( ot->beh.constructors[n] == ot->beh.construct ) - ot->beh.factory = func->id; - } - } - else - { - // Generate factory stubs for each of the constructors - for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) - { - asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, ot->beh.constructors[n]); - - // The function's refCount was already initialized to 1 - if( ot->beh.constructors[n] == ot->beh.construct ) - ot->beh.construct = func->id; - - // Release previous constructor - scriptFunctions[ot->beh.constructors[n]]->Release(); - - ot->beh.constructors[n] = func->id; - } - } - - // Generate stub for the list factory as well - if( templateType->beh.listFactory ) - { - asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, templateType->beh.listFactory); - - // The function's refCount was already initialized to 1 - ot->beh.listFactory = func->id; - } - - ot->beh.addref = templateType->beh.addref; - if( scriptFunctions[ot->beh.addref] ) scriptFunctions[ot->beh.addref]->AddRef(); - ot->beh.release = templateType->beh.release; - if( scriptFunctions[ot->beh.release] ) scriptFunctions[ot->beh.release]->AddRef(); - ot->beh.destruct = templateType->beh.destruct; - if( scriptFunctions[ot->beh.destruct] ) scriptFunctions[ot->beh.destruct]->AddRef(); - ot->beh.copy = templateType->beh.copy; - if( scriptFunctions[ot->beh.copy] ) scriptFunctions[ot->beh.copy]->AddRef(); - ot->beh.operators = templateType->beh.operators; - for( n = 1; n < ot->beh.operators.GetLength(); n += 2 ) - scriptFunctions[ot->beh.operators[n]]->AddRef(); - ot->beh.gcGetRefCount = templateType->beh.gcGetRefCount; - if( scriptFunctions[ot->beh.gcGetRefCount] ) scriptFunctions[ot->beh.gcGetRefCount]->AddRef(); - ot->beh.gcSetFlag = templateType->beh.gcSetFlag; - if( scriptFunctions[ot->beh.gcSetFlag] ) scriptFunctions[ot->beh.gcSetFlag]->AddRef(); - ot->beh.gcGetFlag = templateType->beh.gcGetFlag; - if( scriptFunctions[ot->beh.gcGetFlag] ) scriptFunctions[ot->beh.gcGetFlag]->AddRef(); - ot->beh.gcEnumReferences = templateType->beh.gcEnumReferences; - if( scriptFunctions[ot->beh.gcEnumReferences] ) scriptFunctions[ot->beh.gcEnumReferences]->AddRef(); - ot->beh.gcReleaseAllReferences = templateType->beh.gcReleaseAllReferences; - if( scriptFunctions[ot->beh.gcReleaseAllReferences] ) scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRef(); - ot->beh.getWeakRefFlag = templateType->beh.getWeakRefFlag; - if( scriptFunctions[ot->beh.getWeakRefFlag] ) scriptFunctions[ot->beh.getWeakRefFlag]->AddRef(); - - // As the new template type is instantiated the engine should - // generate new functions to substitute the ones with the template subtype. - for( n = 1; n < ot->beh.operators.GetLength(); n += 2 ) - { - int funcId = ot->beh.operators[n]; - asCScriptFunction *func = scriptFunctions[funcId]; - - if( GenerateNewTemplateFunction(templateType, ot, func, &func) ) - { - // Release the old function, the new one already has its ref count set to 1 - scriptFunctions[funcId]->Release(); - ot->beh.operators[n] = func->id; - } - } - - // As the new template type is instantiated, the engine should - // generate new functions to substitute the ones with the template subtype. - for( n = 0; n < ot->methods.GetLength(); n++ ) - { - int funcId = ot->methods[n]; - asCScriptFunction *func = scriptFunctions[funcId]; - - if( GenerateNewTemplateFunction(templateType, ot, func, &func) ) - { - // Release the old function, the new one already has its ref count set to 1 - scriptFunctions[funcId]->Release(); - ot->methods[n] = func->id; - } - } - - // Increase ref counter for sub type if it is an object type - for( n = 0; n < ot->templateSubTypes.GetLength(); n++ ) - if( ot->templateSubTypes[n].GetObjectType() ) - ot->templateSubTypes[n].GetObjectType()->AddRef(); - - // Copy the properties to the template instance - for( n = 0; n < templateType->properties.GetLength(); n++ ) - { - asCObjectProperty *prop = templateType->properties[n]; - ot->properties.PushLast(asNEW(asCObjectProperty)(*prop)); - if( prop->type.GetObjectType() ) - prop->type.GetObjectType()->AddRef(); - } - - return ot; -} - -// interface -asILockableSharedBool *asCScriptEngine::GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const -{ - // Make sure it is not a null pointer - if( obj == 0 || type == 0 ) return 0; - - const asCObjectType *objType = static_cast(type); - asILockableSharedBool *dest = 0; - if( objType->beh.getWeakRefFlag ) - { - // Call the getweakrefflag behaviour - dest = reinterpret_cast(CallObjectMethodRetPtr(obj, objType->beh.getWeakRefFlag)); - } - return dest; -} - -// internal -asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot) -{ - asCDataType dt; - if( orig.GetObjectType() && (orig.GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE) ) - { - bool found = false; - for( asUINT n = 0; n < tmpl->templateSubTypes.GetLength(); n++ ) - { - if( orig.GetObjectType() == tmpl->templateSubTypes[n].GetObjectType() ) - { - found = true; - dt = ot->templateSubTypes[n]; - if( orig.IsObjectHandle() && !ot->templateSubTypes[n].IsObjectHandle() ) - { - dt.MakeHandle(true, true); - if( orig.IsHandleToConst() ) - dt.MakeHandleToConst(true); - dt.MakeReference(orig.IsReference()); - dt.MakeReadOnly(orig.IsReadOnly()); - } - else - { - dt.MakeReference(orig.IsReference()); - dt.MakeReadOnly(ot->templateSubTypes[n].IsReadOnly() || orig.IsReadOnly()); - } - break; - } - } - asASSERT( found ); - UNUSED_VAR( found ); - } - else if( orig.GetObjectType() == tmpl ) - { - if( orig.IsObjectHandle() ) - dt = asCDataType::CreateObjectHandle(ot, false); - else - dt = asCDataType::CreateObject(ot, false); - - dt.MakeReference(orig.IsReference()); - dt.MakeReadOnly(orig.IsReadOnly()); - } - else if( orig.GetObjectType() && (orig.GetObjectType()->flags & asOBJ_TEMPLATE) ) - { - // The type is itself a template, so it is necessary to find the correct template instance type - asCArray tmplSubTypes; - asCObjectType *origType = orig.GetObjectType(); - bool needInstance = true; - - // Find the matching replacements for the subtypes - for( asUINT n = 0; n < origType->templateSubTypes.GetLength(); n++ ) - { - if( origType->templateSubTypes[n].GetObjectType() == 0 || - !(origType->templateSubTypes[n].GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE) ) - { - // The template is already an instance so we shouldn't attempt to create another instance - needInstance = false; - break; - } - - for( asUINT m = 0; m < tmpl->templateSubTypes.GetLength(); m++ ) - if( origType->templateSubTypes[n].GetObjectType() == tmpl->templateSubTypes[m].GetObjectType() ) - tmplSubTypes.PushLast(ot->templateSubTypes[m]); - - if( tmplSubTypes.GetLength() != n+1 ) - { - asASSERT( false ); - return orig; - } - } - - asCObjectType *ntype = origType; - if( needInstance ) - { - // Always find the original template type when creating a new template instance otherwise the - // generation will fail since it will attempt to create factory stubs when they already exists, etc - for( asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++ ) - if( registeredTemplateTypes[n]->name == origType->name ) - { - origType = registeredTemplateTypes[n]; - break; - } - - ntype = GetTemplateInstanceType(origType, tmplSubTypes); - if( ntype == 0 ) - { - // It not possible to instantiate the subtype - asASSERT( false ); - ntype = tmpl; - } - } - - if( orig.IsObjectHandle() ) - dt = asCDataType::CreateObjectHandle(ntype, false); - else - dt = asCDataType::CreateObject(ntype, false); - - dt.MakeReference(orig.IsReference()); - dt.MakeReadOnly(orig.IsReadOnly()); - } - else - dt = orig; - - return dt; -} - -// internal -asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *ot, int factoryId) -{ - asCScriptFunction *factory = scriptFunctions[factoryId]; - - // By first instantiating the function as a dummy and then changing it to be a script function - // I avoid having it added to the garbage collector. As it is known that this object will stay - // alive until the template instance is no longer used there is no need to have the GC check - // this function all the time. - asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_DUMMY); - if( func == 0 ) - { - // Out of memory - return 0; - } - - func->funcType = asFUNC_SCRIPT; - func->AllocateScriptFunctionData(); - func->name = "factstub"; - func->id = GetNextScriptFunctionId(); - SetScriptFunction(func); - - func->isShared = true; - if( templateType->flags & asOBJ_REF ) - { - func->returnType = asCDataType::CreateObjectHandle(ot, false); - } - else - { - func->returnType = factory->returnType; // constructors return nothing - func->objectType = ot; - } - - // Skip the first parameter as this is the object type pointer that the stub will add - func->parameterTypes.SetLength(factory->parameterTypes.GetLength()-1); - func->inOutFlags.SetLength(factory->inOutFlags.GetLength()-1); - for( asUINT p = 1; p < factory->parameterTypes.GetLength(); p++ ) - { - func->parameterTypes[p-1] = factory->parameterTypes[p]; - func->inOutFlags[p-1] = factory->inOutFlags[p]; - } - func->scriptData->objVariablesOnHeap = 0; - - // Generate the bytecode for the factory stub - asUINT bcLength = asBCTypeSize[asBCInfo[asBC_OBJTYPE].type] + - asBCTypeSize[asBCInfo[asBC_CALLSYS].type] + - asBCTypeSize[asBCInfo[asBC_RET].type]; - - if( ep.includeJitInstructions ) - bcLength += asBCTypeSize[asBCInfo[asBC_JitEntry].type]; - if( templateType->flags & asOBJ_VALUE ) - bcLength += asBCTypeSize[asBCInfo[asBC_SwapPtr].type]; - - func->scriptData->byteCode.SetLength(bcLength); - asDWORD *bc = func->scriptData->byteCode.AddressOf(); - - if( ep.includeJitInstructions ) - { - *(asBYTE*)bc = asBC_JitEntry; - *(asPWORD*)(bc+1) = 0; - bc += asBCTypeSize[asBCInfo[asBC_JitEntry].type]; - } - - *(asBYTE*)bc = asBC_OBJTYPE; - *(asPWORD*)(bc+1) = (asPWORD)ot; - bc += asBCTypeSize[asBCInfo[asBC_OBJTYPE].type]; - if( templateType->flags & asOBJ_VALUE ) - { - // Swap the object pointer with the object type - *(asBYTE*)bc = asBC_SwapPtr; - bc += asBCTypeSize[asBCInfo[asBC_SwapPtr].type]; - } - *(asBYTE*)bc = asBC_CALLSYS; - *(asDWORD*)(bc+1) = factoryId; - bc += asBCTypeSize[asBCInfo[asBC_CALLSYS].type]; - *(asBYTE*)bc = asBC_RET; - *(((asWORD*)bc)+1) = (asWORD)func->GetSpaceNeededForArguments(); - - func->AddReferences(); - func->scriptData->stackNeeded = AS_PTR_SIZE; - - // Tell the virtual machine not to clean up the object on exception - func->dontCleanUpOnException = true; - - func->JITCompile(); - - // Need to translate the list pattern too so the VM and compiler will know the correct type of the members - if( factory->listPattern ) - { - asSListPatternNode *n = factory->listPattern; - asSListPatternNode *last = 0; - while( n ) - { - asSListPatternNode *newNode = n->Duplicate(); - if( newNode->type == asLPT_TYPE ) - { - asSListPatternDataTypeNode *typeNode = reinterpret_cast(newNode); - typeNode->dataType = DetermineTypeForTemplate(typeNode->dataType, templateType, ot); - } - - if( last ) - last->next = newNode; - else - func->listPattern = newNode; - - last = newNode; - - n = n->next; - } - } - - return func; -} - -bool asCScriptEngine::RequireTypeReplacement(asCDataType &type, asCObjectType *templateType) -{ - if( type.GetObjectType() == templateType ) return true; - if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE) ) return true; - if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_TEMPLATE) ) - { - for( asUINT n = 0; n < type.GetObjectType()->templateSubTypes.GetLength(); n++ ) - if( type.GetObjectType()->templateSubTypes[n].GetObjectType() && - type.GetObjectType()->templateSubTypes[n].GetObjectType()->flags & asOBJ_TEMPLATE_SUBTYPE ) - return true; - } - - return false; -} - -bool asCScriptEngine::GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *ot, asCScriptFunction *func, asCScriptFunction **newFunc) -{ - bool needNewFunc = false; - if( RequireTypeReplacement(func->returnType, templateType) ) - needNewFunc = true; - else - { - for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ ) - { - if( RequireTypeReplacement(func->parameterTypes[p], templateType) ) - { - needNewFunc = true; - break; - } - } - } - - if( !needNewFunc ) - return false; - - asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcType); - if( func2 == 0 ) - { - // Out of memory - return false; - } - - func2->name = func->name; - - func2->returnType = DetermineTypeForTemplate(func->returnType, templateType, ot); - func2->parameterTypes.SetLength(func->parameterTypes.GetLength()); - for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ ) - func2->parameterTypes[p] = DetermineTypeForTemplate(func->parameterTypes[p], templateType, ot); - - // TODO: template: Must be careful when instantiating templates for garbage collected types - // If the template hasn't been registered with the behaviours, it shouldn't - // permit instantiation of garbage collected types that in turn may refer to - // this instance. - - func2->inOutFlags = func->inOutFlags; - func2->isReadOnly = func->isReadOnly; - func2->objectType = ot; - func2->sysFuncIntf = asNEW(asSSystemFunctionInterface)(*func->sysFuncIntf); - - func2->id = GetNextScriptFunctionId(); - SetScriptFunction(func2); - - // Return the new function - *newFunc = func2; - - return true; -} - -void asCScriptEngine::CallObjectMethod(void *obj, int func) const -{ - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - CallObjectMethod(obj, s->sysFuncIntf, s); -} - -void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, asCScriptFunction *s) const -{ -#ifdef __GNUC__ - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - } - else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) - { - // For virtual thiscalls we must call the method as a true class method - // so that the compiler will lookup the function address in the vftable - union - { - asSIMPLEMETHOD_t mthd; - struct - { - asFUNCTION_t func; - asPWORD baseOffset; // Same size as the pointer - } f; - } p; - p.f.func = (asFUNCTION_t)(i->func); - p.f.baseOffset = asPWORD(i->baseOffset); - void (asCSimpleDummy::*f)() = p.mthd; - (((asCSimpleDummy*)obj)->*f)(); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - void (*f)(void *) = (void (*)(void *))(i->func); - f(obj); - } -#else -#ifndef AS_NO_CLASS_METHODS - if( i->callConv == ICC_THISCALL ) - { - union - { - asSIMPLEMETHOD_t mthd; - asFUNCTION_t func; - } p; - p.func = (asFUNCTION_t)(i->func); - void (asCSimpleDummy::*f)() = p.mthd; - obj = (void*)(asPWORD(obj) + i->baseOffset); - (((asCSimpleDummy*)obj)->*f)(); - } - else -#endif - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - void (*f)(void *) = (void (*)(void *))(i->func); - f(obj); - } -#endif -} - -bool asCScriptEngine::CallObjectMethodRetBool(void *obj, int func) const -{ - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - asSSystemFunctionInterface *i = s->sysFuncIntf; - -#ifdef __GNUC__ - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(bool*)gen.GetReturnPointer(); - } - else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) - { - // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable - union - { - asSIMPLEMETHOD_t mthd; - struct - { - asFUNCTION_t func; - asPWORD baseOffset; - } f; - } p; - p.f.func = (asFUNCTION_t)(i->func); - p.f.baseOffset = asPWORD(i->baseOffset); - bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())(p.mthd); - return (((asCSimpleDummy*)obj)->*f)(); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - bool (*f)(void *) = (bool (*)(void *))(i->func); - return f(obj); - } -#else -#ifndef AS_NO_CLASS_METHODS - if( i->callConv == ICC_THISCALL ) - { - union - { - asSIMPLEMETHOD_t mthd; - asFUNCTION_t func; - } p; - p.func = (asFUNCTION_t)(i->func); - bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())p.mthd; - obj = (void*)(asPWORD(obj) + i->baseOffset); - return (((asCSimpleDummy*)obj)->*f)(); - } - else -#endif - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(bool*)gen.GetReturnPointer(); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - bool (*f)(void *) = (bool (*)(void *))(i->func); - return f(obj); - } -#endif -} - -int asCScriptEngine::CallObjectMethodRetInt(void *obj, int func) const -{ - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - asSSystemFunctionInterface *i = s->sysFuncIntf; - -#ifdef __GNUC__ - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(int*)gen.GetReturnPointer(); - } - else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) - { - // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable - union - { - asSIMPLEMETHOD_t mthd; - struct - { - asFUNCTION_t func; - asPWORD baseOffset; - } f; - } p; - p.f.func = (asFUNCTION_t)(i->func); - p.f.baseOffset = asPWORD(i->baseOffset); - int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())(p.mthd); - return (((asCSimpleDummy*)obj)->*f)(); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - int (*f)(void *) = (int (*)(void *))(i->func); - return f(obj); - } -#else -#ifndef AS_NO_CLASS_METHODS - if( i->callConv == ICC_THISCALL ) - { - union - { - asSIMPLEMETHOD_t mthd; - asFUNCTION_t func; - } p; - p.func = (asFUNCTION_t)(i->func); - int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())p.mthd; - obj = (void*)(asPWORD(obj) + i->baseOffset); - return (((asCSimpleDummy*)obj)->*f)(); - } - else -#endif - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(int*)gen.GetReturnPointer(); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - int (*f)(void *) = (int (*)(void *))(i->func); - return f(obj); - } -#endif -} - -void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int func) const -{ - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - asSSystemFunctionInterface *i = s->sysFuncIntf; - -#ifdef __GNUC__ - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(void**)gen.GetReturnPointer(); - } - else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) - { - // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable - union - { - asSIMPLEMETHOD_t mthd; - struct - { - asFUNCTION_t func; - asPWORD baseOffset; - } f; - } p; - p.f.func = (asFUNCTION_t)(i->func); - p.f.baseOffset = asPWORD(i->baseOffset); - void *(asCSimpleDummy::*f)() = (void *(asCSimpleDummy::*)())(p.mthd); - return (((asCSimpleDummy*)obj)->*f)(); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - void *(*f)(void *) = (void *(*)(void *))(i->func); - return f(obj); - } -#else -#ifndef AS_NO_CLASS_METHODS - if( i->callConv == ICC_THISCALL ) - { - union - { - asSIMPLEMETHOD_t mthd; - asFUNCTION_t func; - } p; - p.func = (asFUNCTION_t)(i->func); - void *(asCSimpleDummy::*f)() = (void *(asCSimpleDummy::*)())p.mthd; - obj = (void*)(asPWORD(obj) + i->baseOffset); - return (((asCSimpleDummy*)obj)->*f)(); - } - else -#endif - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(void **)gen.GetReturnPointer(); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - void *(*f)(void *) = (void *(*)(void *))(i->func); - return f(obj); - } -#endif -} - -void *asCScriptEngine::CallGlobalFunctionRetPtr(int func) const -{ - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - return CallGlobalFunctionRetPtr(s->sysFuncIntf, s); -} - -void *asCScriptEngine::CallGlobalFunctionRetPtr(int func, void *param1) const -{ - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - return CallGlobalFunctionRetPtr(s->sysFuncIntf, s, param1); -} - -void *asCScriptEngine::CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s) const -{ - if( i->callConv == ICC_CDECL ) - { - void *(*f)() = (void *(*)())(i->func); - return f(); - } - else if( i->callConv == ICC_STDCALL ) - { - typedef void *(STDCALL *func_t)(); - func_t f = (func_t)(i->func); - return f(); - } - else - { - asCGeneric gen(const_cast(this), s, 0, 0); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(void**)gen.GetReturnPointer(); - } -} - -void *asCScriptEngine::CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s, void *param1) const -{ - if( i->callConv == ICC_CDECL ) - { - void *(*f)(void *) = (void *(*)(void *))(i->func); - return f(param1); - } - else if( i->callConv == ICC_STDCALL ) - { - typedef void *(STDCALL *func_t)(void *); - func_t f = (func_t)(i->func); - return f(param1); - } - else - { - asCGeneric gen(const_cast(this), s, 0, (asDWORD*)¶m1); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(void**)gen.GetReturnPointer(); - } -} - -void asCScriptEngine::CallObjectMethod(void *obj, void *param, int func) const -{ - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - CallObjectMethod(obj, param, s->sysFuncIntf, s); -} - -void asCScriptEngine::CallObjectMethod(void *obj, void *param, asSSystemFunctionInterface *i, asCScriptFunction *s) const -{ -#ifdef __GNUC__ - if( i->callConv == ICC_CDECL_OBJLAST ) - { - void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); - f(param, obj); - } - else if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, (asDWORD*)¶m); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - } - else if( i->callConv == ICC_VIRTUAL_THISCALL || i->callConv == ICC_THISCALL ) - { - // For virtual thiscalls we must call the method as a true class method - // so that the compiler will lookup the function address in the vftable - union - { - asSIMPLEMETHOD_t mthd; - struct - { - asFUNCTION_t func; - asPWORD baseOffset; // Same size as the pointer - } f; - } p; - p.f.func = (asFUNCTION_t)(i->func); - p.f.baseOffset = asPWORD(i->baseOffset); - void (asCSimpleDummy::*f)(void*) = (void (asCSimpleDummy::*)(void*))(p.mthd); - (((asCSimpleDummy*)obj)->*f)(param); - } - else /*if( i->callConv == ICC_CDECL_OBJFIRST */ - { - void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); - f(obj, param); - } -#else -#ifndef AS_NO_CLASS_METHODS - if( i->callConv == ICC_THISCALL ) - { - union - { - asSIMPLEMETHOD_t mthd; - asFUNCTION_t func; - } p; - p.func = (asFUNCTION_t)(i->func); - void (asCSimpleDummy::*f)(void *) = (void (asCSimpleDummy::*)(void *))(p.mthd); - obj = (void*)(asPWORD(obj) + i->baseOffset); - (((asCSimpleDummy*)obj)->*f)(param); - } - else -#endif - if( i->callConv == ICC_CDECL_OBJLAST ) - { - void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); - f(param, obj); - } - else if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), s, obj, (asDWORD*)¶m); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - } - else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/ - { - void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); - f(obj, param); - } -#endif -} - -void asCScriptEngine::CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *i, asCScriptFunction *s) const -{ - if( i->callConv == ICC_CDECL ) - { - void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); - f(param1, param2); - } - else if( i->callConv == ICC_STDCALL ) - { - typedef void (STDCALL *func_t)(void *, void *); - func_t f = (func_t)(i->func); - f(param1, param2); - } - else - { - // We must guarantee the order of the arguments which is why we copy them to this - // array. Otherwise the compiler may put them anywhere it likes, or even keep them - // in the registers which causes problem. - void *params[2] = {param1, param2}; - - asCGeneric gen(const_cast(this), s, 0, (asDWORD*)¶ms); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - } -} - -bool asCScriptEngine::CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *i, asCScriptFunction *s) const -{ - if( i->callConv == ICC_CDECL ) - { - bool (*f)(void *, void *) = (bool (*)(void *, void *))(i->func); - return f(param1, param2); - } - else if( i->callConv == ICC_STDCALL ) - { - typedef bool (STDCALL *func_t)(void *, void *); - func_t f = (func_t)(i->func); - return f(param1, param2); - } - else - { - // TODO: When simulating a 64bit environment by defining AS_64BIT_PTR on a 32bit platform this code - // fails, because the stack given to asCGeneric is not prepared with two 64bit arguments. - - // We must guarantee the order of the arguments which is why we copy them to this - // array. Otherwise the compiler may put them anywhere it likes, or even keep them - // in the registers which causes problem. - void *params[2] = {param1, param2}; - asCGeneric gen(const_cast(this), s, 0, (asDWORD*)params); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(bool*)gen.GetReturnPointer(); - } -} - -void *asCScriptEngine::CallAlloc(const asCObjectType *type) const -{ - // Allocate 4 bytes as the smallest size. Otherwise CallSystemFunction may try to - // copy a DWORD onto a smaller memory block, in case the object type is return in registers. - - // Pad to the next even 4 bytes to avoid asBC_CPY writing outside of allocated buffer for registered POD types - asUINT size = type->size; - if( size & 0x3 ) - size += 4 - (size & 0x3); - -#ifndef WIP_16BYTE_ALIGN -#if defined(AS_DEBUG) - return ((asALLOCFUNCDEBUG_t)userAlloc)(size, __FILE__, __LINE__); -#else - return userAlloc(size); -#endif -#else -#if defined(AS_DEBUG) - return ((asALLOCALIGNEDFUNCDEBUG_t)userAllocAligned)(size, type->alignment, __FILE__, __LINE__); -#else - return userAllocAligned(size, type->alignment); -#endif -#endif -} - -void asCScriptEngine::CallFree(void *obj) const -{ -#ifndef WIP_16BYTE_ALIGN - userFree(obj); -#else - userFreeAligned(obj); -#endif -} - -// interface -int asCScriptEngine::NotifyGarbageCollectorOfNewObject(void *obj, asIObjectType *type) -{ - return gc.AddScriptObjectToGC(obj, static_cast(type)); -} - -// interface -int asCScriptEngine::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asIObjectType **type) -{ - return gc.GetObjectInGC(idx, seqNbr, obj, type); -} - -// interface -int asCScriptEngine::GarbageCollect(asDWORD flags, asUINT iterations) -{ - return gc.GarbageCollect(flags, iterations); -} - -// interface -void asCScriptEngine::GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const -{ - gc.GetStatistics(currentSize, totalDestroyed, totalDetected, newObjects, totalNewDestroyed); -} - -// interface -void asCScriptEngine::GCEnumCallback(void *reference) -{ - gc.GCEnumCallback(reference); -} - - -// TODO: multithread: The mapTypeIdToDataType must be protected with critical sections in all functions that access it -int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const -{ - if( dtIn.IsNullHandle() ) return 0; - - // Register the base form - asCDataType dt(dtIn); - if( dt.GetObjectType() ) - dt.MakeHandle(false); - - // Find the existing type id - asSMapNode *cursor = 0; - mapTypeIdToDataType.MoveFirst(&cursor); - while( cursor ) - { - if( mapTypeIdToDataType.GetValue(cursor)->IsEqualExceptRefAndConst(dt) ) - { - int typeId = mapTypeIdToDataType.GetKey(cursor); - if( dtIn.GetObjectType() && !(dtIn.GetObjectType()->flags & asOBJ_ASHANDLE) ) - { - // The ASHANDLE types behave like handles, but are really - // value types so the typeId is never returned as a handle - if( dtIn.IsObjectHandle() ) - typeId |= asTYPEID_OBJHANDLE; - if( dtIn.IsHandleToConst() ) - typeId |= asTYPEID_HANDLETOCONST; - } - - return typeId; - } - - mapTypeIdToDataType.MoveNext(&cursor, cursor); - } - - // The type id doesn't exist, create it - - // Setup the basic type id - int typeId = typeIdSeqNbr++; - if( dt.GetObjectType() ) - { - if( dt.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT; - else if( dt.GetObjectType()->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE; - else if( dt.GetObjectType()->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this? - else typeId |= asTYPEID_APPOBJECT; - } - - // Insert the basic object type - asCDataType *newDt = asNEW(asCDataType)(dt); - if( newDt == 0 ) - { - // Out of memory - return 0; - } - - newDt->MakeReference(false); - newDt->MakeReadOnly(false); - newDt->MakeHandle(false); - - mapTypeIdToDataType.Insert(typeId, newDt); - - // Call recursively to get the correct typeId - return GetTypeIdFromDataType(dtIn); -} - -asCDataType asCScriptEngine::GetDataTypeFromTypeId(int typeId) const -{ - int baseId = typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR); - - asSMapNode *cursor = 0; - if( mapTypeIdToDataType.MoveTo(&cursor, baseId) ) - { - asCDataType dt(*mapTypeIdToDataType.GetValue(cursor)); - if( typeId & asTYPEID_OBJHANDLE ) - dt.MakeHandle(true, true); - if( typeId & asTYPEID_HANDLETOCONST ) - dt.MakeHandleToConst(true); - return dt; - } - - return asCDataType(); -} - -asCObjectType *asCScriptEngine::GetObjectTypeFromTypeId(int typeId) const -{ - asCDataType dt = GetDataTypeFromTypeId(typeId); - return dt.GetObjectType(); -} - -void asCScriptEngine::RemoveFromTypeIdMap(asCObjectType *type) -{ - asSMapNode *cursor = 0; - mapTypeIdToDataType.MoveFirst(&cursor); - while( cursor ) - { - asCDataType *dt = mapTypeIdToDataType.GetValue(cursor); - asSMapNode *old = cursor; - mapTypeIdToDataType.MoveNext(&cursor, cursor); - if( dt->GetObjectType() == type ) - { - asDELETE(dt,asCDataType); - mapTypeIdToDataType.Erase(old); - } - } -} - -// interface -asIObjectType *asCScriptEngine::GetObjectTypeByDecl(const char *decl) const -{ - asCDataType dt; - // This cast is ok, because we are not changing anything in the engine - asCBuilder bld(const_cast(this), 0); - - // Don't write parser errors to the message callback - bld.silent = true; - - int r = bld.ParseDataType(decl, &dt, defaultNamespace); - if( r < 0 ) - return 0; - - return dt.GetObjectType(); -} - -// interface -int asCScriptEngine::GetTypeIdByDecl(const char *decl) const -{ - asCDataType dt; - // This cast is ok, because we are not changing anything in the engine - asCBuilder bld(const_cast(this), 0); - - // Don't write parser errors to the message callback - bld.silent = true; - - int r = bld.ParseDataType(decl, &dt, defaultNamespace); - if( r < 0 ) - return asINVALID_TYPE; - - return GetTypeIdFromDataType(dt); -} - -// interface -const char *asCScriptEngine::GetTypeDeclaration(int typeId, bool includeNamespace) const -{ - asCDataType dt = GetDataTypeFromTypeId(typeId); - - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = dt.Format(includeNamespace); - - return tempString->AddressOf(); -} - -// interface -int asCScriptEngine::GetSizeOfPrimitiveType(int typeId) const -{ - asCDataType dt = GetDataTypeFromTypeId(typeId); - if( !dt.IsPrimitive() ) return 0; - - return dt.GetSizeInMemoryBytes(); -} - -// interface -void *asCScriptEngine::CreateScriptObject(const asIObjectType *type) -{ - if( type == 0 ) return 0; - - asCObjectType *objType = const_cast(reinterpret_cast(type)); - void *ptr = 0; - - // Check that there is a default factory for ref types - if( objType->beh.factory == 0 && (objType->flags & asOBJ_REF) ) - { - asCString str; - str.Format(TXT_FAILED_IN_FUNC_s_d, "CreateScriptObject", asNO_FUNCTION); - WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return 0; - } - - // Construct the object - if( objType->flags & asOBJ_SCRIPT_OBJECT ) - { - // Call the script class' default factory with a context - ptr = ScriptObjectFactory(objType, this); - } - else if( objType->flags & asOBJ_TEMPLATE ) - { - // The registered factory that takes the object type is moved - // to the construct behaviour when the type is instantiated -#ifdef AS_NO_EXCEPTIONS - ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType); -#else - try - { - ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType); - } - catch(...) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException(TXT_EXCEPTION_CAUGHT); - } -#endif - } - else if( objType->flags & asOBJ_REF ) - { - // Call the default factory directly -#ifdef AS_NO_EXCEPTIONS - ptr = CallGlobalFunctionRetPtr(objType->beh.factory); -#else - try - { - ptr = CallGlobalFunctionRetPtr(objType->beh.factory); - } - catch(...) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException(TXT_EXCEPTION_CAUGHT); - } -#endif - } - else - { - // Make sure there is a default constructor or that it is a POD type - if( objType->beh.construct == 0 && !(objType->flags & asOBJ_POD) ) - { - asCString str; - str.Format(TXT_FAILED_IN_FUNC_s_d, "CreateScriptObject", asNO_FUNCTION); - WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return 0; - } - - // Manually allocate the memory, then call the default constructor - ptr = CallAlloc(objType); - int funcIndex = objType->beh.construct; - if( funcIndex ) - { -#ifdef AS_NO_EXCEPTIONS - CallObjectMethod(ptr, funcIndex); -#else - try - { - CallObjectMethod(ptr, funcIndex); - } - catch(...) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException(TXT_EXCEPTION_CAUGHT); - - // Free the memory - CallFree(ptr); - ptr = 0; - } -#endif - } - } - - return ptr; -} - -// interface -void *asCScriptEngine::CreateUninitializedScriptObject(const asIObjectType *type) -{ - // This function only works for script classes. Registered types cannot be created this way. - if( type == 0 || !(type->GetFlags() & asOBJ_SCRIPT_OBJECT) ) - return 0; - - asCObjectType *objType = const_cast(reinterpret_cast(type)); - - // Construct the object, but do not call the actual constructor that initializes the members - // The initialization will be done by the application afterwards, e.g. through serialization. - asCScriptObject *obj = reinterpret_cast(CallAlloc(objType)); - - // Pre-initialize the memory so there are no invalid pointers - ScriptObject_ConstructUnitialized(objType, obj); - - return obj; -} - -// interface -void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asIObjectType *type) -{ - if( origObj == 0 || type == 0 ) return 0; - - void *newObj = 0; - - const asCObjectType *ot = reinterpret_cast(type); - // TODO: runtime optimize: Should call copy factory for ref types too - if( ot->beh.copyconstruct ) - { - // Manually allocate the memory, then call the copy constructor - newObj = CallAlloc(ot); -#ifdef AS_NO_EXCEPTIONS - CallObjectMethod(newObj, origObj, ot->beh.copyconstruct); -#else - try - { - CallObjectMethod(newObj, origObj, ot->beh.copyconstruct); - } - catch(...) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException(TXT_EXCEPTION_CAUGHT); - - // Free the memory - CallFree(newObj); - newObj = 0; - } -#endif - } - else - { - // Allocate the object and then do a value assign - newObj = CreateScriptObject(type); - if( newObj == 0 ) return 0; - - AssignScriptObject(newObj, origObj, type); - } - - return newObj; -} - -// internal -// TODO: interface: Should return status code -void asCScriptEngine::ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type) -{ - // TODO: Warn about invalid call in message stream - // TODO: Should a script exception be set in case a context is active? - if( type == 0 || mem == 0 || obj == 0 ) return; - - // This function is only meant to be used for value types - asASSERT( type->flags & asOBJ_VALUE ); - - // Call the copy constructor if available, else call the default constructor followed by the opAssign - int funcIndex = type->beh.copyconstruct; - if( funcIndex ) - { - CallObjectMethod(mem, obj, funcIndex); - } - else - { - funcIndex = type->beh.construct; - if( funcIndex ) - CallObjectMethod(mem, funcIndex); - - AssignScriptObject(mem, obj, type); - } -} - -// interface -// TODO: interface: Should return status code -void asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asIObjectType *type) -{ - // TODO: Warn about invalid call in message stream - // TODO: Should a script exception be set in case a context is active? - if( type == 0 || dstObj == 0 || srcObj == 0 ) return; - - const asCObjectType *objType = reinterpret_cast(type); - - // If value assign for ref types has been disabled, then don't do anything if the type is a ref type - if( ep.disallowValueAssignForRefType && (objType->flags & asOBJ_REF) && !(objType->flags & asOBJ_SCOPED) ) - return; - - // Must not copy if the opAssign is not available and the object is not a POD object - if( objType->beh.copy ) - { - asCScriptFunction *func = scriptFunctions[objType->beh.copy]; - if( func->funcType == asFUNC_SYSTEM ) - CallObjectMethod(dstObj, srcObj, objType->beh.copy); - else - { - // Call the script class' opAssign method - asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT ); - reinterpret_cast(dstObj)->CopyFrom(reinterpret_cast(srcObj)); - } - } - else if( objType->size && (objType->flags & asOBJ_POD) ) - { - memcpy(dstObj, srcObj, objType->size); - } -} - -// interface -void asCScriptEngine::AddRefScriptObject(void *obj, const asIObjectType *type) -{ - // Make sure it is not a null pointer - if( obj == 0 || type == 0 ) return; - - const asCObjectType *objType = static_cast(type); - if( objType->beh.addref ) - { - // Call the addref behaviour - CallObjectMethod(obj, objType->beh.addref); - } -} - -// interface -void asCScriptEngine::ReleaseScriptObject(void *obj, const asIObjectType *type) -{ - // Make sure it is not a null pointer - if( obj == 0 || type == 0 ) return; - - const asCObjectType *objType = static_cast(type); - if( objType->flags & asOBJ_REF ) - { - asASSERT( (objType->flags & asOBJ_NOCOUNT) || objType->beh.release ); - if( objType->beh.release ) - { - // Call the release behaviour - CallObjectMethod(obj, objType->beh.release); - } - } - else - { - // Call the destructor - if( objType->beh.destruct ) - CallObjectMethod(obj, objType->beh.destruct); - else if( objType->flags & asOBJ_LIST_PATTERN ) - DestroyList((asBYTE*)obj, objType); - - // We'll have to trust that the memory for the object was allocated with CallAlloc. - // This is true if the object was created in the context, or with CreateScriptObject. - - // Then free the memory - CallFree(obj); - } -} - -// interface -bool asCScriptEngine::IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const -{ - // if equal, then it is obvious they are compatible - if( objTypeId == handleTypeId ) - return true; - - // Get the actual data types from the type ids - asCDataType objDt = GetDataTypeFromTypeId(objTypeId); - asCDataType hdlDt = GetDataTypeFromTypeId(handleTypeId); - - // A handle to const cannot be passed to a handle that is not referencing a const object - if( objDt.IsHandleToConst() && !hdlDt.IsHandleToConst() ) - return false; - - if( objDt.GetObjectType() == hdlDt.GetObjectType() ) - { - // The object type is equal - return true; - } - else if( objDt.IsScriptObject() && obj ) - { - // Get the true type from the object instance - asCObjectType *objType = ((asCScriptObject*)obj)->objType; - - // Check if the object implements the interface, or derives from the base class - // This will also return true, if the requested handle type is an exact match for the object type - if( objType->Implements(hdlDt.GetObjectType()) || - objType->DerivesFrom(hdlDt.GetObjectType()) ) - return true; - } - - return false; -} - -// interface -int asCScriptEngine::BeginConfigGroup(const char *groupName) -{ - // Make sure the group name doesn't already exist - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - { - if( configGroups[n]->groupName == groupName ) - return asNAME_TAKEN; - } - - if( currentGroup != &defaultGroup ) - return asNOT_SUPPORTED; - - asCConfigGroup *group = asNEW(asCConfigGroup)(); - if( group == 0 ) - return asOUT_OF_MEMORY; - - group->groupName = groupName; - - configGroups.PushLast(group); - currentGroup = group; - - return 0; -} - -// interface -int asCScriptEngine::EndConfigGroup() -{ - // Raise error if trying to end the default config - if( currentGroup == &defaultGroup ) - return asERROR; - - currentGroup = &defaultGroup; - - return 0; -} - -// interface -int asCScriptEngine::RemoveConfigGroup(const char *groupName) -{ - // It is not allowed to remove a group that is still in use. - - // It would be possible to change the code in such a way that - // the group could be removed even though it was still in use, - // but that would cause severe negative impact on runtime - // performance, since the VM would then have to be able handle - // situations where the types, functions, and global variables - // can be removed at any time. - - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - { - if( configGroups[n]->groupName == groupName ) - { - asCConfigGroup *group = configGroups[n]; - - // Make sure the group isn't referenced by anyone - if( group->refCount > 0 ) - return asCONFIG_GROUP_IS_IN_USE; - - // Verify if any objects registered in this group is still alive - if( group->HasLiveObjects() ) - return asCONFIG_GROUP_IS_IN_USE; - - // Remove the group from the list - if( n == configGroups.GetLength() - 1 ) - configGroups.PopLast(); - else - configGroups[n] = configGroups.PopLast(); - - // Remove the configurations registered with this group - group->RemoveConfiguration(this); - - asDELETE(group,asCConfigGroup); - } - } - - return 0; -} - -asCConfigGroup *asCScriptEngine::FindConfigGroupForFunction(int funcId) const -{ - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - { - // Check global functions - asUINT m; - for( m = 0; m < configGroups[n]->scriptFunctions.GetLength(); m++ ) - { - if( configGroups[n]->scriptFunctions[m]->id == funcId ) - return configGroups[n]; - } - } - - return 0; -} - - -asCConfigGroup *asCScriptEngine::FindConfigGroupForGlobalVar(int gvarId) const -{ - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - { - for( asUINT m = 0; m < configGroups[n]->globalProps.GetLength(); m++ ) - { - if( int(configGroups[n]->globalProps[m]->id) == gvarId ) - return configGroups[n]; - } - } - - return 0; -} - -asCConfigGroup *asCScriptEngine::FindConfigGroupForObjectType(const asCObjectType *objType) const -{ - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - { - for( asUINT m = 0; m < configGroups[n]->objTypes.GetLength(); m++ ) - { - if( configGroups[n]->objTypes[m] == objType ) - return configGroups[n]; - } - } - - return 0; -} - -asCConfigGroup *asCScriptEngine::FindConfigGroupForFuncDef(const asCScriptFunction *funcDef) const -{ - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - { - asCScriptFunction *f = const_cast(funcDef); - if( configGroups[n]->funcDefs.Exists(f) ) - return configGroups[n]; - } - - return 0; -} - -// interface -asDWORD asCScriptEngine::SetDefaultAccessMask(asDWORD defaultMask) -{ - asDWORD old = defaultAccessMask; - defaultAccessMask = defaultMask; - return old; -} - -int asCScriptEngine::GetNextScriptFunctionId() -{ - // This function only returns the next function id that - // should be used. It doesn't update the internal arrays. - if( freeScriptFunctionIds.GetLength() ) - return freeScriptFunctionIds[freeScriptFunctionIds.GetLength()-1]; - - return (int)scriptFunctions.GetLength(); -} - -void asCScriptEngine::SetScriptFunction(asCScriptFunction *func) -{ - // Update the internal arrays with the function id that is now used - if( freeScriptFunctionIds.GetLength() && freeScriptFunctionIds[freeScriptFunctionIds.GetLength()-1] == func->id ) - freeScriptFunctionIds.PopLast(); - - if( asUINT(func->id) == scriptFunctions.GetLength() ) - scriptFunctions.PushLast(func); - else - { - // The slot should be empty or already set with the function, which happens if an existing shared function is reused - asASSERT( scriptFunctions[func->id] == 0 || scriptFunctions[func->id] == func ); - scriptFunctions[func->id] = func; - } -} - -void asCScriptEngine::FreeScriptFunctionId(int id) -{ - if( id < 0 ) return; - id &= ~FUNC_IMPORTED; - if( id >= (int)scriptFunctions.GetLength() ) return; - - if( scriptFunctions[id] ) - { - asCScriptFunction *func = scriptFunctions[id]; - - // Remove the function from the list of script functions - if( id == (int)scriptFunctions.GetLength() - 1 ) - { - scriptFunctions.PopLast(); - } - else - { - scriptFunctions[id] = 0; - freeScriptFunctionIds.PushLast(id); - } - - // Is the function used as signature id? - if( func->signatureId == id ) - { - // Remove the signature id - signatureIds.RemoveValue(func); - - // Update all functions using the signature id - int newSigId = 0; - for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ ) - { - if( scriptFunctions[n] && scriptFunctions[n]->signatureId == id ) - { - if( newSigId == 0 ) - { - newSigId = scriptFunctions[n]->id; - signatureIds.PushLast(scriptFunctions[n]); - } - - scriptFunctions[n]->signatureId = newSigId; - } - } - } - } -} - -// interface -int asCScriptEngine::RegisterFuncdef(const char *decl) -{ - if( decl == 0 ) return ConfigError(asINVALID_ARG, "RegisterFuncdef", decl, 0); - - // Parse the function declaration - asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_FUNCDEF); - if( func == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterFuncdef", decl, 0); - - asCBuilder bld(this, 0); - int r = bld.ParseFunctionDeclaration(0, decl, func, false, 0, 0, defaultNamespace); - if( r < 0 ) - { - // Set as dummy function before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asINVALID_DECLARATION, "RegisterFuncdef", decl, 0); - } - - // Check name conflicts - r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace); - if( r < 0 ) - { - asDELETE(func,asCScriptFunction); - return ConfigError(asNAME_TAKEN, "RegisterFuncdef", decl, 0); - } - - func->id = GetNextScriptFunctionId(); - SetScriptFunction(func); - - funcDefs.PushLast(func); - registeredFuncDefs.PushLast(func); - currentGroup->funcDefs.PushLast(func); - - // If parameter type from other groups are used, add references - if( func->returnType.GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType()); - currentGroup->RefConfigGroup(group); - } - for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - if( func->parameterTypes[n].GetObjectType() ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(func->parameterTypes[n].GetObjectType()); - currentGroup->RefConfigGroup(group); - } - } - - // Return the function id as success - return func->id; -} - -// interface -asUINT asCScriptEngine::GetFuncdefCount() const -{ - return asUINT(registeredFuncDefs.GetLength()); -} - -// interface -asIScriptFunction *asCScriptEngine::GetFuncdefByIndex(asUINT index) const -{ - if( index >= registeredFuncDefs.GetLength() ) - return 0; - - return registeredFuncDefs[index]; -} - -// interface -// TODO: typedef: Accept complex types for the typedefs -int asCScriptEngine::RegisterTypedef(const char *type, const char *decl) -{ - if( type == 0 ) return ConfigError(asINVALID_NAME, "RegisterTypedef", type, decl); - - // Verify if the name has been registered as a type already - // TODO: Must check against registered funcdefs too - if( GetRegisteredObjectType(type, defaultNamespace) ) - // Let the application recover from this error, for example if the same typedef is registered twice - return asALREADY_REGISTERED; - - // Grab the data type - size_t tokenLen; - eTokenType token; - asCDataType dataType; - - // Create the data type - token = tok.GetToken(decl, strlen(decl), &tokenLen); - switch(token) - { - case ttBool: - case ttInt: - case ttInt8: - case ttInt16: - case ttInt64: - case ttUInt: - case ttUInt8: - case ttUInt16: - case ttUInt64: - case ttFloat: - case ttDouble: - if( strlen(decl) != tokenLen ) - { - return ConfigError(asINVALID_TYPE, "RegisterTypedef", type, decl); - } - break; - - default: - return ConfigError(asINVALID_TYPE, "RegisterTypedef", type, decl); - } - - dataType = asCDataType::CreatePrimitive(token, false); - - // Make sure the name is not a reserved keyword - token = tok.GetToken(type, strlen(type), &tokenLen); - if( token != ttIdentifier || strlen(type) != tokenLen ) - return ConfigError(asINVALID_NAME, "RegisterTypedef", type, decl); - - asCBuilder bld(this, 0); - int r = bld.CheckNameConflict(type, 0, 0, defaultNamespace); - if( r < 0 ) - return ConfigError(asNAME_TAKEN, "RegisterTypedef", type, decl); - - // Don't have to check against members of object - // types as they are allowed to use the names - - // Put the data type in the list - asCObjectType *object = asNEW(asCObjectType)(this); - if( object == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterTypedef", type, decl); - - object->flags = asOBJ_TYPEDEF; - object->size = dataType.GetSizeInMemoryBytes(); - object->name = type; - object->nameSpace = defaultNamespace; - object->templateSubTypes.PushLast(dataType); - - allRegisteredTypes.Insert(asSNameSpaceNamePair(object->nameSpace, object->name), object); - registeredTypeDefs.PushLast(object); - - currentGroup->objTypes.PushLast(object); - - return asSUCCESS; -} - -// interface -asUINT asCScriptEngine::GetTypedefCount() const -{ - return asUINT(registeredTypeDefs.GetLength()); -} - -// interface -const char *asCScriptEngine::GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace, const char **configGroup, asDWORD *accessMask) const -{ - if( index >= registeredTypeDefs.GetLength() ) - return 0; - - if( typeId ) - *typeId = GetTypeIdFromDataType(registeredTypeDefs[index]->templateSubTypes[0]); - - if( configGroup ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(registeredTypeDefs[index]); - if( group ) - *configGroup = group->groupName.AddressOf(); - else - *configGroup = 0; - } - - if( accessMask ) - *accessMask = registeredTypeDefs[index]->accessMask; - - if( nameSpace ) - *nameSpace = registeredTypeDefs[index]->nameSpace->name.AddressOf(); - - return registeredTypeDefs[index]->name.AddressOf(); -} - -// interface -int asCScriptEngine::RegisterEnum(const char *name) -{ - // Check the name - if( NULL == name ) - return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0); - - // Verify if the name has been registered as a type already - // TODO: Must check for registered funcdefs too - if( GetRegisteredObjectType(name, defaultNamespace) ) - return asALREADY_REGISTERED; - - // Use builder to parse the datatype - asCDataType dt; - asCBuilder bld(this, 0); - bool oldMsgCallback = msgCallback; msgCallback = false; - int r = bld.ParseDataType(name, &dt, defaultNamespace); - msgCallback = oldMsgCallback; - if( r >= 0 ) - return ConfigError(asERROR, "RegisterEnum", name, 0); - - // Make sure the name is not a reserved keyword - size_t tokenLen; - int token = tok.GetToken(name, strlen(name), &tokenLen); - if( token != ttIdentifier || strlen(name) != tokenLen ) - return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0); - - r = bld.CheckNameConflict(name, 0, 0, defaultNamespace); - if( r < 0 ) - return ConfigError(asNAME_TAKEN, "RegisterEnum", name, 0); - - asCObjectType *st = asNEW(asCObjectType)(this); - if( st == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterEnum", name, 0); - - asCDataType dataType; - dataType.CreatePrimitive(ttInt, false); - - st->flags = asOBJ_ENUM | asOBJ_SHARED; - st->size = 4; - st->name = name; - st->nameSpace = defaultNamespace; - - allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); - registeredEnums.PushLast(st); - - currentGroup->objTypes.PushLast(st); - - return asSUCCESS; -} - -// interface -int asCScriptEngine::RegisterEnumValue(const char *typeName, const char *valueName, int value) -{ - // Verify that the correct config group is used - if( currentGroup->FindType(typeName) == 0 ) - return ConfigError(asWRONG_CONFIG_GROUP, "RegisterEnumValue", typeName, valueName); - - asCDataType dt; - int r; - asCBuilder bld(this, 0); - r = bld.ParseDataType(typeName, &dt, defaultNamespace); - if( r < 0 ) - return ConfigError(r, "RegisterEnumValue", typeName, valueName); - - // Store the enum value - asCObjectType *ot = dt.GetObjectType(); - if( ot == 0 || !(ot->flags & asOBJ_ENUM) ) - return ConfigError(asINVALID_TYPE, "RegisterEnumValue", typeName, valueName); - - if( NULL == valueName ) - return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName); - - int tokenLen; - asETokenClass tokenClass = ParseToken(valueName, 0, &tokenLen); - if( tokenClass != asTC_IDENTIFIER || tokenLen != (int)strlen(valueName) ) - return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName); - - for( unsigned int n = 0; n < ot->enumValues.GetLength(); n++ ) - { - if( ot->enumValues[n]->name == valueName ) - return ConfigError(asALREADY_REGISTERED, "RegisterEnumValue", typeName, valueName); - } - - asSEnumValue *e = asNEW(asSEnumValue); - if( e == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterEnumValue", typeName, valueName); - - e->name = valueName; - e->value = value; - - ot->enumValues.PushLast(e); - - return asSUCCESS; -} - -// interface -asUINT asCScriptEngine::GetEnumCount() const -{ - return asUINT(registeredEnums.GetLength()); -} - -// interface -const char *asCScriptEngine::GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace, const char **configGroup, asDWORD *accessMask) const -{ - if( index >= registeredEnums.GetLength() ) - return 0; - - if( configGroup ) - { - asCConfigGroup *group = FindConfigGroupForObjectType(registeredEnums[index]); - if( group ) - *configGroup = group->groupName.AddressOf(); - else - *configGroup = 0; - } - - if( accessMask ) - *accessMask = registeredEnums[index]->accessMask; - - if( enumTypeId ) - *enumTypeId = GetTypeIdFromDataType(asCDataType::CreateObject(registeredEnums[index], false)); - - if( nameSpace ) - *nameSpace = registeredEnums[index]->nameSpace->name.AddressOf(); - - return registeredEnums[index]->name.AddressOf(); -} - -// interface -int asCScriptEngine::GetEnumValueCount(int enumTypeId) const -{ - asCDataType dt = GetDataTypeFromTypeId(enumTypeId); - asCObjectType *t = dt.GetObjectType(); - if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) ) - return asINVALID_TYPE; - - return (int)t->enumValues.GetLength(); -} - -// interface -const char *asCScriptEngine::GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const -{ - // TODO: This same function is implemented in as_module.cpp as well. Perhaps it should be moved to asCObjectType? - asCDataType dt = GetDataTypeFromTypeId(enumTypeId); - asCObjectType *t = dt.GetObjectType(); - if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) ) - return 0; - - if( index >= t->enumValues.GetLength() ) - return 0; - - if( outValue ) - *outValue = t->enumValues[index]->value; - - return t->enumValues[index]->name.AddressOf(); -} - -// interface -asUINT asCScriptEngine::GetObjectTypeCount() const -{ - return asUINT(registeredObjTypes.GetLength()); -} - -// interface -asIObjectType *asCScriptEngine::GetObjectTypeByIndex(asUINT index) const -{ - if( index >= registeredObjTypes.GetLength() ) - return 0; - - return registeredObjTypes[index]; -} - -// interface -asIObjectType *asCScriptEngine::GetObjectTypeByName(const char *name) const -{ - // Check the object types - for( asUINT n = 0; n < registeredObjTypes.GetLength(); n++ ) - { - if( registeredObjTypes[n]->name == name && - registeredObjTypes[n]->nameSpace == defaultNamespace ) - return registeredObjTypes[n]; - } - - // Perhaps it is a template type? In this case - // the returned type will be the generic type - for( asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++ ) - { - if( registeredTemplateTypes[n]->name == name && - registeredTemplateTypes[n]->nameSpace == defaultNamespace ) - return registeredTemplateTypes[n]; - } - - return 0; -} - -// interface -asIObjectType *asCScriptEngine::GetObjectTypeById(int typeId) const -{ - asCDataType dt = GetDataTypeFromTypeId(typeId); - - // Is the type id valid? - if( !dt.IsValid() ) return 0; - - // Enum types are not objects, so we shouldn't return an object type for them - if( dt.GetObjectType() && dt.GetObjectType()->GetFlags() & asOBJ_ENUM ) - return 0; - - return dt.GetObjectType(); -} - -// interface -asIScriptFunction *asCScriptEngine::GetFunctionById(int funcId) const -{ - return GetScriptFunction(funcId); -} - -// interface -asIScriptFunction *asCScriptEngine::GetFuncDefFromTypeId(int typeId) const -{ - return GetDataTypeFromTypeId(typeId).GetFuncDef(); -} - -// internal -bool asCScriptEngine::IsTemplateType(const char *name) const -{ - // Only look in the list of template types (not instance types) - for( unsigned int n = 0; n < registeredTemplateTypes.GetLength(); n++ ) - { - asCObjectType *type = registeredTemplateTypes[n]; - if( type && type->name == name ) - return true; - } - - return false; -} - -// internal -int asCScriptEngine::AddConstantString(const char *str, size_t len) -{ - // This is only called when build a script module, so it is - // known that only one thread can enter the function at a time. - asASSERT( isBuilding ); - - // The str may contain null chars, so we cannot use strlen, or strcmp, or strcpy - - // Has the string been registered before? - asSMapNode *cursor = 0; - if (stringToIdMap.MoveTo(&cursor, asCStringPointer(str, len))) - return cursor->value; - - // No match was found, add the string - asCString *cstr = asNEW(asCString)(str, len); - if( cstr ) - { - stringConstants.PushLast(cstr); - int index = (int)stringConstants.GetLength() - 1; - stringToIdMap.Insert(asCStringPointer(cstr), index); - - // The VM currently doesn't handle string ids larger than 65535 - asASSERT(stringConstants.GetLength() <= 65536); - - return index; - } - - return 0; -} - -// internal -const asCString &asCScriptEngine::GetConstantString(int id) -{ - return *stringConstants[id]; -} - -// internal -int asCScriptEngine::GetScriptSectionNameIndex(const char *name) -{ - ACQUIREEXCLUSIVE(engineRWLock); - - // TODO: These names are only released when the engine is freed. The assumption is that - // the same script section names will be reused instead of there always being new - // names. Is this assumption valid? Do we need to add reference counting? - - // Store the script section names for future reference - for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ ) - { - if( scriptSectionNames[n]->Compare(name) == 0 ) - { - RELEASEEXCLUSIVE(engineRWLock); - return n; - } - } - - asCString *str = asNEW(asCString)(name); - if( str ) - scriptSectionNames.PushLast(str); - int r = int(scriptSectionNames.GetLength()-1); - - RELEASEEXCLUSIVE(engineRWLock); - - return r; -} - -// interface -void asCScriptEngine::SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type) -{ - ACQUIREEXCLUSIVE(engineRWLock); - - for( asUINT n = 0; n < cleanEngineFuncs.GetLength(); n++ ) - { - if( cleanEngineFuncs[n].type == type ) - { - cleanEngineFuncs[n].cleanFunc = callback; - - RELEASEEXCLUSIVE(engineRWLock); - - return; - } - } - SEngineClean otc = {type, callback}; - cleanEngineFuncs.PushLast(otc); - - RELEASEEXCLUSIVE(engineRWLock); -} - -// interface -void asCScriptEngine::SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type) -{ - ACQUIREEXCLUSIVE(engineRWLock); - - for( asUINT n = 0; n < cleanModuleFuncs.GetLength(); n++ ) - { - if( cleanModuleFuncs[n].type == type ) - { - cleanModuleFuncs[n].cleanFunc = callback; - - RELEASEEXCLUSIVE(engineRWLock); - - return; - } - } - SModuleClean otc = {type, callback}; - cleanModuleFuncs.PushLast(otc); - - RELEASEEXCLUSIVE(engineRWLock); -} - -// interface -void asCScriptEngine::SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type) -{ - ACQUIREEXCLUSIVE(engineRWLock); - - for( asUINT n = 0; n < cleanContextFuncs.GetLength(); n++ ) - { - if( cleanContextFuncs[n].type == type ) - { - cleanContextFuncs[n].cleanFunc = callback; - - RELEASEEXCLUSIVE(engineRWLock); - - return; - } - } - SContextClean otc = {type, callback}; - cleanContextFuncs.PushLast(otc); - - RELEASEEXCLUSIVE(engineRWLock); -} - -// interface -void asCScriptEngine::SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type) -{ - ACQUIREEXCLUSIVE(engineRWLock); - - for( asUINT n = 0; n < cleanFunctionFuncs.GetLength(); n++ ) - { - if( cleanFunctionFuncs[n].type == type ) - { - cleanFunctionFuncs[n].cleanFunc = callback; - - RELEASEEXCLUSIVE(engineRWLock); - - return; - } - } - SFunctionClean otc = {type, callback}; - cleanFunctionFuncs.PushLast(otc); - - RELEASEEXCLUSIVE(engineRWLock); -} - -// interface -void asCScriptEngine::SetObjectTypeUserDataCleanupCallback(asCLEANOBJECTTYPEFUNC_t callback, asPWORD type) -{ - ACQUIREEXCLUSIVE(engineRWLock); - - for( asUINT n = 0; n < cleanObjectTypeFuncs.GetLength(); n++ ) - { - if( cleanObjectTypeFuncs[n].type == type ) - { - cleanObjectTypeFuncs[n].cleanFunc = callback; - - RELEASEEXCLUSIVE(engineRWLock); - - return; - } - } - SObjTypeClean otc = {type, callback}; - cleanObjectTypeFuncs.PushLast(otc); - - RELEASEEXCLUSIVE(engineRWLock); -} - -// internal -asCObjectType *asCScriptEngine::GetListPatternType(int listPatternFuncId) -{ - // Get the object type either from the constructor's object for value types - // or from the factory's return type for reference types - asCObjectType *ot = scriptFunctions[listPatternFuncId]->objectType; - if( ot == 0 ) - ot = scriptFunctions[listPatternFuncId]->returnType.GetObjectType(); - asASSERT( ot ); - - // Check if this object type already has a list pattern type - for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) - { - if( listPatternTypes[n]->templateSubTypes[0].GetObjectType() == ot ) - return listPatternTypes[n]; - } - - // Create a new list pattern type for the given object type - asCObjectType *lpt = asNEW(asCObjectType)(this); - lpt->templateSubTypes.PushLast(asCDataType::CreateObject(ot, false)); - lpt->flags = asOBJ_LIST_PATTERN; - listPatternTypes.PushLast(lpt); - - return lpt; -} - -// internal -void asCScriptEngine::DestroyList(asBYTE *buffer, const asCObjectType *listPatternType) -{ - asASSERT( listPatternType && (listPatternType->flags & asOBJ_LIST_PATTERN) ); - - // Get the list pattern from the listFactory function - // TODO: runtime optimize: Store the used list factory in the listPatternType itself - // TODO: runtime optimize: Keep a flag to indicate if there is really a need to free anything - asCObjectType *ot = listPatternType->templateSubTypes[0].GetObjectType(); - asCScriptFunction *listFactory = scriptFunctions[ot->beh.listFactory]; - asASSERT( listFactory ); - - asSListPatternNode *node = listFactory->listPattern; - DestroySubList(buffer, node); - - asASSERT( node->type == asLPT_END ); -} - -// internal -void asCScriptEngine::DestroySubList(asBYTE *&buffer, asSListPatternNode *&node) -{ - asASSERT( node->type == asLPT_START ); - - int count = 0; - - node = node->next; - while( node ) - { - if( node->type == asLPT_REPEAT || node->type == asLPT_REPEAT_SAME ) - { - // Align the offset to 4 bytes boundary - if( (asPWORD(buffer) & 0x3) ) - buffer += 4 - (asPWORD(buffer) & 0x3); - - // Determine how many times the pattern repeat - count = *(asUINT*)buffer; - buffer += 4; - - if( count == 0 ) - { - // Skip the sub pattern that was expected to be repeated, otherwise - // we'll try to delete things that don't exist in the buffer - node = node->next; - if( node->type == asLPT_START ) - { - int subCount = 1; - do - { - node = node->next; - if( node->type == asLPT_START ) - subCount++; - else if( node->type == asLPT_END ) - subCount--; - } while( subCount > 0 ); - return; - } - } - } - else if( node->type == asLPT_TYPE ) - { - // If we're not in a repeat iteration, then only 1 value should be destroyed - if( count <= 0 ) - count = 1; - - asCDataType dt = reinterpret_cast(node)->dataType; - bool isVarType = dt.GetTokenType() == ttQuestion; - - while( count-- ) - { - if( isVarType ) - { - // Align the offset to 4 bytes boundary - if( (asPWORD(buffer) & 0x3) ) - buffer += 4 - (asPWORD(buffer) & 0x3); - - int typeId = *(int*)buffer; - buffer += 4; - dt = GetDataTypeFromTypeId(typeId); - } - - asCObjectType *ot = dt.GetObjectType(); - if( ot && (ot->flags & asOBJ_ENUM) == 0 ) - { - // Free all instances of this type - if( ot->flags & asOBJ_VALUE ) - { - asUINT size = ot->GetSize(); - - // Align the offset to 4 bytes boundary - if( size >= 4 && (asPWORD(buffer) & 0x3) ) - buffer += 4 - (asPWORD(buffer) & 0x3); - - if( ot->beh.destruct ) - { - // Only call the destructor if the object has been created - // We'll assume the object has been created if any byte in - // the memory is different from 0. - // TODO: This is not really correct, as bytes may have been - // modified by the constructor, but then an exception - // thrown aborting the initialization. The engine - // really should be keeping track of which objects has - // been successfully initialized. - - for( asUINT n = 0; n < size; n++ ) - { - if( buffer[n] != 0 ) - { - void *ptr = (void*)buffer; - CallObjectMethod(ptr, ot->beh.destruct); - break; - } - } - } - - // Advance the pointer in the buffer - buffer += size; - } - else - { - // Align the offset to 4 bytes boundary - if( asPWORD(buffer) & 0x3 ) - buffer += 4 - (asPWORD(buffer) & 0x3); - - // Call the release behaviour - void *ptr = *(void**)buffer; - if( ptr ) - ReleaseScriptObject(ptr, ot); - buffer += AS_PTR_SIZE*4; - } - } - else - { - asUINT size = dt.GetSizeInMemoryBytes(); - - // Align the offset to 4 bytes boundary - if( size >= 4 && (asPWORD(buffer) & 0x3) ) - buffer += 4 - (asPWORD(buffer) & 0x3); - - // Advance the buffer - buffer += size; - } - } - } - else if( node->type == asLPT_START ) - { - // If we're not in a repeat iteration, then only 1 value should be destroyed - if( count <= 0 ) - count = 1; - - while( count-- ) - { - asSListPatternNode *subList = node; - DestroySubList(buffer, subList); - - asASSERT( subList->type == asLPT_END ); - - if( count == 0 ) - node = subList; - } - } - else if( node->type == asLPT_END ) - { - return; - } - else - { - asASSERT( false ); - } - - node = node->next; - } -} - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_scriptengine.h b/dependencies/angelscript/source/as_scriptengine.h deleted file mode 100644 index 9f4b716e..00000000 --- a/dependencies/angelscript/source/as_scriptengine.h +++ /dev/null @@ -1,490 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_scriptengine.h -// -// The implementation of the script engine interface -// - - - -#ifndef AS_SCRIPTENGINE_H -#define AS_SCRIPTENGINE_H - -#include "as_config.h" -#include "as_atomic.h" -#include "as_scriptfunction.h" -#include "as_array.h" -#include "as_datatype.h" -#include "as_objecttype.h" -#include "as_module.h" -#include "as_callfunc.h" -#include "as_configgroup.h" -#include "as_memory.h" -#include "as_gc.h" -#include "as_tokenizer.h" - -BEGIN_AS_NAMESPACE - -class asCBuilder; -class asCContext; - -// TODO: import: Remove this when import is removed -struct sBindInfo; - -class asCScriptEngine : public asIScriptEngine -{ -//============================================================= -// From asIScriptEngine -//============================================================= -public: - // Memory management - virtual int AddRef() const; - virtual int Release() const; - - // Engine properties - virtual int SetEngineProperty(asEEngineProp property, asPWORD value); - virtual asPWORD GetEngineProperty(asEEngineProp property) const; - - // Compiler messages - virtual int SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv); - virtual int ClearMessageCallback(); - virtual int WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message); - - // JIT Compiler - virtual int SetJITCompiler(asIJITCompiler *compiler); - virtual asIJITCompiler *GetJITCompiler() const; - - // Global functions - virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0); - virtual asUINT GetGlobalFunctionCount() const; - virtual asIScriptFunction *GetGlobalFunctionByIndex(asUINT index) const; - virtual asIScriptFunction *GetGlobalFunctionByDecl(const char *declaration) const; - - // Global properties - virtual int RegisterGlobalProperty(const char *declaration, void *pointer); - virtual asUINT GetGlobalPropertyCount() const; - virtual int GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace = 0, int *typeId = 0, bool *isConst = 0, const char **configGroup = 0, void **pointer = 0, asDWORD *accessMask = 0) const; - virtual int GetGlobalPropertyIndexByName(const char *name) const; - virtual int GetGlobalPropertyIndexByDecl(const char *decl) const; - - // Type registration - virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags); - virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset); - virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0); - virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0); - virtual int RegisterInterface(const char *name); - virtual int RegisterInterfaceMethod(const char *intf, const char *declaration); - virtual asUINT GetObjectTypeCount() const; - virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const; - virtual asIObjectType *GetObjectTypeByName(const char *name) const; - virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const; - - // String factory - virtual int RegisterStringFactory(const char *datatype, const asSFuncPtr &factoryFunc, asDWORD callConv, void *objForThiscall = 0); - virtual int GetStringFactoryReturnTypeId(asDWORD *flags) const; - - // Default array type - virtual int RegisterDefaultArrayType(const char *type); - virtual int GetDefaultArrayTypeId() const; - - // Enums - virtual int RegisterEnum(const char *type); - virtual int RegisterEnumValue(const char *type, const char *name, int value); - virtual asUINT GetEnumCount() const; - virtual const char *GetEnumByIndex(asUINT index, int *enumTypeId, const char **nameSpace, const char **configGroup = 0, asDWORD *accessMask = 0) const; - virtual int GetEnumValueCount(int enumTypeId) const; - virtual const char *GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue) const; - - // Funcdefs - virtual int RegisterFuncdef(const char *decl); - virtual asUINT GetFuncdefCount() const; - virtual asIScriptFunction *GetFuncdefByIndex(asUINT index) const; - - // Typedefs - // TODO: interface: Should perhaps rename this to Alias, since it doesn't really create a new type - virtual int RegisterTypedef(const char *type, const char *decl); - virtual asUINT GetTypedefCount() const; - virtual const char *GetTypedefByIndex(asUINT index, int *typeId, const char **nameSpace, const char **configGroup = 0, asDWORD *accessMask = 0) const; - - // Configuration groups - virtual int BeginConfigGroup(const char *groupName); - virtual int EndConfigGroup(); - virtual int RemoveConfigGroup(const char *groupName); - virtual asDWORD SetDefaultAccessMask(asDWORD defaultMask); - virtual int SetDefaultNamespace(const char *nameSpace); - virtual const char *GetDefaultNamespace() const; - - // Script modules - virtual asIScriptModule *GetModule(const char *module, asEGMFlags flag); - virtual int DiscardModule(const char *module); - virtual asUINT GetModuleCount() const; - virtual asIScriptModule *GetModuleByIndex(asUINT index) const; - - // Script functions - virtual asIScriptFunction *GetFunctionById(int funcId) const; - virtual asIScriptFunction *GetFuncDefFromTypeId(int typeId) const; - - // Type identification - virtual asIObjectType *GetObjectTypeById(int typeId) const; - virtual int GetTypeIdByDecl(const char *decl) const; - virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const; - virtual int GetSizeOfPrimitiveType(int typeId) const; - - // Script execution - virtual asIScriptContext *CreateContext(); - virtual void *CreateScriptObject(const asIObjectType *type); - virtual void *CreateScriptObjectCopy(void *obj, const asIObjectType *type); - virtual void *CreateUninitializedScriptObject(const asIObjectType *type); - virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj); - virtual void AssignScriptObject(void *dstObj, void *srcObj, const asIObjectType *type); - virtual void ReleaseScriptObject(void *obj, const asIObjectType *type); - virtual void AddRefScriptObject(void *obj, const asIObjectType *type); - // TODO: interface: Should have a method void *CastObject(void *obj, asIObjectType *fromType, asIObjectType *toType); - // For script objects it should simply check if the object implements or derives from the toType - // For application objects it should look for ref cast behaviours and call the matching one - // Once implemented the IsHandleCompatibleWithObject should be removed from the engine - virtual bool IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const; - virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const; - - // Context pooling - virtual asIScriptContext *RequestContext(); - virtual void ReturnContext(asIScriptContext *ctx); - virtual int SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param = 0); - - // String interpretation - virtual asETokenClass ParseToken(const char *string, size_t stringLength = 0, int *tokenLength = 0) const; - - // Garbage collection - virtual int GarbageCollect(asDWORD flags = asGC_FULL_CYCLE, asUINT numIterations = 1); - virtual void GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const; - virtual int NotifyGarbageCollectorOfNewObject(void *obj, asIObjectType *type); - virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj = 0, asIObjectType **type = 0); - virtual void GCEnumCallback(void *reference); - - // User data - virtual void *SetUserData(void *data, asPWORD type); - virtual void *GetUserData(asPWORD type) const; - virtual void SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type); - virtual void SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type); - virtual void SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type); - virtual void SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type); - virtual void SetObjectTypeUserDataCleanupCallback(asCLEANOBJECTTYPEFUNC_t callback, asPWORD type); - -//=========================================================== -// internal methods -//=========================================================== -public: - asCScriptEngine(); - virtual ~asCScriptEngine(); - -//protected: - friend class asCBuilder; - friend class asCCompiler; - friend class asCContext; - friend class asCDataType; - friend class asCModule; - friend class asCRestore; - friend class asCByteCode; - friend int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine); - - int RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0); - int RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall); - - int VerifyVarTypeNotInFunction(asCScriptFunction *func); - - void *CallAlloc(const asCObjectType *objType) const; - void CallFree(void *obj) const; - - void *CallGlobalFunctionRetPtr(int func) const; - void *CallGlobalFunctionRetPtr(int func, void *param1) const; - void *CallGlobalFunctionRetPtr(asSSystemFunctionInterface *func, asCScriptFunction *desc) const; - void *CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s, void *param1) const; - void CallObjectMethod(void *obj, int func) const; - void CallObjectMethod(void *obj, void *param, int func) const; - void CallObjectMethod(void *obj, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; - void CallObjectMethod(void *obj, void *param, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; - bool CallObjectMethodRetBool(void *obj, int func) const; - int CallObjectMethodRetInt(void *obj, int func) const; - void *CallObjectMethodRetPtr(void *obj, int func) const; - void CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; - bool CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; - - void ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type); - - void CleanupAfterDiscardModule(); - - int ClearUnusedTypes(); - void RemoveTemplateInstanceType(asCObjectType *t); - void RemoveTypeAndRelatedFromList(asCMap &types, asCObjectType *ot); - - asCConfigGroup *FindConfigGroupForFunction(int funcId) const; - asCConfigGroup *FindConfigGroupForGlobalVar(int gvarId) const; - asCConfigGroup *FindConfigGroupForObjectType(const asCObjectType *type) const; - asCConfigGroup *FindConfigGroupForFuncDef(const asCScriptFunction *funcDef) const; - - int RequestBuild(); - void BuildCompleted(); - - void PrepareEngine(); - bool isPrepared; - - int CreateContext(asIScriptContext **context, bool isInternal); - - asCObjectType *GetRegisteredObjectType(const asCString &name, asSNameSpace *ns) const; - - asCObjectType *GetListPatternType(int listPatternFuncId); - void DestroyList(asBYTE *buffer, const asCObjectType *listPatternType); - void DestroySubList(asBYTE *&buffer, asSListPatternNode *&patternNode); - - int AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal); - - asCString GetFunctionDeclaration(int funcId); - - asCScriptFunction *GetScriptFunction(int funcId) const; - - asCModule *GetModule(const char *name, bool create); - asCModule *GetModuleFromFuncId(int funcId); - - int GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod); - int GetFactoryIdByDecl(const asCObjectType *ot, const char *decl); - - int GetNextScriptFunctionId(); - void SetScriptFunction(asCScriptFunction *func); - void FreeScriptFunctionId(int id); - - int ConfigError(int err, const char *funcName, const char *arg1, const char *arg2); - - int GetTypeIdFromDataType(const asCDataType &dt) const; - asCDataType GetDataTypeFromTypeId(int typeId) const; - asCObjectType *GetObjectTypeFromTypeId(int typeId) const; - void RemoveFromTypeIdMap(asCObjectType *type); - - bool IsTemplateType(const char *name) const; - asCObjectType *GetTemplateInstanceType(asCObjectType *templateType, asCArray &subTypes); - asCScriptFunction *GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *templateInstanceType, int origFactoryId); - bool GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *templateInstanceType, asCScriptFunction *templateFunc, asCScriptFunction **newFunc); - void OrphanTemplateInstances(asCObjectType *subType); - asCDataType DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot); - bool RequireTypeReplacement(asCDataType &type, asCObjectType *templateType); - - - // String constants - // TODO: Must free unused string constants, thus the ref count for each must be tracked - int AddConstantString(const char *str, size_t length); - const asCString &GetConstantString(int id); - - // Global property management - asCGlobalProperty *AllocateGlobalProperty(); - void FreeUnusedGlobalProperties(); - - int GetScriptSectionNameIndex(const char *name); - - // Namespace management - asSNameSpace *AddNameSpace(const char *name); - asSNameSpace *FindNameSpace(const char *name); - -//=========================================================== -// internal properties -//=========================================================== - asCMemoryMgr memoryMgr; - - asUINT initialContextStackSize; - - asCObjectType *defaultArrayObjectType; - asCObjectType scriptTypeBehaviours; - asCObjectType functionBehaviours; - asCObjectType objectTypeBehaviours; - asCObjectType globalPropertyBehaviours; - - // Registered interface - asCArray registeredObjTypes; - asCArray registeredTypeDefs; - asCArray registeredEnums; - asCSymbolTable registeredGlobalProps; // TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used - asCSymbolTable registeredGlobalFuncs; - asCArray registeredFuncDefs; - asCArray registeredTemplateTypes; - asCScriptFunction *stringFactory; - bool configFailed; - - // Stores all registered types except funcdefs - asCMap allRegisteredTypes; - - // Dummy types used to name the subtypes in the template objects - asCArray templateSubTypes; - - // Store information about template types - // This list will contain all instances of templates, both registered specialized - // types and those automacially instantiated from scripts - asCArray templateInstanceTypes; - - // Store information about list patterns - asCArray listPatternTypes; - - // Stores all global properties, both those registered by application, and those declared by scripts. - // The id of a global property is the index in this array. - asCArray globalProperties; - - // This map is used to quickly find a property by its memory address - // It is used principally during building, cleanup, and garbage detection for script functions - asCMap varAddressMap; - - asCArray freeGlobalPropertyIds; - - // Stores all functions, i.e. registered functions, script functions, class methods, behaviours, etc. - asCArray scriptFunctions; - asCArray freeScriptFunctionIds; - asCArray signatureIds; - - // An array with all module imported functions - asCArray importedFunctions; - asCArray freeImportedFunctionIdxs; - - // These resources must be protected for multiple accesses - mutable asCAtomic refCount; - asCArray scriptModules; - asCModule *lastModule; - bool isBuilding; - bool deferValidationOfTemplateTypes; - - // Tokenizer is instantiated once to share resources - asCTokenizer tok; - - // Stores script declared types (classes, interfaces, enums, typedefs) - asCArray scriptTypes; - // This array stores the template instances types that have been automatically generated from template types - asCArray generatedTemplateTypes; - // Stores the funcdefs - asCArray funcDefs; - - // Stores the names of the script sections for debugging purposes - asCArray scriptSectionNames; - - // Type identifiers - mutable int typeIdSeqNbr; - mutable asCMap mapTypeIdToDataType; - - // Garbage collector - asCGarbageCollector gc; - - // Dynamic groups - asCConfigGroup defaultGroup; - asCArray configGroups; - asCConfigGroup *currentGroup; - asDWORD defaultAccessMask; - asSNameSpace *defaultNamespace; - - // Message callback - bool msgCallback; - asSSystemFunctionInterface msgCallbackFunc; - void *msgCallbackObj; - struct preMessage_t - { - preMessage_t() { isSet = false; } - bool isSet; - asCString message; - asCString scriptname; - int r; - int c; - } preMessage; - - // JIt compilation - asIJITCompiler *jitCompiler; - - // Namespaces - // These are shared between all entities and are - // only deleted once the engine is destroyed - asCArray nameSpaces; - - // String constants - // These are shared between all scripts and are - // only deleted once the engine is destroyed - asCArray stringConstants; - asCMap stringToIdMap; - - // Callbacks for context pooling - asREQUESTCONTEXTFUNC_t requestCtxFunc; - asRETURNCONTEXTFUNC_t returnCtxFunc; - void *ctxCallbackParam; - - // User data - asCArray userData; - - struct SEngineClean { asPWORD type; asCLEANENGINEFUNC_t cleanFunc; }; - asCArray cleanEngineFuncs; - struct SModuleClean { asPWORD type; asCLEANMODULEFUNC_t cleanFunc; }; - asCArray cleanModuleFuncs; - struct SContextClean { asPWORD type; asCLEANCONTEXTFUNC_t cleanFunc; }; - asCArray cleanContextFuncs; - struct SFunctionClean { asPWORD type; asCLEANFUNCTIONFUNC_t cleanFunc; }; - asCArray cleanFunctionFuncs; - struct SObjTypeClean { asPWORD type; asCLEANOBJECTTYPEFUNC_t cleanFunc; }; - asCArray cleanObjectTypeFuncs; - - // Synchronization for threads - DECLAREREADWRITELOCK(mutable engineRWLock) - - // Engine properties - struct - { - bool allowUnsafeReferences; - bool optimizeByteCode; - bool copyScriptSections; - asUINT maximumContextStackSize; - bool useCharacterLiterals; - bool allowMultilineStrings; - bool allowImplicitHandleTypes; - bool buildWithoutLineCues; - bool initGlobalVarsAfterBuild; - bool requireEnumScope; - int scanner; - bool includeJitInstructions; - int stringEncoding; - int propertyAccessorMode; - bool expandDefaultArrayToTemplate; - bool autoGarbageCollect; - bool disallowGlobalVars; - bool alwaysImplDefaultConstruct; - int compilerWarnings; - bool disallowValueAssignForRefType; - int alterSyntaxNamedArgs; - bool disableIntegerDivision; - } ep; - - // This flag is to allow a quicker shutdown when releasing the engine - bool shuttingDown; -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_scriptfunction.cpp b/dependencies/angelscript/source/as_scriptfunction.cpp deleted file mode 100644 index bbecc227..00000000 --- a/dependencies/angelscript/source/as_scriptfunction.cpp +++ /dev/null @@ -1,1765 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_scriptfunction.cpp -// -// A container for a compiled script function -// - - - -#include "as_config.h" -#include "as_scriptfunction.h" -#include "as_tokendef.h" -#include "as_scriptengine.h" -#include "as_callfunc.h" -#include "as_bytecode.h" -#include "as_texts.h" -#include "as_scriptnode.h" -#include "as_builder.h" -#include "as_scriptcode.h" - -#include // qsort - -BEGIN_AS_NAMESPACE - -#ifdef AS_MAX_PORTABILITY - -static void ScriptFunction_AddRef_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - self->AddRef(); -} - -static void ScriptFunction_Release_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - self->Release(); -} - -static void ScriptFunction_GetRefCount_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); -} - -static void ScriptFunction_SetFlag_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - self->SetFlag(); -} - -static void ScriptFunction_GetFlag_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); -} - -static void ScriptFunction_EnumReferences_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); -} - -static void ScriptFunction_ReleaseAllHandles_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllHandles(engine); -} - -static void ScriptFunction_CreateDelegate_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *func = (asCScriptFunction*)gen->GetArgAddress(0); - void *obj = gen->GetArgAddress(1); - gen->SetReturnAddress(CreateDelegate(func, obj)); -} - -// TODO: 2.29.0: operator== -/*static void ScriptFunction_opEquals_Generic(asIScriptGeneric *gen) -{ - asCScriptFunction *funcSelf = (asCScriptFunction*)gen->GetObject(); - asCScriptFunction *funcOther = (asCScriptFunction*)gen->GetArgAddress(0); - *(bool*)gen->GetAddressOfReturnLocation() = *funcSelf == *funcOther; -} -*/ - -#endif - - -void RegisterScriptFunction(asCScriptEngine *engine) -{ - // Register the gc behaviours for the script functions - int r = 0; - UNUSED_VAR(r); // It is only used in debug mode - engine->functionBehaviours.engine = engine; - engine->functionBehaviours.flags = asOBJ_REF | asOBJ_GC | asOBJ_SCRIPT_FUNCTION; - engine->functionBehaviours.name = "_builtin_function_"; -#ifndef AS_MAX_PORTABILITY - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptFunction,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptFunction,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCScriptFunction,GetRefCount), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCScriptFunction,SetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptFunction,GetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptFunction,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptFunction,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - // TODO: 2.29.0: Need some way to allow the arg type to adapt when the funcdefs are instantiated -// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asMETHOD(asCScriptFunction,operator==), asCALL_THISCALL); asASSERT( r >= 0 ); -#else - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFunction_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFunction_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptFunction_GetRefCount_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptFunction_SetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptFunction_GetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptFunction_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptFunction_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); -// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asFUNCTION(ScriptFunction_opEquals_Generic), asCALL_GENERIC); asASSERT( r >= 0 ); -#endif - - // Register the builtin function for creating delegates - // This function returns a handle to the delegate, but since the type is not known at this time it is - // registered to return a void then the return type is changed manually to the builtin function type - // The name of the function is an invalid identifier so it cannot be invoked accidentally from the script -#ifndef AS_MAX_PORTABILITY - r = engine->RegisterGlobalFunction("void f(int &in, int &in)", asFUNCTION(CreateDelegate), asCALL_CDECL); asASSERT( r >= 0 ); -#else - r = engine->RegisterGlobalFunction("void f(int &in, int &in)", asFUNCTION(ScriptFunction_CreateDelegate_Generic), asCALL_GENERIC); asASSERT( r >= 0 ); -#endif - - // Rename the function so that it cannot be called manually by the script - int idx = engine->registeredGlobalFuncs.GetIndex(engine->scriptFunctions[r]); - engine->registeredGlobalFuncs.Erase(idx); - engine->scriptFunctions[r]->name = DELEGATE_FACTORY; - engine->registeredGlobalFuncs.Put(engine->scriptFunctions[r]); - - // Change the return type so the VM will know the function really returns a handle - engine->scriptFunctions[r]->returnType = asCDataType::CreateObject(&engine->functionBehaviours, false); - engine->scriptFunctions[r]->returnType.MakeHandle(true); -} - -asCScriptFunction *CreateDelegate(asCScriptFunction *func, void *obj) -{ - if( func == 0 || obj == 0 ) - { - // TODO: delegate: Should set script exception - return 0; - } - - // Create an instance of a asCScriptFunction with the type asFUNC_DELEGATE - // The delegate shouldn't have a function id and is not added to the engine->scriptFunctions - asCScriptFunction *delegate = asNEW(asCScriptFunction)(static_cast(func->GetEngine()), 0, asFUNC_DELEGATE); - if( delegate ) - delegate->MakeDelegate(func, obj); - - return delegate; -} - -// internal -void asCScriptFunction::MakeDelegate(asCScriptFunction *func, void *obj) -{ - // Increase the reference of the function and object - func->AddRef(); - funcForDelegate = func; - - func->GetEngine()->AddRefScriptObject(obj, func->GetObjectType()); - objForDelegate = obj; - - // The return type and parameters are copied from the delegated method to this object - // TODO: optimize: Do we really need to copy? Whenever requested the delegate can simply return the delegated methods' info directly - parameterTypes = func->parameterTypes; - returnType = func->returnType; - inOutFlags = func->inOutFlags; - - // The delegate doesn't own the parameters as it will only forward them to the real method - // so the exception handler must not clean up the parameters for the delegate - dontCleanUpOnException = true; -} - -// interface -void *asCScriptFunction::GetDelegateObject() const -{ - return objForDelegate; -} - -// interface -asIObjectType *asCScriptFunction::GetDelegateObjectType() const -{ - if( objForDelegate == 0 || funcForDelegate == 0 ) - return 0; - - return funcForDelegate->objectType; -} - -// interface -asIScriptFunction *asCScriptFunction::GetDelegateFunction() const -{ - return funcForDelegate; -} - -// TODO: 2.29.0: operator== -/* -// internal -bool asCScriptFunction::operator==(const asCScriptFunction &other) const -{ - if( this == &other ) return true; - - if( this->funcType == asFUNC_DELEGATE && other.funcType == asFUNC_DELEGATE ) - { - if( this->objForDelegate == other.objForDelegate && - this->funcForDelegate == other.funcForDelegate ) - return true; - } - - return false; -} -*/ - -// internal -int asCScriptFunction::RegisterListPattern(const char *decl, asCScriptNode *listNodes) -{ - if( listNodes == 0 ) - return asINVALID_ARG; - - // Build the representation of the list pattern from the script nodes - asSListPatternNode *node; - listPattern = asNEW(asSListPatternNode)(asLPT_START); - node = listPattern; - - // Recursively parse the child - int r = ParseListPattern(node, decl, listNodes); - - node->next = asNEW(asSListPatternNode)(asLPT_END); - - return r; -} - -// internal -int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char *decl, asCScriptNode *listNodes) -{ - asSListPatternNode *node = target; - - listNodes = listNodes->firstChild; - while( listNodes ) - { - if( listNodes->nodeType == snIdentifier ) - { - asCString token(&decl[listNodes->tokenPos], listNodes->tokenLength); - if( token == "repeat" ) - { - node->next = asNEW(asSListPatternNode)(asLPT_REPEAT); - node = node->next; - } - else if( token == "repeat_same" ) - { - // TODO: list: Should make sure this is a sub-list - node->next = asNEW(asSListPatternNode)(asLPT_REPEAT_SAME); - node = node->next; - } - else - { - // Shouldn't happen as the parser already reported the error - asASSERT(false); - } - } - else if( listNodes->nodeType == snDataType ) - { - asCDataType dt; - asCBuilder builder(engine, 0); - asCScriptCode code; - code.SetCode("", decl, 0, false); - dt = builder.CreateDataTypeFromNode(listNodes, &code, engine->defaultNamespace, false, returnType.GetObjectType()); - - node->next = asNEW(asSListPatternDataTypeNode)(dt); - node = node->next; - } - else if( listNodes->nodeType == snListPattern ) - { - node->next = asNEW(asSListPatternNode)(asLPT_START); - node = node->next; - - // Recursively parse the child - int r = ParseListPattern(node, decl, listNodes); - if( r < 0 ) - return r; - - node->next = asNEW(asSListPatternNode)(asLPT_END); - node = node->next; - } - else - { - // Unexpected token in the list, the parser shouldn't have allowed - asASSERT( false ); - return -1; - } - - listNodes = listNodes->next; - } - - target = node; - return 0; -} - -// internal -asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType _funcType) -{ - refCount.set(1); - this->engine = engine; - this->scriptData = 0; - funcType = _funcType; - module = mod; - objectType = 0; - name = ""; - isReadOnly = false; - isPrivate = false; - isFinal = false; - isOverride = false; - sysFuncIntf = 0; - signatureId = 0; - dontCleanUpOnException = false; - vfTableIdx = -1; - gcFlag = false; - userData = 0; - id = 0; - accessMask = 0xFFFFFFFF; - isShared = false; - nameSpace = engine->nameSpaces[0]; - objForDelegate = 0; - funcForDelegate = 0; - listPattern = 0; - - if( funcType == asFUNC_SCRIPT ) - AllocateScriptFunctionData(); - - // Notify the GC of script functions - if( (funcType == asFUNC_SCRIPT && mod == 0) || (funcType == asFUNC_DELEGATE) ) - engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours); -} - -void asCScriptFunction::AllocateScriptFunctionData() -{ - if( scriptData ) return; - - scriptData = asNEW(ScriptFunctionData); - - scriptData->stackNeeded = 0; - scriptData->variableSpace = 0; - scriptData->scriptSectionIdx = -1; - scriptData->declaredAt = 0; - scriptData->jitFunction = 0; -} - -void asCScriptFunction::DeallocateScriptFunctionData() -{ - if( !scriptData ) return; - - for( asUINT n = 0; n < scriptData->variables.GetLength(); n++ ) - asDELETE(scriptData->variables[n],asSScriptVariable); - scriptData->variables.SetLength(0); - - asDELETE(scriptData, ScriptFunctionData); - scriptData = 0; -} - -// internal -asCScriptFunction::~asCScriptFunction() -{ - // Dummy functions that are allocated on the stack are not reference counted - asASSERT( funcType == asFUNC_DUMMY || - refCount.get() == 0 ); - - // If the engine pointer is 0, then DestroyInternal has already been called and there is nothing more to do - if( engine == 0 ) return; - - DestroyInternal(); - - // Tell engine to free the function id. This will make it impossible to - // refer to the function by id. Where this is done, it is quite possible - // they will leak. - if( funcType != -1 && funcType != asFUNC_IMPORTED && id ) - engine->FreeScriptFunctionId(id); - id = 0; - - // Finally set the engine pointer to 0 because it must not be accessed again - engine = 0; -} - -// internal -void asCScriptFunction::DestroyHalfCreated() -{ - asASSERT( refCount.get() == 1 ); - - // Set the funcType to dummy so the destructor won't complain - funcType = asFUNC_DUMMY; - - // If the bytecode exist remove it before destroying, otherwise it - // will fail when the destructor releases the references as the bytecode - // is not fully constructed. - if( scriptData ) - scriptData->byteCode.SetLength(0); - - delete this; -} - -// internal -void asCScriptFunction::DestroyInternal() -{ - // Clean up user data - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n+1] ) - { - for( asUINT c = 0; c < engine->cleanFunctionFuncs.GetLength(); c++ ) - if( engine->cleanFunctionFuncs[c].type == userData[n] ) - engine->cleanFunctionFuncs[c].cleanFunc(this); - } - } - userData.SetLength(0); - - // Release all references the function holds to other objects - ReleaseReferences(); - parameterTypes.SetLength(0); - returnType = asCDataType::CreatePrimitive(ttVoid, false); - - for( asUINT p = 0; p < defaultArgs.GetLength(); p++ ) - if( defaultArgs[p] ) - asDELETE(defaultArgs[p], asCString); - defaultArgs.SetLength(0); - - if( sysFuncIntf ) - asDELETE(sysFuncIntf,asSSystemFunctionInterface); - sysFuncIntf = 0; - - DeallocateScriptFunctionData(); - - // Deallocate list pattern data - while( listPattern ) - { - asSListPatternNode *n = listPattern->next; - asDELETE(listPattern, asSListPatternNode); - listPattern = n; - } -} - -// interface -int asCScriptFunction::GetId() const -{ - return id; -} - -// interface -int asCScriptFunction::AddRef() const -{ - gcFlag = false; - return refCount.atomicInc(); -} - -// interface -int asCScriptFunction::Release() const -{ - gcFlag = false; - int r = refCount.atomicDec(); - if( r == 0 && - funcType != asFUNC_FUNCDEF && // Funcdefs are treated as object types and will be deleted by ClearUnusedTypes() - funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted - asDELETE(const_cast(this),asCScriptFunction); - - return r; -} - -// internal -void asCScriptFunction::Orphan(asIScriptModule *mod) -{ - if( mod && module == mod ) - { - module = 0; - if( (funcType == asFUNC_SCRIPT || funcType == asFUNC_IMPORTED) && refCount.get() > 1 ) - { - // This function is being orphaned, so notify the GC so it can check for circular references - engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours); - } - } - - Release(); -} - -// interface -int asCScriptFunction::GetTypeId() const -{ - // This const cast is ok, the object won't be modified - asCDataType dt = asCDataType::CreateFuncDef(const_cast(this)); - return engine->GetTypeIdFromDataType(dt); -} - -// interface -bool asCScriptFunction::IsCompatibleWithTypeId(int typeId) const -{ - asCDataType dt = engine->GetDataTypeFromTypeId(typeId); - - // Make sure the type is a function - asCScriptFunction *func = dt.GetFuncDef(); - if( func == 0 ) - return false; - - if( !IsSignatureExceptNameEqual(func) ) - return false; - - // If this is a class method, then only return true if the object type is the same - if( objectType != func->objectType ) - return false; - - return true; -} - -// interface -const char *asCScriptFunction::GetModuleName() const -{ - if( module ) - { - return module->name.AddressOf(); - } - - return 0; -} - -// interface -asIScriptModule *asCScriptFunction::GetModule() const -{ - return module; -} - -// interface -asIObjectType *asCScriptFunction::GetObjectType() const -{ - return objectType; -} - -// interface -const char *asCScriptFunction::GetObjectName() const -{ - if( objectType ) - return objectType->GetName(); - - return 0; -} - -// interface -const char *asCScriptFunction::GetName() const -{ - return name.AddressOf(); -} - -// interface -const char *asCScriptFunction::GetNamespace() const -{ - return nameSpace->name.AddressOf(); -} - -// interface -bool asCScriptFunction::IsReadOnly() const -{ - return isReadOnly; -} - -// interface -bool asCScriptFunction::IsPrivate() const -{ - return isPrivate; -} - -// internal -int asCScriptFunction::GetSpaceNeededForArguments() -{ - // We need to check the size for each type - int s = 0; - for( asUINT n = 0; n < parameterTypes.GetLength(); n++ ) - s += parameterTypes[n].GetSizeOnStackDWords(); - - return s; -} - -// internal -int asCScriptFunction::GetSpaceNeededForReturnValue() -{ - return returnType.GetSizeOnStackDWords(); -} - -// internal -bool asCScriptFunction::DoesReturnOnStack() const -{ - if( returnType.GetObjectType() && - (returnType.GetObjectType()->flags & asOBJ_VALUE) && - !returnType.IsReference() ) - return true; - - return false; -} - -// internal -asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool includeNamespace, bool includeParamNames) const -{ - asCString str; - - // TODO: default arg: Make the declaration with the default args an option - - // Don't add the return type for constructors and destructors - if( !(returnType.GetTokenType() == ttVoid && - objectType && - (name == objectType->name || (name.GetLength() > 0 && name[0] == '~') || - name == "_beh_0_" || name == "_beh_2_")) ) - { - str = returnType.Format(); - str += " "; - } - if( objectType && includeObjectName ) - { - if( includeNamespace ) - str += objectType->nameSpace->name + "::"; - - if( objectType->name != "" ) - str += objectType->name + "::"; - else - str += "_unnamed_type_::"; - } - else if( includeNamespace ) - { - str += nameSpace->name + "::"; - } - if( name == "" ) - str += "_unnamed_function_("; - else if( name.SubString(0,5) == "_beh_" && name.GetLength() == 7 ) - { - if( name[5] == '0' + asBEHAVE_CONSTRUCT ) - str += objectType->name + "("; - else if( name[5] == '0' + asBEHAVE_FACTORY ) - str += returnType.GetObjectType()->name + "("; - else if( name[5] == '0' + asBEHAVE_DESTRUCT ) - str += "~" + objectType->name + "("; - else - str += name + "("; - } - else - str += name + "("; - - if( parameterTypes.GetLength() > 0 ) - { - asUINT n; - for( n = 0; n < parameterTypes.GetLength() - 1; n++ ) - { - str += parameterTypes[n].Format(); - if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n ) - { - if( inOutFlags[n] == asTM_INREF ) str += "in"; - else if( inOutFlags[n] == asTM_OUTREF ) str += "out"; - else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout"; - } - - if( includeParamNames && n < parameterNames.GetLength() && parameterNames[n].GetLength() != 0 ) - { - str += " "; - str += parameterNames[n]; - } - - if( defaultArgs.GetLength() > n && defaultArgs[n] ) - { - asCString tmp; - tmp.Format(" = %s", defaultArgs[n]->AddressOf()); - str += tmp; - } - - str += ", "; - } - - // Add the last parameter - str += parameterTypes[n].Format(); - if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n ) - { - if( inOutFlags[n] == asTM_INREF ) str += "in"; - else if( inOutFlags[n] == asTM_OUTREF ) str += "out"; - else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout"; - } - - if( includeParamNames && n < parameterNames.GetLength() && parameterNames[n].GetLength() != 0 ) - { - str += " "; - str += parameterNames[n]; - } - - if( defaultArgs.GetLength() > n && defaultArgs[n] ) - { - asCString tmp; - tmp.Format(" = %s", defaultArgs[n]->AddressOf()); - str += tmp; - } - } - - str += ")"; - - if( isReadOnly ) - str += " const"; - - // Add the declaration of the list pattern - if( listPattern ) - { - asSListPatternNode *n = listPattern; - bool first = true; - while( n ) - { - if( n->type == asLPT_START ) - { - str += " {"; - first = true; - } - else if( n->type == asLPT_END ) - { - str += " }"; - first = false; - } - else if( n->type == asLPT_REPEAT ) - str += " repeat"; - else if( n->type == asLPT_REPEAT_SAME ) - str += " repeat_same"; - else if( n->type == asLPT_TYPE ) - { - if( first ) - { - str += " "; - first = false; - } - else - str += ", "; - str += reinterpret_cast(n)->dataType.Format(); - } - - n = n->next; - } - } - - return str; -} - -// interface -int asCScriptFunction::FindNextLineWithCode(int line) const -{ - if( scriptData == 0 ) return -1; - if( scriptData->lineNumbers.GetLength() == 0 ) return -1; - - // The line numbers for constructors are not in order due to the way - // class members can be initialized directly in the declaration - if( objectType && objectType->name == name ) - { - // Sort all line numbers before looking for the next - asCArray lineNbrs; - for( asUINT n = 1; n < scriptData->lineNumbers.GetLength(); n += 2 ) - lineNbrs.PushLast(scriptData->lineNumbers[n]&0xFFFFF); - - struct C - { - static int cmp(const void *a, const void *b) { return *(int*)a - *(int*)b; } - }; - std::qsort(&lineNbrs[0], lineNbrs.GetLength(), sizeof(int), C::cmp); - - if( line < lineNbrs[0] && line < (scriptData->declaredAt&0xFFFFF)) return -1; - if( line > lineNbrs[lineNbrs.GetLength()-1] ) return -1; - - // Find the line with code on or right after the input line - // TODO: optimize: Do binary search - for( asUINT n = 0; n < lineNbrs.GetLength(); n++ ) - if( line <= lineNbrs[n] ) - return lineNbrs[n]; - } - else - { - // Check if given line is outside function - if( line < (scriptData->declaredAt&0xFFFFF) ) return -1; - if( line > (scriptData->lineNumbers[scriptData->lineNumbers.GetLength()-1]&0xFFFFF) ) return -1; - - // Find the line with code on or right after the input line - // TODO: optimize: Do binary search instead - for( asUINT n = 1; n < scriptData->lineNumbers.GetLength(); n += 2 ) - { - if( line <= (scriptData->lineNumbers[n]&0xFFFFF) ) - return (scriptData->lineNumbers[n]&0xFFFFF); - } - } - - return -1; -} - -// internal -int asCScriptFunction::GetLineNumber(int programPosition, int *sectionIdx) -{ - asASSERT( scriptData ); - - if( sectionIdx ) *sectionIdx = scriptData->scriptSectionIdx; - if( scriptData->lineNumbers.GetLength() == 0 ) return 0; - - if( sectionIdx ) - { - // Find the correct section index if the function is compiled from multiple sections - // This array will be empty most of the time so we don't need a sofisticated algorithm to search it - for( asUINT n = 0; n < scriptData->sectionIdxs.GetLength(); n += 2 ) - { - if( scriptData->sectionIdxs[n] <= programPosition ) - *sectionIdx = scriptData->sectionIdxs[n+1]; - } - } - - // Do a binary search in the buffer - int max = (int)scriptData->lineNumbers.GetLength()/2 - 1; - int min = 0; - int i = max/2; - - for(;;) - { - if( scriptData->lineNumbers[i*2] < programPosition ) - { - // Have we found the largest number < programPosition? - if( max == i ) return scriptData->lineNumbers[i*2+1]; - if( scriptData->lineNumbers[i*2+2] > programPosition ) return scriptData->lineNumbers[i*2+1]; - - min = i + 1; - i = (max + min)/2; - } - else if( scriptData->lineNumbers[i*2] > programPosition ) - { - // Have we found the smallest number > programPosition? - if( min == i ) return scriptData->lineNumbers[i*2+1]; - - max = i - 1; - i = (max + min)/2; - } - else - { - // We found the exact position - return scriptData->lineNumbers[i*2+1]; - } - } -} - -// interface -asEFuncType asCScriptFunction::GetFuncType() const -{ - return funcType; -} - -// interface -asUINT asCScriptFunction::GetVarCount() const -{ - if( scriptData ) - return asUINT(scriptData->variables.GetLength()); - return 0; -} - -// interface -int asCScriptFunction::GetVar(asUINT index, const char **name, int *typeId) const -{ - if( scriptData == 0 ) - return asNOT_SUPPORTED; - if( index >= scriptData->variables.GetLength() ) - return asINVALID_ARG; - - if( name ) - *name = scriptData->variables[index]->name.AddressOf(); - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(scriptData->variables[index]->type); - - return asSUCCESS; -} - -// interface -const char *asCScriptFunction::GetVarDecl(asUINT index, bool includeNamespace) const -{ - if( scriptData == 0 || index >= scriptData->variables.GetLength() ) - return 0; - - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = scriptData->variables[index]->type.Format(includeNamespace); - *tempString += " " + scriptData->variables[index]->name; - - return tempString->AddressOf(); -} - -// internal -void asCScriptFunction::AddVariable(asCString &name, asCDataType &type, int stackOffset) -{ - asASSERT( scriptData ); - asSScriptVariable *var = asNEW(asSScriptVariable); - if( var == 0 ) - { - // Out of memory - return; - } - var->name = name; - var->type = type; - var->stackOffset = stackOffset; - var->declaredAtProgramPos = 0; - scriptData->variables.PushLast(var); -} - -// internal -asCObjectType *asCScriptFunction::GetObjectTypeOfLocalVar(short varOffset) -{ - asASSERT( scriptData ); - - for( asUINT n = 0; n < scriptData->objVariablePos.GetLength(); n++ ) - { - if( scriptData->objVariablePos[n] == varOffset ) - return scriptData->objVariableTypes[n]; - } - - return 0; -} - -// internal -void asCScriptFunction::ComputeSignatureId() -{ - // This function will compute the signatureId based on the - // function name, return type, and parameter types. The object - // type for methods is not used, so that class methods and - // interface methods match each other. - for( asUINT n = 0; n < engine->signatureIds.GetLength(); n++ ) - { - if( !IsSignatureEqual(engine->signatureIds[n]) ) continue; - - // We don't need to increment the reference counter here, because - // asCScriptEngine::FreeScriptFunctionId will maintain the signature - // id as the function is freed. - signatureId = engine->signatureIds[n]->signatureId; - return; - } - - signatureId = id; - engine->signatureIds.PushLast(this); -} - -// internal -bool asCScriptFunction::IsSignatureEqual(const asCScriptFunction *func) const -{ - if( !IsSignatureExceptNameEqual(func) || name != func->name ) return false; - - return true; -} - -// internal -bool asCScriptFunction::IsSignatureExceptNameEqual(const asCScriptFunction *func) const -{ - return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, func->objectType, func->isReadOnly); -} - -// internal -bool asCScriptFunction::IsSignatureExceptNameEqual(const asCDataType &retType, const asCArray ¶mTypes, const asCArray ¶mInOut, const asCObjectType *objType, bool readOnly) const -{ - if( this->returnType != retType ) return false; - - return IsSignatureExceptNameAndReturnTypeEqual(paramTypes, paramInOut, objType, readOnly); -} - -// internal -bool asCScriptFunction::IsSignatureExceptNameAndObjectTypeEqual(const asCScriptFunction *func) const -{ - return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, objectType, isReadOnly); -} - -// internal -bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCScriptFunction *func) const -{ - return IsSignatureExceptNameAndReturnTypeEqual(func->parameterTypes, func->inOutFlags, func->objectType, func->isReadOnly); -} - -// internal -bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCArray ¶mTypes, const asCArray ¶mInOut, const asCObjectType *objType, bool readOnly) const -{ - if( this->isReadOnly != readOnly ) return false; - if( this->inOutFlags != paramInOut ) return false; - if( this->parameterTypes != paramTypes ) return false; - if( (this->objectType != 0) != (objType != 0) ) return false; - - return true; -} - -// internal -void asCScriptFunction::AddReferences() -{ - // This array will be used to make sure we only add the reference to the same resource once - // This is especially important for global variables, as it expects the initialization function - // to hold only one reference to the variable. However, if the variable is initialized through - // the default constructor followed by the assignment operator we will have two references to - // the variable in the function. - asCArray ptrs; - - // Only count references if there is any bytecode - if( scriptData && scriptData->byteCode.GetLength() ) - { - if( returnType.IsObject() ) - returnType.GetObjectType()->AddRef(); - - for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) - if( parameterTypes[p].IsObject() ) - parameterTypes[p].GetObjectType()->AddRef(); - - for( asUINT v = 0; v < scriptData->objVariableTypes.GetLength(); v++ ) - if( scriptData->objVariableTypes[v] ) // The null handle is also stored, but it doesn't have an object type - scriptData->objVariableTypes[v]->AddRef(); - - // Go through the byte code and add references to all resources used by the function - asCArray &bc = scriptData->byteCode; - for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] ) - { - switch( *(asBYTE*)&bc[n] ) - { - // Object types - case asBC_OBJTYPE: - case asBC_FREE: - case asBC_REFCPY: - case asBC_RefCpyV: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - asASSERT( objType ); - if( objType ) - objType->AddRef(); - } - break; - - // Object type and function - case asBC_ALLOC: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - asASSERT( objType ); - if( objType ) - objType->AddRef(); - - int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE); - if( funcId ) - engine->scriptFunctions[funcId]->AddRef(); - } - break; - - // Global variables - case asBC_PGA: - case asBC_PshGPtr: - case asBC_LDG: - case asBC_PshG4: - case asBC_LdGRdR4: - case asBC_CpyGtoV4: - case asBC_CpyVtoG4: - case asBC_SetG4: - // Need to increase the reference for each global variable - { - void *gvarPtr = (void*)asBC_PTRARG(&bc[n]); - if( !gvarPtr ) break; - asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr); - if( !prop ) break; - - // Only addref the properties once - if( !ptrs.Exists(gvarPtr) ) - { - prop->AddRef(); - ptrs.PushLast(gvarPtr); - } - - asCConfigGroup *group = engine->FindConfigGroupForGlobalVar(prop->id); - if( group != 0 ) group->AddRef(); - } - break; - - // System functions - case asBC_CALLSYS: - { - int funcId = asBC_INTARG(&bc[n]); - asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId); - if( group != 0 ) group->AddRef(); - - asASSERT( funcId > 0 ); - if( funcId > 0 ) - engine->scriptFunctions[funcId]->AddRef(); - } - break; - - // Functions - case asBC_CALL: - case asBC_CALLINTF: - { - int funcId = asBC_INTARG(&bc[n]); - asASSERT( funcId > 0 ); - if( funcId > 0 ) - engine->scriptFunctions[funcId]->AddRef(); - } - break; - - // Function pointers - case asBC_FuncPtr: - { - asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]); - asASSERT( func ); - if( func ) - func->AddRef(); - } - break; - } - } - } -} - -// internal -void asCScriptFunction::ReleaseReferences() -{ - asCArray ptrs; - - // Only count references if there is any bytecode - if( scriptData && scriptData->byteCode.GetLength() ) - { - if( returnType.IsObject() ) - returnType.GetObjectType()->Release(); - - for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) - if( parameterTypes[p].IsObject() ) - parameterTypes[p].GetObjectType()->Release(); - - for( asUINT v = 0; v < scriptData->objVariableTypes.GetLength(); v++ ) - if( scriptData->objVariableTypes[v] ) - scriptData->objVariableTypes[v]->Release(); - - // Go through the byte code and release references to all resources used by the function - asCArray &bc = scriptData->byteCode; - for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] ) - { - switch( *(asBYTE*)&bc[n] ) - { - // Object types - case asBC_OBJTYPE: - case asBC_FREE: - case asBC_REFCPY: - case asBC_RefCpyV: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - if( objType ) - objType->Release(); - } - break; - - // Object type and function - case asBC_ALLOC: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - if( objType ) - objType->Release(); - - int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE); - if( funcId > 0 ) - { - asCScriptFunction *fptr = engine->scriptFunctions[funcId]; - if( fptr ) - fptr->Release(); - - // The engine may have been forced to destroy the function internals early - // and this may will make it impossible to find the function by id anymore. - // This should only happen if the engine is released while the application - // is still keeping functions alive. - // TODO: Fix this possible memory leak - } - } - break; - - // Global variables - case asBC_PGA: - case asBC_PshGPtr: - case asBC_LDG: - case asBC_PshG4: - case asBC_LdGRdR4: - case asBC_CpyGtoV4: - case asBC_CpyVtoG4: - case asBC_SetG4: - // Need to increase the reference for each global variable - { - void *gvarPtr = (void*)asBC_PTRARG(&bc[n]); - if( !gvarPtr ) break; - asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr); - if( !prop ) break; - - // Only release the properties once - if( !ptrs.Exists(gvarPtr) ) - { - prop->Release(); - ptrs.PushLast(gvarPtr); - } - - asCConfigGroup *group = engine->FindConfigGroupForGlobalVar(prop->id); - if( group != 0 ) group->Release(); - } - break; - - // System functions - case asBC_CALLSYS: - { - int funcId = asBC_INTARG(&bc[n]); - asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId); - if( group != 0 ) group->Release(); - - if( funcId ) - engine->scriptFunctions[funcId]->Release(); - } - break; - - // Functions - case asBC_CALL: - case asBC_CALLINTF: - { - int funcId = asBC_INTARG(&bc[n]); - if( funcId ) - { - asCScriptFunction *fptr = engine->scriptFunctions[funcId]; - if( fptr ) - fptr->Release(); - - // The engine may have been forced to destroy the function internals early - // and this may will make it impossible to find the function by id anymore. - // This should only happen if the engine is released while the application - // is still keeping functions alive. - // TODO: Fix this possible memory leak - } - } - break; - - // Function pointers - case asBC_FuncPtr: - { - asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]); - if( func ) - func->Release(); - } - break; - } - } - - // Release the jit compiled function - if( scriptData->jitFunction ) - engine->jitCompiler->ReleaseJITFunction(scriptData->jitFunction); - scriptData->jitFunction = 0; - } - - // Delegate - if( objForDelegate ) - engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType()); - objForDelegate = 0; - if( funcForDelegate ) - funcForDelegate->Release(); - funcForDelegate = 0; -} - -// interface -int asCScriptFunction::GetReturnTypeId(asDWORD *flags) const -{ - if( flags ) - { - if( returnType.IsReference() ) - { - *flags = asTM_INOUTREF; - *flags |= returnType.IsReadOnly() ? asTM_CONST : 0; - } - else - *flags = asTM_NONE; - } - - return engine->GetTypeIdFromDataType(returnType); -} - -// interface -asUINT asCScriptFunction::GetParamCount() const -{ - return (asUINT)parameterTypes.GetLength(); -} - -// interface -int asCScriptFunction::GetParam(asUINT index, int *typeId, asDWORD *flags, const char **name, const char **defaultArg) const -{ - if( index >= parameterTypes.GetLength() ) - return asINVALID_ARG; - - if( typeId ) - *typeId = engine->GetTypeIdFromDataType(parameterTypes[index]); - - if( flags ) - { - *flags = inOutFlags[index]; - *flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0; - } - - if( name ) - { - // The parameter names are not stored if loading from bytecode without debug information - if( index < parameterNames.GetLength() ) - *name = parameterNames[index].AddressOf(); - else - *name = 0; - } - - if( defaultArg ) - { - if( index < defaultArgs.GetLength() && defaultArgs[index] ) - *defaultArg = defaultArgs[index]->AddressOf(); - else - *defaultArg = 0; - } - - return asSUCCESS; -} - -#ifdef AS_DEPRECATED -// Deprecated since 2014-04-06, 2.29.0 -int asCScriptFunction::GetParamTypeId(asUINT index, asDWORD *flags) const -{ - if( index >= parameterTypes.GetLength() ) - return asINVALID_ARG; - - if( flags ) - { - *flags = inOutFlags[index]; - *flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0; - } - - return engine->GetTypeIdFromDataType(parameterTypes[index]); -} -#endif - -// interface -asIScriptEngine *asCScriptFunction::GetEngine() const -{ - return engine; -} - -// interface -const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace, bool includeParamNames) const -{ - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = GetDeclarationStr(includeObjectName, includeNamespace, includeParamNames); - return tempString->AddressOf(); -} - -// interface -const char *asCScriptFunction::GetScriptSectionName() const -{ - if( scriptData && scriptData->scriptSectionIdx >= 0 ) - return engine->scriptSectionNames[scriptData->scriptSectionIdx]->AddressOf(); - - return 0; -} - -// interface -const char *asCScriptFunction::GetConfigGroup() const -{ - asCConfigGroup *group = 0; - if( funcType != asFUNC_FUNCDEF ) - group = engine->FindConfigGroupForFunction(id); - else - group = engine->FindConfigGroupForFuncDef(this); - - if( group == 0 ) - return 0; - - return group->groupName.AddressOf(); -} - -// interface -asDWORD asCScriptFunction::GetAccessMask() const -{ - return accessMask; -} - -// internal -void asCScriptFunction::JITCompile() -{ - if( funcType != asFUNC_SCRIPT ) - return; - - asASSERT( scriptData ); - - asIJITCompiler *jit = engine->GetJITCompiler(); - if( !jit ) - return; - - // Make sure the function has been compiled with JitEntry instructions - // For functions that has JitEntry this will be a quick test - asUINT length; - asDWORD *byteCode = GetByteCode(&length); - asDWORD *end = byteCode + length; - bool foundJitEntry = false; - while( byteCode < end ) - { - // Determine the instruction - asEBCInstr op = asEBCInstr(*(asBYTE*)byteCode); - if( op == asBC_JitEntry ) - { - foundJitEntry = true; - break; - } - - // Move to next instruction - byteCode += asBCTypeSize[asBCInfo[op].type]; - } - - if( !foundJitEntry ) - { - asCString msg; - msg.Format(TXT_NO_JIT_IN_FUNC_s, GetDeclaration()); - engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); - } - - // Release the previous function, if any - if( scriptData->jitFunction ) - { - engine->jitCompiler->ReleaseJITFunction(scriptData->jitFunction); - scriptData->jitFunction = 0; - } - - // Compile for native system - int r = jit->CompileFunction(this, &scriptData->jitFunction); - if( r < 0 ) - asASSERT( scriptData->jitFunction == 0 ); -} - -// interface -asDWORD *asCScriptFunction::GetByteCode(asUINT *length) -{ - if( scriptData == 0 ) return 0; - - if( length ) - *length = (asUINT)scriptData->byteCode.GetLength(); - - if( scriptData->byteCode.GetLength() ) - return scriptData->byteCode.AddressOf(); - - return 0; -} - -// interface -void *asCScriptFunction::SetUserData(void *data, asPWORD type) -{ - // As a thread might add a new new user data at the same time as another - // it is necessary to protect both read and write access to the userData member - ACQUIREEXCLUSIVE(engine->engineRWLock); - - // It is not intended to store a lot of different types of userdata, - // so a more complex structure like a associative map would just have - // more overhead than a simple array. - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - void *oldData = reinterpret_cast(userData[n+1]); - userData[n+1] = reinterpret_cast(data); - - RELEASEEXCLUSIVE(engine->engineRWLock); - - return oldData; - } - } - - userData.PushLast(type); - userData.PushLast(reinterpret_cast(data)); - - RELEASEEXCLUSIVE(engine->engineRWLock); - - return 0; -} - -// interface -void *asCScriptFunction::GetUserData(asPWORD type) const -{ - // There may be multiple threads reading, but when - // setting the user data nobody must be reading. - ACQUIRESHARED(engine->engineRWLock); - - for( asUINT n = 0; n < userData.GetLength(); n += 2 ) - { - if( userData[n] == type ) - { - RELEASESHARED(engine->engineRWLock); - return reinterpret_cast(userData[n+1]); - } - } - - RELEASESHARED(engine->engineRWLock); - - return 0; -} - -// internal -// TODO: cleanup: This method should probably be a member of the engine -asCGlobalProperty *asCScriptFunction::GetPropertyByGlobalVarPtr(void *gvarPtr) -{ - asSMapNode *node; - if( engine->varAddressMap.MoveTo(&node, gvarPtr) ) - { - asASSERT(gvarPtr == node->value->GetAddressOfValue()); - return node->value; - } - return 0; -} - -// internal -int asCScriptFunction::GetRefCount() -{ - return refCount.get(); -} - -// internal -void asCScriptFunction::SetFlag() -{ - gcFlag = true; -} - -// internal -bool asCScriptFunction::GetFlag() -{ - return gcFlag; -} - -// internal -void asCScriptFunction::EnumReferences(asIScriptEngine *) -{ - // Notify the GC of all object types used - if( returnType.IsObject() ) - engine->GCEnumCallback(returnType.GetObjectType()); - - for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) - if( parameterTypes[p].IsObject() ) - engine->GCEnumCallback(parameterTypes[p].GetObjectType()); - - if( scriptData ) - { - for( asUINT t = 0; t < scriptData->objVariableTypes.GetLength(); t++ ) - engine->GCEnumCallback(scriptData->objVariableTypes[t]); - - // Notify the GC of all script functions that is accessed - asCArray &bc = scriptData->byteCode; - for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] ) - { - switch( *(asBYTE*)&bc[n] ) - { - case asBC_OBJTYPE: - case asBC_FREE: - case asBC_REFCPY: - case asBC_RefCpyV: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - engine->GCEnumCallback(objType); - } - break; - - case asBC_ALLOC: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - engine->GCEnumCallback(objType); - - int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE); - if( func ) - engine->GCEnumCallback(engine->scriptFunctions[func]); - } - break; - - case asBC_CALL: - case asBC_CALLINTF: - { - int func = asBC_INTARG(&bc[n]); - if( func ) - engine->GCEnumCallback(engine->scriptFunctions[func]); - } - break; - - // Function pointers - case asBC_FuncPtr: - { - asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]); - if( func ) - engine->GCEnumCallback(func); - } - break; - - // Global variables - case asBC_PGA: - case asBC_PshGPtr: - case asBC_LDG: - case asBC_PshG4: - case asBC_LdGRdR4: - case asBC_CpyGtoV4: - case asBC_CpyVtoG4: - case asBC_SetG4: - // Need to enumerate the reference for each global variable - { - // TODO: optimize: Keep an array of accessed global properties - void *gvarPtr = (void*)asBC_PTRARG(&bc[n]); - asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr); - - engine->GCEnumCallback(prop); - } - break; - } - } - } - - // Delegate - if( objForDelegate ) - engine->GCEnumCallback(objForDelegate); - if( funcForDelegate ) - engine->GCEnumCallback(funcForDelegate); -} - -// internal -void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *) -{ - // Release paramaters - if( scriptData && scriptData->byteCode.GetLength() ) - { - if( returnType.IsObject() ) - { - returnType.GetObjectType()->Release(); - returnType = asCDataType::CreatePrimitive(ttVoid, false); - } - - for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) - if( parameterTypes[p].IsObject() ) - { - parameterTypes[p].GetObjectType()->Release(); - parameterTypes[p] = asCDataType::CreatePrimitive(ttInt, false); - } - - for( asUINT n = 0; n < scriptData->objVariableTypes.GetLength(); n++ ) - if( scriptData->objVariableTypes[n] ) // Null handle is also stored, but it doesn't have an object type - scriptData->objVariableTypes[n]->Release(); - scriptData->objVariableTypes.SetLength(0); - - // Release all script functions - asCArray &bc = scriptData->byteCode; - for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] ) - { - switch( *(asBYTE*)&bc[n] ) - { - // Object types - case asBC_OBJTYPE: - case asBC_FREE: - case asBC_REFCPY: - case asBC_RefCpyV: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - if( objType ) - { - objType->Release(); - *(asPWORD*)&bc[n+1] = 0; - } - } - break; - - case asBC_ALLOC: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - if( objType ) - { - objType->Release(); - *(asPWORD*)&bc[n+1] = 0; - } - - int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE); - if( func ) - { - engine->scriptFunctions[func]->Release(); - bc[n+AS_PTR_SIZE+1] = 0; - } - } - break; - - case asBC_CALL: - case asBC_CALLINTF: - { - int func = asBC_INTARG(&bc[n]); - if( func ) - { - engine->scriptFunctions[func]->Release(); - bc[n+1] = 0; - } - } - break; - - // Function pointers - case asBC_FuncPtr: - { - asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]); - if( func ) - { - func->Release(); - *(asPWORD*)&bc[n+1] = 0; - } - } - break; - - // The global variables are not released here. It is enough that the global - // variable itself release the function to break the circle - } - } - } - - // Delegate - if( objForDelegate ) - engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType()); - objForDelegate = 0; - if( funcForDelegate ) - funcForDelegate->Release(); - funcForDelegate = 0; -} - -// internal -bool asCScriptFunction::IsShared() const -{ - // All system functions are shared - if( funcType == asFUNC_SYSTEM ) return true; - - // All class methods for shared classes are also shared - if( objectType && (objectType->flags & asOBJ_SHARED) ) return true; - - // Functions that have been specifically marked as shared are shared - return isShared; -} - -// internal -bool asCScriptFunction::IsFinal() const -{ - return isFinal; -} - -// internal -bool asCScriptFunction::IsOverride() const -{ - return isOverride; -} - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_scriptfunction.h b/dependencies/angelscript/source/as_scriptfunction.h deleted file mode 100644 index 132fd2e8..00000000 --- a/dependencies/angelscript/source/as_scriptfunction.h +++ /dev/null @@ -1,330 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_scriptfunction.h -// -// A container for a compiled script function -// - - - -#ifndef AS_SCRIPTFUNCTION_H -#define AS_SCRIPTFUNCTION_H - -#include "as_config.h" -#include "as_string.h" -#include "as_array.h" -#include "as_datatype.h" -#include "as_atomic.h" - -BEGIN_AS_NAMESPACE - -class asCScriptEngine; -class asCModule; -class asCConfigGroup; -class asCGlobalProperty; -class asCScriptNode; -struct asSNameSpace; - -struct asSScriptVariable -{ - asCString name; - asCDataType type; - int stackOffset; - asUINT declaredAtProgramPos; -}; - -enum asEListPatternNodeType -{ - asLPT_REPEAT, - asLPT_REPEAT_SAME, - asLPT_START, - asLPT_END, - asLPT_TYPE -}; - -struct asSListPatternNode -{ - asSListPatternNode(asEListPatternNodeType t) : type(t), next(0) {} - virtual ~asSListPatternNode() {}; - virtual asSListPatternNode *Duplicate() { return asNEW(asSListPatternNode)(type); } - asEListPatternNodeType type; - asSListPatternNode *next; -}; - -struct asSListPatternDataTypeNode : public asSListPatternNode -{ - asSListPatternDataTypeNode(const asCDataType &dt) : asSListPatternNode(asLPT_TYPE), dataType(dt) {} - asSListPatternNode *Duplicate() { return asNEW(asSListPatternDataTypeNode)(dataType); } - asCDataType dataType; -}; - -enum asEObjVarInfoOption -{ - asOBJ_UNINIT, - asOBJ_INIT, - asBLOCK_BEGIN, - asBLOCK_END -}; - -struct asSObjectVariableInfo -{ - asUINT programPos; - int variableOffset; - asUINT option; -}; - -struct asSSystemFunctionInterface; - -// TODO: Might be interesting to allow enumeration of accessed global variables, and -// also functions/methods that are being called. This could be used to build a -// code database with call graphs, etc. - -void RegisterScriptFunction(asCScriptEngine *engine); - -class asCScriptFunction : public asIScriptFunction -{ -public: - // From asIScriptFunction - asIScriptEngine *GetEngine() const; - - // Memory management - int AddRef() const; - int Release() const; - - // Miscellaneous - int GetId() const; - asEFuncType GetFuncType() const; - const char *GetModuleName() const; - asIScriptModule *GetModule() const; - const char *GetScriptSectionName() const; - const char *GetConfigGroup() const; - asDWORD GetAccessMask() const; - - // Function signature - asIObjectType *GetObjectType() const; - const char *GetObjectName() const; - const char *GetName() const; - const char *GetNamespace() const; - const char *GetDeclaration(bool includeObjectName = true, bool includeNamespace = false, bool includeParamNames = false) const; - bool IsReadOnly() const; - bool IsPrivate() const; - bool IsFinal() const; - bool IsOverride() const; - bool IsShared() const; - asUINT GetParamCount() const; - int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const; -#ifdef AS_DEPRECATED - // Deprecated, since 2.29.0, 2014-04-06 - int GetParamTypeId(asUINT index, asDWORD *flags = 0) const; -#endif - int GetReturnTypeId(asDWORD *flags = 0) const; - - // Type id for function pointers - int GetTypeId() const; - bool IsCompatibleWithTypeId(int typeId) const; - - // Delegates - void *GetDelegateObject() const; - asIObjectType *GetDelegateObjectType() const; - asIScriptFunction *GetDelegateFunction() const; - - // Debug information - asUINT GetVarCount() const; - int GetVar(asUINT index, const char **name, int *typeId = 0) const; - const char * GetVarDecl(asUINT index, bool includeNamespace = false) const; - int FindNextLineWithCode(int line) const; - - // For JIT compilation - asDWORD *GetByteCode(asUINT *length = 0); - - // User data - void *SetUserData(void *userData, asPWORD type); - void *GetUserData(asPWORD type) const; - -public: - //----------------------------------- - // Internal methods - - asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType funcType); - ~asCScriptFunction(); - - void DestroyHalfCreated(); - - // TODO: 2.29.0: operator== - // TODO: 2.29.0: The asIScriptFunction should provide operator== and operator!= that should do a - // a value comparison. Two delegate objects that point to the same object and class method should compare as equal - // TODO: 2.29.0: The operator== should also be provided in script as opEquals to allow the same comparison in script - // To do this we'll need some way to adapt the argtype for opEquals for each funcdef, preferrably without instantiating lots of different methods - // Perhaps reusing 'auto' to mean the same type as the object - //bool operator==(const asCScriptFunction &other) const; - - void DestroyInternal(); - void Orphan(asIScriptModule *mod); - - void AddVariable(asCString &name, asCDataType &type, int stackOffset); - - int GetSpaceNeededForArguments(); - int GetSpaceNeededForReturnValue(); - asCString GetDeclarationStr(bool includeObjectName = true, bool includeNamespace = false, bool includeParamNames = false) const; - int GetLineNumber(int programPosition, int *sectionIdx); - void ComputeSignatureId(); - bool IsSignatureEqual(const asCScriptFunction *func) const; - bool IsSignatureExceptNameEqual(const asCScriptFunction *func) const; - bool IsSignatureExceptNameEqual(const asCDataType &retType, const asCArray ¶mTypes, const asCArray &inOutFlags, const asCObjectType *type, bool isReadOnly) const; - bool IsSignatureExceptNameAndReturnTypeEqual(const asCScriptFunction *fun) const; - bool IsSignatureExceptNameAndReturnTypeEqual(const asCArray ¶mTypes, const asCArray &inOutFlags, const asCObjectType *type, bool isReadOnly) const; - bool IsSignatureExceptNameAndObjectTypeEqual(const asCScriptFunction *func) const; - - asCObjectType *GetObjectTypeOfLocalVar(short varOffset); - - void MakeDelegate(asCScriptFunction *func, void *obj); - - int RegisterListPattern(const char *decl, asCScriptNode *listPattern); - int ParseListPattern(asSListPatternNode *&target, const char *decl, asCScriptNode *listPattern); - - bool DoesReturnOnStack() const; - - void JITCompile(); - - void AddReferences(); - void ReleaseReferences(); - - void AllocateScriptFunctionData(); - void DeallocateScriptFunctionData(); - - asCGlobalProperty *GetPropertyByGlobalVarPtr(void *gvarPtr); - - // GC methods - int GetRefCount(); - void SetFlag(); - bool GetFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllHandles(asIScriptEngine *engine); - -public: - //----------------------------------- - // Properties - - mutable asCAtomic refCount; - mutable bool gcFlag; - asCScriptEngine *engine; - asCModule *module; - - asCArray userData; - - // Function signature - asCString name; - asCDataType returnType; - asCArray parameterTypes; - asCArray parameterNames; - asCArray inOutFlags; - asCArray defaultArgs; - bool isReadOnly; - bool isPrivate; - bool isFinal; - bool isOverride; - asCObjectType *objectType; - int signatureId; - - int id; - - asEFuncType funcType; - asDWORD accessMask; - bool isShared; - - asSNameSpace *nameSpace; - - // Used by asFUNC_DELEGATE - void *objForDelegate; - asCScriptFunction *funcForDelegate; - - // Used by list factory behaviour - asSListPatternNode *listPattern; - - // Used by asFUNC_SCRIPT - struct ScriptFunctionData - { - // Bytecode for the script function - asCArray byteCode; - - // The stack space needed for the local variables - asDWORD variableSpace; - - // These hold information on objects and function pointers, including temporary - // variables used by exception handler and when saving bytecode - asCArray objVariableTypes; - asCArray funcVariableTypes; - asCArray objVariablePos; - - // The first variables in above array are allocated on the heap, the rest on the stack. - // This variable shows how many are on the heap. - asUINT objVariablesOnHeap; - - // Holds information on scope for object variables on the stack - asCArray objVariableInfo; - - // The stack needed to execute the function - int stackNeeded; - - // JIT compiled code of this function - asJITFunction jitFunction; - - // Holds debug information on explicitly declared variables - asCArray variables; - // Store position, line number pairs for debug information - asCArray lineNumbers; - // Store the script section where the code was declared - int scriptSectionIdx; - // Store the location where the function was declared - int declaredAt; - // Store position/index pairs if the bytecode is compiled from multiple script sections - asCArray sectionIdxs; - }; - ScriptFunctionData *scriptData; - - // Stub functions and delegates don't own the object and parameters - bool dontCleanUpOnException; - - // Used by asFUNC_VIRTUAL - int vfTableIdx; - - // Used by asFUNC_SYSTEM - asSSystemFunctionInterface *sysFuncIntf; -}; - -const char * const DELEGATE_FACTORY = "%delegate_factory"; -asCScriptFunction *CreateDelegate(asCScriptFunction *func, void *obj); - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_scriptnode.cpp b/dependencies/angelscript/source/as_scriptnode.cpp deleted file mode 100644 index 07ec7655..00000000 --- a/dependencies/angelscript/source/as_scriptnode.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2012 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_scriptnode.cpp -// -// A node in the script tree built by the parser for compilation -// - - - -#include "as_scriptnode.h" -#include "as_scriptengine.h" - -BEGIN_AS_NAMESPACE - -asCScriptNode::asCScriptNode(eScriptNode type) -{ - nodeType = type; - tokenType = ttUnrecognizedToken; - tokenPos = 0; - tokenLength = 0; - - parent = 0; - next = 0; - prev = 0; - firstChild = 0; - lastChild = 0; -} - -void asCScriptNode::Destroy(asCScriptEngine *engine) -{ - // Destroy all children - asCScriptNode *node = firstChild; - asCScriptNode *next; - - while( node ) - { - next = node->next; - node->Destroy(engine); - node = next; - } - - // Return the memory to the memory manager - engine->memoryMgr.FreeScriptNode(this); -} - -asCScriptNode *asCScriptNode::CreateCopy(asCScriptEngine *engine) -{ - void *ptr = engine->memoryMgr.AllocScriptNode(); - if( ptr == 0 ) - { - // Out of memory - return 0; - } - - new(ptr) asCScriptNode(nodeType); - - asCScriptNode *node = reinterpret_cast(ptr); - node->tokenLength = tokenLength; - node->tokenPos = tokenPos; - node->tokenType = tokenType; - - asCScriptNode *child = firstChild; - while( child ) - { - node->AddChildLast(child->CreateCopy(engine)); - child = child->next; - } - - return node; -} - -void asCScriptNode::SetToken(sToken *token) -{ - tokenType = token->type; -} - -void asCScriptNode::UpdateSourcePos(size_t pos, size_t length) -{ - if( pos == 0 && length == 0 ) return; - - if( tokenPos == 0 && tokenLength == 0 ) - { - tokenPos = pos; - tokenLength = length; - } - else - { - if( tokenPos > pos ) - { - tokenLength = tokenPos + tokenLength - pos; - tokenPos = pos; - } - - if( pos + length > tokenPos + tokenLength ) - { - tokenLength = pos + length - tokenPos; - } - } -} - -void asCScriptNode::AddChildLast(asCScriptNode *node) -{ - // We might get a null pointer if the parser encounter an out-of-memory situation - if( node == 0 ) return; - - if( lastChild ) - { - lastChild->next = node; - node->next = 0; - node->prev = lastChild; - node->parent = this; - lastChild = node; - } - else - { - firstChild = node; - lastChild = node; - node->next = 0; - node->prev = 0; - node->parent = this; - } - - UpdateSourcePos(node->tokenPos, node->tokenLength); -} - -void asCScriptNode::DisconnectParent() -{ - if( parent ) - { - if( parent->firstChild == this ) - parent->firstChild = next; - if( parent->lastChild == this ) - parent->lastChild = prev; - } - - if( next ) - next->prev = prev; - - if( prev ) - prev->next = next; - - parent = 0; - next = 0; - prev = 0; -} - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_scriptnode.h b/dependencies/angelscript/source/as_scriptnode.h deleted file mode 100644 index 2a972e45..00000000 --- a/dependencies/angelscript/source/as_scriptnode.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_scriptnode.h -// -// A node in the script tree built by the parser for compilation -// - - -#ifndef AS_SCRIPTNODE_H -#define AS_SCRIPTNODE_H - -#include "as_config.h" -#include "as_tokendef.h" - -BEGIN_AS_NAMESPACE - -enum eScriptNode -{ - snUndefined, - snScript, - snFunction, - snConstant, - snDataType, - snIdentifier, - snParameterList, - snStatementBlock, - snDeclaration, - snExpressionStatement, - snIf, - snFor, - snWhile, - snReturn, - snExpression, - snExprTerm, - snFunctionCall, - snConstructCall, - snArgList, - snExprPreOp, - snExprPostOp, - snExprOperator, - snExprValue, - snBreak, - snContinue, - snDoWhile, - snAssignment, - snCondition, - snSwitch, - snCase, - snImport, - snClass, - snInitList, - snInterface, - snEnum, - snTypedef, - snCast, - snVariableAccess, - snFuncDef, - snVirtualProperty, - snNamespace, - snMixin, - snListPattern, - snNamedArgument -}; - -struct sToken -{ - eTokenType type; - size_t pos; - size_t length; -}; - -class asCScriptEngine; - -class asCScriptNode -{ -public: - asCScriptNode(eScriptNode nodeType); - - void Destroy(asCScriptEngine *engine); - asCScriptNode *CreateCopy(asCScriptEngine *engine); - - void SetToken(sToken *token); - void AddChildLast(asCScriptNode *node); - void DisconnectParent(); - - void UpdateSourcePos(size_t pos, size_t length); - - eScriptNode nodeType; - eTokenType tokenType; - size_t tokenPos; - size_t tokenLength; - - asCScriptNode *parent; - asCScriptNode *next; - asCScriptNode *prev; - asCScriptNode *firstChild; - asCScriptNode *lastChild; - -protected: - // Must call Destroy instead - ~asCScriptNode() {} -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_scriptobject.cpp b/dependencies/angelscript/source/as_scriptobject.cpp deleted file mode 100644 index ef0d4a12..00000000 --- a/dependencies/angelscript/source/as_scriptobject.cpp +++ /dev/null @@ -1,954 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -#include -#include "as_config.h" -#include "as_scriptengine.h" -#include "as_scriptobject.h" -#include "as_texts.h" - -BEGIN_AS_NAMESPACE - -// This helper function will call the default factory, that is a script function -asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngine *engine) -{ - asIScriptContext *ctx = 0; - int r = 0; - bool isNested = false; - - // Use nested call in the context if there is an active context - ctx = asGetActiveContext(); - if( ctx ) - { - // It may not always be possible to reuse the current context, - // in which case we'll have to create a new one any way. - if( ctx->GetEngine() == objType->GetEngine() && ctx->PushState() == asSUCCESS ) - isNested = true; - else - ctx = 0; - } - - if( ctx == 0 ) - { - // Request a context from the engine - ctx = engine->RequestContext(); - if( ctx == 0 ) - { - // TODO: How to best report this failure? - return 0; - } - } - - r = ctx->Prepare(engine->scriptFunctions[objType->beh.factory]); - if( r < 0 ) - { - if( isNested ) - ctx->PopState(); - else - engine->ReturnContext(ctx); - return 0; - } - - for(;;) - { - r = ctx->Execute(); - - // We can't allow this execution to be suspended - // so resume the execution immediately - if( r != asEXECUTION_SUSPENDED ) - break; - } - - if( r != asEXECUTION_FINISHED ) - { - if( isNested ) - { - ctx->PopState(); - - // If the execution was aborted or an exception occurred, - // then we should forward that to the outer execution. - if( r == asEXECUTION_EXCEPTION ) - { - // TODO: How to improve this exception - ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); - } - else if( r == asEXECUTION_ABORTED ) - ctx->Abort(); - } - else - engine->ReturnContext(ctx); - return 0; - } - - asIScriptObject *ptr = (asIScriptObject*)ctx->GetReturnAddress(); - - // Increase the reference, because the context will release its pointer - ptr->AddRef(); - - if( isNested ) - ctx->PopState(); - else - engine->ReturnContext(ctx); - - return ptr; -} - -#ifdef AS_MAX_PORTABILITY - -static void ScriptObject_AddRef_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - self->AddRef(); -} - -static void ScriptObject_Release_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - self->Release(); -} - -static void ScriptObject_GetRefCount_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); -} - -static void ScriptObject_SetFlag_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - self->SetFlag(); -} - -static void ScriptObject_GetFlag_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); -} - -static void ScriptObject_GetWeakRefFlag_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - *(asILockableSharedBool**)gen->GetAddressOfReturnLocation() = self->GetWeakRefFlag(); -} - -static void ScriptObject_EnumReferences_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); -} - -static void ScriptObject_ReleaseAllHandles_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllHandles(engine); -} - -#endif - -void RegisterScriptObject(asCScriptEngine *engine) -{ - // Register the default script class behaviours - int r = 0; - UNUSED_VAR(r); // It is only used in debug mode - engine->scriptTypeBehaviours.engine = engine; - engine->scriptTypeBehaviours.flags = asOBJ_SCRIPT_OBJECT | asOBJ_REF | asOBJ_GC; - engine->scriptTypeBehaviours.name = "_builtin_object_"; -#ifndef AS_MAX_PORTABILITY - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptObject_Construct), asCALL_CDECL_OBJLAST, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptObject,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptObject,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterMethodToObjectType(&engine->scriptTypeBehaviours, "int &opAssign(int &in)", asFUNCTION(ScriptObject_Assignment), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 ); - - // Weakref behaviours - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GET_WEAKREF_FLAG, "int &f()", asMETHOD(asCScriptObject,GetWeakRefFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - - // Register GC behaviours - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCScriptObject,GetRefCount), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCScriptObject,SetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptObject,GetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptObject,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptObject,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 ); -#else - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptObject_Construct_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptObject_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptObject_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterMethodToObjectType(&engine->scriptTypeBehaviours, "int &opAssign(int &in)", asFUNCTION(ScriptObject_Assignment_Generic), asCALL_GENERIC); asASSERT( r >= 0 ); - - // Weakref behaviours - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GET_WEAKREF_FLAG, "int &f()", asFUNCTION(ScriptObject_GetWeakRefFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - - // Register GC behaviours - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptObject_GetRefCount_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptObject_SetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptObject_GetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptObject_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); - r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptObject_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); -#endif -} - -void ScriptObject_Construct_Generic(asIScriptGeneric *gen) -{ - asCObjectType *objType = *(asCObjectType**)gen->GetAddressOfArg(0); - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - - ScriptObject_Construct(objType, self); -} - -void ScriptObject_Construct(asCObjectType *objType, asCScriptObject *self) -{ - new(self) asCScriptObject(objType); -} - -void ScriptObject_ConstructUnitialized(asCObjectType *objType, asCScriptObject *self) -{ - new(self) asCScriptObject(objType, false); -} - -asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize) -{ - refCount.set(1); - objType = ot; - objType->AddRef(); - isDestructCalled = false; - weakRefFlag = 0; - hasRefCountReachedZero = false; - - // Notify the garbage collector of this object - if( objType->flags & asOBJ_GC ) - objType->engine->gc.AddScriptObjectToGC(this, objType); - - // Initialize members to zero. Technically we only need to zero the pointer - // members, but just the memset is faster than having to loop and check the datatypes - memset((void*)(this+1), 0, objType->size - sizeof(asCScriptObject)); - - if( doInitialize ) - { -#ifdef AS_NO_MEMBER_INIT - // When member initialization is disabled the constructor must make sure - // to allocate and initialize all members with the default constructor - for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) - { - asCObjectProperty *prop = objType->properties[n]; - if( prop->type.IsObject() && !prop->type.IsObjectHandle() ) - { - if( prop->type.IsReference() || prop->type.GetObjectType()->flags & asOBJ_REF ) - { - asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); - if( prop->type.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT ) - *ptr = (asPWORD)ScriptObjectFactory(prop->type.GetObjectType(), ot->engine); - else - *ptr = (asPWORD)AllocateUninitializedObject(prop->type.GetObjectType(), ot->engine); - } - } - } -#endif - } - else - { - // When the object is created without initialization, all non-handle members must be allocated, but not initialized - asCScriptEngine *engine = objType->engine; - for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) - { - asCObjectProperty *prop = objType->properties[n]; - if( prop->type.IsObject() && !prop->type.IsObjectHandle() ) - { - if( prop->type.IsReference() || (prop->type.GetObjectType()->flags & asOBJ_REF) ) - { - asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); - *ptr = (asPWORD)AllocateUninitializedObject(prop->type.GetObjectType(), engine); - } - } - } - } -} - -void asCScriptObject::Destruct() -{ - // Call the destructor, which will also call the GCObject's destructor - this->~asCScriptObject(); - - // Free the memory -#ifndef WIP_16BYTE_ALIGN - userFree(this); -#else - // Script object memory is allocated through asCScriptEngine::CallAlloc() - // This free call must match the allocator used in CallAlloc(). - userFreeAligned(this); -#endif -} - -asCScriptObject::~asCScriptObject() -{ - if( weakRefFlag ) - { - weakRefFlag->Release(); - weakRefFlag = 0; - } - - // The engine pointer should be available from the objectType - asCScriptEngine *engine = objType->engine; - - // Destroy all properties - // In most cases the members are initialized in the order they have been declared, - // so it's safer to uninitialize them from last to first. The order may be different - // depending on the use of inheritance and or initialization in the declaration. - // TODO: Should the order of initialization be stored by the compiler so that the - // reverse order can be guaranteed during the destruction? - for( int n = (int)objType->properties.GetLength()-1; n >= 0; n-- ) - { - asCObjectProperty *prop = objType->properties[n]; - if( prop->type.IsObject() ) - { - // Destroy the object - asCObjectType *propType = prop->type.GetObjectType(); - if( prop->type.IsReference() || propType->flags & asOBJ_REF ) - { - void **ptr = (void**)(((char*)this) + prop->byteOffset); - if( *ptr ) - { - FreeObject(*ptr, propType, engine); - *(asDWORD*)ptr = 0; - } - } - else - { - // The object is allocated inline. As only POD objects may be allocated inline - // it is not a problem to call the destructor even if the object may never have - // been initialized, e.g. if an exception interrupted the constructor. - asASSERT( propType->flags & asOBJ_POD ); - - void *ptr = (void**)(((char*)this) + prop->byteOffset); - if( propType->beh.destruct ) - engine->CallObjectMethod(ptr, propType->beh.destruct); - } - } - } - - objType->Release(); - objType = 0; - - // Something is really wrong if the refCount is not 0 by now - asASSERT( refCount.get() == 0 ); -} - -asILockableSharedBool *asCScriptObject::GetWeakRefFlag() const -{ - // If the object's refCount has already reached zero then the object is already - // about to be destroyed so it's ok to return null if the weakRefFlag doesn't already - // exist - if( weakRefFlag || hasRefCountReachedZero ) - return weakRefFlag; - - // Lock globally so no other thread can attempt - // to create a shared bool at the same time. - // TODO: runtime optimize: Instead of locking globally, it would be possible to have - // a critical section per object type. This would reduce the - // chances of two threads lock on the same critical section. - asAcquireExclusiveLock(); - - // Make sure another thread didn't create the - // flag while we waited for the lock - if( !weakRefFlag ) - weakRefFlag = asNEW(asCLockableSharedBool); - - asReleaseExclusiveLock(); - - return weakRefFlag; -} - -asIScriptEngine *asCScriptObject::GetEngine() const -{ - return objType->engine; -} - -int asCScriptObject::AddRef() const -{ - // Warn in case the application tries to increase the refCount after it has reached zero. - // This may happen for example if the application calls a method on the class while it is - // being destroyed. The application shouldn't do this because it may cause application - // crashes if members that have already been destroyed are accessed accidentally. - if( hasRefCountReachedZero ) - { - if( objType && objType->engine ) - { - asCString msg; - msg.Format(TXT_RESURRECTING_SCRIPTOBJECT_s, objType->name.AddressOf()); - objType->engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - } - } - - // Increase counter and clear flag set by GC - gcFlag = false; - return refCount.atomicInc(); -} - -int asCScriptObject::Release() const -{ - // Clear the flag set by the GC - gcFlag = false; - - // If the weak ref flag exists it is because someone held a weak ref - // and that someone may add a reference to the object at any time. It - // is ok to check the existance of the weakRefFlag without locking here - // because if the refCount is 1 then no other thread is currently - // creating the weakRefFlag. - if( refCount.get() == 1 && weakRefFlag ) - { - // Set the flag to tell others that the object is no longer alive - // We must do this before decreasing the refCount to 0 so we don't - // end up with a race condition between this thread attempting to - // destroy the object and the other that temporary added a strong - // ref from the weak ref. - weakRefFlag->Set(true); - } - - // Call the script destructor behaviour if the reference counter is 1. - if( refCount.get() == 1 && !isDestructCalled ) - { - // This cast is OK since we are the last reference - const_cast(this)->CallDestructor(); - } - - // Now do the actual releasing - int r = refCount.atomicDec(); - if( r == 0 ) - { - // Flag this object as being destroyed so the application - // can be warned if the code attempts to resurrect the object - // during the destructor. This also avoids a recursive call - // to the destructor which would crash the application if it - // really does resurrect the object. - if( !hasRefCountReachedZero ) - { - hasRefCountReachedZero = true; - - // This cast is OK since we are the last reference - const_cast(this)->Destruct(); - } - return 0; - } - - return r; -} - -void asCScriptObject::CallDestructor() -{ - // Only allow the destructor to be called once - if( isDestructCalled ) return; - - asIScriptContext *ctx = 0; - bool isNested = false; - bool doAbort = false; - - // Make sure the destructor is called once only, even if the - // reference count is increased and then decreased again - isDestructCalled = true; - - // Call the destructor for this class and all the super classes - asCObjectType *ot = objType; - while( ot ) - { - int funcIndex = ot->beh.destruct; - if( funcIndex ) - { - if( ctx == 0 ) - { - // Check for active context first as it is quicker - // to reuse than to set up a new one. - ctx = asGetActiveContext(); - if( ctx ) - { - if( ctx->GetEngine() == objType->GetEngine() && ctx->PushState() == asSUCCESS ) - isNested = true; - else - ctx = 0; - } - - if( ctx == 0 ) - { - // Request a context from the engine - ctx = objType->engine->RequestContext(); - if( ctx == 0 ) - { - // TODO: How to best report this failure? - return; - } - } - } - - int r = ctx->Prepare(objType->engine->scriptFunctions[funcIndex]); - if( r >= 0 ) - { - ctx->SetObject(this); - - for(;;) - { - r = ctx->Execute(); - - // If the script tries to suspend itself just restart it - if( r != asEXECUTION_SUSPENDED ) - break; - } - - // Exceptions in the destructor will be ignored, as there is not much - // that can be done about them. However a request to abort the execution - // will be forwarded to the outer execution, in case of a nested call. - if( r == asEXECUTION_ABORTED ) - doAbort = true; - - // Observe, even though the current destructor was aborted or an exception - // occurred, we still try to execute the base class' destructor if available - // in order to free as many resources as possible. - } - } - - ot = ot->derivedFrom; - } - - if( ctx ) - { - if( isNested ) - { - ctx->PopState(); - - // Forward any request to abort the execution to the outer call - if( doAbort ) - ctx->Abort(); - } - else - { - // Return the context to engine - objType->engine->ReturnContext(ctx); - } - } -} - -asIObjectType *asCScriptObject::GetObjectType() const -{ - return objType; -} - -int asCScriptObject::GetRefCount() -{ - return refCount.get(); -} - -void asCScriptObject::SetFlag() -{ - gcFlag = true; -} - -bool asCScriptObject::GetFlag() -{ - return gcFlag; -} - -// interface -int asCScriptObject::GetTypeId() const -{ - asCDataType dt = asCDataType::CreateObject(objType, false); - return objType->engine->GetTypeIdFromDataType(dt); -} - -asUINT asCScriptObject::GetPropertyCount() const -{ - return asUINT(objType->properties.GetLength()); -} - -int asCScriptObject::GetPropertyTypeId(asUINT prop) const -{ - if( prop >= objType->properties.GetLength() ) - return asINVALID_ARG; - - return objType->engine->GetTypeIdFromDataType(objType->properties[prop]->type); -} - -const char *asCScriptObject::GetPropertyName(asUINT prop) const -{ - if( prop >= objType->properties.GetLength() ) - return 0; - - return objType->properties[prop]->name.AddressOf(); -} - -void *asCScriptObject::GetAddressOfProperty(asUINT prop) -{ - if( prop >= objType->properties.GetLength() ) - return 0; - - // Objects are stored by reference, so this must be dereferenced - asCDataType *dt = &objType->properties[prop]->type; - if( dt->IsObject() && !dt->IsObjectHandle() && - (dt->IsReference() || dt->GetObjectType()->flags & asOBJ_REF) ) - return *(void**)(((char*)this) + objType->properties[prop]->byteOffset); - - return (void*)(((char*)this) + objType->properties[prop]->byteOffset); -} - -void asCScriptObject::EnumReferences(asIScriptEngine *engine) -{ - // We'll notify the GC of all object handles that we're holding - for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) - { - asCObjectProperty *prop = objType->properties[n]; - if( prop->type.IsObject() ) - { - // TODO: gc: The members of the value type needs to be enumerated - // too, since the value type may be holding a reference. - void *ptr; - if( prop->type.IsReference() || (prop->type.GetObjectType()->flags & asOBJ_REF) ) - ptr = *(void**)(((char*)this) + prop->byteOffset); - else - ptr = (void*)(((char*)this) + prop->byteOffset); - - if( ptr ) - ((asCScriptEngine*)engine)->GCEnumCallback(ptr); - } - } -} - -void asCScriptObject::ReleaseAllHandles(asIScriptEngine *engine) -{ - for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) - { - asCObjectProperty *prop = objType->properties[n]; - - // TODO: gc: The members of the members needs to be released - // too, since they may be holding a reference. Even - // if the member is a value type. - if( prop->type.IsObject() && prop->type.IsObjectHandle() ) - { - void **ptr = (void**)(((char*)this) + prop->byteOffset); - if( *ptr ) - { - asASSERT( (prop->type.GetObjectType()->flags & asOBJ_NOCOUNT) || prop->type.GetBehaviour()->release ); - if( prop->type.GetBehaviour()->release ) - ((asCScriptEngine*)engine)->CallObjectMethod(*ptr, prop->type.GetBehaviour()->release); - *ptr = 0; - } - } - } -} - -void ScriptObject_Assignment_Generic(asIScriptGeneric *gen) -{ - asCScriptObject *other = *(asCScriptObject**)gen->GetAddressOfArg(0); - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - - *self = *other; - - *(asCScriptObject**)gen->GetAddressOfReturnLocation() = self; -} - -asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject *self) -{ - return (*self = *other); -} - -asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other) -{ - if( &other != this ) - { - if( !other.objType->DerivesFrom(objType) ) - { - // We cannot allow a value assignment from a type that isn't the same or - // derives from this type as the member properties may not have the same layout - asIScriptContext *ctx = asGetActiveContext(); - ctx->SetException(TXT_MISMATCH_IN_VALUE_ASSIGN); - return *this; - } - - // If the script class implements the opAssign method, it should be called - asCScriptEngine *engine = objType->engine; - asCScriptFunction *func = engine->scriptFunctions[objType->beh.copy]; - if( func->funcType == asFUNC_SYSTEM ) - { - // Copy all properties - for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) - { - asCObjectProperty *prop = objType->properties[n]; - if( prop->type.IsObject() ) - { - void **dst = (void**)(((char*)this) + prop->byteOffset); - void **src = (void**)(((char*)&other) + prop->byteOffset); - if( !prop->type.IsObjectHandle() ) - { - if( prop->type.IsReference() || (prop->type.GetObjectType()->flags & asOBJ_REF) ) - CopyObject(*src, *dst, prop->type.GetObjectType(), engine); - else - CopyObject(src, dst, prop->type.GetObjectType(), engine); - } - else - CopyHandle((asPWORD*)src, (asPWORD*)dst, prop->type.GetObjectType(), engine); - } - else - { - void *dst = ((char*)this) + prop->byteOffset; - void *src = ((char*)&other) + prop->byteOffset; - memcpy(dst, src, prop->type.GetSizeInMemoryBytes()); - } - } - } - else - { - // Reuse the active context or create a new one to call the script class' opAssign method - asIScriptContext *ctx = 0; - int r = 0; - bool isNested = false; - - ctx = asGetActiveContext(); - if( ctx ) - { - if( ctx->GetEngine() == engine && ctx->PushState() == asSUCCESS ) - isNested = true; - else - ctx = 0; - } - - if( ctx == 0 ) - { - // Request a context from the engine - ctx = engine->RequestContext(); - if( ctx == 0 ) - { - // TODO: How to best report this failure? - return *this; - } - } - - r = ctx->Prepare(engine->scriptFunctions[objType->beh.copy]); - if( r < 0 ) - { - if( isNested ) - ctx->PopState(); - else - engine->ReturnContext(ctx); - // TODO: How to best report this failure? - return *this; - } - - r = ctx->SetArgAddress(0, const_cast(&other)); - asASSERT( r >= 0 ); - r = ctx->SetObject(this); - asASSERT( r >= 0 ); - - for(;;) - { - r = ctx->Execute(); - - // We can't allow this execution to be suspended - // so resume the execution immediately - if( r != asEXECUTION_SUSPENDED ) - break; - } - - if( r != asEXECUTION_FINISHED ) - { - if( isNested ) - { - ctx->PopState(); - - // If the execution was aborted or an exception occurred, - // then we should forward that to the outer execution. - if( r == asEXECUTION_EXCEPTION ) - { - // TODO: How to improve this exception - ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); - } - else if( r == asEXECUTION_ABORTED ) - ctx->Abort(); - } - else - { - // Return the context to the engine - engine->ReturnContext(ctx); - } - return *this; - } - - if( isNested ) - ctx->PopState(); - else - { - // Return the context to the engine - engine->ReturnContext(ctx); - } - } - } - - return *this; -} - -int asCScriptObject::CopyFrom(asIScriptObject *other) -{ - if( other == 0 ) return asINVALID_ARG; - - if( GetTypeId() != other->GetTypeId() ) - return asINVALID_TYPE; - - *this = *(asCScriptObject*)other; - - return 0; -} - -void *asCScriptObject::AllocateUninitializedObject(asCObjectType *objType, asCScriptEngine *engine) -{ - void *ptr = 0; - - if( objType->flags & asOBJ_SCRIPT_OBJECT ) - { - ptr = engine->CallAlloc(objType); - ScriptObject_ConstructUnitialized(objType, reinterpret_cast(ptr)); - } - else if( objType->flags & asOBJ_TEMPLATE ) - { - // Templates store the original factory that takes the object - // type as a hidden parameter in the construct behaviour - ptr = engine->CallGlobalFunctionRetPtr(objType->beh.construct, objType); - } - else if( objType->flags & asOBJ_REF ) - { - ptr = engine->CallGlobalFunctionRetPtr(objType->beh.factory); - } - else - { - ptr = engine->CallAlloc(objType); - int funcIndex = objType->beh.construct; - if( funcIndex ) - engine->CallObjectMethod(ptr, funcIndex); - } - - return ptr; -} - -void asCScriptObject::FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine) -{ - if( objType->flags & asOBJ_REF ) - { - asASSERT( (objType->flags & asOBJ_NOCOUNT) || objType->beh.release ); - if( objType->beh.release ) - engine->CallObjectMethod(ptr, objType->beh.release); - } - else - { - if( objType->beh.destruct ) - engine->CallObjectMethod(ptr, objType->beh.destruct); - - engine->CallFree(ptr); - } -} - -void asCScriptObject::CopyObject(void *src, void *dst, asCObjectType *objType, asCScriptEngine *engine) -{ - int funcIndex = objType->beh.copy; - if( funcIndex ) - { - asCScriptFunction *func = engine->scriptFunctions[objType->beh.copy]; - if( func->funcType == asFUNC_SYSTEM ) - engine->CallObjectMethod(dst, src, funcIndex); - else - { - // Call the script class' opAssign method - asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT ); - reinterpret_cast(dst)->CopyFrom(reinterpret_cast(src)); - } - } - else if( objType->size && (objType->flags & asOBJ_POD) ) - memcpy(dst, src, objType->size); -} - -void asCScriptObject::CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine) -{ - // asOBJ_NOCOUNT doesn't have addref or release behaviours - asASSERT( (objType->flags & asOBJ_NOCOUNT) || (objType->beh.release && objType->beh.addref) ); - - if( *dst && objType->beh.release ) - engine->CallObjectMethod(*(void**)dst, objType->beh.release); - *dst = *src; - if( *dst && objType->beh.addref ) - engine->CallObjectMethod(*(void**)dst, objType->beh.addref); -} - -// TODO: weak: Should move to its own file -asCLockableSharedBool::asCLockableSharedBool() : value(false) -{ - refCount.set(1); -} - -int asCLockableSharedBool::AddRef() const -{ - return refCount.atomicInc(); -} - -int asCLockableSharedBool::Release() const -{ - int r = refCount.atomicDec(); - if( r == 0 ) - asDELETE(const_cast(this), asCLockableSharedBool); - return r; -} - -bool asCLockableSharedBool::Get() const -{ - return value; -} - -void asCLockableSharedBool::Set(bool v) -{ - // Make sure the value is not changed while another thread - // is inspecting it and taking a decision on what to do. - Lock(); - value = v; - Unlock(); -} - -void asCLockableSharedBool::Lock() const -{ - ENTERCRITICALSECTION(lock); -} - -void asCLockableSharedBool::Unlock() const -{ - LEAVECRITICALSECTION(lock); -} - -// Interface -// Auxiliary function to allow applications to create shared -// booleans without having to implement the logic for them -AS_API asILockableSharedBool *asCreateLockableSharedBool() -{ - return asNEW(asCLockableSharedBool); -} - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_scriptobject.h b/dependencies/angelscript/source/as_scriptobject.h deleted file mode 100644 index 399020b0..00000000 --- a/dependencies/angelscript/source/as_scriptobject.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - -// -// as_scriptobject.h -// -// A generic class for handling script declared structures -// - - - -#ifndef AS_SCRIPTOBJECT_H -#define AS_SCRIPTOBJECT_H - -#include "as_config.h" -#include "as_atomic.h" - -BEGIN_AS_NAMESPACE - -class asCObjectType; - -// TODO: Add const overload for GetAddressOfProperty - -// TODO: weak: Should move to its own file -class asCLockableSharedBool : public asILockableSharedBool -{ -public: - asCLockableSharedBool(); - int AddRef() const; - int Release() const; - - bool Get() const; - void Set(bool); - - void Lock() const; - void Unlock() const; - -protected: - mutable asCAtomic refCount; - bool value; - DECLARECRITICALSECTION(mutable lock) -}; - -class asCScriptObject : public asIScriptObject -{ -public: -//=================================== -// From asIScriptObject -//=================================== - asIScriptEngine *GetEngine() const; - - // Memory management - int AddRef() const; - int Release() const; - - // Type info - int GetTypeId() const; - asIObjectType *GetObjectType() const; - - // Class properties - asUINT GetPropertyCount() const; - int GetPropertyTypeId(asUINT prop) const; - const char *GetPropertyName(asUINT prop) const; - void *GetAddressOfProperty(asUINT prop); - - int CopyFrom(asIScriptObject *other); - - // TODO: interface: Add a method for getting the weak ref flag directly from - // the object, so it is not necessary to call the engine's - // GetWeakRefFlagOfScriptObject - -//==================================== -// Internal -//==================================== - asCScriptObject(asCObjectType *objType, bool doInitialize = true); - virtual ~asCScriptObject(); - - asCScriptObject &operator=(const asCScriptObject &other); - - // GC methods - void Destruct(); - int GetRefCount(); - void SetFlag(); - bool GetFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllHandles(asIScriptEngine *engine); - - // Weakref methods - asILockableSharedBool *GetWeakRefFlag() const; - - // Used for properties - void *AllocateUninitializedObject(asCObjectType *objType, asCScriptEngine *engine); - void FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine); - void CopyObject(void *src, void *dst, asCObjectType *objType, asCScriptEngine *engine); - void CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine); - - void CallDestructor(); - -//============================================= -// Properties -//============================================= -public: - asCObjectType *objType; - -protected: - mutable asCAtomic refCount; - mutable asBYTE gcFlag:1; - mutable asBYTE hasRefCountReachedZero:1; - bool isDestructCalled; - - // TODO: 2.30.0: Allow storing user data in script objects too and minimize the memory overhead by - // storing the structure for holding the user data in a separate object that will only - // be allocated as needed. The weakRefFlag should be moved to this separate object too, - // so that by default the only overhead is a single pointer in the script object. - mutable asCLockableSharedBool *weakRefFlag; -}; - -void ScriptObject_Construct(asCObjectType *objType, asCScriptObject *self); -asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject *self); - -void ScriptObject_ConstructUnitialized(asCObjectType *objType, asCScriptObject *self); - -void ScriptObject_Construct_Generic(asIScriptGeneric *gen); -void ScriptObject_Assignment_Generic(asIScriptGeneric *gen); - -void RegisterScriptObject(asCScriptEngine *engine); - -asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngine *engine); - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_string.cpp b/dependencies/angelscript/source/as_string.cpp deleted file mode 100644 index 186442b1..00000000 --- a/dependencies/angelscript/source/as_string.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - -#include "as_config.h" - -#include // va_list, va_start(), etc -#include // strtod(), strtol() -#include // some compilers declare memcpy() here - -#if !defined(AS_NO_MEMORY_H) -#include -#endif - -#include "as_string.h" -#include "as_string_util.h" - -asCString::asCString() -{ - length = 0; - local[0] = 0; -} - -// Copy constructor -asCString::asCString(const asCString &str) -{ - length = 0; - local[0] = 0; - - Assign(str.AddressOf(), str.length); -} - -#ifdef AS_CAN_USE_CPP11 -asCString::asCString(asCString &&str) -{ - if( str.length <= 11 ) - { - length = str.length; - memcpy(local, str.local, length); - local[length] = 0; - } - else - { - dynamic = str.dynamic; - length = str.length; - } - - str.dynamic = 0; - str.length = 0; -} -#endif // c++11 - -asCString::asCString(const char *str, size_t len) -{ - length = 0; - local[0] = 0; - - Assign(str, len); -} - -asCString::asCString(const char *str) -{ - length = 0; - local[0] = 0; - - size_t len = strlen(str); - Assign(str, len); -} - -asCString::asCString(char ch) -{ - length = 0; - local[0] = 0; - - Assign(&ch, 1); -} - -asCString::~asCString() -{ - if( length > 11 && dynamic ) - { - asDELETEARRAY(dynamic); - } -} - -char *asCString::AddressOf() -{ - if( length <= 11 ) - return local; - else - return dynamic; -} - -const char *asCString::AddressOf() const -{ - if( length <= 11 ) - return local; - else - return dynamic; -} - -void asCString::SetLength(size_t len) -{ - Allocate(len, true); -} - -void asCString::Allocate(size_t len, bool keepData) -{ - // If we stored the capacity of the dynamically allocated buffer it would be possible - // to save some memory allocations if a string decreases in size then increases again, - // but this would require extra bytes in the string object itself, or a decrease of - // the static buffer, which in turn would mean extra memory is needed. I've tested each - // of these options, and it turned out that the current choice is what best balanced - // the number of allocations against the size of the allocations. - - if( len > 11 && len > length ) - { - // Allocate a new dynamic buffer if the new one is larger than the old - char *buf = asNEWARRAY(char,len+1); - if( buf == 0 ) - { - // Out of memory. Return without modifying anything - return; - } - - if( keepData ) - { - int l = (int)len < (int)length ? (int)len : (int)length; - memcpy(buf, AddressOf(), l); - } - - if( length > 11 ) - { - asDELETEARRAY(dynamic); - } - - dynamic = buf; - } - else if( len <= 11 && length > 11 ) - { - // Free the dynamic buffer, since it is no longer needed - char *buf = dynamic; - if( keepData ) - { - memcpy(&local, buf, len); - } - asDELETEARRAY(buf); - } - - length = (int)len; - - // Make sure the buffer is null terminated - AddressOf()[length] = 0; -} - -void asCString::Assign(const char *str, size_t len) -{ - Allocate(len, false); - - // Copy the string - memcpy(AddressOf(), str, length); - AddressOf()[length] = 0; -} - -asCString &asCString::operator =(const char *str) -{ - size_t len = str ? strlen(str) : 0; - Assign(str, len); - - return *this; -} - -asCString &asCString::operator =(const asCString &str) -{ - Assign(str.AddressOf(), str.length); - - return *this; -} - -#ifdef AS_CAN_USE_CPP11 -asCString &asCString::operator =(asCString &&str) -{ - if( this != &str ) - { - if( length > 11 && dynamic ) - { - asDELETEARRAY(dynamic); - } - - if ( str.length <= 11 ) - { - length = str.length; - - memcpy(local, str.local, length); - local[length] = 0; - } - else - { - dynamic = str.dynamic; - length = str.length; - } - - str.dynamic = 0; - str.length = 0; - } - - return *this; -} -#endif // c++11 - -asCString &asCString::operator =(char ch) -{ - Assign(&ch, 1); - - return *this; -} - -void asCString::Concatenate(const char *str, size_t len) -{ - asUINT oldLength = length; - SetLength(length + len); - - memcpy(AddressOf() + oldLength, str, len); - AddressOf()[length] = 0; -} - -asCString &asCString::operator +=(const char *str) -{ - size_t len = strlen(str); - Concatenate(str, len); - - return *this; -} - -asCString &asCString::operator +=(const asCString &str) -{ - Concatenate(str.AddressOf(), str.length); - - return *this; -} - -asCString &asCString::operator +=(char ch) -{ - Concatenate(&ch, 1); - - return *this; -} - -size_t asCString::GetLength() const -{ - return length; -} - -// Returns the length -size_t asCString::Format(const char *format, ...) -{ - va_list args; - va_start(args, format); - - char tmp[256]; - int r = asVSNPRINTF(tmp, 255, format, args); - - if( r > 0 ) - { - Assign(tmp, r); - } - else - { - size_t n = 512; - asCString str; // Use temporary string in case the current buffer is a parameter - str.Allocate(n, false); - - while( (r = asVSNPRINTF(str.AddressOf(), n, format, args)) < 0 ) - { - n *= 2; - str.Allocate(n, false); - } - - Assign(str.AddressOf(), r); - } - - va_end(args); - - return length; -} - -char &asCString::operator [](size_t index) -{ - asASSERT(index < length); - - return AddressOf()[index]; -} - -const char &asCString::operator [](size_t index) const -{ - asASSERT(index < length); - - return AddressOf()[index]; -} - -asCString asCString::SubString(size_t start, size_t length) const -{ - if( start >= GetLength() || length == 0 ) - return asCString(""); - - if( length == (size_t)(-1) ) length = GetLength() - start; - - asCString tmp; - tmp.Assign(AddressOf() + start, length); - - return tmp; -} - -int asCString::Compare(const char *str) const -{ - return asCompareStrings(AddressOf(), length, str, strlen(str)); -} - -int asCString::Compare(const asCString &str) const -{ - return asCompareStrings(AddressOf(), length, str.AddressOf(), str.GetLength()); -} - -int asCString::Compare(const char *str, size_t len) const -{ - return asCompareStrings(AddressOf(), length, str, len); -} - -size_t asCString::RecalculateLength() -{ - SetLength(strlen(AddressOf())); - - return length; -} - -int asCString::FindLast(const char *str, int *count) const -{ - // There is no strstr that starts from the end, so - // we'll iterate until we find the last occurrance. - // This shouldn't cause a performance problem because - // it is not expected that this will be done very often, - // and then only on quite short strings anyway. - - if( count ) *count = 0; - - const char *last = 0; - const char *curr = AddressOf()-1; - while( (curr = strstr(curr+1, str)) != 0 ) - { - if( count ) (*count)++; - last = curr; - } - - if( last ) - return int(last - AddressOf()); - - return -1; -} - -//----------------------------------------------------------------------------- -// Helper functions - -bool operator ==(const asCString &a, const char *b) -{ - return a.Compare(b) == 0; -} - -bool operator !=(const asCString &a, const char *b) -{ - return a.Compare(b) != 0; -} - -bool operator ==(const asCString &a, const asCString &b) -{ - return a.Compare(b) == 0; -} - -bool operator !=(const asCString &a, const asCString &b) -{ - return a.Compare(b) != 0; -} - -bool operator ==(const char *a, const asCString &b) -{ - return b.Compare(a) == 0; -} - -bool operator !=(const char *a, const asCString &b) -{ - return b.Compare(a) != 0; -} - -bool operator <(const asCString &a, const asCString &b) -{ - return a.Compare(b) < 0; -} - -asCString operator +(const asCString &a, const asCString &b) -{ - asCString res = a; - res += b; - - return res; -} - -asCString operator +(const char *a, const asCString &b) -{ - asCString res = a; - res += b; - - return res; -} - -asCString operator +(const asCString &a, const char *b) -{ - asCString res = a; - res += b; - - return res; -} - -// wrapper class - -asCStringPointer::asCStringPointer() - : string(0), length(0), cstring(0) -{ -} - -asCStringPointer::asCStringPointer(const char *str, size_t len) - : string(str), length(len), cstring(0) -{ -} - -asCStringPointer::asCStringPointer(asCString *cstr) - : string(0), length(0), cstring(cstr) -{ -} - -const char *asCStringPointer::AddressOf() const -{ - return string ? string : cstring->AddressOf(); -} - -size_t asCStringPointer::GetLength() const -{ - return string ? length : cstring->GetLength(); -} - -bool asCStringPointer::operator==(const asCStringPointer& other) const -{ - return asCompareStrings(AddressOf(), GetLength(), other.AddressOf(), other.GetLength()) == 0; -} - -bool asCStringPointer::operator<(const asCStringPointer& other) const -{ - return asCompareStrings(AddressOf(), GetLength(), other.AddressOf(), other.GetLength()) < 0; -} diff --git a/dependencies/angelscript/source/as_string.h b/dependencies/angelscript/source/as_string.h deleted file mode 100644 index 016e8714..00000000 --- a/dependencies/angelscript/source/as_string.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - -// This class has been designed to be easy to use, but not necessarily efficiency. -// It doesn't use shared string memory, or reference counting. It keeps track of -// string length, memory size. It also makes sure that the string is null-terminated. - -#ifndef AS_STRING_H -#define AS_STRING_H - -#include -#include - -class asCString -{ -public: - asCString(); - ~asCString(); - -#ifdef AS_CAN_USE_CPP11 - asCString(asCString &&); - asCString &operator =(asCString &&); -#endif // c++11 - - asCString(const asCString &); - asCString(const char *); - asCString(const char *, size_t length); - explicit asCString(char); - - void Allocate(size_t len, bool keepData); - void SetLength(size_t len); - size_t GetLength() const; - - void Concatenate(const char *str, size_t length); - asCString &operator +=(const asCString &); - asCString &operator +=(const char *); - asCString &operator +=(char); - - void Assign(const char *str, size_t length); - asCString &operator =(const asCString &); - asCString &operator =(const char *); - asCString &operator =(char); - - asCString SubString(size_t start, size_t length = (size_t)(-1)) const; - - int FindLast(const char *str, int *count = 0) const; - - size_t Format(const char *fmt, ...); - - int Compare(const char *str) const; - int Compare(const asCString &str) const; - int Compare(const char *str, size_t length) const; - - char *AddressOf(); - const char *AddressOf() const; - char &operator [](size_t index); - const char &operator[](size_t index) const; - size_t RecalculateLength(); - -protected: - unsigned int length; - union - { - char *dynamic; - char local[12]; - }; -}; - -// Helper functions - -bool operator ==(const asCString &, const asCString &); -bool operator !=(const asCString &, const asCString &); - -bool operator ==(const asCString &, const char *); -bool operator !=(const asCString &, const char *); - -bool operator ==(const char *, const asCString &); -bool operator !=(const char *, const asCString &); - -bool operator <(const asCString &, const asCString &); - -asCString operator +(const asCString &, const char *); -asCString operator +(const char *, const asCString &); -asCString operator +(const asCString &, const asCString &); - -// a wrapper for using the pointer of asCString in asCMap -class asCStringPointer -{ -public: - asCStringPointer(); - asCStringPointer(const char *str, size_t len); - asCStringPointer(asCString *cstr); - - const char *AddressOf() const; - size_t GetLength() const; - - bool operator==(const asCStringPointer& other) const; - bool operator<(const asCStringPointer& other) const; - -private: - // Either string/length or cstring is stored - const char *string; - size_t length; - asCString *cstring; -}; - -#endif diff --git a/dependencies/angelscript/source/as_string_util.cpp b/dependencies/angelscript/source/as_string_util.cpp deleted file mode 100644 index 4a01f21a..00000000 --- a/dependencies/angelscript/source/as_string_util.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com - -*/ - -#include "as_config.h" - -#include // some compilers declare memcpy() here -#include // pow() - -#if !defined(AS_NO_MEMORY_H) -#include -#endif - -#include "as_string.h" -#include "as_string_util.h" - -BEGIN_AS_NAMESPACE - -int asCompareStrings(const char *str1, size_t len1, const char *str2, size_t len2) -{ - if( len1 == 0 ) - { - if( str2 == 0 || len2 == 0 ) return 0; // Equal - - return 1; // The other string is larger than this - } - - if( str2 == 0 ) - { - if( len1 == 0 ) - return 0; // Equal - - return -1; // The other string is smaller than this - } - - if( len2 < len1 ) - { - int result = memcmp(str1, str2, len2); - if( result == 0 ) return -1; // The other string is smaller than this - - return result; - } - - int result = memcmp(str1, str2, len1); - if( result == 0 && len1 < len2 ) return 1; // The other string is larger than this - - return result; -} - -double asStringScanDouble(const char *string, size_t *numScanned) -{ - // I decided to do my own implementation of strtod() because this function - // doesn't seem to be present on all systems. iOS 5 for example doesn't appear - // to include the function in the standard lib. - - // Another reason is that the standard implementation of strtod() is dependent - // on the locale on some systems, i.e. it may use comma instead of dot for - // the decimal indicator. This can be avoided by forcing the locale to "C" with - // setlocale(), but this is another thing that is highly platform dependent. - - double value = 0; - double fraction = 0.1; - int exponent = 0; - bool negativeExponent = false; - int c = 0; - - // The tokenizer separates the sign from the number in - // two tokens so we'll never have a sign to parse here - - // Parse the integer value - for( ;; ) - { - if( string[c] >= '0' && string[c] <= '9' ) - value = value*10 + double(string[c] - '0'); - else - break; - - c++; - } - - if( string[c] == '.' ) - { - c++; - - // Parse the fraction - for( ;; ) - { - if( string[c] >= '0' && string[c] <= '9' ) - value += fraction * double(string[c] - '0'); - else - break; - - c++; - fraction *= 0.1; - } - } - - if( string[c] == 'e' || string[c] == 'E' ) - { - c++; - - // Parse the sign of the exponent - if( string[c] == '-' ) - { - negativeExponent = true; - c++; - } - else if( string[c] == '+' ) - c++; - - // Parse the exponent value - for( ;; ) - { - if( string[c] >= '0' && string[c] <= '9' ) - exponent = exponent*10 + int(string[c] - '0'); - else - break; - - c++; - } - } - - if( exponent ) - { - if( negativeExponent ) - exponent = -exponent; - value *= pow(10.0, exponent); - } - - if( numScanned ) - *numScanned = c; - - return value; -} - -// Converts a character to the decimal number based on the radix -// Returns -1 if the character is not valid for the radix -static int asCharToNbr(char ch, int radix) -{ - if( ch >= '0' && ch <= '9' ) return ((ch -= '0') < radix ? ch : -1); - if( ch >= 'A' && ch <= 'Z' ) return ((ch -= 'A'-10) < radix ? ch : -1); - if( ch >= 'a' && ch <= 'z' ) return ((ch -= 'a'-10) < radix ? ch : -1); - return -1; -} - -// If base is 0 the string should be prefixed by 0x, 0d, 0o, or 0b to allow the function to automatically determine the radix -asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned) -{ - asASSERT(base == 10 || base == 16 || base == 0); - - const char *end = string; - - asQWORD res = 0; - if( base == 10 ) - { - while( *end >= '0' && *end <= '9' ) - { - res *= 10; - res += *end++ - '0'; - } - } - else - { - if( base == 0 && string[0] == '0') - { - // Determine the radix from the prefix - switch( string[1] ) - { - case 'b': case 'B': base = 2; break; - case 'o': case 'O': base = 8; break; - case 'd': case 'D': base = 10; break; - case 'x': case 'X': base = 16; break; - } - end += 2; - } - - asASSERT( base ); - - if( base ) - { - for( int nbr; (nbr = asCharToNbr(*end, base)) >= 0; end++ ) - res = res * base + nbr; - } - } - - if( numScanned ) - *numScanned = end - string; - - return res; -} - -// -// The function will encode the unicode code point into the outEncodedBuffer, and then -// return the length of the encoded value. If the input value is not a valid unicode code -// point, then the function will return -1. -// -// This function is taken from the AngelCode ToolBox. -// -int asStringEncodeUTF8(unsigned int value, char *outEncodedBuffer) -{ - unsigned char *buf = (unsigned char*)outEncodedBuffer; - - int length = -1; - - if( value <= 0x7F ) - { - buf[0] = static_cast(value); - return 1; - } - else if( value >= 0x80 && value <= 0x7FF ) - { - // Encode it with 2 characters - buf[0] = static_cast(0xC0 + (value >> 6)); - length = 2; - } - else if( (value >= 0x800 && value <= 0xD7FF) || (value >= 0xE000 && value <= 0xFFFF) ) - { - // Note: Values 0xD800 to 0xDFFF are not valid unicode characters - buf[0] = static_cast(0xE0 + (value >> 12)); - length = 3; - } - else if( value >= 0x10000 && value <= 0x10FFFF ) - { - buf[0] = static_cast(0xF0 + (value >> 18)); - length = 4; - } - - int n = length-1; - for( ; n > 0; n-- ) - { - buf[n] = static_cast(0x80 + (value & 0x3F)); - value >>= 6; - } - - return length; -} - -// -// The function will decode an UTF8 character and return the unicode code point. -// outLength will receive the number of bytes that were decoded. -// -// This function is taken from the AngelCode ToolBox. -// -int asStringDecodeUTF8(const char *encodedBuffer, unsigned int *outLength) -{ - const unsigned char *buf = (const unsigned char*)encodedBuffer; - - int value = 0; - int length = -1; - unsigned char byte = buf[0]; - if( (byte & 0x80) == 0 ) - { - // This is the only byte - if( outLength ) *outLength = 1; - return byte; - } - else if( (byte & 0xE0) == 0xC0 ) - { - // There is one more byte - value = int(byte & 0x1F); - length = 2; - - // The value at this moment must not be less than 2, because - // that should have been encoded with one byte only. - if( value < 2 ) - length = -1; - } - else if( (byte & 0xF0) == 0xE0 ) - { - // There are two more bytes - value = int(byte & 0x0F); - length = 3; - } - else if( (byte & 0xF8) == 0xF0 ) - { - // There are three more bytes - value = int(byte & 0x07); - length = 4; - } - - int n = 1; - for( ; n < length; n++ ) - { - byte = buf[n]; - if( (byte & 0xC0) == 0x80 ) - value = (value << 6) + int(byte & 0x3F); - else - break; - } - - if( n == length ) - { - if( outLength ) *outLength = (unsigned)length; - return value; - } - - // The byte sequence isn't a valid UTF-8 byte sequence. - return -1; -} - -// -// The function will encode the unicode code point into the outEncodedBuffer, and then -// return the length of the encoded value. If the input value is not a valid unicode code -// point, then the function will return -1. -// -// This function is taken from the AngelCode ToolBox. -// -int asStringEncodeUTF16(unsigned int value, char *outEncodedBuffer) -{ - if( value < 0x10000 ) - { -#ifndef AS_BIG_ENDIAN - outEncodedBuffer[0] = (value & 0xFF); - outEncodedBuffer[1] = ((value >> 8) & 0xFF); -#else - outEncodedBuffer[1] = (value & 0xFF); - outEncodedBuffer[0] = ((value >> 8) & 0xFF); -#endif - return 2; - } - else - { - value -= 0x10000; - int surrogate1 = ((value >> 10) & 0x3FF) + 0xD800; - int surrogate2 = (value & 0x3FF) + 0xDC00; - -#ifndef AS_BIG_ENDIAN - outEncodedBuffer[0] = (surrogate1 & 0xFF); - outEncodedBuffer[1] = ((surrogate1 >> 8) & 0xFF); - outEncodedBuffer[2] = (surrogate2 & 0xFF); - outEncodedBuffer[3] = ((surrogate2 >> 8) & 0xFF); -#else - outEncodedBuffer[1] = (surrogate1 & 0xFF); - outEncodedBuffer[0] = ((surrogate1 >> 8) & 0xFF); - outEncodedBuffer[3] = (surrogate2 & 0xFF); - outEncodedBuffer[2] = ((surrogate2 >> 8) & 0xFF); -#endif - - return 4; - } -} - - -END_AS_NAMESPACE diff --git a/dependencies/angelscript/source/as_string_util.h b/dependencies/angelscript/source/as_string_util.h deleted file mode 100644 index 707c8754..00000000 --- a/dependencies/angelscript/source/as_string_util.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2011 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -#ifndef AS_STRING_UTIL_H -#define AS_STRING_UTIL_H - -#include "as_config.h" - -BEGIN_AS_NAMESPACE - -int asCompareStrings(const char *str1, size_t len1, const char *str2, size_t len2); - -double asStringScanDouble(const char *string, size_t *numScanned); -asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned); - -int asStringEncodeUTF8(unsigned int value, char *outEncodedBuffer); -int asStringDecodeUTF8(const char *encodedBuffer, unsigned int *outLength); - -int asStringEncodeUTF16(unsigned int value, char *outEncodedBuffer); - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_symboltable.h b/dependencies/angelscript/source/as_symboltable.h deleted file mode 100644 index 41d9339b..00000000 --- a/dependencies/angelscript/source/as_symboltable.h +++ /dev/null @@ -1,567 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2012-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_symboltable.h -// -// Created on: Jun 19, 2012 -// Author: Markus Lenger, a.k.a. mlengerx -// -// This class is used for fast symbol lookups while parsing or loading bytecode -// - -#ifndef AS_SYMBOLTABLE_H -#define AS_SYMBOLTABLE_H - -#include "as_config.h" -#include "as_memory.h" -#include "as_string.h" -#include "as_map.h" -#include "as_datatype.h" -#include "as_namespace.h" - - -BEGIN_AS_NAMESPACE - - - - - -// Interface to avoid nested templates which is not well supported by older compilers, e.g. MSVC6 -struct asIFilter -{ - virtual bool operator()(const void*) const = 0; - virtual ~asIFilter() {}; -}; - - - - -// forward declaration -template -class asCSymbolTable; - - - - -// Iterator that allows iterating in index order -template -class asCSymbolTableIterator -{ -public: - T2* operator*() const; - T2* operator->() const; - asCSymbolTableIterator& operator++(int); - asCSymbolTableIterator& operator--(int); - operator bool() const; - int GetIndex() const { return m_idx; } - -private: - friend class asCSymbolTable; - asCSymbolTableIterator(asCSymbolTable *table); - - void Next(); - void Previous(); - - asCSymbolTable* m_table; - unsigned int m_idx; -}; - - - - -// Symbol table mapping namespace + name to symbols -// The structure keeps the entries indexed in an array so the indices will not change -// There is also a map for a quick lookup. The map supports multiple entries with the same name -template -class asCSymbolTable -{ -public: - typedef asCSymbolTableIterator iterator; - typedef asCSymbolTableIterator const_iterator; - - asCSymbolTable(unsigned int initialCapacity = 0); - - int GetFirstIndex(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const; - int GetFirstIndex(const asSNameSpace *ns, const asCString &name) const; - int GetLastIndex() const; - - int GetIndex(const T*) const; - - T* GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const; - T* GetFirst(const asSNameSpace *ns, const asCString &name); - const T* GetFirst(const asSNameSpace *ns, const asCString &name) const; - T* Get(unsigned int index); - const T* Get(unsigned int index) const; - T* GetLast(); - const T* GetLast() const; - - const asCArray &GetIndexes(const asSNameSpace *ns, const asCString &name) const; - - int Put(T* entry); - - unsigned int GetSize() const; - - void SwapWith(asCSymbolTable &other); - - void Clear(); - bool Erase(unsigned int idx); - void Allocate(unsigned int elem_cnt, bool keep_data); - - iterator List(); - const_iterator List() const; - -private: - // Don't allow assignment - asCSymbolTable& operator=(const asCSymbolTable &other) { return *this; } - - friend class asCSymbolTableIterator; - friend class asCSymbolTableIterator; - - void GetKey(const T *entry, asSNameSpaceNamePair &key) const; - bool CheckIdx(unsigned idx) const; - - asCMap > m_map; - asCArray m_entries; - unsigned int m_size; -}; - - - - -template -void asCSymbolTable::SwapWith(asCSymbolTable &other) -{ - m_map.SwapWith(other.m_map); - m_entries.SwapWith(other.m_entries); - - unsigned int tmp = m_size; - m_size = other.m_size; - other.m_size = tmp; -} - - - - -// Constructor -// initialCapacity gives the number of entries to allocate in advance -template -asCSymbolTable::asCSymbolTable(unsigned initialCapacity) : m_entries(initialCapacity) -{ - m_size = 0; -} - - - -template -int asCSymbolTable::GetFirstIndex( - const asSNameSpace *ns, - const asCString &name, - const asIFilter &filter) const -{ - asSNameSpaceNamePair key(ns, name); - - asSMapNode > *cursor; - if( m_map.MoveTo(&cursor, key) ) - { - const asCArray &arr = m_map.GetValue(cursor); - for( unsigned int n = 0; n < arr.GetLength(); n++ ) - { - T *entry = m_entries[arr[n]]; - if( entry && filter(entry) ) - return arr[n]; - } - } - - return -1; -} - - - -template -const asCArray &asCSymbolTable::GetIndexes(const asSNameSpace *ns, const asCString &name) const -{ - asSNameSpaceNamePair key(ns, name); - - asSMapNode > *cursor; - if( m_map.MoveTo(&cursor, key) ) - return m_map.GetValue(cursor); - - static asCArray dummy; - return dummy; -} - - - - -template -T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comp) const -{ - int idx = GetFirstIndex(ns, name, comp); - if (idx != -1) return m_entries[idx]; - return 0; -} - - - - -template -int asCSymbolTable::GetFirstIndex(const asSNameSpace *ns, const asCString &name) const -{ - asSNameSpaceNamePair key(ns, name); - - asSMapNode > *cursor; - if( m_map.MoveTo(&cursor, key) ) - return m_map.GetValue(cursor)[0]; - - return -1; -} - - - - -// Find the index of a certain symbol -// ATTENTION: this function has linear runtime complexity O(n)!! -template -int asCSymbolTable::GetIndex(const T* entry) const -{ - for( unsigned int n = 0; n < m_entries.GetLength(); n++ ) - if( m_entries[n] == entry ) - return n; - - return -1; -} - - - - - - -template -T* asCSymbolTable::Get(unsigned idx) -{ - if( !CheckIdx(idx) ) - return 0; - - return m_entries[idx]; -} - -template -const T* asCSymbolTable::Get(unsigned idx) const -{ - return const_cast< asCSymbolTable* >(this)->Get(idx); -} - - - - - -template -T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &name) -{ - int idx = GetFirstIndex(ns, name); - return Get(idx); -} - -template -const T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &name) const -{ - return const_cast< asCSymbolTable* >(this)->GetFirst(ns, name); -} - - - - - -template -T* asCSymbolTable::GetLast() -{ - return Get(GetLastIndex()); -} - -template -const T* asCSymbolTable::GetLast() const -{ - return const_cast< asCSymbolTable* >(this)->GetLast(); -} - - - - - -// Clear the symbol table -// ATTENTION: The contained symbols are not rleased. This is up to the client -template -void asCSymbolTable::Clear() -{ - m_entries.SetLength(0); - m_map.EraseAll(); - m_size = 0; -} - - - - -// Pre-allocate slots for elemCnt entries -template -void asCSymbolTable::Allocate(unsigned elemCnt, bool keepData) -{ - asASSERT( elemCnt >= m_entries.GetLength() ); - m_entries.Allocate(elemCnt, keepData); - if( !keepData ) - m_map.EraseAll(); -} - - - -template -bool asCSymbolTable::Erase(unsigned idx) -{ - if( !CheckIdx(idx) ) - { - asASSERT(false); - return false; - } - - T *entry = m_entries[idx]; - asASSERT(entry); - if( !entry ) - return false; - - // Remove the symbol from the lookup map - asSNameSpaceNamePair key; - GetKey(entry, key); - - asSMapNode > *cursor; - if( m_map.MoveTo(&cursor, key) ) - { - asCArray &arr = m_map.GetValue(cursor); - arr.RemoveValue(idx); - if( arr.GetLength() == 0 ) - m_map.Erase(cursor); - } - else - asASSERT(false); - - // Remove the symbol from the indexed array - if( idx == m_entries.GetLength() - 1 ) - m_entries.PopLast(); - else - { - // Must keep the array packed - int prevIdx = int(m_entries.GetLength()-1); - m_entries[idx] = m_entries.PopLast(); - - // Update the index in the lookup map - entry = m_entries[idx]; - GetKey(entry, key); - if( m_map.MoveTo(&cursor, key) ) - { - asCArray &arr = m_map.GetValue(cursor); - arr[arr.IndexOf(prevIdx)] = idx; - } - else - asASSERT(false); - } - m_size--; - - return true; -} - - - - -template -int asCSymbolTable::Put(T *entry) -{ - unsigned int idx = (unsigned int)(m_entries.GetLength()); - asSNameSpaceNamePair key; - GetKey(entry, key); - - asSMapNode > *cursor; - if( m_map.MoveTo(&cursor, key) ) - m_map.GetValue(cursor).PushLast(idx); - else - { - asCArray arr(1); - arr.PushLast(idx); - m_map.Insert(key, arr); - } - - m_entries.PushLast(entry); - m_size++; - return idx; -} - - - - -// Return key for specified symbol (namespace and name are used to generate the key) -template -void asCSymbolTable::GetKey(const T *entry, asSNameSpaceNamePair &key) const -{ - key = asSNameSpaceNamePair(entry->nameSpace, entry->name); -} - - - - -template -unsigned int asCSymbolTable::GetSize() const -{ - return m_size; -} - - - - -template -bool asCSymbolTable::CheckIdx(unsigned int idx) const -{ - return idx < m_entries.GetLength(); -} - - - - -template -int asCSymbolTable::GetLastIndex() const -{ - unsigned int idx = (unsigned int)(m_entries.GetLength()) - 1; - asASSERT( idx == asUINT(-1) || m_entries[idx] ); - return int(idx); -} - - - - -template -asCSymbolTableIterator asCSymbolTable::List() -{ - return asCSymbolTableIterator(this); -} - - - - -template -typename asCSymbolTable::const_iterator asCSymbolTable::List() const -{ - return asCSymbolTableIterator(const_cast< asCSymbolTable *>(this)); -} - - -///////////////////////////////////////////////////////////////////////////////////////////////// -// Iterator - - -template -asCSymbolTableIterator::asCSymbolTableIterator(asCSymbolTable *table) : m_table(table), m_idx(0) -{ - unsigned int sz = (unsigned int)(m_table->m_entries.GetLength()); - while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) - m_idx++; -} - - - -template -T2* asCSymbolTableIterator::operator*() const -{ - asASSERT(m_table->CheckIdx(m_idx)); - return m_table->m_entries[m_idx]; -} - - - -template -T2* asCSymbolTableIterator::operator->() const -{ - asASSERT(m_table->CheckIdx(m_idx)); - return m_table->m_entries[m_idx]; -} - - - -template -asCSymbolTableIterator& asCSymbolTableIterator::operator++(int) -{ - Next(); - return *this; -} - - - -// Return true if more elements are following -// ATTENTION: When deleting the object currently pointed to by this iterator this -// method returns false even though there might be more elements in the list -template -asCSymbolTableIterator::operator bool() const -{ - return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0; -} - - - -template -void asCSymbolTableIterator::Next() -{ - unsigned int sz = (unsigned int)(m_table->m_entries.GetLength()); - m_idx++; - while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) - m_idx++; -} - - - -template -void asCSymbolTableIterator::Previous() -{ - // overflow on stepping over first element - unsigned int sz = (unsigned int)(m_table->m_entries.GetLength()); - m_idx--; - while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) - m_idx--; -} - - - -template -asCSymbolTableIterator& asCSymbolTableIterator::operator--(int) -{ - Previous(); - return *this; -} - - -END_AS_NAMESPACE - -#endif // AS_SYMBOLTABLE_H diff --git a/dependencies/angelscript/source/as_texts.h b/dependencies/angelscript/source/as_texts.h deleted file mode 100644 index 90e6bda7..00000000 --- a/dependencies/angelscript/source/as_texts.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_texts.h -// -// These are text strings used through out the library -// - - -#ifndef AS_TEXTS_H -#define AS_TEXTS_H - -// Compiler messages - -#define TXT_s_ALREADY_DECLARED "'%s' is already declared" -#define TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED "Abstract class '%s' cannot be instantiated" -#define TXT_ARG_NOT_LVALUE "Output argument expression is not assignable" -#define TXT_ATTR_s_INFORMED_MULTIPLE_TIMES "Attribute '%s' informed multiple times" - -#define TXT_BOTH_MUST_BE_SAME "Both expressions must have the same type" -#define TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR "Both conditions must call constructor" -#define TEXT_BASE_DOESNT_HAVE_DEF_CONSTR "Base class doesn't have default constructor. Make explicit call to base constructor" - -#define TXT_CANDIDATES_ARE "Candidates are:" -#define TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS "Can't call a constructor in loops" -#define TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH "Can't call a constructor in switch" -#define TXT_CANNOT_CALL_CONSTRUCTOR_TWICE "Can't call a constructor multiple times" -#define TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES "Can't create delegate for types that do not support handles" -#define TXT_CANNOT_IMPLEMENT_SELF "Can't implement itself, or another interface that implements this interface" -#define TXT_CANNOT_INHERIT_FROM_s_FINAL "Can't inherit from class '%s' marked as final" -#define TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES "Can't inherit from multiple classes" -#define TXT_CANNOT_INHERIT_FROM_SELF "Can't inherit from itself, or another class that inherits from this class" -#define TXT_CANNOT_INSTANTIATE_TEMPLATE_s_WITH_s "Can't instantiate template '%s' with subtype '%s'" -#define TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG "Can't pass class method as arg directly. Use a delegate object instead" -#define TXT_CANNOT_RETURN_REF_TO_LOCAL "Can't return reference to local value." -#define TXT_CANT_CONSTRUCT_s_USE_REF_CAST "Can't construct handle '%s'. Use ref cast instead" -#define TXT_CANT_IMPLICITLY_CONVERT_s_TO_s "Can't implicitly convert from '%s' to '%s'." -#define TXT_CANT_RETURN_VALUE "Can't return value when return type is 'void'" -#define TXT_CHANGE_SIGN "Implicit conversion changed sign of value" -#define TXT_CLASS_CANT_BE_FINAL_AND_ABSTRACT "A class cannot be both abstract and final" -#define TXT_COMPILING_s "Compiling %s" -#define TXT_COMPOUND_ASGN_WITH_PROP "Compound assignments with property accessors are not allowed" -#define TXT_CONSTRUCTOR_NAME_ERROR "The name of constructors and destructors must be the same as the class" - -#define TXT_DATA_TYPE_CANT_BE_s "Data type can't be '%s'" -#define TXT_CANNOT_RESOLVE_AUTO "Unable to resolve auto type" -#define TXT_AUTO_NOT_ALLOWED "Auto is not allowed here" -#define TXT_DECL_IN_SWITCH "Variables cannot be declared in switch cases, except inside statement blocks" -#define TXT_DEFAULT_MUST_BE_LAST "The default case must be the last one" -#define TXT_DEF_ARG_MISSING_IN_FUNC_s "All subsequent parameters after the first default value must have default values in function '%s'" -#define TXT_DEF_ARG_TYPE_DOESNT_MATCH "The type of the default argument expression doesn't match the function parameter type" -#define TXT_POS_ARG_AFTER_NAMED_ARG "Positional arguments cannot be passed after named arguments" -#define TXT_DUPLICATE_NAMED_ARG "Duplicate named argument" -#define TXT_DERIVED_METHOD_MUST_HAVE_SAME_RETTYPE_s "The method in the derived class must have the same return type as in the base class: '%s'" -#define TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM "The destructor must not have any parameters" -#define TXT_DISALLOW_ASSIGN_ON_REF_TYPE "Value assignment on reference types is not allowed. Did you mean to do a handle assignment?" -#define TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE "Compound assignment on reference types is not allowed" -#define TXT_DUPLICATE_SWITCH_CASE "Duplicate switch case" - -#define TXT_ELSE_WITH_EMPTY_STATEMENT "Else with empty statement" -#define TXT_EMPTY_SWITCH "Empty switch statement" -#define TXT_EXPECTED_s "Expected '%s'" -#define TXT_EXPECTED_CONSTANT "Expected constant" -#define TXT_EXPECTED_DATA_TYPE "Expected data type" -#define TXT_EXPECTED_EXPRESSION_VALUE "Expected expression value" -#define TXT_EXPECTED_IDENTIFIER "Expected identifier" -#define TXT_EXPECTED_LIST "Expected a list enclosed by { } to match pattern" -#define TXT_EXPECTED_METHOD_OR_PROPERTY "Expected method or property" -#define TXT_EXPECTED_ONE_OF "Expected one of: " -#define TXT_EXPECTED_OPERATOR "Expected operator" -#define TXT_EXPECTED_s_OR_s "Expected '%s' or '%s'" -#define TXT_EXPECTED_POST_OPERATOR "Expected post operator" -#define TXT_EXPECTED_PRE_OPERATOR "Expected pre operator" -#define TXT_EXPECTED_STRING "Expected string" -#define TXT_EXPR_DOESNT_EVAL_TO_FUNC "Expression doesn't evaluate to a function" -#define TXT_EXPR_MUST_BE_BOOL "Expression must be of boolean type" - -#define TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s "Failed while compiling default arg for parameter %d in function '%s'" -#define TXT_FAILED_TO_CREATE_TEMP_OBJ "Previous error occurred while attempting to create a temporary copy of object" -#define TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC "Float value truncated in implicit conversion to integer" -#define TXT_FOUND_MULTIPLE_ENUM_VALUES "Found multiple matching enum values" -#define TXT_FUNCTION_ALREADY_EXIST "A function with the same name and parameters already exists" -#define TXT_FUNCTION_s_NOT_FOUND "Function '%s' not found" - -#define TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s "The property '%s' has mismatching types for the get and set accessors" -#define TXT_GLOBAL_VARS_NOT_ALLOWED "Global variables have been disabled by the application" - -#define TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP "It is not allowed to perform a handle assignment on a non-handle property" -#define TXT_HANDLE_COMPARISON "The operand is implicitly converted to handle in order to compare them" -#define TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED "Handle to handle is not allowed" -#define TXT_s_HIDES_VAR_IN_OUTER_SCOPE "Variable '%s' hides another variable of same name in outer scope" - -#define TXT_IDENTIFIER_s_NOT_DATA_TYPE "Identifier '%s' is not a data type" -#define TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS "Identifier '%s' is not a data type in global namespace" -#define TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s "Identifier '%s' is not a data type in namespace '%s' or parent" -#define TXT_IF_WITH_EMPTY_STATEMENT "If with empty statement" -#define TXT_ILLEGAL_MEMBER_TYPE "Illegal member type" -// TODO: Should be TXT_ILLEGAL_OPERATION_ON_s -#define TXT_ILLEGAL_OPERATION "Illegal operation on this datatype" -#define TXT_ILLEGAL_OPERATION_ON_s "Illegal operation on '%s'" -#define TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST "Illegal target type for reference cast" -#define TXT_ILLEGAL_VARIABLE_NAME_s "Illegal variable name '%s'." -#define TXT_INIT_LIST_CANNOT_BE_USED_WITH_s "Initialization lists cannot be used with '%s'" -#define TXT_INSTEAD_FOUND_s "Instead found '%s'" -#define TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED "Interface '%s' cannot be instantiated" -#define TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE "Interfaces can only implement other interfaces" -#define TXT_INVALID_BREAK "Invalid 'break'" -#define TXT_INVALID_CHAR_LITERAL "Invalid character literal" -#define TXT_INVALID_CONTINUE "Invalid 'continue'" -#define TXT_INVALID_ESCAPE_SEQUENCE "Invalid escape sequence" -#define TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME "Invalid expression: ambiguous name" -#define TXT_INVALID_OP_ON_METHOD "Invalid operation on method" -#define TXT_INVALID_REF_PROP_ACCESS "Invalid reference. Property accessors cannot be used in combined read/write operations" -#define TXT_INVALID_SCOPE "Invalid scope resolution" -#define TXT_INVALID_TYPE "Invalid type" -#define TXT_INVALID_UNICODE_FORMAT_EXPECTED_d "Invalid unicode escape sequence, expected %d hex digits" -#define TXT_INVALID_UNICODE_VALUE "Invalid unicode code point" -#define TXT_INVALID_UNICODE_SEQUENCE_IN_SRC "Invalid unicode sequence in source" - -#define TXT_METHOD_CANNOT_OVERRIDE_s "Method '%s' declared as final and cannot be overridden" -#define TXT_METHOD_CANT_HAVE_NAME_OF_CLASS "The method cannot be named with the class name" -#define TXT_METHOD_s_DOES_NOT_OVERRIDE "Method '%s' marked as override but does not replace any base class or interface method" -#define TXT_MISSING_IMPLEMENTATION_OF_s "Missing implementation of '%s'" -#define TXT_MIXIN_CANNOT_BE_DECLARED_AS_s "Mixin class cannot be declared as '%s'" -#define TXT_MIXIN_CANNOT_HAVE_CONSTRUCTOR "Mixin classes cannot have constructors or destructors" -#define TXT_MIXIN_CLASS_CANNOT_INHERIT "Mixin class cannot inherit from classes" -#define TXT_MORE_THAN_ONE_MATCHING_OP "Found more than one matching operator" -#define TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s "Multiple matching signatures to '%s'" -#define TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s "Found multiple get accessors for property '%s'" -#define TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s "Found multiple set accessors for property '%s'" -#define TXT_MULTILINE_STRINGS_NOT_ALLOWED "Multiline strings are not allowed in this application" -#define TXT_MUST_BE_OBJECT "Only objects have constructors" -#define TXT_MUST_RETURN_VALUE "Must return a value" - -#define TXT_NAMESPACE_s_DOESNT_EXIST "Namespace '%s' doesn't exist." -#define TXT_NAME_CONFLICT_s_EXTENDED_TYPE "Name conflict. '%s' is an extended data type." -#define TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY "Name conflict. '%s' is a global property." -#define TXT_NAME_CONFLICT_s_IS_NAMED_TYPE "Name conflict. '%s' is a named type." -#define TXT_NAME_CONFLICT_s_IS_FUNCDEF "Name conflict. '%s' is a funcdef." -#define TXT_NAME_CONFLICT_s_IS_MIXIN "Name conflict. '%s' is a mixin class." -#define TXT_NAME_CONFLICT_s_STRUCT "Name conflict. '%s' is a class." -#define TXT_NAME_CONFLICT_s_OBJ_PROPERTY "Name conflict. '%s' is an object property." -#define TXT_NAME_CONFLICT_s_METHOD "Name conflict. '%s' is a class method." -#define TXT_NAME_CONFLICT_s_ALREADY_USED "Name conflict. '%s' is already used." -#define TXT_NAMED_ARGS_WITH_OLD_SYNTAX "Detected named argument with old syntax" -#define TXT_NO_APPROPRIATE_INDEX_OPERATOR "No appropriate indexing operator found" -#define TXT_NO_APPROPRIATE_OPHNDLASSIGN_s "No appropriate opHndlAssign method found in '%s' for handle assignment" -#define TXT_NO_APPROPRIATE_OPEQUALS "No appropriate opEquals method found" -#define TXT_NO_CONVERSION_s_TO_s "No conversion from '%s' to '%s' available." -#define TXT_NO_CONVERSION_s_TO_MATH_TYPE "No conversion from '%s' to math type available." -#define TXT_NO_DEFAULT_ARRAY_TYPE "The application doesn't support the default array type." -#define TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s "No default constructor for object of type '%s'." -#define TXT_NO_DEFAULT_COPY_OP_FOR_s "No appropriate opAssign method found in '%s' for value assignment" -#define TXT_NO_COPY_CONSTRUCTOR_FOR_s "No copy constructor for object of type '%s'." -#define TXT_NO_MATCHING_SIGNATURES_TO_s "No matching signatures to '%s'" -#define TXT_NO_MATCHING_OP_FOUND_FOR_TYPE_s "No matching operator that takes the type '%s' found" -#define TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s "No matching operator that takes the types '%s' and '%s' found" -#define TXT_NON_CONST_METHOD_ON_CONST_OBJ "Non-const method call on read-only object reference" -#define TXT_NONTERMINATED_STRING "Non-terminated string literal" -#define TXT_NOT_A_FUNC_s_IS_VAR "Expression doesn't form a function call. '%s' is a variable of a non-function type" -#define TXT_NOT_ALL_PATHS_RETURN "Not all paths return a value" -#define TXT_NOT_ENOUGH_VALUES_FOR_LIST "Not enough values to match pattern" -#define TXT_s_NOT_DECLARED "'%s' is not declared" -#define TXT_NOT_EXACT "Implicit conversion of value is not exact" -#define TXT_s_NOT_INITIALIZED "'%s' is not initialized." -#define TXT_NOT_LVALUE "Expression is not an l-value" -#define TXT_s_NOT_MEMBER_OF_s "'%s' is not a member of '%s'" -#define TXT_NOT_VALID_REFERENCE "Not a valid reference" -#define TXT_NOT_VALID_LVALUE "Not a valid lvalue" -#define TXT_NOTHING_WAS_BUILT "Nothing was built in the module" - -#define TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP "Type '%s' doesn't support the indexing operator" -#define TXT_OBJECT_HANDLE_NOT_SUPPORTED "Object handle is not supported for this type" -#define TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT "Only object types that support object handles can use &inout. Use &in or &out instead" -#define TXT_ONLY_ONE_ARGUMENT_IN_CAST "A cast operator has one argument" -#define TXT_ONLY_ONE_FUNCTION_ALLOWED "The code must contain one and only one function" -#define TXT_ONLY_ONE_VARIABLE_ALLOWED "The code must contain one and only one global variable" -#define TXT_OPERANDS_MUST_BE_HANDLES "Both operands must be handles when comparing identity" -#define TXT_OVERLOAD_CONFLICTS_DUE_TO_DEFAULT_ARGS "The overloaded functions are identical on initial parameters without default arguments" - -#define TXT_PARAMETER_ALREADY_DECLARED "Parameter already declared" -#define TXT_PARAMETER_CANT_BE_s "Parameter type can't be '%s', because the type cannot be instantiated." -#define TXT_PRIVATE_METHOD_CALL_s "Illegal call to private method '%s'" -#define TXT_PRIVATE_PROP_ACCESS_s "Illegal access to private property '%s'" -#define TXT_PROPERTY_ACCESSOR_DISABLED "Property accessors have been disabled by the application" -#define TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED "Property accessor must be implemented" -#define TXT_PROPERTY_CANT_BE_CONST "Class properties cannot be declared as const" -#define TXT_PROPERTY_HAS_NO_GET_ACCESSOR "The property has no get accessor" -#define TXT_PROPERTY_HAS_NO_SET_ACCESSOR "The property has no set accessor" -#define TXT_PROPERTY_WITHOUT_ACCESSOR "Virtual property must have at least one get or set accessor" - -#define TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM "Resulting reference cannot be returned. There are deferred arguments that may invalidate it." -#define TXT_REF_CANT_BE_RETURNED_LOCAL_VARS "Resulting reference cannot be returned. The expression uses objects that during cleanup may invalidate it." -#define TXT_REF_IS_READ_ONLY "Reference is read-only" -#define TXT_REF_IS_TEMP "Reference is temporary" -#define TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL "Reference types cannot be passed by value in function parameters" -#define TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL "Reference types cannot be returned by value from functions" -#define TXT_RETURN_CANT_BE_s "Return type can't be '%s'" - -#define TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s "Shared code cannot access non-shared global variable '%s'" -#define TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s "Shared code cannot call non-shared function '%s'" -#define TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s "Shared type cannot implement non-shared interface '%s'" -#define TXT_SHARED_CANNOT_INHERIT_FROM_NON_SHARED_s "Shared class cannot inherit from non-shared class '%s'" -#define TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s "Shared code cannot use non-shared type '%s'" -#define TXT_SHARED_s_DOESNT_MATCH_ORIGINAL "Shared type '%s' doesn't match the original declaration in other module" -#define TXT_SECTION_IS_EMPTY "The script section is empty" -#define TXT_SIGNED_UNSIGNED_MISMATCH "Signed/Unsigned mismatch" -#define TXT_STRINGS_NOT_RECOGNIZED "Strings are not recognized by the application" -#define TXT_SWITCH_CASE_MUST_BE_CONSTANT "Case expressions must be constants" -#define TXT_SWITCH_MUST_BE_INTEGRAL "Switch expressions must be integral numbers" - -#define TXT_TMPL_s_EXPECTS_d_SUBTYPES "Template '%s' expects %d sub type(s)" -#define TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY "Template subtype must not be read-only" -#define TXT_TOO_MANY_JUMP_LABELS "The function has too many jump labels to handle. Split the function into smaller ones." -#define TXT_TOO_MANY_VALUES_FOR_LIST "Too many values to match pattern" -#define TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE "Type '%s' is not available for this module" - -#define TXT_UNEXPECTED_END_OF_FILE "Unexpected end of file" -#define TXT_UNEXPECTED_TOKEN_s "Unexpected token '%s'" -#define TXT_UNEXPECTED_VAR_DECL "Unexpected variable declaration" -#define TXT_UNINITIALIZED_GLOBAL_VAR_s "Use of uninitialized global variable '%s'." -#define TXT_UNKNOWN_SCOPE_s "Unknown scope '%s'" -#define TXT_UNREACHABLE_CODE "Unreachable code" -#define TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE "Virtual property contains unrecognized aspect" -#define TXT_UNUSED_SCRIPT_NODE "Unused script node" - -#define TXT_VALUE_TOO_LARGE_FOR_TYPE "Value is too large for data type" -#define TXT_VOID_CANT_BE_OPERAND "Void cannot be an operand in expressions" - -#define TXT_WARNINGS_TREATED_AS_ERROR "Warnings are treated as errors by the application" -#define TXT_WHILE_PARSING_ARG_LIST "While parsing argument list" -#define TXT_WHILE_PARSING_EXPRESSION "While parsing expression" -#define TXT_WHILE_PARSING_INIT_LIST "While parsing initialization list" -#define TXT_WHILE_PARSING_NAMESPACE "While parsing namespace" -#define TXT_WHILE_PARSING_STATEMENT_BLOCK "While parsing statement block" -#define TXT_WHILE_INCLUDING_MIXIN "Previous error occurred while including mixin" - -// Global variable initialization - -#define TXT_FAILED_TO_INITIALIZE_s "Failed to initialize global variable '%s'" -#define TXT_EXCEPTION_s_IN_s "Exception '%s' in '%s'" - -// Engine message - -#define TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT "Autohandles cannot be used with types that have been registered with NOCOUNT" -#define TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY "First parameter to template factory must be a reference. This will be used to pass the object type of the template" -#define TXT_INVALID_CONFIGURATION "Invalid configuration. Verify the registered application interface." -#define TXT_VALUE_TYPE_MUST_HAVE_SIZE "A value type must be registered with a non-zero size" -#define TXT_TYPE_s_IS_MISSING_BEHAVIOURS "Type '%s' is missing behaviours" -#define TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE "The behaviour is not compatible with the type" -#define TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR "A garbage collected type must have the addref, release, and all gc behaviours" -#define TXT_SCOPE_REQUIRE_REL_BEHAVIOUR "A scoped reference type must have the release behaviour" -#define TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR "A reference type must have the addref and release behaviours" -#define TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR "A non-pod value type must have the default constructor and destructor behaviours" -#define TXT_CANNOT_PASS_TYPE_s_BY_VAL "Can't pass type '%s' by value unless the application type is informed in the registration" -#define TXT_CANNOT_RET_TYPE_s_BY_VAL "Can't return type '%s' by value unless the application type is informed in the registration" -// TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to pass by value to application in native calling convention" -#define TXT_DONT_SUPPORT_TYPE_s_BY_VAL "Don't support passing type '%s' by value to application in native calling convention on this platform" -// TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to return by value from application in native calling convention" -#define TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL "Don't support returning type '%s' by value from application in native calling convention on this platform" -#define TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s "Object {%d}. GC cannot destroy an object of type '%s' as it doesn't know how many references to there are." -#define TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s_REF_COUNT_d "Object {%d}. GC cannot destroy an object of type '%s' as it can't see all references. Current ref count is %d." -#define TXT_OBJECT_TYPE_s_DOESNT_EXIST "Object type '%s' doesn't exist" -#define TXT_TEMPLATE_TYPE_s_DOESNT_EXIST "Template type '%s' doesn't exist" -#define TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST "Template subtype '%s' doesn't exist" -#define TXT_TEMPLATE_LIST_FACTORY_EXPECTS_2_REF_PARAMS "Template list factory expects two reference parameters. The last is the pointer to the initialization buffer" -#define TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM "List factory expects only one reference parameter. The pointer to the initialization buffer will be passed in this parameter" -#define TXT_FAILED_READ_SUBTYPE_OF_TEMPLATE_s "Failed to read subtype of template type '%s'" -#define TXT_INSTANCING_INVLD_TMPL_TYPE_s_s "Attempting to instantiate invalid template type '%s<%s>'" -#define TXT_FAILED_IN_FUNC_s_d "Failed in call to function '%s' (Code: %d)" -#define TXT_FAILED_IN_FUNC_s_WITH_s_d "Failed in call to function '%s' with '%s' (Code: %d)" -#define TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_d "Failed in call to function '%s' with '%s' and '%s' (Code: %d)" -#define TXT_GC_RECEIVED_NULL_PTR "AddScriptObjectToGC called with null pointer" -#define TXT_EXCEPTION_IN_NESTED_CALL "An exception occurred in a nested call" -#define TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s "Type '%s' is still used by function '%s'" -#define TXT_PREV_TYPE_IS_NAMED_s "The builtin type in previous message is named '%s'" -#define TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d "The function in previous message is named '%s'. The func type is %d" -#define TXT_RESURRECTING_SCRIPTOBJECT_s "The script object of type '%s' is being resurrected illegally during destruction" -#define TXT_INVALID_BYTECODE_d "LoadByteCode failed. The bytecode is invalid. Number of bytes read from stream: %d" -#define TXT_NO_JIT_IN_FUNC_s "Function '%s' appears to have been compiled without JIT entry points" -#define TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN "Uh oh! The engine's reference count is increasing while it is being destroyed. Make sure references needed for clean-up are immediately released" - -// Internal names - -#define TXT_PROPERTY "Property" -#define TXT_SYSTEM_FUNCTION "System function" -#define TXT_VARIABLE_DECL "Variable declaration" - -// Exceptions - -#define TXT_STACK_OVERFLOW "Stack overflow" -#define TXT_NULL_POINTER_ACCESS "Null pointer access" -#define TXT_DIVIDE_BY_ZERO "Divide by zero" -#define TXT_DIVIDE_OVERFLOW "Overflow in integer division" -#define TXT_POW_OVERFLOW "Overflow in exponent operation" -#define TXT_UNRECOGNIZED_BYTE_CODE "Unrecognized byte code" -#define TXT_INVALID_CALLING_CONVENTION "Invalid calling convention" -#define TXT_UNBOUND_FUNCTION "Unbound function called" -#define TXT_OUT_OF_BOUNDS "Out of range" -#define TXT_EXCEPTION_CAUGHT "Caught an exception from the application" -#define TXT_MISMATCH_IN_VALUE_ASSIGN "Mismatching types in value assignment" - -#endif diff --git a/dependencies/angelscript/source/as_thread.cpp b/dependencies/angelscript/source/as_thread.cpp deleted file mode 100644 index 5f487d4c..00000000 --- a/dependencies/angelscript/source/as_thread.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - -// -// as_thread.cpp -// -// Functions for multi threading support -// - -#include "as_config.h" -#include "as_thread.h" -#include "as_atomic.h" - -BEGIN_AS_NAMESPACE - -//======================================================================= - -// Singleton -static asCThreadManager *threadManager = 0; - -//====================================================================== - -// Global API functions -extern "C" -{ - -AS_API int asThreadCleanup() -{ - return asCThreadManager::CleanupLocalData(); -} - -AS_API asIThreadManager *asGetThreadManager() -{ - return threadManager; -} - -AS_API int asPrepareMultithread(asIThreadManager *externalThreadMgr) -{ - return asCThreadManager::Prepare(externalThreadMgr); -} - -AS_API void asUnprepareMultithread() -{ - asCThreadManager::Unprepare(); -} - -AS_API void asAcquireExclusiveLock() -{ - if( threadManager ) - { - ACQUIREEXCLUSIVE(threadManager->appRWLock); - } -} - -AS_API void asReleaseExclusiveLock() -{ - if( threadManager ) - { - RELEASEEXCLUSIVE(threadManager->appRWLock); - } -} - -AS_API void asAcquireSharedLock() -{ - if( threadManager ) - { - ACQUIRESHARED(threadManager->appRWLock); - } -} - -AS_API void asReleaseSharedLock() -{ - if( threadManager ) - { - RELEASESHARED(threadManager->appRWLock); - } -} - -} - -//====================================================================== - -#if !defined(AS_NO_THREADS) && defined(_MSC_VER) && defined(AS_WINDOWS_THREADS) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) -__declspec(thread) asCThreadLocalData *asCThreadManager::tld = 0; -#endif - -asCThreadManager::asCThreadManager() -{ - // We're already in the critical section when this function is called - -#ifdef AS_NO_THREADS - tld = 0; -#else - // Allocate the thread local storage - #if defined AS_POSIX_THREADS - pthread_key_t pKey; - pthread_key_create(&pKey, 0); - tlsKey = (asDWORD)pKey; - #elif defined AS_WINDOWS_THREADS - #if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) - tld = 0; - #else - tlsKey = (asDWORD)TlsAlloc(); - #endif - #endif -#endif - refCount = 1; -} - -int asCThreadManager::Prepare(asIThreadManager *externalThreadMgr) -{ - // Don't allow an external thread manager if there - // is already a thread manager defined - if( externalThreadMgr && threadManager ) - return asINVALID_ARG; - - // The critical section cannot be declared globally, as there is no - // guarantee for the order in which global variables are initialized - // or uninitialized. - - // For this reason it's not possible to prevent two threads from calling - // AddRef at the same time, so there is a chance for a race condition here. - - // To avoid the race condition when the thread manager is first created, - // the application must make sure to call the global asPrepareForMultiThread() - // in the main thread before any other thread creates a script engine. - if( threadManager == 0 && externalThreadMgr == 0 ) - threadManager = asNEW(asCThreadManager); - else - { - // If an application uses different dlls each dll will get it's own memory - // space for global variables. If multiple dlls then uses AngelScript's - // global thread support functions it is then best to share the thread - // manager to make sure all dlls use the same critical section. - if( externalThreadMgr ) - threadManager = reinterpret_cast(externalThreadMgr); - - ENTERCRITICALSECTION(threadManager->criticalSection); - threadManager->refCount++; - LEAVECRITICALSECTION(threadManager->criticalSection); - } - - // Success - return 0; -} - -void asCThreadManager::Unprepare() -{ - asASSERT(threadManager); - - if( threadManager == 0 ) - return; - - // It's necessary to protect this section so no - // other thread attempts to call AddRef or Release - // while clean up is in progress. - ENTERCRITICALSECTION(threadManager->criticalSection); - if( --threadManager->refCount == 0 ) - { - // Make sure the local data is destroyed, at least for the current thread - CleanupLocalData(); - - // As the critical section will be destroyed together - // with the thread manager we must first clear the global - // variable in case a new thread manager needs to be created; - asCThreadManager *mgr = threadManager; - threadManager = 0; - - // Leave the critical section before it is destroyed - LEAVECRITICALSECTION(mgr->criticalSection); - - asDELETE(mgr,asCThreadManager); - } - else - LEAVECRITICALSECTION(threadManager->criticalSection); -} - -asCThreadManager::~asCThreadManager() -{ -#ifndef AS_NO_THREADS - // Deallocate the thread local storage - #if defined AS_POSIX_THREADS - pthread_key_delete((pthread_key_t)tlsKey); - #elif defined AS_WINDOWS_THREADS - #if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) - tld = 0; - #else - TlsFree((DWORD)tlsKey); - #endif - #endif -#else - if( tld ) - { - asDELETE(tld,asCThreadLocalData); - } - tld = 0; -#endif -} - -int asCThreadManager::CleanupLocalData() -{ - if( threadManager == 0 ) - return 0; - -#ifndef AS_NO_THREADS -#if defined AS_POSIX_THREADS - asCThreadLocalData *tld = (asCThreadLocalData*)pthread_getspecific((pthread_key_t)threadManager->tlsKey); -#elif defined AS_WINDOWS_THREADS - #if !defined(_MSC_VER) || !(WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) - asCThreadLocalData *tld = (asCThreadLocalData*)TlsGetValue((DWORD)threadManager->tlsKey); - #endif -#endif - - if( tld == 0 ) - return 0; - - if( tld->activeContexts.GetLength() == 0 ) - { - asDELETE(tld,asCThreadLocalData); - #if defined AS_POSIX_THREADS - pthread_setspecific((pthread_key_t)threadManager->tlsKey, 0); - #elif defined AS_WINDOWS_THREADS - #if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) - tld = 0; - #else - TlsSetValue((DWORD)threadManager->tlsKey, 0); - #endif - #endif - return 0; - } - else - return asCONTEXT_ACTIVE; - -#else - if( threadManager->tld ) - { - if( threadManager->tld->activeContexts.GetLength() == 0 ) - { - asDELETE(threadManager->tld,asCThreadLocalData); - threadManager->tld = 0; - } - else - return asCONTEXT_ACTIVE; - } - return 0; -#endif -} - -asCThreadLocalData *asCThreadManager::GetLocalData() -{ - if( threadManager == 0 ) - return 0; - -#ifndef AS_NO_THREADS -#if defined AS_POSIX_THREADS - asCThreadLocalData *tld = (asCThreadLocalData*)pthread_getspecific((pthread_key_t)threadManager->tlsKey); - if( tld == 0 ) - { - tld = asNEW(asCThreadLocalData)(); - pthread_setspecific((pthread_key_t)threadManager->tlsKey, tld); - } -#elif defined AS_WINDOWS_THREADS - #if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) - if( tld == 0 ) - tld = asNEW(asCThreadLocalData)(); - #else - asCThreadLocalData *tld = (asCThreadLocalData*)TlsGetValue((DWORD)threadManager->tlsKey); - if( tld == 0 ) - { - tld = asNEW(asCThreadLocalData)(); - TlsSetValue((DWORD)threadManager->tlsKey, tld); - } - #endif -#endif - - return tld; -#else - if( threadManager->tld == 0 ) - threadManager->tld = asNEW(asCThreadLocalData)(); - - return threadManager->tld; -#endif -} - -//========================================================================= - -asCThreadLocalData::asCThreadLocalData() -{ -} - -asCThreadLocalData::~asCThreadLocalData() -{ -} - -//========================================================================= - -#ifndef AS_NO_THREADS -asCThreadCriticalSection::asCThreadCriticalSection() -{ -#if defined AS_POSIX_THREADS - pthread_mutex_init(&cs, 0); -#elif defined AS_WINDOWS_THREADS -#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) - // Only the Ex version is available on Windows Store - InitializeCriticalSectionEx(&cs, 4000, 0); -#else - // Only the non-Ex version is available on WinXP and older - // MinGW also only defines this version - InitializeCriticalSection(&cs); -#endif -#endif -} - -asCThreadCriticalSection::~asCThreadCriticalSection() -{ -#if defined AS_POSIX_THREADS - pthread_mutex_destroy(&cs); -#elif defined AS_WINDOWS_THREADS - DeleteCriticalSection(&cs); -#endif -} - -void asCThreadCriticalSection::Enter() -{ -#if defined AS_POSIX_THREADS - pthread_mutex_lock(&cs); -#elif defined AS_WINDOWS_THREADS - EnterCriticalSection(&cs); -#endif -} - -void asCThreadCriticalSection::Leave() -{ -#if defined AS_POSIX_THREADS - pthread_mutex_unlock(&cs); -#elif defined AS_WINDOWS_THREADS - LeaveCriticalSection(&cs); -#endif -} - -bool asCThreadCriticalSection::TryEnter() -{ -#if defined AS_POSIX_THREADS - return !pthread_mutex_trylock(&cs); -#elif defined AS_WINDOWS_THREADS - return TryEnterCriticalSection(&cs) ? true : false; -#else - return true; -#endif -} - -asCThreadReadWriteLock::asCThreadReadWriteLock() -{ -#if defined AS_POSIX_THREADS - int r = pthread_rwlock_init(&lock, 0); - asASSERT( r == 0 ); - UNUSED_VAR(r); -#elif defined AS_WINDOWS_THREADS -#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) - // Only the Ex versions are available on Windows Store - - // Create a semaphore to allow up to maxReaders simultaneous readers - readLocks = CreateSemaphoreExW(NULL, maxReaders, maxReaders, 0, 0, 0); - // Create a critical section to synchronize writers - InitializeCriticalSectionEx(&writeLock, 4000, 0); -#else - readLocks = CreateSemaphoreW(NULL, maxReaders, maxReaders, 0); - InitializeCriticalSection(&writeLock); -#endif -#endif -} - -asCThreadReadWriteLock::~asCThreadReadWriteLock() -{ -#if defined AS_POSIX_THREADS - pthread_rwlock_destroy(&lock); -#elif defined AS_WINDOWS_THREADS - DeleteCriticalSection(&writeLock); - CloseHandle(readLocks); -#endif -} - -void asCThreadReadWriteLock::AcquireExclusive() -{ -#if defined AS_POSIX_THREADS - pthread_rwlock_wrlock(&lock); -#elif defined AS_WINDOWS_THREADS - // Synchronize writers, so only one tries to lock out the readers - EnterCriticalSection(&writeLock); - - // Lock all reader out from the semaphore. Do this one by one, - // so the lock doesn't have to wait until there are no readers at all. - // If we try to lock all at once it is quite possible the writer will - // never succeed. - for( asUINT n = 0; n < maxReaders; n++ ) - WaitForSingleObjectEx(readLocks, INFINITE, FALSE); - - // Allow another writer to lock. It will only be able to - // lock the readers when this writer releases them anyway. - LeaveCriticalSection(&writeLock); -#endif -} - -void asCThreadReadWriteLock::ReleaseExclusive() -{ -#if defined AS_POSIX_THREADS - pthread_rwlock_unlock(&lock); -#elif defined AS_WINDOWS_THREADS - // Release all readers at once - ReleaseSemaphore(readLocks, maxReaders, 0); -#endif -} - -void asCThreadReadWriteLock::AcquireShared() -{ -#if defined AS_POSIX_THREADS - pthread_rwlock_rdlock(&lock); -#elif defined AS_WINDOWS_THREADS - // Lock a reader slot - WaitForSingleObjectEx(readLocks, INFINITE, FALSE); -#endif -} - -void asCThreadReadWriteLock::ReleaseShared() -{ -#if defined AS_POSIX_THREADS - pthread_rwlock_unlock(&lock); -#elif defined AS_WINDOWS_THREADS - // Release the reader slot - ReleaseSemaphore(readLocks, 1, 0); -#endif -} - -#endif - -//======================================================================== - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_thread.h b/dependencies/angelscript/source/as_thread.h deleted file mode 100644 index 3600d005..00000000 --- a/dependencies/angelscript/source/as_thread.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - - -// -// as_thread.h -// -// Classes for multi threading support -// - -#ifndef AS_THREAD_H -#define AS_THREAD_H - -#include "as_config.h" -#include "as_string.h" -#include "as_array.h" -#include "as_map.h" -#include "as_criticalsection.h" - -BEGIN_AS_NAMESPACE - -class asCThreadLocalData; - -class asCThreadManager : public asIThreadManager -{ -public: - static asCThreadLocalData *GetLocalData(); - static int CleanupLocalData(); - - static int Prepare(asIThreadManager *externalThreadMgr); - static void Unprepare(); - - // This read/write lock can be used by the application to provide simple synchronization - DECLAREREADWRITELOCK(appRWLock) - -protected: - asCThreadManager(); - ~asCThreadManager(); - - // No need to use the atomic int here, as it will only be - // updated within the thread manager's critical section - int refCount; - -#ifndef AS_NO_THREADS -#if defined(_MSC_VER) && defined(AS_WINDOWS_THREADS) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) - // On Windows Store we must use MSVC specific thread variables for thread - // local storage, as the TLS API isn't available. On desktop we can't use - // this as it may cause problems if the library is used in a dll. - // ref: http://msdn.microsoft.com/en-us/library/2s9wt68x.aspx - // ref: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx - __declspec(thread) static asCThreadLocalData *tld; -#else - asDWORD tlsKey; -#endif - DECLARECRITICALSECTION(criticalSection) -#else - asCThreadLocalData *tld; -#endif -}; - -//====================================================================== - -class asIScriptContext; - -class asCThreadLocalData -{ -public: - asCArray activeContexts; - asCString string; - -protected: - friend class asCThreadManager; - - asCThreadLocalData(); - ~asCThreadLocalData(); -}; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_tokendef.h b/dependencies/angelscript/source/as_tokendef.h deleted file mode 100644 index d64f651b..00000000 --- a/dependencies/angelscript/source/as_tokendef.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_tokendef.h -// -// Definitions for tokens identifiable by the tokenizer -// - - -#ifndef AS_TOKENDEF_H -#define AS_TOKENDEF_H - -#include "as_config.h" - -BEGIN_AS_NAMESPACE - -enum eTokenType -{ - ttUnrecognizedToken, - - ttEnd, // End of file - - // White space and comments - ttWhiteSpace, // ' ', '\t', '\r', '\n', UTF8 byte-order-mark - ttOnelineComment, // // \n - ttMultilineComment, // /* */ - - // Atoms - ttIdentifier, // abc123 - ttIntConstant, // 1234 - ttFloatConstant, // 12.34e56f - ttDoubleConstant, // 12.34e56 - ttStringConstant, // "123" - ttMultilineStringConstant, // - ttHeredocStringConstant, // """text""" - ttNonTerminatedStringConstant, // "123 - ttBitsConstant, // 0xFFFF - - // Math operators - ttPlus, // + - ttMinus, // - - ttStar, // * - ttSlash, // / - ttPercent, // % - ttStarStar, // ** - - ttHandle, // @ - - ttAddAssign, // += - ttSubAssign, // -= - ttMulAssign, // *= - ttDivAssign, // /= - ttModAssign, // %= - ttPowAssign, // **= - - ttOrAssign, // |= - ttAndAssign, // &= - ttXorAssign, // ^= - ttShiftLeftAssign, // <<= - ttShiftRightLAssign, // >>= - ttShiftRightAAssign, // >>>= - - ttInc, // ++ - ttDec, // -- - - ttDot, // . - ttScope, // :: - - // Statement tokens - ttAssignment, // = - ttEndStatement, // ; - ttListSeparator, // , - ttStartStatementBlock, // { - ttEndStatementBlock, // } - ttOpenParanthesis, // ( - ttCloseParanthesis, // ) - ttOpenBracket, // [ - ttCloseBracket, // ] - ttAmp, // & - - // Bitwise operators - ttBitOr, // | - ttBitNot, // ~ - ttBitXor, // ^ - ttBitShiftLeft, // << - ttBitShiftRight, // >> // TODO: In Java this is the arithmetical shift - ttBitShiftRightArith, // >>> // TODO: In Java this is the logical shift - - // Compare operators - ttEqual, // == - ttNotEqual, // != - ttLessThan, // < - ttGreaterThan, // > - ttLessThanOrEqual, // <= - ttGreaterThanOrEqual, // >= - - ttQuestion, // ? - ttColon, // : - - // Reserved keywords - ttIf, // if - ttElse, // else - ttFor, // for - ttWhile, // while - ttBool, // bool - ttFuncDef, // funcdef - ttImport, // import - ttInt, // int - ttInt8, // int8 - ttInt16, // int16 - ttInt64, // int64 - ttInterface, // interface - ttIs, // is - ttNotIs, // !is - ttUInt, // uint - ttUInt8, // uint8 - ttUInt16, // uint16 - ttUInt64, // uint64 - ttFloat, // float - ttVoid, // void - ttTrue, // true - ttFalse, // false - ttReturn, // return - ttNot, // not - ttAnd, // and, && - ttOr, // or, || - ttXor, // xor, ^^ - ttBreak, // break - ttContinue, // continue - ttConst, // const - ttDo, // do - ttDouble, // double - ttSwitch, // switch - ttCase, // case - ttDefault, // default - ttIn, // in - ttOut, // out - ttInOut, // inout - ttNull, // null - ttClass, // class - ttTypedef, // typedef - ttEnum, // enum - ttCast, // cast - ttPrivate, // private - ttNamespace, // namespace - ttMixin, // mixin - ttAuto // auto -}; - -struct sTokenWord -{ - const char *word; - size_t wordLength; - eTokenType tokenType; -}; - -#define asTokenDef(str, tok) {str, sizeof(str)-1, tok} - -sTokenWord const tokenWords[] = -{ - asTokenDef("+" , ttPlus), - asTokenDef("+=" , ttAddAssign), - asTokenDef("++" , ttInc), - asTokenDef("-" , ttMinus), - asTokenDef("-=" , ttSubAssign), - asTokenDef("--" , ttDec), - asTokenDef("*" , ttStar), - asTokenDef("*=" , ttMulAssign), - asTokenDef("/" , ttSlash), - asTokenDef("/=" , ttDivAssign), - asTokenDef("%" , ttPercent), - asTokenDef("%=" , ttModAssign), - asTokenDef("**" , ttStarStar), - asTokenDef("**=" , ttPowAssign), - asTokenDef("=" , ttAssignment), - asTokenDef("==" , ttEqual), - asTokenDef("." , ttDot), - asTokenDef("|" , ttBitOr), - asTokenDef("|=" , ttOrAssign), - asTokenDef("||" , ttOr), - asTokenDef("&" , ttAmp), - asTokenDef("&=" , ttAndAssign), - asTokenDef("&&" , ttAnd), - asTokenDef("^" , ttBitXor), - asTokenDef("^=" , ttXorAssign), - asTokenDef("^^" , ttXor), - asTokenDef("<" , ttLessThan), - asTokenDef("<=" , ttLessThanOrEqual), - asTokenDef("<<" , ttBitShiftLeft), - asTokenDef("<<=" , ttShiftLeftAssign), - asTokenDef(">" , ttGreaterThan), - asTokenDef(">=" , ttGreaterThanOrEqual), - asTokenDef(">>" , ttBitShiftRight), - asTokenDef(">>=" , ttShiftRightLAssign), - asTokenDef(">>>" , ttBitShiftRightArith), - asTokenDef(">>>=" , ttShiftRightAAssign), - asTokenDef("~" , ttBitNot), - asTokenDef(";" , ttEndStatement), - asTokenDef("," , ttListSeparator), - asTokenDef("{" , ttStartStatementBlock), - asTokenDef("}" , ttEndStatementBlock), - asTokenDef("(" , ttOpenParanthesis), - asTokenDef(")" , ttCloseParanthesis), - asTokenDef("[" , ttOpenBracket), - asTokenDef("]" , ttCloseBracket), - asTokenDef("?" , ttQuestion), - asTokenDef(":" , ttColon), - asTokenDef("::" , ttScope), - asTokenDef("!" , ttNot), - asTokenDef("!=" , ttNotEqual), - asTokenDef("!is" , ttNotIs), - asTokenDef("@" , ttHandle), - asTokenDef("and" , ttAnd), - asTokenDef("auto" , ttAuto), - asTokenDef("bool" , ttBool), - asTokenDef("break" , ttBreak), - asTokenDef("case" , ttCase), - asTokenDef("cast" , ttCast), - asTokenDef("class" , ttClass), - asTokenDef("const" , ttConst), - asTokenDef("continue" , ttContinue), - asTokenDef("default" , ttDefault), - asTokenDef("do" , ttDo), -#ifdef AS_USE_DOUBLE_AS_FLOAT - asTokenDef("double" , ttFloat), -#else - asTokenDef("double" , ttDouble), -#endif - asTokenDef("else" , ttElse), - asTokenDef("enum" , ttEnum), - asTokenDef("false" , ttFalse), - asTokenDef("float" , ttFloat), - asTokenDef("for" , ttFor), - asTokenDef("funcdef" , ttFuncDef), - asTokenDef("if" , ttIf), - asTokenDef("import" , ttImport), - asTokenDef("in" , ttIn), - asTokenDef("inout" , ttInOut), - asTokenDef("int" , ttInt), - asTokenDef("int8" , ttInt8), - asTokenDef("int16" , ttInt16), - asTokenDef("int32" , ttInt), - asTokenDef("int64" , ttInt64), - asTokenDef("interface" , ttInterface), - asTokenDef("is" , ttIs), - asTokenDef("mixin" , ttMixin), - asTokenDef("namespace" , ttNamespace), - asTokenDef("not" , ttNot), - asTokenDef("null" , ttNull), - asTokenDef("or" , ttOr), - asTokenDef("out" , ttOut), - asTokenDef("private" , ttPrivate), - asTokenDef("return" , ttReturn), - asTokenDef("switch" , ttSwitch), - asTokenDef("true" , ttTrue), - asTokenDef("typedef" , ttTypedef), - asTokenDef("uint" , ttUInt), - asTokenDef("uint8" , ttUInt8), - asTokenDef("uint16" , ttUInt16), - asTokenDef("uint32" , ttUInt), - asTokenDef("uint64" , ttUInt64), - asTokenDef("void" , ttVoid), - asTokenDef("while" , ttWhile), - asTokenDef("xor" , ttXor), -}; - -const unsigned int numTokenWords = sizeof(tokenWords)/sizeof(sTokenWord); - -const char * const whiteSpace = " \t\r\n"; - -// Some keywords that are not considered tokens by the parser -// These only have meaning in specific situations. Outside these -// situations they are treated as normal identifiers. -const char * const THIS_TOKEN = "this"; -const char * const FROM_TOKEN = "from"; -const char * const SUPER_TOKEN = "super"; -const char * const SHARED_TOKEN = "shared"; -const char * const FINAL_TOKEN = "final"; -const char * const OVERRIDE_TOKEN = "override"; -const char * const GET_TOKEN = "get"; -const char * const SET_TOKEN = "set"; -const char * const ABSTRACT_TOKEN = "abstract"; - -END_AS_NAMESPACE - -#endif diff --git a/dependencies/angelscript/source/as_tokenizer.cpp b/dependencies/angelscript/source/as_tokenizer.cpp deleted file mode 100644 index def2fdf0..00000000 --- a/dependencies/angelscript/source/as_tokenizer.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2014 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_tokenizer.cpp -// -// This class identifies tokens from the script code -// - -#include "as_config.h" -#include "as_scriptengine.h" -#include "as_tokenizer.h" -#include "as_tokendef.h" - -#if !defined(AS_NO_MEMORY_H) -#include -#endif -#include // strcmp() - -BEGIN_AS_NAMESPACE - -asCTokenizer::asCTokenizer() -{ - engine = 0; - memset(keywordTable, 0, sizeof(keywordTable)); - - // Initialize the jump table - for( asUINT n = 0; n < numTokenWords; n++ ) - { - const sTokenWord& current = tokenWords[n]; - unsigned char start = current.word[0]; - - // Create new jump table entry if none exists - if( !keywordTable[start] ) - { - // Surely there won't ever be more than 32 keywords starting with - // the same character. Right? - keywordTable[start] = asNEWARRAY(const sTokenWord*, 32); - memset(keywordTable[start], 0, sizeof(sTokenWord*)*32); - } - - // Add the token sorted from longest to shortest so - // we check keywords greedily. - const sTokenWord** tok = keywordTable[start]; - unsigned insert = 0, index = 0; - while( tok[index] ) - { - if(tok[index]->wordLength >= current.wordLength) - ++insert; - ++index; - } - - while( index > insert ) - { - tok[index] = tok[index - 1]; - --index; - } - - tok[insert] = ¤t; - } -} - -asCTokenizer::~asCTokenizer() -{ - // Deallocate the jump table - for( asUINT n = 0; n < 256; n++ ) - { - if( keywordTable[n] ) - asDELETEARRAY(keywordTable[n]); - } -} - -// static -const char *asCTokenizer::GetDefinition(int tokenType) -{ - if( tokenType == ttUnrecognizedToken ) return ""; - if( tokenType == ttEnd ) return ""; - if( tokenType == ttWhiteSpace ) return ""; - if( tokenType == ttOnelineComment ) return ""; - if( tokenType == ttMultilineComment ) return ""; - if( tokenType == ttIdentifier ) return ""; - if( tokenType == ttIntConstant ) return ""; - if( tokenType == ttFloatConstant ) return ""; - if( tokenType == ttDoubleConstant ) return ""; - if( tokenType == ttStringConstant ) return ""; - if( tokenType == ttMultilineStringConstant ) return ""; - if( tokenType == ttNonTerminatedStringConstant ) return ""; - if( tokenType == ttBitsConstant ) return ""; - if( tokenType == ttHeredocStringConstant ) return ""; - - for( asUINT n = 0; n < numTokenWords; n++ ) - if( tokenWords[n].tokenType == tokenType ) - return tokenWords[n].word; - - return 0; -} - -bool asCTokenizer::IsDigitInRadix(char ch, int radix) const -{ - if( ch >= '0' && ch <= '9' ) return (ch -= '0') < radix; - if( ch >= 'A' && ch <= 'Z' ) return (ch -= 'A'-10) < radix; - if( ch >= 'a' && ch <= 'z' ) return (ch -= 'a'-10) < radix; - return false; -} - -eTokenType asCTokenizer::GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc) const -{ - asASSERT(source != 0); - asASSERT(tokenLength != 0); - - eTokenType tokenType; - size_t tlen; - asETokenClass t = ParseToken(source, sourceLength, tlen, tokenType); - if( tc ) *tc = t; - if( tokenLength ) *tokenLength = tlen; - - return tokenType; -} - -asETokenClass asCTokenizer::ParseToken(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const -{ - if( IsWhiteSpace(source, sourceLength, tokenLength, tokenType) ) return asTC_WHITESPACE; - if( IsComment(source, sourceLength, tokenLength, tokenType) ) return asTC_COMMENT; - if( IsConstant(source, sourceLength, tokenLength, tokenType) ) return asTC_VALUE; - if( IsIdentifier(source, sourceLength, tokenLength, tokenType) ) return asTC_IDENTIFIER; - if( IsKeyWord(source, sourceLength, tokenLength, tokenType) ) return asTC_KEYWORD; - - // If none of the above this is an unrecognized token - // We can find the length of the token by advancing - // one step and trying to identify a token there - tokenType = ttUnrecognizedToken; - tokenLength = 1; - - return asTC_UNKNOWN; -} - -bool asCTokenizer::IsWhiteSpace(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const -{ - // Treat UTF8 byte-order-mark (EF BB BF) as whitespace - if( sourceLength >= 3 && - asBYTE(source[0]) == 0xEFu && - asBYTE(source[1]) == 0xBBu && - asBYTE(source[2]) == 0xBFu ) - { - tokenType = ttWhiteSpace; - tokenLength = 3; - return true; - } - - // Group all other white space characters into one - size_t n; - int numWsChars = (int)strlen(whiteSpace); - for( n = 0; n < sourceLength; n++ ) - { - bool isWhiteSpace = false; - for( int w = 0; w < numWsChars; w++ ) - { - if( source[n] == whiteSpace[w] ) - { - isWhiteSpace = true; - break; - } - } - if( !isWhiteSpace ) break; - } - - if( n > 0 ) - { - tokenType = ttWhiteSpace; - tokenLength = n; - return true; - } - - return false; -} - -bool asCTokenizer::IsComment(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const -{ - if( sourceLength < 2 ) - return false; - - if( source[0] != '/' ) - return false; - - if( source[1] == '/' ) - { - // One-line comment - - // Find the length - size_t n; - for( n = 2; n < sourceLength; n++ ) - { - if( source[n] == '\n' ) - break; - } - - tokenType = ttOnelineComment; - tokenLength = n < sourceLength ? n+1 : n; - - return true; - } - - if( source[1] == '*' ) - { - // Multi-line comment - - // Find the length - size_t n; - for( n = 2; n < sourceLength-1; ) - { - if( source[n++] == '*' && source[n] == '/' ) - break; - } - - tokenType = ttMultilineComment; - tokenLength = n+1; - - return true; - } - - return false; -} - -bool asCTokenizer::IsConstant(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const -{ - // Starting with number - if( (source[0] >= '0' && source[0] <= '9') || (source[0] == '.' && sourceLength > 1 && source[1] >= '0' && source[1] <= '9') ) - { - // Is it a based number? - if( source[0] == '0' && sourceLength > 1 ) - { - // Determine the radix for the constant - int radix = 0; - switch( source[1] ) - { - case 'b': case 'B': radix = 2; break; - case 'o': case 'O': radix = 8; break; - case 'd': case 'D': radix = 10; break; - case 'x': case 'X': radix = 16; break; - } - - if( radix ) - { - size_t n; - for( n = 2; n < sourceLength; n++ ) - if( !IsDigitInRadix(source[n], radix) ) - break; - - tokenType = ttBitsConstant; - tokenLength = n; - return true; - } - } - - size_t n; - for( n = 0; n < sourceLength; n++ ) - { - if( source[n] < '0' || source[n] > '9' ) - break; - } - - if( n < sourceLength && (source[n] == '.' || source[n] == 'e' || source[n] == 'E') ) - { - if( source[n] == '.' ) - { - n++; - for( ; n < sourceLength; n++ ) - { - if( source[n] < '0' || source[n] > '9' ) - break; - } - } - - if( n < sourceLength && (source[n] == 'e' || source[n] == 'E') ) - { - n++; - if( n < sourceLength && (source[n] == '-' || source[n] == '+') ) - n++; - - for( ; n < sourceLength; n++ ) - { - if( source[n] < '0' || source[n] > '9' ) - break; - } - } - - if( n < sourceLength && (source[n] == 'f' || source[n] == 'F') ) - { - tokenType = ttFloatConstant; - tokenLength = n + 1; - } - else - { -#ifdef AS_USE_DOUBLE_AS_FLOAT - tokenType = ttFloatConstant; -#else - tokenType = ttDoubleConstant; -#endif - tokenLength = n; - } - return true; - } - - tokenType = ttIntConstant; - tokenLength = n; - return true; - } - - // String constant between double or single quotes - if( source[0] == '"' || source[0] == '\'' ) - { - // Is it a normal string constant or a heredoc string constant? - if( sourceLength >= 6 && source[0] == '"' && source[1] == '"' && source[2] == '"' ) - { - // Heredoc string constant (spans multiple lines, no escape sequences) - - // Find the length - size_t n; - for( n = 3; n < sourceLength-2; n++ ) - { - if( source[n] == '"' && source[n+1] == '"' && source[n+2] == '"' ) - break; - } - - tokenType = ttHeredocStringConstant; - tokenLength = n+3; - } - else - { - // Normal string constant - tokenType = ttStringConstant; - char quote = source[0]; - bool evenSlashes = true; - size_t n; - for( n = 1; n < sourceLength; n++ ) - { -#ifdef AS_DOUBLEBYTE_CHARSET - // Double-byte characters are only allowed for ASCII - if( (source[n] & 0x80) && engine->ep.scanner == 0 ) - { - // This is a leading character in a double byte character, - // include both in the string and continue processing. - n++; - continue; - } -#endif - - if( source[n] == '\n' ) - tokenType = ttMultilineStringConstant; - if( source[n] == quote && evenSlashes ) - { - tokenLength = n+1; - return true; - } - if( source[n] == '\\' ) evenSlashes = !evenSlashes; else evenSlashes = true; - } - - tokenType = ttNonTerminatedStringConstant; - tokenLength = n; - } - - return true; - } - - return false; -} - -bool asCTokenizer::IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const -{ - // Starting with letter or underscore - if( (source[0] >= 'a' && source[0] <= 'z') || - (source[0] >= 'A' && source[0] <= 'Z') || - source[0] == '_' ) - { - tokenType = ttIdentifier; - tokenLength = 1; - - for( size_t n = 1; n < sourceLength; n++ ) - { - if( (source[n] >= 'a' && source[n] <= 'z') || - (source[n] >= 'A' && source[n] <= 'Z') || - (source[n] >= '0' && source[n] <= '9') || - source[n] == '_' ) - tokenLength++; - else - break; - } - - // Make sure the identifier isn't a reserved keyword - if( IsKeyWord(source, tokenLength, tokenLength, tokenType) ) - return false; - - return true; - } - - return false; -} - -bool asCTokenizer::IsKeyWord(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const -{ - unsigned char start = source[0]; - const sTokenWord **ptr = keywordTable[start]; - - if( !ptr ) - return false; - - for( ; *ptr; ++ptr ) - { - size_t wlen = (*ptr)->wordLength; - if( sourceLength >= wlen && strncmp(source, (*ptr)->word, wlen) == 0 ) - { - // Tokens that end with a character that can be part of an - // identifier require an extra verification to guarantee that - // we don't split an identifier token, e.g. the "!is" token - // and the tokens "!" and "isTrue" in the "!isTrue" expression. - if( wlen < sourceLength && - ((source[wlen-1] >= 'a' && source[wlen-1] <= 'z') || - (source[wlen-1] >= 'A' && source[wlen-1] <= 'Z') || - (source[wlen-1] >= '0' && source[wlen-1] <= '9')) && - ((source[wlen] >= 'a' && source[wlen] <= 'z') || - (source[wlen] >= 'A' && source[wlen] <= 'Z') || - (source[wlen] >= '0' && source[wlen] <= '9') || - (source[wlen] == '_')) ) - { - // The token doesn't really match, even though - // the start of the source matches the token - continue; - } - - tokenType = (*ptr)->tokenType; - tokenLength = wlen; - return true; - } - } - - return false; -} - -END_AS_NAMESPACE - diff --git a/dependencies/angelscript/source/as_tokenizer.h b/dependencies/angelscript/source/as_tokenizer.h deleted file mode 100644 index 2968fece..00000000 --- a/dependencies/angelscript/source/as_tokenizer.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_tokenizer.cpp -// -// This class identifies tokens from the script code -// - - - -#ifndef AS_TOKENIZER_H -#define AS_TOKENIZER_H - -#include "as_config.h" -#include "as_tokendef.h" -#include "as_map.h" -#include "as_string.h" - -BEGIN_AS_NAMESPACE - -class asCTokenizer -{ -public: - eTokenType GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc = 0) const; - - static const char *GetDefinition(int tokenType); - -protected: - friend class asCScriptEngine; - - asCTokenizer(); - ~asCTokenizer(); - - asETokenClass ParseToken(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; - bool IsWhiteSpace(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; - bool IsComment(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; - bool IsConstant(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; - bool IsKeyWord(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; - bool IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; - bool IsDigitInRadix(char ch, int radix) const; - - const asCScriptEngine *engine; - - const sTokenWord **keywordTable[256]; -}; - -END_AS_NAMESPACE - -#endif - diff --git a/dependencies/angelscript/source/as_typeinfo.cpp b/dependencies/angelscript/source/as_typeinfo.cpp deleted file mode 100644 index 5918b5e7..00000000 --- a/dependencies/angelscript/source/as_typeinfo.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_typeinfo.cpp -// -// This class holds extra type info for the compiler -// - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_typeinfo.h" -#include "as_scriptengine.h" - -BEGIN_AS_NAMESPACE - -asCTypeInfo::asCTypeInfo() -{ - isTemporary = false; - stackOffset = 0; - isConstant = false; - isVariable = false; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; - isVoidExpression = false; -} - -void asCTypeInfo::Set(const asCDataType &dt) -{ - dataType = dt; - - isTemporary = false; - stackOffset = 0; - isConstant = false; - isVariable = false; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; - isVoidExpression = false; -} - -void asCTypeInfo::SetVariable(const asCDataType &dt, int stackOffset, bool isTemporary) -{ - Set(dt); - - this->isVariable = true; - this->isTemporary = isTemporary; - this->stackOffset = (short)stackOffset; -} - -void asCTypeInfo::SetConstantQW(const asCDataType &dt, asQWORD value) -{ - Set(dt); - - isConstant = true; - qwordValue = value; -} - -void asCTypeInfo::SetConstantDW(const asCDataType &dt, asDWORD value) -{ - Set(dt); - - isConstant = true; - dwordValue = value; -} - -void asCTypeInfo::SetConstantB(const asCDataType &dt, asBYTE value) -{ - Set(dt); - - isConstant = true; - byteValue = value; -} - -void asCTypeInfo::SetConstantF(const asCDataType &dt, float value) -{ - Set(dt); - - isConstant = true; - floatValue = value; -} - -void asCTypeInfo::SetConstantD(const asCDataType &dt, double value) -{ - Set(dt); - - isConstant = true; - doubleValue = value; -} - -void asCTypeInfo::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; -} - -void asCTypeInfo::SetNullConstant() -{ - Set(asCDataType::CreateNullHandle()); - isConstant = true; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; -} - -bool asCTypeInfo::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 asCTypeInfo::SetVoidExpression() -{ - Set(asCDataType::CreatePrimitive(ttVoid, false)); - isLValue = false; - isConstant = false; - isVoidExpression = true; -} - -bool asCTypeInfo::IsVoidExpression() const -{ - return isVoidExpression; -} - -void asCTypeInfo::SetDummy() -{ - SetConstantQW(asCDataType::CreatePrimitive(ttInt, true), 0); -} - - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER diff --git a/dependencies/angelscript/source/as_typeinfo.h b/dependencies/angelscript/source/as_typeinfo.h deleted file mode 100644 index 57d6bc44..00000000 --- a/dependencies/angelscript/source/as_typeinfo.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2013 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_typeinfo.h -// -// This class holds extra type info for the compiler -// - - - -#ifndef AS_TYPEINFO_H -#define AS_TYPEINFO_H - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_datatype.h" - -BEGIN_AS_NAMESPACE - -struct asCTypeInfo -{ - asCTypeInfo(); - void Set(const asCDataType &dataType); - - void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary); - void SetConstantB(const asCDataType &dataType, asBYTE value); - void SetConstantQW(const asCDataType &dataType, asQWORD value); - void SetConstantDW(const asCDataType &dataType, asDWORD value); - void SetConstantF(const asCDataType &dataType, float value); - void SetConstantD(const asCDataType &dataType, double value); - void SetNullConstant(); - void SetUndefinedFuncHandle(asCScriptEngine *engine); - void SetVoidExpression(); - void SetDummy(); - - bool IsNullConstant() const; - bool IsVoidExpression() 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 isVoidExpression : 1; - short dummy : 10; - short stackOffset; - union - { - asQWORD qwordValue; - double doubleValue; - asDWORD dwordValue; - float floatValue; - int intValue; - asWORD wordValue; - asBYTE byteValue; - }; -}; - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - -#endif diff --git a/dependencies/angelscript/source/as_variablescope.cpp b/dependencies/angelscript/source/as_variablescope.cpp deleted file mode 100644 index 63d38a69..00000000 --- a/dependencies/angelscript/source/as_variablescope.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2012 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_variablescope.cpp -// -// A manager class for variable declarations -// - - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_variablescope.h" - -BEGIN_AS_NAMESPACE - -asCVariableScope::asCVariableScope(asCVariableScope *parent) -{ - this->parent = parent; - Reset(); -} - -asCVariableScope::~asCVariableScope() -{ - Reset(); -} - -void asCVariableScope::Reset() -{ - isBreakScope = false; - isContinueScope = false; - - for( asUINT n = 0; n < variables.GetLength(); n++ ) - if( variables[n] ) - { - asDELETE(variables[n],sVariable); - } - variables.SetLength(0); -} - -int asCVariableScope::DeclareVariable(const char *name, const asCDataType &type, int stackOffset, bool onHeap) -{ - // TODO: optimize: Improve linear search - // See if the variable is already declared - if( strcmp(name, "") != 0 ) - { - for( asUINT n = 0; n < variables.GetLength(); n++ ) - { - if( variables[n]->name == name ) - return -1; - } - } - - sVariable *var = asNEW(sVariable); - if( var == 0 ) - { - // Out of memory. Return without allocating the var - return -2; - } - var->name = name; - var->type = type; - var->stackOffset = stackOffset; - var->isInitialized = false; - var->isPureConstant = false; - var->onHeap = onHeap; - - // Parameters are initialized - if( stackOffset <= 0 ) - var->isInitialized = true; - - variables.PushLast(var); - - return 0; -} - -sVariable *asCVariableScope::GetVariable(const char *name) -{ - // TODO: optimize: Improve linear search - // Find the variable - for( asUINT n = 0; n < variables.GetLength(); n++ ) - { - if( variables[n]->name == name ) - return variables[n]; - } - - if( parent ) - return parent->GetVariable(name); - - return 0; -} - -sVariable *asCVariableScope::GetVariableByOffset(int offset) -{ - // TODO: optimize: Improve linear search - // Find the variable - for( asUINT n = 0; n < variables.GetLength(); n++ ) - { - if( variables[n]->stackOffset == offset ) - return variables[n]; - } - - if( parent ) - return parent->GetVariableByOffset(offset); - - return 0; -} - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - - diff --git a/dependencies/angelscript/source/as_variablescope.h b/dependencies/angelscript/source/as_variablescope.h deleted file mode 100644 index 98fd05f1..00000000 --- a/dependencies/angelscript/source/as_variablescope.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - AngelCode Scripting Library - Copyright (c) 2003-2012 Andreas Jonsson - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - The original version of this library can be located at: - http://www.angelcode.com/angelscript/ - - Andreas Jonsson - andreas@angelcode.com -*/ - - -// -// as_variablescope.h -// -// A manager class for variable declarations -// - - -#ifndef AS_VARIABLESCOPE_H -#define AS_VARIABLESCOPE_H - -#include "as_config.h" - -#ifndef AS_NO_COMPILER - -#include "as_array.h" -#include "as_string.h" -#include "as_datatype.h" - -BEGIN_AS_NAMESPACE - -struct sVariable -{ - asCString name; - asCDataType type; - int stackOffset; - bool isInitialized; - bool isPureConstant; - asQWORD constantValue; - bool onHeap; -}; - -class asCVariableScope -{ -public: - asCVariableScope(asCVariableScope *parent); - ~asCVariableScope(); - - void Reset(); - - int DeclareVariable(const char *name, const asCDataType &type, int stackOffset, bool isObjectOnHeap); - sVariable *GetVariable(const char *name); - sVariable *GetVariableByOffset(int offset); - - asCVariableScope *parent; - - bool isBreakScope; - bool isContinueScope; - - asCArray variables; -}; - -END_AS_NAMESPACE - -#endif // AS_NO_COMPILER - -#endif diff --git a/dependencies/jsoncpp/AUTHORS b/dependencies/jsoncpp/AUTHORS deleted file mode 100644 index c0fbbeec..00000000 --- a/dependencies/jsoncpp/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Baptiste Lepilleur diff --git a/dependencies/jsoncpp/CMakeLists.txt b/dependencies/jsoncpp/CMakeLists.txt deleted file mode 100644 index 19362b5f..00000000 --- a/dependencies/jsoncpp/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -project(jsoncpp) - -FILE(GLOB_RECURSE jsoncpp_src src/lib_json/*.cpp) -include_directories(include) - -# the final lib -add_library(jsoncpp STATIC ${jsoncpp_src}) - -# ignore warnings -set_target_properties(jsoncpp PROPERTIES COMPILE_FLAGS "-w") - -if (NOT WIN32) - # install the library - INSTALL(TARGETS jsoncpp - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - ) -endif () \ No newline at end of file diff --git a/dependencies/jsoncpp/LICENSE b/dependencies/jsoncpp/LICENSE deleted file mode 100644 index ca2bfe1a..00000000 --- a/dependencies/jsoncpp/LICENSE +++ /dev/null @@ -1,55 +0,0 @@ -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. diff --git a/dependencies/jsoncpp/NEWS.txt b/dependencies/jsoncpp/NEWS.txt deleted file mode 100644 index 1be7b8ef..00000000 --- a/dependencies/jsoncpp/NEWS.txt +++ /dev/null @@ -1,175 +0,0 @@ -New in SVN ----------- - - * Updated the type system's behavior, in order to better support backwards - compatibility with code that was written before 64-bit integer support was - introduced. Here's how it works now: - - * isInt, isInt64, isUInt, and isUInt64 return true if and only if the - value can be exactly represented as that type. In particular, a value - constructed with a double like 17.0 will now return true for all of - these methods. - - * isDouble and isFloat now return true for all numeric values, since all - numeric values can be converted to a double or float without - truncation. Note however that the conversion may not be exact -- for - example, doubles cannot exactly represent all integers above 2^53 + 1. - - * isBool, isNull, isString, isArray, and isObject now return true if and - only if the value is of that type. - - * isConvertibleTo(fooValue) indicates that it is safe to call asFoo. - (For each type foo, isFoo always implies isConvertibleTo(fooValue).) - asFoo returns an approximate or exact representation as appropriate. - For example, a double value may be truncated when asInt is called. - - * For backwards compatibility with old code, isConvertibleTo(intValue) - may return false even if type() == intValue. This is because the value - may have been constructed with a 64-bit integer larger than maxInt, - and calling asInt() would cause an exception. If you're writing new - code, use isInt64 to find out whether the value is exactly - representable using an Int64, or asDouble() combined with minInt64 and - maxInt64 to figure out whether it is approximately representable. - -* Value - - Patch #10: BOOST_FOREACH compatibility. Made Json::iterator more - standard compliant, added missing iterator_category and value_type - typedefs (contribued by Robert A. Iannucci). - -* Compilation - - - New CMake based build system. Based in part on contribution from - Igor Okulist and Damien Buhl (Patch #14). - - - New header json/version.h now contains version number macros - (JSONCPP_VERSION_MAJOR, JSONCPP_VERSION_MINOR, JSONCPP_VERSION_PATCH - and JSONCPP_VERSION_HEXA). - - - Patch #11: added missing JSON_API on some classes causing link issues - when building as a dynamic library on Windows - (contributed by Francis Bolduc). - - - Visual Studio DLL: suppressed warning "C4251: : - needs to have dll-interface to be used by..." via pragma push/pop - in json-cpp headers. - - - Added Travis CI intregration: https://travis-ci.org/blep/jsoncpp-mirror - -* Bug fixes - - Patch #15: Copy constructor does not initialize allocated_ for stringValue - (contributed by rmongia). - - - Patch #16: Missing field copy in Json::Value::iterator causing infinite - loop when using experimental internal map (#define JSON_VALUE_USE_INTERNAL_MAP) - (contributed by Ming-Lin Kao). - - - New in JsonCpp 0.6.0: - --------------------- - -* Compilation - - - LD_LIBRARY_PATH and LIBRARY_PATH environment variables are now - propagated to the build environment as this is required for some - compiler installation. - - - Added support for Microsoft Visual Studio 2008 (bug #2930462): - The platform "msvc90" has been added. - - Notes: you need to setup the environment by running vcvars32.bat - (e.g. MSVC 2008 command prompt in start menu) before running scons. - - - Added support for amalgamated source and header generation (a la sqlite). - Refer to README.txt section "Generating amalgamated source and header" - for detail. - -* Value - - - Removed experimental ValueAllocator, it caused static - initialization/destruction order issues (bug #2934500). - The DefaultValueAllocator has been inlined in code. - - - Added support for 64 bits integer: - - Types Json::Int64 and Json::UInt64 have been added. They are aliased - to 64 bits integers on system that support them (based on __int64 on - Microsoft Visual Studio platform, and long long on other platforms). - - Types Json::LargestInt and Json::LargestUInt have been added. They are - aliased to the largest integer type supported: - either Json::Int/Json::UInt or Json::Int64/Json::UInt64 respectively. - - Json::Value::asInt() and Json::Value::asUInt() still returns plain - "int" based types, but asserts if an attempt is made to retrieve - a 64 bits value that can not represented as the return type. - - Json::Value::asInt64() and Json::Value::asUInt64() have been added - to obtain the 64 bits integer value. - - Json::Value::asLargestInt() and Json::Value::asLargestUInt() returns - the integer as a LargestInt/LargestUInt respectively. Those functions - functions are typically used when implementing writer. - - The reader attempts to read number as 64 bits integer, and fall back - to reading a double if the number is not in the range of 64 bits - integer. - - Warning: Json::Value::asInt() and Json::Value::asUInt() now returns - long long. This changes break code that was passing the return value - to *printf() function. - - Support for 64 bits integer can be disabled by defining the macro - JSON_NO_INT64 (uncomment it in json/config.h for example), though - it should have no impact on existing usage. - - - The type Json::ArrayIndex is used for indexes of a JSON value array. It - is an unsigned int (typically 32 bits). - - - Array index can be passed as int to operator[], allowing use of literal: - Json::Value array; - array.append( 1234 ); - int value = array[0].asInt(); // did not compile previously - - - Added float Json::Value::asFloat() to obtain a floating point value as a - float (avoid lost of precision warning caused by used of asDouble() - to initialize a float). - -* Reader - - - Renamed Reader::getFormatedErrorMessages() to getFormattedErrorMessages. - Bug #3023708 (Formatted has 2 't'). The old member function is deprecated - but still present for backward compatibility. - -* Tests - - - Added test to ensure that the escape sequence "\/" is corrected handled - by the parser. - -* Bug fixes - - - Bug #3139677: JSON [1 2 3] was incorrectly parsed as [1, 3]. Error is now - correctly detected. - - - Bug #3139678: stack buffer overflow when parsing a double with a - length of 32 characters. - - - Fixed Value::operator <= implementation (had the semantic of operator >=). - Found when adding unit tests for comparison operators. - - - Value::compare() is now const and has an actual implementation with - unit tests. - - - Bug #2407932: strpbrk() can fail for NULL pointer. - - - Bug #3306345: Fixed minor typo in Path::resolve(). - - - Bug #3314841/#3306896: errors in amalgamate.py - - - Fixed some Coverity warnings and line-endings. - -* License - - - See file LICENSE for details. Basically JsonCpp is now licensed under - MIT license, or public domain if desired and recognized in your jurisdiction. - Thanks to Stephan G. Beal [http://wanderinghorse.net/home/stephan/]) who - helped figuring out the solution to the public domain issue. diff --git a/dependencies/jsoncpp/README.md b/dependencies/jsoncpp/README.md deleted file mode 100644 index 099f17fa..00000000 --- a/dependencies/jsoncpp/README.md +++ /dev/null @@ -1,224 +0,0 @@ -Introduction ------------- - -[JSON][json-org] is a lightweight data-interchange format. It can represent -numbers, strings, ordered sequences of values, and collections of name/value -pairs. - -[json-org]: http://json.org/ - -JsonCpp is a C++ library that allows manipulating JSON values, including -serialization and deserialization to and from strings. It can also preserve -existing comment in unserialization/serialization steps, making it a convenient -format to store user input files. - -## A note on backward-compatibility -Very soon, we are switching to C++11 only. For older compilers, try the `pre-C++11` branch. - -Using JsonCpp in your project ------------------------------ - -The recommended approach to integrating JsonCpp in your project is to build -the amalgamated source (a single `.cpp` file) with your own build system. This -ensures consistency of compilation flags and ABI compatibility. See the section -"Generating amalgamated source and header" for instructions. - -The `include/` should be added to your compiler include path. Jsoncpp headers -should be included as follow: - - #include - -If JsonCpp was build as a dynamic library on Windows, then your project needs to -define the macro `JSON_DLL`. - - -Building and testing with new CMake ------------------------------------ - -[CMake][] is a C++ Makefiles/Solution generator. It is usually available on most -Linux system as package. On Ubuntu: - - sudo apt-get install cmake - -[CMake]: http://www.cmake.org - -Note that Python is also required to run the JSON reader/writer tests. If -missing, the build will skip running those tests. - -When running CMake, a few parameters are required: - -* a build directory where the makefiles/solution are generated. It is also used - to store objects, libraries and executables files. -* the generator to use: makefiles or Visual Studio solution? What version or - Visual Studio, 32 or 64 bits solution? - -Steps for generating solution/makefiles using `cmake-gui`: - -* Make "source code" point to the source directory. -* Make "where to build the binary" point to the directory to use for the build. -* Click on the "Grouped" check box. -* Review JsonCpp build options (tick `JSONCPP_LIB_BUILD_SHARED` to build as a - dynamic library). -* Click the configure button at the bottom, then the generate button. -* The generated solution/makefiles can be found in the binary directory. - -Alternatively, from the command-line on Unix in the source directory: - - mkdir -p build/debug - cd build/debug - cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../.. - make - -Running `cmake -`" will display the list of available generators (passed using -the `-G` option). - -By default CMake hides compilation commands. This can be modified by specifying -`-DCMAKE_VERBOSE_MAKEFILE=true` when generating makefiles. - - -Building and testing with SCons -------------------------------- - -**Note:** The SCons-based build system is deprecated. Please use CMake; see the -section above. - -JsonCpp can use [Scons][] as a build system. Note that SCons requires Python to -be installed. - -[SCons]: http://www.scons.org/ - -Invoke SCons as follows: - - scons platform=$PLATFORM [TARGET] - -where `$PLATFORM` may be one of: - -* `suncc`: Sun C++ (Solaris) -* `vacpp`: Visual Age C++ (AIX) -* `mingw` -* `msvc6`: Microsoft Visual Studio 6 service pack 5-6 -* `msvc70`: Microsoft Visual Studio 2002 -* `msvc71`: Microsoft Visual Studio 2003 -* `msvc80`: Microsoft Visual Studio 2005 -* `msvc90`: Microsoft Visual Studio 2008 -* `linux-gcc`: Gnu C++ (linux, also reported to work for Mac OS X) - -If you are building with Microsoft Visual Studio 2008, you need to set up the -environment by running `vcvars32.bat` (e.g. MSVC 2008 command prompt) before -running SCons. - - -Running the tests manually --------------------------- - -Note that test can be run using SCons using the `check` target: - - scons platform=$PLATFORM check - -You need to run tests manually only if you are troubleshooting an issue. - -In the instructions below, replace `path/to/jsontest` with the path of the -`jsontest` executable that was compiled on your platform. - - cd test - # This will run the Reader/Writer tests - python runjsontests.py path/to/jsontest - - # This will run the Reader/Writer tests, using JSONChecker test suite - # (http://www.json.org/JSON_checker/). - # Notes: not all tests pass: JsonCpp is too lenient (for example, - # it allows an integer to start with '0'). The goal is to improve - # strict mode parsing to get all tests to pass. - python runjsontests.py --with-json-checker path/to/jsontest - - # This will run the unit tests (mostly Value) - python rununittests.py path/to/test_lib_json - - # You can run the tests using valgrind: - python rununittests.py --valgrind path/to/test_lib_json - - -Building the documentation --------------------------- - -Run the Python script `doxybuild.py` from the top directory: - - python doxybuild.py --doxygen=$(which doxygen) --open --with-dot - -See `doxybuild.py --help` for options. - - -Generating amalgamated source and header ----------------------------------------- - -JsonCpp is provided with a script to generate a single header and a single -source file to ease inclusion into an existing project. The amalgamated source -can be generated at any time by running the following command from the -top-directory (this requires Python 2.6): - - python amalgamate.py - -It is possible to specify header name. See the `-h` option for detail. - -By default, the following files are generated: -* `dist/jsoncpp.cpp`: source file that needs to be added to your project. -* `dist/json/json.h`: corresponding header file for use in your project. It is - equivalent to including `json/json.h` in non-amalgamated source. This header - only depends on standard headers. -* `dist/json/json-forwards.h`: header that provides forward declaration of all - JsonCpp types. - -The amalgamated sources are generated by concatenating JsonCpp source in the -correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion -of other headers. - - -Adding a reader/writer test ---------------------------- - -To add a test, you need to create two files in test/data: - -* a `TESTNAME.json` file, that contains the input document in JSON format. -* a `TESTNAME.expected` file, that contains a flatened representation of the - input document. - -The `TESTNAME.expected` file format is as follows: - -* each line represents a JSON element of the element tree represented by the - input document. -* each line has two parts: the path to access the element separated from the - element value by `=`. Array and object values are always empty (i.e. - represented by either `[]` or `{}`). -* element path: `.` represents the root element, and is used to separate object - members. `[N]` is used to specify the value of an array element at index `N`. - -See the examples `test_complex_01.json` and `test_complex_01.expected` to better -understand element paths. - - -Understanding reader/writer test output ---------------------------------------- - -When a test is run, output files are generated beside the input test files. -Below is a short description of the content of each file: - -* `test_complex_01.json`: input JSON document. -* `test_complex_01.expected`: flattened JSON element tree used to check if - parsing was corrected. -* `test_complex_01.actual`: flattened JSON element tree produced by `jsontest` - from reading `test_complex_01.json`. -* `test_complex_01.rewrite`: JSON document written by `jsontest` using the - `Json::Value` parsed from `test_complex_01.json` and serialized using - `Json::StyledWritter`. -* `test_complex_01.actual-rewrite`: flattened JSON element tree produced by - `jsontest` from reading `test_complex_01.rewrite`. -* `test_complex_01.process-output`: `jsontest` output, typically useful for - understanding parsing errors. - - -License -------- - -See the `LICENSE` file for details. In summary, JsonCpp is licensed under the -MIT license, or public domain if desired and recognized in your jurisdiction. - diff --git a/dependencies/jsoncpp/SConstruct b/dependencies/jsoncpp/SConstruct deleted file mode 100644 index 1c55bcd0..00000000 --- a/dependencies/jsoncpp/SConstruct +++ /dev/null @@ -1,248 +0,0 @@ -""" -Notes: -- shared library support is buggy: it assumes that a static and dynamic library can be build from the same object files. This is not true on many platforms. For this reason it is only enabled on linux-gcc at the current time. - -To add a platform: -- add its name in options allowed_values below -- add tool initialization for this platform. Search for "if platform == 'suncc'" as an example. -""" - -import os -import os.path -import sys - -JSONCPP_VERSION = open(File('#version').abspath,'rt').read().strip() -DIST_DIR = '#dist' - -options = Variables() -options.Add( EnumVariable('platform', - 'Platform (compiler/stl) used to build the project', - 'msvc71', - allowed_values='suncc vacpp mingw msvc6 msvc7 msvc71 msvc80 msvc90 linux-gcc'.split(), - ignorecase=2) ) - -try: - platform = ARGUMENTS['platform'] - if platform == 'linux-gcc': - CXX = 'g++' # not quite right, but env is not yet available. - import commands - version = commands.getoutput('%s -dumpversion' %CXX) - platform = 'linux-gcc-%s' %version - print "Using platform '%s'" %platform - LD_LIBRARY_PATH = os.environ.get('LD_LIBRARY_PATH', '') - LD_LIBRARY_PATH = "%s:libs/%s" %(LD_LIBRARY_PATH, platform) - os.environ['LD_LIBRARY_PATH'] = LD_LIBRARY_PATH - print "LD_LIBRARY_PATH =", LD_LIBRARY_PATH -except KeyError: - print 'You must specify a "platform"' - sys.exit(2) - -print "Building using PLATFORM =", platform - -rootbuild_dir = Dir('#buildscons') -build_dir = os.path.join( '#buildscons', platform ) -bin_dir = os.path.join( '#bin', platform ) -lib_dir = os.path.join( '#libs', platform ) -sconsign_dir_path = Dir(build_dir).abspath -sconsign_path = os.path.join( sconsign_dir_path, '.sconsign.dbm' ) - -# Ensure build directory exist (SConsignFile fail otherwise!) -if not os.path.exists( sconsign_dir_path ): - os.makedirs( sconsign_dir_path ) - -# Store all dependencies signature in a database -SConsignFile( sconsign_path ) - -def make_environ_vars(): - """Returns a dictionnary with environment variable to use when compiling.""" - # PATH is required to find the compiler - # TEMP is required for at least mingw - # LD_LIBRARY_PATH & co is required on some system for the compiler - vars = {} - for name in ('PATH', 'TEMP', 'TMP', 'LD_LIBRARY_PATH', 'LIBRARY_PATH'): - if name in os.environ: - vars[name] = os.environ[name] - return vars - - -env = Environment( ENV = make_environ_vars(), - toolpath = ['scons-tools'], - tools=[] ) #, tools=['default'] ) - -if platform == 'suncc': - env.Tool( 'sunc++' ) - env.Tool( 'sunlink' ) - env.Tool( 'sunar' ) - env.Append( CCFLAGS = ['-mt'] ) -elif platform == 'vacpp': - env.Tool( 'default' ) - env.Tool( 'aixcc' ) - env['CXX'] = 'xlC_r' #scons does not pick-up the correct one ! - # using xlC_r ensure multi-threading is enabled: - # http://publib.boulder.ibm.com/infocenter/pseries/index.jsp?topic=/com.ibm.vacpp7a.doc/compiler/ref/cuselect.htm - env.Append( CCFLAGS = '-qrtti=all', - LINKFLAGS='-bh:5' ) # -bh:5 remove duplicate symbol warning -elif platform == 'msvc6': - env['MSVS_VERSION']='6.0' - for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: - env.Tool( tool ) - env['CXXFLAGS']='-GR -GX /nologo /MT' -elif platform == 'msvc70': - env['MSVS_VERSION']='7.0' - for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: - env.Tool( tool ) - env['CXXFLAGS']='-GR -GX /nologo /MT' -elif platform == 'msvc71': - env['MSVS_VERSION']='7.1' - for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: - env.Tool( tool ) - env['CXXFLAGS']='-GR -GX /nologo /MT' -elif platform == 'msvc80': - env['MSVS_VERSION']='8.0' - for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: - env.Tool( tool ) - env['CXXFLAGS']='-GR -EHsc /nologo /MT' -elif platform == 'msvc90': - env['MSVS_VERSION']='9.0' - # Scons 1.2 fails to detect the correct location of the platform SDK. - # So we propagate those from the environment. This requires that the - # user run vcvars32.bat before compiling. - if 'INCLUDE' in os.environ: - env['ENV']['INCLUDE'] = os.environ['INCLUDE'] - if 'LIB' in os.environ: - env['ENV']['LIB'] = os.environ['LIB'] - for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: - env.Tool( tool ) - env['CXXFLAGS']='-GR -EHsc /nologo /MT' -elif platform == 'mingw': - env.Tool( 'mingw' ) - env.Append( CPPDEFINES=[ "WIN32", "NDEBUG", "_MT" ] ) -elif platform.startswith('linux-gcc'): - env.Tool( 'default' ) - env.Append( LIBS = ['pthread'], CCFLAGS = os.environ.get("CXXFLAGS", "-Wall"), LINKFLAGS=os.environ.get("LDFLAGS", "") ) - env['SHARED_LIB_ENABLED'] = True -else: - print "UNSUPPORTED PLATFORM." - env.Exit(1) - -env.Tool('targz') -env.Tool('srcdist') -env.Tool('globtool') - -env.Append( CPPPATH = ['#include'], - LIBPATH = lib_dir ) -short_platform = platform -if short_platform.startswith('msvc'): - short_platform = short_platform[2:] -# Notes: on Windows you need to rebuild the source for each variant -# Build script does not support that yet so we only build static libraries. -# This also fails on AIX because both dynamic and static library ends with -# extension .a. -env['SHARED_LIB_ENABLED'] = env.get('SHARED_LIB_ENABLED', False) -env['LIB_PLATFORM'] = short_platform -env['LIB_LINK_TYPE'] = 'lib' # static -env['LIB_CRUNTIME'] = 'mt' -env['LIB_NAME_SUFFIX'] = '${LIB_PLATFORM}_${LIB_LINK_TYPE}${LIB_CRUNTIME}' # must match autolink naming convention -env['JSONCPP_VERSION'] = JSONCPP_VERSION -env['BUILD_DIR'] = env.Dir(build_dir) -env['ROOTBUILD_DIR'] = env.Dir(rootbuild_dir) -env['DIST_DIR'] = DIST_DIR -if 'TarGz' in env['BUILDERS']: - class SrcDistAdder: - def __init__( self, env ): - self.env = env - def __call__( self, *args, **kw ): - apply( self.env.SrcDist, (self.env['SRCDIST_TARGET'],) + args, kw ) - env['SRCDIST_BUILDER'] = env.TarGz -else: # If tarfile module is missing - class SrcDistAdder: - def __init__( self, env ): - pass - def __call__( self, *args, **kw ): - pass -env['SRCDIST_ADD'] = SrcDistAdder( env ) -env['SRCDIST_TARGET'] = os.path.join( DIST_DIR, 'jsoncpp-src-%s.tar.gz' % env['JSONCPP_VERSION'] ) - -env_testing = env.Clone( ) -env_testing.Append( LIBS = ['json_${LIB_NAME_SUFFIX}'] ) - -def buildJSONExample( env, target_sources, target_name ): - env = env.Clone() - env.Append( CPPPATH = ['#'] ) - exe = env.Program( target=target_name, - source=target_sources ) - env['SRCDIST_ADD']( source=[target_sources] ) - global bin_dir - return env.Install( bin_dir, exe ) - -def buildJSONTests( env, target_sources, target_name ): - jsontests_node = buildJSONExample( env, target_sources, target_name ) - check_alias_target = env.Alias( 'check', jsontests_node, RunJSONTests( jsontests_node, jsontests_node ) ) - env.AlwaysBuild( check_alias_target ) - -def buildUnitTests( env, target_sources, target_name ): - jsontests_node = buildJSONExample( env, target_sources, target_name ) - check_alias_target = env.Alias( 'check', jsontests_node, - RunUnitTests( jsontests_node, jsontests_node ) ) - env.AlwaysBuild( check_alias_target ) - -def buildLibrary( env, target_sources, target_name ): - static_lib = env.StaticLibrary( target=target_name + '_${LIB_NAME_SUFFIX}', - source=target_sources ) - global lib_dir - env.Install( lib_dir, static_lib ) - if env['SHARED_LIB_ENABLED']: - shared_lib = env.SharedLibrary( target=target_name + '_${LIB_NAME_SUFFIX}', - source=target_sources ) - env.Install( lib_dir, shared_lib ) - env['SRCDIST_ADD']( source=[target_sources] ) - -Export( 'env env_testing buildJSONExample buildLibrary buildJSONTests buildUnitTests' ) - -def buildProjectInDirectory( target_directory ): - global build_dir - target_build_dir = os.path.join( build_dir, target_directory ) - target = os.path.join( target_directory, 'sconscript' ) - SConscript( target, build_dir=target_build_dir, duplicate=0 ) - env['SRCDIST_ADD']( source=[target] ) - - -def runJSONTests_action( target, source = None, env = None ): - # Add test scripts to python path - jsontest_path = Dir( '#test' ).abspath - sys.path.insert( 0, jsontest_path ) - data_path = os.path.join( jsontest_path, 'data' ) - import runjsontests - return runjsontests.runAllTests( os.path.abspath(source[0].path), data_path ) - -def runJSONTests_string( target, source = None, env = None ): - return 'RunJSONTests("%s")' % source[0] - -import SCons.Action -ActionFactory = SCons.Action.ActionFactory -RunJSONTests = ActionFactory(runJSONTests_action, runJSONTests_string ) - -def runUnitTests_action( target, source = None, env = None ): - # Add test scripts to python path - jsontest_path = Dir( '#test' ).abspath - sys.path.insert( 0, jsontest_path ) - import rununittests - return rununittests.runAllTests( os.path.abspath(source[0].path) ) - -def runUnitTests_string( target, source = None, env = None ): - return 'RunUnitTests("%s")' % source[0] - -RunUnitTests = ActionFactory(runUnitTests_action, runUnitTests_string ) - -env.Alias( 'check' ) - -srcdist_cmd = env['SRCDIST_ADD']( source = """ - AUTHORS README.txt SConstruct - """.split() ) -env.Alias( 'src-dist', srcdist_cmd ) - -buildProjectInDirectory( 'src/jsontestrunner' ) -buildProjectInDirectory( 'src/lib_json' ) -buildProjectInDirectory( 'src/test_lib_json' ) -#print env.Dump() - diff --git a/dependencies/jsoncpp/amalgamate.py b/dependencies/jsoncpp/amalgamate.py deleted file mode 100644 index 550f6a67..00000000 --- a/dependencies/jsoncpp/amalgamate.py +++ /dev/null @@ -1,150 +0,0 @@ -"""Amalgate json-cpp library sources into a single source and header file. - -Requires Python 2.6 - -Example of invocation (must be invoked from json-cpp top directory): -python amalgate.py -""" -import os -import os.path -import sys - -class AmalgamationFile: - def __init__( self, top_dir ): - self.top_dir = top_dir - self.blocks = [] - - def add_text( self, text ): - if not text.endswith( "\n" ): - text += "\n" - self.blocks.append( text ) - - def add_file( self, relative_input_path, wrap_in_comment=False ): - def add_marker( prefix ): - self.add_text( "" ) - self.add_text( "// " + "/"*70 ) - self.add_text( "// %s of content of file: %s" % (prefix, relative_input_path.replace("\\","/")) ) - self.add_text( "// " + "/"*70 ) - self.add_text( "" ) - add_marker( "Beginning" ) - f = open( os.path.join( self.top_dir, relative_input_path ), "rt" ) - content = f.read() - if wrap_in_comment: - content = "/*\n" + content + "\n*/" - self.add_text( content ) - f.close() - add_marker( "End" ) - self.add_text( "\n\n\n\n" ) - - def get_value( self ): - return "".join( self.blocks ).replace("\r\n","\n") - - def write_to( self, output_path ): - output_dir = os.path.dirname( output_path ) - if output_dir and not os.path.isdir( output_dir ): - os.makedirs( output_dir ) - f = open( output_path, "wb" ) - f.write( str.encode(self.get_value(), 'UTF-8') ) - f.close() - -def amalgamate_source( source_top_dir=None, - target_source_path=None, - header_include_path=None ): - """Produces amalgated source. - Parameters: - source_top_dir: top-directory - target_source_path: output .cpp path - header_include_path: generated header path relative to target_source_path. - """ - print("Amalgating header...") - header = AmalgamationFile( source_top_dir ) - header.add_text( "/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/)." ) - header.add_text( "/// It is intented to be used with #include <%s>" % header_include_path ) - header.add_file( "LICENSE", wrap_in_comment=True ) - header.add_text( "#ifndef JSON_AMALGATED_H_INCLUDED" ) - header.add_text( "# define JSON_AMALGATED_H_INCLUDED" ) - header.add_text( "/// If defined, indicates that the source file is amalgated" ) - header.add_text( "/// to prevent private header inclusion." ) - header.add_text( "#define JSON_IS_AMALGAMATION" ) - header.add_file( "include/json/version.h" ) - header.add_file( "include/json/config.h" ) - header.add_file( "include/json/forwards.h" ) - header.add_file( "include/json/features.h" ) - header.add_file( "include/json/value.h" ) - header.add_file( "include/json/reader.h" ) - header.add_file( "include/json/writer.h" ) - header.add_file( "include/json/assertions.h" ) - header.add_text( "#endif //ifndef JSON_AMALGATED_H_INCLUDED" ) - - target_header_path = os.path.join( os.path.dirname(target_source_path), header_include_path ) - print("Writing amalgated header to %r" % target_header_path) - header.write_to( target_header_path ) - - base, ext = os.path.splitext( header_include_path ) - forward_header_include_path = base + "-forwards" + ext - print("Amalgating forward header...") - header = AmalgamationFile( source_top_dir ) - header.add_text( "/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/)." ) - header.add_text( "/// It is intented to be used with #include <%s>" % forward_header_include_path ) - header.add_text( "/// This header provides forward declaration for all JsonCpp types." ) - header.add_file( "LICENSE", wrap_in_comment=True ) - header.add_text( "#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED" ) - header.add_text( "# define JSON_FORWARD_AMALGATED_H_INCLUDED" ) - header.add_text( "/// If defined, indicates that the source file is amalgated" ) - header.add_text( "/// to prevent private header inclusion." ) - header.add_text( "#define JSON_IS_AMALGAMATION" ) - header.add_file( "include/json/config.h" ) - header.add_file( "include/json/forwards.h" ) - header.add_text( "#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED" ) - - target_forward_header_path = os.path.join( os.path.dirname(target_source_path), - forward_header_include_path ) - print("Writing amalgated forward header to %r" % target_forward_header_path) - header.write_to( target_forward_header_path ) - - print("Amalgating source...") - source = AmalgamationFile( source_top_dir ) - source.add_text( "/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/)." ) - source.add_text( "/// It is intented to be used with #include <%s>" % header_include_path ) - source.add_file( "LICENSE", wrap_in_comment=True ) - source.add_text( "" ) - source.add_text( "#include <%s>" % header_include_path ) - source.add_text( "" ) - lib_json = "src/lib_json" - source.add_file( os.path.join(lib_json, "json_tool.h") ) - source.add_file( os.path.join(lib_json, "json_reader.cpp") ) - source.add_file( os.path.join(lib_json, "json_batchallocator.h") ) - source.add_file( os.path.join(lib_json, "json_valueiterator.inl") ) - source.add_file( os.path.join(lib_json, "json_value.cpp") ) - source.add_file( os.path.join(lib_json, "json_writer.cpp") ) - - print("Writing amalgated source to %r" % target_source_path) - source.write_to( target_source_path ) - -def main(): - usage = """%prog [options] -Generate a single amalgated source and header file from the sources. -""" - from optparse import OptionParser - parser = OptionParser(usage=usage) - parser.allow_interspersed_args = False - parser.add_option("-s", "--source", dest="target_source_path", action="store", default="dist/jsoncpp.cpp", - help="""Output .cpp source path. [Default: %default]""") - parser.add_option("-i", "--include", dest="header_include_path", action="store", default="json/json.h", - help="""Header include path. Used to include the header from the amalgated source file. [Default: %default]""") - parser.add_option("-t", "--top-dir", dest="top_dir", action="store", default=os.getcwd(), - help="""Source top-directory. [Default: %default]""") - parser.enable_interspersed_args() - options, args = parser.parse_args() - - msg = amalgamate_source( source_top_dir=options.top_dir, - target_source_path=options.target_source_path, - header_include_path=options.header_include_path ) - if msg: - sys.stderr.write( msg + "\n" ) - sys.exit( 1 ) - else: - print("Source succesfully amalagated") - -if __name__ == "__main__": - main() diff --git a/dependencies/jsoncpp/dev.makefile b/dependencies/jsoncpp/dev.makefile deleted file mode 100644 index dd16bdd6..00000000 --- a/dependencies/jsoncpp/dev.makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: build test-amalgamate - -build: - mkdir -p build/debug - cd build/debug; cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=ON -G "Unix Makefiles" ../.. - make -C build/debug - -# Currently, this depends on include/json/version.h generated -# by cmake. -test-amalgamate: build - python2.7 amalgamate.py - python3.4 amalgamate.py - -.PHONY: build diff --git a/dependencies/jsoncpp/devtools/__init__.py b/dependencies/jsoncpp/devtools/__init__.py deleted file mode 100644 index c944e7cb..00000000 --- a/dependencies/jsoncpp/devtools/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# module \ No newline at end of file diff --git a/dependencies/jsoncpp/devtools/agent_vmw7.json b/dependencies/jsoncpp/devtools/agent_vmw7.json deleted file mode 100644 index 38b50d94..00000000 --- a/dependencies/jsoncpp/devtools/agent_vmw7.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "cmake_variants" : [ - {"name": "generator", - "generators": [ - {"generator": [ - "Visual Studio 7 .NET 2003", - "Visual Studio 9 2008", - "Visual Studio 9 2008 Win64", - "Visual Studio 10", - "Visual Studio 10 Win64", - "Visual Studio 11", - "Visual Studio 11 Win64" - ] - }, - {"generator": ["MinGW Makefiles"], - "env_prepend": [{"path": "c:/wut/prg/MinGW/bin"}] - } - ] - }, - {"name": "shared_dll", - "variables": [ - ["JSONCPP_LIB_BUILD_SHARED=true"], - ["JSONCPP_LIB_BUILD_SHARED=false"] - ] - }, - {"name": "build_type", - "build_types": [ - "debug", - "release" - ] - } - ] -} diff --git a/dependencies/jsoncpp/devtools/agent_vmxp.json b/dependencies/jsoncpp/devtools/agent_vmxp.json deleted file mode 100644 index 61f5a4c0..00000000 --- a/dependencies/jsoncpp/devtools/agent_vmxp.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "cmake_variants" : [ - {"name": "generator", - "generators": [ - {"generator": [ - "Visual Studio 6", - "Visual Studio 7", - "Visual Studio 8 2005" - ] - } - ] - }, - {"name": "shared_dll", - "variables": [ - ["JSONCPP_LIB_BUILD_SHARED=true"], - ["JSONCPP_LIB_BUILD_SHARED=false"] - ] - }, - {"name": "build_type", - "build_types": [ - "debug", - "release" - ] - } - ] -} diff --git a/dependencies/jsoncpp/devtools/antglob.py b/dependencies/jsoncpp/devtools/antglob.py deleted file mode 100644 index 8b7b4ca2..00000000 --- a/dependencies/jsoncpp/devtools/antglob.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Baptiste Lepilleur, 2009 - -from __future__ import print_function -from dircache import listdir -import re -import fnmatch -import os.path - - -# These fnmatch expressions are used by default to prune the directory tree -# while doing the recursive traversal in the glob_impl method of glob function. -prune_dirs = '.git .bzr .hg .svn _MTN _darcs CVS SCCS ' - -# These fnmatch expressions are used by default to exclude files and dirs -# while doing the recursive traversal in the glob_impl method of glob function. -##exclude_pats = prune_pats + '*~ #*# .#* %*% ._* .gitignore .cvsignore vssver.scc .DS_Store'.split() - -# These ant_glob expressions are used by default to exclude files and dirs and also prune the directory tree -# while doing the recursive traversal in the glob_impl method of glob function. -default_excludes = ''' -**/*~ -**/#*# -**/.#* -**/%*% -**/._* -**/CVS -**/CVS/** -**/.cvsignore -**/SCCS -**/SCCS/** -**/vssver.scc -**/.svn -**/.svn/** -**/.git -**/.git/** -**/.gitignore -**/.bzr -**/.bzr/** -**/.hg -**/.hg/** -**/_MTN -**/_MTN/** -**/_darcs -**/_darcs/** -**/.DS_Store ''' - -DIR = 1 -FILE = 2 -DIR_LINK = 4 -FILE_LINK = 8 -LINKS = DIR_LINK | FILE_LINK -ALL_NO_LINK = DIR | FILE -ALL = DIR | FILE | LINKS - -_ANT_RE = re.compile( r'(/\*\*/)|(\*\*/)|(/\*\*)|(\*)|(/)|([^\*/]*)' ) - -def ant_pattern_to_re( ant_pattern ): - """Generates a regular expression from the ant pattern. - Matching convention: - **/a: match 'a', 'dir/a', 'dir1/dir2/a' - a/**/b: match 'a/b', 'a/c/b', 'a/d/c/b' - *.py: match 'script.py' but not 'a/script.py' - """ - rex = ['^'] - next_pos = 0 - sep_rex = r'(?:/|%s)' % re.escape( os.path.sep ) -## print 'Converting', ant_pattern - for match in _ANT_RE.finditer( ant_pattern ): -## print 'Matched', match.group() -## print match.start(0), next_pos - if match.start(0) != next_pos: - raise ValueError( "Invalid ant pattern" ) - if match.group(1): # /**/ - rex.append( sep_rex + '(?:.*%s)?' % sep_rex ) - elif match.group(2): # **/ - rex.append( '(?:.*%s)?' % sep_rex ) - elif match.group(3): # /** - rex.append( sep_rex + '.*' ) - elif match.group(4): # * - rex.append( '[^/%s]*' % re.escape(os.path.sep) ) - elif match.group(5): # / - rex.append( sep_rex ) - else: # somepath - rex.append( re.escape(match.group(6)) ) - next_pos = match.end() - rex.append('$') - return re.compile( ''.join( rex ) ) - -def _as_list( l ): - if isinstance(l, basestring): - return l.split() - return l - -def glob(dir_path, - includes = '**/*', - excludes = default_excludes, - entry_type = FILE, - prune_dirs = prune_dirs, - max_depth = 25): - include_filter = [ant_pattern_to_re(p) for p in _as_list(includes)] - exclude_filter = [ant_pattern_to_re(p) for p in _as_list(excludes)] - prune_dirs = [p.replace('/',os.path.sep) for p in _as_list(prune_dirs)] - dir_path = dir_path.replace('/',os.path.sep) - entry_type_filter = entry_type - - def is_pruned_dir( dir_name ): - for pattern in prune_dirs: - if fnmatch.fnmatch( dir_name, pattern ): - return True - return False - - def apply_filter( full_path, filter_rexs ): - """Return True if at least one of the filter regular expression match full_path.""" - for rex in filter_rexs: - if rex.match( full_path ): - return True - return False - - def glob_impl( root_dir_path ): - child_dirs = [root_dir_path] - while child_dirs: - dir_path = child_dirs.pop() - for entry in listdir( dir_path ): - full_path = os.path.join( dir_path, entry ) -## print 'Testing:', full_path, - is_dir = os.path.isdir( full_path ) - if is_dir and not is_pruned_dir( entry ): # explore child directory ? -## print '===> marked for recursion', - child_dirs.append( full_path ) - included = apply_filter( full_path, include_filter ) - rejected = apply_filter( full_path, exclude_filter ) - if not included or rejected: # do not include entry ? -## print '=> not included or rejected' - continue - link = os.path.islink( full_path ) - is_file = os.path.isfile( full_path ) - if not is_file and not is_dir: -## print '=> unknown entry type' - continue - if link: - entry_type = is_file and FILE_LINK or DIR_LINK - else: - entry_type = is_file and FILE or DIR -## print '=> type: %d' % entry_type, - if (entry_type & entry_type_filter) != 0: -## print ' => KEEP' - yield os.path.join( dir_path, entry ) -## else: -## print ' => TYPE REJECTED' - return list( glob_impl( dir_path ) ) - - -if __name__ == "__main__": - import unittest - - class AntPatternToRETest(unittest.TestCase): -## def test_conversion( self ): -## self.assertEqual( '^somepath$', ant_pattern_to_re( 'somepath' ).pattern ) - - def test_matching( self ): - test_cases = [ ( 'path', - ['path'], - ['somepath', 'pathsuffix', '/path', '/path'] ), - ( '*.py', - ['source.py', 'source.ext.py', '.py'], - ['path/source.py', '/.py', 'dir.py/z', 'z.pyc', 'z.c'] ), - ( '**/path', - ['path', '/path', '/a/path', 'c:/a/path', '/a/b/path', '//a/path', '/a/path/b/path'], - ['path/', 'a/path/b', 'dir.py/z', 'somepath', 'pathsuffix', 'a/somepath'] ), - ( 'path/**', - ['path/a', 'path/path/a', 'path//'], - ['path', 'somepath/a', 'a/path', 'a/path/a', 'pathsuffix/a'] ), - ( '/**/path', - ['/path', '/a/path', '/a/b/path/path', '/path/path'], - ['path', 'path/', 'a/path', '/pathsuffix', '/somepath'] ), - ( 'a/b', - ['a/b'], - ['somea/b', 'a/bsuffix', 'a/b/c'] ), - ( '**/*.py', - ['script.py', 'src/script.py', 'a/b/script.py', '/a/b/script.py'], - ['script.pyc', 'script.pyo', 'a.py/b'] ), - ( 'src/**/*.py', - ['src/a.py', 'src/dir/a.py'], - ['a/src/a.py', '/src/a.py'] ), - ] - for ant_pattern, accepted_matches, rejected_matches in list(test_cases): - def local_path( paths ): - return [ p.replace('/',os.path.sep) for p in paths ] - test_cases.append( (ant_pattern, local_path(accepted_matches), local_path( rejected_matches )) ) - for ant_pattern, accepted_matches, rejected_matches in test_cases: - rex = ant_pattern_to_re( ant_pattern ) - print('ant_pattern:', ant_pattern, ' => ', rex.pattern) - for accepted_match in accepted_matches: - print('Accepted?:', accepted_match) - self.assertTrue( rex.match( accepted_match ) is not None ) - for rejected_match in rejected_matches: - print('Rejected?:', rejected_match) - self.assertTrue( rex.match( rejected_match ) is None ) - - unittest.main() diff --git a/dependencies/jsoncpp/devtools/batchbuild.py b/dependencies/jsoncpp/devtools/batchbuild.py deleted file mode 100644 index 6f57945a..00000000 --- a/dependencies/jsoncpp/devtools/batchbuild.py +++ /dev/null @@ -1,281 +0,0 @@ -from __future__ import print_function -import collections -import itertools -import json -import os -import os.path -import re -import shutil -import string -import subprocess -import sys -import cgi - -class BuildDesc: - def __init__(self, prepend_envs=None, variables=None, build_type=None, generator=None): - self.prepend_envs = prepend_envs or [] # [ { "var": "value" } ] - self.variables = variables or [] - self.build_type = build_type - self.generator = generator - - def merged_with( self, build_desc ): - """Returns a new BuildDesc by merging field content. - Prefer build_desc fields to self fields for single valued field. - """ - return BuildDesc( self.prepend_envs + build_desc.prepend_envs, - self.variables + build_desc.variables, - build_desc.build_type or self.build_type, - build_desc.generator or self.generator ) - - def env( self ): - environ = os.environ.copy() - for values_by_name in self.prepend_envs: - for var, value in list(values_by_name.items()): - var = var.upper() - if type(value) is unicode: - value = value.encode( sys.getdefaultencoding() ) - if var in environ: - environ[var] = value + os.pathsep + environ[var] - else: - environ[var] = value - return environ - - def cmake_args( self ): - args = ["-D%s" % var for var in self.variables] - # skip build type for Visual Studio solution as it cause warning - if self.build_type and 'Visual' not in self.generator: - args.append( "-DCMAKE_BUILD_TYPE=%s" % self.build_type ) - if self.generator: - args.extend( ['-G', self.generator] ) - return args - - def __repr__( self ): - return "BuildDesc( %s, build_type=%s )" % (" ".join( self.cmake_args()), self.build_type) - -class BuildData: - def __init__( self, desc, work_dir, source_dir ): - self.desc = desc - self.work_dir = work_dir - self.source_dir = source_dir - self.cmake_log_path = os.path.join( work_dir, 'batchbuild_cmake.log' ) - self.build_log_path = os.path.join( work_dir, 'batchbuild_build.log' ) - self.cmake_succeeded = False - self.build_succeeded = False - - def execute_build(self): - print('Build %s' % self.desc) - self._make_new_work_dir( ) - self.cmake_succeeded = self._generate_makefiles( ) - if self.cmake_succeeded: - self.build_succeeded = self._build_using_makefiles( ) - return self.build_succeeded - - def _generate_makefiles(self): - print(' Generating makefiles: ', end=' ') - cmd = ['cmake'] + self.desc.cmake_args( ) + [os.path.abspath( self.source_dir )] - succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.cmake_log_path ) - print('done' if succeeded else 'FAILED') - return succeeded - - def _build_using_makefiles(self): - print(' Building:', end=' ') - cmd = ['cmake', '--build', self.work_dir] - if self.desc.build_type: - cmd += ['--config', self.desc.build_type] - succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.build_log_path ) - print('done' if succeeded else 'FAILED') - return succeeded - - def _execute_build_subprocess(self, cmd, env, log_path): - process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.work_dir, - env=env ) - stdout, _ = process.communicate( ) - succeeded = (process.returncode == 0) - with open( log_path, 'wb' ) as flog: - log = ' '.join( cmd ) + '\n' + stdout + '\nExit code: %r\n' % process.returncode - flog.write( fix_eol( log ) ) - return succeeded - - def _make_new_work_dir(self): - if os.path.isdir( self.work_dir ): - print(' Removing work directory', self.work_dir) - shutil.rmtree( self.work_dir, ignore_errors=True ) - if not os.path.isdir( self.work_dir ): - os.makedirs( self.work_dir ) - -def fix_eol( stdout ): - """Fixes wrong EOL produced by cmake --build on Windows (\r\r\n instead of \r\n). - """ - return re.sub( '\r*\n', os.linesep, stdout ) - -def load_build_variants_from_config( config_path ): - with open( config_path, 'rb' ) as fconfig: - data = json.load( fconfig ) - variants = data[ 'cmake_variants' ] - build_descs_by_axis = collections.defaultdict( list ) - for axis in variants: - axis_name = axis["name"] - build_descs = [] - if "generators" in axis: - for generator_data in axis["generators"]: - for generator in generator_data["generator"]: - build_desc = BuildDesc( generator=generator, - prepend_envs=generator_data.get("env_prepend") ) - build_descs.append( build_desc ) - elif "variables" in axis: - for variables in axis["variables"]: - build_desc = BuildDesc( variables=variables ) - build_descs.append( build_desc ) - elif "build_types" in axis: - for build_type in axis["build_types"]: - build_desc = BuildDesc( build_type=build_type ) - build_descs.append( build_desc ) - build_descs_by_axis[axis_name].extend( build_descs ) - return build_descs_by_axis - -def generate_build_variants( build_descs_by_axis ): - """Returns a list of BuildDesc generated for the partial BuildDesc for each axis.""" - axis_names = list(build_descs_by_axis.keys()) - build_descs = [] - for axis_name, axis_build_descs in list(build_descs_by_axis.items()): - if len(build_descs): - # for each existing build_desc and each axis build desc, create a new build_desc - new_build_descs = [] - for prototype_build_desc, axis_build_desc in itertools.product( build_descs, axis_build_descs): - new_build_descs.append( prototype_build_desc.merged_with( axis_build_desc ) ) - build_descs = new_build_descs - else: - build_descs = axis_build_descs - return build_descs - -HTML_TEMPLATE = string.Template(''' - - $title - - - - - - - - $th_vars - - - - $th_build_types - - - -$tr_builds - -
Variables
Build type
-''') - -def generate_html_report( html_report_path, builds ): - report_dir = os.path.dirname( html_report_path ) - # Vertical axis: generator - # Horizontal: variables, then build_type - builds_by_generator = collections.defaultdict( list ) - variables = set() - build_types_by_variable = collections.defaultdict( set ) - build_by_pos_key = {} # { (generator, var_key, build_type): build } - for build in builds: - builds_by_generator[build.desc.generator].append( build ) - var_key = tuple(sorted(build.desc.variables)) - variables.add( var_key ) - build_types_by_variable[var_key].add( build.desc.build_type ) - pos_key = (build.desc.generator, var_key, build.desc.build_type) - build_by_pos_key[pos_key] = build - variables = sorted( variables ) - th_vars = [] - th_build_types = [] - for variable in variables: - build_types = sorted( build_types_by_variable[variable] ) - nb_build_type = len(build_types_by_variable[variable]) - th_vars.append( '%s' % (nb_build_type, cgi.escape( ' '.join( variable ) ) ) ) - for build_type in build_types: - th_build_types.append( '%s' % cgi.escape(build_type) ) - tr_builds = [] - for generator in sorted( builds_by_generator ): - tds = [ '%s\n' % cgi.escape( generator ) ] - for variable in variables: - build_types = sorted( build_types_by_variable[variable] ) - for build_type in build_types: - pos_key = (generator, variable, build_type) - build = build_by_pos_key.get(pos_key) - if build: - cmake_status = 'ok' if build.cmake_succeeded else 'FAILED' - build_status = 'ok' if build.build_succeeded else 'FAILED' - cmake_log_url = os.path.relpath( build.cmake_log_path, report_dir ) - build_log_url = os.path.relpath( build.build_log_path, report_dir ) - td = 'CMake: %s' % ( - build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status) - if build.cmake_succeeded: - td += '
Build: %s' % ( - build_log_url, build_status.lower(), build_status) - td += '' - else: - td = '' - tds.append( td ) - tr_builds.append( '%s' % '\n'.join( tds ) ) - html = HTML_TEMPLATE.substitute( - title='Batch build report', - th_vars=' '.join(th_vars), - th_build_types=' '.join( th_build_types), - tr_builds='\n'.join( tr_builds ) ) - with open( html_report_path, 'wt' ) as fhtml: - fhtml.write( html ) - print('HTML report generated in:', html_report_path) - -def main(): - usage = r"""%prog WORK_DIR SOURCE_DIR CONFIG_JSON_PATH [CONFIG2_JSON_PATH...] -Build a given CMake based project located in SOURCE_DIR with multiple generators/options.dry_run -as described in CONFIG_JSON_PATH building in WORK_DIR. - -Example of call: -python devtools\batchbuild.py e:\buildbots\jsoncpp\build . devtools\agent_vmw7.json -""" - from optparse import OptionParser - parser = OptionParser(usage=usage) - parser.allow_interspersed_args = True -# parser.add_option('-v', '--verbose', dest="verbose", action='store_true', -# help="""Be verbose.""") - parser.enable_interspersed_args() - options, args = parser.parse_args() - if len(args) < 3: - parser.error( "Missing one of WORK_DIR SOURCE_DIR CONFIG_JSON_PATH." ) - work_dir = args[0] - source_dir = args[1].rstrip('/\\') - config_paths = args[2:] - for config_path in config_paths: - if not os.path.isfile( config_path ): - parser.error( "Can not read: %r" % config_path ) - - # generate build variants - build_descs = [] - for config_path in config_paths: - build_descs_by_axis = load_build_variants_from_config( config_path ) - build_descs.extend( generate_build_variants( build_descs_by_axis ) ) - print('Build variants (%d):' % len(build_descs)) - # assign build directory for each variant - if not os.path.isdir( work_dir ): - os.makedirs( work_dir ) - builds = [] - with open( os.path.join( work_dir, 'matrix-dir-map.txt' ), 'wt' ) as fmatrixmap: - for index, build_desc in enumerate( build_descs ): - build_desc_work_dir = os.path.join( work_dir, '%03d' % (index+1) ) - builds.append( BuildData( build_desc, build_desc_work_dir, source_dir ) ) - fmatrixmap.write( '%s: %s\n' % (build_desc_work_dir, build_desc) ) - for build in builds: - build.execute_build() - html_report_path = os.path.join( work_dir, 'batchbuild-report.html' ) - generate_html_report( html_report_path, builds ) - print('Done') - - -if __name__ == '__main__': - main() - diff --git a/dependencies/jsoncpp/devtools/fixeol.py b/dependencies/jsoncpp/devtools/fixeol.py deleted file mode 100644 index 53af7612..00000000 --- a/dependencies/jsoncpp/devtools/fixeol.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import print_function -import os.path - -def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ): - """Makes sure that all sources have the specified eol sequence (default: unix).""" - if not os.path.isfile( path ): - raise ValueError( 'Path "%s" is not a file' % path ) - try: - f = open(path, 'rb') - except IOError as msg: - print("%s: I/O Error: %s" % (file, str(msg)), file=sys.stderr) - return False - try: - raw_lines = f.readlines() - finally: - f.close() - fixed_lines = [line.rstrip('\r\n') + eol for line in raw_lines] - if raw_lines != fixed_lines: - print('%s =>' % path, end=' ') - if not is_dry_run: - f = open(path, "wb") - try: - f.writelines(fixed_lines) - finally: - f.close() - if verbose: - print(is_dry_run and ' NEED FIX' or ' FIXED') - return True -## -## -## -##def _do_fix( is_dry_run = True ): -## from waftools import antglob -## python_sources = antglob.glob( '.', -## includes = '**/*.py **/wscript **/wscript_build', -## excludes = antglob.default_excludes + './waf.py', -## prune_dirs = antglob.prune_dirs + 'waf-* ./build' ) -## for path in python_sources: -## _fix_python_source( path, is_dry_run ) -## -## cpp_sources = antglob.glob( '.', -## includes = '**/*.cpp **/*.h **/*.inl', -## prune_dirs = antglob.prune_dirs + 'waf-* ./build' ) -## for path in cpp_sources: -## _fix_source_eol( path, is_dry_run ) -## -## -##def dry_fix(context): -## _do_fix( is_dry_run = True ) -## -##def fix(context): -## _do_fix( is_dry_run = False ) -## -##def shutdown(): -## pass -## -##def check(context): -## # Unit tests are run when "check" target is used -## ut = UnitTest.unit_test() -## ut.change_to_testfile_dir = True -## ut.want_to_see_test_output = True -## ut.want_to_see_test_error = True -## ut.run() -## ut.print_results() diff --git a/dependencies/jsoncpp/devtools/licenseupdater.py b/dependencies/jsoncpp/devtools/licenseupdater.py deleted file mode 100644 index 8cb71d73..00000000 --- a/dependencies/jsoncpp/devtools/licenseupdater.py +++ /dev/null @@ -1,94 +0,0 @@ -"""Updates the license text in source file. -""" -from __future__ import print_function - -# An existing license is found if the file starts with the string below, -# and ends with the first blank line. -LICENSE_BEGIN = "// Copyright " - -BRIEF_LICENSE = LICENSE_BEGIN + """2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -""".replace('\r\n','\n') - -def update_license( path, dry_run, show_diff ): - """Update the license statement in the specified file. - Parameters: - path: path of the C++ source file to update. - dry_run: if True, just print the path of the file that would be updated, - but don't change it. - show_diff: if True, print the path of the file that would be modified, - as well as the change made to the file. - """ - with open( path, 'rt' ) as fin: - original_text = fin.read().replace('\r\n','\n') - newline = fin.newlines and fin.newlines[0] or '\n' - if not original_text.startswith( LICENSE_BEGIN ): - # No existing license found => prepend it - new_text = BRIEF_LICENSE + original_text - else: - license_end_index = original_text.index( '\n\n' ) # search first blank line - new_text = BRIEF_LICENSE + original_text[license_end_index+2:] - if original_text != new_text: - if not dry_run: - with open( path, 'wb' ) as fout: - fout.write( new_text.replace('\n', newline ) ) - print('Updated', path) - if show_diff: - import difflib - print('\n'.join( difflib.unified_diff( original_text.split('\n'), - new_text.split('\n') ) )) - return True - return False - -def update_license_in_source_directories( source_dirs, dry_run, show_diff ): - """Updates license text in C++ source files found in directory source_dirs. - Parameters: - source_dirs: list of directory to scan for C++ sources. Directories are - scanned recursively. - dry_run: if True, just print the path of the file that would be updated, - but don't change it. - show_diff: if True, print the path of the file that would be modified, - as well as the change made to the file. - """ - from devtools import antglob - prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist' - for source_dir in source_dirs: - cpp_sources = antglob.glob( source_dir, - includes = '''**/*.h **/*.cpp **/*.inl''', - prune_dirs = prune_dirs ) - for source in cpp_sources: - update_license( source, dry_run, show_diff ) - -def main(): - usage = """%prog DIR [DIR2...] -Updates license text in sources of the project in source files found -in the directory specified on the command-line. - -Example of call: -python devtools\licenseupdater.py include src -n --diff -=> Show change that would be made to the sources. - -python devtools\licenseupdater.py include src -=> Update license statement on all sources in directories include/ and src/. -""" - from optparse import OptionParser - parser = OptionParser(usage=usage) - parser.allow_interspersed_args = False - parser.add_option('-n', '--dry-run', dest="dry_run", action='store_true', default=False, - help="""Only show what files are updated, do not update the files""") - parser.add_option('--diff', dest="show_diff", action='store_true', default=False, - help="""On update, show change made to the file.""") - parser.enable_interspersed_args() - options, args = parser.parse_args() - update_license_in_source_directories( args, options.dry_run, options.show_diff ) - print('Done') - -if __name__ == '__main__': - import sys - import os.path - sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - main() - diff --git a/dependencies/jsoncpp/devtools/tarball.py b/dependencies/jsoncpp/devtools/tarball.py deleted file mode 100644 index ccbda394..00000000 --- a/dependencies/jsoncpp/devtools/tarball.py +++ /dev/null @@ -1,53 +0,0 @@ -import os.path -import gzip -import tarfile - -TARGZ_DEFAULT_COMPRESSION_LEVEL = 9 - -def make_tarball(tarball_path, sources, base_dir, prefix_dir=''): - """Parameters: - tarball_path: output path of the .tar.gz file - sources: list of sources to include in the tarball, relative to the current directory - base_dir: if a source file is in a sub-directory of base_dir, then base_dir is stripped - from path in the tarball. - prefix_dir: all files stored in the tarball be sub-directory of prefix_dir. Set to '' - to make them child of root. - """ - base_dir = os.path.normpath( os.path.abspath( base_dir ) ) - def archive_name( path ): - """Makes path relative to base_dir.""" - path = os.path.normpath( os.path.abspath( path ) ) - common_path = os.path.commonprefix( (base_dir, path) ) - archive_name = path[len(common_path):] - if os.path.isabs( archive_name ): - archive_name = archive_name[1:] - return os.path.join( prefix_dir, archive_name ) - def visit(tar, dirname, names): - for name in names: - path = os.path.join(dirname, name) - if os.path.isfile(path): - path_in_tar = archive_name(path) - tar.add(path, path_in_tar ) - compression = TARGZ_DEFAULT_COMPRESSION_LEVEL - tar = tarfile.TarFile.gzopen( tarball_path, 'w', compresslevel=compression ) - try: - for source in sources: - source_path = source - if os.path.isdir( source ): - os.path.walk(source_path, visit, tar) - else: - path_in_tar = archive_name(source_path) - tar.add(source_path, path_in_tar ) # filename, arcname - finally: - tar.close() - -def decompress( tarball_path, base_dir ): - """Decompress the gzipped tarball into directory base_dir. - """ - # !!! This class method is not documented in the online doc - # nor is bz2open! - tar = tarfile.TarFile.gzopen(tarball_path, mode='r') - try: - tar.extractall( base_dir ) - finally: - tar.close() diff --git a/dependencies/jsoncpp/doc/doxyfile.in b/dependencies/jsoncpp/doc/doxyfile.in deleted file mode 100644 index a4161865..00000000 --- a/dependencies/jsoncpp/doc/doxyfile.in +++ /dev/null @@ -1,2302 +0,0 @@ -# Doxyfile 1.8.5 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = "JsonCpp" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = %JSONCPP_VERSION% - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = %DOC_TOPDIR% - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- -# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, -# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, -# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, -# Turkish, Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = %TOPDIR% - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = %TOPDIR%/include - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 3 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = "testCaseSetup=\link CppUT::TestCase::setUp() setUp()\endlink" \ - "testCaseRun=\link CppUT::TestCase::run() run()\endlink" \ - "testCaseTearDown=\link CppUT::TestCase::tearDown() tearDown()\endlink" \ - "json_ref=JSON (JavaScript Object Notation)" - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. -# -# Note For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be -# included in the documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = YES - -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = YES - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. -# The default value is: YES. - -GENERATE_TESTLIST = NO - -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = NO - -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = %WARNING_LOG_PATH% - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. -# Note: If this tag is empty the current directory is searched. - -INPUT = ../include \ - ../src/lib_json \ - . - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. - -FILE_PATTERNS = *.h \ - *.cpp \ - *.inl \ - *.dox - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = NO - -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = %HTML_OUTPUT% - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = header.html - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = footer.html - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = YES - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = %HTML_HELP% - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = jsoncpp-%JSONCPP_VERSION%.chm - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = "c:\Program Files\HTML Help Workshop\hhc.exe" - -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = YES - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = YES - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = YES - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , /