From a40b7ba4d7a9a93bb4eff8cff3417c70516eb408 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 3 Jul 2024 14:11:43 +0200 Subject: [PATCH 01/10] Fix support interface: Don't confuse the first support layer with raft if there's none. supermerill/SuperSlicer/issues#778 --- src/libslic3r/SupportMaterial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 692f13ee7ad..bec29405624 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -4142,7 +4142,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( float raft_angle_1st_layer = 0.f; float raft_angle_base = 0.f; float raft_angle_interface = 0.f; - size_t raft_top_interface_idx = m_slicing_params->interface_raft_layers == 0 ? 0 : (m_slicing_params->base_raft_layers + m_slicing_params->interface_raft_layers - 1); + size_t raft_top_interface_idx = m_slicing_params->interface_raft_layers == 0 ? size_t(-1) : (m_slicing_params->base_raft_layers + m_slicing_params->interface_raft_layers - 1); if (m_slicing_params->base_raft_layers > 1) { // There are all raft layer types (1st layer, base, interface & contact layers) available. raft_angle_1st_layer = m_support_params.interface_angle; From 28825b35a4e5a4b42b1c0854d3f7beadfc01c8ab Mon Sep 17 00:00:00 2001 From: wschadow Date: Wed, 3 Jul 2024 23:16:20 +0200 Subject: [PATCH 02/10] only start manually --- .github/workflows/ccpp_mac.yml | 7 +------ .github/workflows/ccpp_mac_arm.yml | 7 +------ .github/workflows/ccpp_mac_arm_debug.yml | 4 +--- .github/workflows/ccpp_mac_arm_rc.yml | 4 +--- .github/workflows/ccpp_mac_debug.yml | 4 +--- .github/workflows/ccpp_mac_rc.yml | 5 +---- .github/workflows/ccpp_ubuntu.yml | 7 +------ .github/workflows/ccpp_ubuntu_debug.yml | 4 +--- .github/workflows/ccpp_ubuntu_gtk3.yml | 7 +------ .github/workflows/ccpp_ubuntu_gtk3_debug.yml | 6 ++---- .github/workflows/ccpp_ubuntu_gtk3_rc.yml | 4 +--- .github/workflows/ccpp_ubuntu_rc.yml | 4 +--- .github/workflows/ccpp_win.yml | 8 ++------ .github/workflows/ccpp_win_debug.yml | 8 +++----- .github/workflows/ccpp_win_deps.yml | 6 ++---- .github/workflows/ccpp_win_rc.yml | 6 ++---- 16 files changed, 22 insertions(+), 69 deletions(-) diff --git a/.github/workflows/ccpp_mac.yml b/.github/workflows/ccpp_mac.yml index b198e85a7fb..64f3e0d6317 100644 --- a/.github/workflows/ccpp_mac.yml +++ b/.github/workflows/ccpp_mac.yml @@ -1,12 +1,7 @@ name: C/C++ Nightly macos on: - push: - branches: - - Nigthly - - nightly_dev - - nightly_master - - debug_macos + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_mac_arm.yml b/.github/workflows/ccpp_mac_arm.yml index 090671cc17d..06aa977cc15 100644 --- a/.github/workflows/ccpp_mac_arm.yml +++ b/.github/workflows/ccpp_mac_arm.yml @@ -1,12 +1,7 @@ name: C/C++ Nightly arm macos on: - push: - branches: - - Nigthly - - nightly_dev - - nightly_master - - debug_macos + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_mac_arm_debug.yml b/.github/workflows/ccpp_mac_arm_debug.yml index 10b4e1ce387..6ebcbcd2309 100644 --- a/.github/workflows/ccpp_mac_arm_debug.yml +++ b/.github/workflows/ccpp_mac_arm_debug.yml @@ -1,9 +1,7 @@ name: C/C++ debug arm macos on: - push: - branches: - - debug_macos + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_mac_arm_rc.yml b/.github/workflows/ccpp_mac_arm_rc.yml index 0fbba7b9c21..63fff23144a 100644 --- a/.github/workflows/ccpp_mac_arm_rc.yml +++ b/.github/workflows/ccpp_mac_arm_rc.yml @@ -1,9 +1,7 @@ name: C/C++ Release candidate arm macos on: - push: - branches: - - rc + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_mac_debug.yml b/.github/workflows/ccpp_mac_debug.yml index f43b8296a03..f3cb71e5478 100644 --- a/.github/workflows/ccpp_mac_debug.yml +++ b/.github/workflows/ccpp_mac_debug.yml @@ -1,9 +1,7 @@ name: C/C++ debug macos on: - push: - branches: - - debug_macos + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_mac_rc.yml b/.github/workflows/ccpp_mac_rc.yml index 972bf701623..530ffb09cb8 100644 --- a/.github/workflows/ccpp_mac_rc.yml +++ b/.github/workflows/ccpp_mac_rc.yml @@ -1,10 +1,7 @@ name: C/C++ Release candidate macos on: - push: - branches: - - rc - - debug_macos + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_ubuntu.yml b/.github/workflows/ccpp_ubuntu.yml index 363cdba227c..8b2663029f7 100644 --- a/.github/workflows/ccpp_ubuntu.yml +++ b/.github/workflows/ccpp_ubuntu.yml @@ -1,12 +1,7 @@ name: C/C++ Nightly ubuntu on: - push: - branches: - - Nigthly - - nightly_dev - - nightly_master - - debug_ubuntu + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_ubuntu_debug.yml b/.github/workflows/ccpp_ubuntu_debug.yml index 824b34b4af4..972c7281980 100644 --- a/.github/workflows/ccpp_ubuntu_debug.yml +++ b/.github/workflows/ccpp_ubuntu_debug.yml @@ -1,9 +1,7 @@ name: C/C++ debug ubuntu on: - push: - branches: - - debug_ubuntu + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_ubuntu_gtk3.yml b/.github/workflows/ccpp_ubuntu_gtk3.yml index 6bcf54eb255..d6867a01d56 100644 --- a/.github/workflows/ccpp_ubuntu_gtk3.yml +++ b/.github/workflows/ccpp_ubuntu_gtk3.yml @@ -1,12 +1,7 @@ name: C/C++ Nightly ubuntu-GTK3 on: - push: - branches: - - Nigthly - - nightly_dev - - nightly_master - - debug_ubuntu + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_ubuntu_gtk3_debug.yml b/.github/workflows/ccpp_ubuntu_gtk3_debug.yml index c8c4d69bd55..03f44588738 100644 --- a/.github/workflows/ccpp_ubuntu_gtk3_debug.yml +++ b/.github/workflows/ccpp_ubuntu_gtk3_debug.yml @@ -1,9 +1,7 @@ name: C/C++ debug ubuntu-GTK3 on: - push: - branches: - - debug_ubuntu + workflow_dispatch: jobs: build: @@ -47,4 +45,4 @@ jobs: with: name: ${{ github.event.repository.name }}-gtk3.AppImage path: build/${{ github.event.repository.name }}_ubu64.AppImage - + diff --git a/.github/workflows/ccpp_ubuntu_gtk3_rc.yml b/.github/workflows/ccpp_ubuntu_gtk3_rc.yml index 70c07c82277..cc68b9d7189 100644 --- a/.github/workflows/ccpp_ubuntu_gtk3_rc.yml +++ b/.github/workflows/ccpp_ubuntu_gtk3_rc.yml @@ -1,9 +1,7 @@ name: C/C++ Release candidate ubuntu-GTK3 on: - push: - branches: - - rc + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_ubuntu_rc.yml b/.github/workflows/ccpp_ubuntu_rc.yml index a8412e7a131..3e16ed8e4ea 100644 --- a/.github/workflows/ccpp_ubuntu_rc.yml +++ b/.github/workflows/ccpp_ubuntu_rc.yml @@ -1,9 +1,7 @@ name: C/C++ Release candidate ubuntu on: - push: - branches: - - rc + workflow_dispatch: jobs: build: diff --git a/.github/workflows/ccpp_win.yml b/.github/workflows/ccpp_win.yml index 6ede51d046f..7410dcd44b0 100644 --- a/.github/workflows/ccpp_win.yml +++ b/.github/workflows/ccpp_win.yml @@ -1,17 +1,13 @@ name: C/C++ Nightly windows x64 on: - push: - branches: - - Nigthly - - nightly_dev - - nightly_master + workflow_dispatch: jobs: build: runs-on: windows-2019 - + steps: - uses: actions/checkout@v1 - uses: ilammy/msvc-dev-cmd@v1 diff --git a/.github/workflows/ccpp_win_debug.yml b/.github/workflows/ccpp_win_debug.yml index fe6abf9cb46..e2e5fead6a2 100644 --- a/.github/workflows/ccpp_win_debug.yml +++ b/.github/workflows/ccpp_win_debug.yml @@ -1,15 +1,13 @@ name: C/C++ debug windows x64 on: - push: - branches: - - debug_win + workflow_dispatch: jobs: build_pot: runs-on: windows-2019 - + steps: - uses: actions/checkout@v1 - uses: ilammy/msvc-dev-cmd@v1 @@ -77,7 +75,7 @@ jobs: build: runs-on: windows-2019 needs: build_dep - + steps: - uses: actions/checkout@v1 - uses: ilammy/msvc-dev-cmd@v1 diff --git a/.github/workflows/ccpp_win_deps.yml b/.github/workflows/ccpp_win_deps.yml index 9155f24fd8f..38b203ec064 100644 --- a/.github/workflows/ccpp_win_deps.yml +++ b/.github/workflows/ccpp_win_deps.yml @@ -1,9 +1,7 @@ name: C/C++ dep build windows x64 on: - push: - branches: - - debug_win + workflow_dispatch: jobs: build_dep: @@ -28,7 +26,7 @@ jobs: build: runs-on: windows-2019 needs: build_dep - + steps: - uses: actions/checkout@v1 - uses: ilammy/msvc-dev-cmd@v1 diff --git a/.github/workflows/ccpp_win_rc.yml b/.github/workflows/ccpp_win_rc.yml index ea5f0563844..450509f8b44 100644 --- a/.github/workflows/ccpp_win_rc.yml +++ b/.github/workflows/ccpp_win_rc.yml @@ -1,15 +1,13 @@ name: C/C++ Release candidate windows x64 on: - push: - branches: - - rc + workflow_dispatch: jobs: build: runs-on: windows-2019 - + steps: - uses: actions/checkout@v1 - uses: ilammy/msvc-dev-cmd@v1 From 9717a868c1dc98da84d84c825c14757de28d1b05 Mon Sep 17 00:00:00 2001 From: wschadow Date: Wed, 3 Jul 2024 23:16:37 +0200 Subject: [PATCH 03/10] adds a file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d1ee7ca9522..56329de85d7 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ local-lib build* deps/build* deps/deps-* +cmake/CPackConfig.cmake # MacOS Ignores .DS_Store From bb1e81e4f628eb6692ef180570e9f6b5ebb5b57e Mon Sep 17 00:00:00 2001 From: Wolfgang Schadow Date: Thu, 4 Jul 2024 18:41:48 +0200 Subject: [PATCH 04/10] includes .mo files, some updates to build files --- BuildLinux.sh | 2 +- cmake/CPackConfig.cmake | 70 ++++++++++++++++++ resources/localization/ca/SuperSlicer.mo | Bin 0 -> 273285 bytes resources/localization/cs/SuperSlicer.mo | Bin 0 -> 442401 bytes resources/localization/de/SuperSlicer.mo | Bin 0 -> 275835 bytes resources/localization/en/SuperSlicer.mo | Bin 0 -> 7028 bytes resources/localization/es/SuperSlicer.mo | Bin 0 -> 275384 bytes resources/localization/fr/SuperSlicer.mo | Bin 0 -> 532128 bytes resources/localization/hu/SuperSlicer.mo | Bin 0 -> 450930 bytes resources/localization/it/SuperSlicer.mo | Bin 0 -> 566749 bytes resources/localization/ja/SuperSlicer.mo | Bin 0 -> 291893 bytes resources/localization/ko/SuperSlicer.mo | Bin 0 -> 170236 bytes resources/localization/ko_KR/SuperSlicer.mo | Bin 0 -> 219703 bytes resources/localization/nl/SuperSlicer.mo | Bin 0 -> 256228 bytes resources/localization/pl/SuperSlicer.mo | Bin 0 -> 272421 bytes resources/localization/pt_BR/SuperSlicer.mo | Bin 0 -> 218455 bytes resources/localization/ru/SuperSlicer.mo | Bin 0 -> 361382 bytes resources/localization/tr/SuperSlicer.mo | Bin 0 -> 131390 bytes resources/localization/uk/SuperSlicer.mo | Bin 0 -> 283802 bytes resources/localization/zh_CN/SuperSlicer.mo | Bin 0 -> 390528 bytes .../localization/zh_TW_copy/SuperSlicer.mo | Bin 0 -> 103368 bytes version.inc | 2 +- 22 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 cmake/CPackConfig.cmake create mode 100644 resources/localization/ca/SuperSlicer.mo create mode 100644 resources/localization/cs/SuperSlicer.mo create mode 100644 resources/localization/de/SuperSlicer.mo create mode 100644 resources/localization/en/SuperSlicer.mo create mode 100644 resources/localization/es/SuperSlicer.mo create mode 100644 resources/localization/fr/SuperSlicer.mo create mode 100644 resources/localization/hu/SuperSlicer.mo create mode 100644 resources/localization/it/SuperSlicer.mo create mode 100644 resources/localization/ja/SuperSlicer.mo create mode 100644 resources/localization/ko/SuperSlicer.mo create mode 100644 resources/localization/ko_KR/SuperSlicer.mo create mode 100644 resources/localization/nl/SuperSlicer.mo create mode 100644 resources/localization/pl/SuperSlicer.mo create mode 100644 resources/localization/pt_BR/SuperSlicer.mo create mode 100644 resources/localization/ru/SuperSlicer.mo create mode 100644 resources/localization/tr/SuperSlicer.mo create mode 100644 resources/localization/uk/SuperSlicer.mo create mode 100644 resources/localization/zh_CN/SuperSlicer.mo create mode 100644 resources/localization/zh_TW_copy/SuperSlicer.mo diff --git a/BuildLinux.sh b/BuildLinux.sh index 45f01e7f4f7..68d05131a38 100755 --- a/BuildLinux.sh +++ b/BuildLinux.sh @@ -1,7 +1,7 @@ #!/bin/bash export ROOT=`pwd` -export NCORES=`nproc --all` +export NCORES=`nproc` FOUND_GTK2=$(dpkg -l libgtk* | grep gtk2) FOUND_GTK3=$(dpkg -l libgtk* | grep gtk-3) diff --git a/cmake/CPackConfig.cmake b/cmake/CPackConfig.cmake new file mode 100644 index 00000000000..940f88b8ca9 --- /dev/null +++ b/cmake/CPackConfig.cmake @@ -0,0 +1,70 @@ +# This file will be configured to contain variables for CPack. These variables +# should be set in the CMake list file of the project before CPack module is +# included. The list of available CPACK_xxx variables and their associated +# documentation may be obtained using +# cpack --help-variable-list +# +# Some variables are common to all generators (e.g. CPACK_PACKAGE_NAME) +# and some are specific to a generator +# (e.g. CPACK_NSIS_EXTRA_INSTALL_COMMANDS). The generator specific variables +# usually begin with CPACK__xxxx. + + +set(CPACK_BUILD_SOURCE_DIRS "/home/wschadow/github/Software/Slicer/SuperSlicer;/home/wschadow/github/Software/Slicer/SuperSlicer/build") +set(CPACK_CMAKE_GENERATOR "Unix Makefiles") +set(CPACK_COMPONENTS_ALL "Devel;Unspecified") +set(CPACK_COMPONENT_UNSPECIFIED_HIDDEN "TRUE") +set(CPACK_COMPONENT_UNSPECIFIED_REQUIRED "TRUE") +set(CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE "/usr/share/cmake-3.25/Templates/CPack.GenericDescription.txt") +set(CPACK_DEFAULT_PACKAGE_DESCRIPTION_SUMMARY "Slic3r built using CMake") +set(CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE "ON") +set(CPACK_GENERATOR "STGZ;TGZ;TZ") +set(CPACK_INSTALL_CMAKE_PROJECTS "/home/wschadow/github/Software/Slicer/SuperSlicer/build;Slic3r;ALL;/") +set(CPACK_INSTALL_PREFIX "/usr/local") +set(CPACK_MODULE_PATH "/home/wschadow/github/Software/Slicer/SuperSlicer/cmake/modules/") +set(CPACK_NSIS_DISPLAY_NAME "SuperSlicer 2.5.59") +set(CPACK_NSIS_DISPLAY_NAME_SET "TRUE") +set(CPACK_NSIS_INSTALLER_ICON_CODE "") +set(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "") +set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") +set(CPACK_NSIS_PACKAGE_NAME "SuperSlicer 2.5.59") +set(CPACK_NSIS_UNINSTALL_NAME "Uninstall") +set(CPACK_OBJCOPY_EXECUTABLE "/usr/bin/objcopy") +set(CPACK_OBJDUMP_EXECUTABLE "/usr/bin/objdump") +set(CPACK_OUTPUT_CONFIG_FILE "/home/wschadow/github/Software/Slicer/SuperSlicer/cmake/CPackConfig.cmake") +set(CPACK_PACKAGE_DEFAULT_LOCATION "/") +set(CPACK_PACKAGE_DESCRIPTION_FILE "/home/wschadow/github/Software/Slicer/SuperSlicer/README.md") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CMake is a build tool") +set(CPACK_PACKAGE_EXECUTABLES "superslicer") +set(CPACK_PACKAGE_FILE_NAME "SuperSlicer-2.5.59-Linux-x86_64") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "SuperSlicer 2.5.59") +set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "SuperSlicer_2.5.60.0_2024-07-01") +set(CPACK_PACKAGE_NAME "SuperSlicer") +set(CPACK_PACKAGE_RELOCATABLE "true") +set(CPACK_PACKAGE_VENDOR "SuperSlicer") +set(CPACK_PACKAGE_VERSION "2.5.60.0") +set(CPACK_PACKAGE_VERSION_MAJOR "2") +set(CPACK_PACKAGE_VERSION_MINOR "0") +set(CPACK_PACKAGE_VERSION_PATCH "0") +set(CPACK_READELF_EXECUTABLE "/usr/bin/readelf") +set(CPACK_RESOURCE_FILE_LICENSE "/home/wschadow/github/Software/Slicer/SuperSlicer/LICENSE") +set(CPACK_RESOURCE_FILE_README "/home/wschadow/github/Software/Slicer/SuperSlicer/README.md") +set(CPACK_RESOURCE_FILE_WELCOME "/home/wschadow/github/Software/Slicer/SuperSlicer/README.md") +set(CPACK_SET_DESTDIR "OFF") +set(CPACK_SOURCE_GENERATOR "TGZ;TZ") +set(CPACK_SOURCE_OUTPUT_CONFIG_FILE "/home/wschadow/github/Software/Slicer/SuperSlicer/build/CPackSourceConfig.cmake") +set(CPACK_SOURCE_PACKAGE_FILE_NAME "SuperSlicer-2.5.60.0") +set(CPACK_SOURCE_STRIP_FILES "") +set(CPACK_STRIP_FILES "bin/superslicer") +set(CPACK_SYSTEM_NAME "Linux-x86_64") +set(CPACK_THREADS "1") +set(CPACK_TOPLEVEL_TAG "Linux-x86_64") +set(CPACK_WIX_SIZEOF_VOID_P "8") + +if(NOT CPACK_PROPERTIES_FILE) + set(CPACK_PROPERTIES_FILE "/home/wschadow/github/Software/Slicer/SuperSlicer/build/CPackProperties.cmake") +endif() + +if(EXISTS ${CPACK_PROPERTIES_FILE}) + include(${CPACK_PROPERTIES_FILE}) +endif() diff --git a/resources/localization/ca/SuperSlicer.mo b/resources/localization/ca/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..2b7927e5a0eff54fbec43027addabc167208b4a4 GIT binary patch literal 273285 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≤|m^?Iv8~Q|zPG+(?GqK17TA6{#Z7|c?N7}eZ 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%0AtI;UdjwD<#U<@c*Sf*cjep$(X1k>ga$-H5APz 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%0ALj8kX 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 literal 0 HcmV?d00001 diff --git a/resources/localization/en/SuperSlicer.mo b/resources/localization/en/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..281689abcab57079a1ad44e44be369360beb9dce GIT binary patch literal 7028 zcmd^@O^h5z6~_y(fehg*n6HSB63Fr{+8M?ULD8Z}*s%#K?aC$|6LH{B(_J%D-tMkW zSNG12;Ytt^S8fR901_82+=vh-I3a-q5(k75AucEZPH+JU@q5)hv$K&2C>VPUEzka^ zr>kGR_kUmY{K7-0zM;4t=JNqQf8cYL&ktY6AFgY!SL%82bKsA_2j8HS0e=cU3ieMa zbp}kpcYufBN5QXwkAvR>H^7&{)5tt?TB#SgfB20`{T}=)_+#*QZ&GR({O+5T`VjaR z@Mqwe2b5aKbMQIvi#?^D1^*6y8~n;!l=>w2u?LlUH)z0%;2it~_yh1y;Md>U?(?O$ zwf21a?X5k31IIjn9_2;O2jAJs8G$@fH$k!I7AW?73p@w@20Vp5ryf%3x7hY2HE5#D^1yJlM z!C!*k2mc5@i^JGnajP&*L1W|}+TsOW@e&(QNuB0{Xa!x-*MLIxc(L`d3u+bah!=Dz zOkG{j887j<=tmeRLL+jIi&0jOz0a&Ev^^{<8-nwNZh|YOx}I5`_+sLwO=W8N{lH|6 z4cbpM>rGO-1FOr*6*YhT#ASA%cP6~&!n!moubG+`Yp?67v0Lqu?j6l)wh1n^l}-7Y zm+Usqte(4i7PYwTR(D8sTir$F*EUlZ)6@y8Cd(Gu=&?!mn^K3ulwsy;Az2(SpW&TX zxIqZ3ER3dlY$v|5;*O?F`9;VyWtlmf4%Ee__ETHf&UPF17nqo)<+^b*ZUqoTe`psUF$GT0h}4Uj=>HhNN<(7^W^; zyjm~B6hzw!Q~5%iWLwMlU>8?JLn~8Etsb7$eSLm7JUdXAeQ~bVg|FQNe#XAx#?EzR ziPk_cnPQ=Hj8}x5EervZZt1g7GqcHl(C`x1M>di!er+Z3O#~O2D~Q&oXO=*Y>kisy zFiHf9_yglIk-8-dL<`qRf#TGKGBXRbH+9s$5DM0}3bmwmfgVY!@DF_?299l$+hk@67xJ*h18s0-ju{DrAw0`klSCPhDX(N9_46Y0CJkL+ z#H<}RF01hZ^B?Wx2jRf=lV3a%@2V6$ld+*GL)v9{(N*J7Y=1YW@(kXlMT zlM*ITNEWo-=LLvl1==KJl8eQ5Rpp}8fx0@rX_LC$8-tpFHL_<@ksq>W;cwkSw3(1n zxZ%hySr$;1)aH>R+v*u~&V7?Xi0nRhc-4}!L}uso`4NwX2dS0P!m7?jmy;%v+YMB9 zHOWT}g;}WvZ08Oo6UZ5{y~%2fD6GbG$xq!b*LVu0X)x15R!hU_XpUNnWv%nb7Ec0- zLuXhsP)}KWK)1oCySA9p6gEaHXKt$NABDLEl2 zWDTUy$+R>(_#C?_QG>NHDJ8UXD-5T0LahjT=I451s_25mNL zT}bvMnI}4=@!3Von<$xEd@2ZG@(JfiMUdql~Vc=3N5%Uv<-0)CZ$ zdwa{w3+hI(U(h-@Csc6Ylca$=_4H?VMpyKu8@sz#M%r;&BeqiMhtMuOUcu8(a z8bcx2M6k4&fr<@b6%9GhTz_fjGI_gmA?s^GrmHWx*|++7=8{K9J?duWpc1w{4J9K4 zCAhi@BXKUhlw4l4Ygkz6jSJMZm;=j#B|=IF?UtPn^_G5w(*7?N5fZ5uVYW^-JCjgW z)VgIWAG2GI2DKcTq5|t7k)v^{Cl!gpKKr6K*%Xg}%aE6bE&ahBQtrqtu`}R0sjYDQ5>+Bl2a1=puq;Z|YYiwT;l@ zP`NBV1k|<4OJnNqr2WsgXQl1VFTHD5`%l?}*v|Tw35sofVR+#}fB1?1`A79|xIG;9 zc1@`JBMy0igNv`W`JtFLoPzozYx3>h-p<~YBe~}X!`>5~8e8zvqC{X#w0@j3mn%NS z3C~pU{`ig2XZnvFtrOv#A^KMeDhnoU>&M2fUTw5(iykw>CGz4v9e3`8>Uj3<&1!3# z9UFJ#Nc~@$cl495Y2eXq*S-D3b8O&|8gS1Bp8tz^=N^nZocaEpnSJu79(}LIo)b9rFimBPyD|0LCu7gDDxK`P=ieH9 Y`rUt}b%Rg;e}3>8+^3VzYae|60cW;M@Bjb+ literal 0 HcmV?d00001 diff --git a/resources/localization/es/SuperSlicer.mo b/resources/localization/es/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..389842a5fa2fe4704b5839026bb08cb516d1c7a1 GIT binary patch literal 275384 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

NwSkeb*5@C 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 zú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

YA;- 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̽}dWr#r-*qbuX4WG#IJCu5Do^K0K?kM}b?-JoOW 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 z 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 WD7T+W3{x&G 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%0A4k|=Ke6K6w{=f+LbuSN7!|fa zDox?13Od0KsM0Y|J4_W6vBQ*5Bu5F~Biwj)fT@|?4WwbwlD-AkyK%GXjc0cMgN8INhmfBFKb z$*U26gscM3o4$0;y)8%rkXg?tQFZTP5J^-VE|^bx zo7SR?Xlo!wv%bjK(cZgqRWjae50=t?b>2ErMb;rGTof=7Og5aa=?ECWXY$6Q8nGj* z!33*v@%Ra*cgSK!yeyXu&twso%7BML0jdX*0Kf z@aZ0k<9(RIS13%30Cz8bA|k@iV^rX`eS|vvM%GX0WML;*5@!2OAm7bFArWD<(=)Qn z;WsN|*D7R$CC=$!XyCMbZa&Gh86^uYnALAmD>wx@fIN3iwFp^`qu{N;WLN=#K$3yM z9S8(IRjncY=2I*hP%S(17dn-p)Kv9|oY*DQJ*N+}O+_UJr+kT~cm)-iy z*?*aTeehx*dJ>Py(KI2z)%|h+jDNu%7f|SRxVw(3n{^y8Qm$%%Gz9eu(`*5G{L%=t z*Ee6LtP8m)cWHRig_`C&=o)vPGAhC+h&5%<;AJMB@mxxY<`#3K-b?44N_Y8AEHYkT z)ITgQsZl{vnM-f0X{!_f`ze&~w&cpnVRyfW%8?u;{6_aNho#%Wy#(WGYE+OX0CJdZ zclO!hCDttbbZoYQj)0#My3a3YJ6(5fOktb%>8Syl7ye!vCX^XG`5*Ix)06i&Cy_}@ z3F0EpgN1!-5imwb9NF!L_9HpSY3lug`3b{n6Vb_F_OXdYPB9Tyd;(Zynr!^S0Jn)H z@24EOZ7{FboK;XlyzxVHZAHwfr3|PIV!_sg`dSnCAHqT^noW4I-GFjXO{VAf&s47} z=B+6b5?MC(bUVW2?4$D>y4ERBAT8;bR^viG6;g1*u>jSw=|DlK`SB41|2x@WMZ)^* z#o|x!HAi4lHFS~-x4pi@z=&H)EyVc+1_=ZUQUDM9>N>JeeVyBHDNBP0yv`pkOb2op zsE>ARW2qZN>EtTK9Z`i|YXsM3V`#AxO{GI-SKhPjb@G}=lO+KmbII-?xV9h;Dc*q;l zG;zysp?dHla2hTGvRY8D(iK92XKIYNa1X}sY*=M21UnpuByFUKG*RZi94=n*PY3H+ zBl|u3>pz2{;4IAbNS1_@{l=N?;Sq;GB}-X;iuM#%)V9hrmACPSZF7xn{U_?5F26 zOLKqWecq3jAYmD%5DxdXptnIb0$}{1eaGJ3b@&62-`vE9vXh%HVKe6yv z`_J(en6IKz9MMsNPSL9m(Fm7c9?9+QN35K^WDHOT0R3=g@~}DOAA<#BZTTe`3_8F{ z!u@4iU_^e_fpLJ}1QqX-dT}E-YFD#64?e#B{)3N=ft>mf_T3qy_i7g?*G+BKSV6d2 za@STqT9{UR%H>eG>h{5xi$6&lmZG-t6~I8Q-g5Tk{E1#ucJcdMTefMmi@yqZS!?R! zwqyoFxw7GrH^gitqNEC5!kg4i`5_=|EXR znk<8+XU66>&MrgciPm|Pk$^xUxkC|OA*dLWd>AMU{aW5Mt0$!pa)b^$NVE$3nswGy z^ceW3|6fsAmGrm-SzFV{~|Zwfm~r$Cy== zuZJ0hT~&Q&*53Ol%!d_ko^^U459UUQ8>b-1h@r8+W%p?OA&=Tb7nh&1ERwBH&rYdt zjpo}hKgUREhM`;JlRkl11U3)+*;MV2T@G{s90$qOp@?|pU&V7??4RVyB`8U0If}>P=*JPy7 zC-wEM^=axM2LR3K1$Bq?II^5->6Gnk9<+a_&xZF|uAd2Hmw)nxi3Njm7uR>MSC|GS zxQv!90?5XNt$nkywAU;tU}z|`?QmwVKdp3K#kUhk@M&MnhI5{LS$k2(wyj4v?5$#~ zR?ofW$)^nWj4qIqp1V5F47hTL@D6i>)ln5BaFOBgPSnv`_HvBw^3q>>SmvZ{O?TWmQr|hFc|D zvakM)_;;cWo)*>oMK!ysFb9+Mt%J_Rp16HHuQ{VH>(#ZXrFBSq&`^ zH-9+25dm4N6YmlEY3&MDmnE-xWTk`#J=(t?siUX(FP)#&&9TC!ne;l2>YlKR>;LOYZUV3DR3k;SbbO3hn;!@)6<HO??_sU$T5O(MUpAf4W!Y>YKj}iyOn{ z|7AzEzLDx2F;0*yQ&F>7gGN4m_y-gyZTM9@=BQqgkOfXcn`m+{1!-(5X@n(*A14(O zf=NS@Tn>=;?W~nsa#XqGnAD)cc1FTbV8RGzAhu<}!3GsG#0snFWpDarXZC}23M3Hf z3rnwE;0JDC4#?S$3y=$d_)MOrG6;ic$8k*tGEqFbJhc&MkpaUwNR#I#lDo?zx*=fD za%!-rN@GQVCLNU2eW{{4ITy8}?#D^H@HO39$BWRcb}!vs9;?)i!zH*L?bB|@&Dxhf za(cV|n%%nm9tWmGXl`1a-fP7mNk{6l$H>> zb|kx_630?(Q4UMd%Em z=_JZ*Q5$V2@>v?`SKg!kO(#Q=Z0$u!CLh~aDkMG zyUJ!3`yL1Ox#mZTPKFWEdK&;+#ob3q(2tCI5v)A<$QbCq%J~K-2PXP8SgBHVju%fVPej~3M_#mYN9O@}HjU6V>s9?*Pd{-UWT+P7 zSa;9JSC*T!hPP-Uv)tlNb>2<{9jAJO_Pa`2HSl8y^9Lw0@CVB! z40|YDBr?9c3U#|!c_(UrUjOz~P3p5gY_P6>EoVQLCz)&rnP)9Ya^=KLHxu`sk_hao z#`|SfG@?Pti0?ke(a*j{BJ|Bt@vV-hD@QFW_p_jJ; zBN^pV%9zn^l%vmQyC;Xbd078*g0;g@XUsD~49tQ?^oOthxHI#AxJDM$Xyl@RYvIG9 z6uUVqIV33{?cOkiQ?>DBx$q04xbP}E{yO?!bPGpQN2*{dM*MmSVM>6cea%rT5@m^_ z!w?=RlRFgwbG_<5sBy+`+sx8(b4aB^D4E8D*arvUSf;aI2YX|~^M`5KE5d&ujZ=0` z6;nNvH=d#8I6^~!*YXF0gy>VpTeAgzP=6I^#HdHu3Hy>z`d^s6AZ+Rrch`ZUfWWlk z*&Zj+E6gM7O6ntnp(GnhQv903He_`gx_S{A#sJjKf}pA>u}~va*1~XFx>7g5I!bM4 zdwld#zW;?Bjndqe_d~QzgsicwsK}Nj0wI>?5yNpQZ5_Qu|F0YPlKn}n_3l_CO)o(E z#nvOKqTXrzg88&O)_~>)l!$+=4w$D~pDFq;FcmOS%*)vVW)xwAobVy?%52r~NAW>~ z-dnwX>3(zJBV47Oh&3D#E1@-~4LRjEf=xij4_6#OvQ7z3uP?p2^OTpI^fd3)|WuYL9qJO@YZv^wTeGIel}i>=xT0Xdc6nEi@a3ceS3h4iWa zp?ltrr!ln}5jJ=1bou~>1l&M?^-!vlbQZZ2L#{zaofsE3DjI+0O}k=57_hX7|3+La z6=f7I>?wel2pHYzC2Q(?Icvgq#jkerxG-Cp3#`89A<3 zc4a5Zn%34TM++rQN@!IhM7J=tT-fw&`ciuKR-iO;t0hSwsjP>Ggoge6AoD?Xr4&eZ zyv3~Qc!5F?F~Wcl_8c@BsTK35&hWxu!@cIL(%AB3x_&aqZ6NphG3%8RmTB>oZ3nF5 z$H!)58Pndq^f5WqS?gRDFx@xE%VUw^k8OJ4k}P_ZCMh6ZhhAtpiiB$Bm1G~(I4jg% zDNMSpJU{aa?2a_D<2eC&tlOYkF-LqM)e#QsEObvK!z1f-d-Z`W`7z)UeUw@a*9{A=}hpFQx2{&B;s*^7%|KIoV5 zx#k3yo9lT6Rpsa(%r6Onl%PN|g>GB$rMPeq^tGkBfrPFdQ+z~DOtjUq%FG@)r%=?S zAIL>O7+BpUaC%T%j6#feGYpR>XNyBLV4b3T4~C-pld{%eXYd|h+aZlk$waV0``E%6 z3J)WjRGt?evSinhgf^1Y%D@~f-Y>QtS&A&4!YPM(*aqV^L!5t0ONu4SGGTB-Jl4Qp z>;%>9w^1qgGSyXu)=}dH9IO>Nz7zlp6TwQKd|-87i2O^eS7LpC_Fub6-Y2yXr*s!} z#_I46j^Mw+3tTqG+M9n{Z~nL4*&XU`0k*h(+D8-Qg^R>2S* z9zwi4p1@Z@QI#GvFI~VFV?<`35ipK#Fi|himsmQgkj*V+W>??`l=-J77#ftYL~c6m&z^zw2ju@SHhxwEDNH53x7FlowtRvi=wc;49^Wa4M>iL0 zXXcA`?g_nYGNDV_a{)_|CMY74VQ&utf14BVw?g;ew0CLkQ7l36ev6ArL~S#lI}yaK z>mZ$m2PKHs?dy@&3sLl+2Y5~{l&J11`q_>L@p5icbUpR<^x5MdQ>lOor2kRcs z9$CpNn_)0f@c;P5T=uf~BKp&ySeeE_O$92BpMELw^Y)vcoyrAig}#)?Hna@P8&_L# zrfh#oj55xHqlUdpJli3VV${dVFr1Y5j(9PedLX{_fV02;GZpP{96^ZLDmT3f&|wMv zKG}1E0F^Db17G6?W7|)9^*MBQiq9fj90A_EXF`*>w9!|7L;`AINtev33vmK%z=4k);&e^^2DOHoOuG z24OO0BXJY<(A0>xecbXx_c^$* zwguQ-=#^ZZS-J1(<;&|QwOH>bv^ps_)kIY5YdOy0dDjmlj6gngf6>H4`Qhl$4>amE?|LduDL1>hbzjz@FG{QKP??b-5W~Fb#tZ(sla$$mbTWsk zBYGkMq~4{{A$=@qO|&?A+CXV7KWj6{ZD@%A z6l+scJ?WozWHE<1`Ab4D-2Jw{^}u1A)MC=dD5W6$kHUotM9JU__4|q%_ebWp1_z~| zUqkZFXOI4T1fn%$`wQ;zU*i>FF8ez6XDiRq{{JjVy1+HjzuJZG52M(#b2!`1TD(RX z+uBNcwEEhBachmVqfduqEoG6RSJU%b#hkN!#JI(`k45Fze= zh7w*bKym8AxMslU-ar+w^S?hr3%33d%!0T$OuSDM< zdT<2xsf0?#!gdr_0fQ~AI94$Vc!w8-i?H(BOHOMP^Dxe$%sXkwvQ&`NcBpAj(VZ^1 zPN()h3f@B;^=i{=`oSA+*Jg~GKD1U$^-Sg+>y|2j|3wR=XLu`UF2Su49ihTLP^%nv z6_0ceMHSz$>3~ecZef@>Z=#!rfcXSx7{Nmo!|cvD(B`NPSR7YN3|vO4Hw-t`n7K|55XA=tgh>0I+ySD%;lZ51 zoJG@4_%#q02#b!5xJ>I#k3u{t;|k=p!=b+8-~ffGXU&A@aZFG{g_1V5WFe9N!OmfQfpa1N~ z3gAo3!gl1~WisU?M1igp8uG#vRM!Y>e(U#6M37X^A9zJc>!=-gbEFR6AKilK5}jfI z`$$|E~(kFW>r4yYD~K4IuPcbWszE@5U8O z=A14E1d@E1FuM&4n7;7(MOst9H>zsq09iZ=!+@M^>iS+gGmyx=WWCE9<{QytdJxW! z#p@7d3A@5XdYJ?PWNZeYK@FgrvvG%ijyC~)5*G~gv|VUmE;3p?Lr=SW^FNW7VJcty z1%lum4oC*DV&Z&>>%FrC1-Vl3=Z&aFn!K^9A#dHWg9Sb*t-V>DzY)_U-x1l|LN39* z*x;UOOFkp~1S@C$AW#-1b4J>nJl#pD`)jmYzuazL0#K_1BZbFX?2>0fvrVIJeCizg z(aH4)W5az_?DX<_@#gA~!EIpV=4Dz-{i=(4Xz_dewYX!}OMVuOe0VJy`XCcap8=s; z%|{EU!ISFMEVP)pJNfKE3cB_!l&9#qePG! zmaQiHZLd@zb4YeXhERHCgZ-B=236cS->yCOT9X>5JZq33y4bblQ5#PjErm%3*5E{+ zyhys_@Dg9@2jPUb6}ev{Gz3ldn@M3(M;o9r^>V|rbH>6Z1~g&Y!Vs@iKR0w28X1M5 zDmu6a(4ErJ})DvjR$6Hsvg>e}iPahdzdX_Ka@uN%#y?M0`H zq5U9KlTJ~HGoz})5nSH&WrvRXF1R;KD`HVi0a6E&z=bZ!ucTCoGm`R7U%m=u>e)V* z4bu({_>jp*E*Yv$8sZR+a~!}Yaiin>A1TTqIAMMIJu2|v9F*XnDj0C#7qjd^gCHI2 z^Vx%s_U=fPrEWF>6b_}P<|@d8ZeT&gWnQX;pM46;{Nz6SXx&9b2SUzZ!T@MP2lWd5T`h*J`pktF7`qA$Tq+4a6wJtDxBAkzv2BHe%MRe2%@F7Kgs0! zT|sN?gm93}kH3(+fA*XC=`&&$fqwln@BtnOM`{)J8dZs!EuGI-9Vu$QVy+8YBOm`>6r9(_=dw!2N7gf|6M7 z$h2@n!{f#qnN9vg;eGi_((E-qj0Z7&FJ6F-`hdeV*^}Q%=L`F}JUMEHI+%pR2(7eS zuyO0IoRLHA3%4$5$1}Xn7XjGkhzCT9|KK8o(GVDp@S+@M(hx9dAcL8FjK0;Fi+k#y zdfcZOc3i^)*SZu8YC>tMgfv}=*9}UH4`0#?UCI^!NzYz|w|i^|`&r*mdguF$#QGGv z7Htk_X>EK-!PJtD<%oblb)R4G1fq!TLnsH@SJ4VUk$I|6xYW-Lm^iS~_C13$hd#2g zjs|wd)lwwg%F}>oM0L3nH-Bm!E3YacUqU>u0+Fg33_{1Ldb`w3^*{!2HJl^6!cq@J z{Jjd5Y?@10J1&M|Ni~fPMxY{30;QnjC}C|19LQp2DM?o7O+gDjSxrRq(hwcU=%t1G z0Fb#h7TR=FSq)m^J5JG}Cb4xE)zye^vv@ac05EV=iTY?`*O~rBhQw{S2~6kwO!Ptd z1$J5)uyHeK-cO2_80F?PsgD~<`!9dYU%(GgQBtY}?1fkE5v0=R_>Q+4!xSa{gzYGrpEa}g|-}V>*wlRhg4%%VxtX)uCWBD8!5caC_`Lj}es-jj*sD1-tD|`8a)Fs13 znMhUi^_ma<__iN>zWM>Ms=Ip8%suJkCo?(mgrNEdnPx^)&-%>5a>#s8afT2IbJewy zhC;SlXkrHuY`lzttl`<=R%^1=oy)`-@K#@Cr5!U8Kq*tHB^E^%Ubm_{G*w6TD5I{5|3ne znI-M3%WE412juTRAvjOh!1P!1HDH1aA|?_4MK^=977X zMGNZnL;Yg(qQgI}`g;rQp&p=@xrzl|U7eqUj?aIrX>wg&6tPf3Ec|zG^&3BC?+B5h zkzjrs!fp6{^7Z=D^yVVixSHD~kfQQ{kM#!|XJCB(1Yfbi=0<~BbC_Z>Z=~H$0V|Q# zcIc=9{`iZ$<3+E$xN;7w6FxaRdWw7oE-8S=_iGV-$oge=<^7k>u5S3$y`I9`ea7D`Ughaw@|_H^HIV?m)A`8@d*eX_ z!VfdNw0f7j zW!OU&O_H^zj(}jdXQ6gPMEc)Tp`)-836^Bv5DGvWtdFLD`Ww5Nke9SLS$%zF%z7!s z>`SFGzNC(CIz{zu2^7kir)7pR=h~7kPzdy&UE^bDkJ>+YzqxRz0}{Z?U6LoQB@Hv* z1*_F~pG)6|8oIXPIx9?uIXA-n_{G*;FboY_|AkZyIC47(z#S~`H64Oe(T~wlJ%qA_ z4rYh4bis!qTi>ZnGHC1xe?EuJVIasV!MzhTozywvl4HFsy$x(<1O2ivsJIeqbRP$k zL>l>3pBpsjHQ5)ULDfio_mc7Y#p&s*+t;tZ_?qB5QC{eJ_X*is!0L1twsig0jhi>G z-?(+1&%S;^Z|{@c7pE@|v0vPGL94_S#?SOCFfgPIPxbn9AI$zM^!4A`P=LjO6W{VK z3n^ysMv-+8Xr3JkCV8KD^!K9t0h5_;0S{CzcZLSazPu#DtUN=>$tJh?jJE|a{<8Jt z>G%df%-;X7sY>Cj-jGoV^Gq*AX;pH>J4Kw46%$Thg57FnwWXgG@7B`ulg)a|n^(b9 zq5WLoRbzgxN+Dx_5%qG9xM*MpvjfmSt!Ck2XX89X5|aG_rM&8Hqi zEm{C}iWim4{DQ+wKq8sFvY4_6j0<_Gp8EN*GO8efurTW%WXT zU7_8FkG;$B5{jGHM-_J$TrA~RemAJ=gnY8ZZ;#cdtXwpK>BDCV;MyOgrKCfQH6kll zfFTIt$id?;18EpR>~Nywc~ihwyBdL}b5{sH_c4?)~BiAP$4KUXCtUG$ z2p#3nRLiBeW9sb(;Uy)11+4&$&=tA3YgE%vcxLbUIDC3$=7%RVQhSG~(lazpm4L3| zU%|f9IxzVB8VZ9hb48Qwxn{eUe&;H5y-wz<*n%4oY2|FW_mGf9J${&-1rQ0mxlO2C zujYjpe2Fh;*O4$z;8Y zO*6O0Q8y?@%B|s;O#n~ux9Hz?f~V+_B7h;PIDaE1^vJA+A{S$F#A??pw70jeJ(^!r z&Vig}8-9u;f=v(Zfz2cjZF*F}(we-_0R2j5b$gOcUn*H)g|i==;#0o%8C`9@=nQp! zts=;hL0ts&-=zpmmsek`udbeKUfl3>b#0PXs%Ao&vnVYQiFY6E_mgWFS(0B>mbap{ z#9N?cMU3T~=evQ$309GCQ7lsIMZ7t0Q+WF?$oc{;!VfiEX|#1WFNzv|E5ei|sT`Bi zm%_A!6zwp2s3kBlNXoU%kmPdAD+)*WZ2P zOoCQr3WjANm05XdHHDS`{)$J;cVITGM>(q)@P*jtd^gz!T}LAI9AA@dUdyPcSr@Vy3>4h1N)A55r=RiDc7^TQ-{J3Byan1dZOmX??MHiFdt6B;$#O%Ne zT{*waMP6^5cML)A4f__?C&<`N+38|3*}|&k%t!CBdBzt@WsBn<=RQy85FWee1ERg! zb`2thH2_3Mnl!{^*%Bjz^#*;ETStuTeh~c8?Rd7ZpU+b`m(ORFO6s0rBr^qmSPw(} z>_!Du3f`s()}pLMp^-%YwQssA$o^#lkl(XQ8BvP`hfP(IeRp>4$Nr=}NAT~GRrXe$ zpKD1ViFH#0J6n5NWK7CsX>^hJ&HIzw>t>F@iUWuiw*4I(BH8v3fYS6Yz5mh*vx=A+ z0yHIiU@>xcFV$2V`dhbWar5{h79~iI%j#3QzRoCP-=+a2xFvTc0t+xLt0Z2uhLr7gfH0v>I2Y6#?p zryvE_sQ7PRpidoRW77RUO0yc`!PGo*^>9VM;)sI5I;-;KMTvdygUgGm#i?!Um_3e0za0$O3MX@lb zn{S1Z-v^Rxu4?&LV-l0&Mm>>CZ6}^t1jv(zOEPju&9o;TpG~q#a58B#ct_NL1oMcI zc|(c}+|g-dPAG#h;^UCVZ%E8>AIj|VEH;Ew0rB;Hp&P#S*Ge*&&qhfj?7x^4`wv7L zb(9HTnI3BK@D#{}TH&NWPXQX}X@>1hVfxD-kPY!Y0JNS4}UUTDvx6!k{525z`YRi<^NcmSB zHO;8+$Z}fE){EXE^xhhEoWh5wMM8sqJ!e8^O3$B-@6uJLrc)owttH-G)T}EtF=R7m z&Q-J5Y!F#h>Qt=gDSq$8@&LUW?@n}W8+?%gmcchE-<2X{M9^jFu-|BU4=>DfDuaSb zBJ1?-F6Ileq8TGOCEc-AzJoymXq(6d`;^cmuvle4y2_cg;)~VwL6M{GR~PE=FB?uT zlc!Xv4zO&wrJODn^^o29APd5a8@)cVJ_bAAicz1g!?4?YI3@6zfg1{8VnH&18ezR8 zcZtP(t`cQ@s?>=rHtCnW?BJyU?g{qwK$ZB=kR9U#74RrbazJ~_3*eN8wtyZrb|+BiSF2Ci))nlwh~hQKrvn1muxM7M3y`p_crKTvJ+f| z%}-gf291PGqLJ>8Bjmn1(bC?c4WBF{>dlV5s-(LlukuahSvg}J$E%LOueyA^~E z+S+j?iDbA$LFPIzoqamqTlABU+K;18f6W^&_$wTsRu6We6Zo7z2ku$ygpc+%-HrAS zcV;(lVK?=53D}YZhPU(= zx7y%fb6p!I5LXw8oXQgc)10U6)ukZhnrENmgn)m&-Hn?p=)!(dVx4l%CRJcN{1n$Y zM_$!!qy!~S&%~+dNO%ChmM4b&fuiEZavOtC1Ah#&%6S8P1UWF*c`<_N;>|VydTVo= zbX2G5y?D)W8-NbNQ8ar^=hP;CP1ZZ0arA4`(rBBS$*AkgrkniAKDhfw`F_f5Onwd3 z2xQ{#s_^N{*qwd&?cmhM4o;cp6XEyidXynd=%6a_!#Ov7#SpYNM0Ey>UtaKwtT%n_pvgoXh8y&>No={ z6b~UQvu-FN0pNv_L;f}^!7}6r`y(tAJ*w-4)@6MC9TLGNqpa4G@w^14C@h2e=2faN zLew+ zAn^9QFM5T1s>HJ9Z^13sO{iVj!689tksdmoc~4KBTC^xGax0Qy)eJ12Hkcd)iUqN5Fj|nNG4N|~U?*M%Q=oFza^?ZKRejg#Gc8zMd zOD%7$3JAnavF(@D8|CxHz*x}v~d^G zne#)bWN&19%G$}wZh=h4+O~?qQ{gZxD1@!LAC3)HGB77Av5}ah6oT(yoa>RM-i8u8 zH?L+>PB5g&o}!B^ewat+Pe%sP4LPH&>LW2d)oP z?=V5V#%GBZvnzaox%c#{Xyr{uoZ)3x^EALPK@%Ap&PC*?d>qLOb>X6uLUGvZzaeTY z3qoS25g30ae@`wo(Mp9}7)=P-g}cYU{~;sL-V(z+clRBSYR5_y^9#^N!h$|YTX&W< z#8LI<+-pbu3l)oRVE_G#*Kwz<&lCcIrW(Vo%%I>JYEWwSL4v@Si>C-FE0ayHyT0mo z81GOU@1KvWn<_&60YUQl?C zdg|M9_K}#HbH32&{OQUE)LBIED6%nYV36$%eS9zd-lZO{-C!Mv`R-ubd~<`jhtiXq ze{uN4CawVX z25b9JNawKp)+fHD1AX0gS`|PHKMPMHiIs+-^_c|6ANb;rrflr5>(5NG*;v?AM!eBXEropj5)5D7{M*YHuu z&2xek!AYiUq})`643R4Ml+s-}F67B_Z%x!Yp{{wOU50V5mvV7g1bJ(W$5^C;)xJ_g z(=zuywfdR2IuQG;Mcs^5o%^9KoMwNw-tZc(x61=W3xZj0r4(^IM4Za2#aATk_vta` zOui^~y7Y(r$*k7vBmnynLxH=}C{>weHpJHO>ANQBbS0`G-v3vwiSYZC)e|}g9 z3~(W#cun&9S9EA2#|5iNmB?cZM<{VCm-t;?{Js6|wxJjVjy zbxyxLmb`yWgzW06gK!AR(>@#BTLjav8a;EPZfYV{vm&h9;0elH~o1SEZQ zIs5gUhsVpWzP7Q7d2Ho{!H1b?v7v7$!IQ4|;RNcv<-QKPb|1Vr*$JdthHhi_Xw*T}ghV9AqLIa(i z^CG1lliTm?F9HV_x$(@ZL^P_&;9VHKheWI<+0?$Cx>Tx zbnEXv;98kn%6Bl_&wffU`8yl#{ilEb{`_e)4_5;G;-XT#Iy=eNRsWR4E;P3U@3IB9~62 zUkGz0I|}>En$72VXAgh#3C(Zb@I41)EfZXpRhQKQB9fszX5%n^SA;LVfQdJ!D^*00z<(EHzigi2K=2cUPf>FX;!*>`2@emD_F@e3W{T}q5#jX*I}TW@ zoEajsq{sOg#;YzmQAfZ4vI}vJsS>d)Rz!|5F)ffAgWZ#6RF(MRltK<2zx4HTp$tq* zCK!H9?5u`a;$a+~;DJ$dID79m234%FJ3BQDK(2WRmY}i@3@BvE*RVRYR4%#{5{b= zuX-T?T4`fU%a6|};t|0@*pM5MAG+HhW7>wD&~d6bqJ!kB>Kw&ERH#_#JyDwJ# zJ0>7XA)zn42jiiEqy1MWFP08V0kOejwK``b8Q*vEmeVGwGObLf-jHnLlp~>v28LDH z9_nP=&fPu_V1Z*2u8Gl5rlU1n0kcP(K(DZGT4QkT*mb&zY!Y!OSz=5QCghM#+(6RW zUPGWb%H4unVvdl&TG!+LG$-4atE;7BHD9r8K-O^_Z!#64PHv7a4uQAOGY1weFO)zaE%v;Z zdUr=JrNo?vmCO0jx^@Ds(jjf4oy1S)zI(2oK)X_IG$}2j{|l!j*Wit9k9BCFkO1;h zGEcNCRaD8Pz)_RULsJ85i0HnvZx+wL*?+!E^{7q%GGPZ37te$w7X`G^D&c5~PZ~EF z%MMKG1yqfjAie;djICk=Sn#we&}A=mVJy|1_ri8scCYGFhl>CTu{ic7ub}! zkj;wK)pcwNQ5h^ziMlJh?FJ78uW$_I?xNJ8#Oz;OIp)QZzm*#^%?X?aseU zqF1@m`mImowVdFGJCSPABiqx)Ru_a~M`cG$g_y2jJ(t~yNmWte2SU3I>H8C^dCffE z>#3i+y>EAxk*L%;;176)$rr4RslR=y*V2zeRcy%nc2qYotj3~5q^U77%`;Xc*0Kh>bHRI6PI6zO`uK;Z=;>4?Q2*?C;%9V5}Z;WWLGRUlFcqu4GAMrm zX>4N0aR(l{UJ38LZhI^w8;}6UuOCBKydU0QicIzV78gGiO*#Ti?Z`CBiQD zu>jb&Eoq9ghB=1MG+j$M;84qJC*wz>WP?kAPuF?BZWxK6n9OqH4I|C2h+(2%9TKF) zTN=~B3^3%p57`*nNgwqDFEp&yH;S_~<$?i5;WVsu+@6aYwX;}H>h7)XY1pK)O9+_Y zY_;vWVd!z>+gp!toftoueE#(8)z%&nDBT+~)yTY{eb=K|_mkF=RmsxqX zM~*I+8!x^fuSZNS9h1W^g3@C6`week>Jm!E)e)cA{e}ZX8GP9(C4KM1kKrD$yV{Lp z8gC6cBS#0R1|dD1D^t}7_k@nWWY+A_tNc&yQ}vACw*GXFU0V4);V376ef2fvcpNIu z!+HQK0xe`B1S&LbhPC1kq?5t}7X!$H!2yE?Sp4NvFusqP#C0Ubq}@%kxxp^{Gm3xd z_9DneNCN&>_#uB}CGBd2NX)MXqBmHwszB?f@!gifo8d$2Pw`^F3u48A7HU<%Z^Es_ zAXyYW$77d`4)ei^L>q0Y?J2VwXgI&!?y6PfVj(?R9_Oxcd^b>ad3);)MI6}ulPWMS zOfm`rGPpdw#%H&7-zQ;4v8mx+%!xZx6h0&W=RmDPR)PAZG zMul?dhevgdftI#9c!+^mI8rR{G|NmC%tRxQtw@kzy!U z85ZE&EyRTPxzuN8@KU@(N(#bH#yipE8KBjg+U(vEe!ef1qw4ZM+>m(0xJrWw3H$25 zy1tdb-Z^s2ptlCss+N$$j&Dk{QRS&9vdNL%8R#GtPzR|a2am>Ey!NU{LDeFadHU=O zR{4eQq-JrtRf>w++oYt3=UUTgMC{*=vHl&8;rhNafd;Sn*%6D>z8F9L%PY>LGUFq; zS7j;!7tG2fWhnZ`%kZSDgt~q=Hy5QoZ+H8`l{E{ZUd0y?_sCJwzySN?Ro{`HlF*fW z(`)ll)D=N@okVmQB$0jpn7eEFqTBWIxKcbEudpmKJ%k5vvXCI~^Sx-gxBSu8-b*Qg zfLaVWd+{Ov?f7r50*`;9A8n0~_tG&#L za57Sb#-%)hYD_(ahAZh5HbXP;G476>loCW%6XezIo}o6_I3>5v#-YokG- z*6sLid_EaQIt#49(Ub9|Hb`HRk$8MZ10}K`b#ptLk0zJdMtuN}j>Ly?H6QU>TJ&oCYGjIR9b#=rdUUzG2h zrVVVB9g0Sv$3vRaOXser2P7VK^T@`1u5PJ9|5jBnDb|-7(=(d76IE;{nj2hsNqICR z32HJMS{&p%yccoBR}v$jFS!-0Dgp%?0m15Gp^ju22FQr9)}%S+>D(}0GmmNfVAIJ` zN>?YVnzDxZow?Wpq{V0Z(^~29hHa%*xhDDJ&?W>58_&4>L`3wwGe%3XQ8`$mYPe?6 zM|*r1a!}U#h?ZOmMZJ=wwPvy(WPJQ^^_Q7S=>}VAeAyB%ExtA>Mf2zxTquo7RhBv;ixf_Hhy6a`0Oskkcf@ zh>b>?kPJZ!-6Qv!KyubHtpl=Rhz2rH77BNRg;7C`J+|~o+{^7$hU4Xz2F%J13WRd7PS1D0?*Q?Khk2HsLIV!jxO=OYuFV9+T z0=sQx{*B~vEU(?4NkPaC;^;&mJUhFBeu|1QKMws36<@YjTbhk_=l4F%;r5G3_~7bC z$>)w`fRsN>rQB4e`*DKG<#Kp1NQ)mXR>pBVKbB>HB-9bIuQCS0=0z)u1p*2NC*9ZCzA`^NTd++&(~(%0 z$0n1Zl!;A=M^f^QUA&L#Tbn;cwX{~5Kgdu>B@&2Bn_1%Vz>KQn3oGjURp1j4eh8AB zQxhyfLs?76oIL3>(z=A@hnd5#$q2IAUe-tItn%lu`uUG8UHX08rG&K;77z-$ENTc< zwPVv%?&Plm?#h!$@{X*6^rEzUD$ENx%4`m3xdmrnC;#8ICZBeclne|*dPr}z`l*9% zh;E}-F?ISRO;)j7n@ezj*}DIYdc? zC4{+a^h0%q?@Ut@S`C>QU)|NQ_35jaj~46donmUAZ#~+7enQedWhel8wTeRMG|31a z>oBbE;slC|KUv3+#s!+U>hN&{5#aPqt3$`6|Ldll-7R_L{2wUd04|}wr6ZwsjQ^fp z`IrBF_bQ8zMA7+%W%0Wa}{W_Rr6L@?2>83eqipNNTq7iwZG%vk( zvQJIF!ZmcpfPCdzkdb3e-<4trIp4b@pT9dYDbWGt7g5Iw7UHMrpOgbf?Tda-=5YCw zCo7$7m)#D3b875JnWI%z#^B1oai=j%cG(YGRNUBv6$Eh2%7zn|EGL`Jl6={TpYVH_ zw9QCB27)urS3n-O+C+;P-Ev|@f>>+lRl*$(hX7E};IbBAtpk;Sx`tJ&vm5|oX0j3R z=`i)hUW=@l>4@@4h4fShI9Mh+0PGlm!^!}eN}9O;hl?JSIWH-NDyA$=mi)WDU(I%R zU8_J81-~scOAUv1$Xih{BbLCbxNbyuY`nU&!L<&$*fm7yT%Ja3|ORi(6N*>=q#JX!Gl+CW?J8wv;*zk2ci)oNeb; zMii5q$ooNd=lT}g`jB(Xd(0ria{fTcoI?oI3ho48R==SQ`#6mNwA}Dcn{x&+9Pe*< zV;sdfco3Q-Z3`~d5Hb9P_e&XceHj~`d>QwMau#(p==RqA?aIK@AV$S*YWa$(XB*I`oGnf>J*c&|w&&hn3Y8s*PLn8bTtbs6rW)%;2ZB0*cjw~NZn-Kb4N!`a=h8UL z#!JC#Rb3=1ktP68Lc4fesQy?deuhF9Ve8eWWns?yd)WveU1w#8Ya_D@?);oh$ANth zJ6D3l55Ds*V;dsX(Sw^HeN)n8e8Czq7!huvt<~wQ;U$cJM9pDDqmzcEal@IKhI7e0 zn*9#4K!vH-_h86iGZ|3&g&YR{S*=~b)<w#a`_a3^PVO6ae4ZX#{YQ5w{=x*7!a4XCejw{u=TSFgLvC?PClJEs|1Ytf@ z%fBuS>spKyjsOSty5Y-TzIl`2L$o)OT3Xl=J7isXN~OoP`UGRD;3=&_lW=T*N2#4*;Fpt8`t8O+|!lI@>RmZgTS1|K;$eD#WIbYeV6ib)mQOOwjZpo+pIDX->C6 zb311?G+l+3ESkOmB_X#o#@Ptg4hAXSBlIoB=NAfvIk=W?)jzoXNfnm0g`(bFIl?bw zPVx(BRiJuWt4Gpyqvg?(R=V{JnW%(xTeg#)yKS772o&oL)`5W$(()A-So)Z%%wTbR zNRq~HvrHYx^GZ{CEbCh@d*M_X_O|s4S1R@m7bhOfe!$+lIdmffB1dVuhrvlUy$gg~Qvv z%T)S2=C&Y^YZg8|S@IwLxE*zge4~H_DOgH(+2y`Htc&pQG3Q{1v5C?`_7#SOPOv(F zg*?#RJSY<%_cBcyU|JQ!n@AZ&Uukfw&molb)e9d))D9PzlXL5QZbUrEXK5dY7>vM!&S%sMAy%!JC~-OQJ~k?7&}=W zV+DzK$Ze#vs$M}MEQ4c-o8u~UAPLx|Tf=rWU)WnJ9;vw9seHVWZ{;nrS4?Ma4+sNI z4%QMmC-Kn`r;bQ^6xCzA3w0PhCuJH{5mIoCa(wCjHb9fNyJ5~ktS?T99(cSan`*H; zGn-PeN?kQSMX+%laP{dL72$S)ZSim3RzUq9fLzG(`Eqk$Qzfupxtw0*xE82+Y8RI3lqJ441_iPVT z0UEXd6_`2HEYUSD^VaRPG8&Z&JYdCQ%(Y;wGGGkZeDO$YdY{ez{Qr zSnI4W2$kt*a5d?0<>ue+WGk~QPwMBARK;9|hBouKg=B13b;d9}p z(PRyz) zb+Pm5tcO=xrX~C=*nD=In9tOLNYF1+7VV*D;PGwwPRXTv(@^CDkD&@N!1^`_nRvq> zc-rhxD92rdKh*e|HQJmqZk&9LZSr#V@tsGvWnZ@VKdu>qN|#RnYx>+HeFZn1+sqN} z;_h!)EAD^z3{`-Vmr!S9+aHqbSvHM5pKd6`(X{I22v7Eg{Gs_v;Dpy_Hot^^4-3^# ziXO=@m->!71^Px_7UZ>5RIpfTMS7fTbJ4|;l+zZQjVZq4^+FpBw1Fu$A!N04$G}3e zn19$-!E{TNRakNB7Y2={?RZ|nm1@KF%P3SLa)$HEyri4V9YRddk-JW z0Ozqcvfs`io*cq98^$bxevZj?7X*3oI`1K0NvaiSic{|UnF?CZ>sr3WM1AGY7vD$+ z>FjV=_W(-k3m|Frn9)DONIiu(?`wpn-2o4^Y)xlmDe9%^wTO_+9L^(S_|Wo70K{EiwZ8uxOSU<@y&*X5!tw)brmRh9hc;x!6-S#Y;@Zk+^BTZsnN6pM>2iCMWI>_Y?~v zO;6eAvcJS_z*sby{Fmc{;SHVuUtt!}2fhcWWihAVMnY=PrLIc@;0g|VJj7_&RYu=5 z@ffoib!YYszzk|9sMJluA#Q321x8s<=ITlbXbN(u(CJ$GCDcgA?No@f7^(+I&=eHe z9FfZHU98>VERgq5Ofg$4cdZVvrDil}AXauGYR)c-oqjh9(1g~lYYoytzLTwKWDedj zgc@948eunkkd5|I$yb5yZogAzm+&-Q2NjYg#;>*{YF9M-UAsQ+$o3cViL5Y{PywC; zdJWs33aoQHPdZRXpH+w{MAfP`ynu4BMn7dy5p+IfNpcsKf~Wk$inQV|^Ku62gPR%B znn*y1+RaKT-I=}Tp~YG!!?q#cGhs#bQL=G}O|VMTKhNC$*HT;;l0A7e2uWVQgOS6W!84v7NgoERqSt>C< zJfN{)w9~l17=2{2V7Rs9FgK6PQ0icdT#v>8n#gXes~B~af6EZ)n=nij9av(+o*+W_ zD38oVn0#7DENZ=ME;05MBuMQ};@*h+l2}9Q?BYAOZ>N+aGfJnZvs`1%EQMWV{;Y)2 z%iY}rx73I9ntbBCRzy^0bGge_2)`;(Dnx722b|7MY2p7sLe{(`7R|rirgxP+ zQ#m7_1nhm|;|#bdGlXp#tA$u0NY=l?U60(8#0<_;l6%7hQG|HTo7khO(}09PCOEup zW;6N}{?ba~{vgoqgj=pS0m{^uFCY8W$0Ulu6o59McC%3um`tW8%crnDmkQZy1dEfD zNRwEiEVDjZ&y867+KM7sDvUd8VwV49Om(ds`N@5aLK5Bi@l0tvgD)Z6GYWXfNW@0h zCXDDw^uXXkW9l9}sUh~76x5=MhEyO=;IJUw+Mc$+b<77`F~ex(zJra0qLEPxYu2IJ zXh}u^{8!11R-jUpOG+gtZ$(@9FAk+zu1qZ(eQFXw;leZE9J&j2X!d(oJX|YX>Md3?pZ%k)s2vC`J3} z?+l-6qTVSF9PS|}NQ%S|Wl(nu8`(+is#?~rd0<3dO+!pF(b1sJVpdE7F-*f5sKa7J z!K5^n+8pRxLA~X5j^x6=gKrtk>#m$v-!A^vT48|~DS|`60pF5#-wT}39blrn-0kkA z*^hqoBXEf}=ClYTCBQ+p-G)&hZZ#qct2vc0K=mweMwVohJd zPAMv`*(3PS`~2*BRsRPZN_u~$hcdgOGl_ue2o(ZtxGqG=b*j8~bqz{zdzokx26ePT z>dGvaOms?^^qL_1NH7fws60Xt$^2KoYNbd+Db75WHD5lb2=$$Fp^y9v>S7TdY)B6_ z$2Q!kbyezLC;0ez;Sk$$&79E^!cCe+*%eTOAjN!klPhR{ zp}cB@K=?d(a>C6E=snk?hlUFMZtUE;c4OxQ4+h~<6r(Hs_`H50fkHZ~Z4;wxwrAEA zDTx{ZJNN=zCvM+<8um;ReLe%lL98oUpK)^sI~YSPj^vzb{LfOba(ypi5M--?4=F=A zH6B$fZ>4`<3F}GHddLj;>h_JD+1L8dH@9zG<%1q+Y&ug&uAmM1S6r|t#$}waW$P{{ zFKp@6eDDbHta9lAS+>@P3qd$?O)I{JM9j5{e8KXJ@J4l+^>oMyv`a7SpFB> z=bv^nQ_ns3fg8WGasmfKD#xtd*K(*EHRWITSXxE^a^S&H)7nc%RRIM5HbdVZYkI_P zRwrPA+30t&-K~`mL2KJNa0BF!Hhu1gBdw|nxl$QnCE^1?1jbUBka`rWJiUdwiI1!G z>%FwUv|Ps*$Yjyg17@&*9E}7T>F;fP{BsTCuit<0@gT8WJRb!B5&>{n$-c$x;}0Jo zB-BEsJK5w}b1)9)$p6aDf`I{Pn(0<$G-Z#?JU3d)LrIrQcG?_ z>Dr2n%-=?uTOLuKI^=4##<}ufbyI5s)ke1tFwdxyz4K_& zT!-C))5e_!Xt0x>^v%N)wh2`?2bn{}h0Ic1Yur|%clG6C)l z=V?dXuD$TPm$+lkoH6P!%h*6Ak$Wt<=V#1qh41p`BpqbbwOEg7MVeO5tGL{`YoWCY zS72RaE!8wgCpJofO{%5|QI;D}rI<|$37`#~xjQ;)dNzZ; z-BThL8O4S4b;pvfR+ccAHtFO_Esr)GRv$rX`8!vewS&wLRhoYk_i4_L(L9F|8gUAH z#kg=M)O7=Nu+&08C(e&J-jz$ZH7kn5xN!5K(X;?ZGa@A}6+!~*>q-_Wsay$@t$7q8 zZ>3OT=SaJ_s+w)@?cIk$F$)zu){M7RDXZz^5{;TaE6k9VItE#K(JXyb>r)kAhEH{iZ}|I%f^$4d_z9wzj}x^50e4AdO-ApS1mbEScBgdjIPCSd zlyW$_2F-A8fd;fZJK)I}7VccQM_!-H=h&AnRN?5`^Gz)>&s|HCu_ZetR_*LD=={poRD>F6bzDJ9u|ra)ozG`B@3MSAR5 zuX-lv@^>l_kai@4IWPMIH7gNk`Ro}X$7`P(>ocV_iF4x$I-SW8Hcly0*lfaI>G9?i za+M<>M$6jl9&RIpl@HH)wB-$c2nn9idR_7&h>>7A5 zB{d~eY2SDl0(4JiX8L>u54ijqcm~bJ)X~bS1o8OiSWTxdgDd3QP@ZlrSE_`XXiC$N z!&^-16iPi>euI0;L;_?Pb9?{k7jhXq>*%;(!a+o&HB18+5234FOXtZos==w&d) zU`w)g`fDy9GvbJjN!C(5%vCAP7SYp2v-J)A9g1Nn)r%Y=`%Y}W@c^$#SebZT^DZ=U zGwPE#s?3?PhNJ8jPEIA!papqO(PIqAOmqY7x>DVBCaUHa%*S${z)cUhb$1(NMR!<> z^XubLa0wkt^|ieU5I6+qcI>JV9_M5YF^+1oD2-Jy=E#v0i;a8&#Y}Juyi6AZ%LkNYSHlaU63oCe()Ah(WCGR0nrFep!?yv8c89~;EgP=5J{|xRXU;RY z9k<+R>EeV`-6v@)6;(RjVs`68cX}KmmJu-k-OIuA{)gsn;IVozC>20WOT>=}XV3x~ zljSKLUKBmm8d$B2HR1C~0jQ|Bx*Y&0=?I2c+@OYm0&*wtPtH)A%aN+`8Sfx!N@(tT zN)Qb{*qVYaddbe%gI4}9^wQ{u&82~%<;I`$t&gJ(acQsh*6PiBfHU>mdShkSX`{T? zzRO8ulrTcTG|?S9GXcPr&mX;59Q{+k#@bWh(&ZBr`IGp0S&5jOf+S<%0;go_Cdo)= zg4jtu7R<%^vUSp(4f=!LcGSvB`{YC6^`xqZcS{9J6Lqxom8Wdq7UGu#WS?|f_Q<1F z7YseTLT`20ELoIP{9N+*<#e$tAAKjwEqil_1*}1MFoWyN(uhgXpr|X3F6*-4LcmW@ zt$Yj@q*s_dp|EqHVhR%CaEG*haZ}Py1+s?TWYmgDa9EkPX<>@4fg+cX&ZS2h(Ij_c z6nj1BD~K~|K)k#L>bnow35~k3?Q^ZRIZ-T13UF&6Gqvqf=-41PS(ELDrAgCKxjGAP zrS%P`3E-~5a&Sug+`CqTT9!0>aP!7bcJyEF2!3$$CpTa!4{l@%-4YDbTGXGztynl64tU;+nx992`-56NiFnph5N#(j5Za4G(Es!Kg>h)Le$U|B;k zCki$I7c^H7RzRC=OB60^Jb=~4=Yl4OU#g>;3ds@kZeX6_A!pqE*`H6BOZv?qeCCh8 z`OD7i&zAe+KZ)h)_m}%$CDi>Iyo>fWXD6+B#b1!Ae?Fq+MgOIpWxs1~MB_fQ$jZIJ zCoX_QkYd`8Rz~0b(T`^8NsZ0>qaWQC{#z$S&oIgaWmkO&LBI)Oci2Z>?mAa*XNJun z3I6S{2}$py8EYRU4w}9N^H`yso;dey2?#1Z`Ro4*Imcl_D{ey~A^BKMJav}qzr?BQ zsCA5m1L$k;QDV49r18wQr=L;RovH|_9MGxo)Qm;M@9ZHf(fWA*_UzAMlgccdAMeaQ z`ilR-$Qyq86c#Nk9DcedZwGJD?u;xPj!%B+`s2~^)#UGAVH7-{*V9k-Uws_k{AqD~ z%BNx9JjncmwI4i{n%?iYhs2}hms;k7#aEb#f7#7{1V$B41}&}Fb4bg!+T+EHsJC>dx-lMl2(mjRv2P8U^A|4a+QxgN`9!K!yBww@tzT zGOB_oz>I z_>R8$){fn?&AA#WQ)ClM<0Y^oTCy(!7fY%pDjh-dY#s`rj@F3I;eyAVjG$NchgXe z0WXx~qa4)I#gO7)O4?I_4m~mkHn{bJ!Bbz98aM(OSjxkAQ5b&@n+v{$hk3Lch&P0l zuf?t4I?D&i+@f287KG^Ox@K51h3jHdPO9q|%6Y?N#5JR>n)q=3!hy%_x+#N`-J7x8BtWnNXywR zG)oxN({jiBA9`jZ5PyI(8&Tx@J+qQegMItSO=Ze`ax;?MC{$3}r$~C29hP;+83@Ic+tTdizA=d=J`Fy~Z3N>BGxy*@{&_fwiQpJKUiTv5S z#NhFuoj_g@Z_1oJb^e)p$zaezv!~qe+x8>HH1te7xCv8xRXK{7r`yhZGVh53ZSkcKS-TuUuRvdjM4n z_;ETdGNs*#Nh;cw20XbDTrER8EHG#;2XEK|dh>LlL|*&RlaJG_zlTGJ_vu|^VTAn9 zTmayJLQLG8k@7#o#v)auZstCd_Z=~*egRVGyX5hCS{<8Se5YodB{|Uf5BIN@;^Cl_ z^)L14P!Dr*B@{O`BeuL=?H@cW&v9ZEt-XBt{`HqHuimDMK_OiP&vZ55rr#dkyZ)0> z|LZWU(pb`?WXUsFjYa|TD+BuM1Z9oW(E-XPys`5$PVMH-O%t$MM%Z(v z)Nu9ti`}yvVIEr3j_5gKZ08dUm}B7`5t0c@_-GB=|9=i(p!BmFmw_?=xOwx&Ak2Y{pD22xg-j5D5VU4!Gbfvp8VC__(Ac>K|ZrQuc zMyiN!kk9~fVuH?j*#>qE91WXKwwkehAFg8>h?K4-$p&fdm5@m$c9HsQ73{LKOk<0f zx|m2@x*2FVShH|g`GJPZRYNXM3@%L&6ZI?Yu5EZPDLKvIOr{cJ4(Ak-u6!|KcOJF$ zLO!^ea3`ecV1D5zhRde+LH5&HE@Fyr~t@U?=8 zy&z6Tsnfi5RB6kqHm`g_6P^1VVBcYp7p9!f+YQVcK-vNEuApzzNyvY{!2j0;YzNf$ z3eW#Q<&llxttD^d`^4n+*}i{7{&&Dd;8r7KqBW@7$^2l45#{^eJ6HKPbQrQUtQ-!Y zmmlk>q)s?Uo7hzR3|#;Vtd*vtl&APtpm6FmdTD2pvTp8$2Wxh5X=^J;MykYmD|^XA z+=<8yU8Xb$mk?-M-%{XyPdq-x|ijd@=0tLg0A$#&Q1di1Rkk^fP&D z)@x?f7T00y5a5IZf7eFOTk_!62@+Jq(+W~JBS;1ih^kxWgO84AVfTl4@F60F$LuGq zX#3Jg4;O+d6u2rM!_nue4_qQ=>dSfLR*}xXYBnPDg5!r!U(0V{3ILT^tqp5lvv?{{ zzR}un>ekH=p`J#tm6mFFi(3zccm>DM=SnJ-Ea_N|2v$#em(HXIka0S@jcinx-XiUlA1GWc(UG2CytYa` z?#IQl6UhD4I&gFJiqjDX)0oc}(bZ&687|jJe|fn(`%sl)%3qwWt9@x_Y{x6{Sh@Gf zXLA*+u@cN9WEQGo9fNYz8w$XPl?c%_Iyexq>+G0lYsa=Qfv*jxY(ZL z2O?b04)^If%qAjhLrliLvOGj4`K4X^aamn>mI+^g<)Q0A?4>3!kf7rB$nLMU{#pKc|hja!mS-lpr*K;y5Xp z!G+rMvzElU|N1|@G!-&%Ll(`EV$m=hRr8wO52C(itUguuisW4_`8s*R_GjEf1CYiM zSUNz+UXBDZAkE@Cq!6C{^`F_9@?ga&PPxP=V^k2_z^S~#6@<~U#hDtc#xNQ(gOrsa zwJxsI%W#^)UmyzPT5HiI9kNHG%RHrFaV^{a<9q>n2;d+=pL6L!$YGr&xlnXqE@~+^ zw(l&Qtf1$XA&U~?!thqr8)+s!FDVq8UJ)%5GGxG;1%q%ylgLFPfJ8E(bHHoPDG^Fg&bn7eA#AnNY{<;m_kF4EJU z;N27woQ?@IsY}?e_QN7^QUHSaN^^~Qm3k(~vWA(I~3nsaEnsw27#t}r-#d}GhFqNH1 z;?Psh+aT3Em{T$!g+(hZB9gMyr2uawlWqmLLF1Q zm3=r2S_jJVTtZco2h$wigq|lR+5F&OmvmING(QnbM(Ki#I~EDGnLQ2R+uSkz!DUjK zR`JkmaMQLF?EUwL<=f>D35^YbOEG!wxm_9$R*OS4!=bJr4i}tcAK$dnj_HVaO%9X< z1d$>kqZC4b4zj#H91(|e=|1u*Jv3SnA34WaC74GDN{f;s%HUv067FIGD&HoL z7Wc&TX!&qL9n;8ser3yZf)Kqv>GtgJX^p4Dhd~W1ltG_O+QC$n`qD-R_mjzuSCu{f zhwhPUlvpL~!qR!?j4Ojr7}CnTQr{=1l03*h5n(cl+5laNIyB$u#-)5*wz{!0xX-FP zG^DqWG19gTq%crlS#_NB+SdljNR-gN*3=VdB{fzS^5$KF2ynCu?rRWyjcvYRGs7pj zgP3rX6>qy}d1cV4?Vil8r%2HiwMjh2%c%~g_;5nCfdb#n) zCW5EhjUJ7?Ei7S4(5N)1V|pO01Erf_5E|9o_{0FLvSP5UZwqw~F$HND$bP56kGw<3Un zf2^PIYqrE$=b;9NYxBP29vazv|N9uWzDBe)`@8JMn3CQ#i1AnjC0JDnHV$yn4QmA@d)OXzVa7q{5=kQ4!?0HLg zmwm~vpy(iaQ-pHghOKld6gpDRDSU&9IT3vFLdoA;XSuSTciG)0QfwUS!bB;PWlg!i z=qYNe>tCNssl)1GjIZP_+acaG%?2P#_+%WTuY)k6Y2;8{@n*5lO`_6byv=`Q091_I#lk&Q_0IdVN3nt@)n(^mvt_VP7bop zM3>c-*HO@_uDJ^j=Ub}VU za->qM<_$DORA|UsliO>+k@Fp%{YzyFsH17LjO)MKm$ouMUeh*Q8VC>6jYPs(xy{*@ zYQGwJiM&i7nYCh)xT8rgnpJ<-z_TM*<{ydlxK12DuxM zi%azT+2yn8YtbMyswbVyW7yMtrMq>M@v!F2TuD}ZTZbf#OTTem)-v6ZVftU(9hr9M zxQ&)lk=We>Reh@!_E1PBcbJaWDPZ$>Exd8(A0JCNB4PIV*Qr`|I&CT(k(H;#c|kLB z)Z+gt2$rK(E^9;IA8c?ajQ*7s44hI4AP@)V)DiQI zo(ZEy9PrJuZdGS0Ycrx{wftIqWKf|{aA71RuEgGyK9Wj+!*Dx(BpIC{xDygJ5SLej zser0O!75pN(YRGQEj~E-3gTIWs}i9Zd#lx zi_m>z*r-FIkjcEt^^x8IW>hN}L;*jtuGEUrz)BH!fcq`(6n}n=zJk&?1!U1?wp1Ex z7nNt#pcDZX8;=6(H()M`Wt<^7O=c0wFZW+Ng{$?f;@25?b!*=N>=H;|t3AwmPBCJveHS=~e-jGTtRYpJWW4?=KTKaC4 zMVZ3ea)}KRWXN0W=zWJu^DrI)5?5Vi;#AQ@2ZWgyAy3$ksJNk*B$Ujh!Y`FmS!Ho{ zosu0O6kCRT#RXqyPvbClXLn*Q>WaCll{_T!OuTc+b@Ds-ugy=p1u;yACKRd<0d*C8 zx8s7HbNdu+D*RRD3;O!cmBlupTR^ZaRLbS(CopM1q3{oPI44aime=H5oVW_OqxFL1 z*Ry9_vH_>Wuyits(qc9`+kleSj{KB}t9-ScDvEOe{JdLLq?JbJUE<)83--=BppT?ujnehP6rJ#LVKtuia=9=GQCheSST6`wqKw=*|MR ztxI^voyYIG(E)yqN&+p!jtIL;@sPtxT4_ks@j@liSWZE^myPeHs0cgfWG-0op_|mG z5Gff+SM5QJl_)iYadEpOopLRG%j(8Tc5uq=>Z8Dn9MXBQ&^KEssUcQvLWA0Cc5bc^ ziqNogkiO$?Fg17x!;6%&7(}(E?*@?2CSW!)D8_DY(k@0rY{~^HZg#H2b^NsRa_uO% zMC;wrjqb_x7r~7Qgk%BWx>FCifB41hr(6yR%b+ojtY_szqhcW;-T<$bb`@zhM(?*l zo;oneodA)nchTWGpf;F&OWhL1#h^|~1^U%gk$;}JYqa6VUvZf$Jn2lWZ@=N19%+f1 zef|<=zdQSsd!DFMSiY(sfxETGR2^*}OMU!e{xpe>WSu?}Q0F zBivYF^lPC+NN~}U{dq_>Z927Npob!Cn^a01dv)iti*`GS+48TRR*nzsvSl- zw=$aZp98A_pnNdS+h4PAFygCm>w#@uJjx>HO#9NeHM}HAqmp7eislfI6cFJ$ZC#$U zvA*3)gy=XlY5wy2qZgJ+7vwC%PZyi5(n;r26a-PaeDsu(pzuoWqxP$Nd-_<_fLvY2 zF=btYr!`5_7mPvF$NJjs0jzt)N!J1dK%Y@^|e24q(< zGj{BV73+Ko`>c&>J(-00g^L%y(#>&gm7F*rlqJM37lxP|{g%eyWNpR;yPlA;h34t8 zW1T}0*jABxEl_u;pGt@TCO}L#uYb#9P#o4tDF{Ke1*??1{2SGFbt>3=sqZywOf1 z-658#;~zF(@I@UI0Lapf+tMH&SJ;}%huZ#nP7%}s-(8h^=_FPq&v zKjW^LS7zGXfuW+WG$NJC1R}fNfNq?T>EK)W-m-cd-vColC%GrB9dP_eqMr6FL}BuA z=#}-d0$mE0Y<=BbJeY`6R#DkQdNqM$4cD(2>~12Gbn8B+MyMA z_KY-n0xyu$l-A7-i$+aV@sU1 zvX0(KG2(L^TD363uB z7z|PuZb6jRu4>V}U!Ieez9DaCE6W_$E5&@JSWkPPy7Q?!yyy|Dq2nXAfe2Hb3VS8W zsL@y+Qr}zEY85ZFm@vRD^{FO zQ-D%A2q0G`8kmhtW^FUcD5y|8Jn^NvkVHsDEhWO|-*pH8is@szjNv#kVy2e7ZgTvl z*;Lw)GT=zCkuh8+{f(%XR27S9Il^(jQT4CWlVl3sn26LI9_ZtVpPg5(0wa?(xS7Uy zy{H>NCu8T%7tR-|n>^q=ixrz4y-!I9!J$X=hP$}J_U+Eecfd|O^~^rV>y6m~mW*JY zarxfi{tdsHRxX%w1Uv*KVlZFe$d1q9n=ID=cjqDyC+LqTsasjGEVJ8@>MjkwID&~- zSWlNGhPc$Xty)TDwy^RlMX@Tusth1a8)+Msxbb7P#WFJ}E>Uo34IiMaKtYS~^-B`3 z9h3Kh2SV?YBdr%?5EIOYb)KBN0}omZ(np!vak?#)BCm>8V|?a&@X<#f;L3n`kjpnp z*ENj@5eiXJtH(0fE;L_&<)3F>i5d9lz?O(NJ4c-%w@~6`G&2whd7g#x{EW8_F3!L^ zSGaZX@t0e7>|x%(?=D904)c?pN&}Tlb$mxu^1IMn07? zmHq+X)*vvwgLAyPatd5t=kyAr55h;eV0F0=Doz^7s#!%|0(zO~WzGw#vrlh7vG3Df zd(DC;5C@5{MV;?q0?0!%wUP4D+Uhi>)#IxSob^~^&V+e%GIzoV>;x~p_BHXK$+Qdv zlsf^O31f?0A$50j+m7XX6EdU`h&UWXfku%Y_4MMuYv0Td>(Q-8>7QElTnQP+DJJGx z=-w$!?B*&I!Fq55tVsev%Zy|NE%g;zVF|X(*9p^Zx%lM*Bnm#(F32(QRRr_bsAZ&` z$o4oKJLuGpQdfn9AvuxV>Rje@vypBRF7G*`W)qIxB(PyRS<${F$RQKlf00(e8$Y;% zZ~F9#^{dOMgrZE|bjiH9CB=*a!6-i%D5-ljl69QJGMtSy$?err zl(efC2fh$8L!7;@Rl*DYie`!2li^^Np3y004to?)MF)RySy{QMRu*zOq_#sw`+?jH zvebZtvkxEt>VXR~VDG{>w|= zR}{md!IR~ckU3J~*J>7*1Ci`8D02cscZ7A6XFSd>{V>!uAgg;NG9({azVC*gb55d_ znGb&&+X7|QKyfABS8WacDzIP|UJbN-#1&`4#|*MeS9UOe4e}qZhEY$BD}yxx;oCl-q&O}*9DSx`HP+PH%Ov5D0iGh19ifa7K0Q*+j7>X zfFDm`Vyp~EO-4dZGA<$;7lZ(*N$5NgZY$dz0+*_PtEJ+hAOA9(5~-BOWQK2~Jxi&B z+k}=b%g!o?gykr2DoqXaKw)fsiqtp#(ksx9u|ZJQWUcQhXOF|6h6?9CsU5mV%lpx< zIHiC^uwkO&9I@kV;4%<`qjo8i&DK1%fwQCTOFY|8t?jgYKStI348!S!p z2cH&rBVE6xKBn5#3HmiC95Y;w#WKx{S17Z`=}Eql7&7XUWy|%YNG2N3KAfl=Df0c8 zG*B6xeKDSjoQq*c*awhl2YNukHaHaUTY2OXlteFj@ZrxsP&S0aQN}{6%_A0$CSGC5 ze_&zWI6ofc{vWQ+@O&OauZjXJHm`Kpe@6#7Nq@hIt%`djr`cVC8#h6e(-&^=c^21v z>)+~N%pFZFRo;y2MKP`y!U9IrbmPtS+~TyutR(avyx3WO_Zvoica#5nbMt8a9iQgk zz4>h^VQ^4}xpcPTez>~`sy~?@Y4*=Z++QjvE4#==hn49HiI45IU>%HC7xR>3PTQ~| zE6ow(MOtrgRy+ve4MK4c51O+RL&YbjVrw#+#&SIg(WB*g3k8=bTdmBvj@ZLfC)YV` zMOlB7l)Fn4xGI3YHm)b0e<9kBJ1fI=*A^&38nYfMO9j;->YT(+xsd#LkCnf^W0foo zTtYV9RMp-b?=fQL0{lY4n>nXi*^i}3D9yuahTak~t9fqD2ptg7xuv1(H&O;K zzOYmY<$D1Q;0#;m)Q&LlS^-b<7<>H|r`C7ox1|!;{V@vHIJ@;lJ1IR|MU1O}^*{(o zwRS&jNfqc?m=6^=YKzfUX>EU?pi}ZNRHe`@HnZkOb|8^hr(-PWC2ett#MTqM%!TUU zC_CH%^_7$*$#(p5ae&?zZw$w$^aXKOfQ#2drc8=|c>RvD?_&T{=f&n;m4TRPbh1U@ zyZgK8=H*T30(F@-OS7_~o(fSt^4+gQ?)q$6FC|H`VAP>?eMWqDGsVI6iPX*W_& z+rIk=uxeieGW(`H4R#4+MIToAY}#i1cpS4v+-G!m45BCDZ6cNJYS_T6?B%Q z(doL-K-)4C8V?lsoe*Edw=AmR*PM*+RY?_)wp%i0rp$!@8QLEn4C?Pmr(3VVNxHMutzNnIZeR41R)eg zi}SBv07FZ5gmJ;FnSyYbhfUvVvsLwJUP?A5G5ujh3PaE)eV(> zUj~|$9&ipZBh8=upU5AD3q@uD&D=lIH8iB^aHgZllK;OK(tSSqru>cH1X#cj=L?ThZ2kAy0 zo%j(|Fi)MoJ!})GWf{U51^1#I$b5L@>MIPA_RWL*v_E{NWYCs<#=2_I{&4Sj7i(-@ zf8#jCwegt=p5<3fGY-$;@GPQLqESEVXX0BHCkgCe3ZFyr#hkHTur&NHIVR?UQJkD{ zU-GufDtqe!|4xi(5=QPfgjL=qP?M_KQtSgkCO$lSAggTl05Po_D#-p^oXtMk{NP5) zCq>BtA(XOOOImks@Kaia9CIbMxzbqt4nAl8XmObuz_Zcx^Y$}`Xsq^>dZI92gtLS` zA(72*m{X96lr5>y1>?9x8YJ}>IvDhvx9$I3yT>LQw?CSkf8!g^!>E%;aOn6IE)WI> zmN`7K-~Egk1lvGY=|yG9)mS4GyI%;)g|hy{0HIHWt)ch?FP7BS&q(EY)m`PR{CNLh3CRkhJmI6mevKR#p~M=(3B1} zIrAbvb{{8Ux6qo-PDn z?$6i>$w%Y>m6k2}Vp8fOwn_V1N$A}F)!pwMWcQ*fSaf;km z#}X8y;h9P)WZp<0lJf^1QeI$t1<^OkA3A=T{pVpj!oJ0cfjI8Q{n;1sgS9d1M#b@l z2XnIFLa<5Xg^zVHJQNy>2qgN_@j5(}OFcC@6G**gcsv@+V*2fS8W9b4=>GWr9IU*6sx9;4}rI=z7uIdBuSTq;NOOh{}L%-Mqn@cFnE3YVMSZvATb zvSs9H{j#?*wCI1KN`jBlWv5WIyeYa9N&KXrTbcKKcv`tod}`h313<6g>Zv%=x&*TT zz}M)pl=u#wSatm=y;I^WYr6XKj zE?2oN2@IX1Do!F~wcOze1no)$U{y6IE77zz_8Et2epUlfuUwq+);HXrzk$|kHAV=F z!@SsIxKH@Uhgn17a#`pWQ$R>1pGEz)817MzvjTI4FJO>LITIg4it+HJAinmIhA?yO zOR|)FvI}3#hOJ3^vkTClK-+V)b(%!HaDCse|E&*=M}8!Z$Eo?HiH+_qF+$?0>slD1 zjYJN&RT?m14!csSm!K8-ti7@vJ{>t}NR=kN1}1;H#O#zp?#@Edx4-#%l#>v3Z+0j+ ztEI6TF*~%Y(1p(yw^J*|firxmrZfb{ycC@fJ<(yR6wCj(cf)UjuEbMT!d)Gt6}jXvKrl4 z8)+#-0w6EP!}$Oz)SA_YOX4UyF@ugI4k0)sWH6!+l)NkalKzt7%i`GVk}Hn5*+&XZ zNC`hR{?odhCb}~`z5C?J*0bkNwq_3>J)C`d|IzmL*0ZhQ{st9%=wQzu^36Zr{cNT` z7%s@y-03Q+ zkR~XUDt0T~nS9?lX0-x~I`9sgBP87L9AEHDl;<-HBABRfg3e1g ztmeZPL5Moh^48*~YajLG$;-p#x0+))Y#m3LJW5sgLau%IU-rgt*{i-L+R=Y~d-jC< z5w?XTaX9}5sD-d-lOaRV-52wk$l{LCEVm*d6v+Hep((BNgzGOcw~;_O!&}DZSgA{Z zCLPrSer^y9Ln}-|A@z))pETFbpZ%W0?3duj zOjKTf6sVjj-_ZZS0?3pm&zO@}wk?UM0qah8Z@;W2b|@{^e2tTYmjM}AN*k?t7K2jj zoyVIqPjg0&5GZL?iztX3*f`}N`K%-v_G&8);FmNi=Z-{{o?q2&5Y(g58^&Qy0Xp@2 zZ2y98M0oi}%JTw^5XYCF9{r?Xx4au6n1v6xHSCW%pKYD&kw~?yDP%;;o80}I8L=b9JFkH_#5P%DsP9&X{EbjZ>=q-AXm&okv; z2#yZi`aeH`y#RY@Vcx1zQ$GGoE6f|O>X((!K${N+pwuB}pJQgrlCR%bkb;2(L_la> z(4=UV{UQz=r6)R|&Qextq|0sBS6buCjB2W8hPHGc=7b zESg&elOa%K<76`Dyscf(ID&-qkSyVJY8fyFAvWa5t;*#;KJK*%)TpSCfK~uOX?ZMI z$>0iv&92XG&u#!B5GDH|*$1HGC#DH&f5Z2{Xjdw*64mSd?f$Qq6f?lAG@&+N_Xmgf9iYBX8GFdrQNt*GhEkX#|^9uU(6Y z&y7CeqBuIU(Cn|Y)Ah4w0zYsCUI~>k7Y$DW*(HYc-BgoR*t{G*Z#{{55=;I1!HtXG zEsocI`NO}h`TA(xcSjofpus9%b#%Dq%X9SfAOG)#NjM=eeIH+lY{%g5Mt&rh1x4m0 zi$XY~^!8egQK=6GN=ZPQIF75yyM*KpZ!z1te}(3VTvk^DrN~X^*73JM&4p?mICfw& z+Cdklk;vo~mE(cJY(yV*G*tJ=e$3^7*I%*+M5dMx9lV}Vr=!;Rxe0*`JQ0lmMoKaVq5Zj-RRW+#Utba9gKM@VTd)R%seIrv8Muj-6qyA{jI*)SB0xxw8GC&!|c?MC-U@s_(Ilr8~qcX z=Osc{WO!JW!oruR;tm!0b%}X!fsP5&lBV!5 z)H3{Lb2^OPUax|Ak-fjV=#ntk8jv? zyOdjj&F-#RIe73&+!@cF-F^7=y+;r4-WeW0d2|o2@V)zYXP@5Ndbs_lIgCGje*ga6 zXZbDY>PUd>n$RmGMmmiiZ+?D*i*SxWLtib=?%J6IfmI)jc|2bdAdo73xoj*2<1NvG zcfTE6OQAZIpE8KoO5|}zkGJmMzxVLb3UIU~cteB&^$&}%=09)86S7P(3+lsc$+KOB zLN0&tub!!xf-o8*#e+cu?hjFf4dETMmtVCZn$Gy5fmJ z!y=R(461UlthV=6UpsBXo$tlWCrirYgsbFgBLZy~Uwn$BOt4z2Hou9Xga1Gmw)e^G zUX({6by+~z!pj*9vX%kTV=rZDF^}3>hGnPUTobk`@J|#vl!1i{f@j88n)3>4(`JH{ zoKVMn!N%-o{Deefb09E$G}@Gx5)v-t5kD3ax~@!ZpwLo7LZX1Zr8d>bOf_&vNTA$l z8&v`i{vE&^uup9^TIFofm%vdMv8#(*ka`XmR7FQMkw_4Q>9vaAL|vp4y=FZ^vRDo0 z%6Qe4$u`O=&<8poPPO3(LQykCWf<=eWAap?lyBggLpKHd-++$u4WY{jnXy&$I`eUa za)Bq)^dfjF_lwm@n-Li8eMO+u?-j}Gw6BZbb|Eq#4n{}v*!9-n#b?sKcR?Mkd1P;} zE5ws&v2GW@w+g~472O!ZX(7F^RJGXV%N8%R_W;4q=TVB8sb!COI|T6x>`6bRp-wm~R30BA%`9@!JcA~xKVKtJujSnm8U9JQy=1_Te{k3mjsuqcLN0rDHEibF_D z=uB)yr|n|`O{a^9tMbS%ZSpY|o)6lsHaBLEJjU-<2&PV zA2}ho0Z{CB`gJe_S%yfteijgsZ$*SSMBoFFQ`3!y5aqxOpDBNGubc~P!AB4wmaqJx zuixWEz}>G(xgHI**US%Hb~5B$U~c%;$X@JUBq?B-xfPSS$bobsc4eHCjE7Q(VTt4m z{e)mW1PcPdf178b-4#$}Bq#*u*%gzMJ8uxHME+3Y;P_@T1|pQd{64$?1ya+yXcz#u8P$=Cgeg7JV#|^nUNWkQ{~LoeS}&Bn zWv|pN$-6q`*~W{FmF5@TBADZev%tsUf380|`&Nt{+(OBzJWc}0b9BwHdeY=Yn!Y@{ z^-pV-E943U3AqI(BU-W@jwJm}IBO<)bI@6U%{5+Rftnh5zX&fK8tuFSKMBexkyFlv zY=x!uB6*=1mzkQU60KMCM6q&>M3-i^T#lHXRX%=kkGodr=88#FNK6Hewk^ z7&OcPvkr|WQz5u?lYj;XEBZWqmlaAo(8GbED$wj&8nrGDZK?sP#j({c-ywnkVV`0s_83CgxCwX{DU|2 zTm(^o& zMU4kx{vrKy&NZtqUe1qSkjij+77Z(CF5%i*TXKTYOFV2I1jX;~#UKto+nNS18jB;7 z7n^xC#)PyS-3(;V1a5MiO{0~LyoL#dn<4ofr_kIAHZ4wg%3TesQj!@=@4gF|8bK6p zorf{X-m~C1EC=}^+Og8hhmp&{v-|)sjH!^@t|QR9l}&sz9I$DeX=$7_Wm#6;nVBjo ztR;=v8a3XKEJ6YJi8or;VN~9Nl?TxoJ`_`1Y#aW< zwh=&T$0@6W_z4yWIxV+;%SE8xpF~%1sNhSH%z|&Lf>WYAJ>C}g;H81lm#>qjA8|>` zxfQr~9ftEAiP?IILMTNA1%_ zBR;)3dqV9rgG-@XL3C(ICAGM@;H}xB!K`FdKH0Jnt6zZMP5{paRCk+IyjRB(se`^< z1D?a`MVuSB0L1>l$51Op_zihji=A7cMz~y6#73q^h=is+iM++XkqB&4{|lE8Bo$5x zDQ%!fS}o$rQY2C zgDralL};b{dWJVT6*ctMv8yPjvxbBeULk<8YtFty1Gv|485!CAmNjEkG5zIGhD`qO&Xc|Tcuq=!^g!hHoJ!J@xPWu~ zH2XVp!Os!G-B$#_Z*>2Z`zRS*>|d3KR$7@fu6tNJK+2YX@8^=g8{ehkc4Fgd9oPRX z?PG~|)-=Gv+dw&V&e1>t-PD&;N5x;x8+Ul4-0RZvRAzTWZz`lLQf{!YZlY{vT_r?N zOoO3V^|Q7{Bo$t+EA(FofaPVVz|5Nb+q^wpg(#CbndkKN;rz|Yx1dv|B5UI2%0iGU zCV^cRjIBD*ULSc9;ArXNl;B~fp+E$SugBOa5WqVx{mr<;LnFGjXHYoWG9Z2H?eRvo zuV>-E(#$MFIFg({l>hP3;PA%87!OTz>Vi@|0i|goujPGM^FQG^TEm&8BejFo3RC6V z9KKNG+Dl;3^n=QOAjJrBRDY<-W|8FJY!Sl<9G9xMQU&}Aw4=RPfv6zIQkCONslyzyy;PXtbYd3zuME`W zn!=mc3A6DglvJTn7(s?k+ehsnx6IS7sxA=NqZeKo$PzWVi)5R=cu@i#V;^T9Te2L)9Myl)9kyximas}#A@mVk2x_*nerg8iqXy?cj7p>jf@$noaP+MZ$U9skMke@ zgh-2v|KfO@%`pnq(XP=>M?WmFUfpTg+_8QP(wMjka(z@Cu>x_K-E(k>iEv?(yJUU~ zX4%c4pRIeOnwA=Pe)}R^EQ$;ZGRc(LK&nO}L^!lW5F~GuWidPO-pwmpYI5dW)}MP3 zehX|6ZPv}4#laXH;Ux1$|6;b2FCt(>boU)|aB{m6UjZu5W`U0A>&XM22&5l19MLC96a~;eLR@DZ|;!PSOnN zYwg*$lg4RKJp(Tg#6r=7KV}I5hn3Mh6@KG4S9<7|geweS-T(tdWPjq;knL)dw58Q` zzp!GZQDZXRN#c<-R3 z=V}?BfMjlHd@$Ka#z!6yNBI_@&Q5ot^&v%o1?2hcE1wfy7&DZnMk#X7A%`6{(V~j% zzxwrTJDnFJGY!`Q&*8lo-Z?^`1>2QJ$ddZ5dSCr|<%=q0p7BdG3}oFp0QiZ%+Q$q` zKFDi%zfNVMJvk^@SoRagzg?q{T+V2e?&(6MAR=jJNo(lg1j|u3lH4gdW>1XVT_TOd z{rT+IKlNBrm^?kh9;gHg>mFt;M!TZ1+0*-5=(Vi+r2>uE$yxCV*;l{GV6B*tXY^~% z`M75fIj(drlwHlO{w{^%Gdj8C&%i=O zPYaJv^=4gNb}UXDj;5?vzKmw{&h$Z@`2?j0#u0uub5jx)`FFTI#QfRb(R>$5istH^ zJE4?Fg~nTR<&n~f=xPV!I!7Lcm7GkurTY`U7}Mf>^Z5xOGs%&=yKI36B9ePncuf@yv zg{cb{=OGIA=QMKgdGxUMken$TY`f%XjI-+kK8kR0%!+8gS!*UZV4Gvo zhVeN*aHE@4OV$bK{Jm8#AblSjAQT>B_W2U7&Zl@2{34gRvt$X#v>S0Y_B+*YJS);( zg@F*gR)+8Y$3F@*R5_*SRm3ccKH%m+T28(ZNVzT*;Jy)qUxz5=s1`Wms zt-C$9<(-*%X8F;8J_|QT%`Or#br3o|KKu~Pk$p^W-W=p07ADf z<^yhnsuSw)n2s?1EV>BZeFFH$LG>4cxo&eMhD#a_%2l-fUfpgpg}i$Urf2;>$_S_-ku z6tTJ_U9saZ6~Zmt+&SudshC6=Z#D;ux>(WlSBq1x8{M39j>0^=9a9*eatdS}WCHFeJHYl#Os|sBjk&(z1XBeem0{&eff{YRQNA0e!Q;n)l&p5upnw0X2*;+wOlkEtBmn%%oUd-nX%jH01u zkN(r_xk2eYHQpK~h!4Xca+Qs`NZ@ghEvl=NB#$Isz!T&m8rV*l3}VO#WV8V+b?LZp zcBx|HUAAlBr#nW0tb*ZKgUAILg<})LcY~4l1w!nc1Mn`VWpe;s%e8>=Et||q1+2Ph z;s_}@GElY8i~!YfFZ1kK3wi)XMqK_XbjL_YdyI33 zBgUhKI_s(oP3GUrr5fg;wShpr@51L^@&!`|_n7@);Sox@0nG%`{%(mov)>c0 z;F8dAQT^fO?DujAzrZobR^R+#rquBe3sJ!m{PXuzv%|cAo1S>HKR?l597SiZ^kHxQ zMt@!{&*OWFG0yh&O?cwlYjpI!i{HFZ!uKCGhlhYl+MakqOZ*f! zv)6^4MNOYILm4h=G8*o$auvoLX4{>i*gT04mEtksuE13HEhikcl}l-s^2m~HU@Kms zqF`7Yrv(p!mwMIdDx>H{Czmx>exL9=s`WmWfJxlrPbHBA%iY<0>%HVwiEECl@AE2m+QHjJ<69&J4piNHdJ z$2jGm(O{x%zwosJ*nP-#lFXzL%n(rgo=oUxP7V0EPQimu91CKx77G4qen_U-Z8Az_ ztv!{nslgW?+Z^sH?uMLUSpZ6`L@(55$c}%qNEmbzGI!)MGj(w`z|>wsiraL#2x|>F zh%ZP|LNp)QF_E5$ywAw6z{&d{6s%C?3ZP?(`uXy*IU|sEXLjY*Y+K$IB?YjQoBB7V zGnBxb;xpaVQx0QKMe`-EX)B&+D8Qr?6c$(L3JL%kco-CIiEXuv*Zvu=L)!Ezk(g1v z##iA4iCywWHzw1;nMaBk``uYbQDy_0vXzl_JrU8o+8)=wWeRXkSRPY>8k9?po*=RY zn(7$-!_|W^s;}xvInm0a(}{=sD=u6GQ-v}xST}A|-3H9JiTX|@G{Pw?pFkz&;Lo2- zViI6RqdS~g=(M_->BczuJy{e4LFWe`dIXK=IU06`DGQbl`vOg)2eXnO+Rs^6BNQ;j zqcdAlnH#eO=2f`}kD^wZenh7aKK$?>|ME%x@#8i}307=OjEf2*(1~9LKJ~1JQwrS9@g$Hb zq6H{q5TbiIaMoBy1|PpVqBoXMVG^N%0!lN9uLp|PRGR~&9Y9;^7|?o@=AT16Q)b^O z#HxK{Fkj(`Na&8BL^rcB*&2f`^7hYZ<+a>I1xflq(bruTfR#*TLbRnK(!YmCyQH%c zqi9Azf|1ir=CiMfppC=X+2Y{V*Yktn>*ex@p0qwOr6c%@+4B4>J`h!q;T!*u30R6= zuMJ!Ys)|MorQ2bw!zr`^r8NU_gs+qzAwwxBO#GYAs4FLwe75}U?D3fLmW8jOm2pMo z3x^b5fFUnJ!^Nkuqyxy0_DKc?97Pw8gud$Y?WnLW7bBwJCH1%c@{w}q-?O+(gJTA9 zp`bwH=yn6+%RA_Bvf8OY1MSp05r5U!@ix1K(kj78O+~;5@!T?PbQ?hR-0({`pYV z7*6j|I0-JPcLETXXG_+Mkkje-CTG<4s4FmUw%2VMAQDz+6F|Xb}S*HJ6oh~zO>H6n}~Ld9Sno=VB4zD*c=?CFMR|c zn<;jiK@Q_8!rzX%dIWHs>xHoTc=Mx|?jW~!5%*q^+S_4x~daseUxwKGB0l^#j zYz16Uzzt)EUF!K>z8q+{xMrB_oC1(U0C5QpF}(3ZDO63Fl7%h}BO+#utP$dGvBlL9 zVNI-ksGG<-Tie{4X}hsQp>em4l&tfCGWJMTMHZpVS%?v^K5$vUkg_T+jD;Z5Dq%vh zIKgE3l%O(*Y7ix;Lq02)Jud{vpW$%3lyUiN(BSwBCmBhCZrk!>YQOCSJ}j#Xt6cRgXogccdbQ-#ol+r z;+X$HA)f;uy<@F2d#_H`+O0F(N-Q{ZF#qCChj4ZdGx|P>uc?0#V&JFWaPhfZzLhAB zlMar&dL@TWc+7lacrywn%NDdQ?~ZlpddG8JP(9RvX7vcYdA@WqFPsw_>n{huJ6{<1 z^0sp*KVS3Rgjo~{IyibcOg68qh5qMH?rv}2Bf9bMGa98mc_gCyYaGC33*8*LC<6d# zy>66qCSUo+*{k!To#Xl9@N`4e0R~`mpK{1DA>J?+>A)BfI*}B{JyhQp6<+9LBeGP!A3`h6Kl(L79QvDq z+~NQIpFiH-Q6(C_{ki`IHt>7;(X%EWQ53iMkP2D4@7MPp4^cWYq(dS9F4|v?0hO`b z4e2l0ALI{3lF>2NTnb&W3D2v4e>KFOrClNOP>8d-6j2>~`J4*^ok-gqSY0H}Bb7;M26B>j=LrUtUpg8o z{kQouIu&aDUYrKT)($UKE;RrsEd;)MIxt`P{~=p!S`H(qUVM_P$z^5T893n_hs?x^ zT!J0)!$ux8cHa;v`mvg#AC@brG`%W@50k9rCTlgv9iVH)HgH@#}dcLl+kb zy#fIi5m9*Taf+IjUnIoGOGng5ogJ#|E?pC)xwm~LNR4>rv+S~_W0eK;k!5AgDbljAmsHw RS8kqSieC>u{Ok7c{{h-l&({C| literal 0 HcmV?d00001 diff --git a/resources/localization/ja/SuperSlicer.mo b/resources/localization/ja/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..0c34b16d42b089b2cb4ac783cf629c3aa341d191 GIT binary patch literal 291893 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

sP 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 literal 0 HcmV?d00001 diff --git a/resources/localization/ko_KR/SuperSlicer.mo b/resources/localization/ko_KR/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..6a8c1ab96426c1556d1f320c1da1387d4801797d GIT binary patch literal 219703 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 j4DA=19Xe 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 literal 0 HcmV?d00001 diff --git a/resources/localization/nl/SuperSlicer.mo b/resources/localization/nl/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..f9f9e33d23c1850896973def6664c6c3292fb4d6 GIT binary patch literal 256228 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 z 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 z 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

  • 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 literal 0 HcmV?d00001 diff --git a/resources/localization/pt_BR/SuperSlicer.mo b/resources/localization/pt_BR/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..2f82486d8c39b9d4612ecc9c94dca03fa1e77f81 GIT binary patch literal 218455 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 literal 0 HcmV?d00001 diff --git a/resources/localization/ru/SuperSlicer.mo b/resources/localization/ru/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..1cf6c78561573884aa66ecfa5d3af768ba3cb171 GIT binary patch literal 361382 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 Vo;U(?iHWZWw?cn7}pE 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 literal 0 HcmV?d00001 diff --git a/resources/localization/tr/SuperSlicer.mo b/resources/localization/tr/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..68e379234e2a7b0d4ce1ccfb6edb06514608fafe GIT binary patch literal 131390 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

    1z-kWs3Tr|NV`2^Q%Rt9O;s?jxJ#i z(x>3HoYzzcy71*Azv8M#THnD?tF!=G1f()Galr0LDQ(Y!Cp zs~~9>kbbt>&b@`ak`gzOdvkcz;r&1yLVRB;N=!Mmc&#RVP2zRwJDXn@zdCcT2&73z z-qVEB;;$=|H?hd8s}E@+@rq^hETN9fgqv}%Ic2XTe3`cDO2l}qCXWAvqSMO8t^ZHC z`-zXn{j1!|N_pqF_lQ?G@p(-V&U?b&DAS+U58@Nkj&!Pn_-(u|hhqrqO3nLE*oHD^ zx-p!aq=%F`oW3HtA}k*U&_fw`nQx* zi?rv6zs>!ow%qf?{Z8C!UV(1u%&{$NGxyFAw*%{veg*OOZM%E z@rBnX(iY@?GU|RwysmSY%hrDv-;r(!?b~GYE6qvrWG7uD<)z+w#HGMV_%~^5lXe#2 z=cIW++yK)3y4u-xHm2-qq|HT|_xS6&K;D6*PhsO;bAP67kJ6mx-ZftQ^HJwK_jD~X zIA;m}AfNu;ATs4d=cQ`}FTSRCcG>hfiEl%{Vw3hAWp^NcHQ^_u`^h~ouXfy9Og*t} zdq>%_R9*(s@8Nzn?8bflKHz^YoBl8CZ0q}$*d}2HYP+d^BEHc%OiIjl*jZ@AW&9ob)vgX?k@D6bRszv5mD z;xh0)HgSQJwSzL>*%DfEzY%d^#OaF4Sp2&FBwq<$zpm4i@#{)Q9dEc-m58~NtG}mt z`JekrSBkQek|rW$*R=N{5$;L)T!g3aTFPrW;f9nKgY<35mzi)0;#Xo1+E$%7{asIc z?(fBY#5Lkx6W(XH?N)sQh`&sl+Sr==9{Tb(VO>{nGjaEM>3YbkCv`lr_uWYTXDj7( zB!4k%N4Nm(ok^OMHo+jm9`flr%KO$f|4V#NzG&PFCH^M&2T|7`+NkTnuX-^d;SkF2 zO1fWHa?&Lu|55Uv;NDzb!IasJG(T(^N;{DJ(|%>bRix8ZmwYLBU!6QR$@7zRYls`c zy+gQ+a48&%zpmM~?cJ=k$#<7m0b6Dl5+0^a;p7=a-ag#>b;Tf@ihQ$)IBL_+R$k&e z6BocMgx6?Z|GnmsCoiw^r2Ee6*HxK5rs36!h+;N!0`-m}?kjEh8+(v13hJ6gT`g_? zT*O7T>$U*zU)c71AbomX7bqu{z2BYiGG3d=--`UPN&D6It0H+LQdeop59igEe3Q5r zO57q|EA*bYNQ>fQuQvMj6b3xkAF zfrVHGu)xymmZ~OerYfr!8kib}rn~Km7au&$;)#h|H?)nE~03FC*i< zyD#USd$xNn`Stk~p8qP(ze-tuo9FWRe4bD8@_!Nj&xqfroFC8n9^w5Pcz==iU#GmE zqR!9ZSD&xv`xE5-*EuF{=KWJiKPCRh3I8U3{{dm^k zmFG|5`-RHP=gpM!Nrdb3d8Geb>b;cjpGDY@5%vj=Mb<{XuOR-dggs6j1HNzM`BujN z6`u9^0K&`X<0$`w$)nGE^ZT*1Q=9{vPA0Ww(^8NRudzdo5m-tWP`)ho^l{D`~eeX~F9ln1=K7Gy+r_Wn> z|6%fcEzdui?fBYk$9rV?A4%M|WY{m|@88QfmGQ$oe;IB2Z}|NM>bk@8>nZmaDDT4v z`ya^jD#E^z-%lmJ`}uw1A7EU+ir>%9`oA^PT%?Wv3FY(&zeuK^=J{Xp)kjJH4e1`s zJfD&M`FQI1CCYlEQ_*gokMVq&-=EE}e@dD@--olT-=}Rqn{|E#X|9o0pGPS3M@jc} zy#F)e-@x;T=Ue>F$@4z^z6W1@zMS`;C+?g0{T0gnx8$7={#yF>Q%-?ggS7uC@%sFC zq`jSO|I?)X5x)Ng@gKzZFY^5q(tHkeZc)~6knYo*i+A!pMEDo-`&RP2KFfO(Y5rH9 z|B!T7h(ALaZy@Y?=Ij1^CgER1nki*mr2KzOZQ{KPJ$VX|z5Ayvm%3uEcFzx*T@?0eSzasL_k>(BAex-d4WA)vnDW4m}y@i+0 zChTvM=R3&zbF{g9j^=vQ`}Yv{k;HBC{YcV&CEq{fdz<%vO&f1e*I(iJZ&B92AY7lH zB>ck()8|#>KTh25ciR0kJpWm~|7|4c{UT}pEP1{+^C4p?trO_}?V% zD@gl>tmjqyzAc~Uq zMdJ1OcHTdRGOqDGM)*G`?0?JjucMq#Al*3YT_ybeDev#|exBzKq`dd!{kM4j43`G| zN8FcYdIkMD<$gbP=<^;te*txz;P>13{w(>spKr;0zexB$A>tSK{(I_wGV?3#hm!v< zQ|BAW{|kiA$a9VKpULwl^8Iw)zlJp3&voLzfv~@s;jiWWIr8f>Q5bc+2W5UWdH(|M zkMsR{$~sT@=hL@M(vEpwb&mGmuM)4%Nq&EZ_!mj{bv%C}<^Q9I>fI&(@8z?8-bUQd zk>&>Jzm)W!$@kCleHC^7An~sw{L6X%Hqt%C_oryn=kfmSeD(PX^^f$EtoxgJ)@P6R z&*b~vo%$S&pWZj;yIwzp zwEBEOhJ6%mTBSUFzMQ)LI=}CkX%zN;gz57D>3@yqFQKh(&#;Jz|F;PLKPhXQvVM}F zA1QSb{)PGcS^4{0#Q#+G`TYp{dD{NFtG`t$SIr#~d!`vNCTcf1JuK=M97o-ZKpxy<(} z!oHJq|0VDLIlo`e@9j>$S5b~WUroOMntUHXIp3P`pGVl2=kreyuFrSSh9Al2kE5(6 z^RJWcUuD`qLpl096+ixeh5sKw`bYSEf?s_;DD&$1V=4DPkpGYL!sqKLYVoyOI3-0ev3wdz`xO zl75_Rcq?Hy$@@Hc^!Yx*|B$@@vQy_jA^s)auk!oJ{Qhz$?izVMf%oqq-`5eZ&lT#u zL>cd)`uThp-*d$OXS6||_u~1_@O*(Z|1{IQF6;k(-d{s`ucxe^%P{3x%d)>Z!ye@Q z%L)Gy%FyT2Df5pg^H&v48UGXMJ`foBG2Xw6=PlB`K)PQc&A;LIqe%ZHe7}X~71G_# z@_FrjCuzQh-&OK_zS_t8_mKAYDCdiL{bt@@OWbAJ`K4L^FK7NgO}bwu{yRwfQN+DB z-`5kS&u5eVQwaZ!?DJbl_bmC|M)?0i{Ks|LaE>s2hJ@W9{fAM`)8zdg!fx{ZMLd7E z%6;(Y!$%)%hO=gKIP0&E2Aj?LV57e`8#E6deI#Ng<7PPK^-*3o`t!loWV*k413CZCoc>(=FP3)XrSN={hi@xUr%ot4(>KrCYuhXyj#Pq zy=i|wRIg`rd}Fe+%PSpK>dnbuHh%S-9_*@B&F)~jF&NMLTaFz}r<19YZPUpCS@*{C z!IUxWkDHf`TWv1Q>Da6p4Q~$^7taFIvENMh#^d35tC{T08P{fKu%j7hF5U82^rsB^ z9{)5j+xZ zXE+ADYbVEsuMRxy?QRl3Yx;Nk!;wJWNm~#Zj)rr?l*(fXk#gKbrcHrrr>NO{y0e-kS)-o*NK5b4Yo4aE4qhG8xjqT|WCti52yoTd#cEfNoKe?m zwm<*|(7}-8(-H}s?)Ini;l|#muRe|T2F)!MJ)F}umH_yG&Q9*I%!Zo-f*bJAHrY1z zX7kC;@Fj-V*%`4~J=5R}%7(9iZ{ z!cgAb9=NT9Bueb>Q6~VlkvS3yW(JrFa@h-folCkXhsWEC{`^|Vj6#S z;<2Zh{YD6M8L-Cv-PtxX=~~Div$YB4o6hE5qfE6rG*;;#-1)>9it@($&3w26HrX~F zP;-DT;RuF`X6&>>rNLmVXP`;i^pqFIGK{b9jW;0)hI_qNTwOPyFIOpzu@7TG)Xh8qh_}O4j=p8%1Ih^zVMd7I4u?wur9l^p{Spqlv z>kc01|9Cjt?j5^$asza)J?Rd(zjy4(!DzR4?2@;c-m%O5@z$R3`LV0?@p|kVdU{_pl#F>5z3$2N3qO~|@t zk3KbLMx)-br^d>lt*LkH=^-z7dn-g7@2%Vz9ADFh*<76*Bam0`pS_i*#+p`Lj>=QN5h>V z1AM&q=(*-e*6%+1;JRL}fJ_FW7C>lYPr|B#2h4-8jhg)EImf-IJ+$DW-p4e@p6GAf z?wx7YY1BYF;)_~N0wEBLnhU@!L9%y9}@n0BO6g>G?uQ?4!<4PLJkW}IX)v7>;>Gk3K)$UlOQa28 ze}*b2BZxYv)V;aDz>pVk#a7Zc6-HMRy3bs{)Vyi1-<)b#;j_Dw>1Izsw+H*Zir9Fd z=I456AZ$m2q#pq?HtkWf(%-zp0@G?D9_n&~oPGdboB^sQWB=Ttjq$+GW`9@UULTsX zd+WmuUa5U^Gl=d6YO&vpg_?5ywBu`9^xfUwpF!q~i1XH;^tf_g9E{niH=4D*^~t&j zW0(2lV7RqCZ*G7ARqtkV2?9V3FEBGpwA*wtUGDF*4>);6x=$GMd#ba{X)W`xMAzCj z92QM0Pj+goNz~cHs#o}7MJjx`tnL18^i>4LW<$dV(=ouZ?IBDuAIO0!8jRe_KKr8+ ztndWd0^H#O*f*iBpxwuV<4u1m1nUyk%@YN;Akxd^_iac+FP`Kgpy#y}kA~XpPe9PI z8H+x5IMmoJ(LH8(rqKR(pgT1?eNeebB=2S?o3r!jsCg}G;MTm^V2c3N9!zw@Gu%dR zOhydK#&(^aZa}jF?{-|%c-mzx#GPEO>7KEM1K<<#l+h8wRh^oP?ICULHrYvoV#{O! za$X_yW}%Lq{`5B8*Q^#~HWDyKTTS+romwN2#li;dj=aza6FwWpv~EuOkpEi)(bWMF zEUW1r;E=-uf4MZaHG#;p!6)x&&v)e_oV9NJ;x;wy0@yWo?KSE6ddfLUAcQUO4uGnC zB{15v6cikXlED>B#-O6IcDrH2F;ggNc``PfWm;HZm{Ujw={^OOkPTDUL8ndvk7-`o`0K??#Y*9Wih`gXdxwm08pC5|Rry)(D8xclBX5*$QR zz-qq;snG0BW^Q!BlTgRBel+QCYO5?XDNs@Nn(^eNm*{}FspPs$yv3%da%(1ytGRo+ zkb(i_*k`W>#>9g*PegBb_oiEgii*7qGzAww209rDMp>*biv_gR--x8Q2)y8N5N|A-Qlh{l)H=&RYBW`O)WAWQEYA12PPj9Bx5mvg&-TvvLG>Fot7^S$Q6U_uK%Qch1};G~HD4lM z+L_EwH#a78V3-9x60)RgP_!W3`DFZh_V_UoQ{%~Qj0=ce2w(!b3hj^}8AE<>Pe_ ze%4TXSDRIuDsVUKwCIA6S}EDAuqx5fHoa)<{uB_3;%1Z4a8r_=TYa$>&I*>xcf*KID-Stz*D?*%u=rDL!xYil8Ae&@R zNQHF=7TGez*%T6%bp?Avp&g+Ri>|V83Wr?N|6KWu{d8lS4S!Qy%vt!RO$CJju1eyH zh*IKD4MC-y0#iPI?;P;w5RssO>CRmN+O1K4w#^7Vj_``sB2`520|&*}TDDhEKN29? zvp3$eAXn&NK6v0h)wED}ueL+-h}#YsakRS(+r7xk`}Aw6G;a>~OAZk~cRYd)P!~PP zO*DRCT(xCr=pCLTOi&H+xI<%&5N8FNkVF>*XbOPQB6Kii&nF?GB*i2}7dV9wCO7fg zV5)7(T&R%Mgh>KwTsM=`K1q}&CP2%!#3DB~j0tF)bFk@(;!y-eKAJMi=cjgiXXbO{ z7<7gi+?xYq!&@{fXtwh-Zb`JG2rtn{TD^-NfbUBjJM|7y(i9`eN%Jh#*J%F zcOIJ|XbC{rlz7-gI&!vHy(v;NF$AW*{w)7S9v?krvHn?}_-r8i+6BEuK8mYY1^2bQ2O@kdOHMv;&f~4<1dK zDy{#b5;@JRmM9J&vlC-V@i0mwqhR1iCPPV!R2UxriNXA?MDk^SPif%c!Oe>1FSvub z=q+Pw`h2|i#Aw2#&j$US@>rH}#^h^Dpg%F0&mkLw$mr$UU32Yzn@|!-5Q|%Mn9rvB z5O-+*FY(&-koz$oksg+oZW5~PYG((46F{ozF*L~fB^p2_NNk(SB#BeZdQTvDM{W>5 zY+8(!mHgyqLA^woc zKuEG*u#(WtYDe0x#RV+hfjHNa7DHdMLl{CRFbZ0cu3~@!)dk4Q9~n z-tl@*>{nHfm8CH6FP-5 z%J;~l7=$TXC6Gt)reqOvs?*xC4>7u)5n%Xq^A_}8;*Ub=Wt7&p)>*3DS`a+h09sQ* zw7UuFK}__`fpqb1ECk1b{Ze|`2{eRCxj{=(d}PU7C&{~A?M*;+xlpZI1e#j1=yj~r zok8(fTr|HsIil7`{c>kGVInp8>Q$-)7MAzRH*Y;rUw2%z3F>{hU6=?Ey4BwWlmcOP zb9F|=$o;Sqj;Lq!3NnXZU{Z+=Yq*vt{3jGw!iV&LcSYulqANPpP#7GNM5+igN5amF zsk}$Aipn4^(nk+85-cr-iNj7?iW<|BL2BV{e_fj5;b5j0ZBVpwQI=8U9V7^Qi{4oi zb@}6g@J7-VH3sV&)F1T#*W&RhK;$#T%*tz4H>UFw&1+V72Rp|<#c!|o%cq22e!KVG|hhIxdgyaPQ0KPjEE zc^-*Xny`P7>H-@D(=&mJSFT^Zcxvq}7mpv3$2!4g1xotVwI|+q>dci3ryk{d{l-&k zXFBOyT6?LYV1I=1+rsae*n61UR1-_#FL-KJR4vuFm9|kA&t5xs{?sZz{5!Qe-r6{I z_2SvZlnkte;0eJm(;?vpLk%-l*=O(J$T+*aGRtE)-9Y52ADI;Nf&xD%_R+wIQaZIU z(zHA|l)ilbzR3|m+?9L+7#Ua@T^QA*@@b^m3`*XJC82f)H5ufg_bpHlu#Z8>E6LXG zz=e~LLYC5OcU9SoZD^cQ9x`hhs<+){2lc}6q&UVx)jE7Pq2F5Fvl;+`k#({rKye}B zhCT_6zJ#07=$C*~DCNuE(22u9$|Oybi#@652s5FQ@i8_FFU^WY5vo3?x zld$>Av^16Dc}JCxluD*Ed(k~``P2kYFQaxMe4wVYzb~!6B5*3wvWHab9V2Lvt6rKp>k+-rSu)1i>e*BduYH>;gc2 z8C*e>h@5_DxOMWS{uc6I2``$J&B>nV(+oat!eJl!8@+5;c$o`XU|WiHWvvp#VZ)vV zN)M(0L}kMdx+I)Z7HR395|vh|`v5n_AU2~CODy(uZ;VA1ad37bzT>x<@6rAgoGgSD z%?BxWA!tfPg``g?RIFAJ)(39^ay8hBg^}x4hlSC zc!VE*_~`0 zk+kgtD=K^K9DLdo4HO)aX>rLr2Ahu`IWIF=B(Jj>`qtCx^~;XmeXC@4prLmxp`dOy zPAeIL4eKM{owGEg7Oh6gb6_OkK$F(rLiMZV7iLIOxXXa6+(D>XQ48m?SB%+Mg z3=R0Y^}=`6GaJ#$<|M5}k^t1EgVs`|s_wESp-{j)$O9}BTbcE^PZX4|VPJk%drL2E zLAv_CFdr&%iQN_?WN})3;4PoX5;SfN!zQ~{EES6_W+-MOoiM6w} zv8lHwZ{EDV)?C||PYjQOp4_2lvPNd(oS%YsRa*25tt4q;-fjs@`9dQxTNx(U zx-dy8lq`us3hXs-E!XK9R5vfdlchc)c>U*Ad*_Zp;ma7dfrsy%>(Be_`ocTnQqIB8 zz64r1&6A{kFfhfWYetZ*#mlddL#y1+cGgInF~uShGOHT>A!yQI36&$rJBj@?j4aEr zh)~TJvmTAXhb(lBRAADfj0Az)(&)fS%Pn3A{gZC)Vr7T7RV)=ku2?8b zLquQL9-5H2VtI_&3;?81*p~chjv2fiBuH=JIOx}FVL=#qngv6~3@d4(sS~0MAxr*hfx1oF z@dGoR5b36hS?!Xrv(`gJ@X%2jh`sz#twwQP*#AkWdk*4p4&mYjzb5_lLXZ-qE(Z$^ z>sy3URc($m;yy!EWiFl>c5N##OVOn}vADDGv3PzGG15vJ23h^*FaI5*WNSTs0$Q4z3~ z2UUj7F>zxssHj|#HXWX#0$niJZK_g&tiQAe+1@S#CEGoiQj1%nRcMJI;V`z7*39RC zf@bF6sEji+EpKIGt{DViMrNGnV0(RPSBSQG^WK1?RCnWy zNvTS50h5>qOU^AbrGE@vsCI_aiH|7C{@G2paIi*8@Q@G&sHb=(gd7=c_>U!PC{t^T zRf=FzTVAO&XOw9v-1x=>I~||iE7%39ohHF}*c^I-O?PEK>LNN=WK8MF&<12Rlr33E z$Uv$Rw5Sz0F$Md-+_Y|N+oB>Y(Sflf@9S0%c(IINj}<8^uCN{zmqJupwL$cHk)uzW8S+S2|=5-7rH3?cYwu55Ho;>Nf*I`yC9lXfU(u>Flp_mp`o&+0I z8UxIjPrw>h8>1-=iO@meb95H4$TOaKmf0>dfqG{LYKl<(ey_E#}1Y{9kEJ zDStEeW^EZ^v7^%=WfeZYoEl0?hXxOXD{H72maU>Hwh~sF9n2V*elyQ*cB$|x-cTp?Ak9>rgqIn?l_I#lyh}960Sm-SN-xv#I0RDO97`N()*SbjikB{3+Az zUIRymLBK??%(Afz}Ypme4!5 z7srHYQh5?bwuOxcAt5U0oePO=@BFbif_NT_vKu}BKb=3Z#Ntf0#0OP`GI(*Yv1c8% zh8cU;)t-+t>fa&_>yY4L;xQT1AQDeDH!S-?Fbd_Q0dY9E1X+j77iWVlF*Yu}5aCG| zy0{JjSj2LX_5c|e$%C}>vn1t(SUY$EwRBa|p^27oKV^U_Q6q zFxeb`Ql#T7N-S}kFBg~GgvKIaOJ;6W^vewEGxkW=A^AYwyv-ZQmqeOUzY4V*xW+oBW*vmdpURaykcO$S_?T3t&_Nj5%7=A zmxNU>Za~NGMdy#BIo7Cad}ccnPAdsN-@<&olr@zhK9m#MkQpsJUcw8`RL;?0ivx4b zqvy^_8stNzY3a0_x*kpF+FRsMdHZ1C`xtC&gq|*OOTfrk9SP=8KZme@foQyrT4k^9 z>Rfn|CuESsbu=O29P_iFV~lYIoX9pfs8GqVq97DNm@{27kBaT_9-C*`*o*N$*{@!^ zsiqbEpd|}yv<4kfRcl_6q81rD1`g8JApYQVjJDyYbqK?_GOIb&2}0QdPAw3{KA5Ia z0XS*fm(W=T^&ky+7=Un;(5I=%#aww}{Y%UGJ0-9RF*ThUnV^X?%i*!DdUYw8z>=d@ zdm!lZV{iAhrD4R#OmEzV3RObctziKKK_j{e4-Xl(z#Cf@ctG5jDTSHEqvb1m9xAg` zU08vROlMrh=bK4?n}*Y|d9fEvtr4smtOjWW!kVMnp`thBG(ngeB9=GvVta+Mkqc*- zY}SKgSXq)kiFfIgTZ~sUR|^H)H<8;pn7$h49;{qAS+*>l5$R@1D522medUF{9c`AK z>a}82?|qVtITp+y&^{Dwu*>X{byPZ*x!n;7YFg{^&@P1mY{5s!Qs?`v2yLb#@Djp7 zB_L#ST0lZfE(=I!I>0_=`RY(R3j+(ZCf%i~wa8?wW69dYGh{7G+4hRCV;{NR@$>yH76jax+5R(HQUn}QSp3&k5G9!g=e-*918As3ST(hTVXI)(RExAOD*xp;FDaGA`f)}lS zO*J>vJ#v5y)1!bLlP>7Sk`n4S!x_H7Y1;q~E7t|F|Ivk#WOd8hY?=7D0*AEfMy(8%gb7#S476baNL7<)g+aIl0s&3??Hn{eVummxY$C}RAOXi%`r^$O1U*qCwh)us%}ZvQvX}h zNiCgy>f~0Yg;5ZPEMXIx9&MK~Ox#R=GQmgKw; z%|(Y7XS$TJ6fL~N*dE5iL?aL6>kPzUah(B3TDeZOodOBiM7G!>Cu9ajIw9OGJgDi# zM|Wi23XJos!Knp-a5?c@ZEBQG@x`t`XRMU9R4pCu6kLW_7}u?_FnQJh{}m>e<5&>) zj067e8OO-AaW6CM67?LiE=zu)i-q}BKrtxlCW=9buDP#y9^CGf*a~ES&u}K4#jmZ* z@r1*I4!klE5fNF~9>R4c{dfd{CwC zU;@P9SY}ZnDIzgouWhKDS1Xi8u*=VDRcNt29~4s6=dYHWEQX@GWfSk3UKT@tB}LI4 zhaHa|_ZzkmFgXhMQ&pHx`-}nVa`QeQ>ooJiN9gELBj9A%zGJ06M2}@49Wqk%E7jBWSE8 z#VA_i;_8rg)h5Q-jvR!x!T0XpYnz8Po-6?UgK8M*Nfg1r#8T&3%Ds(2oJc^qgSp>k z7^Gb&vKk$??Y;mzX(v!0nxdvU-3DEQK0{ClHZ93v620nYO~|^XFsgA?GkhSVkq5IH zDnxxXoJW*OJ2fykgR)#@Raditf+RWuY7k%ssUud6SL~~d{Q+I*hoadct?4byKC##U zEHToNS=LPSY}2xEOdpeIISC_P>?cGD2CY_u!rZsMO4XqXibkZ(%OVqvB|U0QEtCHC zEmR|mog0aa|#TM$O422Y97|H3^A5+DagS?X!W44IGbjhyJCmF1GRNLgBg*7gVhFgMqmOs?NmPN7nOw*hq zH%qfiaX*X{XxhV7P4<8w3@UL$>h7koWGj2sE*X_rFejOGD2w}>FR%;4@fQ|sb}HC# zW}dUPMTQ!OQYu38v=<>W78tV;_L<#6WFZpDx8*6V712<3O8-j_Va;WzpXOOaR=_pd zuha&rqrg2nE02=M=GbIonq3Yg3Z>BkAGW?AU!2;?VzVy$R4?hr)_=CmNtc;m%K3Ln{9tY+0gv=7W@M77!) zvOTv({X2*c@=aW_9608yp21%iuRhhBkxBHVxoDRYqvkpbhGPnsvFG3b?TO+Fw0X35 z@u^F_ix|}ks(P6`f8m$##0P^RTbu-@b}O0P9x}!@2CkA5!96Qq^0_6@ySGeiJr1;c z9j>w)024mkRN-g`3mI7{q_JH&Pa1ZL<{k&Kp(*JZ#`LpM5JZKhd&g8A0Kky;t!+;O zMbI%kDj9i-c#CGA&>}<$=0RdQix?1dVAkS+21ugCHV5)TYB)8n6oIf|g`IRDir3KPO&*w2`0;Sfx_rtMb7%nFpMvWKuqfp_s)a z9~{8hfq|=f>L9sm0u4_9W65IZ$JFXY&T|MR7m|YYy6Hj`#BR2bs37)&e7ZSGTzE1$ zEM`6(47%Z!gX{)MBT-w}yC|L{@BsQTGrIsEL=?isoVmA2E4|`6B$lkspEPw zri;{K7&H2Y-G=3hOO0p1>;EO;??u@nT$B%)_^Sxhn>E6Cu!G4w@%LNXsv7JzuJ3p z;WV}1bifMHgIl*8P>h^J@j+!l34%PN0m-cbg_p=JTxh6h+rq^UM`w19XHenHAsInF z`z6!{o3ng7oxd;yY@_z2ZW}2$csBDiHv%^TClh&T#iR-s(IaVk2P0(g>_sv_dLWSK zQ4k{zq-UY_Dl{dB&g|`Ff!lvQrwJh`s0^hdvJYW@8Ue=Ez*ZKRe%dm{0II&?o?8E! z6`AnlVPbVyK|&v$Ae2%nOQ!NrS*opQA)4YJFf|?w+B@EE=bp3xtCsMaCl^ehd|@@@ zQcprm*rD%~N0cIEPpro7tPemZ25xq@PdiD*q{Z5jMHJn&f!k3h+JsJd5ywGfNEQkSG3F()N0YnX9v9olp8bMo-+sRj`Tco3gIci#{c5SW6 zztgKl!aNFJMYUE|(Q@%1isFQ}Hq;xxT{FoZ_RPHFU8klokh0kfcEmBMR$wCfsTaH} zVph`*SLk%wcj)Mttzxjn9!@luu8Y)p>c(Y~0nIUEd(#<#eh=r7Mj2M&dMG;@Q(Gz) z^DF=&(rcu!9^yiSwC~gqigVMLGT-ecEGigJwK|=eC;vcg%QntQW*qyQ_7QM@InoaD5cwVsTSTM)B)Nxa7((!24?EqeEX_v_yfPMd zUk)xKLc{8Ehn>2=H8{RnX?<_zOV#WQwBHS9JFr7AXLY>6Fci-Dbsu6-W59X`MuB?? zY^Mw#kyoRzchu`h77ieowbe*V;usF#R&QE*ShC7|w-iX9K{>RCZBjTxYW}K-vKc;O zwAvZi&R^uYLvW2P4%Ml2mXpofg(V*j-L;1IVo>0Rt2qc0KZyWYtz`1}dR?(n@cL<2#u3B7^EK(LcFrj!=zA)QSxR)c5R)_sc$g z1DJ!!YAjta!5s%4p&I0Pz+DnGgK%`QFGakwgU*UYt%*{d9iM_T?{LK zPu*dZQEfGSbe1u<=m3WlLZpo6yHW#%t2N<~+tn<#o`du z5Jh+XWUeul&AG~Mxk%8g)Fj+1Z0baH84|Fo7JE5%x#8nzO#5D8a41KW)bN9qwP4P2<5V+>#q??9jk z?c)8|GWS3-hO+8v+>&Aw*CI36Zspd`!;3^Rd>oR2>7=8yM&liZS#F=oa;b|GCEoTH z0v-r<`7AV8EUa}UkU)|~ni$J;3!|kpz>H}hn5z4hC8b;OXI2s}6jqqI7^@(zl0U=O zlKn_&*@hopcg7qHov!#P_p!i4pw;3ZxQO*SRA!6KL)`Q71p+oFSrqc)+RBcwN1Ol< zq9ZYtel?RIyd5xI{VDsvjO`i+Y43aEze`r`t*-_q+BK<_eNLk7mcBf5l^a?-p8H z_%655EQ%)G737X}Xba1sumaNtoCO~_MQxfUb!yMw&`pBA$U{iGJ-&$HlMZ}%;Yjuy>|Fn-dEgzK2`WPH-6IxW(S zc{QHP1Uk_qLn!@dVf1BuZ7U-6r*3P$6R#S##ua(X)~Ji2E`vMpeBEmAkT@ixr!X}< zg>~R5lZz$MwQ%8(S>g?`LNq~Q&SE}Xg0K%=;Td8L)!0+=TXwuAuZ}N|+4E%yPY4(O zD?u8S@?2yq#>OSkGAwf+Acbz~i0GD;J59K<2SAohCbQ*PPPZ1#!NEQ%G|VlG<~!FU$fN*HmqYS3RBK~QQ8P!`FiEKlI(_BiLq!U#}Su%?5 zdX%9A2c5#8KjH>D$p|^yr)q`{Iz7w{%Hay;&ca(&r1-ke<-0l?dx!!i{s$>;{lTTU z$%92(rX^+WA|>8A`^!t+oYnlYgt`Hc^`gXSfeZuV95MruhMm?g+%N9P8K@v{(k@=7 z$(R=kkhZ^bI@xgM^UF$Hb|aB3abXNzOe|A7^>PM<8qqN8Y>sZW&kOpYlA=v(s;6vH zn`t7UXk@%rU0Ofid1rGYN=6UHBb}HO**a_MOoIer?Z2%3sS$P+QBrBSi4tPUL2a2e zskR7}b^z4PV!LCRr>MP69RLU!Tnf?SMpr>o6m~kC8`mOH&I5`YY&*W-s>GwhjxImoTyOVbLCI zMhLj>nL88YxK-VfM>dp#kqNa6_KW7;*|y^bG83*=h0s@M)LpE65C>xCK<{P6Byn1( zov2n~RO__ZAJYyv#46=HM@KalGz!iMwjh4(^%rtN?hh_WCxM}{3}ymzB>4(}FWcv5 z>LJJshSOSva;PK>HEe4W%!#bTU8ztbK1H_2kVadQ#;QVbX5B)TO?NoiVjamsi<0jf zOjmnv9AE{O((5-41;@QN#)-DF*cV?}vA8Kfqs9%Fa!b59kpBUN)aj~oprQ9fvT#}X zW~`P?`y*6#>VS z0;-%&Ip>gsp07rEMHN?U{E91G?OoPU-@>x;h8_Nfu43RRuKz6$tgCe1MI6&%!MJ2W zAR3A8;!rPZJ|!Z#=v9O6BJ}?PPu-USc@Y*Kg@7f=VU2~2G4><>EPsLuX*W%4y7Vt_ zkDsh%>iKcu`mzHdr%8mSW%JbedmOa792e!pPvN5T1bTQw0VchEjQ&IVQsM=_lKET1 zqO#Hz5dGP<@)6ebhuVwaazgOlQ;;W|!Uu@Kfpo2)I_ z<|%o{0lPHE7^bxaQU#;*96yN7E+dWbze38IXgxrfdbH*0ByuztL@6q-pO_OpUe`j4 zr=)rPk_zXD0ZfD~ihmJfH1J;#uHkSuG9lsib=)lrmQwZ5&R5Y!tJ6W)RP48Q`Y=s= zHCU|+(X_w4K zCqY}f8dPuOZT;6bIy=NIBPz1|GMs+bur3r{Lu(~UB0vm^+?JFoDT51oE2MRas@#HM zq?QVuhmBZC57GlzS>Jea0Mj>!>f&0{T0W|K0yd`Bzw{;Y_-SCiB%+~g9{2) zXnoLrX&iSj#3voNsEZh^`*f2Ig2TW;Z3uuYWokGHb4ssJNdV#ylai(jF$~Up%3v|h zXY!MpcVY*`aO*wnV`L_e`xG=YEQ>Ak?5^!VY!Mk8i1qwYASNMscaQ*~+ZM-^0MTIyFIheDYwk`!eQTeIuHD9~17zH`&D(9qhef>K)lwA(U9TQI~0 zub3YU=84T9j-{0_-KqM!VA$(+~b{f=1Me={v0^sU)Oy1D^&R8Ob;O zBW!_USMIi@`YtwP4laHfm{Ga3&bt$D`4o=ov}bh_)?L?5Ae6ERjqH!R^=NzrE`e__ zD$)Y5_vk&`{qeMjt8#)DMu)a!GLTi@YF+b1HX|>1JX3^ybq5)iaPBbHuuw0E*LMm> zsT@^I!~SI_FRt{S(GszQ+h&GEm5_1?=rgn|lHh)Wqce87e|)oY<&lRTYu4C5mlEc9 zP$3bAt+q^muMQ#G3qLkNQ%D(nYGDv+jf%QwDF@>Y8J^n-6CW%&jr!Vd2rapZ#!vJiR2{*$813pWZ)~yWB6sxQuikZzSGD}-Ln4;48W0dE$XluT-IkYGc(DD(c;B-Ua z5RT9V;Khf`QH=ELVOM5}5dZZQrF8*ix6+ow{)YvI8Y?jsmc+hZI%|5T;$6@t|M9HaZrzUHrwNcRz7)yFr8kr^I5-0BIz9gQ?$&Zkh#UbXx z3yyV)NK)!6w4#(%n^n#s)iS-MK3)bw_OHH*2JNLJs$w=MLS7qd54&lsLP53-&%4^= zO1R$DYt4-_SFT*Tda*fkvpIA5a_=g;ng111BfEWA7(y-h9WI~u(X+veoYfz3Ku!~y zxk`!v9*K#|eIwyfo_5PfQ~tMzqH17{mhrGuJreKnrdz!bXC2jvV07bjgS%LemPi<` zjDR$`DnlbIpE&?*wjbI4Z4Q!Lp>JUH6dqzo62 zL8BiM);x1)=(C;BIK-UbPGicd5~W?p>Tt{{v{0+PUpCR48s&E*d!8m(s8ZvS?aX6m zRg)sEZeh_;d;kzdY}SbELo-lTfVVjXBwJ7PazZ@FCoRk#F9`N5oCnAk-I@Gp04qv+G<0(0yXp+ zbaB^LK()psI!wYb0aletYY7X_U{%%|l1&$^A{ZZG*HeLfVxptPggc_GwXxfZmd$;& z2dY4P&#{BG-Qg5OcK~(tu7$&&Yp~U^pIjR^*VdjXMw%#>J5wOFw zK_`c97hkcIe2UTYpakb02r*=Gg)2&L&m_(@6uXRGDa@kvn8%>&Fei&co9wg&s|EO| zU4>YwKH_z5P7T?@jrkVPB(iYEJ9D*6prw90itx#RBsT%TfDQnFu~jD^hOvBOZ<-E- zYAquvH}zSc98JbFiYwH@d2z?^-NOJlJSfu@U9s|fLh6HRDory5$S5ar9df$|yD7RO zp}xM)s+42ua9DBxv6REf+>n$p!{;aUs5rR?T7^RNlBfcbe3G?BaTFC)Vrot8vmQO znDL-yuiV(Ld)LBD_JUMy`FzEs`XyOzWr#@d?z47HHJtXA;7REgcukfq?b!FOm7q#- zJBX7Mz3V8S;1!E@$-1QLsCoIKB^HrgM63rw!hqWg+Q|_V@7U6Q@lESZn|4Te3t4g~ z`?2briENYe27i?!l>$(;;y?l@e{8xBj|)j`CmUB6I;ACSsn1fh->tc7quIsMC-!v- zcq~iu6Y`+z>@f3_;JJjIS%hdimO~p`iL%mY*s^yLW?#p}Ti{W@Apyj(%D7{QEm!mv z9XT1k;!hc6IR*V&oi0yK9B72tUQm31OrL zFadq#t(dHp_d<46;&^#2sdprb|KajGmt_XUiY<3kU&pXYs0ZA}qhK6#%{X+96Ww8u z>BM;MM7;5GrN4N zSq+HI8c!+L<&LP&cA`x=Bn$;IsFS_+sM1K^A<<1<&lr?O1{a}4Ne1K&Ot*!Uh2TZ2 zx*`jbaWyP*z37t`6isd^lAdN}rkdqm!fSA@5;2?bT8Ls~O#_B!J)m|mG91{Qko!w) z@4C|h{sMKq0lfU!v^7k#ZQ-74)dv2>dR6i%2nHc3q4bg~O>otGp*zv&>16pjDs!Q1 ziKzB{va6>cUg?pb+(n*T5Y#t}vxL_m0HBR|xWpe3GS@#(i(*_G? zx2F+!4A3imY&#|Vsv0|y2LigO+e0pCDsP%1OW4A)x!TZoBS0jBY$_GW!IZ$~kP=$E z;@S#394&23fqspQJ+Z#N{PJ{Hh3R-u8=Rvqg~EDUG!d!*B}$P`+2FAG;ZRYbNKA>! zXl~b|(BbzAIa*5PUY%flpD!H2^EK)XZ)hIU$~ln24c2zJnD#h_%2^K4GP{E_)X|Kx zrHGg>Ef!c+f5}HR6XEk3*FA6#c~xcxYH-5!XMG?DEt*CmEUqYE@twU%B8XGz4))%u z==gN_qOv1EbX$w1+vV_F^5$?;)XQJA>}$4vc(aaq5-Ng7C*%g*XQPre_A=!43io9M z`o&ocGt4*z#zR!q=T7D^UP*6Y3b;4p2X0LN%E^`+X`CM?3WqNR(Og0qDnYUrcNp_~ z0>s` z_H_#dbx>f67!W<6kay9QRfVa%E6KC@C+n__PJBB`#!TMrbmP7HwIz3L?q;azEacPa zi^(`tb#3N2EK%;t$eEJaak$r#1BKNiN38Q;7%fTzSIYb<`elmf(Db( z@b-W~hv2j=@=5I?l=5~FmWA+=u% zy{Ms!T{(~&>aubL=#0UxxY|T*nMdluWIDSnQ+8PW0qo7@aT;Yt;F`53`FP=QxjfMs@XhAR`L#0# z%TSX9`y|k;A3~){N__FM=yixnHEkE~g!w}*?hXn5S~N0^mt_ELw7*CZ#C437?G>aC z3gVFR>lT+4f#ng`lsR24{m|44Wos_Yd`Oz21&0B~Ej+NZ@TR&UTTQ@jrSWm2F8Pt+ zR*SIR$=Kgy3E>uEh_F;I%z` zc&jq?cwMp_i@+*f$P(;UR@8Vzi~3gmRFT-FjblT*P)G`C9W}#BN4T#5zY%`+xt<0g zt`z86UO*;iwMrBn2}BW6g%TchAYCy!Z{h$_Co)5tm7CR7jh1Z95L93%0Em@%qB`{m z)y;x3p-sNtrE!_6$Rzp)Nm_M92uhbjU%bqOZcv@Xm)JfdlE{EOQ z;xvuH($$#|DmmO&l9NixVlGgWnsM>ciKMU~^#9z*?TIM;7y$)zd91_H)8(x0nr|1rz z$>8$-Yd$ z4iH@tDI=#1AR0+XyEmeA<7ZC2mb%;PmU}vA%U-CF{KP5NYCPn~!ssr%*httRZ8Q8- z`3NoTLDU!#74+1knCHd&N~YVhcg=Kt5+7OBIQ}n`3>tBMy}nD!(qOw;NDS z@YRfwt^_k>f;G6O?uorDAZZJLA!;bJMpx^5&ls8-*%n6v4w5mCn0S_>RQr*sO=Ki| z&~OFU8pli02!izKgu3a~t9fcj4TauaESqJXG(3kT%_!Yk*lnb@Zc+DU#FSA~2;*kw ztdQq<0%Oe^p8q#DwZYLX1xd*O^Fa6gMtj;QUgVZsg~oBuAR1^1X;pFLmBa>QnyMwm za%a(=6Qn^O1$`34-Y2ahdmC^IFg)Ge=H$l)M-o!V1!?6PSM`Fy=n}Q`;;kqn;_aXo zA(I`9C<+5IPB)HiD;;<5=8y2od63y~)(vSFn$s##32Hu`j(kGq_88Fna{F@>T|%Wc z)=9gLI+A>L%_v7WeG=HC>3+ z_27}d3B)qZfH|@HtwH#S=E&7+3ptdoo1)_cK;EHHy@mdSoV=VpbM@?b_C8&%A%F&o zx1m2boD1i+WjN02@rGa7d-`Ols5MaEf&tu&=;Q&y-kuzZWVko0?Im)hL=n z4sohK8>X_WlGb>g44VuuQO!Qn56jQ1Y zw6H@}`lXv{Fr|b~*7V5NitSEad?3ym23sa>+#U&7>oyhCEMqfkMuq&Qf5e~(PR;hk zHRIqD0_IJec=BV%I>+xQezA&%xl%e~C=uC3UJhx1EFSKv|uz=a7M0sp@6(pa-kUOG2_q^(;(C%LW=T();=s|Y@21P zQ1bK#!+lhX1a~dwIS$J;Z7EwNR70r^Z9sGR>^U)IaME!4t$hm!suF*q3f&)M6U}ud zQd)fT^&$Shg&B&Av6Uomxi;xQz+|DwFE*_o~GE-}D@(g*l!Is04rCTVEGXNkLr0$aH z%z~cH&jqn?uuLE%t_!EDmgG@d9BX$usnx=1ko&o^H)FI%`^Vj$XOQHhJd}YFrY_QW zp+lgd9BV*PiB#N;SNmyvHkz*LZG(-E?E<5ZjeSTVFTP-x7Mias8f-Mc79nC&jz+p8 z;cF!vQah{xK^t_Ney{{YOXEn^vUscUqJ1&YMV^g4j)oexg{B_@canRBBL-TarF@4= zGFF?1PTxXPG&<2deA?Gko@gF94MQo|Ing|N8oLW_Ao+;Xn}hW|0v;V%T1v0hm}&3ZF&Tara%+B{)@fqj{?``J zx>eF{lBxmG5D2xyUaXV0z45Pbf~gV_$+FzuLuy1=wT55l5d*v}M>MZR_OxWIaqk#* zh|Cn?ldc3qaUOq2{9|WR6B7he81g#4Ic9f9s-1Lrdj+werv*kbWb=*|4?3}&vIyQp zY$KA$99K7e091lcq?IgMoOjxCI0{&>i1C6l#4;hF>`IO>5+7v! zG3wU#uKwj^X|`K%K+2;6oFmOb&>^jf_*0Th8?B7wF3OfV?s<;(qNk&PHz^+SNjXRB!*jq0lT@{E`e1_t zqhgz|0Fd4Q!oRxPXr0VrQ&JJKBCR{JP-Fyj=9Diodh{GgxkCfesqm1s{O)pi#i?Of z>a8H1dcv)iq4)gast~VgC1KmB!vU?ghBTIqHo$;vJfE*>d>y8(LNt=zFIue3%-oo+ zS~()v6sj)!8%h)TnDeDbnk%1;sU{pp&P^7$*p7_1q%n!NSR&*_c-JkJup$>u-h~kw z=rvkilVP90d~*bKIl{&=MXo1isA#Y=VO^#2MJ{mn+;&gKIcaTT$d;?>ztl zx}9sWSuub7jZoL59`)@?{mo4XG8^)7%Tk$`?wE=8HZF$Rwp2#>p~|ow*leCWbA38_ zQBIn{ov4lQ-NaQkTv(QuVSpx%~ zZno!h?f^S=N`LEyJLJeeIl<+%hrrMSaHN3sWsrk-+&<~~uJnwNM- z(o<*W1VFtvY#PQz5g}`%c+#5Iq8J(CL*3hM0P4RPQVFP=>sK$vEQd(+KsE`aq)c|= z0PsW7&l=xSH+3xwH#X&LKHnPLEp0%yP0b=Vq5e5GqF&I-@~bmig9qwcIrUWo5b6utPi?1GLD1gLkm zN=?fq)@&j91FxfCH?w=b6|QzS7|>R4%x zu#Zg7Ah_w8tIRtf^SHwiHN(8G!45wLVylaLdo|MT^z!;Gs-{wj4%D4ozedve9Q$>g zPcaQ4`@A7{9nN*c(uuV0vdiV-fLsu;3@S@(9qz z93BdHZWddKo0S*vE37piqL7e{B;?q3Ed=h|91z8(R3oS;2pDU3Y_hcw5BDI-;Xt%k z90nwU3W@Bf7)#nBgpv$ilVS@?TnR>zb(NNAWv(1WvTN;W(u4WJKvV_aKWDR2EoAzf zibMm$T!nuuNx22TZBaIG4J#;UK3Pa{pWSkc+vKWQvZXqH$vX})I0UE8Wj44_S}6=R zdRGT}`O)EZA5SjNclw<9T7!dw9@Kw9+O;?j-v(T#=>m$3&z0W>sB4O6vd|UVll&Ug z%q9i{JszYH3- ztB-R1#DdVE+6am#zKqZL7j09P$|TI*xRPUP@L?35Id`#ng3)Qt+4~blkqy8kZE?_y zi1jATk)w|sEf%tE>6YJ=u#IR`%24Hd3s&~=j zt4E%U!~YWNHQKGzseAS3E)-5t&;xO_>ru7qtTuVc3t3(Tcqu}=zQxI^Q$@E;r%$DE z&0F|C061XLF41m)e@o8#>Q z7BdYDS)i_0jj8p9)!vaKPpeF9Q#E?!(g0qe1L3kb{fyap`~c`7VJN?*4tbF~j}B<@ zN+~l?sO57i@B=&rP4AfXWXfx(C^w@S<$eV2g7`j?4AXbjzu2~x) zZ2})b$==dxoZ6H$Es8a)BI$Il1yq=JA5YNR+XECY`F?h99e--&t=!jH11{oKAERyT z$V!rRfoLJA7DLNY%A%c8E#uPSBEYU0bQ3^*X{n#gS^}6lTCa`gK-yC}huy|k!l5Pv z%yoHYIwW8P;^(e(qTTyrEw&Lpi`l-~N(M-mWVw?)g5^)ABn2d*?eZtowI%LEh$3ml zQ6x8$_8@03inj7(^B{OfHWiWWehCEDn&a!{-%hov_frwXDhyGDXeheRE>ChO6;UfT zy3}i&EH0I{HsS#>uAe1}!P&UkMtwSE^SrH^*EuZ)i`HAa3)}SUDOoycABQ%<*GJi! z&oe-i>8a~bnM3?wWvmtF6nZvn+zQ2aAiATPZ{%Ck*K4!nq7DjxT1h#34eGi$%9O%G zv_NBe8jW2T3`E_f!A4b3c_AhurHh5of?Nf1QKZx}mf!`*xE%UwUnu6~fg{TT9`7K7 zO_un*CEh0HG>x&zF%f`#vXM!sLaTzVs#gSyZ%)<~;tZg5?o;>ds;n}k#n6EgU{(dh z@;cIOjjPY93riA0(PP0e#*3b-gfxN*nBK%rJ3YS_(dV(X<37t8~sLzgb76}ul=YwS@7(w|>n#=amyUEzchGPyf zH6LQ()Q6c6gfAVNgkLVUh=(6~=;+acUucI4D4qww-g}@gWi>ajj$E6a8yl{rblQxS zDjXH+N>u?tZWdI|mZOv95?LY!75>)b1=DxK23%=}>MN0RM}BJUiINdwLH^s-xDG{E zZt2uEWSu}~TOwYLK3FpvaR>bmlgH<7iA z((N#XXiZBHCMXZ~gv}WVC}E3ayPJ9peY?o2KN)5xX$9IVK`Q|(Hlh(zX~X&u7iw9SGuia)R`a@t z-tjhA%&Q<^u4oZ4Q4f(zybwi|zLvpYw~RZjlH7WFGG#w(RZ!{f?ZlBn++yhx&Z#t> zI<2=E2cmLI%eJ=#BsM72cbp8+ddwZu`&Y6g=pHw2(>oCN3+dxCvt!amLU&UmnoFg+ zu`k9(n8S=F`x?Ta+of+PgtGEw>r_EZ3{2mv*RuA*c&S%gm_Xl{Sk6O0n~13gK`8sH z7kwMOx+Cr+NB_~{uE6nK{2e3EX;#2c-hRuG zhE}=)Knh?hsJAym=Z1(Zb_eUJx>(SvcX{KRj6kazlm;xh93x)T6~>0+&f)E%ls|1G z*ygR)8LSO!nA*H$NLr2la%Kemad}&?%yA=@PGB)^sgef2inR^CMHAOL+Ls_vqA=ho ztu7b4^{$j&4FccQvb`MC&bn$j9`Vu+&IcA+c@Nx_?r95(D!#p>q85|h-v7UkY6O+0PzrsruHfZ z!B~#f#wI{3WEZ1}uYleyLgINrD5ua4YmI7zK6L@BO_A9cM>q@=w}ApRH;Y5rQg>ip3krD8q9ix2>v4ffAEkHRf{2z(R@+ zls#6d17|OUh-ePa0c_0W?(ai#w&`Xvp@0wq`Me;BdW>c(^)z)6RFj2tG``kYX?a9s zax@GgzyK5!xIWmBUrA|tYJ<#Lh5CJ(vr!9THf@nBunThuAgD5ftIIOoP_d}=iWV_= z^NNUqut&$tB^bPA>4T63#$QK#;jUcqw0HK#Nid1!7br6CV$s)*1wfW-YyZ`7mt&#& zUHe>SC@guN30~9JPLeCRQsCBdVr0UXyK)&(7zht$Ij9P92f^v4b3u5>i$7+RfF@6FLjx9Kyn!14x{F_2HA zl6?ysM#w9XyR21s`f&U0X0%2C0UXG*63+?QgbbjN5XDQFra|MhYzV5x2=oip-?F4i zT`-!5khZ8jL7387AB?c17{}_iZAfWM5Y48HGtXXo=&492ShBIJg*&Fw1Bom{lLA=m zNKc?)TYzSXO-h59cKM#`P=F%&O6SQdm1>H*Eekh7j*}#-N6u~!@S$KmaktvwbV2iM z4RU+cEk7oRZoQJ4>)LXyo=5dYWCjZ;5cdm{^>=4EW=lHSk6`kO=vVc5;>(!48O!gE)F5 zld7zu#mbe_ZF~)RG^f?cO1m#FODc8v)?46}zVyS{kUU@?V;FQydYxh1Zi#SVm$Jj8 z35KEwe4A&nx9DC0hJ9CGZc&)#GUGH?c4^!J$5Mz(RzP=Sj=;NX#VuU&Uf!EL3)r?j zrPFaS@qvsBtMSn4>zr8^0?DFJW*=0Fo?A~v1Cy}e)<`Udt&cHILADjYx-8?NI-chx z-qf^i#)}mL#pgV3`YSujaqZBKi6 zjjk-{^hL%2eRU$Y2QQlXZFQ78x;D`(rP9^ltdTIYj#XxI%8;}V?!?Bs!na4RCmqh| zNyJQpO$RQMn<8P;T8NxTFH{$$)sh)+SrHw%9*SKr&6)}NK_G0(!)N=Por}%V z^@7lI>ZrM2&0s=n(T%ADCN!k)EdqxWa13+Lt`a?ZSpmIlmrJ_AoUjvh<(giS(xqf* zPYMgP86^#z?dWua+W|N-)h&Au1C4u>7t$9**U)`&=A{)0d(&k#3una{ ztx~9x7g|nRkWo!(aiIxUf^_nId8gTd9@94T=wmjVJ09(0PVwZ*u*uc=I{QN?)v>Ro zO&c-`LpZ^<$_6lCZ>pzR7zSLOa;&%vM#X@s*yxb7mf3+3!Uc<*yQ#%G`oLO`X2_RS zhzm7qIN38zBC>FKEi4XiqBSNaz_dj=6|WJY?ZOspLA+RuW*}UZOHB2FjWh>eTTcVsMO#vs3bR9D)SW9LyYBtNr%IKZgNz<)>G#iU>CtA`^NVescV_TwCdun^9i0+vph z;_4Mu%#rg5oTFPTYWL%1h|ML98sK~|AyX-liGd7Ap5fw8im@ZJ} z3bg!eZ(Zl!sRG+NT?wL@7vww#foRKQ$YpI^4op2zkow-LXeJf)zGr=c7~hG zUy}2j(L}_gTMP!`dGT0F`;lyb7=|3x%z|W{#>J|7wSQg}RoevSLu`$2#r!paSin`t z0~i`fGN=<)nimU%=Ka}i`g1KkgQ=A|Xq7t}YYJS5SP#GoEr`0(Zg*8W$BY1Kr@WcZ zW_WJ{=^?=OKc7V4i9>k$SLF=_tyel+$V=s4Svb6nbuYljJ+0=XMg0TUBG)Q~lG4xx zW4&g@I~H#$sopEp_A(1g>PI&AGfqx|l6`Sb})qA{-B&^9s-W=(oUFwv zjhUw!&a^Y$mgnGMhwbJl`mPt5tR2X729blrH#uQS-#GgYQpaV731K4~wPiB$zveH+ zPj0C}KXijYMA}(*`cs`u@pGXV{FWJ8vLehnNH$^5;1r@V9 z)Yw==ak&-4a%c%jp5MQS%&b9(Vt7KurDsl!^1~JKz%Nh{T8eOK$fha#VSF#)QB00b zd6Y0g|2u^y&3kHodUpkCcg8Gb+kB-FxclgNq5L@1P~%L!+4gCsA-AXwDG37>b}_Uli^H*nP(|{3Bv*SBVxivhyR;Do675PvE}pUC zJsg;ZrJ3d&-mY^xO*x91ANtbw6eN?d5EaE}Wk0oxM`Sp~GWJ`lbdmxNG7yjzZbaQWrWIe1Ub6J;M2GKmt56-?I>F*gNXgZFjDgv4& z^|arUa^X_Bh!(^|0f>45Q8*9N*n0|I6?=BbAQ2Ndk`Pj=^mg^irDWyy%CgToZ_*bt zaS2}kY$e4dE8|PHE>*L`<*Ev+qtI%VA{>}NV-GmdMt#@HZG6cP-5-D z;hAns?2CyVd-Icv|$u z8$!;ma8vk=43H1Ng?LG;-v5WaH|^EyIL~zVXZ?yd1eB&aCMns+jX*iwhAa>5)1F{C z@$e;(E!t5>6G*9(9P|fSjvWUOM4M*Bjv|SY?31{04iK55ILI1+{DOD?h5jXdUH4P9 zrgy!Yo0d9B0|&M?_g<@3)l<)KKSR~3^;G*jD(uuGCi_8aLqrHDk4l;6yPMB?;gRv} z&6D51XL;q(Csr=~(_1?iAK$&g%4WOxrB2|<#~<6d#Gd@8bMc&G`(>8AFM04s*13%` zV%>Ttq>$h1eStt=YvoSOV}fiUC!({fY{@Lds9~$WR(3MNK|LR5VFtIPs(slv5&a+- zOT(dWZ_9_Kdy4mzxeq+@FnKN~rS5C+r9|{8(CuyWHJP~gZXG|P zLp-Q2K;O^5=f2}vk1a&zPqPy**D;_Js&N+M--$fWPyVhQ$EP-50;c-rjyf|lA1NL> zB3iMqv(}Jr7$?m2M`JQ;ihP3fiqIL*8prXJp)p(40m0-St+7@kIAa7|uj;&NHO(%+ z!&lM1-=2uJe5Dpq&z()V8Gl&4X^@j&Yn9qeq2h&y2X`|zuQo2@?>v~b{gCD1CzD6Y zhkoOMuYLIoU;h042jBRQU-pJs$Q}~@ z#eRDTrd8!aGwxRF-7(6+H}vRd7Udmp&@%f4n(P~pi5M#m85@6QW75Gl&OSy7^lbmP z$BK9JIgnY^^8q&33F1%Rw&geYO5nLi4sz_npXHrf0&sSexM3+(fjHIr0Bv!(RWVRj z6zfww$&yga!9uj`tg=v6LKjDF)@tnTxR9oZe!NZ)E zAyr|gNu81_O)eTGRresh+Wu&eU}l&e>rDqk0?O);TAtSvPBn3@5x%sbu9M)iqzdj$ zY2Bntt{JBwO?ea|eSYy0d)pHx?@*5(M-j}R0ogbP^0_`rZ=73ICqYk34sBBe5do&^ zM$cA@s{@5kew;abuQ~*%?8F1hTC@Ak^P$O45OLh5QDD!`IDdo;Ze>c-cQ_Gd9iQE% zHQV>0Bp+i1u~rru{jEIR4o_iyheJmQyE3CJMy2c{{{ZByf$-(WUg3ye>lMpB7TkPh z*t`93d+W=^|MP!ZrGCzRV%ly+ptjq%jL3cQ++Bg0F*=_;-&#dR?V+Hqncc4FNqdd! zJ7;-_CH-(_4Du2|P<8u0{sRMMpM$2jA*I=(r@5kU{8PPTg01{q#m>{4(x0r2{g*nMhMw%vQJ*0Hsn{c9~VsY2Xvgyq8=m`@Bg+0WHbt}RmZSQ+Zhp%5^pN9fziIOP25h%K<0EC{&{oR!sJXxcpb{b5P4 zm3uKL2ctgZk4?_nu3uBEt@>0#nDwh79h(1jgUw1xiSxc8#c=j!{E$%8``&K|!46w}FOP6J&2FSD_ zS~JepZIjD9UOaY^lheIel&u0s4x5^g($;~AI8(qtMf#yGEoQf)p?v8dOoifrfR4p+ z$Xz?y_JEHI4EqDRJ>)|ZWtph4yC9av_|0$O+EuC)8~XN3mzgUZ*Xnd=T@-iNKAShG zU7>Pj)IcwJet!XIx*=-w$$RhS^V{OHwre~v7SRnWR6viPrQY6mG2yv5qFk98KO1zgB7@3PfN6Pdk!bi4vRxF!;7tB>Lsx&C@MaU>KgmY7_#d)~ z{vr`iD=fW6jv>w7Dh`c5e-h7jPm5$7rwh)yUE+e0QN`B*!}j{>siLZsz6Hx{VVOQp z&}Oo?b6A4bnN+NwuFzknIAfoN&VGgqR;9D-?5&KR39wJ^yDW(GP0(`v#DjTtqPHTbf;Yz>mYEDHD+u~L_Zb{h*me?kJMZpMA>ovt{b;n2_$7r5&L6%Xw12Vz_TiR4*p=;InSAg+$0$mMAG!p`>($VAwgtz zPqCdP{$H_jE6bcG1;2t!@1O`?feCHXDOUs44#d=@}ubUGSTW1`8 zxpPs_nslhyKJyfYbI^)L{oi<#v4UO4Y|d_$EFf29816*lhQ9`iP(L5 zNer)}*3u$=dwSo!PqPQk`&FZ93#^+iO3>+J6leadMWmqtdsq*$kfQ(cYc_Qx+x=)~ zU%O5D@6^2fcWP1o``BH*liJ_E+skeVkaz0p6-y#e{7b&Aa{53wcu-puOX~GSweO$# zE_K#}@1J@6v4b%?vQ$7>;`{-&G!mSl{v{Th;o)peeE6&~HuF)gK`*8%GSPp%^0+Ll z=4P#$-033vlBKh8j<zV?-G+>VQqwN@P#L%p{{!)Ydl zEj-3QE!@u60{FA6UpsN(a=753vEbl7RO`x6* zAvPy|?}XnBIvAKzc043D=MMtU_4Dkx{_m#9tXInphL^`Uw&XP1dnXszAGUTOg~Q&u z&Z}s`W*5wO3T{vJ+P|ABn~`M-GlJH+(gWnS?@H4hbQTv9@^EMj&>XF|IpbG3ZxPxaX(OTj# zq#1lLf4DZz&8A{3hYedC%t>dys<$1Ru*`PuFY-<~U5uAoS$B4g3eBH9`N;f|+hS4S zKOHoNEz(avc|cb2$U$tYQt;+|vgwcl@BvlcN0<@uR@NO;IH}@Mc`MIMJ^M)Na_!N7 zdh@}9uhtU6sV_WoiUmfWyuVeF@A~Rj__(R>B$CQ}1|NI>=HvH%{NtzY{Xb6K_sPw@ z_uhZ+y?1?)&7-HX`HPtT$#eH}p}sDA>g&A2c>i5r`ofn!JNA3u>3cn7+yli=xq<5b ze6ZpSg}6tb_ye;+^24Y9{U3h)bEkfPY}a;{o%$^6CvIZ7fAjksmNN`=|1*Dj*FmKh z+pF7~+jqC`Y~S0y&42HIY_om;@CVy>4qx2<=J0v0-`s4kZus}j!{=!67I&XLeDUxy zo7g^a_leEn54TroI_ZEL+WzF6LKatc8Ki-s@?Tzi5{C;zL>-53hkL2?9H{ALO-SU_> z>3;EWsQw_+c@9d`YWqGNoWE=PGak842bY|4QS<)xT3TJ--gFY5q8&xW?d9#?ZGXCb zng3qd{?tET-u~EM+wCjNz?nREcmdYE*BEg4m-K&Y`r*U8|nyS8s2&Zte4H!7uKH84W8E(~Hv zGmz;`nrrmI;F4m@^j%R%B}DB|zTemYEZbxFmrox6J~Nxw^3hQqxzQ|GJ?X@0#%Qbr z6p1(6f(Znv{B1uC%>QSx=osNuMpL`rL*E%13y~)U$}etCOf4{Nrr5u| zd7>GDw$i4e$uXU)fsF!X0iG7x$O8Ad0jmL!{LsXh;a^P!p;cWIRIxpb=?1;rJp56Y z%6oDvH?CqkfA1V7kg-B=gI5Q-F5F8h_(nHyRNtT&N%u9a7vc0ILwUpL^=xHSWK!`v0tVyYx`^GpO^({ zzsa9^4}K}0$8B$LyKNSE@bI$YANU1{{J9uv`!35%(dcUmvsjBmM1I{V-x9J*)+i)) z2A^>@gg?7nEfK|>)!CVNVj#h9bf&o+x{7$N2DvH@ySX{Mtd7137otBUc^U>ZX2z=p z01KCCqHhre^fK==O&rMnM>Yg9s>C}4Tli?%{a#aU)R^bv-sJBGiqC1~zaKCh{JIQR zb(`p57}HFSFr|2-J=u3 zZ&sjP=8bG-H4avKZNvN-vyYVH73>?NhfLk`g+XAdz?=8q`LOF@;^^lH0Xkgg`kY+6P0_sr}5gYB!rIP6U%4l5e8{F+_(ad+9dqM3cA+2q=NFN5rzq|b}$|PM0-+otyAO6UJXw@djfNEKrbx|=@-iN;a z#Zx`MP{zORd?~#WZaOWI=YTVsI0+Z@|8Ax>K}|)5Nqp0r-9sTz#Q-3I7q$tFkVFEreV5%%_Y43f za)HWfk4fFVo0D=vn{0XjUEv`x8XHeqyS;kP0pBOFwFV@kRX~u=ZtgkYErDo4<;Lp5 zJ6@yFO^8C5Tjz~%pL!GQUFs%A`iak+f`YOZv@FW_qAh2(fLoq?bo$``+(a4U)UF+n zdE&~-?4bnTs!E034Pw2Z6=bf0s#cKjZsFqg;;1f0@>=3kel|K(7Amq`!;Xv#e|UP# zz)VnP6cIw0nxfY)0DyRD_(;SBn1a+H`l`qQ;qA%kAb8!Y{BOv~`_t3ZwmkQo-b$S5 z{r!d~0t( z1P$F24{<_S+rK%ygyv}Pbk{7<;No^YR!oE~X*D=^)b-TnzJGV`sgHkxFE>2clY*~) z@qvoUK7QXPPksE8(_0UG`k~cM{@t|E@ce!EO)vZGCVot33i8V}vC{%W^cGhxj7%bq z4m|-mwR(Gl2j23rm?+h+cnqsEi7Ma+riMbnq5)(S0k|w^iEO%9g8zzK%Fhvtj5d8h z01+78_|fk(SZg5aeJ(yfy9anlQ=${x1@Z6On{V5~@Ixx{2;%2gWYcg-h%`kznFcpN zQ6bE$Alf|#+c!#4n4un+5!(fCA8api{lWpow}w%$tR+E{i`ADG3{5@=tBT9?uyPSF zq@NZ~wQ(SxhkcYm$3Lo+*FLqD*kaVvCijMeU5w~1e{TOe7cq#-sx#&T2bdV zvEmDIxVoU=HqT9jdZ$C~XvMMvfVcdFVIvW>y$ipueM2h73?8fHOAMU!){VQXl;_jk4@I zC52WuLD9btcJe^NV%2KVN>Z_B$vpf?>7vGQ3))fzjBbLzmmMK-1`IIgg)}jvG21kO!YW_t@t5C=+m#uDqd}`+$Fgxq>}`-t9YL5+L_6`Vf_b z^a_TVYItYy+Q4iW>gZ;h`rKscEm`JFnEU#60pxh|yv^XZ>t_H8b@YRl(ctu}La&&n z0c``U85;}?EeJjICy%nzA#8Brx0SOg=hp+(w3T`0S$TL_f@# z_0*;W_AQrgC*4JFJ6$M^DgxoY)HnV_3>vRPjn-6Jw&Ttg{V)CEUXaGsFpC??d5DMR zea)PCSTu`?7mX|E1r7IIZxapdFwKhLQbC!Sqhkyu)Kg>@e%Gj&ZDP0{#@SQ$^C}J=zPjlWcRbd{lw;!m@`#pP#pVHGd4T0QDS!s zh%Pk|JU3OGDOJtx{e$gmJh=$zEj_n2?bZADZ?-O*Jj+CoUb$ck{MPYEFkHrVsiwO- zRYZAo$QjCo;ay^E{J362@T)qG=|=oTsv+SgOlXT#w8|QXOX{=wBcw3446~)lx{G2o zCuT0s-YVk5VviN1ss~xsdK)1kaFm*--q}&?WVkIUVwNenCrityspl{ex-5wT=Mva+ z0fL~^m=fJ^`(6R*3j)n2MhFIV9@{AvX8t09dEx30p zwz=zG=gtFmuFUfEK`-P6yYkFj-3G6G5#EY2@W^cd%<-Gwsswzv+TuheG{ngnwT6}# zIjbU8%x&S8_s zRh%Qk&RBx(n1GE;2VumpKc`{nOzhd-kCRxpwKnIAl@1uVh^Mq^^Ng7YId zH3&k5jSwvkJj?Hsd(-y29X!CnqeP)E(JvzlB&vN&4t}a-)0=1m4)R;-uMlFxLLA(L z3OKFxaI1@?Y1wg0JZn7-g1Do;?g~|~*)*rDc@o)b$tAe9PS#fgT`8SOw9v(w$Du}W znro^>2-{B zZ>tDp$u|?1xE8C+zN}ahm&&TLNa}JWxS=?t0u3Qz3pl`amQJDOP3BT=(G1tkr_qGxzO7bnJ9x=eG7ghm2i|*3=+)!Gp zolcoe!DtpJqIiedxPcEcB3KsD66e8!36R;ZAcz|>822f};C!izfeAYt+B@&MAy&nT z=*ln&=bUrqIZa^2@Xmo}cYxlCP!C?OvArBPAZ(ghV1Twd0#wx3v>dTXy4|lz!tSZ!K`(VrN^vQjJno5i!z`q+Wx%v zIc?K&Xyw#s1bHI3q#(?54~-z>)P;}j2GaKovws$oS@+$*aI%L_ppX$ZS%tiakAXe4 z4s9Y3m8e^kZloSeWcDJu)z*>1=>!u?FGz-6$$D32ZvQ)}>Uz(}v2rN%)M>;RvTQux z=&&-1>DEu$)JZb5W2U~l(DWwDOutaLv5Od6^D0g1E$YzB)uo|a4eV0a|E(XjF7`6| zLcxsuEpB$}X73;hAV64ZG>s{|zI|i+8oO5hj(G8>8)BcI;@W?@y`(EQKKv^hzOy;8 zx7`Wt7^4SDv-(H!+#X&kOu7TGg>q$s4th zUD!e2g3`88)MYWCIWt?WRYAo&S2tZygOUZ6a-S`RtWJsqQYR4uf(GVvSZ#k))A&Uv zK~{kLg56J+rEfoUSb!Rt(d7NazV;nLw4_Bdjam zM6iFb<#`?f)HabQX_=Ncxr&tay2K;K$<*|x?cM-FT|N~b3(dN9W5epR@R=S%JrUEu{Z%4+oxDi?b{?Wu!i5SWoSH=c~z(x&@L=E>9VCp)s z;|l*+FEM?%jueM16o!-2-o6E^gA@ComuXs2dnmvI)<09dEmkQ=NFw_C2^YZP-8(aP zpNjVF+kgek1jbCN*01)}ZweQ+O3o&(uHF3a3$Omu(l+wlckvi zlj0Eb8p>{V(4OqB@Ew#)M`+;I`vSmJ_p0QvsdhBBxLWV{!+N7 zQ^hDcAFX51ij&)s-Mffw zx3GjMyVboQKlyYUb5<^^WIYQ(0v{~7H83L1&<*4hjxg9o8ciRALX51|y6^jawl57G zph?jJ=g=hCScb-6EAB|aQYPJJRRco6++U$_hEYL6m6;8mspv#&Fs2kXE=)lVJy45o zDAtzqG!&lSd6hqzGE$(ml`;b(^gxmFyNcW5mKnUJCL$0DSk8Lq4UxDOqn`nY2zq=o z1AW&T)e(ei+z=_KTn5_e@Z@cmuePIIzD!6~AcGjmb~i~2qgF7Ko|?_zVXxSKChJ>y zZ&LOBd&}mnV`C>tc8!)vc9&mqa)uy2z&L9Ue?6ujTI@A;7woi*u>J-N6)1)R(gENg zOjk&(9V)@Y&4XWi@YE+hjfppEM{)$Wrl#_Ex+u-AJLOz13p_<6mlco$A%wjD zDyLIBi)Pf8Ft-A)QZN9DSeyhT>c-qPSvsC>?YwrTyvsGPz;Ej>O=t6nK$bmpLXojMwiz?32 ziGSoAZt>kzO#r3_uXBcZeW|(8iJ1nzCKm#4_{i4#LTU5RQJM+!bxU(yuBYZC&DHO& z5}K^7p%+Z0OF9|eY!YLS=Cduf*A*wiNDk=gnwZdP7V{m+F>PH(+nRp(e2MG!-AH)! zN31i1j0akD)1AUVPKL^yu5MXij|B&5O4ZV7l@ZD>#hqE{K&yXe)3+}4eQ%PGdQkIX z)7Hi^Stk~|b1ncN6<;_Mh_Ef!P4Hszfzzkq!pl=e#t2`;KWEBr%1u{sYT?y8<=Iy@ zD8vadvGLFXLI?H=!Zv(0UJ349o7Ma((&3^t2RhcoCtDE>4{FJ&>5{K1w0a?Qx7U+Q zN3v0Xp~rP1-$c8*Ir(o-fA`$eAKU!f(@&j!{GR`szy2V9{MT(QT~b2MOHSLH-2J!i z84=xKSKr<n?vm z9K>X$#y3kwhZ(dX~!9Y;Zgy=AxR3sks{R<%6dNT9%c<}086zs@}HrO%!D z1pj^YYk&CA14CD`xarlj61|7c2n~gYu;kI5#_f$x+MV^MzB3u5G@bEkZ*Ze68TC^~ zPC6TAwKkWP)}MdyE1&u7nbZ8kk29yA`2Kg#eEIVa9{q6MSRQuv06CrE1%p%8?qw^2 z3{I4nbenZ-p%<-nFFVO9VT|>sc(o&&dWlDr{eNBxf^qb;G$^aWEdydG-MfahtvX-dbb&&Ox(qeL}(T?6XPfx+Xezx!RAcn=fj2Qe^2~g~+_^G7&F_)RFQ-t!0 zd_+ns;vm1M*X{$$gh|JJy?oj5%=R_4O>1JfVezHCOr=vtLD9eV%1CSwy?J(0BOX+& z0=r(a!5dfWRB#w1#u_JXur~T?R2b6)XsgsSdhrS=CU-U`6BCWDcyEhAk9Q&<9-&rx zEb@n7VuwJyV$0s<#AlW*E*WfUsIQHC3iMvlx=G!*1|hIHB)V!9xnn=Ed16v3D8`#` zzNaVYe3P2vWOh>C*vum&#nwIVmf3U zr|;nbd+&B(M(sw~0H~#C!$PJrLlXwjifR*JCFJ@JM8rNU+9wa76GP8FCV4xezvGU31%}{8k#Eig(-=r_HL}&|yb1?2&v6s_ z{wfwR!19gcO{&WW_B$j)hvjLF>8x};;pKb$H0c8u3Q5-S9sK|eR(s4@$TT!mmpauh@M52aPyk1YIrNi zhKdU5J?~uvPH8zFDh0;($H$9u1qgsFQ;|tg=UD-wpb|wj0$F>S7L)2e50tWIe`_d= z#0etyJ^s*4cnW$aiH0-91R&{dgzfy#t}I#rj67|Wv7wL zzNepl{HdnpzvW!TtbPcioABFQl|R_xO)sHz%bB`$g4?M-)DrYR@9bI5ZnLKvv*bGB zZI&@rZP9oteML7gRN?^40uKGH(`+0e z=UFoZSw1Tjh=CjBFuV=o-&P=7F)M2WZ|l|dtXBBdpZ2PaD<-zxJqQu&R}Gn^NMXd% z2ugGGvaO;7{@_9#1eFlIfYK23tLL6M|F9o&Se*6ICrT z5c;39H@PMF7>eX&Bz02VlT_3A;gyA~v^Ezq@B*iS#*)gE_mbaicj!zo_Ka=OqcS2q zKr(Nr>8+l?*jS?42|JmnuF>cbp+iBdw;7jS-+a7=m=qT30>_ciA?E(34k2C`9x* z(I@kcVnmr-{cs;?n9p?25NVe6KTTY2Tnr*e|lnIcmWd?yExhi-omg5&9D*$nn)B zH`+FXD(l2{AcC^dVhZ#KBE6)L8?r>4Sd0 z#!DgBq8%jjltozkT%6n^G{f?7aOK@feVeGSDN}p-ioYl6M%-jD_Cxg`SB4==LFTqM zRq9lxr!>=ajH545Y5}(8W|*a=vW2je&@_ux%~uePYRAPPnoX--{fA>hhZ1qek1>N1 ze(-^=`q8eq9_`bH9mlpeCdn>}{U5*n^{+m(`3fJO$-XA|X`Nr+8O+5au-bWsrB1Bz z9}#;tn;V&c??OfTwt7;sPuz?WWJ1?5Fmf(H;>cZX*?rNuk(Z;ZMqB4kt<9BQuWr8b z5EI5U&>}`FZ(jMHE3GIleC@&B@miIej$7&a)=aVO*U1Sh^4Nn4_YDlo`miycBgm^b z1TMuv?d?(KB2oR^a?@97=1>x=%KSP%a@LKgi!eNJUfN}l zGP|HQEDG4KVeRY`L3V>miqjQ@fUsOGe6RI+gTrsbWwTDrVUo&gGnS*-znv<|;g6g` zY`{UcZ>j7_)x7g^vlSrE{;f{E$($+W&Rv6v(Y|E+Ks6uj6-0?~YJ5Cm{Bo-7C1d5( ziZz%BQDCk6uU|#6L1Um{3aLQ1EIPatr6{*Y1g7+bRvQoD$H1@_04zYr9UqI02csP- z0wWszkI}=xU9O@a`g?Ajin?iBKf?T9_EPM<`q2gSm4^v&t~EjE`pRAw6`jqkjPYh7 z68uRf$jo8Qw7@hta{A+*KgF^-oM7UKQ@*8}#nM?bXc%mzCo!Y-wF*tCOO+ABC3R_3 zz*T-O_PkD45!zd=Y~{l zcFd+;Z-Oo8fb&S`>K=fo>b##;iSog|o#_Qy%=;k=M2i*Iq}lWM9nERZmBDdTRGgFo zHEZ$1qgkD@h#nTICgfx*qCx0N6^}MB5?{E+qZA8UpGI+ z@SwL|)dAkrtZ4Hr!6o!`psLHYevR;_n{b0Bpx+^J>`vpIQC8Y8;&5u?P6taQ^1$z9 zqbPiT>pNCCGnCy2BpK{Aa|6t7b3YxjNE=?6*saZT(xJ>9r)21|q?bWggOHV$l~#=1 ztu)yu=eBq(CMKUDm=kEIAn(v)i25w82!^$IGeF>N@!SykPVugA%GhR4*KJ#b{ee_H zpj)8<%z?vlhHy8HRjI0stTb0Ib`K<5&g>)Cj0W_{jw73i&8|qg0{YvF8&fv~nBsX) z%q%gCTON0DV>#u-PhFV2R-2s^bZicuFr&ST?uMQ9{W}|EkX@_LEtH61{o&e|VY!M! z2sS59omdggsCep;p^mztkJflr6)-R1>@^$E>C)0S;PtM?h?D94cSfqJLn|~KY;cMriJ5WQJ>T&QnNmi>p|Tcx4BaMYZb;lDUGoR^Ix4N@vF_d({-(jNvz+hjxE zwa97v!(SH;e{@eP3=u;ilvKc)6F$rd7YIvc%r{dEoJqkKD^6UlmtpohHEx|saxp7A zMr)I*J4x6jXdE`WE&gO^Ef@k2{w5RjR{%6qBne+WFt(vvlzs>3_C4q*jOBtp%yVho zG%{Nimt)9%X5{_r;E;vbR^;Mpz0x;X@FqoRZ|7US5|vo&s5+(W{Hg0i>70GL zC#w9shNJIZA`fULT1C{?_+K4_NC2At8Y(Qhc{K<+O|4Z+mk9T5L3SR&ZQC>KPR?99yx z428?o!V6-D+DSPYddT8~-c;|HwTLdN-5#bpGaCL?tzh08Mj5s7g_7)ELGjyqQm;1x zxBZBTA#N`Gfupid-fDDC0V|B1@lXofsQk_xMfAB5VM9ZtW*1?vK1Yu?xOgjM=OVop2|{=(Hou_YW^Snc2366Mj9>b80X1^u_ z01gy1OVeft%(X7d<3ecj6KVp?Tk#bL;G5r4E0shTPOp#~hzb}}W_^*DcJAi=e{rhh zYz)n3!|p!M4gwysw zU19IT%iI4}=Y>h&O_g5tDpI+C{XIF#?1$mL0-k3{*Vb0jqM?EU#)Q8e99Rx@5S!D z)Dx1-J96rTfd>79aq9Z;x2+YflTo@MU@U}NLB+Go7gK`A?$-Fd?cb?C#-k%o`D56$ zF;kCa4@vx!FYSALL1L*>i}~kem&qQ{nbH9}J%dvlCq6x=<)JQF* zLYo2$h<;mq5pS@x*@i`0$K7N2V=)=4x(HX7b*0Mf-q{1FD-Wph*qA@Eg;bvNnWNiesDrGHsQ;r=I}_=FHj zx5?L36GxeENNQ^(+c!@P<4xAptSAk@YzWetDidj0ki0axj_T7kl?)Av1)7m_MJ6q2t+pI72$ML zbBxL_&O`JC(csc zp`J#1-RxxC_zY@SB5LWyN_Rb~$wLs{<`Ryj~^fE2UCbj9^tvdZ>hm(X{FH?qX8kY{`s&>h)+UcH;D#gH+ z6P47TFsZh8$MjzmJS=RmcLHy+-bPF=BQl5!CY)HvyK1^P`otj(a;Fy4lXJMNO%5^F zmSkhaG|FCuH_LU$tEC?hKSwL5skR*MnXH&2%1Q7RDxFap4;p&3wGoT~|!38F^bI360aj zIEE02jwhEX&Vhcew-qx7T??}3gvw9`N@A&HCz~?8wde<+I{8>p~C+gv}?X<2wA& zsyDi$egaj3AJdbU8kB~lj*w>}&>>_c<6h9Psuf46!klZ^>?8u*CmvN}O*}qIjVD&4 z5p4+_d$CBnQb}{R?T(`55Y#Jyh}5Z@r=tt}o8=UPQ0ydY^!yQoZuWvK3TMzpg&Fq> z8W<`=%Vc2wT-N_0bUL1lA$Y0jZf{5xKi$TkTggkO!%XwS%KN0^y4N3-BZOSviEtr7 zhUC}XapT1&#Mx{NoATPu1;ihLsBYZLE>)~97ADkGIb~Fsx<$ybHe47u45+v6Z~$9( z9b}I-Rs9T!g>v(qumt6;vpxJ~3h)8)&+ek5+G z`=}RG{dMcuWyCU{BD9cTf->}}8h=#uY{rcQXh6Nv&eBSXy8JAk$%RXU8ZWF3y35VP z$NKBlZN1tJe(cb#OGR?ix&f~mehpb+}bgdVDycBKr z4aQmbWprK=fH2G+Gr37YM`o?BRrp-_@B*Q4f6zzfvJ)D5gNTSsb61wY9VHz9xv60q1o~{}(O?^$* z-x|6BL@Kdz!3TX|D^gsMAD}GKXa=xyB1T9S^JhGb&S1a=YYG`QUU5RqrF~DzKYKhf z2~`X(o>j(-)|(sm%$|;;kF{`IhNu~>;E9+ue+wRW^IbUii!Po_Ryc`Wn&5#H;m>l# zWGBMT(?ZWmJ7YNfteh?|KK6qlweNReB0QcdWvbHy2Q-~I;rj^58D*y^k@#{zPVS%2 z|Jz^q>g1fc9nSvFg7Dud)iv9#7e*muSTC^bG3&iC909sA>Z*h5Iti$k#h!Z75d4D3 z*y<}0*lS4s*as*54Vo=xDMmMC=tdP`U-KjcL0%C`q^qtZN|%9X3^tiBltE{($RtrW zAsTq;g(z2PBQ168Eo)!a98kN;Rg-B89AsKJ&uZa52Y@$`fuj?~+Kle6}Y zyg4W?>ObSaWB_F0CJhP``(}UnLp==ASrDritv!LvI3^CQZ88^S=P41v^*(AlyC))# zNM{-S?BU6s0(aNM?$s{(MNO+7Ut4u10Qfp$0S!9iY%*%{!V^7 zMIBb`^l;`3D|RmC?4dj^6l`gw1}j?0DI;)~PSI+uxohZR;)};yVrqYw2JD(Xdgpp7 zpdN#^6=j@1xk?sKt*XIo^>b7$J%bq)rmncNus(-K{0O!G_=(?4e4=4M#k$}|mAi9g zR517sMpm2PA+e!KJ6rO9yScR%(QrGp8lS>FRM#O<=Sp{jg)gKyRo`RH>HU$ohadmm zqPNLB;Y?J3v3HE><y`FAK}g1mANf)pnK?)7;XQ6R%n~GFf(k%y3Zsc(;@7%*=e!GiM}4=)@~@0 zhBj?7X z79l0|0O48KDwn7N(Xgro+@1NAtG1_T@WUQG#h3_gF-T(~B*& zrSGwS#p24(knXN@HfZv+Go|$s(^wS#b||3JO-a0 zegdYQJOA__KlbonoIQ8`L~ufvCX;+`#osD#jEEd&?B;vVJoZ@nIRDhyvyW6CCr)op ztX`jxo^l4Xwo_wZdeo!udU4@diu-5e_LEDLYI%o^eHN+5+K}mx$84K_?uutYi7V#A z?z?bpb@~ONMm?^Z1uw{iVTRQu2di2o-Xlzc&)hLu+D|?odB1O}RCIJ}q6_|+-l&D3 zU7`zSsHzd{6pA}(?_m_++b`oKy1+#F>HWliYN=a-r9a(EJx-clQT=wN+Z$Zt8w@&7 zhSA^zCy%KB1cs}OrvlQTWy5Y}oV;~K5I(=3yrnM@y_aIk@=$iS{c?(>n%>Vo`h?&hxT?po2{VK<_j+a38n;Acrm25 zcD2K@IW$+PET7?9X*t_ugb>Hmh)}}RDHw)AWQ7^H64*3xV%Zyy0#V{U6|w5TubJk7 z>b@8z^9kUaOj@xB5i}o{&t>Mg4%tOPknR&nDKK_th&A{EMLt{kVh^Q)v}{t96g0jC zPCFsQz{0Ll@g{10X5%tZmKs>1+|jM_7(L_z@?3*`RuI4rp-wGdee9w-+%iDRT-JEj z)?b|eDbjk%zlK$~F$LsX0R<5)s zG|iu?V7hyzq0@Jo)gPA#HD1c9N@Ok|fJ&Xb+DOnZ*6KjbU$|L$VK{N(ZXcpVTT#8t zud|3AxgZADFXT;dDi>I(Fv9TNR;JvPHliNH)j8fwz4ySBK@lHW+yDaM6q81cJ3b5# z5jF8tG7W*RyqF`b1zk~x%If7?qmO6G$<)KfMi)`;Y(kzl%A!ZPTV%Cw40=oXplR4l6tRT0n5Prj*)p5JH_)bRmj9acy5d`}F4?{?2zM@&nC`0wW|t z9=N%&-%qImQF|2QrgzJ$Hkdt3`OWf`IBX&I*4&?1exUwG;GT(Ii!>4>QTIaYGlgX}-=3Yel7*po1Lu z&_zHe@Dy9>Qpe2TzCNHFcf82X_CL+sbO6ct{@9C*s(h}NHYM)w@6rlPd?qBjE6P#% z?hB%{@`p9G7_y~+YO2z9^|>HGk6j0V;tiy(&)CQ_o^eia(hH-%3PiFi4T7NVdgfNY zj{3S-YASs_!_&WJESACR0`~h-NE4-#6t$(UVNp?qOw7p>sQ>e*JytSJh!d4ncWEq? z)Z%==LhWu=gBh)owc!chSxgL6@8z(IV8;x1pN@$%ikAlJirGcja}6hsT`|8p4>EWNkH#lN)FBr}C2 z!&^T{um^s9G7cH#6L-)TH(ZT@etOQa+Z2G*b>-%k0Yw7oV=pqeWKhoV+EMqk=GlFN zI4!8K1jbVvbT9^LnWw*c)*7E(<~M4*U;e|*1K<1J*>g`Kg^K@tt?grjdH9WkaaG*8fbcGi%VuS(TVU2I+TNMW*agcCx$a0kwXU24#*ukViHd;XQt&&un1M)3S zquE-#0H|;AD#e`kz2olpB2n=~=8}5(svC~0>3<5DP@{4hL&NaV#ds#os-o;L?zrs+ z?HSgNnB}dVr=eBro+9cmOQNN&?Y{C5!_Z>gEI<4XR@n*{_H`SMw197Wb81E%`e-43 z8=dEU6T4q;$DJ{7r--+2%ozK=&-m_p$jLy4hbqJkOvg%Ha0Gx(c~pyJ3QZJVWDM-x zZ8x&cuFGcxPrrlkLsFy3Wg7(D6cPjJQRozd6ww=8)WO10bo|Zj1bUzBOvI zw}4dbci2{=GFh`Dsn+p#Hf4Gb4BB#?jPFn$s6BW>i+MMFh~e-%~X)j?qNF zgzKBb9P2f{1yVkvA_VmT=UwcL8~A}QUGcnFhF;C7)=#W9IGXy^Rh_+kF*z~K7qIj- z1YORDcpg~g1;b;Ido(pG1OH3#^k^dYsNX~nN-|}2pX5V^vCI7;WVn|X((BujMpa7I zq45O+<587@u*{F9WQl_?V%2LD#;Rd7s_H%AW1xjYtlP_q(24<-alg3vzVknyRYiLl zLd3vV>VO!;Z@+WdhvOMBx@H+Yba)5PQUjY@WkVMrd z2mDxpX~5y7s1y8Z8KJBb)86f|kwgei^`SfCIn!X4Q?rk!mLYjyU_7M8wb&1CpS+Bw zH7I>h*!lr8Fsw*$f_|$L!kgLW8u2vsw4vET(#|n~SK^ZF#1j&_mo)%|TxS$Ne4JLr zm$Ey$!&zu@y==!XJpzOQo@ipy;hdcTWM0gCEJ;#mpZvjhgZyy8{2Fp}_C|9!?mkBs zW~~O&VYo^Q`kOsToqp`wy^CmjS~B|_xayRBu!|_@dtub_@|T&cjLcEr*J1~Q`@JbSYRg6 zY|J&ZP&AzmtuWi5SZIhn4GSo+`jE8LPqPSgp{Uii)gi z)}N5*%y^I;3LJbS(X+MA?M=k!gR_BF)qSjg8aeEC;JPA$C*~P1keP6z*6}0{OH{dw!e^QwVC0{VLbFFkACmz zF#<*1GQ6RHeBlQ@EecR}pSwL7GFhko+!`K=LzL0dP8YwxYSn0|YFtgHcua`8H zB#GH=*+6*jjYzQB{fpvT*{_jV1~b*+?O^)Mc`n#m;^S!%8MK6K2{ri= z@?>c}8hwT82`K`ZycK6ao8>q7#hQ+2F!Q z4SvzuW_MjMc?QaA%|xBcaFBx-#e=U$AVZ|cL`95S8fi*DaN1=aW!)R4%woGLMYp2C zYHQ<8^o{=vHrinUcha+mX)Kkwkh3*aca~G4&;ljHPxe6kGmdE(V0O!> z|4;GxVEcw(Q7@CrcW~|%+F0}l-Kip$HH}*}hD#sYeBrB@jx5~#;n#SP#OFXc6sK*V zv10cu#ti?XRz?k)$p`#vJ+LkGwp}5zFE#~|h;@l-1q}gi{J@qQL0%XR%S2hj_Mr&j zmbn)u17+RrAKm=ua)o6_`i6S-Ma~OLIbK{tT%CC{a~$jN)9X zMow#Dc-SWb*%?$4b8ffHK2GPYk@<-y55e2XAP3v97W9gm*tN0Q1UNJ?0~TUR*rVI~ z!e56c8XNu~LZ#lp^1la{;9E2%Sz!j};bxjRW81r`ba< zV88+NBp-2b!g2Oo5?FA?;Zd1L)iZKHr!f2;mZ?X24|cr7-%O!5M>=C;Um!;e$&~P$ z>DYx%wb~;JY8^`|rW*v&02(7?wJYZ>h0&U4I|(JsXluX`>a=IP>N@^gq z7X#dbLO#9My_imO_#9>e6NP{rh!fyia(xZY(F8|)<@L$RJgT>)q&*JZhGZd;$T=S7dDD|NT+ zMNS|ET3s9bMZkc9hMfXIOMmAcgAwke$_Kyb1geTTL)DoYO*R4QnI?Vd=xoG+3F`sPbi5Sq~y}&yEgexeC8B`7)(qI<;bYI zZ^@3?Rf#56xcpfB3!ATn10VP~b+H zGg|4E`;=zuG{xOS>w#ic6{aWm25Q6V%EjJ>+xk*?hJIOwylQP_^WfLN_Ql`((rw7I zf<%s{_~V7czBc1{nIUL6oCVGiwyk2;c(lHqjgK`V+j8+hJ1F;U{YDG|utKoEz>eVSTzQ;QnE;Y1JdP~Y3= zzXId&fkrfbQVEjl6Mn$d0t5sNGUhIJGC_cJH?M}=!2pv!nVAMYEkg+eaJx+1I1Td* zTSe5{+4-H!GhP`R;NKCJRPG6VAK9D>9&q29jEin3D=kA`S7pxDg!hQ)1%mdn{aE!`8jJMk9}FU6=^1>%SuUGZS3A_EWV zeXP-kB4J`u)OnH^MZ>tDo>?1+HS@=?u?(xbfU9QQ(tP*psdktezs$0+Wt^V?aBGx42cK8{ZDAx4xa<8fW@$HHJz07d_EMZt%P5l2p`88I< zW=50D`P^25gU=!-Bajv}#QL-@HQPBb-}o!r#Cer{-s&7x4JOYkU?%VGn_;()>Vg71 zKi9VuY=EkmIDk-K1Hr@Bes@u&Q<+g*rEoh&J7j30Jdp5q>1aAj@qg8-Txr!_n)PpQ z&ia#oZy`;P#7~VjUS<)5D^pFj7|7q>rM zoWMM#=%MW!U(`}mxpqDp+Tb!uR_L=3p;{4Z`tA8e-(UaY8O~7bWY2GkRY|auX6%{x z;*r4>EUwSGTG`q%oe|TJ>UJ7r))xwEvuXM8g`>KjJnGgJY_=aNVfsO}u9#F=&4`$z zsnfoeob_1qb26ti&UteLd3l}6qHWGeUJ4%2MEUuttBKQH8bCAhpb1FK?TeNidu0#{ z8`iO%>oTDAad!afBH|jRf)J!E*}8YzgU>IKpWlirL7d3T8cr8;W3ymnoO#kaod^p|99&^HfP|0P|u#q?X zC7oX#FuOvv3c4`Tigxt0)9A}siAF=hzv7#3M{}*>$*I}_`jPjS?|sWU$nUx|{pz+J zQpQ==_u#pD4O+v{*iAS17e9@ysI0TZB@9QzDk-~I)b39m3~RhSulKWSZ+rgtu$2^3 zapkGK9>qXhuso`D(b-DmoU=F~$u$ypNMB$ZriYZiOs77*@(vT~J%50n>wx;jW$fc} zi@ckG?mh}-aKkvZ?X*$fMt50JM^iN{B*!I4SZU33Q2e5bLUbr*glN>)aQ}L;?I3~$ zG(!+q>v=eO+dC`BUR*4lWwIyiHrQ%f$qJaa57O^wlwr z7lI-FLf|`uK+>$R3l-UZB^LtOZJQnZul+krAsOD`i}&|qYUd=8QMJANa2Z;5tfNgr zgP3zO8D|-J!{i-4Ug06>N*qu#JlMWrKg}{1_r7rc$sp7A+9tpLEi`3Y-+L04{MDHT zF5_5?`Qvzq#!Xp!o|&sq{xTh8nb3qI4NI(9@u~-wUNCGlQv@h{S>k5AS4LGC^ox@` z(s`H|b#OP?s8knK-+2dY%qeY`)vsW0Wy?G{piNrodI)wqnrF*Yw*FgH6E!?QRHqm>TuLIB8XdU9M%mrFO%>YJ^ZQsNQinQnHcv zgU5aq`NzL^+gIF9juhUP;No?v{pfh~D;=;68REfheCup z^W)6qNW%6`XopMC4bwpeYCGKI!IEWaUln-vuZ{#znBE0v;eAJeWMk1Ec4U2ni~1S1 zH!(qsMQm5*MjtujRx{P~4Js(ZRMe{`4H2}i={gUwqCHVX>BC5(bVJkN!pilE_3Jf& zWhXxeHJ*i*R&@{*D8e|ruej{LcX|6$R<>W;{UnrMRTetnT{+{T>_FMx`sil8AVu1ANzQq)%(Xt} zW6wCQQ0~t5F-*adb6inUU*9wZg*)XuNt(+eLzBuIhN>(?5l4IE9asbunA zxVn2{n=I`_#w>KxH4F*K%VL$W=Ky|4WxRa_k+<&$}8wN57(> zIu^fk7n!0cdX;8hg_jLnMchFUi{3GFW1;DJ%}6FVtD8#YTJaMQ9QpyrIjyeULofJN z*1wbF!~eE6!#0{;UiF>K6!9_=Ehv?X4n}$vPN&W%;v-Lf0xKAvM(VN_r&tPN+js8S z0BTdbkZd+=)=kmUs6RK`( zc8aM@%Mo6krw9db0q3=^_nzq7?*0)ythl(H$u;GX#fQ)B8!Nz6B~8jNy2_P)1h3ZS zW5L-LG(}HU%461e_YF`m0e-iB-;#S3sxF{N;i3bg&bY|};PsOAN@c6bp{AsS3A`7H zO9Qf5_GmC;w2h^!#L=sY{kcs1)x4u)x>7$BK=$a#HgA6eX4o=nU-sNV4f7Be#NpZ) zyUz2jBYTF}tI_+~M|FFra;uCdy3vEA70H|6?ABhgYmoUFDNNmP!S*-`A{a8!$_B6u zWw)|Cq~4X-$HdaKNrUERav~vwD$xLfjz1-OK+PfC&|sswi)^Kr8W1mNxGsViPF}e~ zJ=`pxp~@Mw=l5}YAKvWOY3a1&*A|O*Xo3JL4y{}w3vT#%yUpp-`^aCt(-^eVJ5z0Y zBG(1JGN1m$DDC~dHX|U!kLGnN$Cxfq5NaX%svxH+&tRK9e?WNq$E<~ujI8RJO>_yS zxI1Fni^ePJ0tYs;H6}Z-zLYY2kP2^HkI0?7>R36V#IC4 zl!JkY8Ud@6Qvtn(jypk$BW07L8d}lD&dS9v>BU!9Qk4*NcI}Gf&g`_VFy%3ND$SM_J-H@(apm>bgY#m-Q{l%@Bm=hFJ^u=iyrwLBA+%S^+YM6WF_8~4J7m^Q$Dh}f~LxB2k9LKMrB~&&XfwU zhn#|Oi9=~s{9b8JTCrnIw|OWf(Kd%lOL3t(N(um4l<|4I13f1kA7(dW^IA8uyLV(< zJKNo1KDuYl6Kax3EvB^hxhBIhL?h#wr1n0xXooIDL<)Xp{t;9I88yFQmRvD(F+USk zE&Jz90by(r&U>KN+NANe1_c(!DrV{s|Jgfi|IIsW|E)W0PhfvX^o!+@1S<6dQj0sC z&+_>@o!|2LJDu_#TNLbMQU#{%3hw0BUN#{ct>(^z`A_G3n^T zac0ud9+S8&i`TVcs)nx`)wgP4}>Jt?3?S ztu>vn_zuXPJaq>%m^^g{lbJlVXI?wO*KNyPYu<%kh8!{`m93AHh>dDIWi$bYi(8f= zjNc5%v$l#2Qq%Ci=Dbs=PY`QCp-LEO)WSW&!IvvWw2tbwMAeAMyej%;(Z;^nyoJA} zTasS0icK)jH*+k7&EARz^ml^3P;IT=l}=TizQ`$GU8!d6Uel|3Dnl$JGc*w4>L$Y* z>#9|dHoil=?3*?m*hSxsWCE7TMTsL#p%M%a@#9!*V@yMp+7p+uP~zdRxkzCqt=>N0 zYNyJ`9LOT7i%gsazYx_j_bc8=6HEHz06gO=ZPJk+>X?kTS}0^y6P$j9BTkW*2QUxg$Mnx}&@-BG(i^ ztUb>!l9|BaG_Y7%Ip5RMGVVQk=qS^4v?4@}>3XIXu>&DVmg=mIWN9`QLmq6bvceMw zhA)3jM|svBT~A~`WRnAi9pMsz?AjmERW2CC-@!NIUb| z8`D={wjL9H1ifrde(B@)esc2=yLwj{wUQ!EVz#x1rjx$|pS&{{>|-Hm!0FCKJFXR% zf}Bz1KD@>(yM?fifVgEZcdU7;QLEa$3s6o@A0s~%gbNl^?T(+SQYomsCdzeGyN&#B z`%qK4ukTa2xzq(eb)#IT3iT{p(ref9c#K|0Uh5vdsCkk0*Z3c6u{2IWuXzvo+g^n| zvKd9}aA$e4C;sn<&PykV9BRyL$K(kXl9|M?4Vv53Ol&nh?sDRx_(*VeFDpPiYt;1? zwL8*6t5WQPB;IJ#Whuz(&Y!|*MKp~O=#F&oQ`8E29nsi;w?!(vZ^D=mKJ2W7xNHf5 zE9G!R!YurnHTGS>FHGJ88<&V`iPT-^MfK!pd6~TDvH^kZ87L?~ps{`XV0@>=KVITK zKHmvC@wUXgcJ=PkrVKS(oR6rCGJs?hYls0&~OfD``<5U1#NwtOMbo6DtyCJxuAg~qPu z)XR55S#;eu5kX}8s^zP0qsb13HEg$(PS4CoTNk@?g@-n*9YKBw$v?VHQy#aeNRnro z{LQoj?zK&PDm)pJ2wMDD&JP=i1CVo}DcLH?umLw-Z%eSQ-{rPv2bIYog3;Tq?Nl8% ze{F9}a&~&1?^4wfN#gLm?rCGP{jfb@g1*Qzfp{5-+5U_f?ta2pJwrEYd%&=du_oV^ zu>rAJuRL-~4pi`@(!i)}WK9NsDgKASj?xc!F*r;?vKGV&TvUdV(YATZ#SBM2LdsP> zlzCa*E~iB#ilk^nGYG!^~`&=CQ4%DL_o;lFU?@T>|knLqf*MKABG`@NsVedB2J8(0Z6Q54wE- z;n2D68z;xi5sc#T(pV|D!w$>#v#SZoJI>oK`PSQJiVAIi<;?byI`2NwpYz|}ZGVi; zVPoul$`-1!N6YWVfNsD*&XZr8j&)^N+!G*Ve>6icG)EWB*-qqjns&htzf~_;#UuUi@c)sKA9YF{ZQv!IG~W=#z3-D;efMN?wWX(3^KI z`E+dE8G=S>X83C&NMb4(YXBlClY2u|g@kU+lrp5I77 zN_$3+%1Q-B!80!q{oi*tB+5j3nRtrn?Vmv*pgHvjZK3E=V5+?r2|O$Ao)P#+44YB2 zH{I=fYWMEWp}bRRfE0BJQ!y{(KWE)$dp-Rp>N6;4N7R?j`!t(;Gw9%CEq0QM$Hb!H zW*%}clJEO{EboyxwGN_N_0hmo&~=QOW-z~S|0aepqWfGo zHxHbD`rMPBe)7-D7Q}LCVzr++-*@`H)Au5p+jsf7#~wcaCl5S&Zi8{Fb~12qo9-L^ z`00D^J$>)ThfRB74Mh8WRQ9bAv3M&l3B#Hgm+bT2Um_R^0!_)$;YwcTP82hRP&{SX z(DpiAzRld_IY2eM__>(_^eVyIDFRB0# zk|;uk##GUf*@o_H1Pxpe57#=(>SI$dmDzelShsY&33YczMQ{5e2+#EZuf0xcCoO*L z=Z3jQ70fqgzrIl+Tgic6-#r=D-ekXZtYC&uOd(syt(`C8bRR{4yR@loXpUz9r=-x_ zyD4@yTKqQ8m=WLkNSkl1Jp~m%)R-g4CA1SD3}3@whWJ?YH+yIRCXu>|x!KjO2O2B0 z99FT)jw6Q~1T_rW@S~Yo1|7#RHNd7uGJ*j!GE9wjIdvovx0&-~_-uoo4YzmJgM!k# zI5Y*p@Ut|uh2m&z48ni`d~JI>c$7SoJD&Q$J5CxLGr7=%xP%w8Rrqr272dD+DaVN{ zj%u>TKnc;(bTGRgrAw&_gB(FhYa7kX!}J=QGM~N--1{6)nG_Gr7=c*knnT&>q~0IU zH{o7iRwHS&@*ev*9z#&LokYyzEfDa;xQt7uC%R8OK@hWerRc))5j%v1RcMddsom2=*!YN+LfHi1 z=iaS*KANmb3PB8CU|Jq2xrDe9nq;Rlrqs?yk_jd$ZlWUtG&n=vt!j}1MP|hObCL-L zfJEsH(;XC=TS=6oi98HfvwxCQ>teZ3Pd=zDU&qF?a$N5dHkA){Cvy44RA;6^WT}^) zLWKbqUJs|Fnod;Ds1z(Dl2u$?IMt4J{ihk5Y9_sPn7#Bq6HeY$@o23L- zx7Q&LNnDzo$!JVWloNx8#PZ%0JA553aa$)SU(50pq$Ky=s(^#eh`?$DjcMnFL^${= zgQ$Y!Vn~Jd#&ixc!4Si^*=d54wBP;#q&a;k6rxT{&(8$kc3vfqWTAwf%E%zv562IA zMmHGq=wHOoRy#eln(r2Ww`{U6z#>OTUwg%6F`1MqhQMn-W05^rkiJ#r$(Kny-@{KC zEzM7^`ci2=hs&AW(G0cO_s`80lS1yiH`>yw*}E)`r(VsTE>>3Y@jspYi|_u)!;d}z zmA^=Kp7W0xo+r*&=7XQS;8zz0{#OJ9vn8ELp^j)9ZJkUTPfBAjT@a!dw>7M6g%yk< zroFulEieLv)yk#wf)WA`*iUfUE7~IK6s6Vm#$Z1sg^N4!Ujv(_SS=TT2h1fNv;we8 zaOn*uYe6u{u3DTZg{CfQv>G0ggbP^zE=6;H$Z+H7u2U;M{Hx(SPc!M|11sGg(FkpL7G4X4r0pvWvwARTG;7k9lVTJ`qy&3qebZN( zP?8q6&z>!&YEH8!_d@A%o>~Snthl7K^4L6@KD!fPh}s;LOV1`7x~Xm!Dy1WFv+49v zZRN+|B@~?2saw6U+q#zHXzAA*1hSe43~lx?`w+AI<-Z-W`cpB=-pR})aRnCx@@?kw zE;}GOcQoNr)VwXDwrGFHIWqLs&8MIIvq#Q8QGPP+3%wB?3^Ln^7T6O_uR(~q#r?^i z00{Af*;zf$w}zRy;ZCauQ17^uTn#{!IXN#|rgMxvAT;FZov{;xz;buqEJN>Tsd^$d zCEJ|>V~VxUhAW9B7xfi`LB^G*?skZY>~xRSzH09?VGBHTYaP`xzcc>p*-@vAoaI@!EuPiGJ*ubPh9Ha&pv2!MguVb zWC+i8TPy#l=?zmumB&2WEl(?tzQ&Eh zS9Ix0B=)GCkfi5ThJI~`;~MdKi$I#L&zjLmUM!yU20y9G70_btYD)T0J7+O<%c-1Q zC1S&x)UE?v=pE@!RKi6%H0hv6zk^R!HI}b%lvwh>5E8)clP6d?Kfx;R6-a%*j-)w! zE)J;Rimr6`-X)SV0=Ur{Yo!Lg+PdoQJVo6Wv-r@6e%>QhZ@ti|2j?f$C7v-ks}qr# z4;qL{O}H`cyuh05Jo~9=S6KzWaB@7NxXypEIs+984tn9xHyF^wt^EzRB+A$bx0|wE zY;|Z;E_CJ%)!$#rg3us7->UhV%B99}`}-gt}-xDuCx&CVLijqm4xG zHn3>g)ahsHr)K4~M7Pv9TDns1z?KHSdXbbxDdzKMJU@iDB~s-+K6p*rMAJ*F2E^yV zh(RlB>+#smDhWz&rp7(FXWq5v&nd#Y{plz@Od+zYmuCVr{LJxTz%yKOxzgwfUtA3A zi)%!i@^kpJG`$cYDmHuJt21D*@u<@43I06Bwk8h_BL7oT5NaA7L?RKw@R1_uN(}rn zZUlTF6Ffke!W8CeNKd}y>p+lwtY&VYxJGXZLjE~jM0ZVV;*wK}_m`_5_Ny@j7lzCL1%3LhHRNL_SJI!YRN?%9uJ96#`%@$ zegp%hPu)`O)sF4&FlwB_Ae$l{D}sTwa~I}Kad|jXx8pjY=HXv6pSIV0`RI@UD-Ugu zn0D=jMq}wskHT4F*zWI zA)CjRFUG+F(<|>Vc04uQEt$W6NE$y@YF^wOX=Rt@v?R1SsXeX$dXh&srVQ{`H5o6h z))9@j3|`4W{~^2pEz<%UcQ$9y#*swNz)R)2rw+jVJ5wWcipFo_D$Om zUdcpFP~ChU{KX_HU`u&dSKM?5+^+TRQusXQxC!0^L;>L6UOulO`xetrBqOWW^E*93 zTSr<*^GY)jQE8cEB|^ywajHC%#^X$eJC5vTPO>yB$_b^ZS7<29NlVE3uhSK0Aqy+_!KHbrE78R)B{Ok|U$=*3O(@KJp%AUdLAH+*Ys%dVU{Pcdg zoPIwl$d7pIq|nU24h4qMxO1#Fkslnt5vdLrP#`!08^dJss2<~3M1HF z+bWM9WoIVLo(Hi2D5(g}U@ak3pV_s{w+h0v%i+8$J6BVODU*5s)O^VFES_ZRlg2Q3 z0uAov?aP!PCnx!)wo`WbKihlPUdyiQJhMLYSL_r*GzIf2S&a^Zj#{y7#c3-RqPStJ z(NGw%WEDV>0!cYmKGCA>b^wBuD`l3O5wD748~GrHEEYvsrU3qeQ-2}9q@U*_AhBNxGd#Z!TXnX4^`c!CtI|)lj5T3(brIlRF>V7>l=y*$f&o8&4kA(y~)u0>Pt7n`=3rs(Q|8+E`z9 z^<}>NX;i+hW5fUiGA<-P9ewh9@x8V6tPS=k|Do&Q1bUwYz(+%}AS8Jd`yRaKo;s^r zG~e?s27+{zL@KCy8G(N~H)Y z3CN~oI>fZl<@MYz0jUjCBmbM#k*c}PqfOc}PK|WU*0afSW$%`6Jn+DSEna6px+H5V ziP!Zp2jgo>IG(v67p+7rs!qjRBYgA2&4pXOxozy#6B^lGDFpwFtAqW@y5~-QnG;Vg zoq>t*Q;`f=<9Mv9>mUPPI|;8qC_qb!#vA=CuYNjbdmEZNrl7yrIFX3;uPxuh^nXVUuYdh3PA!LfzJBiOapT z{Cs;tjC}(aKpnmoJN3@Z(K?vv(!{ zL@CAKl5fTQm}Dt!zlF7QcCM*JXFzL1P=?LYbmaBXR>OUuRJ7^l}7ghGB&;wKK$mluRQt1 z-)Q2NJ{65#?X^!uSJ7FX8L_sc*}p1uHG0giGEe-mYvZKdFXy#j{w;YeGQD_CLc`SC z$8MTgoBtrMu+-ZxUu?)pNSny|xZCj+3^~mI?gx8rqjwx+*7wv5sHPWL^&ldj-NGuY z5d5nv&wk^vfA{YMsAI;)@5}!H??I1o-iUtIN%17(>P>7$mg&SpYG~U<&y;Pk} zGSa^NTpz1erH{00;5?|1HWReayvUoj#4?`W_{zh$yk zp%?<$iO&kI(%4OVxyvnRwdj=k8+{;YBT0%3S{90X#kO1oUNES|Iq=7#ii!aldholc zzfL7rpNH;x95-;wOQmK85UX<7Njm8c%Cvh239RmM=JFB(AAK$ZvE7SZ70OZeOd4fQ zF2FKlOj!bfbwDfrsyo{`ldnE^2kaEH(Mhi`h`FejU6uFu>H`$NOHRld5BqkmggTIm zRLFFeV?QdWHX*d*v6HZ_rBFUV>xL>z02X+9-~oSjXN*vEW*_Qk$LmWMwe8&^P%CS- z-$hn#UD7=i+aIImFue^8X9({s%xyjTO8exBnqv#PM?RKp9Idgri2+I(V~eWeH2aWq zjgrr5g}wr61C-KEUqhw+5D;YlzLIOFp3t{@BXXvKGuJ3RKY=9Vb@k17;*aYWYQ_}& zsUi{hZxz7RIA#3D48QHZ8yBkcv3-Rm`Lm6@xscS=U893|xN93z0(6wbgxXS8yGcaX zG-CC5??}isuPRm!CM^2@J&o?9sjUO{#~IBc5wWxjx1yGBZi|C4`D4O5LNlEz=OOcG z*!VDX;~$GnH4^})#sy;5MK7q8ELooR&Htg>uPvd=FUmFDEvHcv2BZovdt%GQF8rMq zmO~|n@@My|hGw0TG$Ka?(!V?|tck_U`Z8^Mh!~*(H^y?d zpO#KdA(7t}t9}{91WbvS*KH4Jeg4wk z*G}v$2APUe-I#>mm`?{;fEVRtvgSC9B#?hY?`7=4N;ZHMIOeT+79Rjt&~dLryK@J` z-fzHtzHXpf;etVk{OTYfeqeHZL#Hy(>^9dJ)2gOKD{~)47$gZlUCwRI?;9yJAe05U zmy?YFQYAsE5p!AoEHzrLu&tk#4#U%=&A1wQ);kal#bYhGrve{;?yqjoZ`J<-;0 z{_}tNz_^B&Cx*xUi7uY^))B15nh(_I^f+blhS<545GNe);W?vt#Vz0K$q`-q>sQH`jPGlhdO+kN*7l4ei{i zztn~lTnP4=047jmfG&Weegh1Od8I=*AQN)=HY>Vb~yV>6#(xcqB@toR=~wpT$(UFLN!~g zTQceto!S!P^xTT2D89YWQz93<%+Obha*n>bth0T?1pCLoLQJ*DMRXF_+(ykp8B#YT zYdKOQm89`?c`tiILU+8~ncn`RySn)Bf1`r`XBt^!FAPIoK~<${8Os3xQYO@efiPeL zQYtT!YHFRO=HeYzF-om(az`%UYBEKgQs$NOT$r=(%kGz&y%b$>Q&Me-=?n^KR**Aa zkkPblz(;6fi@OCR*aJ{`H?1r@;p2>9%>x^MDf|(1^h1yReTBRZj5gbiWNNQBg$^bg z09!Af;drJNCCaAwn{p6apYGuqlRrMMyOCm6vSTmjH(4uPN!|LTt_&~} z>~q|%&JFMyOwun#(qQCG@aOwyZ=U@Sa`%1Y@#kX*ar(Bp9KHLXEd3FWSdwnNVLDN3 zVReK$qI0KRx1Wc$9V@?tI3?xKYp;RNV_TIqG$GLWYN0oB?;4c|(M( zRHo$t4JZwT(U6HJ?gypBxtJ_JWNY78=zOOQui?MbWXdlo5`j=_UTq@jni~!YNnJvC zA9~gPYR#usVZgYlu+aRdmW-fky=>6F56P)wvJNt6KhvNN<}^eyip7|gyn4R=1T+&oIh7&o?(WM`lJ$rh+k_7}n8M=Zk4`@kK?o zx$%zT+T3wLk!|j~1EkG+M0%K82B+=4YSagsQjI~964C|cE9i7iIJx_sZan&3!*2mh zKo}0L|5=SQ8dPS9yIVi{n_$Tp$pxD$*5xuPDFb-$xA6!9?I;dvNCw8h50m<6bA2iCjemhXYas>N-tZs!Zy zS6$wUjS|Yh9a_Tb?w8uSt32y>;WhU=amSW(zIftF1=CsoiEAzcVF{K);FnJ{w(&EL zgS_aytF&sr{mV!*O8NMsxljY0z%(LdeAp~-87~@#FyK>DM};I9J6bK@SedVWS~Pdl zFuHbE+15DjzL_yXV#=`H#ce*RUhZSaTT0C|sGIE0V?0b9sDJ?I=D0v;hTfR%H!_=_ zT(ku-2OZFkROLc#_;|$8+P9jtW=b1!^m`w_X!l~FY52vbzzwHr^edS)TMTp0;V}ZN z7P;f%hu`>>FFb%%8m)aKjdxA7K$+gcRAEPyhLO>X-W)q|2$X?YUJ5QX5T8cbSF+n$ zs-AeXSxw2W>ePr5N<6kx%O*iQ#*`tp)tl9LVV~{y>3kEnG1LynsYp^vmOmqo@+Ecl zPafW^N)bO!h*bWbnrYGytbu(Bd15Ijzm`!}<9FLh?zItxgGnjCcQ#B#0d+U#-%qed zn=D31)tORBF7_ zGHQfLqsH;ANZWZD=?Lkto3cQLBYLczEKe-+kiB?_GJ~fB*F1Y#N(@ z#BvGZ=oLF+I1nVZ)X3zDCaXak#DaGCCAo?V2v#$END7?wik-0|e8=Mg+vcF26F=z4 zKCWg)n@4$8ka4oTtOsc@+E?<0szFvULJo;N-DaERUutFySFGpToJcK}uM*t$VBhY@ zHPTS9&HCc!K7rP8^V;14PB`lMnEDuZTiJHYvk#PY)dfO@3h3;~aR61^^5Z-eClcrg z)?^DNcC>WfXiz;dylaQ1GMf17$pNgz3@|n%0ufOP3aPqQAdShl_lN~K(UfS&;X_uf zVv!3#oa!*a=Wls}M6l7Z=i`rq$B4t81$%?PI06!X{CSTPVXGvR-7AcfHZOhUn^(W_ z?BSOVXaAY*5Wnaz&0`0=f8cUB$;%hK?9t`A*CY6o4U&evPA^6`(>@fn`9gR63&1OBi4NW?|<6gQWtF?E55gU#Dnd@ZJdsJ>961KT0^MH|To67I+H!ej` zILBnSH#b1ZIOqnmCF(PtNWVG{B(!Q|n8&hICH$p(V_8;xkEF@(wyFv7Z-YmMC@Okm z{obH{HMv=iUTOd}l*p#!(vpYUf1n&2vzg|0*Z0Q9#}l2b7oma^?a6J9%9S|i9*R$6 zE84TSKlfN(IOTLG-n+~ZzYlNW9Exd6$~3xeZMX|^T9%k1B}0Btak^m^&tObq6$drU=)D84p>9K+2IFaE;7 z7yv=~@Z05{zmphHX&3ldhZ9+q;wz)s^h*Kq^hI;=kcvh@iR}G z?6hK^$s8aWxv>pwA`yMN218w9RnafuM%X+OdJ4J!ReEp01cmAY{7>UAH_XxlBh&@_ zkL%cDuNa$tf04$An(}DV;qzbqbt=PHVv-3hH(O??)mZVcJiIz1q4^?$Wrp%d<{3%@ zY**&>3pP>s(NAUN9F5*|VG;4yzx)7`wy;^pX*CJ_*1!IZqwhCdS_l~p?HS2mbo&|9 zq%wYx2VoJ44Rz%q|Kjsse)_53|E{pFaXM7=Ql-gk#+x5CgqEC^IxnP0V`cfl!PKCP zA_d9($YH&5MH5{!<|Y*SOWnr7H3uOx?17b=n?0C5Y^1|?OsQaAoSKqwR;V96eDm37 zzx~Xk4?XmqXRbW`N`(A@Dwi-|Mt}f9((-pr>{Ko z%tL`%@Wtl?S}g(Woxey;k;)BA-_H-n-Q2c&6#`f`ugzz$y%9TjSzwA%peS;=_BLA~ zgi0ZUFdM3|h*HM`%aA4d@9+FpWy8GirwKOkKqR5XF7}{CJ3#1&w;KXKJbd|IeGw=< z?pX!2K(y0fN4K3DV=eVy^$Ve9hhO`(U+Ykim8@n+brvedqkQ;J7|rmiRL& zK93$Si1*^zH}gx?idu~)i#PntLK#!-*1JEf#YkV?mBBhw&H}P|i~VI`iwO{*e>etF zUp7OTx&LwDY3%t>+pIM^{mM^PZI>1;e zi(OTIbIblO`O0gjgD!K{3!C=%a~_NnKJKffR>5*tcQPRt6fMF?iB~N&DtYJef(RI; zA)?bnbXR=HY^cQ^mq2qyV55@fUZZ)J@k`v8v$RB#HHE2I-D+1+k&;aB{n31~@3qxJ zO)>uK^k60$_9@vBYUs@gQ>nK{tF1h?IX@8mPDrzs6r(|AzKgHws4Ans;^q}iiy9l+ zLQO9eLy(6ippWWW{n_gBMG(&ZJ5xne?l4aX0t<%4B)ybzMg2#!;PPc<5&$t~zt2cn z87pm<9FHd166PvZ{8PnzYB79TG<8myd!cjIM$aG3v20t(R0S|^Oz1{gY%QWW&pb`Rc`6!A$%&3%tIxc9&_t1z~ zX6yn|v}(Lp7R9HgAfH#wJMHQ#(D*ZlQWo-;J>Pina7Id@s~lCf%I13z zef#!x!Ybk*_gRKR-?evXZ7Dq(%+#*cH;(xk4DU_^(@qTNe} z`*esHUtSo5J0YN3vpbg7Fy(rNLso*j&iEvx-tYz8JEKmow?|nDk43%~S8m3<7kRg# zLP&O6sj_5k-|gFL_5QnWtL&;U>D)Mss{$6HADvX;DiRP;akfg#*hEnARwOY0i2FSV zW!g;Q!X3A&guuIMl^#*eYPBW4P%v~$G%y^A_a<-Wjs(ge{9llaO@g z3QpJC49p(o(gs06r*V-m6x=mX>m8GjTksU|QB(0OA9=$(gj0+0vZ2UgI_~&Wr-X^kMT= z(+~l%or*XJ@_b`m6&*IEopTwzevHPhF+J+b$smBNVkwaIH?bPc9RdM{m_Z?t8yLWI z6`@`qwgn{^m6j^ccB{jS368OI2@JQkr?!*4&8FGh2J1@YcK&^*5ebX=svM#fgZNB@ zHcumkVipmXUfcU!Z|{gbdAmp{*m#`d;nNR(2DW0E(zy$#??x^(El6;hw}w$QOg!%J z8&{wF&hIZo09T@4z(28noorXeaA1N$HybC{7165mwPYZ&4O@)ABRdN=MIR_4UJywVPjVTdJBTET;X+Go*UEQIk- zswJO#@E#sH3yE`&-t&ihKXY&Rq`XMDTu#GCR-!hN1a1dRzx(Ubp0CMi>DU<_A#GwO zYYi`kG$Lc_{Su3lAu4Od|BdU`=X;G6^qj!0u}1tg#>Jt=Rq_Q5fu>sjx)?4DF`K zT|U5fFz(kGd@b<{N*{3Y%6<1f!^UfK@(?z4qz~f6OPsBZ+_5D49fwH^N;S;0pSe2W z3yl((V1$1faO%lPMJH71?9CgBdD_=ca>^1De;Hk++w~PVM3u@=yE@{Q$a?20HEC|B zf&#Y3y(MwE&H$zgnNGWh7?Rwk7 z*mDG99pO*7u1LLm3lLVYw8A2Jh0h=uN;>8!G#cD&E#Q3P-T#w29L|geU>W7h6h39*I73Au6h`7MVs_#tkj-T7Z-E0%KJ_0Go zD=kim0i4>ETD+DHQozJMUh<)#mkS~Jug>d1QP_c|gEQ3O7{27rpohuI31YNt+)Tu2 zp__3hi>3*N_&X1M)l0=p3x|fhZd>`*Q+hpo_R=zdXpBiBl zOAl?e9P7!D3@|s#+b$0uYroA|KI!f4=P-so(7R~HE^uLPKimfiaFY;!dkjHu?1QK& zCB~4I9fPgHe+fx`CHa^vzdmlfbLrwpu!i4$loIg4;**t`WnDGTjA%c-dIp@d(bg^k zy9Xrjvw&3SqY7+WS$1boH*8*MgCU`EnwepxcMLJA9Ic9I#xzMB_7*#sc6-Oz@^u@< z?U(-%Ovpw2&VOpah+kA>q{>k)fzf@8?f;DI07%JOTl^ZuNP^^&^^8;{kp1d|PSp;F!+g%-w84>K79NG@tySS7A#R|m_;m@J(AwEdQ6c`cS z7;o!KfeCphGMr0iZ!!CJM;2E0$}D@c~A4t-~cD^fLA=?9zO{;Sw~jMmtHqgu$`V}o-{ZB!Uwi!OGtWNuv{RxTe4T{dg^(x@JxCJ^M;Cc43uRlAK`inQ+Xw8@q z)IFNz9YWyWyLu!EiG4@!edoAo1n=HQY(cgre;gQL4 z@y(xM&StuVWk_dv#Y}Qa+mv5MCT#y+47%`NGc%)Akfvp3wp8wdp!4F{Yj}c>tQEg& zwTST$e2G>r#bwLJm28{3o1Vyf&vUR1q%Ba}alrzF>BhD`KbNN3Lq{|66ji*K!eAv; z_v~_OU||JSo$`NklW1j07>1Hsjiaq8Nc7{I^O8W_s?3vcJI`R01Fy|ustXI6a?GJa zwAafho+xu|rhW{J^hE|3AHojubQkvq9c#?UrL8OnD^t=8mC4WdF_PN+)mTs}o5Ewu z8}d92QqV^^*5{+QUGjUihmaVX3F>ovV(xm$IE7jha%7s_rtj<~b8=WB?3EskNPJw@ zCTXu*0>eQ*NH+GMgn3|h5}1L&{MONrCz6WEVnSR#s@{krgD+l}kxfU0*2gYC*J5_s z)w)*JX363e#TbfPJa@m^%iwAc>1-bvgc+`*$I>Di1ZSM8V!6{x-qco^ZoiNo<;xzM zkwD;}^(jWYaxI2RwY^rnYEvG)xGzDqWx3SWjiTY_^#lXo=oGgy(Plo}L{XGq7$||b zHV6=n9;7tz39iVbsNiJ6#~s$-*_4^;wHoo0T-#twN$g5 zDn|ziHLx;`61U8>w!^YPCO4`arjv;9&zNCP>q0(hNcGNvjjjeBM06I`pDjpgzk9%G8^P_ z=MDLLZI$(&kmGuK`*LJfJIjs7rI3(|BaI&Jd*qkyKRi5Ub1dP3_ySrFpN*1iWR;`7 z$`3JD3M#=e3@OVL3CxTX0^t8esCFZ@d~(0HwgQGIC?16-!FTK1lWes3BZ;drS-)bfS@Nt*pIZ znY%-nHv2VM@H)4z_Bx)A(bv{KsxK`zQ^~vxBiZWCLZ)HK<75IHpr+4b@?4gGqS#pZ zQl?*uY8rWm@V2_hE!}XkjYpmXFS3t>CE9c2lonql)51@_oR07mx>wcxdSK}va`-y? zbD9i}diO(b4%RH{V~QK^7}A{OBa6?dlARLqe)sBs_|{XG&Q{c-5u_B6Eq$&jVGE>n z{zTPXiwuXl98sts!0;Gt1TGS7s>GhoHP>gUoBzFpOI{Oa0~+bpo;n&$2mzcw$9^n^n8hHOy@DybHJA_Y2o5Syey(8t;q4oC zYJT(|83V(%4fmb_r~GF7{9jDW@s7xGD~XZ=)C_GYiD?oW!Ho2DPZ}J;@U>^2dgAKi zUwh)Q?_PQOnZK_Y7guPf|L@Iue*?@UY$L8ygDEIGb-+u-kbF*4)CrbCLC<6N($7`E zQUwG}iFw80M6g&yZ1S~HZm9SPh-kP);j?AUIu9!zsg{Q_)n;lx62^Y-|PC2k#BkmDoC z6hIo$Ziiu+u=g2%oX|{_<8Zm4*6#tPJ$clUkq?Bn#@L-bZ=lcxvy&vS!@L_UVc5zZ zBhy0M)NzP*eF-7>nWW5 z_WUwO)FLJwbN;^TYf+I~yR~%mMyuJca{C4?<7d0~PulfXWBBl~Ds#0B`LyQ4Eh+SC zS(8S&$E{GW4%hA8GvnjV>}+EyypJ%7uq6ssV092H+=MkOSQ@g74h&MCB<@F(=p}Jl zun++2$SQ!1_~+h8%6S5HT2-thrl4{ZOCwB}Yczmut1B5t8{Po|(nz-e$VkWQh%#_` zFIY9aG-oYn1t~sw>LE@-+Sq>0sFt4~X{~eW#<|zGf zj#%`1p{A$LPBqb25IcWyJ|@uA$Ee?7JnXQHO)L0jngf8*b#w|2)K+8$_)6Ds!y`)c4N4lu@*uzW;O@o_KrAgH4^I z2zMvyTxQ6SRQPff_BUwc@N@DN!XwoQq6HkzisWakM|CBP%6s zTvOqvtYF^ozX&<2Md(e}H^}AaF%=`?EomDVL22+09nP|Ou%G1KU}F%3h2-D`Z#LW% zRN4cMPDWxe&a*%p@#J;F=2whoweCXD?`8G)+IT2$J+1+XV@z1_4gDAqy*Rt0Ld`=4 z5a*4iSsQZED_W&HGu6BswM}@!ZBwILrdyjUFO<67 zV5{?`7NdJuy({gxrz98S@yq59m)fIjh#3_U*AL`TCOK7mfwG$?bp*_$nu5u$?B z14w(_A^3b05lK9O*}aAN5R+ua$*rl)ngtgx92XW8i3UotR`)A{AkW*pFX zk!KX;w=F+>|EJrP%Sf1sZFA9>jN#TOrWWcb!XnZr(t zjv7Z1V2yiOZS)|e*OXBjOv$maYObfOkYd{^1kTCX!e_qp*was3eewZs8q-b|+MfGs z{VG`^k!uaU`X!0Sh=>6l@UWA@EZAkCTbVM@YYdX=$0(YHCL?KmVw4$nB3oj+QxQ*( zJa5E12G)x=2{!fkJ!IM>J){GL+f!Cow2-BA1~r#~#wH9xK4qS#P0Fu3ov;0Xi^*5J zS#-wJsYZ65s#ZMDV7y&S`qW$L+>|F^qgs6ApOhIta{nXT_#;LLK}pyCM_$Xb6klv*nWVq?4vtFU z+80rA-;jka3vV-^upq3b@rn$qC&i5mt8+=Rw&^O75EPqj2ykR|Wfyw!yK2V1Gcs|yJqBvGKoG(TyZ zGT>}hwA797Cx>O|| znp=wt^LRgZ&)J{i_&4PZsXk-N?$L7=wvzt1Ah{#~WZniV*%YKq+`mE;G z(IV})ST+nN-DcAuKd0gwv?m_8fx)WSbqt+Z#!BLqdFWFE%7Q+6Ow3vxJGbD3Bi2zg z3eSgd@A~zL%`INHI6(v}#-SCDbs4AtxI|4xz?XC~Q_a$A04g?>IAg-!3akutYI<4Z z>DZZhdsG@vF)~-x&~|Pk01zGr%Hz**s=c?{U+dih0YXP;fU(Hs0?~jP(e@cp1;R8(5N*q^js)!3 zdxeY>Fw0DxL@E8E6^<&wB9r=A(y)AN(wPHy`}WXGNVHO2sjnvKl%jQf7Xs zQ`nDFWs(Pa`R{y`tNfT`D8cS|BMf#|cA0{a<^4tgXzPzYW!%Bhym_^45ub}d8Ntyb zvqDy5CPxK6JB?lFy8DMQA}rmx+gLx{N!Ko31B$8{8I@d%p{ghC(lY=f1ZSNn(e>^G z0%1r7v~~;xkZU6HI;8n~2VJJc)U-f{Lz}%dt*F~`0@V&_r~xcgDsIzeW)T8H(Ph*z zsA#z3mTP3|L+ztkjuqRyP-F*+C9D+P5eRvK`9y52M;~F(%oealu_=ed;rViTMK9tL zzr|G}F9V%;95KkS!w(_zTt!{EN}%OnQen0Lm4DovIZSGSLs;A&T5J!adJ(N6tkz3% zi$(N2e0AN{6L=gvXurAr?8iKj<+KsOvKG~RaVIM)a8jixoG^^mH|H~y;l79WP1`Rm z8E;%xLuBy1YOC)uPSw%gK%KxIgEb_`p9d#2+P6sC#=;ewSgV5T)gGB$n7No8y(a0Y zN$SXY2Ac^RIVm|aIqXaLtNCu{phXbpM3Zt;t}S9~y1|5|rj6!+C6sKv3lP`Zkz-!~ z(aZHx`B$LAZBpZb4ZB#^#xs`k8a^icNI_RAqj#C`zm&GY=Oxbb%f`Z*OoFbAVR}ZQ zRLFD$10PwhSE!V|Hl1B>W(RoV01pBZh{{mUO@lm6BQ08@At)(RWW{f7S?R47VkgSs zNaAiw`)k3J$F0Dq*@21&c9L)q%vdN^d&~H94ugpO z7UJ+Z7b*~yI+mFrqH&Phf&>!)IReRzu%^eqKI`c`in*CpcmP!b5s73h~rHb8DQ9UmrU2Z9&XCluX!@!L(&Ec7?EsVm48NT#CT)TP=s5jLRZ=KiDx}=+~lYQSz@onxMbtFqq|( zyr745Ga<7WrN&u1OoF=_k#o>=i>eua2cO~>*~P>6eLZDE&kVIySWD&4zUvE%T7?cc`;$o$Ix^wiw5NN**z2+saQU-3RR-BIn~aQ`st*xG6uk~Pw?PO z{4`0!p8l(m_gFM18lEdaevDf;48$qH)r@#!z{%oX3r#te5();RrY zSyHYINy5@wKw<1lr>I+;u3wYL&>B6)Qs`&zUNk;mWY*0+)=Mhz%6$wsZ!s||JsF@t zVvWHqOwvVcq_Pqu;G3nB)t;^1!~`@0h$_Hr*5SJY1^Oa<`=EMsN+4eefQx)2?^Q9C zzJ5G?q$!j!`v;;0eB49{rI|A4y$wC*d ziASkh-C8MEi1QC3rv6;8?^rV%XPUgrS(QKy>TSpA$eWgX8BUsMCr(&dlKgUO4v|fB zAP(w5tuc=5m8#V4(%D}!v3BfwC3_r}knhG%T_R~|Swac;4wlQrdNlmfcb<6m>fuX| z@rJmok3DhtttYQO%PH&+Q$v^&B5_%pMwf*iM*HKvK*)d*-;}aul*%`&cig5aW#X&g z=346NmZoq;&;Mik=--%ueYR&z?YZ^Pco^U{Swtfn`e|vgpttTRUfIY*Odwtxn_Ti5 zgpWtl|9AwubvaWsDQ(loCogmbu?YQtO1ep!K&oWiKwVnZQd-@kyFvpn^f#-2_d+5V zmq9B73!TE~t=tRjHZAC&%^Z(4kwv_s3_zduD7wXx%3V6{RAo2*Lp_jQS>VW$=;h8Jgoy{V05n zX5gk`plulh*M;xWMueNoS34*L_t4x1T9oy!XVCajqhd4x@o{5yd(?$S!~o zlM?F2%X|zSBbZA;mA4rzbBga#TL?`Pi zCj+S<*;{`*uc>gzHCQ7^U(QbkL?~jKu0{OH=TWHgs<@z{8-?l;2%+xB2d(G36Zhz; z=Ff*(c9QgdkbWAoVN!i{v|YmFL2?;YH~@kedmMYpl!;nYZ2~0RpAz6hhyU}+cfbD4 z$F4q!ZeDK_J37wjCc1RS>be{-oWR9G^8wSYDKAAT2SXyaaJuH#-2y2Gt%YxbtUtC> z@0)?AzSxE8rh&xts%B!QK1bsDvPW*T`{m(({Nc-&mOX1-^{1khgR6Lkh<4*yo|Meo z4d|z?c^yIYT$^IjiI!eR+X@Rm6cG%)cN!oDj=T^wF?xT+324&Ic%l8~*?;#eOOu|v z{jyJ^s4rFczW*&Qp!=f?y|!;w$7BSc@qE}rbX`mD?)bdnXjTu&QCE0XW~s_!i$3^3 z^R7@Q8wiIC3{0Nokah0t?$TU){kr4PCBTg=FYl0Gl8XDZcVR|YNWNDBuFHlYkR9xxH5DL!goE$r!>ZJ_~YS{N0b zGwI-ise>YQfJ{|GSVhkM7&Gc%k}8$S5jSEJ{s}$_gVOX{d}}Sn_DbLwA5c~C3yQbn z7Iin%MiB<&R(zYjK=}LfX2`6fDM|4<{6X`a*8;MmaPNLbE}y-?y&V$CgXj(t*= zcAY2h*Q0JUMi(=x+&Dh)mX0bLLvor-vca9r`Q_Fv4^hfX)YE*Now5VSVu;c)tlXgM ze|0ZE>O%M7nfT7KT9q4JRf};V5T!pk19zh-f%&fYltb1we#v;Xgar+uGD^4i%eI!!seN%7@# zuf41#Ca^HV>lvZ$-(LBoAf^}pZcJ2m6DjvlD8iu9Qh69^gp2|Kv3kw~sGjMf!YzC?faQ?~z3NJf)Zkr-iuKopFUQ{NU#-lb>LdTgK>6anWRL?&62l0-El zuVz>>bt!#JI2$-hV@InTc6@i;MiA1t)x=F2rukqd7nK7Z{>f>08bZyilnRzjN|kEt zEA{&Eyo%FYbSf(m(Ep2fp`uykJ+Z1N*Hy%**FrCpzUbhP^Q$SL9m9?w5a-8MragfE zA>QHGEM>-bfY3+p@rjK6hB|THZ4fu-E;?E^OBiP14vnBN%~Kv4M3clwcllci>}pu(1mUDeRhnHxJuVr%Bh1DeUC zbd>HoFpfof?O`_cNw!Z$lGBt97){o}#I68DAyZKVOB1!Al9;TZi}NK1F?}dQ6gZ23 z)@sdfe*4OkU;K?4-~J7upkpi+2<9XJf2!5B{>W3h|2{f2<7m~B0^8}zR-h{YWs>a5 z`@m2P8+HUr;Dg;xh9rme(=@+k^AcWyiIH52QAGuYsnm64e ztG5rIfBNz7Tz&GXqhxW@SU2mqopzz;EgN}&b{h+1XvWl555M-rW6yl^^H-l{pf`5G zEw`9h;1pY8?mUigQH%6?Md7cN)j@usoca8fd$(3HU99ku-dyX&KIRUN& zn1S+Vel?J*+7}N0`pUCcpM0!`=FfcL!1omI89Byw+(B#Dw8pah2kYcR+VkA@rb@Az zA5X(=c4cu*5<$9D1D0s#9r8s{5KGptdyT2-!5Wn?M$J&kZHgs)_s$*1Qi!x)Bs+C; z7jHx6mO^f9@6_#04if=$uN(oBL|})Mfj_T8?&)ApnUl1)cl(K^%H!cuiUldcd%o1 z$+#G)V=JHh6B-_`5ITx6aQ)LSxNl~k>K1xDI<}EvXCSWbr>@0n=&8XEk@r$c41?SM zYTJhGwS**QaLkkgauyNr#Z$KvDdeX^2AK1zYNiYMM zSyN9ug5N-*2`Y7Mra4j<^8|6-V!5vaK3rz?2T@rj?HMqLr~U# zh;&A943?sI{>$MP%;i1GU$1+aN8IJ|yeZ)Jjms?o*xkLT$7WF=cjBB?$h{}^->k-} zo2-zUxThT0m}+vI5N!8SL z!ri9$%9P2t((-tHoKPY!d`_J)2B9vYb{RlTwUq?o9xi&(+Z5z`wLOr8n@HxOcV;6! z3E}B8qQRgRAZDLs^C&d~F`W%%y_>5OGV8Dfg5MqP6lT7E_U74Jya3=0{{J%nf0h6J z2)y`H%DDge?E41-=nwhuBd@LSz^L**iS_T7m7l~A!|CN(Zg9n6Ra?aGN0CeD)P(XM zG^pinE2~qK!Zz=I6gpecMdga!GRSEO1(U^)-{ps8D=W9SyQ{spQ{sP}>7nOfQW@Rd z1XuiP%0;XXoL>z7d8fH12RPU=$z{Ec#F+0(r;X59wLW&?ZqUeWEFYnVx1z0D-o=K& zYNXfzpIkbEDqI_j_?NIFeu$N@y|aAPQi-zW&6wx?ssOp;`;$5O1RtiOr|xa_w6uAF z7Jq;>aN3yZVC7w>TVs!jMo!Ydda!IfOQO}7CL`C$W*Od33#I*f>=-&0GkoE5m(G5K z$7kPyh|o_=^l7fSK>(*&)7b4^F=GpH4SN_v-%znK^Cab|B^6Ljy)X}+b<#Y9FU0dg z(%n8fq$Kdk2__rTQ_P9^(RIzS8#@6;iaJN}ED{6Of^kA1g1UnQ(qpWO0kKR=4+YYO zu(4|w#C0Mc65i+!t*Y4ihNTz1-|+;LSAv;b!)(4K?_5H9S=Z-Xs!hd9d{x2PMaei; zQ047uH$>l2>^6NQ#KpybVt3Wg+YS4?;iMC?{%=vFgoeoNr z)H8oI3mu%Fl0g$-g@w`fq*^;quRogD-B{1WYJcNr?%x{eLO>Nk1^{cTaka+NW!{p?KV2aFz6(rv zlk(AXa>L|jm3Y<5U3O-rNUC%er4@Q*;$|5%&;PYOFJi8Ismrp@0#T)sj#TJVv6kD` z21O;#ruc52*8Z<&)HQjU?Gr8IE0+}u#}k|G<#36=kAXyb-s+KRYtC%YS&%|(F;8;v z2Q3A-vPmVypjY_LWoJe$;7D-g39bZWWQASMvg4Kqm{)OXPVYx~t3P5T#QeE8LfaB?hq;jRL3gH?&U>h~I zMg-tm`Zo$qod;@|h(+@(Nho}L2vpe_Xlicpg6@XOfGdkPqX03`eWu6~jjRkDG2lBc zO4Mj(ql+rNNvvQ98>^b0$xXO7w$YVuO$t$PvcfJp(kE(_#=#_E9u*{iqH&#f9ALNlqcS>@x#@!D4a_An zY}_@Lq;H_88%Q~>gOvs3yFd7x+xmjzmKlf3y*kZ!o=S6IKlah3{e_1m-2^}LZTfcM z2ppuLS}QP<3a?#m5fGP<6$kS1CDkiRMkc$^bQ7}EGgeX^n5aC^-05)#FR25yX zrSS^5L1LduLibTB?N7A}l(2c!N{6j5W6$-8c{M?X?mDgR6`G-S439a#W+(h#mf326 z*A$&s<0{+V##gb;sH(*bA$Sr{D>d~Nmdl+_L=-QsUNv&#&Tbp$4d>Kvmge4IA~J5y z^_iWy=`eNXBH75F3sU-fU0E}}Dc^3Uv@4HS(A@V*;r0BVh=T=uviAfeqhieB4@85% z*i#+jVC;^-V^t*i{8?M9lgOx%8_bO-!?+?rV}nReJpo6e?m>%+!UOOcS4q`PI@?)e~xQ`oXiyuwX3B{o4BPRskeOX>;W`p zZy!0T=+fDndIP2xuP7Xs*x`d(p*9&8s07)9K(^pfmmK7ARn@Gyevao>Z>VBgBC5nm z8=_!t4LIWCPQ+fq4trJ**Dh-jI|_bjPL4{Bg}X8iYfD*`-OcVn_1B|lE}X{dP4a7f zS6SFP4L1c*4r*lZfl|MeKDiG=j?J=B5{X*Z6U3OEGMCkG`7p5&SN3B;GakPq`D%N8js`TNggbx z^Rjobf#xb3yOGPPc$UnD*uCbVu z?yK->?sYXfqAl4XTM_sLjxw*9#BQfNv3&_4@1QJipLrW z_TNi#Zxc{P7RUu#xzDp`2DB$3qkwt0*>`)GUqO{CC8jV`pt$q=$s>(03s!SM$db|W z^f(9QLDEcUl5_%7hk%Z`qM1e!5RjZK>7FK&R7@K$q=051!)%3uDKiw(bVsvK+ zQ2Wwy_OSwO>{8|bkeouPI+^7fL(ChUHFM(!V9@^Tg!7m-YN?wj)-+dq+|86}Zz8jNp zH+m)()zHgP(LHzHEL-kh?OazvZjNP`#)b&R(IhN*x9#0~Cabyq{5=Su5t8QoInZt~ zEXKxm!m;hWXh6y77A=V=m`|w3g5GH0l5Wm*?_Ht?bG>4#!1$$U4vQ3f6T^frHNMz| zr6;3Y{i?lRgO(A3=j)NvYwxp>6T6RG0F_4WAP`KUwr|l1lkfqfJT+8tn-VuebRnGL z;H7zBnzY{4W?-4X(P;RRD*lWtr(ua-)ITGsN-jUV6k)`H=$CQY+lQ5QfMfefP9|8h z)Nj~tLuZL6F23)yFkJ5ZI~^I>qX7bOtvaZQo$6#xlbBEnzQ-+`9^w-Cw*Ag`ZCJ~B zU5tp(y{HH=v(rn6iZWWu5%re3N;o)Ssbk_3i-C=e01-T*-6DWx{(ksFg{zS}9q%W+jk^@fEUN|{n*Nd0Vd|8wmI{gH! z!s~r(j%E^bC8zS?IF<(~RUp23HkNadZ@qBS@Np!_c?R;{mOk%HW`7=#`8H3O0t&U# z`9B{bH>R#^Q_?iSE|@v?eIA4FIzmWe&sExvrXcI+fdbXMiPN0xcvQyd3lC&90d&km zgIaZSUE!yt6y-VZN~QFD*8d8axurrLeD1 z2E48Tq*Dhs(O1^4F3}E*q3zW&iF}7`1&++HHiCBGmhJSHm^vq5JY4CFMI?#QRQKg( zuV@pwcm3C$Zv^6V3;(X$;ERuVg2x^G?H}TRe;E~)PxWJ^4z5LUNvflvMDo$f^%8Ay zP4s4Q*lZ%{TrFDWF|mg*2GjrcSmd29R*I-aJ4h}txLFJ%1;yCF;j6#?bNt(jU18NBdH>QX5OaaUvm!ZLamtb7BFLtMC5aNtn{KM; z=bR=t?&)%h7G+2);1VfUDjB?DYBe|SC08v}tkNru{B)~;ze}xun6O{NCu*E`2MfZh z{l4d2>zFYc*Ql_jJ6<_y5VZ;rCA&1UU=TvS6+hdjId9 zb-z5nnZ5VSnl-Y|NkZ?9#6h!t{I7C6pD#7G?&$L!O62oxxS(2}Z)d6iUuN8e)A0`0 zz}~3?e5LRZ=D?sd0lrAggDr6uHo*@Vj&;)p__E_b48hf?`lG1!UtnEKp3Xhj89V5@ zmGguI_}WpPifQpZrpNC>1AMWu5Z1!7sBz3Px8Qe_PhlwD#Z(wQeSj}1rpI6`h_SE+ z>iI?(2m4@L9DyM?71Q7*jEN^PC0@dW_zJgUU83TM-abQ@0FEOsf z7`PMT;{p5$Ph*-upRYr>8{fFh&Kc$+)N^a_4Q|G40Y2Y~EN&cUvIh8=M&C75yH7DW ze!*y%l$#ZAN>n);s=eH(d=$3&T2|ixm5=6_06U`cH4yduXw>r)t$qe7Zwsw{t(CVR zOU<_rqvHvyKaXnXmU$l)-&556|3md3C%d~ZnVAOFZwAynWJAqw1-sr7HU9Rfc>AHo zH^R#Ea1!Mxtd0>m0(|*!Fe-mrQ0wauYCNY<^L8DR;B!>}ff26#*r>RZqT&s+`rN4J zi=z6kgo>*L>iMpy_1M?SlW;fXnYa&YXH zQ+$Tou}Yo*Urr3j>*CLi>bD#!@6}N2xsKI0!DN(Mq4F>Y)8Q1<`rU{c=M~g*kIdJo zdHrJLz?88hR;0s+49_$R9U8UsL|x^A#$e|Doc|Tr$Adjqw!66qGlXa`7KQma6Y8s-3_xZl2?y+Ruqv7X|S) z7R8>JrmTD4{D{RUpT+DLznrruhEr~jnQ)qwcc8|11C^IosCoT{p_rh&iz_z{qFfYp z{|?l9;4cip2dH%rvw|B>MqEv~1UA9@m>bJfbmvfSRQ{%+_RnfmySuO~p1{VKuu_08 zFLp$oUyHF9?n3R~9F+rn5jYWBs2&wZiYhLD`BD3~1Zv%tL(M}?)OzWURdA$TKZ%O# z3hKF+sQG)3AsAHEwHt;yS0Yexw?U1sKeoknsP&hqnmaf1q2e5gd2kEryts>MKd8Ek zCoyWCQ=`^@MpS$HE}a4eqRl@E@PwaPm3C7gjpDM&Xz;1r&_4_ZH!tc9nICK zc<*8)#;ED?*a5Y#$5?qes{Q?_asP$N*FUH@-=Wrbj9PA-sZsmBCaS&_YMu2*&C?jv zdA$rZp3A8FZll_JkIGZb+HO5&M(yt^7=n?gct)b0n}XU;QJ4ew+V#hHf$}??gMZa= z`#-X-TMzwE`B{qUcP(n4?Lo!0A2r@%sQmqHKC}97R!&sU-Jc#cAK6jswHRvsZbm(S z9M#|7sQJE!ivJnv{12?}&f7$&@fN^bSREDDQ1r%)x_=649u}h3(>C*W)VX#BwGJ+$ z=Hp+~{U1^{_RKF)teEiQ0?_VJvYkg=c4kp z3^lF|sQtYaHJ)8|{ZE`h`3z>jR*l`~&2gx4gnsYhj6n5Q5Y-utymbJVm=IS<@#-c8h2k*TuU)GZb!W*A6hwKYvwV4^@++?jW%w6 z>Z8g(pz_%c!?8P7$GNCH+(Y%7w5@w@RL1O-hokn(M%4WOZk|EyuN$cRzDKRs813A8 ziifICf!Z%wQP&GweM!{$TFdG?qxMTrRNf||*5y*v`q+SqV;5@uoI>6A78O^__O72` z)cy)Xjk_S~xe{hw)I7CEydlA*o11tOc zx%%%=`y~@jz#8}?UcsW+p}#vQw)9?gf^s9Q zf^$*%x`SGG8Hc&+gHh+!9xRMcQ1AP&;Q_vaSPY9}Z`3~j#XN}G?`JSEUb6Bd459o2 z^I^gf?wlx(+J6mD^UxM`zKulXe;sQ7oki{IC%6<}Tm8(D?i|>NT8Dd3@!Unl`^L(# zN4foy0yRGoSO6Kv+tYPUJ6|9+_R zU@R&RKcd#_a!ifuQTz8O{)Ydc+F39rz{}HG>`3`9RDb!$y0~hh)@?gfe*6Cb+z2LaoaP48bC(xSOE%QCHM>N221Kfy&QP zRKB*@^<$`UUA6k>Rv&$$yFVCpK4wC-n+LUSE1;h1WsXPnzX;X-W>o)2?fMnF{tR`l z_$ImYDLZ;`qZc=7-;YGChoyFX2Wme4LapO-sCE)gcJo{ewT>%WxhAUJrl|3E!w?)| z*B7Jmx!yd8>i;roT|Ysck1?jWdCG=rr#$MMtcy>uDb~YEQ(e4^P^ids*tQ0))FF*p|0 zf86Qrb4pUwyyQgHmqe}qil}wo0JUCwq4F^Xm8YLDD{ex4&bo%`{~fA7{|pyrT&zzy z8)|)wz&bbwE8-)ZjJapJdE1BT|2S$K*RT;LnHAuhf}Jrhe#RUaG25-Lrl|4uM&)fP z>iL~m9$%RS=eRhBpz=KlbuMhQ`rVkB@=;X2U!msjD{9>F=DPbcU}ws?Q1h_J>Q|%Q z3)@if>_X+|JVxSk)IO~>&pp=^mEX3gy!A)T!w7Q%Y8_8Uou6~D3NFUn_z3f1s-LV~ zRR2v;?M9-;(F^t78;aToyD>SQM2+h{Dz2}n_g>8TZvL~O;;DpMceSj(8){!n#!|Qj z_535$`hAC;Fx3M0bBl2pLissr90?Y>br+19hj7$BuY_7>ZBcn2h?#H_YMpGg`cjMB zxlsnpsPQ&LotN!V z>tQ&?!wGmC=c3*NtyZ`^jY6&WxtKiA=R1hX$F)`N=UtDmA>|ya-FU{J*2_98-$ac+ zXpM_A6P6$kWw9{zBiFJYDDTCZl<%!`KR3<4KEOAha@Yp9zYd_*Y4nXQ-ngjsk`gta zg;D#zI%>VO#9r7R^||RO>i!8oyYa0-8qzM%3HZIjD)8dSatpyDWr zx?UcYzhx9ZrFRXzhu^^tsW*BR8fbS)FY=?g`?nYbP&jZu`>b_?W!fxDm8nxa_ zZg=rjMYUVUj6|)2?x^)K!JLJf=Ow5-Y{qPO81?*XRJ;K@+`34BdcFYaxzeaS)Isfw zc6NQ5IUjZ3O4R40?WptT8LHiwJKZ`6#(I>CqVoPDDi51b>-7OfpnsS9`9L1jz8-|x zaT)5qQ|4nc`fgXB9+m$RsP)>w%6(DuFclT&98~|SQS0O|YTmD*#{CL)&V5DAZ^Rxq zj)JK3qCD#UR;Y7rAnLv;R-S`;kF7<`$6-`IH&N&F8`L=B?RDiWW?9s}Xoecca8y6@ zQ2lN~#edSuH&EmJipo>!-&{OpQ0Gj2{EP!o@%7&4*3S@BJ}02&e>*C^KT-W&MaB8b zjI-aJLt&`<3gUXKiX-s@>U}=&fQx4$YQ3yO?VJ6m>&L8o6*aDZQT=~LwHxc8doB&? z{yeCCSO#@|RmLLN05$IEsPkeAX2mC{b1C?D_xZaNYJSR@4N>c{BPy=`sD4LcLH6Ao z)cfnyA@@GJg}U#a`2w~7KB4j(?GLxEvY_J2jcUIHD&N&m{ntnJ(;k)A!B#&9wGP&z z`u!8NKQEilQ1kBRP|!LGMdhmqs-McJb{k?B?1bv?D(b$csQ$j7?)&brYd;HyP%epT z=Lgh$bw!PL6zcgYm=PDE#&ZyL&i#do_YCU2e+RX19-!KJjk-U^5to;QsBxx2wO<(Z zTv;rJl~DJOF{h&9or{WZJ!;+WLamFxQ1fsNm6!Xd_Wwhz-&9B4^LbJEtcZ%M8EW12 zMCEA$>Kt5%HSs9wTu6S*Jzo$t&Z?;AnpwFw>iszu73W5~eh}6F71X+YY1coX;*Rr| z`<|T&i&CzEdVV5mo))9>vJ*Al-%$BFh05<0%*s0b7f(=*f5LsPy>3RFbo*lj_Tc(n z%!3i9+<6v>vnbERTbTKDfUiHsI^!IPI)A=k9ZY*Rz_$i_U|URi&YkNcQ0sjmD!*${ z`Ph$&|2~$%C#d<0IPc;whFU)rty~?IuSQnxZVp1_W30IpHGjKNc{z>B?=93me1M@C z=Yp%xfxRf_L#>N7s5t&Wt?P5BdA*Hl_l;eTdC{$lV9ZW^7W88S)cXA1Y=w%WGpfBI zsPld@YM$1j=6f4@{i5DK=TPljL#?}iF$*TRtFHY}R9=c&xglyEdZ6+#0oC4OJb*jwdjD(g zxgSyI(gxIXf1%pHgL>`_YTd@Y?(z|gA(TT=>!u7=z?!IiJO}e(6qduw7=o$)cE2Yo zj>>CS)P5O&YG(@S`T3~zunM)lHex^AinTG@KW<$PL0un-+W+HG&n-Z;6NSpx&!~Aj zkInG5l}p}m{z>tHkH!kst>AEEY5n_Dif zj^+^5{QihFaVa*%m#BPHzwP#2Bg{#87;0WOq53I{u?#_)!w@APg`*rwHtzPRFZfbV-u^(Daf5c^^|Z1L6oTz3WLq5KNdG0u$tbMK3C z-^eTFVK|@bGye6SY;=n-PK+3JK9^OEWJFh>`Hx`%UG|U7a>H>$l-(E`0Zd^Q(G5A@}y-x4tbeZkl}rfYXntUw=M?R?Q=2YU0iHBO-K7oNX? zAvis5ptsI`L9N>xsPpg@YJDV%7wGNBFw}XN9kmaOqV`8^%!pl3`(y^{zNM(=H(^RV zggTFJp!)fUdOlA4K=0hkgn22KL|yNNI!DH$&e0jD^Kdn4zZ}4DJcsJ%6DqEF30ye? zYQGi4{JeN7Vjjvv5(j$UM>eBAhup#F_zCsAFNy0f7!_|eR6ONT@is!;-y7BMAXHq_ zP~%=>qHX0=>U04MUA%JZk?gK%Jk5QT?1kwR;V<-(RBQ`)uVD!LHp5sJ!Gw z#akVfhvukrs3$6~gHY|wK;5?nHE+96_a8^ac@q`a3sk#-$pU@(Sg)y3_toZyBFbAE zRGxcUc@k>;^RNzXMD^=S;qFU@8ecBd^Mz3Bvpnh?tc&Vz66*cC5|yt*sC|ADb$`Z` z&OE5kFQri9EQcXj9nWJ|%zMJ*N36*pJqmxzoOzgiv95d zHpJ@b+_+bw*27j*`@f;uIgA?bRn+>65fbRV7vrJkJ2@);EEt9buq-x3&FfNBJKIp} z>KcM36iE3}K)sI8<_Y-PfH=y?M zZdCsVt$YhBP=0{QUqpJhf2yGF--sI5HtdcEQSIi*;QB3(7bw@nub43-@v)vm!vcL5 zDTjv#dcP0+inXY}l*z5rOj+DGa-#alXXT=popLGExVoUm)ekj}kyigBDz5qFYSekK z4Kv|soQ)q)`JIy0or8-pBjq#L72jb9w$A3x*Dw zr_-?m`JIj0U;jlo3#fMD=W+9s1~m^E zQSs$Ot-qS6@kOHI?QiuXQ0sRl>fBk2it`X^UXP&G(OFbGcTwy7J!-u1^SXIUjRh#@ zK=t3+>bs$yAC6kLGp&9TDo+Qj{tT+Wr&fNC+DD1=xpOewEQdN@TcYCahsAL^Y8}`%i?f?1aF7t}{0W}}N#a(_fqt-zM zv%cBd?1fs_Bh5wTPV+o!yw7nQCN2@^TZHp*GZrf8u0O(3l;f3h=W7kjOt~KFd>DfL za5QGYuc-ABUfRuP39LrB4(7onsOQe1_Q_S$y1IcH&r{So`GPth;*@duOO4+7hHAe& zYTY)o`bboMdZV5ji<+mo=0>YOgaxU;fLgb4%ewxOq1J0A)O)BbYJJwkaBPgBI2_e~ z6zcxnsP%aXSK$*}i8IQ%`7Bi4<)tBhq<#eIJRVpf&^L&6(yyY6^Gzl9c_CJ1w~y1K z@>~Wru1=`W2SZSKSb&P-XDp3}QTdNq#l@8e6?Y9xjeSt(!wl4OzhDUdh1u{4Y95kR z<^4!pVOWE5hia~VCu)BlM#XatL-8r#e*OHO|B6trOI|+(4b@kFEZL)qh2u12Jnj)1k&$05v}~Q1Q1ywc8Ih{}VAg z&NhEHUzn+Dy8A2Rc=FN|75BYbZamLX=TeN??%WPV?YpI@eC|QTbqqB>w@~l7*mVNE z-@oQW#WN6p!zrk^s@8S;uK{Y_2BOycd{q7yqw>5Nm7neC^@kegG390y?P(D51*s<RhT~A@ z+D6p8oj|RNtL6(-f6*Ga&(HBt`S<~Ke=k(thGThLhuQ}(QT@bk=;k*IDo-WM=BUpB zL+$z=RG!YD#&Z!h-n*!E^#ql_52*Y{Yvkfch6HDzM$d_igfX&MYWp~z4O!RYoa%wR_=wra^GmweMMTj^;`k}pxg*G?`c}Oac4!X z_adk~RYR?-x~TOx04L)p)X#+ywhr|EZZHXIp8rMV>ouxfUmMq6Jkm!1gZhC$J9Xd#F4X>fk=_ERD6X{c_?Q#K&}7wsOLsuD9%BB&e@5|({-$e0iE3XXn-RquST86 zSvtG;%V0&ybx`|pKI(cDDsOvG{U1g3cg@Prto$EpeI)MU#+3z?m*Q5gj(RQ<6<=@E z{c}<6{)`3j0BXN~#1Ks1)xF2cVkXKR%^9fo+HTB?m+=RT)6KQl8S_vcif3^P>OC;3 zd!YCC7V}W!Y}do(sT+n%14DkZhW;+ z?}>Kk%`>W>iKuoLS^XCC5GuZl<~>w@?@-VA2D|o>pzh0P<$S32%cI^i4Y30bLOpj6 zmG6(J=MoHY<#ed`ZviX!Lgi~BX2W?_{sXn2&Y|*p6*Zr?u^A>C>ef#m)ca-*YTax` z^}ioAf9K5Wn2GXT)cS}!%*}U2RGclW+!vM4si^%p54C?*U}pRSmEUKmefJF~VeoMG z9*@FSl+R%sEHJ{IuM1J<$TQSDBpn&(i^R;Rbu|(5;u2Jx=TYbM7c7UNqXNC(KeWZM zlz&0xrSNEXZk9%^qt>YXHUzcK=3D(z)I97$&D$|lzOJM4^%x7`|4{iXFvg9u7HXeI zVq#vTCs586kO0+g7%G4HP~$6wYp_1*^Tjt*{7EOceo~|E%YizV z%Am&69JN0B+4V6PN_oDy*Svu`KYSD2=jc>sDYFe~oD)&;E<)vF9V*`4sJtITt(#Z) z5K={U@ppyP~)0_%EL-j|23w#d2Wsx?`Ty1 z7hwkSy#uu$uTOLNx{rG9Ick2tp{@u0=<=NaH9x6P`OS-ZUlm2|r^cxB?g!L;ZBXMM zf|{?%sQH@QfofYV7fZMSJ#+&WN-31kQe{(b{-XBr%twi;+9n<3;R2(-@ z<9~wM|Nc4d{*9_KejlOQ`-qy~ zICEXz!cgZzcGUa2F6z0SsJx9r^*bB24%eaPbEnl`LgnoVs{JokAAg>UD+8*%VyO12 zqsG$$6>n$Me2+)vVKM6dUs31eVbpj6escY%MYWS1wNFamc&vz8UuRI~01#TP>sC<+_#nT2gPlL@_s61>yjbk?|-Xo}Zu2}gtYFw{Tam8Hd z)@1_J^WUN7B?BtIc~E(*X!Q+I>#D8Q_e8}p67~Fi)H%KeLvSx@-T#9+hyF#~{|&W2 zgBQ8Hg`(y;FDmXjsByN!syGmp-@{k~ub|?}wAjT{5VKM)i;BN1>i!|9{-$9Vu12ks zlc@K~6I6WZmbi5ihKj2Ymc_DI7{_4&Jct_qN7T9sTI$A|3{{^EmDhr(_)3^HQ0u!n zY8~`PjdvcZpB)&2Ur_UvdYSt^6=v2khoLvmsP(rSm9NXFxF4eWe}l@$XHa(HpS|63qHmG=qq2gPJ>USM#-nXO1 zaS9dZb=3NQj_N;XrOQ(a)cP!k8gC1$?}3_+g{XD164l;%RDV0Id>A#K=TYnHHL9P4 ztK8@5aMZZlqw+BT_54uOcqXIQkJYa?>JC_ro<~;>I#1Pat zVy$uGPK9bG0u@(9)aQj}c72#R12w-ZQTf?~%I_bj=Wm;zQTb1@)}5C*a2Dmt=&cjf z^G~rV2CQ>&R7b`218P2dqW0xN)Vc9HDu0(y@3*(8eu}Mk`E7u@ua7wavr%4zn!jUM z3Gbqw&#}S%JfRP2KO9A!-)}GCKaj5YwMyv=sYPdiZS zq*|%7ka*AL1eL?{53*=AUe6e@%cQ^Q8r~7$hm)(Ir{uI<#VK2XT!le6{ z7ks~;eS#uc)@ljrZigV8&?)R`4QTw#hpMl=rA@xRGe}$UwIEP(* zW>owuu{fT^QkdX~i@O%;dLJy0%TW9I0ct*;q4x6^RQrKP-8xB)%40#)daH|hu{~-% zEJWpN8ERdfL7i7mQ1ki`wQl1cbMu!LwGZ>7=A{Mdoa~S4cM^u5GbgD(bm4sC9f3_1p{0fyqz0_9~#B8;%<1JPg4Z-$}5p$KoK$C(pV0t$g17oV7cu z|0q=6*P!O%5URfisC@V?xcQHb%5N&niFL3Jjzqkhj~!%mCC66wL`Vj6SdDq zp`M?J>Sq?J{U}sER-^9Qh>CX`Y8@X$^>YC=zmKi{Kh!==eA(R>fqJeqs{IlH+8;H(rKodaHEP^@P;nnb?T=H~7w@C?SF?ZI`1|4al&4@Re2CXD z%MCZ4pqp;rWJHaxEb1I-g*v~6V?o@81Mn$oTy1Z;xVEC=*lpz_sP%QqyoSo_eN_B! zQSryT?eZKSwf@psIl{^%QRhMpEQ`%i{Y2UIO{nvJAFBN$sBvCIwV&&byT1Uc-?FIo z8lv*k4i)DJ)H<1h{7I{CIV#@^?z(x2Le1AYE62U(+D(e;ClqymCe%10Q0Gu_yWSLk zqude|Z^(W3bAc?Vc!s0m{}HwB7NhppCRAJpQSo0!&C3(i`iS|!#SxAgPhQkIsE%r< zjn(%>ofki%_S=nX z$x|0sIBLHaNB#Vy4ywOCI2kWs8;pGBe*bv{)o%UgE}y+o{f$74cNS`V%Tf8?f*Q{$ z)c$;qI*)>1xbrI&YF&k+<}nXyUdrJDY>LX~M^t{}zjXbkMddXcs=YF(>lIP$HAI~g zt*{h!LiN7^d*cNhf|Xyn@8L&K`!x7wa!E6}xiZd+dU3-no5# z9&1ys{@$(EB{)X+VO<>jfxNJe&Y=FD;KoOH9=7`&=zGNVEm#5`r+UPRF;HAIJXZ_TygE{HEno^cF0QI_=-XOoXzJ_2;$}3QDzD4ynE1KW?KC%P* zP);4)@2#g9sB`KgmcwE({NBI!9)a3_&oCKr#Ej|p-oqiW{N8`(sTXShW{U0i&fC(M zg>oOvhD&f19>-T$GmhW;y>RKcv`0BnJiqsMd08-!_GiX-@y$u#_kO?s1;=sUgoJ+Y z_xy7ML9(hcl{y$KzVXfzxQ+YXPA+4_;-G9{a3{vlsjQB z{0BQ=?O?yR?)RY9=Sfsv-(e*znauC~oM=3@rhFOoT(RVS-%?zKov>mGzxQ|LTT%P- z9u~r&lz#8OpHLhZQl5#*cdk@^@AGvZ%s_bsYM&m(T=)?69!rth@0}~Pu{z~$sP+6C zYW*cj`- zFPGo@_b3B$`+b*rK5ZVq_xG;vQQyxd=k@y<5{as&?9~eLF z-$IS2T}!|BektC{<)u8vqW%PG{a!+?-}|Wb`_bzCt^MBnDhcZT53iWw00^?v&RD2b!TpRUXZ)WwKtiF%ck3fB{n}*tVb5Q5>NespZsB`HXva)?? zI=Xcfiu(N14b^^sE00C(?`f!gzuer3it{8Yuh%dS-a{{+om_o-)H#vEEPM@UYgj&wf_@pUZOAyu13Xo78T!pRDPb~ef*4T@pf0guMAG=#(9OOP~-f7*)Udj z_k4a-e??L8Rzbzn!2AK#e@9G@-B9y40~P-U48dKfey*WDU-^5u^%(~vD2Jl*TMMv0m=|6p0%5Y>dPu7>)tGU0j(_c`u8(un{Wm38?k39@YLn)aQwFsJuSL z;`j+Q{(^nnI;@CV|8=k)cEHBC4>gYDeciqcLETpjb)MHny^lL%FPx0E(AUq6vo>m; zTcYCXjf#7m)i1R2&vyNgl`o;z(G%2se?ragH>`+p`n&wsMXjp=SQGc6)@9rQ?mbcf zHGh#9g8eW9&O?0<*^637*HGj9A1Y7L2D)-m)V!od<*T$=8@0Y7QS&kp3*i=2ypK`y z_X4ZoC)E3{!XUr*^RAJoJZwVU_Xld7oWk6A5p@p680_XJ11jza)N^%E@wY>*r!lB= zYYytX`4x3e96+tdh#@Y21+g^ca@ZTkVqN@#8h6d1Zrshywy1n|MU8VF7RLQpE`V{N zK1Y`r?#}reIG1wA5q|IA&jya)fj zQS0F`wn5)CcfPkp<#ii2#A8?%Lw|Jh*#?!@j;QDRpz=KlwSLyw^^@imRKEU2%}?y< zE}m3oW>h=*&8n#V8i_j3`k>aqG`oHf+f%-b)yZF}8Lt1SGu{5$h-bOJANAbyS#CZL zVSdWzQ0pn?Y`6Y0qSkY5R2-40{n-z5;zXQ@yHU^AnBzVdjm8klH*qQY=K8(A%UOoy zDaM`W_x_zh9n4Po6Y9JP|H++etuYVfc{mu4<9}FbzPqo|0>Ah7$zxIH;!V{4Nw?7N z{X3)1Se0^$Meh4Y8`O9=q4wi#RQs_PyK-@yPPr{={y$<1%)i8a{-2Fn&#zJQoqef0 zFT11e8;`Z|A!;8LS?1nLWl`mtsD0B2mCtro-w$=33`d;@5uKl#A{)?i{>-wnoLMv1}gROoBs-2~% zeX|;MejP^T|1Rdkw5wcwT~r)BQ19WP0mdp;#Ia9NXdcweI^z+I6nI52*OQq1uVJ-kmRLQT>)j<+~xO-7cs&x})On zXXPQNe2q4zpz=Bg)&4q+i@U6R7&WgKQSJU~-bby!N2vAi4YdxUZ*b!dF~d;f%ZiF8 zpIH=@&ob!88mN5LF&m=pZ;Fby6>1!vt=tn8=O8PON3}N{m5)WJ=Qp9owH+1bpQ!Pk zM74VxmCwhh`@W#!jlI#elN2>y;i&#|V|6TuYHtiGKT}ZsEkJLc&8?_?_y_9w+o-r7 zpq_tg<*!zb^|R|Y5vrXGWr?h`cI`Aq_0s}%F7!ghH3Jp*Ce-KG-KcS$L*?%xYTewyBX}P(;Lls!&qdB*N6Pho zaqqJOsB`8e_QkAQ-MPLDHJ@)#`6|85<+B!QeK$wd_cBLf80G2a4)Y&OPrd(FcRd`H zk7}sAH%E=98&<@DsJ#A;%J)UoIG>{4(?Q$ae21XgDS*0O3AH|dKt0#d$|F$oItkV8 z0@Ql>*{=VA%JV5ydv|a#zC}GZbBEvi{{vc%*C;pN>CV5xyIj7Tpystbs{bB100-fc z0M1{lpS{OjUt+E`x8e@&{|#?qpS><0^?!5u{sFa4x>~ufl}DrEo^0i%s64Jgoi|&p z{-k-){0B8}_pJQZ{EB)$XrJpZ0c!swLyap8mDikBUjY?YJ=Aket=!J+hRSz8R67%` zexAA1Tw`uVt@EAcWz>3pkD3SnepgO{dXI*n_EBM+gr%?soDI ztci-d1!l$msQfNRJ-6B1jcV@?^SF7=u3ts%pMS0X6PBdxJM8L9q2|2-YQJ_s^)m)F zzcWyAY_aQqq3*wrYWI^}PjJLNml;)`AN5>Syo0S#pF=7hb)Ww`U^dFd?!UVT*j1MT`xsPf5cI&sc*~T1zTF+BZ@vlI& zw*@QVLDam)KI2S;ia$B({%ojm7DDyg3^N39zN7Lp_pEzvGwOTl4pclh&$+xjLbV_B zyfXn_rW}mQ_j4?T)h@X2J5x~W{~&4}URXKVMHfeTRK7c+;+%krbD_Bw74LQ{U&juV zA6mK2CAa=spgt!Lvhp0%cz(g@cpSAan_YIFA2y)+y@Xo7?@;|Gy5jPg5zA1{hqbXE zYCj!A<^L_}`%#>$eqSr>gz51#R>0S&_6lEfd8&rm?{!h*n~G|0ft3%V&V}=+{3g8a z<|i4doCEb-KGe8Mqt?~;mT*ldf6tCy9BpzfcDYIl*j!s^#sc^|5uKXDeGvvRu! z?z!Hm>w{4F8INjrnbmJI4_f^x)cg9j)jvk{|H1rb_0b->b`#@ZuBSuo&xJS#ccPxF z`N-J-HNIx3&pYj~3l2hW{iE*xWM$uDcRnS={M0u@U7vy)&n$Bps@ov6?8zhh}U zkKOURC+_!pV{tR(7*E|g-f3P#y_deC`YHd+<*Az40#)DB9Dv$~!%^{VvHAz7_@3ih z{DL|+Rz7#*ykovL17Em)5~I$$Fx2|0h004?)IR8I^|MiVUXRM-5v#wBn%`Hb`HlV3 zmD8ZN?oi*8Dx>0VZcam;uLrDr4|NU%zjEKxN}#T{M18LuhY`5a$`?@Me~r2?^J_at zQ19D5sC-m^T}agRC{sWy1e8Ni^X z5Nf{8n3t{ohWP~b`T8R&&(Ytxb0Zk_Tn<#;^I>ePi|Vhr*$Fid{V_YvLdA8^u3t9q zqVoR=)o##xcV8S-zoDpk%Z<8T1+|`Qqxx%NwnxoNAJjTogzEn&Dld1@8^;INelV)v z?5OriqS~))^|esrZ)NsC^*79%jQX7Pla)W9-g`kG-RF&>sQe5?^}h)9{C@KUs{gB~ zb^6rmeV<$$@sR&SrY|Y-pTzXV_~PRK^3~-d&i|YlQSBDDauw9LTUmLSmFHP`8|vq% zCovqK+4ZE~Tzk3D%L6K(wNT^ek9uw{ZowV61UvlazCXv}rzq%3B%KIO|)vhdCOxU*_TOC z1S;M^sLwA`%{8d^`0uFonkGh&Py4wN>ho$BJdB%B>#AQ&=g+9`%l9xZri&HieIBlh zDo3HNUqYQ@31hoBOQZU!Z4O4ox!T-@8s9Rc&wVfl<*}&yx0y%GYpC|0Svh(6&2qy^JmoadrD50qXuf<}g$|6HwoGf5Z@6kBZ|2>KwR-dMk%+8*A6sTm3%N{2WKce;u_i-=f+p zk}}BqyMgMcb7=y0#oeg>v!rtI=EBmtAM4;?oQ$W@Ti>bO{u+epZ!N0*U6=t+pw79M zSQJyGaW+KVKNHo?a@6>LN9E}>YTm9|{R{Ie>bY2H-Tf(0=XN+M?h&Zx$6I*@s-2(A zO{kwQ{E1$^(^puQoh-4VHRl&bWfw&p~0%5WGpb7;ePW;V$04Q2jhY#S2kaAg<}Ziyr}WjGdrT_$j{+$ z7XaNO@ey97<%t_45r)^^;|EzJ`a_j<*561p~iCxwU6Tzb$Q5&Di_2G z*Z{Sk7oqa-o0UId7Ro7#x%e)>OTV2PbJj2TiNyg<``67XQ0;IN~_;z<>OYq zYraDD`wg{zVwQCI%7|*GEULZ%YF+h2&BHKM{#T&#yW6f`weo#@Mt!tWuKhQt=l_Q} zFm`E|k3y(^DxrQ3*#y;YFLQ!jUt;B7uo>5nqR!j!GOnEwsOP4et5M_n4b|@vR6Z}D z=Ha?se`43)nSo{9{RvR_r?zqi)c1^BsC=}>>^R)Y8&P>UhI;NHYCJDc^Aw|;TgRzU z@#Hm2VJ`MvbyOaPmJjlN{xKbO-)u9=+=QXj??v@=GT^*v~&U0;oA=Kw06v*ry{J5R7722^zA#;EqXq52zU()06=!eM^ApYKn4j`I z)cvQd{tBx7o90tgJfBeKRIJMG{$!~7P&2n#+N^CxqT=dd<lSoYmcW8iX~uJ`1&9?xOllUL(l+?=Y3cTa>qA6P#5u z$ouyLFH!H`inZM5m~J?p@>yfzoO2g zc>=YLuA7fA5#U{d$>d&LveT0ht6KZ`# zZ|v%`q1H!H)b$aV1*cm5PSm`9L%pX$zIXT4Kre19cQpr@<5A+_)pn z_Ne>1nFCPsH43#)rlI2BjcxHS)cv`ex;ToW_DLnwd$2nyucuJ!?4s4*MUAgaGiOay zJ54bJ+hQjihkE`ED$k$IM9p0}GuENLBsRwxsCHkW;`oO8yb|8R?VE~MCos}oPk?GCJ*qy7SpXGBS+f&rerKZ2tE;Hz zj<tF-^f~Qb%j%dyK#^>c(sK58U+t%&Zm+jpB zsoT5uOCY!TDxub2RUD4pQU5*vSNMkV*A7A6zYl)dG069Ta@S5l-rsRG=?tIPO)1A+4QRAJD z)$lA<$F#kiopB`P-Pjq6_YU%YAF~d(P=1TOa8)07PN(ea&X1m0i~5TFobyoqJVNCy zq<@h2cjeg!@OguBN1Vs?p#y`w-{&S9i$^c z+~>xWsP{uo)OlAL^|`Vc>ib0>)P9L+~276_QJ~HQ(XUrQJ)hkqdu2c zxB8Z-dF+W5aS|$y^Qdv$LiO_*b$$d)b=Tvd>XW0!kNe(dEbGX@I2i+_2pWa42=bP>F5Cb*-G^n@> zpzg1Xnx_VKy{%mzX7w}7D69VkHE(}nEj*2-F=UQwuO+JAZf0MrAA)+nPekSASF7KJ zS~rJL?f#95^FHRl|4{MenCsdvjv8MTD|bLW-xoEm$*BI9*!5MY`?sRbpL3}GU)uGz z=&k2@uKhS>a#X)zR?d%Vw+w1ORJL*})cdw0s{hSc9S>nlO!Sj$KP7gdoDtRT3{-nj zsQ1}gypKKS2YLTqzVU(}@Bgp1!onc$-$f-^#J=ZTzK445!(um%Z>VzM5@#&b&pQ*M z=C_zx8NGS7a$B>PIUJSuDX7mAt8fsWLXE4+Qn!AanFFvk^|P(~0Ck^#nKKx*-m{?c zTi&c`*BhhOLuXW+bIlc~IJcnMJ7``oADEv}&&7*!^Pdt`&V?FBaVs}4TcOrTchtEu z7K3mWYCZgfA8`??ojJ>$%dsHk&6pb>qP`!bToL5`JNFkDLOF6}kncwviG?xAD))SK z)ckypItL;#Gj_J?vr%zHq3+vh_4}><1Zq5Y?D`kG9=O`IpTJCwx-SbVZ)L2$K4zrc z(#qpd`JIKjZw2bP9acVL{)@WrJt`m3*SPsif-2`k#a+y-gKDq6ISBJpo{DPc57c|> zf_dNkXvSXa+E0yozZWuVneENtsC6|DwLZ65IoCQj&T6Rj+XL0_Pxu?I#h2J_eUR@s zHrf#68_IslxY5ny@}FJ&-)(YnW;TnM)y(Fo__~|p&86l}RKI6XdA)`DUh>I|x!IMI znc=ASaDKCj*~09NYG(rW!YG`9!CTz#)z_l(QT!M89%_tQM?a$GeXf=FqRyW~7>c>K zx;X2i=CKv(JvIPy;bv4jw^94!A!^>ATKy+0`?k6Ic&KwRrIquc@=zMpPHn4iWVSJT zqWT|Z&bIpXsQ7nU`5)B!dW>rKe^wvwSJ!_^RGu=S@=*$PUsKfi-x<}V zJ??rLRKN96?G3Q{*{FEepyJ~o(x^PtZ03T7=-d*7p;kF;`c^!i7gv*WFPj@2(h$a%b%p7JeL*@Sv_9HLnQSnth==!UJ%3~)Sj1#Rs#_#UF5Y+RT zP~R&GqVnGm%VHPQ_oOYj0H+>u&t?6?&3|rGd=1c#{ZZ`=M#VANoQZ08zFpspjVT{M zt&5a@x_wv>b&hpK<#Ud?+}w=H%WvipRDWkt{oS_uhgN=#itiI@ouxYL@>~#Au7di0 z(H7O;KvX>A%oSFD5cS?ag_@_3BQB1-sQea3ogYn6^E?IB{wmbCf4A}#^DUO7KH*V! zy%s8eZBgUth#Jp8R9quaCj`Lw%m=ZRJI%Jg-B||6x=-(J#6C zEa}rBm+q%WD-IU8;YQU1sf;=iUkXz zfDJ5Q#oiSa6~tZ;6dShh_uuw}VOZ|Py6#z73!xSj_}&)uNbu}46iJ9mRRR|T8>I@8%O6RZRMB2adggR0MU;F;i; zpxUqB2fqJ~0`DL_2Nb>4hX=avOuK+;zmGuq@tI-TN51?ggR+wj%D*9?%5f$rxpKqv zEPpmA{nr`Z0&0BSXXz&mUp4%|@GDT|_}S7`w)pxy4wSxTpzL+9bcW#|qmKhs|Cylt zoM!oR46gyD|7J_y4@%z?mVVCCZ-afIe*lWV!B(%Y19&>=e&9UtCQ$vN`Nw`f?FEXz zAE^470Lt&Fp!R(i7=5kb8;0M2@;7ap=Rel4u3>Y-PKJFAPdCg0)vt>{wbPxT=HnMZ z)yEN^c)j(&-lSWBD))3yex7gn*BkwI!+SuL=YCNBZM5_z%m3Q&dr;;46}$ng^r=tZ z3~JxD5|q6+LHYAOsCjHBDE<3?=Ev=^p!VM_L5;gxLFruyYMy)q91I@xxz{%ulwT7q zod8{Z8~p-HUuC$|aE0Mo!)HO~pW*wU?0;sCw88%D?@-^msTZdQDLBT|wC$VmKDmc+Li6;CxW+`wJ*LHNNtCni+NgWw*EC zAW-c)64d%z2+GclhARvo1ts?qDEn`MYNroD%?G@=5J8(RDCtIbQe(N8vtsa&jh9KT2Oqez%1}-aDVQp8}0D* z*z|j^uczTKQ2Y}uU2J%+(dU914@*G#)A0vizav4_$3#%=lK|z<9K*$yzsAx}fs%jE zaF^lXyS!XOur~Rf4bLz<2b7(~hW8jg2FmZ3LG2&5f>ppnfAstB<3RO;U50;x;y>so zPp=889qNIV!KR?{+komPy}?G{2vGHU4ygUi^`P{&{n@{_?E-2Z7z?WWlfkd{V?F}K zm;bA`GZj3H^x2la6qKF$hD$)zqEPb)1uK=}P-)QM|h8sc2y#>n8%|`zW)cE-UoB;O! z!}rTOK+WSH7zTfO`7FaphEqV*|1?m3UTX9OMqgsM%J6B!O`yvCH7LJ+v-JLddH;?E zH7-v8)jpj;@sF@{HmLbwx}_I_vcJ;s5m0_TXSf-Zo$o;Pi=RO0J(|B3BE1a_PX#5{ z2Xyrgia!t3dV8VKZve%&9F(4QhOb%v=Z3pL)%Sk;dA>tH$<+a6w+$#eJwVL|LqX}A zW%)ON;=c=&p2xrAnxpC3Ja40CdXMw86IiT#^ z4yr$|HToN%_`U~a|1V1)e4tNP12sMZQ1z1zioYi)KZaR)jA0HaJ4s7lWO$X~Qo|LX z^8-{pyL z$?ItfO1?EHeS;0h8$AxH{$_z{w_8BXYimKBb3X+o_a!KQe*(2`MJlJcd7>q#^cYZl zml$3Ls@%6&dJU*@Z7}*q!%d*-^9xY>{@)CbKPb(uUu{A8H3O9Vd{Fil8a{9Mo8>n> z*xPLl%Af9rLqPdI0o1-B7nI();E~|Xpys#Lp!&hHp!h!o)jz%fwT}D*YQ8_Rinmh} zRJw^_J5cf&p!ALgHJ`>o)#sI<>g5_x<+&BqI(#>%d)voAwb$FA-rIZ+>i+fAL(<%Q zG7waKB|!N<)94F8>0Jw|A3YDMUAKYa+y78sAIF2D*RymFQ2K^~lFPRA*`WHt6-HkN z)*$^RSRecjl>gNZ^H>X%{gXlIYh&r&pyt6*pvqMas$H%DH9y}BivLri|6-VSxaT|C zur?@rO)cFTlw4O(eh;^FJ}AC(4KFgB2R;k^YEXWTKf=rBgOWej(hCglGWuhN?|_oq z0ji%yj!bjwR4q{Hj-bjn+UO-=92CCi; zKibn%EWrh!e;(x*LQ&4vP0<~W|`Z!swjP~)}?RDGOp`ImvJmwS!A z9#lVh$*Ix(JIBjF;0ifDtA}GGIK())2psQCOArTsD4nlMw209&jjEaE{_amX zsK1x}61WEJP%Dk!x-x!GOp81Tjte}!cHOkdeWc$!DUHRRdy#r+?(YuGuAdeeOuBIc z-(RLTOp9zm|D&M%UECNOG)!R|cyuQYuVm4rVW9lD2o&GV zpysCypzM4Is=PZv`CYlCr?&!C|2@IxU=qv#mw}r1KLvG<8ENI`wML-ESwB#IjsT@M z3TnP9169w*wD$fq0ad@fLAA#y!!wK?Gb{y9B7YV*2)qMSKlufeT#GgyPXT4Ov!(kR z4g+OpjOE7-r-GVqE-<_jJd^Yiundf}Wj>>yPXiMqSGG%YzaOZ5il6TWfU-Xu)Vy>V zsQOqAsz1C2%Ac=5+5Z_-dsIHv_xFxqXVUqgYge!p>4z-+H7NbRfb#P%qaW7Z^VcwJ z07`!wQ2Kfp{Q|=)K#h+ZLAC!)Mqh9Amq5wCX1Enpzt{=NuLC>y^iiPN_he9hrGv_E zYxHiG9stVUF_z8+rLP23f0%9Q8x8LTRbNk9dNU|H-+|KqD=7aeb@cUD4Sbz+KT!R; zRws|`!Cs_Cg3`AL)OfrfJQe%^>;YCgEiJMh90%$i?1au9^T2%4Ye1E+P8Yx5Y6!}H zAy@}I2b5n+L6vI-DE{@9eijt}dtfH`6)1lOcJ=%@V0Y5xU?=cVa0|E_RQtT2;mfld zlw7rLzTTRHO-c6zTY<%(?#pfkn}ccH)7k4_YP3yc>hsXSzQ5E3Rqhssr-7=EexUrAVCiB|^T8}o<-G}% z-Q|{k2$bH(LFs!7ECfHc^w1$*?hL~isQo~`rOyVX??O=WR~!8%ur2B3U{&x#a4h&e zm<0|T>i6~cf!ZhU1YZZ64oi!C0{#W6{yrJbz6v~cM4I~^F9xb#t_G)re}cWi@{xZ2 z*Z}5|PCMPtQw87_(yPIKjGL=R`Th7uqto2~AF0|Hzn(u2wukQ*Z~@qAtZ)Apz^>pQ{Z4f%sP=yxyb#<3HU%e~;rT8Bn~{DL zoCSUjs=cO6^zAYa97=kb;g4Wf(!J00`E$Ttq!)uK_otxx!N91Wzt056kiHu{6Rec! z=c!!7TR@$kw}R>i4YJbQ``pvOOGzJ+o#wtrzYbJ>5cBoW4%9d}!|(zyL3%lOJ$QUh zn*0CttOg~QpUXT>{m%qnC4Ez#-zOKxz1;m^3G{lCynok&I`_Q;UH~39*{5#+*OGo8 z>nKp|m<{#;F9$V`Zvu7hJ2v6x z)zP5z+zQSGe+SP8FD~-!cgPf9&i0_%e=w;2G!r}*d<2w#or-<^6@hB!1zdv885WM zX`uSatTI2o7l0bSOAPNe`op03)*Jl|@F>z-K>7Q=A?=mnt4zYx^_kM|9* z`Tp#Grl&>Tg?{mjH23{<*4b&?jdIRAC(V5a*yr4|$S(4q0#%NO&-3T1I_G=(l$mLf z+3@FFz`6i#zc9`Hz1O2JN^{@Wt^+k*=gm%Yf5*J$9L5`bl`c+m?^|16;>Y*d;Aikv zyVTD|e}LNeMCW=tE5KExZ=UDdVdQ1Lo+pE<*Q-FaU!}|KTwyp2)c^NtCaCs0@=DJ) z5LADSgFk||g6c;%%=dmayvonJRj*EqTr7D|^?vBJeq7WBHO{XF3&8imKfu1%`EzdX z1!<8FNlyiD14k}Qi`)TGx)J+e^~K)L zW#A6d3zww1@0l-In&$rAa@kEDcY>?&ck<1&7wud7mb6GV{IhTK^XE69-s5$=J9g0j02lwYrdD*wlZ-+{9KyWs(k`g*GZ zR)=28(x-r$XZjiDfRdYO`4@xodl4x8Pl58|HOv1TtV?<~SOcu}n74B(DF6C{k{b!i z?@Uno&jQDSGcEmr;U|V)gIdqN2UWiMk9%wfs$cX1>wxEgYPY4J?7aq_0lp8`13Rqu z{+?+#6;yfV8mo=}SQEG%5yQ2pZ^Q0+1w)cSpo(Vw>TyP)cGhvC6bdAoH% z)o)W!ezpeHzq^9+V>+mMy#myF@f4_fj6ChJE-1Mkp!5#~<;NsY@)ucp5m<%vL!j#I zNl;cig%Uilf1%|Z3=QJ~~zf#RPF_5~M$r-9o*?E~sO>+K8xH4lsj zB{vCd3Qhr4j>Se_56bUnLFwHF%KsgfuC&q9tAg@B0M&0=fNHdJO?ssboU-9ov=Dh0nvqN6v`~%;5a3k_Ry`JX2i+lVHe_tGb)AJqrmfsJ} z02jh{`rB#lJ^c<)e)oCD<6uzra5{Jhm;=i1Vo>e56pVtaLG`C&H~I1p2D_3T4{Bd| zBPhL3fU3vmK*_%Wsy}@Os$Kp9)h;#P^?VJ%6G^uM<;PI4G8i?CgKEDimOtCl*BPz= z)xVy!{I5Z^=Wk#$>S^qIUVhH|-tJ;>8TogC>R*F5d-`-xe#{2t_ido+;bBng;OC&~ zX9p<%e+Qd@2Y-;}z87x`N`4ine)5{7YkZjIeplQc90C0+P~*PKM`@9z;JKjsaj?bL z??6!FbT-%$Tn8q=Z$a(LCT#V5<39Fwt^qZkKLj;yYHaiSv(cc&)8U_ZzR{q{a}y{( zUjbGA?V$Q?^-ujiqaCPrz60zAZUg0S{m=ZqGY3@pmVs*5Z$O>%(mwb7p+Bhhn`?MA zsQOz39tPeD9uBTH`V*k~%L}0T&s&C@4Yz^n7hi$Bz};YF+BM?~&)@e;k3&H9lTo1B zrvQ}R>6X3_l)qPknpf`xHQ#OktAlTWb-?dHt!qbp<@wuyN)H6(M-ixf?|Go?ya>wg zcMZ3I((}2c5B}P}r##Xy9hBSvQ2veqXMB z{2yjG9?T(~1Iq48Mt==ddEN)*$IqbFlRrV(KX|*RR|lmxuyhy0Uf{#f2ZEi!%HO5A zzqj5Cl)fK8`L`QX`6}=5dTM~8w+F@7%Wxnl|3(;&Hu`u_{Wi-mA5?plf=7avg3`0d z(#t^UUt{zQ;QpjH8vO-O`Zj^Jz^&kc;9rIZ?)3F=Fev&lp!8Pt{NC&92}*9HrNfRgJB%8v=4^i8t-DV9D9l>AIk_j5NG{aaA;)h?k@+xr7KmDOFCycSPE^kDuB=*tVLR3wFmd_Li9g~jsw); z2|vnl3+*V>M&!z|xo>z5dQCd{Y1lf)^k%Em6Q+=NC-L)n9w$8?{fop0{Yop(OQy30 zzUyx1Fl?O-Pi4~lIqQn>G%{hR49`jUd6CuWTH~vd!hg6Lf{+K#B=nt2oqmO_sVQYp zA5&;+y0hU`5#GRd7!J1jI0#(Fb2z*Yk-0Tw07p{3i?9)fi9`-CUmimtf2KZiH`oOI zf8oddJelap=Q$6#GUN{=9#3iGA@JvzAAQNYg!C-Ha6vjhiIg6}7=UZR_dh(zLGDJ8L zJI6s=Nc>xTyAWS5fiHmG1(|8&Jw*Ne0{t}7VfY!^;k46_;F;K%kL=UnA-ES(!wC0NxL&hxPC)bb#ks@-v86CO#Z`y5)^WS50`+u%R%}^pueQ0eKzh zH?y%hkGvJghT#K?{FFjFigIj2<`rmN(ANUFD<}&`f=D`gzcRmjpmPxER^T}DZ-=jg z`BMmQ7_K*;ls=L8i(v-1#OyY(_P^G2Z=>vgP}d6miPyuYBsvq=c^Mt|!S@(4OGr!P zRPt|d-0W%5c{gd6*2qj`6^_Ht5pq&O!Av&Lh?AVm-dC*4U zUm5w=q3=i1*AQ1&;vtfS{B!2he(*kpPfx*fANdazJO>A32107{;T&0Kbn#ek(p4i;k0sk28is^Lqe%4HnAXkpeQqt`xvqD4k=Tp|fX1fnO%F3Efe`pE)E_CiB?*eS!i0!4&6ds0F7uhQ2Pd@aw@ZlZw z9tZDAY}7`!FYyzwUC2`t-VR_To^tpU4o9Xl@iVY{6a3$xXSMmQ{CQ?iaa8gDjNm*D zeu4di;9tkn)A;X2N5aZ+5crIQ2wX=-=D{-`e>n=dP=vAsx;i4$5gdR|<9SX;t}z^M z@~o9X3*Qlch5RtwOZpnhIF3i*5%gx`YftL!L44YYt?S{hPx^g$ul8*2-1Ce(Sr*ZeVB92`iiU`Ck-8elUL* zled_3Yb(!L#I^BWWc){9>rT?|z&8Y$Szr>DGoWur{}}jQ!~RFa6;>E3{xBuFmj4vbC93F*3q1}wG393H}<4L#YX#!t9dTLRwUHI1NO{BZQVW;(7yHXwc*c}w7# zX~JER90za_k_&HtZBFT>wF_)Y@PQ{9o@4E}n^E1U;U8M?#pIO)YH z>2J{g7w&{1Y^T_%F%bZg{Ogx0~%tk?#quHsfU?{@qGlPb2*n{O2QlHoVV3>jr)S zhGC7_T8Pdfo-m{#R|!3rqyHX!=+4s-+Emh4p|=-uSKxmY;tG9;pGsa!(q|+06S~gF z&H}U5oVrqI1J5>|gYn~9cz+?D8rDHO23;SSUxUEa@b*D|28?gw$56|YTpzQ4rRo}6 zPm_NvPiuUA-SXZsA8tWzyV=WwCk$)gRfroNYI0Yb&uh?qDzbOObGYS+e+m38C~Ix> z--W&};klFN0NUVQd_EqzyU}qHJRd?2!*J49z`p`iSO?x^b^i|OB< z=zR~`ZuGW7PN5lk&Lln^9buSnx|J^C>4E$k$b5{>MwB4~9VMh+CjA$3lTu_Kg+3=# zWH_Djy~eW%+57RK3-K`gks^B$`kpY`bMQOB?j{(gLpvUs9{70=SQ(j9WQX|K_)^zo zeusY`a?QYlXq!8+rLYUTXCl)I-r>lsx3cSw{UdnpgW)$ZS<5-h{G;;XOIfU4oJC(eVJ!$M8%ez18f< z{&~ngLY~5L)ZxYO3?%bM*m3LC(M&<4Wy5vV)ApO8D*%6BAjg-+nn7WWk9adaMq zKP%9;)$EiI{}kB)(8-S6OdIj)B+`{~Uq}2q_-5nB<=8Fc89?4>XrIHcFo*P9^4sw! zj5DlF*%jWf^7Td6`)2cHpH=bi5Of_w{t1>p3;dJk4%2ZAoWrnvIq7xKSMhW}<^jrg zEq*?RY-%`%bP4&z_;xcgFT;Nx3@=bth05S#&}N#ijnT81Iw-NWt_1y5_`XKR8Af{% z+Mia(XQA^&bSvBry&lg7pLGAug|8O0s{7RcJme0f9Q&iQ6zmL7dwi`;x(@mtHvjfR zK9_hIKE901Dz!Jf3di&O!t*%3^+$H6hy-2}xG)9&_o07-?Z=VZ0rhwEy+QgEo;Kvo zH@`Z`4s!kAse-M1Ybz<@wO(X7d{yDUhxBd4b-zCX+#kLK{(XXcHugH=i^3ToKc|n} z25y9B3Os*8Zx7!P@G!b z2lM-F^aTu-N%(jd?J^PHh9UP9JntfthHZr{U^5LW3kSg08kwKa-3tGoO)0~llwqNz zXMjm`HRm}FUwWE+A8Z|l53QixOrFAP==$A9BX42*SM)3Bw_^M+S0mlgdogzVBGVkb z6Y>2y($`s?eQ$L#8k`OPwdk!z-tp+E4sV?lAEmbjK1_$FANhBHX^JDBDLA|Yp-WgxILJLC?_NJh-E3zZ7 zUyA&`q1^ZvSl&AHOhflh`1LpWvJp7Xc*a3f7=pgX;X4eOI$$N9w$Pj6Yd*YNu-nb* z>TYzL4F9pv188SiT}sbYq>rI2W1-y+5C3~k7q$}*!$ZVZqHhy=;_!E;yamX#g{CkM zn?ED}A$jNH-v{_K!1R1Yeh1P|lGhTRk4RsQzK*0b}LiBw=`Zdz+kx^(1|5)@~YHhUzZ0NHhO~Dq(yo0Wo`Khe8dA>l$8$3nS2cI8A zo`dg6bR7)eG4L-$Pdf2KXw#bTeT|>X@VPb5K|H1KzXD%1WNPwMCtu+O^W#kX8-o0w z$i52J$H$}K8O?Jnd1=s7!*8Sqz;g(BN1*=}%K0AYp4izAOq zE`cXBc`%Was6T~It$d1~0`IZtQ1}#|6sBS;%Xn&;f)SRUMqU^AGQsaGPw&{9P(NWP z#TSJf^j=4Nfls=Bmm^oh>UkYyJ%aRSX7^&^ea%NPFCza7c$boY19&}8A9zZ!bs_$A zHk)Op|0-l}rObV;4n;nYdZ-UA3}2(`ZS*{5Ht)m7&hXq|cJt92v-nwHb$E|X(Kj9Y zap><_ee@uH2l-X3&0j!YCDn`h)(t$|>Zz91^I~+&p+7-U~2{}xM&ZI}5_03UzuDe^o| zRckL(6IqU}Fzm(_f7UDV7kUOlEHHnRA4k__EB77f=w#(o-gL8hGCU)Z`IGb;JP-0r zpuTR0_5^ma!J+sPgMKAtpNyS8=sbNNpWY+ySjs#ceJ{xX;YQ@drfj2b51?iif@at%0s@;e8lX7;Jt$O8jc*H>2YM z@IcCvj_q{p4kd3S&&B9&YH}naZz5ZUtz#(PKx9s#Jns^ph|HNh2b&)ok$cB{mfUUn zhj0b;whBDN`s04^bfONz@GQ2L;=^I+c^v!`pJw3SrSSK{&N%a>5q3|&ehp~(@LYp} zn)p`PY`zTbJ>*X`{>dpeo+ob<>08me+xSmF&m8!_g{H8Ycw1=2@cnK&uE*Xko`bM+ zBL46xROA-p-yeS$qH8yKqmUm19%N$@Mof<8nV}6<3g}0K8E2Ae5q#T`UANaiD#Q{6X5%j{4Q1=$>b6L4ISN5d=z~$ zvTeXa$omeSVLVr&>tvJNX?`CK-%@zu_7eADDpX?e(Wfp8nPM)Mqt zErnmO@gcrniXDZMY4?w@^ErA?P#MhDB6u>OcY@ZRco@o&dk}puk++%nVaVM{`bHQ& z0H-0pg?K6STPeed;1TfZ?`gja{T=ivTn5JB?TtSQcbPw9tSo#|8@U#Fk&D3qz9WqH zYiJqde@=b2gCQ3^tKhi|{7uRTT}dB+u9d{Q;lu0X?Z)N;;tDND|3&=c3%x(1{{r+(vhvp@{gBn;68Qci?=$!^pkIc};iMHdq3<=Y4mNgKd0&VB2>8CW z^!M=Qz?Y7E7xW*^bB4)F$93ebCEZR5!i&gOp*$_nvz@%Llz%Sin~_(zopcyRn~i6% zukakYrx1S--fGC)N<4p&V)W0-RGj?3w-Nu{4Jqf zi0*dO!PC$_LH`&p66sF7J$Dg9yUm|}E@dB{O?6*SqHj}x7yye)eMBWT5i?SX` zsh@X|4Z{K0ebaos$#^EGHF++EcLDTPrZ=?p z2(&549S_fe$lim!Gs)~r8Rt+3ozc;PczfhVheF^@@U}2rZ({pobaaNluK76teT6CI z8vy?s$h`<}Bh&LXy!w0A3Ha_qz5`D)(h38S*WW-_I2^q_$omt%x2gXy%qCKXe_P?J zhpsK~q=u#`yidZ{ll+CC!ZC(pXp_pw=R>;(9pj;|*r$#bm>;dlS7?B5qo6&6{wFC< z7`Bscg0Gu+x>K)h&4%*NCodDd2b->Wq~CxiO1iQ1;#(>Fjj8Lq(OCx@z0k8A|0Y|X z8e{c&DKcZoe+v3Z&{`88Yd&9s%m(!KhNp_zI?(cFkvG`tXquJfa(EBNd;xks#O}T5 z>}Pi5_k8^9Y`puYl(jiL9nm)j8wZoWzv=A{|7SdJk^UGwiswk|*T&9D_zyKc>Anov zN|bpT{wo};vY5|3t;{}$F^Igv@z@%U&M@>K@=i)UA4C29LVi2==cDf-8CKIqBus>jY%It*@jT=hozkG z2xqRXZldv}nKTd%6EYkI?ywkAvwD~sJaWa08-GRPg$ZRxP zFT-!qp>P^9Md-eQcn5e_;jhB6(29xIMt>3Z_YHqirY$_x$$uHX2dJk<(bWLGrw~`T z9s3i&YplG#p#N6*XIojsQ$YG?+Te5IJMnWAwmwL)w?Fv}NPmTm(~+CQ^9OukcomyF zNWaf>iP`Or50_!Pox6y?P5Hh9&#^jLN_iBT zlYRug-aOhk-iLql(9;H;*TVCi=#;4k={v0~8%)Op9L;~QlEFn>hLMs^eYXQt5Z zhyOXs){pXBY4rWkJ<;@@g5B9xA2Z>t22XSHkAQv;`W4=T)&$yUY%07!`Y-ZNH+{XJ z-#{I#!`~;s>G1r3&TH}c64IB$HJCww{=nGPEu<4S_kc=m*}@a z`x1YTCZ0(dPvCis_^mvLAYYsMszv_S;04$|8olR{?g1)%g8jST3&>x9{ddt{&HU{M z?KkvIketzaV{eMZPc~mh!>5qTa}l}~u14=k;0AbKrraNxOadDjX8SPgRx$br;?JVH z66LK6&x`1J4Zca};D3j~-(;muu~&%RE+#KK_h9=T^6w=t9X!{3X+d5m{4Pr2{R6%C zli!KFD|x=iCXxRXdJ_=ZAg8bvUzS4uiFgC_wl(^lq;G_N6#Q#>z9D@&`Dxf) z4^I~HD&Tvh6~2R~V~VXLA3-&x0AO9T1)b~ zV*g_Eu^8LcRiT6_a@NAxhL2)H;YN6>n#`ld{}=l1C;uzbbI2mHM6$Z4edbki>ZhG%-2TngyBc{T9Y`| z_(lJMa;Jtvsf)*;HAj!anbg(sl;JYy&y)TVz1Lx96+CCj2g1krydU`rC#t;Amm%Mc z^eNas3wsSM|5fwrd*q+Dvep6%@VN^0Q4c(uyjN5Fmfp{ypKAPD(ccJtvv|5M|2=#clJ_pQ?f?Vu3!YWz{Sx1PCchDWW~BJFgF0M+&PmA6L}owBD*@{x^EUjG zko%pyYCH;Ctt^VaiN7bHe_LJuhKfVGVMb*!d1xlK2wno6!5T`TH_DK1csS{`>aTJL&5pjS6Gbi*CTTa_WC08EP5Zp=U=cBgZ4V{v(R%FI7s@S zg<&A^+st>-mRT9UhTarC4`8DQcsM`6J{ugPlo_Fh1#> zjV}+Ae#pw0L0aK)Y+r-ST+;VpE1mo-(|Zy+CXheEvqo;V@;+ecDdabT|3`2rbub7$ z(@8&sKgHk^_|ePCb~Nb^;JFmtzmtC^G75h}zn8MDAwCR#g)E+7&>k@#9nt>DfaeIx z@fP_Tu@{Dmp?`$_{@7b)er`ejO8Eu1(l>4Jy#c%6$xc_dN^nRei zJ;-bzPhk}PHbd_!Y_vzNG4UV3;p86(UtjPQXs?oAXgq1_I{8Q^8uIe->!ThTa?NamULU=wy=Qyix>A4b{E1}i0w!8wKPvNh`b0&FB%qQ`N zVGBHCkvRn2KN5csY>K@$W^*o#OVBqIzZKTPa}{;bkNg{vJJiSG%YmoO0^bY8Kh4@K4zmc9n z`YU`@cmh4QLhp^;1oDTGABM3+K0?oDJhxkYDzC3GdmF+49(hA{LZy+8J+Q(v2~sW1n9&8+P2liwG=dy{`X`M06#De{gd zy^=hIH_gsi_^Kk?lf2ta{z2MsmgSF!cPh3vlRpnXuL2cX;ZGs5KaxH{bproJ>?kY) zYhtG+@fpT{uH`BJaeQhD{di>hh(LG{{_pW42c7fDA4dFEtCw@|s|h?GA(M}u)3H4Q zA1^YUONmc~XFE@8d_5I^CZOjO=xOlW3vMI*9MAFaTmve+0bQX#v{CSlL~ng;?r(M7 z9bKmwulT+u{w6-G$G>*SwuE*FybJO5e&kNzxd}aedEycv9FH&WgGa$P5q(RMZ3*9D z$e#~RMdwNIRL6%O;CTuCx4?fF>944tOQ3Z^e=ex7fcQ4#E=SMV(5`~kRT&m0kXMBL z9_alQT}$A9k-9wqd!Lb3$U(2d(WY}N`7hyHf9Si=I~UsutB`GDb@TwdQS{!7euX^p z6h4MNjAuEzFDJbc*)L6IBYJ=0QTWYh2UAvs{-(#L_&x*MZ=&ZyA8S(U3gwVb_sS5ri>rr*Q@AIIGOU*vw9r~eK9&7 zK=&7xKcDF~Me z#P+x3eF2ZcNMzsRIS9GcJoj52D6bAYAM;#BeiQW9M6MIQ9EHxM==mI+4IY8qx5zy~ z{(9uDLgr-X3Z;}|I5NM&a~t_1jD9uzUlIS_vqd&iZ>_C358?YG%+hPASFbwZO zKOEar(W&qa>6=K`MaL{`g`r7`OauJ5340g7dmQ>cGubS|a}m0qHYmf#ThVhle3!w0 z3HokA&$IX&z;g-oqf91~yx)tK9UxS#w>dCHJG3Hfix-;JL? zp#MnHk3fGNT~omupv^$f+t9;MgFJ=C=;ZL)Hz$ZCOX3C5l2~?-A1#j+2c%*_JQ-xh z@)KpjIrUoBOa8}Acts~GK)(KgJ?+*4T_2r zMTz2)c%m?xpI;ut3$qYQ#tUqy3E8>O|@ySyz=zhFnoOv!bQRSWuUWayc-fpf2UE8&HN=Zlbt6y~>D0 z5G!=fI~7fXqI{|gugc;jS$RPsC&z1u)a~8ARnW6V-JmR*3~~~sR2=FuV>yZ9*hJUR z6LYf?*|DZUSza7Te4*|W1w~Ys>IQvzK{PX&$S*C41+i%*#iiMlIGUYZ980Qw(*ME4 z{~6u&TAoauM6)KBMT@h8SaxnK@~@<%r)9@-V}-F|>WKc86)X9BsxeDdkQ1L4%l2$a zQ$c$OPDM~0E1-pq$B~kMLxV&&Nd607Dlw5ciT>uAAwLn#rm0=kW|byO5(V_eXhFL7 z#4{#?vKYPeKVkhxoux$@Qpx{R@87Zii|&Hbd_PST$D{c{Q8Zpy;yQtAm49^oKalzt zOGQzp18mUACjSQ}{vG?j=$;zIeRXd?)#b(Fxp^i3Q$77#p(5s{J>4@ACe_>O1r6)9 zq8lgkV)^-v_9Y}eWeCH`b=i7BL9}>s*gZOBc5d9Md1hxfoslR^l(^)+Bh*bWam_gS znnj9=X%~8=id4^)K3ST{bX>w9wvNaAl9HK~#c0kc)zq70u8d_PiJDk3ivWr`1ohHe z5&MSkg;1>qDeC=p-xg7>k_G#44MVqhV{(o-*-^& zpnIQ;LA`r=Vh`qjEdp+k={eu2}DpeVLcy>JahiZYF1p!^Ox<2E&-j znf$2hWN>;sRu&9oLQ?|6Iq}?5rUcEm`%G(^=OCsCTOMKj3Fk5WBezpqv5KCUtS&t?06!T2ZMcFhkJ#;FAMH8N@k39=~JU?FI##g*BC!wkm7PAXvytrgCV8#hb-9}7Xslr$p z`^0?))*kIuy6-jOMln`dw$*x4!>+{b12yg9RY}D(#fA{~3K)5~N;e-qAOj&fD8rp` z;hMc-a!YsPPCb}?lK2B(%Itl-Vy9J_RYEso5Dcec{LI*3xa(J#)_j|6;QL>uww6qp z#fj`vCckhql$W4$so0sN@%)lzjK1txPLvgp^}0msp0-rQffj~DX|kd?8h~gI_BMqF zg{lQQYe6DAo)ecHl`0k`LRpGc*=4S_wE1NlgXws2kSHq*-Gx7oT9N4#7mC?HBnsJJ z<~V2fHk)20Lq)3)^96TSV(jf`5X)p>xivJaG(V~`O9t9_Sr<;3n#*FD$#{vI+RNgT<6?AMebqWE zClj%am-Jw;td+&FtYRj#Mri8MmH`(WGo>7qaE;^+Fj_qK?SX~SqGTRT?yMm1n>Cx> zUYsm(vk!ejC3gn~dSnT^a+VAZM1|%40EWC~IJrYN)a*x{;zq%qI#sP%f$?di8}j=O zhDtq4{(!ERaiesFIv^!!fcBnF(Wj&v>K}Pn}XrUVz zYL=eUSSL$3gwUX#Lp_?qN1mEAQOHt&zt9-sImNLlrF0!=ba6I8;lL?o(MGAdLNWX2 zT-WPb_n>&TrPLq_5-NC5QkJmEgTiy3 z80&_3O5^@4CSy@6jGJm=t}K4|HN_8(b#A%MFHeuu&&bpQRxcT;-<|$SW2(H_vCL?( zC@Fi3eUia&Yk4PGR353{gVNGhhPy*2yO#Prv*RWFJ5B30wE_P^>Ugzjreo+5&csQ`zv4wv$h!exF!=QKWufw;hYrA7C4aNc}0 zYay=?_azN7^7AA0M{**M)Yr}|Qh$^?o<|yFaIwHNk{fH_cUS6p^q>6fy|Vn-e@|XR z^fih!92RRdT)Wg@P@;aBOS(;Kq~UO#v-9Z!e%(@sEQEh#;bg|RVw}^M4gEYBW&4`1 z^P+7IH4!nmTeoP@!jFZR?~EF8Dk8JB1l@j1W3*-47A>HK^8-Ced%0-f&eJf$;s$;R z+kPp|r4utwom`{zNJE^{v9YP$aQLZ66peG{0j)$twfAHfUr^ATu~qD*%0$5Koof)s zB=;%Vf3FQ8b^`gO*={u{N+eXZYzgB9r3Luc$gSD#${;<`B4}tMojr9SL!^;N>^Iy= zhq)myQOrpO8jF0RNXwvMzK&GHRGSS;3-j4CGd>$dS_KVl5p5J{9W=~~MW>b%>k;%} z2`gtN%2Z+?>uF54B4$np3&=4>4Rzr9JV`^xGfk}+&MuKoLH%yr8bmUJOv)8wmZf>z z!~xfy?F^DByCt`HQOP;lRM@WDO-Er5a64Gn15&gxi{+PUKchBg&p|(NEY@pu?7&Qt zc|&viz6Uo=lz(gL|B&nSCUfNfg7YcHa6ccs+Z8UC z*|CynR-PtxZ9`O3dx@uGLu=m~839l~7A;E~sFC0q{3^GB};Fjd7dB z(t=F&&z9|4sPndJ-6DA6-tKNi9x@<6R_` z&?FWNV7$kI>9OKOcv^D@KxPtV0xjT~zKN1dd#*eA-9Xrhg91$}YEUL2_5so2a_tSn zF}>%|;C7sOFr#FurV)02^hT;*dscT{!fGQUTywDXOS=+kEc)@l;m!d_9q|O=CNeQzJSEt;-mX>J9J2id|VIQK40@Sk;$nrgL zNZ+78Ta@Mjt8KC@QJfvgfHXN)9%1Xj#-L&YLWF7?D+1_O&WdY^c*5xN+2}H;<0m$6e+H!`S)AZg$XD*J5m7!nw%b{L}6!LId>5gGz&a zc(?`Y=Jw2PG?>of3Y~w)G}ztn{-X}OY?flNLW2tXcjiU^JC&mEtBb22U)JG@`T4T9 z4!p&*k;)`8hgHp^sq|p#Q4`E*|B6?E1m7#62atn*5qdXe5FRsVu(lv13E%5{rIyc5qCn6@o3PZ zS!cEm^}LqSBEQdauagqqnr-43i6v3ZVQ#)iuR^tIx^nYbb}XDd8Jg6B4!GI8mtiF? zWU|TgONzhx!(p9a@{N(ZS}`)}RN>yGxDm(QV|at8qd(3RL?>%M zKxxC9MR!!;%;T<|{p&Gzq2=h@2IRy!cRSbpD+lwK3j@tyZnNJk=w4EsA2eYO&EX1$ z4KVu~6>D#%VQz-plbw~wr$)25614G-|)ORzNWhDSnaKcXY=FHO&^qIFB|SEoW7_6*bc(o*n407s}noEs3uG;_l8Bf zVRBsBM8tiwW*76iLbs~S{64edeU`5tE~odY+X@EyRMMSfv%I8Re3?|74d)XV#9EEZ1703b_cOYFzi8nuxnycP?j2O}DH&MH&-jj9FG99d23|vkt__j%GX76m^Wm zc)oj)sq=&y7A_Vd_9fhir&r+}q#Lw!#Heltbf?cDBAU;;Lsq{6-aP7suWnzp%XYj; zKkIQAVWFVMbDL|MR)6v8_skXcCfXY>-%bDjEiad2uE5TUdy9Mu6N6oLsxU=HRh9APt|0`@;IUHQzzleRW@*}h*T=q zB}qCG_xP+D{*`spps%F3caN9&D;DlsxQ$Z3)CRAj{Q@2F*or`R{U$var7ekCLHB`b zM9pUKkpWbKD^+cw6wj^R#Ow;V%LwB#$n<9iOb~cw3Hd1(x99ILlQZfm1 z&u?9y9hAR}LM`t;7)&KxMX3yU?26=HpsAv=CUe411`SIRMNKjj>{)n$>J+;QO*V2v zz)>cuyb~*mubH`=7aN+fQSIh!Gt1j}6)l{vT@h0$esf^iEPwPgEewvujUbl{SaS00 zts(`H`o+0%o8zWo@0+#LE@p}3@}=1k;hSnVhk&EpVbJ;v=X=vz6gP0EF= z&nW0Tu19H%huVj`PcPV+x;J>d(aPsks(T2!uY1GfS15FQ2fSgt<*=yRMJ-;shAh?< zs2}@!nL-Vvr#omq%)J@coZ~OUX#z~6dS zMA%BYj+tJV9tU5FZ=VN*jX?8P96AaU)2CAd;ky@ll)D4- zhdTAk3L!O&>uuCQzJHUa_Y~#qq}a958`6Vr{-jexX~HSfwVe)a8qV}ns?v8pbz!zm z(X3+Lab)oZ$M)Gx!)47K@1yx;(Q-FMP%(b|RBSQB?&B59*OVH?6n#{eV+;}Z0$MLe z_n7`y!~Uxky${g08*T^2<*u)9zjE8^AMPZ=buy9>#@zUnBjNeUd6Zsd0J|OLunu7h zpT?b;tM(>FnW!%xg2q9^qIj+jk-j3ES<3m)sLIgNDDyUR-2YC`e`E8E)>ZnHGdW~( zr27x7wn%T=WUmr5;>_AGh3ZQ}g~f9VgVAFwq8f9%YE5KHyPkWi1)ksyti;~nj1`P;I~)e4Ev_Pfu)0UO~CBrHUKj3 z-n)1^8f^6U2ICs2zcy&tzzsGXe4+Agj(0Ahxo{(dL3dK+Wd##!(2(XtNrQ1`M4L^| zXg0P*v-T4jsG#lzh&EQyWL7-x%yFHn5^B50-rqiDlSlb1*C|^AE$$-w?i}8SX>W&L z+`HOWbR1;dye|8pmztP-m0(2)GZ~-GdzcQvutW*_BR07CIy^Ac@XsIjJ97C@NCrD1 zZdOuroX>l1nZnuH?KS`I9<$jO4T z_^oVsePXk@pKSaz>NWe5w7tM%afEdFaUJP6D2H4d;yrPO zU!SAN$!_iAV^$4*cqo zp=KSBD=r3nR)vSI&Gz!9Vt?6wqQR)4>kyDO7Hpz=p;jZWHt&FK8{7kNkZ2D$*pOEd{1Np`Q_p-DS`p>=GByY13 zQ;KfM{b#}z=Mk+D;YY--K&CvLNZs6^8&u8S|8fsq;md!*US(K}d5}$)bcWY5c5YDj z3uj>WB_UNRcl3VH&SuF@W*V6qulfT-W{Kbhf7xPPu|J<8f0RR0&IE#mO&Ea<@OdxD6^ky=A$;5oY#Dr2lrqd}@2iHB{ zkE;V#ybl+h`&IoLcDpc@a_1IQe5pdW2-!6gIyvgg_ZGK=aX+O#m@E)2T;eigqWP^p zeidis@lhsoTw&0iTFqua)AqU&aGQ8V!VfRiFV#pD^M)TIbiRL*VEW{xxHd`!d^p37 zi46*~ZEhETQ_E+KY>arHO6y}tOB-E^C64(3e@Y8W-Dm7NHu6Pgl_b&zhO}X~b=A8bY+0_aaAI|Fh@b5%;p;fYXzDq@Q&|-=$w(CKUyf?Qa zq@`{0Q@=2ZYdBV3Zs2)m%4h3Fi72bIHGL;cZjLwmfk>rkbh`l0mE zTlU1X9_uR$y><mWF$Yc=xua>3% zQ26iGqknJNmOb=SJz6mJBanZ;Zsv2YXLPIDqiSnEZ|O|pb`To%%Gdj`l!Y~!OmMQM z7o@i?$WaILUmq~uaj+t9&oRht3--xPmS~)(O6sJgUdg~MEn#X2zqB5~Nl_#&=Ik@0 zihD8|9eOi;G_8%UUZi?T$mtJzMr0qzH$!x1_iF+FeX*1On+y|iC;y7;S+CpC+)oNL zIEo!He5vXZ6~_0v&GQ;9PkTDIs`|@7jr4+Oq5r{;zB0i{cTCj{Zuq6)o>*8BXh|X3 z*MoZ~+^XqgIBhljl+KhI^=`ON7u~HJ1BAN9p5ACBxciGUenOMF`_?^jpwA2Uka3sw z&wqi%yj$@RRw!p~`B!kMFMajmfz4XN{d8xqP2oS~a55aoi$UsF^L>7-Ft;Qx(k-KV z{~%-7u)(8JqCuRMpQ$0+eTrv?c)$GEM{VvWE&e2?*H%2t{@T{?W`*rO9Zc-*OzekE zIPYt(Mozfd@RKLMEK8IYrB~^$H(?TXdqcOJRvi1>F7F>C|IuFhe^My_(o*}w)B>@4 z_@B%3FD{4W@;d*i8gPqGnp9|Nj{TOtf6!#xjrUvrOM9)r?v`(#U98iagps2O_a;O* zEe>$M^5b(6j{T8tqS6Q5i{d>o*GR+pve%JDa7NVka@;+4a0J`6y7eZNP{IigCP$)6 zl;rW9Nul1t$wbn#l-E!+39Dc(z` z+lcC`2Tsb2ZQfb4BuWjNTu#nZr@z&7W~>#%vy){Z&DTTvkgQvb?^NRa9Hg83Aa5+l z`Pa_+fx550r0>RCH0Hrf-jKVNv6~+E7SSCeQAjs-cM*F``Cm4MYpvZvqRRc?ac^?a z&`l=(n_Atix(yh%8b!J>Z*=3gCX?CjMGL~HKho0nKF5-KUSD+M^$9NdtCfhQ%B)kk zS1XRl8y5HdrWlB8OT%oh!WM@4Zcn9yYIuoYyxLInnJLw6Z))^2DBZnjcUqwDx-@)M zEZ-2mN9sI9?jEU>_dAhp?#odFHZ^;`;|ytBwZ}94r=1~5KjKM^>pK4Lc=SV`cp~KV zrQgd0TMr5KTc=HzG-kNOhAf9K#SuIDI=2(o&~ zfV zjB9ZYR~j)ZM_;E@RE8tD3e?Wmz4Orf9-|~#7=7F8#?>n?(H_QGE{kVt1!KpV6s43; ztKGlh#3TwkTg`d;4Kts}x*Mm89~I~gOg#?foVVTY0`!rwIOJu6j z%>oyjh2?sO?LJcRl(23qenF!tYTv^Rhgj1;R zOcCi;PBr?Usc6$U#ExkGE$p5fP~D8v#>t>=$T6sHkX`EDiR&WCU+E|+=W8**_u6sI;@Qp_JjpjeQAL(8{Wyp2U7}UMzfSx@f-3JdGGN9)O#fEin*18pn zW110IFj$qkj~q6DTH(;4pP_l8zOvy|%es%@untT8@1Yq9%*?#D;+uIk&Hms(Z_`K1 zG>pEkh%rSaXb;z!_q=8FUy88d>%PZJwj7x;2%NN{2L7w#?u=RLfI*?xw-}AO4U}en zzV6FogBYb*Xa{e} zNx|Pau329n%T^RX?*sJCjdSas&$8X`B>s*?7p&SWxE;&hT&}+}6NQzy_nECu@GoCw zu%BR|@P9CY9hm!(d&+@K=8K}4`e|dF6@i5NSR%Ujl2h@)01Rw~)k(Fe>s!_C%xC&5 z3z6>bRBPZG!0om;wN!lj=U-_0<1dEwr3x>-QD8^whKKg$!3D}Rb_Uz(Q7Akz^ zYdE{UW61a^LNl&&ci%;VeEz_NN-wFN_Gc#cP1Bm5VX#~2^vf(G4AC1gcTZu2EH`Bb zTK0MQ&P}@gu1iO51}lHvgI|qhH45eT`ZSQvg*4qY%%$(TKYOunI%qhkc}9hfkn8_r z?_HPcI*vV0eCAVZD;gx&hX6^*3ZKJ{GY*P3(I!QjfMiQE6Kq^IL72ETHXvRcexUh0 zZ!q&>{rmqjvsSIWH%Ll$&*_<%2#MIMR;{{b}Fd*8 z7RlER##HFUw$#u+BL`-g)tmq%T2P0cr7&hWFnEKt=ifcLx%tDR>r1{dDJR5e>&eY$ z-~8d`-KP(4e#QUKUwprLx2q4pX1Lj0N1^c)3oRyw4zV z?m^T9wQX}14j>*Omg3VNzI*=xfCyqwkkIH$ZF8TmCNz#FsY2M`ICQ=5(XLi^96;lY z$(ojjWf~S|c=hPsv-=NjZt#bHZf+d!@810G(Y<9gPv4JAnWvpBLoN8J?a=7S7$l?Y zi5*Gd&otoK>x@#&HBvpFL*TX<7Q%}4eq=>xYvXmn?5w{Mwo;@N89v-bfd#D%7O=@N zc}S2N*gX+uJS-U%$6CBOyrL{By~J(?!rD0;Ubp!oM7tCw{0TyYDT9RF=QVt^ z8#u6w1_dr|dQ9N7vdFAq+q!l?S@1M>g^+mddW@#|I?BmTj=>O7NVxduBxqU-9C1(b z54Zw)ba1wdFsMI@mR-4rA?9rIJyAt?xEjj<@E-LNm_j?dYG&^C( zMeHI90oFy$1|OBWN0&rBG|cluKH9;@4qnA7Cp*H@#A4wDjX}il@YdQsRg-B8+4#X>Vi{ghUrF^E?mUu56}h4CXhBd|LM8njGe@0Q^%H5d zV!}YGQS0Sz#H5DX>p~s5>ddz&4}tL)4l|by9uZv~Tm*Hx4PsTsO!BEExKhZ0K z|}vuDEOzg4N6Ws6?}Zmap~N$p0JHoG#{zTWF#<+CL65b(n68r zrnvfajrqlCOsD!wwV7IxqDK5}9(mDaQ2>{e2-*C?d`uBQv7jj_i+ya1KOQtYkcY@) zWrZpJB%EM*(Xc1H(rFMEvxcX&(p}skLZ6r@Nl2V7`)ni7!F7PbYE;Ix*63R&ve8`k z&X74xuyP_wT@e(qn~!VMsN3Lb{2n9$vA8$C9!zxgHs;Dm90?PRzC@S93cQq#lrcMI zKUBe8r=CrWipgk2moyF;F;gRM(rVSBJE4x%(uxKzjJd*9XjX3}s%2 z#23~0bKuds#=kL%5I*TsLE0gQsWGdT`CEd2d?~PQgE1}?_|*JFbUA_DA{Yq&e+W}1 zuFr(9@h1My1YRT9UkY90u>)F68wOC|MCJ}NlejZA?*el-2`sx!V~m6*gNJp!%Gd;+ z37@j`|5P(G;8f;kIs1cDjFp`E;_Bp9134+P`}5}rl>vCiFA;G#Ba3f4(?~X^5{~6g zSl2pOH!2sbXN_=P{#b=x;t7GM29-^CuBmZToY@;0HTFOm$Dv%Guddj<;M^=;^{?53 zRaOeO9vxeXubR*g0=JwWJ=oU$Yb`LV5n8~`mRA(Siu^&Liz#RR4u3}_g9M>t;NmrL?F>WWL00oa)Y)VPlM&pyp z7VC(!Z>Ps+2X7{rvEIo71ot;RzA^a@AqlB_a-ZQs=NSAATsCl*`W8MALU)5G#dBiJ zr+YtRaJVt~1A@uvYo3o!-rbn|2<_TFJs=IuQ|a|KvCbkjzafjs4<~=MDdU@qo#TTy zHzxOq`Da01{NMk_(Seudn4l(9q3C0Q3niP>!i@$z-^2sPzk4#-LbZP|G>H51jmfja z=^F((o^4MaV}XOuJAMPdx3zu5)SgafWRg2!Do-xn=ox~nsZ{%aJX3(%eJu2QlRx4b z_2whvJ0Swg1La46f^C_hqG)<_$o8?U;G|(NjR6Os4%nDr9T6`0aInArVH?$|eQ8K( zb8;a=NETnWhWb6mGO`nN9=uImfii-iT+jp*zI6#62?q!9412iD+ljz%&8w0fiv+9E zX^u+sfjL1_B_kXV3%>*JPZliPu}1IG<-f{8k!>MW$L;jw@O?_G*jsra?zYMPsD2u*q`A&x9IKLFlBNsqDcMoIJ6)Vl4W8rV5e5QuA2B4xq2 zWL!tXrdJCH65shm4i918B-`p&lHgC@XEmW+ImeuwDc?y**QxWrV`V(iI#MikHa(W#F0uNVpE1_uV9&?AZF_>KSY zuOHBtpE)2_Q;RX4RN0e1F`18i>!4jgN^Ni6M>IHtJV3*21(Scxbno|99^lK08Wp^Y zOu_yTX z4-O7^1u1(uz^It!VrhKB4zw9-^q>1S_DB$=!{KOBQhj3cZJzK5asWb?YmkAX- zAI4(#ElF)2-b&j0%phTyH{uSRrPhGl|IE}96HBF>SD_ps8amDJpfCqx>1*r9Xl`4X zF?L{da2(Lgl;4Z>A2R=HRbe+zZJXvd2|^nhYdBb$3tp4k?vHQ3Hqxl%23HRhDzmiFp`gqAmVs zIvxj;t$eD2SEyX|q7_y)TV?M>P_bTIoDoPeJ32wiVxsfUOz>RSeMml7cvqf0Nj^YM zyM&`a9>;AqkDsC5&(n8{)fnUML6CXpUZNe}UU83Pj~(tdS1Vr=cqRE=IM=oLgm1UD zo^MW`?Vg`Jm${@vqlk8pe|%+b;wYoK_)%IBYWLP192}59wV$-Qp}K%8b=f zq)`TDt)>U~u#R=z;lQ@Wn=)DTPZGIyN8V@3l7%-i5xS$#S}QS|g~nYx#Y`8i=c9br zFHYwR7d}2sgOV%(XQ|i{u-9sDk;QI zYSWIgKn3~Puy)Ox6V|BP?b@mqSQ&zAkH)9M$=_w(Af(1i49FXdm6Uw02XW? zmPwY5EyIhxMvtZlvvEB&okHm#%38Qk!R{L3^aTM@W2~p$z9l0{R!7hPNR1Qm@wGoh zONEo9Gs_F2*{ES;1Hql0nk{al9NvWMb`5TDn{Op`%;$Hqk@Y$qq}z-Lx-K_;9r-$V zSr_+sB^DMOY726nmsA#x0{JZTS6kej*J03N@Pl8p2BS?pRj1)P(n>wN1y~)GqJ#b) zI=yjc%jYJu9qP?M2XjlRx$r&&Eb$OfC8cLY>7_gl;Kv1XkKit9DI1YwZ#!OFX7h~z zfu6MXksXUfNAS_g2Mz}dv{}AkOPx80^CPGtudA$V-q&dy7i!|AU}%l*DhW#@%tA+n zCOZ&etb%B-1_yfs*&-6FC36&Pv#p6liQ|h{PL<+Zn13c$joVx#G&kU?5ICPjQqlOv z6{19_%(nhaP5J`T-P$aCS9QjX49=6;#PiDb_B=>VeYRjW?EI1rggQsOf;fIZAz-~zPzZD@boC^3yK&2EMReKl^zC3*c*A|1XsqSc6!Rwt0XEs$ zz`Khb?wcEDRjKHVAoVxAq1w~6yO)KXb1g`6n}Ie8O{Bg_yx*uoHL0n)N9Fo!YL2Gb zr9?U=r)XEGgh6%s&X*JkN1>==!`&Hh+(Gx6po~Cf$xh(IlMfjf2}iMGB^Ro2M?hh}Fn9%&?Gkam$w1qU)Ru<@<#Vo4{F zv|1%2$g8&XXWVVd&lMbSqTf4GZ1SgzDHibXPHzoxcEb?3*kAJI<>AVxBk6jH7NxNY zM}URb_LGX^F5(cr1(|lF)X(fs5IP@uZC53Fz$w$RM0IMs8g(`H7)hQFfV}KngI|6T zYN!;NHP~^d*tQ&6$F-3OZ|iJ2*udA)D>MSk6gV4lu0E53PSYd{frS z#ITxolP|VP@*^~>i=v=mWjZ=i8l=_P>MDoN0;P6qmDuvx@9`tE?%>AT_aDaCsP`>AeE4ulD`IsL%ov%U#?%EO zf4fBOtP$Ql^$=RNd;;JPULn2t4lvn#bYmIXq@VzblgWx&ullKYplw-Pt00}FLW>X1 zjgWDBe&mC**_c3SgM(uWuaeF|lXyQxiCj~}3c1%!*k0j`kldDKh4vzJD_!$0oh@4CppJO+~7npX|Ls5I!&c-NRt2!tnOdnn1; zDsoAeuVCdt*}p_S6iTjiuVP?>Ng49De(`+Xr1nK=v~(1VJH3<13CW_2pUVW?6b3d% zr);2-wSX~ERBo!1fkzO@`JJ8tU9u?9n!qln$rI`%mlRJR_5o~`SNs5;CYO32zuzOKN^A$M+Wu_eIzAi(H87bf zWR9A8ixOHafv{7xNgm!X5mbT11o##6^R;#iUYp>H^{Sq%;u_rG3v4;b0$ws@nZe8K zYnyK;Ae4w9892p?xYStcY&bUdx-M#IUr7(55!ywz7EGuX=;)@kjPn<`rGJxSFlRND zb|bHB%@kHATRcqm(t$ur`YIdBx!8+kzoIUpEJWc{H~J4$tEJ#}ZHp zVb7o{z72H9t0;()7QzEc<^h5I7dDJ&vV&u*{3`3Ja{an;S zEyUq;pL?z*U){eaA;fnK#vyMLuiC}wluSayZ4Ox{SePNVtB84ZYI*=fi#F^=;M(Yr z-jm_$a2u%AtYW*uL(;?ixP-?%9@xRv~Tfcazazpnp&yfln15Y4==vph69}n?V@i&$<)ANGH3w z*%dt=AAnkm@Yl)JfM|7$39}OT#%&uiHGrZIK~K~I$o4v2pmLE}mnH5hrfX@8a|h)R zbqKpM3y<;NS5QRyt2#2`gP6CRp=1LHHu7zO=6<+e2f$;`+cXLz_1-U-?UG6UokP=R7Z2&&m=@f$}SNBvC zo3rv_i^^#GQCXtph@-_vrZK1Uyv3P5I^z9JPI#*4YCq~us>czAu=c?rk znB@n@7FrpZSm%7oTp(tj*65C|rEQl09Y<29PeCr78+UOWwn9gUl-P$}W%bJ&{YC1xfK*}R!o zd}-%fti<9AjbaernAqQHynh$CX>*2;MpIq*FyFpJiUWfFE<7Nxk~AmNQa(n|X^KT= zmhlcaZl0xkq0W`oPPv(b^w5=MDxFF-sZnu8`*c6H(NH8@0R^;v-zTlml0eA{QvL87 z9bi#Dc{~m6R=OE&-Kc?&R`NK3tQmZ$@TYu;b)`-JQPMOW?^0j=_2Njfde^;?0VfggqW%>!?-rAayXH=*f7L6_197YfRghtf#t& z?^xN{h3?{%H&?czJc6p>;nxz6R*y-bR%GiZZ%~xUb{*<>S`&-!lMInNN5SqWD!8M{ z6S=&-v47E#<7C78}g%H~Oixk&wGr{mBMacTJ6YQ6KZ=9t@ z&<&Zc;CL@kR7r0&pAw?S0Fgk1yS_yElKG~gG$;H>ECMtzd`$)JXAm(Z4!65oaH;f- zNFn)IR)=E9@+CRU8~_ymPO@@71t*{r;0rAvQLEg{vfm?msvsva165WaKRQw|4{!)9OMPy%Dwsb= z_RG@MHAiiwf|pS1eRFOIx`;InfCPn$?m@J~%7EdVbWs9b=bu}dxl~hpE$32eQW8;9 zn;5_%pk=V?h5#GJ6Ga+8$(OfoNHxdND6suEg0k>0Cjc<9LbOT61YChU;LmvPTb%I5 z71;;0Fv7KqV`6?}58xiZ7jf(5(8(R?MYV)FG^C{o`CGeRIY*%4abb#T#8f;JX!|-| zz-sl6y2r?*BJD(@R)?0vlFYS2>o%A6UsDI%BG!%iA@ghLhOV*~PhY27$+f^lpD~lq z?F(5_i>Se36A){~VXCgWwfUDEipTb_K9Sij6_m>sOXD*mHlet zKXdajV*(b$e#na&MG;By5kd|4dG+aNu(G0ac{*wng~v~B{%@v1Vto@rM2SkTqrlG`9UJpk(5QhRI&VIvv&G$@>OnJ;niRN(dexCm3H(2JE9j9=O z$TrYmww(^}Pt?t+7iA7zX|f`M&fVj z4az^MZ}SeR6p30)S#Tt-wutiZcL}9*CuTtg*(>^#>=B9+J!QDzTjgF%gOcVDu_2ld z8J+UaCTqoLND1zJL7K4^Y7yRCALjKTtL5|G&Nvh25r+^PXz35~TjZdzA17X1A zJuZ#HxT1UBPuk>HiKiZ|OFi#hh)2b|S3`q=?Gj66TyNHmo1fzmJ~xVDa#zWJTJ5$% z$3lK)1H1oCgd#+OI{EcW6#FaW`Y>;puvV2viXY)OS>tvLlr5)iDuQjwZ z5H!sB?ngtkSx+((xF*U~OI9fi3{;29bYPGn2Uy}%|EUHYU~ z+jaR<%>^{80NctGQI|ud@KUv^t+{TQaMy5E79#U#>}orkaHtxf&%fi8UHT57zVsa{ zH@rKUT#ab*@uC0Jb_jDVK?2pTc+L^pP{9}$BMV^8Tdz?eApBdP@RplzwVOwA{Z$;j zD1W%r329-L!GsO57%<2z2#(;HU}I0D3UY^`6SACus#F{wy(=zAbdH9^Un_g&0~xdQ z8r{6@F%c=(6(`YAP3IkGKL)OANs(0lL57yT)KHeZ5CBInL*q!wm(`|&i0oSSRfIk* zdlR0eydgD^&4^l)>0-wk3{^_Ufk!u-Cx@rXk*c+Ws3YvWnZ=E}hI5-Bh6VHHnbBB# zyI7#4KP6LOJ9ghg_256X8D_5YeO`A9$rcN0CZRJa35qm>i{rr;D2n8es*AV$Q6tf# z30`0(>AE*B5%vdTkQfh}Ttf=xMeI3agoPb~3`gsLl0f`2IWh!I7TraZRI8?sp*vR&F_+qF+`eis&-3YUW>Udds zlh$)I!xtG}(Aq~;hoXRFRINm3kZ>|++fbJG$@l79fqxG*vUN%xDLp$_?OfMh_1_FC zp5XJ0l#pbWMcP3=qyfL2?uj5*X;Ee)}kO=gdx*CUDZ3t`*K3IAq3^-LDj(=eYo0k}_i)e$o`IT7+A=0+8?-}Z z8p=;~ybg}hd#2ZAy+;S+TU$VmDW}E$zEodgNnWyzC~6E*Vxn5h>Kzda&ojeH$Ft3j zxuykqqpu441fSz5pw6ANF%b;sSpQG{h&6Z9H&cj|y6E|zpN3p@YaO$ViyQK-B$WW3s%wjiv5g#a0!57a;EA$>n{c&gJ4t?A@;cXwbG+ zj{&y!@=|0OcH0o+=9XL-UgUr;pWnYsZfoCIOYH*dgkpI6Jtc4f`p57SzmTt0rl^#u z)T;e&`4a3B(krHjfFi}QMMA8H5u&@2f1P@7^uQ5FAB^^6QbAOAhN1`Xz{%8AeVjm{ zE&W+>PHO^1ZBsK^C|Ix-85C3N->@67#o15n9!LMUhr;?39HgxZ$B9SO&V{J9%1rhOdP= z^@MBbPWm#p)<^`sjECj5p6ZgE$wTqm8b)ZVbzmw=0^eSR2}Ilio-(Rr1HXPm6XHQ4 zmOg>wP_=LrmET+UlLaQuQC6oYM1LMX(v}ww>U>eTsdunfEE~T(R<`YC8)foa63cU` zA~&mdw>di+6&z`=LTKSfg!Z%_D6e6q9PK`o`OciG8rOZpOtk|0mg>Z{90mPvIS1o- z9452T3#Q-mAES5UEo}{hWb6+%syi(U#9V1IeciZ19T}>&zBn1O#UhY|HXp;$zFg?w zUyOQJweQ2A;`1~gDBOqCXjixl9bj6lRSpDJqlik}+PEc5+SOd-=SHtfLh3(B($+N+ zDq7s8cSj#558;aG3mT|iEHm+~1YX;iX`kMQgj$?)#fU7l-%ZaSZtn=Ez0=uUD7FUj zd00XxR~egQ##Zca|C{)u?^sa40bInC^@++N5M=&&qrxyyqndI{``u!qolT?&IHf=xl$zhU1r zsg{ki#6=*0;T0Iy*k}yWM`<=1dw`I*KME@DEsn(oC`FmfNK5qSNXXSWFGjrf~5G5eOvrBPrioFJW| zox_tItE=qvG`OSNzxS*G2go9>g|&5Cb|(j`D1|$_2{Y;~AgiQOW|uB}yfH>P zvn!RZf*qZ`Cl`gX9&*ph&`M9{5~ltc9ouD282%S@j8cdobXH9KW(BHCx%S>31_DK@ zjFRvJ_YKdZs}pz$iv!lsYnEPCW6-phtL4#yI+KCzJOmGHt{Gt>4M$4Ht zt_I!S`zzW7&S#;M+0Ec1psL>wks;PjgrQS99izvz#lt-w&kirfjmRfFv`gx?-_q8R z2dYfp>t(G`AS8)bF4%v&$Cid-q>u+cODc~t*e&_{2$t*gM~QC2yD`yKc3d+#_r9+@JeyAM-M!Biarv_!*sD`6$YjMLag0l!zu#1?J6VSD6i4Y09I^$fogDd} zNk+0fL7`kE6^62Nq7uE$&5#u*<`W>xU^Tg-7V!juK8D>;27>rEE?s{pax5V~R2wD1 zuc$n)+Ix8M;lulhV(KW>Pc+TP^NI4hH<7BKslvNAApG>D?+dv`b7LjUocTwmBQw~0 zn@lLAZk2=lVjXJF*RYW^G1T1^$O=8G2G26JJa8jKfh=%d4 z!;D*`J0}8*prBbPUo;POZHNK`%g`L%N)oSkhur6UR!`!|4yJGG5dh1SxK+}mFcG0D z)F;SNk7OH$mQAm!z`BD+-+e#1i?`a@$>b4P*}1%6@|=@{AI1|5mn3PrAw9YEiC?We z`u_0>lxFe}0^%RQ%<#i{c3dagn*b6$s$Obc4T#M;u=2?Bmk)9NWP+L4GhVd`$LLmK zl(53}gTS2Cpz@9;O{7<5PxA{yT@u@yA#m03?Z2cZd=#hLo)Cfd28BeLPLw;D6CUoM zf)&t%GTF=_$-%>=PFUGn^5PE@m<`j|IgEEisJ09=$@{bvs?K#``?sUciXa0{UL*yw zWbjoX*vsEEae)(^=~0K72JK^FBF_M|k5>%)hR6ko)QbdIgFM0h(!4v8VtxQ(wZr`b zf}~owml#3zZ783OwHYj7QI;_J@HPB4dQA_vViC-oMYmfxp37=f}3AHcPbTWOEf!a^x`W#YBET>E2s^q zt?`(!(PtHDQoEmbL=Yk>OqLQUZ*L#fh|d(5T(#q&s~-hTY1xin;$U`5d2`;Pa);UT z_G)z;(~<-5@2 zs`3DMFV>&7bzP6`Vy9$9i}u!EbW6GJR^tU{=Vbfv4*&kggc>|LBSza~lEkFsFfz%r ziiMDv(o1r?li4B5U8ozab(^d~B=>`ZY2j}0zK@g%|WIAvW9Q0d<)~q;KBhkp3tsIXD!)&p`iS4Mb$t@ zBPFg-mIF1d5_QuKkQ=B@ubpnxm^FrBPu2kY&q5a3IkmQMpiS+|?c?fKO11nGJ_Au? zDecVxG64*zFo71VuCU#(Sv=Wg_+F*{PBEKl5jIa7g|ZEw2&_Ob?m3X~*j9 zH^DPNZgr(Ygp@a7ADe_?#I#<6jrhN0EHSb1Z#nCcF4nZf-VEYi*;l0CJxAf0f6&AZ zPyNqiO=+O=%IND^B-A`Ex;as<&4WXN3%`{{Lv2ghAhwpIzt%H(cf zrBIi(I+l9DBhw@4)bu&<5})hgh`1*fLkmyU+8^E3Q!j7+RcC|h>l%*>X=*m&nE4@el}N%cZxre< z1`BApK^zl()1&rF8xFL(wB_Wkx|W?|!pXrf0LXO&&;Nmb#Cf#{A7ihfg1$`~WeE}A ztieUU0Ho>X?Gz(mEjY1!p zWHrms8O>cfQ^6`rF>tUZtdY(oZ>WNH@$HeWMD9LDK6co#EPzViR{VlbPvo}>1fyup z=-y4ZW8Kz5=d#~0kKt3jjIYvcH+1dIN)e*Q;oKnbTirXBJ)qAp;uSEjC!7shAITDl-_S#`Oic>POQ=fbxKP`B?7_o5E`->lWAa!bgH~ObOa)_)58?= zq?f7|&1hCX7Ef@*VyI~& zZ19+9%biF|Vbj}(^`gETS4LX%JK8ArD+s2-yco`8hr(QsVvsf_e~v615l$#TNq!3L z1=aUuOdqn2ly(xH87I}~)4#_Zx@i3a>^iKD0Op!ib=B!LfiA+@wdj<`q1TNo-$7yT z;Gi`5uwHDz_k*%+b8JfC?A7Tk2wrN#;4B`KjH)eXRHk2e`3rA+=X@g$76l4v(+;;+ z9^YSi46Y%{fM`9=+cuoB7#DMV+P1Q9tHR3Ty(u!u`(Q%SXGMqNt)k-Qa?l65PFEWk zKa&$qyBbYznBo`KGR{0My7%gZD*YdN}an7X++k z+=N&wi3M;6(l9IRi;aUE8%`o;5)JfdS#0d!C}CqCjml=WC&#-1u=r_2oHBu=5Sn6- zq+;d7i9%NrMl!uJ%trRb#hjd8BlZ5l{yrgqEELEfX`)9KP& z=P=;pqnGJ_wa!fYV1D^GyrSvuE3IGPAW?3PTcl#!em~_VY3*Gsu~dD?acL+LaZwgj zrzkS<)dr}bwtMcXOyFL)IcF!9NljmSnoS5kwiS#npk#5>d`wUB4m8l-O%z+W$VX1C zLtZIX&v4XWeZozpzc<`5FQYCp(xCZc(_rh4ppyHCW4E!*x485 zZeh;S18$4~l6t1u5;B)th3_#4Pl~cXnI%<(X(3S6W6b72cjWv7;%sUtU_wAlSaY_* z;-%_A{7dYflR@=em6P$>u~>_WM1@1ZY2k?DvF#9Di_x@axSs3gXeu?u!R!d54G6cb zH;9bJx#_|#$Qlf%YGDMzECa>)I*4#|J4Yj8lJE8{lWlC-Q?@=8 z>Z%5rGXk1`vRy|Z*Veej*>^0U*V;(R6n-sskh*kzMXIy}QrpLZE?LL%{JMC^2AR09 zfZ$^{%1>8KE7h&@BJb&>H$YivLU_t;ycYT3Fmq#Rv1p`qev5nEco3VV+`(~rI3OIv zUCkn?6RDApf)xQ|VHSE4NU#1~{8vzlZ(lkU9@U z_0QbIS^|;t;Tk;qivQvj6JbA{o=2!+vPnLYa)q?Jg|aCY665edvF8?@!h!WoJ__Nh zz5(;=W|0IiSR&MjQ&MX*0%I+{RH<3T2w?Pf3_c!2@OUqr94AbofXSQUVU7DoXx4J6 z$V>RFgKNbWGfFFKj(;Zm_~Nvb3sY$MpWMwAj*|{e1KW@G;dR_*ZlI3z95iv&_(6w~ zH{cw609^$4gp=CblF3?~NZ9QKCkTxr_K`HnO2{fs5ozr`%CaLfh&Qe%=Ym)ZX?3Oj zL1kvt37jMz4?_~?Ju)+JmobO`V*l{Hg@|8paznAKYuV6q4tk3jrhW9zQWl4P$N?|u zj{tqKyjmhk$PkV9nj6AD(nC`D$Q|Nt#_OAhB}OazVCJ{5#R|w?JQa($>r8I5oSRfs z4Qnvv9vM!J_3ua9+!NAc#Fa z?OP9PUwDs(M30`$fj0ywDIZ$jG!n`N1q_0?c;XiBx@`wrb_q;SRGxgs62Pl$&2~Y zngW|RG35ZNEG5{D)E4yOd--a@!)yBI-<; zC?s>>>6Te%uuWOgVl)C>-!V-m=_>42$7?A3_6k=Q^pHx~=i@!1u&N*-ok1eLU}=te zqt#L!&c4+g@`3qSTMD9+Kyr$Kv?|UwCNUnbCn+-}1%%C&zF~9B;#|yOjdZ_l@V9+P z-bOIZS?GH^!LGE)_ww2ySJ9F_wfXEh+KU@R@uZ9W4bTP>p z#u%2#n5K}1ROmo-DU{K`Sr=&Q$>1D`!uSN0HMTbTFRGS&wV_a&xAEq7R$kDjO{S-) zJWZoC`o;+X!?pKr0qxV~q7%qJJn|lx#v?UQD4i)va~2OKQpzo-KZ28@=Zg_$Kl2Q(NN4mXIMyG3tD}L5^MBOfodcbWXrEOp7VJ zzXooWOh~K1dmuMfHtt6g5L!ay1cUO$#)N;v=X8z9H4^r?1uc&ZA!@@sY)Gx{CrEp+ zBOhHL*ikjArMC}vCf*oMsZOx0m??lrYs>+`;U#YB;k(HAFmTZe{k4;%54k4@;eiuN zA^~lyue%Q@J+L(+RN~2`7#@m26PeS+yrXcE=TGk5K>d1lRBps~zu8>AmR>Z|Nv&AP z7{GsBo70e0&efS>vYue@FkFQ)1A>5>5w(vBS5T=`*nY|4c|0OERufzJO)&t7P9Egi zGr6`cDCM^X^TMo5U;}>4i*l>OIK4^rvIkD~Zs5T-3Y|=E5>N^4a3H+`=eE&5-*P9knf5 zrNSJaP)#D+gq@NV(cf^MscI)z+xs2tF|FecOyM6mh(OS59cnFHuN0{(b^?LgSObuT zdu)ZIVh|uq!sBY78!UNbBDcXi;tPkNYa#+lc&5Ofe4*3RC7RS;1T@3a!l47CA^4|LU1J33^5gwS== zNpp&-*b&{2BE74?!n_aLX=|!=DbdL+oiu!b%>-J3U2e1Rpdi*4X$#OCqAS)Y5-!Q| zK z;jX9%o5p7S>Xq^>Nib%#C`;6MgiCa{N^FNBDcD5=WvSjokK{a#AUN+l4ivo72FVXh ztt#t;kV6dl_~e*?R(h3^Dp8F2p{#&~7fTd}k3ZV4ZC#(xj#kqgzz6TkhZ$}L`U)JZ zJYFcWUPEo$p|0MG2|2s)&{iJH0C=8%T4viQoliwOF7=4Wjp^9;YT#aAOuvKYyGcsW znD7lfm8y66Cd*xHx+GuW*tkr04%Z+LtokN5 zRa`|CX%p&q37zI~sxXuiIxdjfzIMFm+e(HrGA4j_OS5e_BP=LKp6&F#2%HwzMWx8k z%AF(T)BB*ZG*4rIIpjVZK_b)-q-@r>F{l{7efg7le)!LuEb zdD4!sxsWdEKu!v3L^(u*F6Fy!wl`YH=qjh=xH<4WLreMw9L=JI;|2)+W*=9H85zMx zo6dzd#3Gk2)SmE&T2cWxJ50KzgD#IJxcX^|(krl?k-<`WC{NZM7cgYupoS!c~0 zNab~KCY6Lv{}rILJ&)$$Hnf_hgmAE$mKcSwQ~Bh2GEQ?z;IBOy&qPZ=%)@F2tHy}Z z(TSHFZJ1zh1y53O6^}Df?hUZKHezS`9<4==e>Auhv{8KOsuJ)w^NRR@Zuza68*#nN zDemi-rvW-9S5N zxm*Sz6uCROv&tN?f76IN0OzQJBvTrHr4th+jcLBk}p3d$taya=1WP#~7# z48drmrkLt2%mvK072J_cn5dIcsnmi{nsH$YnT*6;kVi~?JWlh8E4%0>DMRDkR2M-D zIna>yApeX!XsfJlUut-uy+Cj$5^U}foCf}p9A7Vri>>F%Q59W}>skYp6>oM31MAD# z3EsrA80Bl7NFOL>9U;2WU@P~?PE@Y87ce))0#r5(ROlXMV) zN-?nTz^9NH{rI<>%{WY%`U!R;UpXux$cB?_njsc%DCz|Xanu!cg>9F1Fdfp%k;2s$2r2kS5xj>F?_M3?&f=2Bcz?hqq^gf7AsrJ@Cu_m_Pd7qX z6>^lJI+zDZbs$szS864ZOneR5E;#l6TVNHIykQDUrlcswfl@88x1qaMzevHXqCe2% z4k!FIq+Tn#apfMJBY|*Tli3P~hj3)Ya(LVvwa^9BY&9}crh(O*+Q4HHPS1@3Yo;Mz zWoIWycY<#oI7sk3-)dbdf}?+-gdeSzm^?A)_+qN<_%zj{QL30Wju|Xo+&ZsgyT@Q5 z@@TuXTAJ&t7DpA0>E^H71j|;FFbpiAE>+>E4?V%r+2^&qomULKFr zMo$}dC{HWjK$Xi16U0~+a{7#>BPn7paJ4r9#BeOyM&@-f8cG#+?&9rBFm1d3d$P7A z9<3l5=z;mrszvj`h7JG)smy`pNzA7_%`>n)!1jZ3tvrU~uR!QXsRP@lU^v?}#Wpuy z7TDtg-(86qfGBVmL{eK-w2SXBYPHzOy6r@pS-DNgRVzqk4_F4Go+@}{SXD`EJ&;yN3U`lbwRZz_#6@WP3in88}a#ptiuW-BzKqe z0>LU+pfukze-%g8K0ta1BhYX@Bcq9#(Xbrr?gn=%S>zmV*<=(2SXv}A$wi&(Qv&hSI4L*qud*Nuhks}LE0*?I!{rI8B}jNk@? zo>nSO5fg~pRYAj&edZqFpUi42ot6*CRMB^0z8my6kghF&4a3kI=zK|Y`TfvhtK&Qt ze^BJ~;L~sHm(a1IyUhGg(%d*8IvqM)vv?&Qv%DRSqbRmdFdNStv-sh?2(q4EYh{|( z4eYc`Y-oFYiyDp&EJ8N(e&0FhW2xA6med6q59HtBU%AGTrlI+IDqizwW3WpPfYdL`ul)40I&NI# zXLq`>@?;x{zHFmBVNBlz0qGY(d;7zWTw+nvC&EW!Kgykp?MtskaI|3A(ztH(1~ETT z5J>zx*%DLj0{@(>fp)HEK>~BUjfVl{SAew7^XhE$iCAKFY670wczcFD$Pq)bu%+V_ zd3Z-XB|3;QFdNCau10pQC^EOMQ)K8;BPKoXb0ku~c0WfGvubvq{31~y2R}~>^-_{S zN`FAk_73J&R?dp|I8s1L|${*v8~RcsGb^&r_}hozuzs z`tiwn=sQSDw611Yqf&-Mhaa$Qu~K1{q6iFcUhIi39DLY?l$$!r)zizXZDA-HU5R;& zW(dKPuARk6uZQy72rgU9V-o&C9oHk&N@4>jbuz{94I;g^8L@WP?6!IB&vNj%_Fvp- zC`ZaRI5^p8;u>4I)c|5N6z7{=|9|(Sv|5d0m|S}XS;HOXn#$6{D~|a`CjY#|D^9-L zWj=R5hi?C)clMvK2%A<_=b`^)>+l~v`;Tnxmb^j!KRGjP`GaC*8zf5b1B3~l1SeTY z8F3_wXo*%F2^0z}B01raAu!W32XCqqha$BOY_$vm#Jf}t1$id|IaR~PMgc>~42Et2 zWi{#!bQD-2eoV{4KL@q_qX&Rse$=Z^K+yh2G#`gF|5GNwr8Ne)SO|@lBI-)U&t)2Y>~e&p%mC|_x?sn?iE_bo9meJKa(|ilb_4uG^Wb*1xh=BEHw{j2qE&{birrk@hR{@(#CkmL|EY(C2IqKM<`>i9NNP zfW)BP(fHK*XojuHw(_bX&Tw3>pX4Pq7F(ciX-82#Ro^r`j4|vs^{SbI^%Z=6jyAMf zqbHdF4GWSnsR*Map16E_R07miP8k_7BN+Q&M)HY0ovz}(PxeV+h0O$SKlLc5nzhVM zi%5m`10n6FQV~48efxJSPk;B7{wEEK(ueSC^89ZcU2!VG+E4fXK6&vs9L)3VS#m)! zLbEu|&;G8#-_9qFAgT-yy!4cT&=T zmD{0#baFtFl0SaMc}aIJtR5%(O8QQ$!|%R|V10KzU$HHrrunCL?e@6Ar4I}a&5fc*f`qQ zm|fdg8E4CBk11%@+jz8~l41a^nOpMjlI$X}*0@0<6@ z{zT8bP14-=?hH4&t?=>4>ppa9jk82lQ{gRxDrwm`A>r^PEk4x{Rt3}wuTi^?- z$=*KM4IyP16n$lw>{L{KF+F`jV1bU4xB^tm`K3(NfFqA*L>}>HM&R}2-k&$?r&Q9y z#seV+)|863ZrVVZZJRE>V5WrL~FAhK?l+ zm1ysG;T~C>w~JytT0t8P$L}1ApPD$0F${b`$MhUP))?{`h`!Cbt0jK{*$xE?L+GEo zcdhWqw9QVfM&uh_fV*~e65AiKYyM*4ZP@nlG@Jj{ZVD9YBGuR_ZDv11zo~+zA8Evb zAtP1j{@avA>(UysoVs1EczkqQ;yrvVyvSZF9VH%nu)O#$%Zqv}5UBc+pSQQzGv^o|I!c6~C>5X3Y9w)I1K}6*&P4wUOd{r?NvZU@EkZ?7Dc=zCpYm+yw+{KUZJqzh93F3}Un4@Va#vAaB z_x-@A+TSWgyp~xp=R`Bavs{tNq%TzkH*lfF2xXVzGbYARVD%RA@;oMg+ z3oN`p0$30SWXV$qp?&171MX+|^Fgu@j)9GBN+AK40-{hXK!d69jTGR@M3bH!@DBJV zPS2!UXH9<4B@#~K)m6!+S}?=w3%K-cY#jgEF0EVV}P#j-Y4sa!1_u{03bRx}XURx}XTRx}XSR+N}# zj$F>ao+Fj>ujk0*{OdUqS+57YkG{)^ZkEscuX0)#=IqB|zJ46$>c?T8eq27s{?*+4 z`d4#v>tD^yD;UB;dSg3Y?cv};ore6tC8-Q^2%y==VxGw$5YDOcnLx3a=?j8-q#son zTHwjz`cEL$d^g45af?Pf*l^{TJ0PgwMGeT%4|7&R`-mS{?2o~tPn_wN(IF*e8i4qQ z#bj{imH~CYXZv&mcrJ6tIQ#gjO0_FRpdv7lTEZb(JBzigljpMP}B zFHp=-1J~`k}y1Sd%bYCmTs>Yp)?f8DA&c@^?U4aGK5!y{=F{KSkmkmSX|7(K2;S3$pRR@ zufx=alxt867Zdxv;+*m7L}SaD9D;pL>(RZ z6SAJLsB$r{q??-|bWx=KaI1lWwwLk9B=dFib*uuh{4Hf?t7au27guyGK?<6eAstcm zSpP4`;}n4db`?gLLVJ|_%mqh70a66o(U_hOquWZS6XO935H9Vd@`Zv+#B>ndoOsVD zN>t`&haKGHrD8R8A%XUl)@*%x^u<_?O`J2ri(2%k)(&*j4Ru3tLrK(&;I}Vz2?h*| z`aPBUQ}@@oRXFP2pCSrDervh*cwSgd1A_>}q3UAwf!mDYi;Ia3o`l5fFYl7kLE>?SH++Rg7?F4i+j`gJ|srlFA(;h79KEVoE$vw#+Cb1D=q~a|N6U)uUGZM6i{3= zs%mhZIm{A^)P)6;e&V|7rQ^5lg%gzCY`@(1BNmg859}xVbxk64(C(MXzoh>&sk^S+ zw;QU0Hk=G=J&tay%o>hmUnBW3#}E(|#>Eu}U|56#;658NOV1vbbmxOhKOPMMG z?xoC4Dk@UQNlHdtI`RYVDY4wlkqsjS19t15o;=Iw^ktG2wPr&?5D(PoP-n94FhF|J z<6lp9%*eDb=A$XH;Cpn^vae3Q#ZPIy6V0qtmKZJ(eRunenid_Ak`;`r86_H2)PO)L z683dW1_MoAfR0%b?98M~s5F*hRU{A1i;b2j!_|J`=xb~{Oo6Phf-e(z=!!O824c;u z8#RcOExdJ$%hx2ugEG|5J0b46 zyctX#Hrct#5LOgUKrH7#ZU{g*Y-qZ#P1dx0(|6m>cX*p?Ub*pTxM)X8NM9?Xj^;;U zb6NBI%eY;|{YQ+sP9+}+S1PLx+L*6aLv6Le^|wR5v(O_L1E5II=fkXI=$czmRY;-1 z;z9Y61nBOeaD?3$!>!Czs7PkkRjIkNGba5kqU7@lH`Id$+$8Kq*0G=8=! z@8_kFh7y}JRP1|Nu^KekXNUQfLs0!-a8@0v=@3{bfXyNtX?OSqC;(N{J)j*OApZ#a zqM63~p!&rV+dE5IdR_f=A0{EHjEe2m>@P>far@I^`S+*M25!!g?gvVE zoL!?LB3TN|tJKd?%}j3mjA#L1hopMa)Pmm2;xzdSL`Siea&&i}AFKT1XH+h0)n~Qb zDlfL&D?MUl24g5%#49if6_Aw&|9kAdl~BZ-7@!8Lu|}PiF;6OH(OqpLmH`O@@Hdmk zFg7z?p)9`+0U+@&BSVSBBdJNG?kq0=Rx6aq#ysJ~A-lGPY(BS27R#Ba_9NCDkU;%M zUlG-#XIn=(iBw6waDO!n%o(#|T2hBXhhfhG8C=6h9%J>{HF&ej+w(ZIJh4`h`-Lq{SZV) zCbdJEZ$cix&ByCevo2;`d|(T-rE@1a)ARrxJPldo8h5sQL%vQIs3{+7tge2Ax{M$E z$(-1IkUqp#FaaFX7L$&Tm2ysPw>EA4_WXyPJ1czI!J7$kWH)J(}Fzn%sTzgp#cXcUHbb8uLFstD8vr@dQQFVM!oe zRtE9L?LunPhXc=GDYCw*8qMg?{C%(!u@81vnPX2FEh7>^?Yc)uB3->^GJ5B{E#v}~ z!(}7~@wAH$D&SV>0^&2<2)z#&K`N$^&2cxc-_JzZYv3#2?O3v9d3FexoSl=%fnOJ= z{E2I(_&Z9s%X4_3DkVPgTi@YG$p5fDk*`O;e{j%_elZM2U?7L7@NFs*;z6?QG8G2x ziX1+;rWiNaL{}oiAjCU2O#&}kqRL_9#L=tIYrMKKkM1YA{KA!WS|(k{#C<9#QTxh={&(nPUa=o-V1z zUgj}lm1g=BF4TX}l@k4lR)TdYYN`q!KES)(&%3RK;#{C*`vzd&8ra)bxtYMSZqEW| zQJCmfzH4dSMnSV(d1G(q*dr#;zBRuf15(imz>2V2xgYnM^Pq)F457i7C8?ORUN$bH9ow?RsO^rV47DV!I3F9lzu0k}V^?PO|Vsk)OBk+=#Ug`}*>}Ts8tKf*6 z3r}?my;#`%{8%zs_d6KwEC5+cLX`rs>f|LIuwPk6E|4)d$)Muy@!3R3urvxZDJ`FJ zA96NMV#G3*?CAQ|xNf3xPZ=(d4Re$}vt{v1(RAMV@#)5`;;9+1yzC<8=-*dKp?$#L zJWD7@v_;2>g-r%*rOOL#wERxEUpOY1$F~;O?F!;l#|j0)vXj(&P?;Dyn-i_+v6WyP zJ@V&pA9|tTnrIF2NV?xpTOs!&oNu)Cdx9It3RIKS2HQuIO@b(3rx&Q`%ClFmKw9|+ z4oo0yB|&NTB@!B8l2P>;%7>6G^$XaCaD{C=ZdD3yBc~_l-L$Epxu`e_yVnMLrem48 zD7*k#;gl_b_Y?V6(p2(td3H-$2aF}HDvXXP1JB2kXPbY~IfC5**jmyTL?U5W2-A>M zs-beSivOhHwiqg%|*IML|=XR7>6yCq-kTB?1V24tG~UIpk$Q zaEY@NTi|O8;VnePU!iIJC^e;#IK$%!Y-o}zJtaa15p)ks6_WuaHZecj46&BbEPk@D zE`37C9el2^3R*E+NXdT0>S&>i!Q>_isgU|h%w>=@ixkNS>H0CJ_HK=s+e<|!d-GQRW9oFTGKbuL`Cbn z6h$Y(2$iGAp+z8{bC|s$VUT1|Q9dd;mfV}*oJefC?ph5_oCgcBa+xkovf~VOc*BQU za9sSI+dP;aq9D`SCw0>A*m7s)xgq2TN|{Z*-P(G-$xS12l+^*DC?!ZZj>zJ3Z+JP` zbhI<;MN%PTqXQHaYFU=dp{JXiV*|QDBstE|Y_U`}CP_7bhdUo9*$Syzk9De~J49zy zsqHOZyS|Wu{Ie5>Tg8boKk{S49TdOFgi~g2LWOQTKSn@T1}%+zx-O2WS2#R7-na2A zqyRxQhjw0n*_?@mi)?WWw`ie=KyF|rNP!e8sH`KaNZn{8^@KAAXy#ZkVj500Ql3M@ zb&zU7Vj$9Euv#w@>wcl(OHpizv)D=j1n_bwl_>{^RAgLIgv1DjVj$tvG53Y5d4Z}$ z@?4==+_Z@xJh!7ObY223=Ymxf(;Ic65*9ps4WtHc7ok{;)N9}_bKG)zP2o( zX;Np;$F_2S=E5o~ZNM&0c88F2SC~3tx=!Q~z567?wqM7;j-vz{^o0ye#e8 zWIY}3l^1yY%3elGiZrN)gG1mYHMYhlndzkCKxzffly(n%Jg5MpA!D7EA<|^YHz*ak zw&X7u23N~}vnd&yI!h6e#jxbD`^OuF4}_`Ya=I9$nJ8`JA7xC{rR}jLWh4{_S`dA9 z0e-T$C4>PgqH?MhuN8**%e9!uHGVX?oYR_z!cAl*?Sv~IibwZ!syPfIMUco7*jA)` z>59z`kDpaBRk3V`2NN1kFi%^?j(yAQS#((3x&Gd}+aq}!X`;eIe9e{5(6uvAL+taN zQHgjPp=&iIRr|n;t7N-k;`L!vQgVv7qB6yzR53(&$RpwQ;K8#n>NK4jiaea5T}KXg zR?7@U?H+Dn-O5jsH*v#0Yg`&aPN|=OipRsML6P-gAq{^D#PbFRcc6`Cj%j#c9x}!= z8~}>2uXaN&Bo?eODE+sSHgr#obS{z!kp{74)KX)LmCPWEB+ z@V@i7be8Y+`hBiQ{y<=Td#Sam)rl+?X52z46)g4zJ|$>W1B7Oitpn#m)r9xp;{e#^ zyP=sU?>xSP6*Nl}KFv`Zt{HaEyiMJ1b;4#w2k?Os#a^65)HcJ+l4J(X@`ZWF9VLfI zzJ%MOw#D*kl$U(MIytlEQMx&8w-Bqw;F{^vnw9EkaI5V3Msr$9_kW@z3c=4iv3xzZ z7G^ZEWO#B0<~dK`)76dY8in!&%2MA&)?{fR2JlipqamJsm}a_p*%?6_&@O-TJhhtY zg-qpv*%{4%+>_;|qa!?gKtG{{3B2>o$y-GQ7Ba;2;+qO)7s_rBl=$T21JlS>(q9SI zPg`vlT7Usp|29eKMf8+sw(>g2`$@Zoow@#ce`^zpY*=tR!}9R)T213t)j)N+eY6lB1RvQ(ai!1?l5=3bIVDr=z%*=l%v*fg-s z-0N_|T=Kqw=I}|W3>Qn5b+FiG%t{JLj+4VYG#a8k-JqgAdkr#2n?L~;W6%=7kD2L0 zKwDH!Hr}|6oWr9Gcxy$n2wg>)5naapCo*BRMn|s}Tk~r+Bu;TMYcDfAErr@aqANit zbi8KOLs8gmS}1&*rx;i<{gcOCbsGH=*$NXN=h|oeC=<4$)I#5ftYTvt;xi&jctjy- zpss)+OWprXbjA|yH_`9Z_m=J2^t~PbUw1PtPIhiuBxNnw* zN0~C7lVyzmVL^3v^OP@^#D#)p2>sG0OlNZZB&;hTCOqPet%W`_n{6y?CeC6wbenjc zH!>D8R}nLivJcME3i2#M=veyBz|+6Nnct6w$;@e?Fa7NMUWV6A5~GN9vxB04;biz6 zVg8(Sosg96qwXnq%~_O4mqj{KtQAP+uuu&12Hej+9E0PmgOp)$>oTio6=)j0LVPAa zxzR1~sMqikY93dhh>O|l_SLa=dWZHPhuOkgeITZbHI&n(U5nV37y^#GqV-~Xfd6>g zS~CzyigHsbuDA?h8xBaEF9w`K3pvb2j;-|ME4=j)NERQt3M$(<*?XUP@UJ|OJFOnR zBq=^Eoco^v5*rs5gXk znuq_!611lRS*Vr>vyCkBgLd-%&`A|)VxgjnT}2gkg2#;m3hKsHz*Zs(lFL>*g;wZ|e&~ZLAw%H_$9_BV|KeDh8|lrYbj0v3yj}Ee_@$QNbqi5e1)$m4 zlG_(Z6!sVIzAQr26I6qH)JXhW?>TJkCowde4)ExT>=NA9 z(KuG-oiT=jB+xXg^HAbY_yLyC!OF2GtF9xTQZtS|McOziXw$D^d$JKOz~Ue`W{0}N zPJckf;4#tR(BBQ|r3EwFSW&+C%ex#4s`Col_Dj4(%}|a6D&!8R>jT! zpVe5lscjtEZ*pBfpSu>Myh$|!g|P!Uj-B!uiJq!SfF(Z$`EjPJycOpb9m*SE2aE;f z5V4Zn0jz5+WS&CPn5?`)A@z)-UabKtf`=sc;b+#^=vbH)n9PuxF z?XPTy^G78_XaCl&b}1^ksTd~PCOXz&{}2ie`V>M%u@osqv=&?}d4X25TDNnM5s7wG zH~}1l_sYt1@@hx{nofh>9_)%pCGE{QRzQ%0(pKo27aVQhTPSyt(pT^!ZkK95bjD8y zc*jn|$I#`7tYuiDmQ1v+ys2AuQMST1q!OajF=7tI2dCSSXJsFDd3o zw3rcoWttn8@>}PkMLiVH8YsbaFMW@;^{;V(294rertxL0)liVUHs_FQf;EoNYzEt7 zVN&SEeh+3?Y|R1f5(^P`6M6H*`r-R;@AC+B52i^JMf~q+waZ)ttP;B6odg;ovBj-C zVp5wP&|^8z7pB0}9?pEKZ;Cs=6JxLXG$fVdGSzLUhD27`a>Jh`RasYpxcxKx03rP9 zUaTdxj2rh0lv>HxqXtG`nxr+D(@!_ubYf+oG>-Yl8?0*4a(bBNr<8%Pn?pF4MxpY9 z@i74=s{lBNt&Wbpt2XL-*N01ULwBadKGfw1@wV%g9t05j)ZIE(+EvkL!8v1o%8p?B zjA_LMftZ6@=QoU_oZ`SDF(ly;@q&inCG|d9D`(Y=*MUZ7y0^uVG4n4%%j6*sU4>=< z)92T=30vs|nxg@oN(WwD@%GplJ9#sGk9|iSXyTj|;<(sEyJc&QfyFrPGNQc!{;O$1FTWxZ>KQuph+v}CeN zz&Rj6f}G2(6RlA#=}L?eX`v#CS};z^qN@m@3(b%?_#5Hhpm{6B7>#Q0jOAtV3yfI$ zo0r2hUWTVQWQF7E(})KyG22`vdLMJOZiBMYLk(+Qonv_)U%$6~B#~Yjq;1pVlZ$<_(44RUd?cxg&g?2#AYnB? zItKf;_Jqn{c@4`>E>ovyocXy*i$%zfQ?&5cf!4HZq55&5hHs2^to#nUfKvrG%Xce5 zIWU;X?;MbuJ?1WAmW$m4bNyyAca=R}ejsy+>gg!qPsW=l9}0s-^Pet3TUnfZTCcK6 zg(U{GAQn3Jw_Yw3^tG{kE8qfyR^Iywv1uRda|NAFoG%3JU%;G9bA1^_5=znfp^&Sd z?2j6Wzm_#pHGXt{&yUrJG+-aAv1E+Z{P0SQZ{{JZHCkRNM%0#Jd8N!vRxJ%z-L>x& zt=%3nfNglTZK6GXnz`|z6`#ltkx75isCNn9_Nxd^N0riDv7|M5GjXYX#_n(uIe8$C zQ$tK=*shaatrC_I-wYnq?bW~kJ8EOlV1+2wT zbJZy7Yp|s_1bBa9^dm5=F5>Kj$vYEUr<;X*+sDjZ-V9COJkiNqj#A;d!~Y_tf0lgzM%^pp{QiVyD!! zk)^`sNtQSVnl`xkXCyJL)Xj@<2DrQyT8y)UclsRp3i|#E6M{^tB(Qg~JKl7ZDR3xT zpQ~cT%Od&a(lyYBSh0v`(yRS-E4zGQhz6`{72+<+mNNZA~cyM=PH@I`x|)5 zF>=Gl8<>{6#%yJvtLAEwZY0+V?MwJ7M|O!(8J4ksQxyH0Omc^X=l1uFl|NlfH9fJs4FWj!EU`(%*hd`zv`mP)N6%b zd7TT+bh$#7J{oV8r-`-YEro&&4|Sh8))(+UJ;Qn949!K{t)l(tn3p)m94-(iG#mK? z{xMlg7QwQuWi?QfJVy~f6EzF|+eg}I@sLD4PY+*-j+_x>rY~sP+Pp+xr(ja^eY!yQ zj5U;fNLrz~kfB@&B(zA>{cjh#F?4u8tdco4PqCbR_fK&5@H8Vf+;|ihFRl*2#aR=t zpxwMgH!tLc@rN5n+N7uLJ*~bpKfdCTH58cERSN6A2Br9N>2H&z$nU&@h9-p&v*;)x z?KJ*Zt_-}*YXqp13kVI$ zm;Y(wD{kr_`yU*}>Q}3)tGJ4PRzKSMPHJmi^<^nmeWJs0f2oGn^vD_l2I9J7@iYES zmSR+o40SZ2)r~LFVjS;{#@)5Ur|I3$8o4t;fb4K=Qg9?^Fk(gllwE6Cv!CB&r1QX{ zD{LVn!2GTOmQ#B#8yG_kg}F&^fCVDVll|`@mrqy0$s?$>cjAB8;QzEYxoZo?LV@52 zaqwHvEs>~txYz}tnj+WcbyvD@_BeAof@Fm&Q2iCW(Cdl$WYi24?B{U(m+47f3CxWq zU#Lk+Ug{bCwE{i^pnIKx;ZV#M+^M%H(;bSk@R?vxF9G;V-_5_Q%ZnoY09{l;&W_Z0 zJG6Hs#|{O^s74f_kdfryu0PWo7A^lY=h4FDp%~P{Ml!0XJ$b799`J3#4={?>iO0^H zR%&@<;?TObg0MvNB~2w+g^`=Do{C+FWf_oDGzo>-u)mtT)#?+8*^WcYe&dAM6{V_p ztj(Ds>kWnFQ_)^P0;KzCpEnyzE727KqlX%>Qe&91$B5fnj+UmCj@M^lZO{xgJv;GN z5c}ipQ(UxCaRgyKC*P5B6@Xf%QrTRuL0PJlYj=-ucxk=+v)WicZC>oGx2>imHZ^_} zOr(`4m~Ppoe5^vH(`JKO8UZvc*%%w-!zWQG-83fm(kTb0^Vi1Vw^ujLkGQxz&1Z5` zP@rQNv9|YdQxS@RXlN(&Cq!G8feepUiADOxPrnzxA(2Qrt-Z<92b*^n+t847rl}y1 zTB4qm6!++fl))&5G&Dd+L(?C=`s(RJk!^ce=psRRX~IL;a4LDOt?_5p&xq{B_FH-q zv!LPv@#ea;^`*5(ZEG(>vmJf4XBoDIsz@vIYI|n~X5maJl5)zbrd%qpW|2mYukja~ zJb{OpBoA)JJIftj0|y6hPPkDtV@t14pm3&bkKW_a!vr_*D)_yA03l++9$%I9wJWeS z7Mv|+{>2pKjBo^ePy7qwk1RMY8+?}IQBFH{_hS&pYLxF1W5#jTbGb9;YpH*#YJYZB z6&CJcG0_Ut6r5!F4wOYtwnuc4kS-I%M8Kp>k(SCeBUh%vx#12W9l;|d{uB)qa^MPj z#TRkzLxQgIn2Em@?;auQ-ODVQtZg-wgb+&mAcU;0pffb|^*BkA77*2By5VSqRkTwr zn7am(Arh2E+4>9z&Fg5jJ~M%JR}zgeLY-J>uh{cFu;bp(0z`QJ@-`H|Wj)v+9r5ns zlxWqyxo+WD6@gAzAx6gO4^l^mX05YbRaF*~7|izN;MM91k`;jf!9-d*qNZg?^`*@) zA24^TY5UrCkyb0*Th)dPRXU)viycreH;HHh;wV!B(MwX1;Hd5(bQV@Od&j?=2Sel! zP6*`}$-JvhStU6aHi#mofo(K}PAL;OC*)0=$3whCFpuWaviUh})TVvv%U1{7s<`!p ziQztqnIKV9e&(L?cW+!>QUt>BJQ3D0={bUd^P_kL#J+G%{mb0*kM$gekW<_(2-$`Z zaYbf++0ek`w_mf_x;lO~xp(i+AAjFoYcGw7wb0gFsU$5mA4(1qT)(oQ7E5pbmc5O^ z>kHlEVt*5XGIFP`KhFw4NYoTKg|FszOjjSKQXZO;gCD+HtepD!&#RoO`f+7B03$PF z8q^AQPnMMit6aRa5OoxOGcPXWlw^a?3qr7k@%f`Eyn-}9h03NFrX1sp^6gMnYv3pt zdAX#6%*y6fDMivdF&@|tixVrG1jaQc7?L82Kf~Tqj9>qL=GvR7Revs~F^cvNJ{+CM z8gA!Nd0U;Gqvwj3rS$N}_23MzqmrmR49dSy>?MD0g_1vr7wv#)fT@zlCXn$21{x{* zg_yS^PhllE+gREB;nB(_Jh4rWILukKX7$-B*oL%p_1o-EE9hN|TH&*A{t#Rex2qu& zgE3%@gjU*pw3T4Zj1y;_>@d|ulJLpZZDud^U0xaege#-ReTRa=g;BFK7Qvpj7RSYm zLn{Hy^mis_1IfMuYVNvBAiW0{R;(+{Ely{!-$zwX&Y%jN%$O1_esmo^No==Pc3IVY^?`7(ej4T%C0bi^r4Pjl zv$EoXIi+=z$maH26wq8(xoO79|4z2VD6s-6qNdytSt&m;u;CRCuTVv*^|;MDSXhQ6 zCInVAzLmiVypdkKek&22>2^v7z9GT!g+EI(GR^;2luQ3r;TBV(?of`sovi;ap)CkE zjFG#>=I+_SscaU9#H%YVa#Mc#`e*XI{Pg@3D0UZ26K@qD;1`xZ8F)U8K4L%SJ>;_5 z;)`;IbEB|LC~R2!?2e^GDYtu-HP_$zWAwUxD1VG~-$5teQH!W7Fvt_fTRD*S(o67@ zVlCKMs7h|dl&k47oUVutCW`OTooJ`h%IHukeX6px9dU)T^Xu?#A!o<&cT#WHsD_l< z9T$i5^V2&wZ@zwy@*mwe@UgL@Boe15=No7hZ+>~}_U)UuzPwpq%{E@2A06g=0m;b& z0usn*-IWZu(2Jrl&;8sLTvISE}&4s6zj$u+zN{_3 z;iF~metfW5p05?)AE^y(tDOOD(r6D^h;HEF@@({lb)a31$qY7{06k7zu*Jbpq7aws z*}c2p-FpCghsVcMXow?E<~K(w;iQ!-gTWQ5J3I|e7m%V@QL@tF+9X9kLV|Vh$+xzR zri;2d$xs(pfY^jEGgu7Wq1p;oSI5a4rb(sprYn&mY7cfWSOu6GL6%35C?dXvKM5CY zh9LRRw>s)*^s_?rJ`0`dFw+HMB`|AK?kK45Zj?a+$?HICP2-@3;~A_Y9D-OsuL&9? zkfjP0&zmy|V&H|a3npoj^NpGj^KInM;Loi3Xamq|r04yMz=xi!%F;MAY9=k482K_< z&nU^`l$TK(jK6Ow%bW$bAI)GO^{bH3;;I)?=C(Y~EC2{iZ57pq>-bn7(NH=({fc&c zZIPhZ%omOgAU}3g_t87prilis)3Q7H21TiJM?*{XZERgG6F}{j=T^#Pyh*M!Krj6u z_+-wbcGOEY$F}RlWD}CGKlTx7GN-IsMFn~OR++oxtL3fe1F-EY-8@pTs(fwvzvWkz zV9DM{pu!ok1GZ`({nD;3XZ>gO(sjZN(^Z?Dm=cu>?=bnW?qnZ1uK&*7yLMSwWqH2) zb$p7QoPz|FL=a$FT}f7EA4D`At*JvW&9p{0BY*%Yxt$15u|}SO7X-Y4Dc-M`cqual zQZ41CjFBIuo4q4=m0#if{{K1GdY-)_0`Zbn-KS5DEQ$R*>sgn%=9>38SIaZxg6za@ zY1`1ap#qBD)8rTVKxvG4LL>ER*7UE7UHeXp; zn83<1Z%w3`dt7&t8TU;W&|=Ehhdyu444FU-b?h0-QXfTm8aO58iV1cp_Xs*NMhVox zU#j^!^yKzpqK~c3&$@So8G7)c?I6nK80y2%hbf|Z3afpqb(--9r;!gAm`T2wH<^6C z(0tmjhNpx=G{7#bNV>uZu+2jT9q{`6PK=z{OFGI1l}On|gd$K?(RQn;X}MqLRI0?)$>YDTt-K06~aUYB+Ak0qmSh^M%nXYn$?^t(> z47;E|evJm>kY_R?PKy89a++`;fxEupSN5QgY_?&~cbB>;Q*u09r*s)H2V%+T=ZEox zCc-pz4w*?ZT?BlUq$G)5Ag?AZ$e9iV|^63wN3$Q-K$?--~~U$-9@L9fR>H9 zVEE#x)!YC`R4O`1=|RE}G0_opFg(uqhyo53sU#3gMV+~28}?2r8ey4B$}PK3)h3qx zEO1QoZo1BF-6^i@<}LwHR(M!J)LnKLI7EKzvetwHUkiB)6+LkJ2iT^z*yB)2tt`Zy z*!+-{h<%k4Cul3y$B1)5Qq$APtz1F^m;M$||H(D4`w~osVwa1LIv*P~3SBPuVpTly zM6^91YM@%#-B?*8`_xa^A@=P5W1E{b@C2tQk6a2yHYbsz@jVaYs?|T_X}l(04B^BN zy<2~yBi7ml31rP4h>$3HyVzXv*trB^>!g9i=;BJJA#OfW?BeR{APfqHBwAvZjIJEU zxY_N8+u$LXS4yT6_$?0nx4Yl(2d1%q(~bS%K+UBJ*Kw8>!kYQySuEODyXzuR$Y~;> zBp*ryO{H`oT^tn`_Y5xl|IK%^GGR>H3&9w1KK}zs;tht9r(CVe1DXG1 zVv;vaJ~WDMKCnj#JZgl?NN${#rZY3SZHkhPk(z{zYjS08qQwK)@TpKzhN^v!f?dXE_mf{Yl$8Q0eVmdR?n&LDLyrWk_>?RIj8uQ z980bo17fLJ@$xR^T$rI8)G|blb78b=!OYE&e>v^M0pS2t0r(#o8!48Pp%oW6){ zDhA%Fud)gU)biHLEjfH+*qO5KARyYy7hR)`hZxoxl-ARMY zKyiT&sd{R6VvSP|S9Djcaa{O{?&>uJB+25jqI=^SSUbw}Pu6Um+Pt3!H?2`v-PFjf z;Cf!KJg$D7$MW;l`cvV$m}JOK@qNSsc=iXwl53e%UR}N(^VJEr+01`r%-Hqa`mh^3 z!!EQ&xRRkxPza*U9PU_5N89nl`Disx!z3&`<#QkL7+iEEu`+_c!RL4b^^lbU;}9ez zf-8mB@iKmMSyOpH08FtIfy_a9R6_4z`OFj+5HdhSXI*p3^7aTXYS;OFXM+py+};G~ ziKf<8T1W}dA#UTEZJC~nCFsm%x%yVc`|t3z=6fFzk;G--hHE+~@aMHlMC|e1AR2aJ zej|AXF-b-WNN6Yoeaq<6YI^{;u1cj*@wRYZ8!+rN9bVJ|(<0mz*f7)Epav?S>}p?N z;{#aWx<4kCm460;02h6O-8(;un85Z|+325Lgz>e%||>4rNd$<)-U>9*DD zEt3KW&*BC#Oko`Ed@>v;n~%{Ui|cokCG6a9ilwBsQYRimt-9Pw5+O|^5UJgB(2S%I z(N-w|5~|WC9;rC)WuZ4Z``T(-ouh;H_`yTW1yFl2**eEe5mX6)`4M&4W94emv@_M! zF@t^(Tbe{8+6+8eU^el7rHrDMrgj?oq7paW(w#w05>hgj?7hLU13u6xJ(l@ezBe%h zGC6SEDOnVj=@LMt4OdHm41lbVgnWTKL68+eia1*H5vJLlaGz#Pg>dBixH3d+ApQRF zTrgH$l6|l&)doqhH`OinQuc}$Ic+sB7ZV2W+_763MH;r?p4!w+8JxIZxl#{%A!}VV z-plUXTxMD#(psZNfuH=$9CKwx6@Jr~NlR?W)&!Jt0Jjp}Di^$ggAk;c5a;7h)2_&( zDLq8YNw^8xjTA#UfB9*QU*JvIFap>?guUF+MoxH~g2lH3p<0n=2`J=ip;Q}^nSL{> z^kw4Moz1D3Ycpt6Gui@LnkoyT)V>)}o*`kmZ_7} zM8~9dAJ~exk1Q<0g>J)oc}Z*)8Tq`Zfu<@9tGcje%V=wixlMLX&O6yBsx-+Y3RzOm zie1ousSbKG{>S`r2W3E6tzT$q5^?fp>(8p5n5eW~gxHxM*jo^PuZ$s}JoOrhj%tYT z%f6JT|J4eUwx~N9Y>qRnFo9I3Lv1t;0tf}xno$BOG>D+dZvFlGpNUK4+as*K`*z(f zrMOz5^WLnD%$_+JKkAj^cc<>5lsLtfv4!7fkqb;hOH)V!{=^Y3SwxAdrqf*U1$U+M99q$sTfwm}phvH>g!&-&ggWKr$r20?o z+_`_tmK|P$ww0{9dnm1ssJCnXZr{t1TZq)C0JXf%i+raCf>RyVUw7IjirvaK zK|WC=w>k|gb15VOeT{G;a07Cq|8lN5o3cPd1j?;7*LX!KEX9OQa#Z~}vDB!HL{76e zVb{tRD%cTCz!X)n0#Nxt6SLgnwMV{bBao=4lpGY>@T=Qmg|VJ_pD8dy*{l$#5~H&~ z`ox85pjmDnSdKv6hxn1q~D)0>(SQA2Fp^gp}YifMy8BfP9)HOMNW6i0gy13}zV z?;T?_XeM{CmG&vU_$P}j|LPL5sUOu}cRCgc*a{Ak`*odceXFWO^+!0999fX zoE_aGu$N_)@k;fffYKuUz6Oym`1@YgOM?JMN*EVQO{6$%d$9UJ^YLy|=OvX@k1rGsv z-D~~{Mj?OjE|MJlk6~T1wj-))_kO^?2ZK=jx10Zj8)o1~2|Q9`K&auWKr+~{RLXY0 zrD?9O{dLVube_*(AIZ4fJkCJAZ*{(3#L%2s9^)`ckB3XRNudt|;3NcG4D?j-Vhf2qY{U_lIoP~{>_689V(kcd$`OcB{`Mx}aI`CcTVfOpYGmIa_WUWG~{GO}e!goU;NBl0da zV~Tv5;8>lK(wD;($!O7`LjI1i1nY;e+6x7;R!-h>nZ30eLmEw*r+zkU3>FfHK~$ky zVLIKlNDo*dW6u$nG`!-~O*5k;9oknt57DQ63PYVq)bdsvP#zM#L#S3MZ7!vYGXpV- zlBA-X)+ESOG0zH*Mir+OorH*q4hDVM26+%q2_K225kjB`x=w*+v&xTJR6C%p^DUy> zdB?{RMp&pFhEsS|blBNY$+gTams4yr`WE6C76P3IjXqR0I{Hh9Z6Rp}UEY$6XF8xM zmXZ?Rca%5;W$K*QmR=tjZFK}Q1IurDE<>Avb`bGk4NDcCc5rvWKHZ$@Mmk-&bqkiZ z;9k$&l8wB|bm}u;#9ozu!Jmjy_Y72l5T?mS2H_~ak01*WEE8S$mKxT+nm%N_WLEBB z-UvzO>S4}-)Q$?b`Ogrc4kMvm^P{_Vtt3r-gMWyEwriznF1oAT&#^Sg4#p7;Ish_6 zs_pp5eX2!{qA21Jj%IDYWeQPhqyuER(8P%vvHF(zW9A%cV+x)}qdlzb>E0Jm@u4Z? zu{xn^JQcJw12iXJ^cksUnH{SaH7J=v+#Fg-;oYT0z>lwjJGZBjQ}#T%qyM~r7rwZ% z&!Mp;k#L%QB<*l-M$8yVU63wgsEC3OseNPHoMYX@|7D&V0`a!})65qc%aw)^{xtiz z^f4t6fgNdiv`Y--QtBiw%P@bY#HtjBm8a(Ko~bIne%qYyM{28dGrlSJxrSYN4!J{a45TE~i@PoaTeO72nhR zOxE2z5G3k*{Hx-J`J3bAx*p27jfZw%{f zpoAh97lR|dmyVxKpwsinq+3V%^5z%C%u&}LIq+zfH80GZxBwB4@$Sud@i>>Fj3F1GB19rPdt0lO}nedZzQy0fMwQVUBdi3bT2!ckvQ$hgv40fzP9T(x7^mfS-z%Q z$RJP#^?@$fq!jir$lxm9(;eX|tWw3W>3u6qPI7`TU+5lyYK_8$p}ca->T-MSqSh%9 zTjWTfjgvVI;SjPCI`B(QBn{*$@8X@Kld0oIwW<+VE|^G-I`vtM!TiJ?ffbj$nf=B!{xNcJEm!Mqs{}1) zrK#m>g*I76lH&rLLg2=`E(w@X5$u)R8yHH3+x8BXe}SwrjR;oJ;DoH`A3S-?xMDRw zf$1*mS%N-@2lDPd0H4zW4oJP#f8C(w8)zGfz~jtEBr1$-DvMBNTNHR!43H-=ABMm| z)l13p(g`R$L4=DV=4P-NGf4S}yPi!^W>B5WL-q?rFdhcKd^xkM-<^i^RQPVfGJHv ziQxb#K|k3){Kl< z)=12>o531S8pLln@Rr2{}JzeXR!K9h%DB_He9h%FV5eN3hcH zXM!s-y+aLY&P-)MaK%9VlsX6nuEvFjxZ6UsH}J{hL$5hjTnRz~@HE=)gBrQqroQ1} zB&y%8l*&29oIz*G4HWfjJ)5{^dga|wjAHohMwPmV4;<#mIO{Clv`}^Ewacibb9EH{ zyj(mJHWtn3Acuk;NcELnneDA_H)M=g>rq;;k~c=n!D3PIxv-ATwKHqF_r?|LIo-1C z!s<#1gdkj51g|Xtf}l|8>3xx;Vg`m2LtMn-PEj5p8ah_&gr`-yH{D?4T22F#9EmGH zz*3%#t9nrO)#k=xH8MM8n>;dHjlr=|`YwW*Zy0J|GD!X5eFrKfm=0zPtAX88C&rtp ztHrTnC9>8ceUe3fG&1ZrcW}nkRz!`(qr;eCgj=R=5p*;R)?(irME-}ArZjywjv9cK zpCkaWAhXe&1sx(AZ6$pM0DPLsP=z!-q@&Q9jeE?Yi%ca4QC(_Jz% zNkJv_6}0dr-5ERL;XzIHl8B55L$p*n44_O6SxgpzTw$&Vl7_-+mtSk0U6$5f!Hj=! z#DG4L9SCx%{%z!N@{S{MtNcgzs3(3ul2sh_or9)28^N2<5fH^?J1`Rz>S(=Y=<@Xe z9&->_zidHE3&&$u)Pa;C1>tb|_oGqhQ=33HtD1(dw;yUJ{YkC-&SoJYaCXArP!U}L zs%U-OcakE7cwwTtM+7XR&CnEB6SLFj_inhke2BEcC8Hix-Uzvq**H#d+ zk{FG!9|L)h1<@Hfcl323R?$-47vP%uOcebOvIcNkgXQRr@uT>2BsaN&0aVNOq9E1c zfa)jB_PdyZYZ|0gBf7h1F^JLT1&nFPHv~3G^ zmVE@MWg#7MdWj3~JTQXF3COVnL3;u|;mzZcR&FRKNV~|hDO@6iV};i=oRZ&e zoXS4AnikT=$*!oDaVJ7CV}5C|X=+nZA7_5PYW@jeSqm)2z)@^op27t&K^h#SBrnQo zsySJAN%lG)h~IUzx^_qJ%{vn&ZCm!$#V)XY-*)5>L1TG4G0A+twU{vwcZJqz*reSC zmQ+Ym`n}l^VQX_0kLhGnRp8d*1#i_smPCdfuH+lA(IKZe>@qgo~zEYQJ!Ze|hH zujZo#v_KBsf)Injlnc7`+-Ham;!iCZNNg}nMt1rAC2)v_SxH_QHd`xbn(A+Ut9VSLZ#+@@U3z2CuxyO( zCTGD!;OD@?m5h-ZT#6FH@N)%36FmG;9I_++AoU8sBUFjud~_Ll+3ilbWr_NNr6JLx zmPzbeCJ84it*;=UtG3CKQ>Vnx_s~g*VtAv0R$kpn(XR&LvEUY@NbV^~UDpk7I z!s&3;9)$S>V|I6@tqtUsRvtqT%#OWyVqIdyJ{!rCieX~9qb@%q(@(f#EJ5g;7gB3K zrtDsr_h;K{Bag=m;BK?v8J)m-v=8Frvb@5YHx#_sl~o6q|;=%hhRu z`l%R=?y?Oz`-RN0%j~=fMTwe0l27>(zNgQZ-L0^b*lb3kzDu>U@daT=*k_c*7`Rfo zHSgq#7{&Q0@jmS4>Gf%NdR5JJK(V7mU1Qr#Ja|at<|aR6|9Rqr%81FU_>oKP;4sqa z1-qe$HWYH5TWwx@bIO7jS^uC05M3_3lEIeMFBpg>+~J-u>nCMIVcDwd>8r$wNDsWO z_K7OHilQ>Q>c=an43%4|)feJY=fXR@&)k*>v1^I{GbxU>+X*cO7h4d$4p_zi?)Mrx z=z4h3vAfFP%-jM5#Xr@Az_=KX&b%fFp-I9S!fb9YUwQIrmw^E((WtOFrBvY&B$=5j z4ZxF%(2aY}e65mUk6>l*DwZB)D8ghCZ!0J@C9ayQbCTWm+EZe0$@34v z=)m79K6RAgP>*T#i4fLB+JLcfqk(ZD zqaWnbZT5w3T%y{PN{6E5FGFpTF&6q80`$-fzDw`L4=As|cj~*&vl1N&(d!zA#b#;d zhfpCKbG@Ktih9jDbc=`-7&l~!ERsdz?nK5A>>Q&=(aML6u=ZL6)^0C_*bAvtM1u}3 zr!OMTc!0|w>|`8O6;n`5Pjc!;<{%DVVIyF^HpM)LdJhqsR$LRZHpUD@&ebl5(Amo@_N(Gn}Hl5a5))52R@n<4XSMk#F-E_(Ig8@x@C40APb`m+GPh#23Ly- zfW^9lUYb_GDP@k8tuz3xzntEKtnPGTER4$>XWXv8OA7wBvh*r9z!_W?ZY|p@pRT;W z4F?A)y#JvUXONvP0ZQ+c@0HadixTPrBQ+D9uvl4nrBh+IP}o%Qsi-|ZZw{0j#oE5# zDBr4&w6xBfYIH(rj3(efTTVoDk+ETj3b2(Qk^S+?T=v>g{o~!Wf#M-J8kZsI5A2Xe znMku`68DnC_-3pIInh1sYBkO^6*~5*%uTj3s4Y~p?Pxvlfx4$s4{fgmpZyKnnAc{f zxL)=ZD!*7CA_(Swly+AZcN`HOX0#@b0ur=ti2-s_GHk=%8`6^1BS8?}Q0PKQOeJ<# zxUzWJ%9~Ut51>!71&Rh67&hR7n5t#R&B_I5zndbFx^N*A#ZFjHi#4k_=v5I81_m|T zg~)v;{x1m?a_BEi;L=S;MSs+=fw(tmMJ;WKAA~B$HN$OnEygP})e-fg98Tf`@Y*Y2 zk4ub-DhANd8_~C7c2IJrohXPDY=T-E#%yKIK%$CdG{2?&z}IS9OW!AF2vs92 zqe3*wBcM;3)NMx3>PE9oZnmj3)BRr=6{g*mm1Jfc@`>~bXggrs@*tv)_2M!P`Q@q0 zG*;Q{53RUy%)yL8WZfo_waU6M0+tnauHfNfGz*K?X|zfs)ipXaRdB{cXwLRv<)q4B zirsU4pkfP?c1%T80^7ng;r75SxSWMkbh9jZ`QeB3vIoHpMB-X6ig20q%*>bqvX zl96OH66p)^K6HX1_0G7qp#3z~lg0(QR$7iNbH?+0-hd7x;>y2~3GsT3fNlGq0taky z59hL`Z((B@d`CXu>1Av(cv`4UtY>_r`=cNID9T&4LZr;3rA*f2989L#tgdYeOf!o( zy-g|N_WD6|0|J9ptd;<4qv*Kj@xL~tUD$9zFn31<<>58Mf2SrN3>bTBXcQ{y5VBFP zTU5)39>g3bG72TGZp+4mP*FAFCFy|6vZN`H(I)Z&Cs!ht%7MWGiw(NS9->Zco_+Gd zf~*LWf<;a84C1C;My0gaooXd?lVowx+sc#LT_~(i%!GTY7MhJlRM8c6Fy57$Ku;{c z`58vLEx2Gq?rtQ3Bzhw>MiNlCVI;Ly@~TNvT$=Y$1bd8D+a|FvIQ4a-#(3ZWY3|Bz zaPr(V(@-yfUB=34<_yke&xLV(I~UeDvoLP_$u$l2mC3gL;QRMBe`YvdVI=`6G2S0w zdf&Fo9owxMENvvYYDpR0JoWHCMQThKUsq9x?dOW}fZ9z&bKSZ_u02S(lB<#Tlg@#q zZ+!LG#Q05a0J0(23E5Zq_hy_7sjJxEP*6<}uz|ZAf!Ir-lP^vTAv&zc39yzKEB7uh z87uTM1S3LONzUnxI`T4Pk;d>p(|u&k1Tfcs9$hoB97)0`>X;wC(zJH%*vh@irPDy@ z2GPND(MjKkMIcke+B6~=f<4sTW!`q-a@jK5^MkEUn=%MtZ&S67V$LllpCPymwwqC24wN6o?4Nc2s5wnB z`jnFuTjel1j$MUta%=~trB!6c`D2@>!rIE&trN1GCV>qOo9ypo7hXR9el&O}++Vp~dRxNToAo_JyTpIEY6~QZ_Anjb))qKdFwDuWpk;YQT|U zDjuLiIjx~-zP&}an-uEx?=n*O(W8p21yvMXz$ax8q|Ge;G?b^Yu^Pgw>(IjOB!DJW zPmD_SWm!K~*oTq-T;npL*@9>(i{`gbeAzS}fWnBD?~&}xM%VpS4*TlJy} z+6|jT;5KNx+$Ry|V*VFwmF%PO+EiU;9LGWyult4#caW)1Mu=16z;)u&Wp`MkNY4CF zIV8{{aUfY;A6Cdp356;eh}fG$E5^IcMKI(O!0c6dYSNJo`ZC>Gh;yQ}SZ+#oD%M1WU8%5*(y!nU6cm$wsOSY1nA$#dt{MIZCHoKh)dDa2(-VteK| z&W;|+P&-SOq&Bkd{APc1r&tL+!xlx3tZ4XFCwS)yBx6P*1Fw7+f~Gz|%Of`?I%oZg z%x_uswXbFI?2|GpWh8`NI-J`(8SWS=96T@uJvHdt!-iQ|>5C*lLmArr2Re#iUB}1| z7kVG~BdpbGWSa!aA*KKGp3NC*^_^Hm&ZHIWpWY1?R4AplvcTjA87xngjb4aB?%Q== zK<7LhiZZvI&$uJMa0#gaa5AO2oiPUYl}utP+2n^AT18jZsG^rH8xF{DsaaYrDj55# z!1pjIDM`9%l8B6VN=XkJGM-vvHIA{!L#A9da=Pzv4Aoy38E$^S!nM-t8|-3AO>lh=8j@%8bJgqfo)-#H#b_{cdkY7(lSU>9bIB zHEOgJ*@E{nlxTsBx`-fBX@+H0%VtV|^1Sl17FV++MqPnlKo=8_BIWq)9%bSQ_qOn! z(Y$W{o#z%QG|f)!P+ErNQAj@Z6iAVn+BS(_vY~6jN69}@jZ4anXmj{QqBCVbJUnUr zz=gejCP7il7K^xZ)x=L$=)XVJe}6I|#JY18a+G?h5}WZ{YiNMEqLke-L@Y6E9h?U| z(sjhfl@l*k$r07@kSr=rW0MNTS=kJW!5n>=2?&}p1yIzhkYmaXMkc?$mgRV|yF|0@ zZul3QR>HqR^}Y&+-z@>;odr7x!KYn6%<)n|QOAFP<>)9p zENeOc{)>FYk@}${v}qbw^6yr3|D_(}`osiq6Xx09S@!2cl5RIW`nz!F$Pz!zmS-0j zipf(^grz{XPpNJ29N-?0!zE4v<-c_A_U(^IJ}XqO*R=s#kM05z${uVzx?N%tLJx^` zure?~^_j|#jeGVE{Jz;v;PUpi$-TG6H_9vHQ{+a%Q|?S_!Mq0^O2ti9IL~LJgdH$- z$0Hy;>yAIzyFxk95oDVccNH9q@=!rj&OPC{T;aLGG=S?Dw(JWtRZvsgZvorBDMUAy zTNQpkNZ|p;B@G^gg)zrllOX~t@=niCB{Vf%a)N^}PA?cAf}|&@(-8HOU;t{{vK+=W z=Re4K8bUzf(E@mtlF9YFb`d1$E2@l-wl+=n2E~7-q?Jx}(1U)8E(scO=3o&vi|wjbv9SIVGWtVMN2{75 zZZ;2;5cJ9>kV~|fSOC*&tPVw95Y{=bBq`%}gxwFbn7}%U*qJUxVTVu#bk;(Irqm+w zw;}C?8V!hZAIhREACg&%(6=^|ENHZ9{2vH*_{(Q2Xa4dj`>IeO!v~^|a3V^_nJWS7 z4c$;b+Q#Pd?&!q$Pj1?^tC6@uNU~31;Bf?8t)S51)K>Sidcvj7Tnp%?@t@>;xbn0# z`1{hp+||Up3b?CbikSKc!n_8cfD*FQs&IwewrW-3h4$MTON0^7mWaQVU<$R=v&QZq zwgSNUpQ&q0wbUi$w%SF8+&4}nj#r4(>yz_Hc#axUuBYcvbo1a+`cWaD6m)F8EoiP( zm7I7ChWwLzBO9l&!6M=@=g^JFaDyMG#sy%{lB#N7a}95uI5 zqET>V?u(Q$$T1vXEKLmfvm@<>Y1M0dM4P6fep9ueOL@r1(uhA)AR%cBHo@3q?`qYa zDS|ONkPA#^>?#u_YtKe3GlUF1HH(RB*_iw)or4JTuPWJKi!nDTd7DOBso2WAAz>oL z=Zud;6OchjWFlnc)&fZ$TgM~~K->kT4+0c*`GT`THvx@J77{bYtfG0#z`PKU6z#<6 z!7T3U=E}O7Ny8r|akr$wUx_MeVO zZ1#muz!{npBl)h>CxUrP(Z`nnG0{e75)HsgEa^aJjS<3SURHAANH5R@EG?SpiYeBr zjh=#p6C53dEiZE}A_#SXtnichNO6X6$<&5`C0a2$MYfj$ zzC5J=5W8G#ML(Z1S8ewil-9Vpv3t@c}e>pK}t+>`f7Dq|ri? zoCG~6-NvFFxa~wx?OzE=*t~PkX375;{vRyV9J1W5c53{w2hRZK`a~toSM!yoG`NUR z;+MH~&LLVakUK%*vQVSS?V=1$c9wh-)Wn- zU44{F1xMCu<<#yy`?o(J? zI2l?t%CeMnD>9`eC%VOPxM5uBD-l2D~%6F zg`+&YE2<`f;5+PtHCjPK%qYXY=YqbvTWlUN9CSc<-t!6;@Ra`#Dkqd58zT6U@KGw`zXN`dioDd&kC>1tjk$5&OVt1{FbWgG4Cs&5EEI zn8{E46k-Ao&z)BHtiSt?wd>Y*C&uD+T(6P6(a7ob=0y_ov&+1L!|2CC4a+;E*Wc21 zm)IHSe?QPj{EyCqLS~_nRU0o& z>!C?n+7=4e5QTe_%w{*<^b)pHs11Gtt(}~~yb{^A z(221aXmTr_7^oGY=j-ACv@TZ|l3iU^F6jk&AfMfcG{er+n;61>-rHdJSCT_yy>3%21SMldUcT8M!3C#&8n_xy@1P3Ta z0BIfCp0Jj7cjO%*d$GDT(_1w$wp!Me4I${IxY|xQIeZqPR7BL=@4}t+PEP&aX3md1RZF|txu8Tz{B+<1Yk-j6+^R$k=1Qh|1Vu{jh+OWeh-U=zs}svja&P6r!;TJE41|<2t1wd8|-)U~5V;h*4U4 zNWO9x4%RS->x17@XxE(fsr_N ztz0ExMCyuV5ARYr8Flh9wky&^S^m`=S>oDub-}zg(eX_+2#{2f=lmkG2(F*e1F=ePgevJsrJ z#o_Y}!~M>F7-4|jFq`boOo#y5sDZ#9?Z5}Y@pKKXZwTs1gA8j8*4CIyM7`4`1wxkE z4`z7nShQc&$d;6xRsN*tPhcz4$vy{-Toz$*Uq*xt8$`8y(d6{0NDbWK;@!Ks-YjqZ znJgHx;4IP81)BA`C#Z?&0Ao>|I5PMw~(grRf1bpJ0hhV{KP=2 zNrv6C=TW8|7%ee2OA<~JZ^Eyr9Xz;laXRbO1yPvd{(TO8B@Kt#sjfF{_}JxR@v@2P zDH3Te%hL}}aIy*}r?Djn-n!q{cf4sq2zm!q^xVi2U3@;J1MHS z$cGR!D|r#rosg754qW9^kTHRxe;RpS1b?}DQ!lG)-p(rx1XZN4&H|fKOksQ#tUR2J zFwPck3YxL-6$+9yu=oJwmidNEkX_fPOY8ueuVxc01|zhMf(byAaPqFAOdMTGqCHsHpbu}H8^`uSDs11{W9_w<|K(4T4M3M}M z8q}|nuU0@yy-mX;%gMLRoU{A}1;E)RJadKCNftpaXjqQ%+Y_0YGDC*JhQ}g|NSIkw zV3Np&44B}3X5mIN%Qc*lEUgiTB-7qoG4Ag~xo7H-amd{9|ncBUb zSmOm(4CsCCAR7{S2XCegC^X6&6AoX81d>LCU3A*vPZ)3xVe{QVAqXLtWX^6=3rlBF zora|iiEXCXX^QJIne|o#gD2)TYEjK)b*k zTc*Plr4fVT8ppvy0cq4#^1k;+Z!r0bw5HTw5pHG~gqj2(-XRuQ=!v`?s~Pw?RA$8J zvkfE@u|vXbwP-rBfm-SSrDD*%rQV=}MY#iTPn+=&lb;u^PgS&Dw$oS$)mao?v#wv9StOTe8VN3cf}@4p7yCwjr#EpvYPR z(__?me8fCM3`=zi?(oUC2bfL5bH6F5vC*d zo7{MtKUZDV~FqCm}nOz_^vHPLA1B z1yrhBf~Zv0N+PMwTzZV=>8r17z(+PA5EIH;UyfSDtQQaW?a^gPAx64BkpZMEy_uE4 z{)J>NHxVG2v4&L;v3Qk@V2(`-1zc2%NttRcyek89VtHUDL?II8Q|?d)dHVb|wj}jq zN9tCCV6Lq=U0`Rekinq|Bz4pLIF`nUva_*QmN-Ku74<+Z$#luKzNu2|-8)yWrWilh zrgt$6sk4w~vPQSiRILQkTT2+IqsLRzu{|$0E|Tj-H`*;_K0ta-d$x_c-1aQ9HYl-X zggc7v{`J~5-G2Z@SkB*1EY+h8>(<_S>zeM3H~H7CcdY+S{c+dEU#`Dr1813H2-G4j zvG|%{OP7WaBwzv{fZPPRn9=s{E>0(85h>jYZ1rNoSiLKYr~tds2){;T`@yoQ?XYJ$%(crQO_eoJI$d7 zNor+cm8i^&-^;Fu?zOBtw(W7|TK6HFIMuHTiAEk`loIjaHn!EZ)vL1O=-(W*0qV;y zt;_^qm`l{L2=R#G-i~0bk2jSMgoj0D-ZbxZFb6g=RAt21-xkwmo{)K;m;f){qfk-! zVlPMVq-1}Qc2_H?POMP?L)1>PRc;NK-qiG~c2Z6NyjIIG`Dm7_QAmc+jXsR<&u*Ol&hU8+Y6ZH;h zM(|~2VhF|)<{eSet#pZ|Nh@1|O&COWsL?>K1c{PibSWJxSz@EW5g;&U5$w!L62t_b zn83rseCKZEtd@7vNLQ?GizdG@6*H4oz8kQ#eX2%|doQ(HAPYd$=1Yz)kuH|aBWGa{>DYL94_gph8bEJ*Nq$Upg7i3jHbIDv!2;6S0 z0_@@@36Gmx2qAt)picEmM3{PW;TD7n7P`H3*AOKRIl8~q>`j~ZJn~PpdSnIvIj{nj z$zPL?9Qd!vf}C3^N~BvW!3gxtd*V|1TevrG57D9sU{b}1ky1H+-&ZfaFvwCh#}5vBq?{nq})af2YhoIc{{}< z7}Q(rHMAuYeJCMS*KX`;h1>8Fn%d@63e$XuOcDXWLsa)*@gj7OTh+3gnPLuv%uEZ-0OoONMt-_07~zX8Nu*jm>Q3kmgD0Q zvkDYeL%1j(I2lR133ljoOk-}q*8M2(RLO>@?Ep(%n_mB*p0c>ZYH{%Phr4b1F-iGmNHv>Za#7?3ao+frr*@D_u1OH>Ql7{t~gi`qU?LV_SW z9IfH;RI_Bs9=uFZ5X*4o`BmO13}OkQx?Y&NVXTV-r*=Q2s3{j?tI>tbKs}ZW({*dH zK09YwTnuVuomDMdlr5@zdOp&QU;ne9J)DZ=!^^OueA~^p?{F8Ji z2u1r5bW_c+sFL{=e`~AbuZX3Ize~PL{F0S9{(6+4w`~ww_3|hOaU0dLiL7x!mjmuaSdJbr7I7h_VqM*p!xEam z2v(#2b{t0QL2CxlB4gKEP0CK}-KG2EOJ=s*!!$zRjQGbQ6hWC{ zvV~ou7H#0r;YXZ`;G})*JG>AvI4wg1puJQN)Y16>JUhrC#FYOO5p>-Jh`W-Y=fW+Te8ha`cz!%nX#yyjSo{} z)#S<)ga5z|WH}U+Av9v$CW%GhiW|*4#B^7-p0DVehif|b{_2jq*8P|Dw{-Q-;IHlu z1bohHbCnVN%(s%)?QwbMpdri}f?h14alvlxUUCx&eVOsFykKczf`yr8co?Bh`^9_# zm{~r2Lc9(dP>0r+3w>3vZt+3KuVa~lXlNC_Bi9ORtdO%OP4W5`IByAM#?kjT!H1bf z4gw9gQjt3h2&Iof^^2`9+DLXA$%w5kEPiTb%}sY)=&I1bH6u%BS`CrekW@jAIy%R} z7q?oGYQnZrQwy267c=TMzTm$Qr>MY`KfRmrH|FfE{%cyqTz~EHf1tqs=hp68QO`dxy^Eeg>%ZnIivoYT^S za^^*8!g{PXm{*``1zZ{62IaU5Hh0?{s$?g5S06{6E?%`i*axN3I`(pf7E)Fz8CxD~ z-jBLBhFW{K4<5{-Z5_{6OwFGMD+yv}8IG}pCQ_4;;ie;sY(65-Ede6mtexJve+SOWxJw}^Ui}I(b+=;m z+7C8xiH{jcj9_8Y6t&c;kz!!vU$S&&Nt5xX0xBFgjv_n0pJeC!-Xy}OM|CH=w)O z-B%Z`#Zl#4`uJm1xL3{BVX%N%P+4tei6`veBB+IEG<=Eq(e@q!m3G^7)lM1`^|E)6WK+1Of{>xlHm|OA9~J_LRXyL@<24(Gp*~oVb*M! zI6ZV{d6@CyE-+P=n?X8&wD2W%)(G1QsM%e#g$lOdBkBH={070^9^v3<(jg}_p{%kQ!$$;S` z3TW|G;dVxhU8^FKPf=S6f&dj1JkJ!W>O+;fUgY? zNvnht?@F^p0lf~o=Jfz7<)d;Suqir;(P2o_E;6-VBW!J=j7GOFAAYi9_X3ap^4YwH zyXHTkL|Q()vrKSw*Uov5kSzD*!(zzMB&PizIYwFhOy}2*UV`OnVa^rBz0)j&>jL#rw&^|#-%#yi+Y%XElu}5b_N~Wp>biatkpXqM0J~pxkn$shFkRfv#9)jdg_H z+9>Rd}WG7js_|sSe*AQGZ4s@Ayif$LkWq4SGFb_ zTfhu)4-k{sZG(yaqPkuFBVa_9-l%FRE{{SKLj6JnBwufylAIAA8u#ytP|s=Nm)TDw z$9N}d*7`FHG_wB$6_~7YWz)PGamtKL5sPJqB3n`7ae2GjkeXY4_<;}LS_ISb8q;HU z-Tuw$Sbs*UBL7Wap3Qq%NlA-Roal;>xiAAG02qEd(d|UXvHf;$4&DODqGVmQH*?rZ zEbVybzP0!K>h@pVwx)C6FK^$tzI*e%cigdl0?bvN9D zP0J>-DJz>I`GL#;(CG9l&m+@@ni>`@azNw0zCnXz4l#wr24o=;Gpl`&pT29LbKlfX zh{ja;SD2}JEuHDE8}P8M<+d0}3;VvY<$YXGKE1VbpX}}r@7a&FhC_u#RTY$Nkxv00 z!&5T2^u2PN*!=&@m#`d8Too7a;A2XH=Sb2MzUb$6lhs#L!q&)G%{| z4@hPrgsBRxpo{i+nqqn z@Nm``gv(A0yL&T3&Xe)=NR?zAF@nAjN{;+qxO2MZwIImFzDxq=55_{$l$3C z62YT98S=5`=L22tNV5RQy2w)~;oNZuL$zHXk;}Xm5M$v(MzOyL!yiI{P5;nn9YC=} z%nvn~K$DSW4;Ggq=g?fL&5&ZV+a0-}IVs80?g(9*8<#dQP3aScPfJ)PPJ`45CXIX@ zp)4e2%4RE>S=NI1z*YkvHzkW_H|~;#(ytRno}|8aXjl`~7aL2+OyD4y5!F3@3rm7t&J2Bs?Le6;SP6a`B^|8TmuS+&r>tKv z+5OEJDst`e{zbbCI^^i#(iOKO>=UNJ#S!_gA8rYzQmW94&)jiZ4iFZor+3UeC`eCZ z3j%$-B&WL zCs`cKrnl+IrV<7FSBl2LLWSR6PT6Tv3x0(^d`&gj^B^Gegwc|a|c>1JRsdx4?G*Do-9pn0q4LWbfuowZI=akEBLFgkz}QB3eu zJD?ikIJhN8A09Fe^0Wrf89?6SEQL1G>OY*v<;*4yB(MeM5Cw}3%xiBWys9i9iYR6j z7H1A#;suJ2!I)zt&x)}Ck`-H8M4#)KzS@M!WAurAuY-P@1tj;;u4pgW zAg&ai0#l2z+(;5JuglgIF+sj&?$ebqD}_vo?`cx09CHHEWE9s#ha5QM3{( zDIW+%;;2dh+7dj*GbS2AK;|8NABhj*KjGaJaTBY~!CO}kNF1sW+!_rjJH+Wa9MZQn z7EjLg4&mLZD#gxItDs5|iB3P*+Ot^8yc?_+TW@tZ#D`k5K>V;AL6#jj)RqW&446ZG z%1H}2H9T06Y^jkny4{0QQ-uD}U$HNQCMBV6A4gmAU8t%G$Z^AL5O%QCTr`}fLkVN_ zdEa2>|8{S{m4@FqeqbwFo_|&i(gbg2ufrmg6(1X|3DJZ-9C(!k=-1p86^5g6SF{jbm-5|&t@mQ_AL%ch{2!{*~UvIy15$A(iN zWk`U`tCTj99wd#e-5ab0gg(GSGznOk1VUK^I7a?c>k6g39ZzjLyAl(uF}e*Gi8nJW zQP~=de!Vhhk#jbxk=|29haiTt0Iie`2F#KmCFx180F?eu*LOq3pYAEp&dS2VPjTo3 zUyj$Fh-I<`3hG9aFcE6V*u8k_jZ{|lK%M}?wvvk!#n^6U0Jk6frv2l$?H@*&hZAed zkmBXo=0M1qcH6?)+t2K4k{8q=NsGS;!h)wp&Nk7rN5+-A367(^EdK8jtnW31szlz2n>&c0~M)R%>kX%GflMoZOX+SYDZ8w18_P#VLG0|_LNQI$qnL5O)~FG_{WK*@*UgaN^XCXSOyfI1me z-e)r`{hj;vOatInN)b zDqUn67IW@g;~g=1l3c;mFayk}@$knHcCql&S`|qjW~hP4K`Ge-inW-5tRv}?{|D*e=4Fbf-_d_7oR*WTWFRFuLL_#ACLp4C9v2=@}5~G|U zn{UbY-?PWI@SV+2mg_=PlWxh%C}ZTz=5qF0;-F=X+yS7st3vc!^@1(G)rb0&+q3Q_ zq&btj#nnn^wtfJTl^KAs3Z1jcXty zpNY{7kb-2>_?%OS0&j$@W;%eD1AweMlsM8mID~ zA+BQiSp`S-46PBikX8d>e=8aZfx&7HjX=lNRT#Juip4`>J0)i7uFJrq9tRmsC>Cbb zC0V4nWfPyt|CYEq-o3S*N9bgGo4^6U(>HcezFlYQ0Mep+8-7nX8*3G;jWsO^Q4G zU0pvYmdXvN(~86n->geG+LZzO5wKG>DbQ0W4AQmk=&dig7B2(`oTZzmqBfYMYb@wG zC3sbnOi}A`W)w2IJbgGCr*td|U^`OaXn2;as!~Ejd3j?otFYRq9ReAp{k=dd;~~LB z;?2Ybl8ymM6;rnS?~Yo2mX+#L)|wK$s-3bLZkiXd^OL0(r#O%U1`~i8V?+nl1r3hu zJ3#iW@|>I!Bq&8-1fN=E*?C|E-|Nmfy<4)*S68nyPso-_M4<`$ux#1gP<-mYAe;c{ zW>;zDm3y)=f25wh4;+|rx%6`E93;{mF&rK6rbgLuYPw5cGE17iG^r-wvyfPK5R|JN z6hR{<8R4S)9T6Hm?LvYtX$Jcvs@F7$u-Uz2=Ex5KHzbA}G!De{W#>gORMKr*2#hYG zVG47J!kXMSm}0e}h3pI+Ak$DK#N3Fz(T4+p047CJs9fHc5M>$x+3DoQih+p! zeK;i%v60jfa9lKl2&B9s34FT{1@RjMx>F8wya!Ccs*U9+QK;|_j(6_wM%EF3ShXUX zXD@$eBH#VRxEkh&`^S{*XPbyB;dJgFEA4h{AG?2Yd*}W=dv^Ihkf->UnELpG8Qu&j zRttfo(xZUZ2$Vt$H-0%7$PwEXkD%8q!UUKe{^=H#wNk>y*8i$-e_2MuG)d8nDAlbh zWSh!m3{mwvjm`+auG5%R*=&OW$U)EzPZeE55V7ISb*@CjN)VRFcBWlwL!(qHDiM)d zB){*1r0H~-M`=5dLgLcfm7-QMmq~eaUE*3|JNQCuP6*a2fJ-8+GyrT~SU*6BMQ%HA zZha?g6`i0v=F!z5)B&h_LhQx!qm+^k8pre=ZXJ<@Enqa$Q7pNlJS>wZqIM9NP&Ae< z4KJ#82jj(7)RLh$3qPH&UJZX27O_P-l@1^=Nyw|@$eB*jC1Xx-q%yNI{-O;Qn#!V$ zhi0{Te_S70cDs|V;y8pr(o_J=&VRUrg+DfW^Ra>|I&rp8Ypbmc1(Tc&5@kWnPL<8IY9dl4Gm(31 zWoEoXUB#)rz>n4D*}^;~P1w>k%9GEKU!f9!$*Cc1UHHpTFt7Cy#y2>n4lx61*eFw~ zC``H>HXbbSD2M^c9P?YxbmBD9yK4YZAf95f0HS7W(17$;odA_W0qcrK3F7G^&?!4n z|DaQaSp`SP(;iOrqXpr`g9k-ZA%8c4E@SYGhXqL=w}x=AA~s)%73x9H?a@pzrZ z*8bGJF-?Hp4K3BpizXvWnjd6z@U{D@RAHg1Tyvc3%Lo3JLCGZznDyVhcHMvJuD$1; zyYBlYC~AcZO}{{L-W&u#PU24fNn+%CmiQTTQ>WCZSsq}KcPQT??4mS7;SIM>2O_Ej zaPm2+G)$hXDR1Y&?VTXG9o2fA>4evweY>@s zjr{gQPIR#D{6`P56fhSX6k)PhWTp=I3J5q@`~X0CHG$glw@h&N-+p)D(mZ+eQCf$v zoBzx-|H`>rFyXH7DoO&zR=2Oi1T7-l(6sAn}|Vx zadx@&fHEfwJ+R-nw6-s+Gf=gnl%_yqncRt*Zdez$LdkgZ(UAPuDNhPgmItf{{aZ&36 zqLplXoqc=wUuqRPvoriuG`r8X{v24g&LKhrI~1pVKcRc_rb=_H!lCw0MX(~s2`ojI zuW8luM2*t6X+kE^^Z}QO82B>Ppn+#Nh#%N9IDk!PNMBqw7J5YoI|!@9_C~`@XB6lL zZbYl*njJG86R_}`r2t`rD``3%LSD)C;-4TO{Od%mj#W9MwG?2`G!28_Pb3f8Mo^;B2*|#509HEBWwzY(`@pvuCt!hz?2*=CfWAB8Ngb@A&UF5Ac3tQ02&Nyqee2k-WBF?`HhARjyT=tCbHQm({t5=Ur{A6s^ zP2Gu!H4_sfcTh8H3}t^edBQkA*YIFBxg6W4#x_!SYR$-37xm#K=0taE|$y z>ux}P9@)1N^Y)J2Ka(K@d-=Yf-@EbFv43dVsdJR)vGrsU$mT`mc&b&^fz~|wz@~M- z8tIIT^gejJ|Mr_#E}fk_eX{rG$NR5*arKqYuYC3Vl?%^z{~r;Vp*FLxKe=GDzg~Lw z%2!Wax%gb~)Q9oy>ZLP0>>YXS>K~r(A3fYV%iH(SvZO8ce*bKD=}+|6mGjRqVE@^p z{WB-7eEm%Cy|;T$zsn$355Cj8@WI^W<8vpU?R2jmJbLxy`QCFUd*`0${rTWuFTLJB zda(cI(bjm9s|Szw&mCu8n$(fAJej+EHYV8l(T}<` z?!R;V%7r)jFFtqWt2bvqyEuFCo!+q*=y&$$5vI~Rc4qF0udbYXZuX!ru| zU+2Fcd=vQo_k(ZszWj9dgU6V=!1czvSI%9~tJQw>=12PbM*The=Zn1~e^hs;o&>`E zqc8R@9h`moi~hmKnE1%t2aolRpP`r9FWt?Z`LcKDv#YOsQhU^}xBYZ=cm0G$K73*J z`LoPFqB63^si|=3?)ygRG@@=u+?Wd4X)f9?git z1{7V*U4HGldUG+4-tp(>zCJ&D>D7*YUOjlQ_w378-+Ir#y76Z2y+2;Le7bk)xp>Ii z*$*#XeeG2J**o^!+*g0{PZluu=aayhJ)HaMtGUA;vkh0yAMHQ?{_Lf>$#PkddWvGlK(jx1fxWdHElUoRbHMoYU_ z-+OZI^w<6qpmhIn^DqAHA6IVvMYsR%;knaib(T(^2lRoX0>bH|OpND3q36!BsRP@o zF4Yeh*zFyA`O3vVxNAP_AK?&i0uIj}J?!~y?e<>y=;}+CIgd+aTj`(qnz=x zb85ahbE$XeeSb4Ea^dWbXT4pWz~e7;>8SU{dskn5r~mZ( zeA4^s#okef#br?}HsaMYy%#^8{qVWDGoQ?TbPy`lJN7iIm_6}M|C3W!UpamCy;s%j zi9@}o{>{CfeQ)mUdjOIj(C`-Ji}MT#o4t6X|H*p+^6phnFJ{$Dx6YEY88nKC%%1o& z)TQ^-q24F20-L!nKD&DGU3Q-F=`7eq|M8DzPoCxs>5tc+42lO?1TeJkoqC6d(SvAE z>HNz1cj!MM_Z77Gi6!r~WZ0YA!usw!l(&RD1uQeCpS; zOZ`tz0zq~nup*GP|HkM2m(S+n+n9Uh^2z>VM$zW4=ppc`_5<$HL-a;JBk>oI?r|y$ zYZAP_enU*8QU`xlX~h3H_}JXRSD7;z1z-MI zb2SxRapmIky+dEXvI0-rT|u$>M=#fLN8)#U2OK%I@$u}DFJ>=5+|+vZ=y{Gw@8G2s zV1G99sjobUcXJ;+HT%ZPb7$V?Z-WV<5#&*Qo_j{rgTG>AZKbD*q!MC_sK@aSg88f4 zr$34Y1DJy(0(H_(HAHLns~2Yf_?ma`;^)10E;Rcn5$MuE=xXhwt09iO#*2VA!!b~q zZU3{6`cEE{{BriGs~^1FJ9H$V+dKVi|E13>CiE`IIpYOkWtaC%0u<~!fm*%IQ>mB)mf6YHRbRdf8 z@#*uO8)h%PJoohr9i9Ed7e;Sbznm^D2V6P#RxGB<#=HrpdxMVfTkmKdANBssu(u%< z%)a}W@a)4Q^a-Cja-7%aPWPVvSNDDB{m~n4r|;ls>gg<}Em%1pnE7{q(b3SC4t8$? zzt!RB4R>MA$SGYqSet+P>fGm_v&s)%j>+*SGU4G1{EN`=*z27eLKf_9*my^`OggAY z>4T~BEfe|usjDXrGBJw=OvNgMgji&EWbgjT_xtZXhHxy#fB4wdSC4Qi7kC}=f4)X2 zQ~ysO!XNF-{_&aKbDwEqmXtdDrPap|T81EocF=$Gi(VLlZ$gG7V(X-5Vz+CWKSg=9f{)bsDaJg!`NJvLr{yzung8Tj=f z)FH0?o0#Z=o#EnPK0-U@f=&l{q32j`|LnQB%RosTU40D!=6R%^E)t`RcA`-dagV%g zX(<~>j$De=dh|PXmtS(y`_KGo_QK`4uRhO58s#iR=jeE6c{iw1|0pt?nI+IT5~q6Z z^4rMy`bN)a7ZUZ=6R*!ce!e{Bfa%Xw`s%SWy+cR+%Rtp9S6@5Mfzq?pvIUpMO4 z;phD4E#0{{AD{jBtq#=U>ZNy)zWXnK!dNlB;K_?PeZAK{O7y$&mgW!7Gxo0YkKG&Q zE}!VV@pdO!>gN|BxAPIAA*}~5iMXI1pFJ^m@}s%0zeeO`&?K~iRcFgrd{vKfN0PpA- zSR}YEPVB#F4@+-1(*Zp4)a(aV^g>jE$|EcEj-BO@#|ANe(D#63|MEd#C{ z|K0Qb=T0MrUH$mk72UfL@Yw!Ue?KvI__OZn8z-=Ot#EPzPgk$HiKnY?(nBq4!B4rP zu>DPU)hhiSFPuL_T}(YseA2t{^a|-o(CgWkUc35+IC6&_3bdO2RO&E%U)+(&Tk3?y zXi*p5U_WO6^#b3ZO&}=QLjgU603JRzd+EjA!LR!- zzlouV^OgGm<$dEVXaFi&*rR$EznHuHj+gp}gZ+PdMyj4^bMM&;y?5S$?K4L2%lCVS zzMT8=Oz-O_$2)89Mm0V2)Yad=zmk7oZLKFAW{qyvX}J3RT~-H&?}+<6|9-F@siNWn zW=Pn{P_Q~d`uop+XmXSigUC;swN8Ek6Pi2rCX$Xo^SUeph{@R3uKxb?-091RSe^K% z_tdAeA3xUV9exT`u7B{u{EJUIuqJ@f2}~^iAX!RExp1OW|ANsWTU|MKbne67Yi3CA zo&J{)s&{2>vTZAPD%OzM<4;w*(_5Rj7z~CH=ovC=e$Q%s_bI&lE`Uoho1>C2qfgXF4 z{&dcS_gH0q|AJ)lw?UC-+KcYJ{YSMxWtlyRb?i+4?JqDyffdoH|MaQe`>%9Ifl&Xg zlblZ8AUQ0jV=0KpR$sr8y}$7}^y2DU@2=>|dX0esI`jJ1OeKtono5HH*ardd5L7W& zt=l)fv-{(2@5>Lao;b~U>m9zhXxrYg&xRXaeecb=qo1a=3kZbpl(sJKcDqG)l=HM) zx=u`I;N93llZY15mrk5#w(V(h)WZImZH~O$-SB|I2?tkGRn%yP^o)(%=f&2m!2b4h zVz4kf<~(a3Rm2~D!3Ou=x|~mEFFrN*bOCw)`QP`?e%|}!M82#x=mi(m0kN7Eaa@j^ z#TS6BkOP!`EI=TVo&?8`w&`yf1JiDpH`$u2k6rE^dMhlpIqg6Gr{3F->j>aL04b|s?CM)@qgV#lLQKQ5 z5$=L?)L?K+X$y(Yq+O@#(uLV4j?5i=V(zsUBht|iFVaAk$uJsW1m=H-kM+*JP`_G9$0+2|_|VLY zU8-Bq_Vvf1Yr*^qnh)~B^7QfZLSnR%M4ux#naY`i+E)I_5WQ1}qfxR=s3BBr?(z#M z&Ya}udskn3k|)_2oRMSeg=#_U%jLJ`&O8Pd3OoOR%K2jN`PX5S;v*I#e%!n8k{lPO z-|k(;>-IQ|M6eUa+7Iq)hns7LBkGpwLgaPefakv@V6^+A9~D@brnAC<-yOsgLmH!0(r41+Egwc&T9l;d~4EisA(0}HW-pLca@|V3=KgR^7&BJqXVQTBrh(zq>f=ap$VM&TpfJ=il|y4 zCm>t=9heg!Tv4is36LK?gP(>!gxolgUpfmm3J9U)ocJ12B!IBIlPAD0#1#34B(VVA zD_EINyn}rq#Ja_X6+R`i4r!oR+W=W72y8-@q42lGBfc6zXhJgp-mweapLYY02nrF* z;Y&8Vf7cz|yJNdzCU16j|5*N7t6PGXk6gKcf9GWXWsEJ~tD|o-=zqI$q<8Gu{u`gN zgzFi0V*I8b53FH1DL|vGr?D1Ho9C~7b-eqV-JQkH829Q7OxF(H^javZf{}r zsn^)du&**|@t*amRyjmuy;QX;C;CTx@1oZzFg zfBI80H#djqbeH|pvM!j{T{gN*$Mp!F%=hUGkza^bEIa*A{-9UIR0P%6p<;&1{^`F> zjy<||?EZ027;c<=lI{OHZiFu)>Csd;SMy zW^Y{J?6S*>o`_b+=P3R8L!7?8fkWaW3*J!&j7c_Y0A2{d(Cf$MPM<5JEUXXx*Des} z60}-g4;vbLhaJ3eSjI?{EP1@)rkIR^m(d;S1q80T-{qLGA-Q+#aR_3Lgq26id<+}X zvp$W`BAaJAy<;E8Ya2g4mRY)+@_syT*&3vKNnRs-q<$7?Joks!usa~D=2&c?gdj_J zz2ir)(}jsAq^4cF4gZRbQ=e|1KK~ewVivgx!^|IDUSI9)mSA4rY@&H3kgRarSF|+Cl#USh2Z4pu4*Z zs*VdP&^5ww03r4+#pJ|F=|xX(^rI0FDcly&9Q@O;ix8>UAsptW406jmf(As1m!c9t zMNv(MzT}eu6nplun2~AJvk}k{I++~ptxz-Joy;*Ai4sCc{Z=T_zlOcj!y}+B-XxGx z3z_@y551>8OV~v`OT_=wV4~1DQrR#vb#T!@pgXfqeKh+7{s<`u^pz(KW;plxJ7REQ zQ!-@<-cg%&QmZ&}T)yuZU3~A&k0P)Tmu>PcdqaI%CD?H?F5=IgJx#3L=lXHws|+v@ zS-fx}u+K)D=Ye5xgmn0Wk_8LZ6Xav=L;h)n=rmr;c$zO0leLpiXE0;ihLb2RRB&G+ z0rt-75IFEK`_T)pu}Z?pq!f~d1OHgyjV5>X)yuM>{rR)r*I$ZpU;3bvtVq#4Z)+^c zw{jl`!i%N~^&I`<_s3rDe{rM-m$~@G>=PgMzIrJlx<F~vDk7HgM|iy6b^m-fFHlVVIP!?O$u%>mNLRx$XDawsHAKh!Gu*7*%TT*!iV>MM z3=c~O$w)1f2^@9C%!-Bg-~AGwbdFWu0HaGqV zBeLtuU(LQ0HV}Lrn9rVrHxY#xL-sDci_0d>Iwk@Taa{tJsOu2j(vyG4?`1^siHJu; zh8#IQjui8B9y5fw^4GD?%F(NDLyhmf_*kq2qP8&GU@Y=($LbXP@eh-?)qLN}qQIn0xF5JFCMe z?C55ZnMGgE?Ay8Ew?VGAj){$)-Chncy#6bs}l3Fm6^#v=P?Bh(H@d@$H~pJcoZ%DqwubalsxXp zA(MVCP z@fYzw_({5>VE|d)3FGqImmd))gnWe5G>44#(zAmv{0I#vd^@ujU*h-@dka(S$W|J> ziob}Ai67|vvc;eLh*+l3CD^0jGFmR-=$~K(eLk78i4P7jQJK){9E2B$$+;Z~7l%X! zR8@kN*#P?if^6lN)?8z-5WvJF2@L(y$ttnc9yRTu$@ZT;tjRhOZo$be)>qC>5_Opu z&Z+B~0-k$TBr*(Rj3^vn5Mma6gvcp5@aa>X-dn))WC!ssT#B&Vr#s=oPTySnhgd4e za`sp@>7V;oc59735+Xzhx+(g=quC4RHJjN>{|XUi6O+<1QZOfUUClXsfiYh6+zDd< zvy|915y%qthr;1Geu%HBE|-+qXkRU;T zXfhKb?)@w5otdBf7w+?pcg(rh-kBg(+2@8GH$o!!T5GPkW;^C+-Z2I|b1ZIk(oV#Jc81z1Bw+=n)UXbQckb`|=^hx&Pq5d+g$#`44LGcXn)A7mVt`0wJnx{-z z7SG(nCgq8Ix&s0e^FGV!Fn$R7lk~PK#QV4AKl?`Z@T+%GhjzGNZL?~mpwB-EBub@y z@E2+kz<1w*pdj1PqrBF@hi?I0h#8)~D{2r+JHY=&^D~sZkAc9}0cI=&Yd?(l2CW38 zPew9u@Yy8XVYYPZ^qEjT48a^+IAITuD6;PgrOe=W{0Cr#s2{hXmkYPii$}Hj!Mq3! z!N9F7R!TpzfQ5%F<_jZr>9tRTU=y^FG)Sm);*d%GM>M5MB1X?r%*arN+>dz6>mrY_ zc#HbIbere@3eb#{7zl=ZrdF4Y@_=<7-oMDQ?{x3X^)Bx-;p*rFnLV;FdZRaW%Mw~S zE25MS5!W|Rwu8MDy@FrQCq_J3U)T8|fo*U~ne6aMN_DRy5HSb0CWQp;j@@RFGS@Tn zUmZva<$Fm8v9hN;dgZ*KzuG|IDQ4V1$5MBPY$}xzF9hp~v63Ng3Hi<_C4N98A6a`) z7O1arRx!j{sYby-mEn{S2vfS6oWz@}W0KSh4-51}nyD6?i^@=1@R3xZJlKh!8RSxv zj>&NU9I9M)22`&$yZKq_X$zNiOllp7azTnO+g?)}9kTnz=PzCZS{3`n+;gYGsXMRy z{FP^3e4)|Ip1P2pFR%RF&wo1X4nw!OC5Ii90kqaINszc;cLe{Q0r@0&q{=}<;VsiR zG>tlPN3jZpAKBz5i$}KGD=XezZ914yQQ@yQ& z_OWD*H1OgNy|jD~5?D2PgwsTA2#iyVRn(y66C9HdmcEL3-$ZZnQ&jJ)II3eL2 zymJSYd%~vLr8O{F?y8X*1da;^7~`R_9l_4w`HzRJO{0w|p|otnB0kN_XK>lAhE+GtQ0n> zwb&IU0@PULmF~6cUOGjwzol*7Mnpj{H2amW1d2W?I0Ujb+-LnowZd~2!ne1@ zb>hwwYKKs%S?%Brk4narQM+VTt|yhn#AU+%ocZI5l!?hX8+KWWnL{VX<77U$v+yX^IWyJk7%vEeFgK1vDOw<@Xh zUEwZ9IYoESUuY2CZ((3Ma2JeNg+d9daev#g-)yx>Rw_tmNV8E%=&5UyeeiVvhN?13`{im((NS6;jZ)g>#nFVvl6_hF1C{#0 z+}r9V-L0J*eEQleZ~W-TtDfZ#|Ezj;{cqk`^|RMr3CN+p(k{*d`{;M9tRAjahR#g6b}9UNReifI2AF@zUu0p~(~~c5JUE@A=Eyzz^6K=3|4ZEi;P7SqGGr zB7@>Q8|YJ?G3uka%hX|J zwqqqwTHnLSuGyI#U6pFji5=a^ukkv^5U^a?SfvBnZdb^B%Pc)Poz%pZEiUsYI~f4= zz}PNZ)TBMXr~@yY+^lKpXbO=cEo? z_&oO$d2I$);LEfa$E(3T?b{mzAQgWojgZN7rxKaoZd6J#{wusieb8q09`_6ll$7Is zyVf~;T}my{kcB`JccoDa5W>E_aBR$|M@ZA@wmgZaWpCG>dKK>6c{T7TokH7(tDIk^ zXBT$f%pnWkX(3C_Ux%)(SiJ%M$w%^169|vG54Ov8arhhSbb|s1vuvO8=tLMi{LOIE zl~9+06k40HFYN@G1;Xul_%$CPt%dwus+hV&s2nnqIGr;rVN!x6<`*b1;)dX^)>(3Ior5>)C;OGLzz|E_Tzi$6;b|TXwlSpR@jqzU&6NgvBP|>e?ho zEq*IP zCXFE0r{kq|Ykm07p9%%BTMIVuY6PQj!yJ0RNCq}%M$LMgj6B3wd|SchmcH$V)~^YV zVxuO6Gt?3qr`Fe0{w~h>2hf%+?i7ebjcpa+(rPZmCv* zt#Z~+HBQUkRKzd%Kw+2%wB)r-R%(|~(pSSAuA@BX0%x&-*J}vh07G9 zn(_Sl5&xoUG~|ex8C+pQGhEve6FcM;9iGxGdYcChU(`opF1_fg&w-F7_YTM!6;7j^ zEDcUh&yh$DUuhx%#K95KEv7W*>=!l>4_r-$4U96?cOTySwDq8PBeb(k=2OgNa?48&lVPOK5p`tQmg$ccBE$4io9xJv-DanZr zuPz1IojdBWp1(;t&NV+Jp#7tZ`P=>qb@6$eK9Y&@Gg~MIAB4AB!J`-~1iryAsE`_| z%0xL3DYZnPJ=@f}|JWXle&%CQ43?h%&B*$VYd>gEZvVDw#M>-B3t;Kq+WCT`oi&CmazFV?M9 zj5H9IazYAr23Hr&!_71EdlmJhv*hI;(}Q<5G`}Dc|JqhvBkOea#)l&xY*HuIG(RDY zC@C%0f3Si3zgV-5?!7*;>Gx|kZcuN2`tb+4LEyURP5H{-5)oOIl0oy`=5IH=!&rSw z``CddqG?GCCG;w*D>ZZBlBu&xfcD+J(HTTw&MvwJlZR4{GA?X@8>g_$X+^$ zC+Qe4@_L{4h3s^xH%bV%z4m*~h#&C@%}@vjqIoE?i1FljAm!_pLlHVqA*rqKA`5%2 zgC3NfbWQ=wc%Zw0viJolilYRX@5%u`gz{-k;1#Dch6i(J(}!o765+B5A(H3j{M9ps zvcxsI2R8FiY`cYU!m_!H_BHwL(z2QW+TJQ|tzGM-;SX|cuM1(1k(w=TX`aK`9;jSI zE%6^4hcdDeJ+%(P&%_n%x=ch6ISziuTWI{O24TZD^&JN}i@;%UParZOX*XePtGJ@p zMYCin2*%tiPm>$>3!8jOQ4B-PFRmX2W*`cA-TtB)78}`X)rRqk06n{T-AAz){++%Z zMhamXX#B(}RH@(E1~Qjr8yM=LA*h2j)c&+O{jo1-B=E5c@c54!LORNTwgWs3k*AIU zfrT2ca9prreLBVvX|exN?b2ryHBK?`!gd#70mN|!`jlBjLv8*SRSDV=PZ-qr!@E<5$Bs-WtA< z1s87Kh0X1Nq=?uQV~d|&mkem#VPB!hsTw7ssZ*nn%HGy5=I4&d$dB^J>_2SB{!36n z$P)cW69TQORd{Qnv^# zbqRPJx_6uI3g2#KMLOl>pNNggC)(E$=)uOIX7%cyV$+bRM3Kopkv;j5hE)P@5Dkc4 z4p~^sM<;H}=!g^W!7&Ym4>3hyoWX8N6ttLdw>*k2+}hT=w@(LU@S!Z$b#(&GuMp@Uc?3Q}kl-`I|Y`OX0$}#$B@B7;P}Jg_*>4Mj+a$(w=N(b{ff8evi5pWS zr^me-fvpB!4XgL#DmP;t5Y<2?f|QVlk|gcF`Nc2ZT;04uj`24m+px(GU`>u}akNps zdFAD#kmj^jik8gcH+_$kWW=i`nZ55Y3RW56%8y%@B2f9v^?2C#*Vp0fR8R)ZTX5Lh z{J^KUKGofFTNZ(xlQ{eJAvp>u(mQt82nU8?SV4&r~KJ^zE$}ct)%qveCM-qmI1yS8m&S+~SM9*GYZjFVjnwd_L_?bqhRh;x|-1@P8V43}@V0g-Nociq6Cs!2h~>MCwOhN9x5 zPzSf}+IAV*1#M5c?$K32>Q^=lwKs-FEuzrk*Ux`L^<@t#3_4+-Im1@*87b;pZhO0u z80tqiW~g6F-=|aGrAJx?tu8HF4`@HdDDUskvIPg)>p~o;Lgd`Oj%tJ^EUUf7wSzJm z^#~I$7At&C8DOkALT^3Ty3+CIebn|&?_by^?Fi04%#^S`*v2E~K=0%h0DH`Dci$a+ zQ(W{Re14-crqlP`-RP_4It&`T{xENBK65I6@#3pbF~uRZLhSJ6wOvwd%?Wi=q^<8>ez(VD7(-+L&Xl__ho@SvxEp&TE0N@9wlrMG1W>}`M zJwsuski9uoIDei2Yyi@zw0xX1X0%*5G(sBcqx$5<94RL;AgLQy_$1K!0Sk#+VOKV4 zJk4t^$wH31>`O2fxS+7!pL^mNsr#Q0A>FHxbG)GyTO%&aUzvpRs?{+n)U6E>^{Cv# z`zID|9nyIP8A?j@=nEhhiuPFtkg9rtOa}RoSYRVnGmb4IHGk@hkb;GAHPIP3RtGjh z4__ey0v+FhpbdDue_<_-+S|U1z)nHv1I^I0g>BbCJhTI0G9L!v_~0h^eJD z#T#UbfP`|Aq>5tC3|ghrv>RSgkrbC-%fJg<`;nN;5aIGV7?nY_^zwLFe>-%N?_~2ctI{ta}og7%VLm zd2jb?L}MWd=-x&2;P5?YvCm2YVRVUoUZqAM3U}}#D2Le{W7J|i-hC;$_;JrJC6|QO5 z7xD!6a`O_qh($oF6AnTVIv8Cd@NV@ctW?<)yF5z(Wq_hEbSdVzkE*<|dSmh6l(2Aq zZdL!ltsEvlAG`>T!D=Ns3E-Us6!`OI$m>VeSbRD{WVD)4cqc0opxf1ulDufD+$`p! za0nc;*2A{li23|53CLncFJXlos>0*8gvrfZ>@1)Hhs5d{Zc3(otaH4EQD-98F6@h- zPnG4ZMh~w!x&g~twVn1jplN*`*_;To&(<9($D5VwBw`0sYi()!eV88`i}jhps@XB# z1Oh!)ckf-8H#++)hLy1${3iU?dA21egHFOI?CL#pw0Y*4$X?7hEKiG+p?aKB6f=H9 z<;aVHindR|c_z|^`Ml_OwZ=aujCm-y0}@%G;HF(F9AS6SciUD#Y@-}(O$y30`DD@t z0t-E{iG)oN9&6l}+>yFIktvQA09!da>vb;CU+=6$)$Rl8d%X9(l`A+i8z|Yz>~itx zr?CE`Oe(vsoP+T3acYdl1pO0cG>pCeh`C|eaCwhP#mk!Q2v)%mCDk!DTG43z(gm6y zKK#9{H>^;QG`^3(Vzoke_1LVg4N@I+s9y~q^&=2j!t@6GP@`7(r6`Ibl5)hYaImks zNKWqQPUZkvE@?@!{fGtacbivVeYNSYvLzLGwU!73EP@aZ4T^<8#iDRTOTe!YK?(|( znlC?wOp;kkWgSL3e(m7&K1P&!G|*OHWnHXG>=IeTWJMS1J;77Lr>&F>%V%8R>-=CR zhcJ3LHl4q!SZ8~#FxSZql!R7B2H_spa5 z9t8Nw%u`L1nJ|JEvATwZ6$_cO0UKrnQAh)(6e_9Au^F^CC6gjym1S&(iJg6tbBB;9 z%1fkUbD3YVXpwot0SIn?&XJuE%+qM$6ofNb!f?q#B|m@f7G7al(@O?$)%-m+I-u9J z#|Bg0509b%PSam@$CcDgawHqR23!rzac)@L53vh$ydCn-fH0QWyO3t`d9w3yO9DbG za&AIRXZFi0_Uf&Cp&qVvZu3D~#Ic`PJ{T5sN-Km3Ev;zDD9Z)<^(zCCOsk<;NpM)e zSRz^^JQQwW1OW)1XBJ5Ez12U${JCoJ@MZ0vFRnAyOvh7C{^DsO3h8;XIt--4CA1jy zwCFM=JU^~{tmr6EKLWB`Mp3BkQ%`JqTF4#OP?vd!F;dXK0@T0>4996LYO8A5b#IcE zdd)^9u5LC&YEC{_suVle9Q2wW$_wjnI@~b4w1?{WoLS@yfuRGlc>mW)Zo`)=0P< zoY|!N*}e;72a{(<3Sx^X$DKR4h(RQ)GJzo&=C5X7$nj?eDujM;e6rCls@EPrfVWbN2N7%qda=fgvX0D``F(Zzg)=124<^ z?6<<*EU^YyC)qS!(AmAclABG;fR_dU?Y0!Sfi z$$1w6b5GVCC#{@$<}lzyURG`R<`qD&BOksITerdOQp&meSnd@lmzGM?8n!@HJbtjx z5r+|hkO_Xu7IPRE9cUo|tjg=qtcZW8i6XPJB_4ysr?77e3LX7avkF!70WDs9dQ$7- z1aRN$RVBhxtd2w#V{~Y2Q3()zZ)PINrUyqAgyn>~7tfxMH z$RlohK(lhjot7~|LHOu0IbVKr42Wmh-5?f(Z_PJQ_$hLtSd1FF)3KRlts>l#45VH= z@MP+n*u`ihZI(eUV5>HOtJ&6Ih2`A5d9@~BeW1yXZV`jj(u7e_^8*5O*BY$2f<<&z zwGOz}?lt(OXGkDBf?i5)nJxE{1spRK!SPxDFj*1v*m~~zh+2Y6E4*t~G)cUXoy$EKXnxqkN?(FQSKyMYqFm#M z!uSu|&5PR0;^(saG|t-=tp)j)Bmk8)cbC_Jenc-ypEW(Cm)*2^&Bo2oM6OjO!KDR| zZ2iC++{{!YN5OtqQZ8(%dl0Ym8kr@9uiUCm>Z73~SKEW_i)UuwRMKdVSsnyiq+|2f zot{;NBkQc@V+a1+N{A~p-YG=|C>?T`a1cZ#5D2j$K9kS-zNz_}XBVc&^V;m2q={Ij zOxQB~8T}XAcs{^XH7G7i(s{{wNBcjm-SF|I{(Zf=vtnf;^FJxFxEr-E}7@_lI=^>?OPO+wXk5 znNZLFQcIV`0jw_LSePZW(E)>#*G`duldHQfF~z@WCSC-|wYxMtpknEk2#X`(?-plA8(@5}Q?GipzB@eX@;HNX8`L;X@%!G6WgUchj@MZ8`EE8?6H zwk4ZyRPTe}Qes7)n8nF%mJ!qj(npmO&4a2TK}0yLl*cwcqAkTv4^krjF7UH_pfv%p z`sx(bN$i84JokJg!v#kIIL$$v;_8M;fIbw<2|`NX6h_YW1(p!i>jjVf_-%+seP7KE zZK*Fay^WQms2GEp?Vde&QW|Q=>~ggPi&F=>TB#mWMN$ncCN~b! zUJt6Y>8CEx6ctthq;QHc#xDQu zt*_fS-KS&NOX#lj4lsPshY(Ws;-@!yUq7h*_k0NtL-5O(aXR2UNIBgCs_slRhBfGw zSoBWf;g0yMbkj6;#o{MdC7E712cwB_&#{5%$x)Fo=DZcbU{cqTe+s%C+j?Z?LL7fd z3ebp!a}KGEeTJH+B#?9r$$D2B$#K#qmrz75>qwJ?j0QJ?Hlbe$ymIg4zJP{XdNNyF z3up$B5Q8mdmaW&Kdtfi*C2z%MYF2}xX6bU=Sq%l@uSr@7y8Hjpm&5?Dy4V1OEeCa| zY%oA&4?z%v%bGkap(KDcT2yR9gg0(^CUaKHc!pXghIlZZW*wlEZ=2tTc0ds+`j3h- zZcA0m;T|hovbBOm#m3~~NsXH6OfIGn{W}k5uMOYoUf9{)0tova*!^!h7{{O|+DPo5 zh_?@em8X!O={v;aa#mD*X4uu-aP+F{U23~F*&;j{^#*|>W9e-UQ@%PFgM8}JFMnm| zR~)-Sxw|&kU?HEynH%zwl4W4T)(oJOg@F@+3!Sh-Y$EhnJRT635o`hphTQ;QgGG-V&8lv+Dnnkm?pz=M9@=B>=?C`b6=L$hcY$ zt}b4+`r%ag@k`K z-OW|{C?y^P2BwN)ImTBp%v|BTMLlTUBPt?qY=_E9o>R3)9D1DyfuG>KmoyMdg5gm* z1b->2R;5!)qshnG01GZ3&K|*53;0bbm8@f8p)?kP4WmIBEh0r=@jDad+&*!C4c@YdA?Kg|72=q zq|c3(8`0pWY#ss|v2vgM1+!C(1uwq-YWYbFpw`a}p2Ysmo8}IlBx*y^=nlro@>fy= zOQCF2(c8srUo(bKFVq;dZ!L! z(el++FrH!UYZ;kJiymo|Dm_@H`u_O3leLH>S01kHPt~XUW8A_f%VB3>7Vjs<+S;pJ z>ifp)a5svLPT6J+e?4H(mz>aa8f=A6557G=4Vo?BX< zu(=-bgk}ARCyYRU*D&enrsk#b)RS*w5B%2Aj{?^0pg2o}QzW!+`umBTBvGy^+4FjM zGiz9;5BA%{_$MRFwgVQRCr*)U$_0*!2US3Fb)E@_Yv{i)@LuP~zunw?G_r9mkp(wy z+T6Uifi-*n5Qb~PV^F&_z%F^W8T1_(c;w>-E4tG3IC}b$3u^KCftrRRq+`Rp+xzGj zA6E)K3Co*s^t`W&(Njpoc>#VZn_zZ|wQJLZfeJ;Q+cz!aK4`P@*n%?>g3J^Pc#6!; zCBh1EfRo(3OD(R?9+U%gtLJ`KnVupL90omkmmL9O1WE z25laR2o*}XhmKT3zi)b(9_WB~fcWE~&kVtH^hC6eJG#FR7L8v(_PT6j&VDtWW2K$lCdDjv-2AlyVF#pjw3%@gnTFT_N~Da|Xi6#7xiRb4@r7UI%ih+3pFg8d3@ zxu)86>tZ^~SAE}H@Nnq_lGbV!X6WEGaa#43w@7!(B%)BKt_Bneut}9-SIwMG-M)!% zFiuWbjK$-z4nrL~98JE~Zi5F4yB1~I{!LZa?qo;$*MUqa0m#dkxj(~Y`-8$D#l-|! z#r;kM@fUO8Yt)JPtH36sSZ1|wnS5fYxwAk(U6eCnQY2LNb=di&n4vPzX>L_doc(o) zRE3jLt&22Rhwk&ID5DgFp2K^?$D2R;c=Owe*Sdbqx{Z=mO-oWfl%(h`S-6QWMC6{ z2Ay@@G!1T8zW+MAUF)~a+CTb&ML|uB#=C1bt@-tb^l8m{I>@o{_J?bJN5B@rPhuUx zGe}$kH-GjdL&bs0Tkn1R;fL|crjJHO-t{Z>4XITiB!MzaQ?gAfkN+Gq^_ZIN4IK`y zno{MQl4`uy3NfBL4$f)n(&In%7tf3MBQ=EaSadX+>|@6W3Qby87$-|{sChuH^ao#3 z(sVN~oF^CuznfSRt-cz#pvewD+@1Xdxsdg)C=A8+9Wb8^W}EJ2&K*-!YbW}in%367 zlsC|ArZCV+KWDotJI;Ak&{}j&_f8ia;419xQHv*k>w>x0tl{CGmt!Zcz9d};sGm-MN{Q5E4(;Z9JC0#JeQM5tHBl#`}@!7?P%mX5T6 z3Ux_Ma2T{8KbSH!wf)zM9vE`px=TXn8<$$wTc#G~J{QctzR2XUDYDt16x%VDOJ{<( zC5`lpIm@+{3X|@CzGGGoisA5Yq8-NjCg#RMj7wn<%<}oiK6OgzkZB!?S9a(Ne8El* zh=ElIWI{=0f?av6jY9LrT`W&B79E}IAe{GR&UY|l)2jTl$_>g@fSuciRB{w|zwu*n z1opxVr(LBn=@=c7f0$9?bmc|a2EiX?4m41ee!)1Ympb*p>;Hl@i5IO;d{XwWa~Ar~ zv$F;AV2y68d^ysBy(RoZi2=|rlB_|k($_GCqV(r4au7*%JoMO#Y?k1P6+=%T$*_Rn zMPO;3d-l2KwM=Uf?#vv@dmDhz zuUQ#zg^OSo_c(fSKS@GXn+{$krB&NlY;hf%ubB)u~m=y@>D7UjyMUoOapJWGfyUE@1&R6ul`$X%4gp@c@$$r_g>hozuUE%Ym~$&( zB(j_*`i)MrCQ5)D$h_#Bzz*?F>r!RI$&7A4l*QH~FIRCZPk?o#hAf(5`cteC8_-M^ z#YWw^{72Mf6yc-lf~#oNWp*v11DMl8$dAlEgJF(!zz1|&a$#tzsbfU~Oh>ma9Nlk! z07L}N$c3Ay`qo)6f)H(4Q;7BbK)G0`j4q}XGa>>u|Gf5twawz0TdXnKooxU`ZZ}zd zJ^eGJXLq(?6O$}DfAgXue1$QF(qjLtw4XZ*AbudMO!&OGWL;H`SDtXVa#b}&v& z8J>w#tl26p@JVatrSAFubI*MLg>~x~peCV|HH}Gq!Iq1G*Is;%94&qg*42~Fu7S@q zLI~(VhF>d7UQ7oj%Sh!7_89O2Qy8Bus1WVcaFU3G@Vga7=+J)VNJBJs)CSRqGq?4P z(2~c(P_hmUU+Ycfq3PZG28JN*T_CCNjEXCW7>`t!19}|;H$kD~xRU-^5NkqT_O1jx zOb=Xf=BOX87`CmuZ_IPIvZ<90*BR1KzgmsLd0a##fEbF7mI5^ns9CY}6L{Gi$LU>j zCz^YabaaYQWKL@F$Qb>vG{(R_3<|g&nwV)&@-EdoL?Gez4;@|QMV>&H@MBBk&pCw| z>gNXxV+S%d85@Wc?CmK};BfyL8rp;aL-N2IltbE7CuRqeNsEL?>FK~V!8IW!g|cxA zibaGai+)91lifP9?Q)`gkdU1FNg^>c)|gS6=>6V?CiS zf%AX#yUp(l&%8|`ed6w$zgtZ?HgI`^FZwZnx87$HP}%t3&|iEDq3`-ClI)FxJoA0- zByynGuN5Pxl~z5+!MwKWtOjP{jf^wH3f){HvSa!VG<|qNlLmSFrS5h7Bd3oq?7hQ( zv~d2|)rC)B{VtuEzX8{v3n^jxp+({W-q1W?@1&B=#pVBf?5dNUEmLWY8rex342=~X z4FwPC8;5qJ4K0Zve4gU?>X#cRQL4gokgAI7Newnpt6~f0X=N4Ij<4r0EBW|}bVuRL z#Dp4d%RubqCF2+>tP;X5>Rt0FxM;EnpXL=3rkFwoC(5&RNw zyM=kTZn@!WrbZC0RUs((fWQDi8mY*Jm!*vdo}c{;8#EkA-qm^KK}$1*FN&uA*wU)A z(t*0$1DVzNmUOuTb8>or`S92%W0$nvMc}F_-*2H&r#_U^PdjAofSClw)XZ18Sz~02 zNuS)UW&0WUtK;sBCadIqbK+)AR-BpQ+)E{^T-y7ViEjjeIXNYgz`=j~bQTQF62b(U zD6Q4k*8YCohUV2Dy-x8X@*Xgpf649O9J91G#fg1*LhuUU6FJ}`wz4m@WM(7>L7q`_ zBZKD~7>XMd39t;<|FRhO`a_+$L&~#={(WYL)i+s3(fV-e@50^9DKo_!;7&7+8Rjr) zmAT*y_Tf1|^(sX-9y5v&v2Htod++GrZPl zjW1q3a1MqCmlnrs?V^wQxZl*5iS-cTc;VYP67eIYA|%TQ z4&pOT3ZE$bOnXqDVd_|I%ovL-pL-NaVfS3aI`Kts+hlj!17cw)5G)Pqqa&URwrI*X!tnN ziIl3=yH>0Mj3bX98F2ELr3t4cGFrUT(*cEGG%Z4FfrT|zpQ3v-go)cGwxfHBtpC*kl2%c=5yuq1g(w`Bb-P?Vd&JI)P+(Q>yiy_; z*Y5Ro?G^*lG)^$)BK9c@@~tg^ATpZ0N6{{N;_e6Un|+P1j4G2@vP)p!?p?)*-`fjV z<_@Zn0}p4XrQMH+pdFFD8Gp%O<zRvm9!s``jis-~9L zW1^+LiqszwFTu62NBuD=x6m_8?dW}@fO-u~FlI&OQ|*l&OCg0uB)}K&*k}bh@VL_{#CYTjjv=(G?A(}NX1`x^WK?(Hi~T|d&ITuoGNq3rJ+=7djnE(pxHm zsu=l0+gz1pNc8eK5W!?>AWnXnu9)(2otr;+!5@v03o(-RqCqhDOp%o|ZgC4s0NRO) zN?Y;g4O8T^rEQrvqh__Vj3FTD;(+c=klK=S6`=YJRt;xJSvwLav?PC^3_;Ki({37@ z+-yt5r$yJ+=eC+uUsP4!rz$T{VLgaCCT`HWin7L|Ow;ZTOazwq4i`sW4x^P>LwexNe>@q@dKOM4yG*v<9*LYlr9)_N?)07z#MzV^A*!?5bp ziuqSggow?eqbg!v7S{>;?q)y$1z?MV&vS2rre;Sj2RrIgo7xGN#lelaLxSYhFPKr; za*5P9B|Iezm`^^YmONY9IZk3Wd09<~L(wgub`$(|+z(>7Ux0omlaJ6BK+<-%H44*T zDnSwX%Zul7&M!k@<$~xIXCKb1V6sr_oIv9jk@bqTRkW!n#^qU#>Kt}7b~m=5&9 zg9b9l`W!4NzDlbXqFurg$Q}S!#2GlI^}#FD?;&&Kx&A1(`zb>QasyuFlhhGL&G)S5Z&;Qho3%SQ$$^Ryztfu48|6*nbha*rPTuOg6SiUoTd}{jbA> zzYozomuY$!$L*d$Gt>q4eMlg&)`X@J6`3XA@!;GJzUX1n4!cFl_%T)q>(4KOq+a~& zK3dUbzV3aJr=QeYScP?>n-n9lTQpYxW*(I%Kb z)hdYlMir=g+$n|=ZGS={%pS?`59j2eI9$Jm3RXIrCHCdq76P}@K86R5RGVx6+{2mk z)Qd94l)_uo0*x3nqY}er{lC5Tj5vxES4qO-S`A4AX;nhfc$ehrL86Fo$z~MOGWN($ zw0C;l5NLjO?)ZDsL2mfxO{PBHO^oRZIbJdsk-5f{(3)=)wp~CGcXn&wi`PAdQv@t2 zZ0?T{9iK}E^53w|(2|Gs70O_`ym;mw-jQh;-ZhFhNK#0g5@xnn`(U!@W;|#@Gu(zh zredx37&f6Z!UcGMk8Yn{{oNM!46__;2^#6WA=l2a!^^L(Jd{i*W*szhIl->Ed&S+%BP^cV7GN-Mjk;>88(ZN6h%e8^Zl3aeb`uc8c z{~on%+WcWE`4OSUxec)q*1i7bkJ~c@u^N7(hX_F_FIVi=Y4WFK`$Mfmw_OyOBQZmMe``~ViDMg@W+kqe7ix3Zqx3*d!@{ZZ^N0h09Q#XV#K)cc{~vw~g8jPA+x zp^y6Y`9*Gu&}bHA;g%LSl`!1Glfn-x@fC{7y;~NKpjti49cdckPL-_c0QLz+EJ>P? zpE&*vlS5VY6I4<^VFszTQ-?jVGB|C6U2WHp>H(XsKPOjX0Cw9eccnz#G^{CvxK)U#4b6eL_Su^))x6SkNu+>QdarZt+M%OZ%S^^DHEAC-vjmd4(h2waL0bVc0F#L zN-zeoOYkF;;Pqh+(X_2jj`v}Tn#Z;c04D8aWf8rts&7qJ1o|=ENutvV{>%9|fALdL zR-P}7P6+l!JL;zJ!a*!2KkX86G9u&VoU*oKHhn1#pRF0&c}0^>BUaRr4zKzPUi5!r z>)d=(zH9<#^WI&_-x8o56zh&O3D6QL|5T33guh#-x@3b`orQ$P=mwk zjgRyt+|*MrQ$e`UJG1?Db`sAVBTHj~qK{amNxi0|A~n zv(v=)1rmeCS8lu#vzjHTK2_rai7&1wK4z73=`ve9tb29eaW-4c z$^nD)jMi|$D(CQ!)8ZrW0IIrhKm{@mpVPcW2a=BBKhi>?y61?Z8J4p6dR2}~iy}^o z{t&Qb9@C`eEh1YhCNRaMU3Fj}_Gf_v_@tzmI($f~q&hl=oltpp78!^*pM={h&8j0s zv;39+4b2KCrpGi(%ab99PTD*MQ5$Mvzgg%(e1eE@IlW+D{Y_51;R*>sC2b54!^Na4 zp{G(Gu^@1cq{|+X5b@~pJ?<` zNsz|Fr))a(DVpV7742w?5Do!9A1VN_7QjT(At~v#C7|I2#C-DwdjX2O3Bp=eocO7W z7|wAS6AxwlS_KE|m8`iQM1=ss+Ee?uG+O~|Lf;yiNDBT`CB@;b{y3< z!$CzD#)wxj^HnV9iGH#k9W>x#CT4ty=7w!|&h`1@e5d&_>AVF^L%Oi7KnmD9qv=aT zp0N<5V#Ua~;Vz0_1WQXSl5ltRHm>Yuf1$NM3}vg#PB%h0YcQ{FRU^{m8fmGROW}Tr zJvpPiXr3r7y+qFlb(TuZ2ghltz(f;!U@fUmq@3g~73VmCN}Fv-aehY#cpp)~;W>ibztc(6y~fv_(|u zqIjICex{e~eal@u^2>g4^-rH)#s8}rlHQqfSwZA`8n{D9C@rNu*RhIOtW)z`g(7CH zBB;};vw@ECN$hi=tm)83LGu;udArEo#T<GYUp2~4xpS`K$40*aI7MBWr+^4laO9>I{EAq=zdcn|VSige$3A=I+@Mu9upyEpD z6J8YlGcI|`=U2ra;g?nnw*(tz}3aUg5w_&B*#qA8#Ca z`=3TOZeEKE#oL?SA0dd$=JyG9vwmdLCPMg+yt}E{yrKE^NVDdh&1?T@&E}DJn@t-U zifn4ueE6FU8`o}re_iv=n)S^;Z`k-j#)}fCU)ZnospEWg=nRA}#aG859FCfxaXLCa zfd+;WmbFQLW7#M=k2SVZI?WssrW?ve{Dy_y*XKV=#VbSv;$RmUQ4mp-={p_GL?PESS zOUSlZ!Icrpcfl@MX7lM3$01P{thoHIlWAwFX? zCUZw|GW4dUj9$^^?od8+p6W}Mh6D}YI95#{ZxD-hx(`mvZgoZoyL2>Oj_(~&{7e{p5rHN20@J919H>KH* z9D5K=R3i8~q5bH8Kaar(nx@7s8vIO8@56^&@HSWi6dOjoWdJwL_4mu?cs-(a?P(73z>n!29izc_`ZH+C7lMMD zXvLnB$un<;uL?9->nbv-D^dwKi~ZRnfEt*6v%Y6%|;B93K> zL}eiuy$*zmMd?n+k05H~dvfY3i`dy^%y%31s75>WPM(bI3l6bl`LQJ zlFbOcVO^<)!VJ`_sw51%VEA*nHkDeqz16l3T<^j$u0U5Sr72uf@w8;BQnXaGyI&EUBw#MK zTW|a}zsW^0cx{z++e$-`EmX|E{a^C&4cxT_iNZQh6q}yh{gAI|j4@D8iRmw?8=qz! z`-FRRg@HPjOmbs}TsDt*Jr?lko%rgd01iH7;Ueo}`pUwk(fnhscz~q2G>vQTe)A`) z60QsG@xEk{IO=r6zk+{;Rviv%+GoznFOjHr>@@Rl^{`s8!Z&m_EfXxQKFsatHfSXg zGXplvWLTRj8fVtdL;s!H+v<{Cpz|&Dk5yS%@9^Da|0ttmAYUBmqNIzCrL2V4f5zb> z79tEEb}H`Rnx_A~`k7{3s)b_A^XsqVeco~D4~m2}5ZEMMh_X+v<@k0=QN%YAIseDhWZs_Nez_KegBbDy~g zdPj|_AmyQXu!e%Oefu}~T#0T5+T7*|@2Otf-ysgIXP#NV;Tegm&um!#%&$k@?HhNq z0lx=A8aW)vH_Qp$Q8w4&66h01!#B6XTsFPKkD_KF!i;){=1UT#2Hf*rK@yDs}#Vd6blJWq6mFGK&4jn6-aXXPea< zK3oe{BN&7K>l#E4{=QkYCg(AhF2+hPbWek8_ta$I^zQqgS#r1ftnGk^Mm%>$f$ z7XerZvuim8s=us7!E#xcB@n8+5y3EDNmaYwAGk=VOu=RS{#NiBq&D$I1dS_o1VAn? zur54Lz@pV3KEIl@<~BRTE2gb&BLnOsB{;vt`JUtuMh=5HhsiuHl$5_DITM2pu91c9 zTtLx(8%Nj{5 zTa#FZc)NHjnSb}uU!_3=SS`!Pb*C~6PhWJNrFp580DXg3osHWV`mS}q zKHj}fmef637Y72uNlF+o{DAb#oIAWOz~t^20U$$FC^j9KQN%eDr_Ke^?^`J_zW)64 zf7yBcFJELDEL3|6}v>f7m#(ZVd*( z^}lI0uU$8SZLnFlcKyejM>hRqgEr$hb5pH$x(6^7eMi7{GU>}&Jg5Km#l{sa5b}BK%ZAqRUYKDPnLnjqoevBZT!-jfOd<{hq#w z^=o}ZFX1?Ol|ZqV>@z>`S?d58`^C{Mj7J4jm<9ExA^Q30CFv1G`j4MxKty<~Qi0?| z5L-Xe&=##s7661~KNKJiGw|n0qS}q7U)k-@KPh%!zk@*Azok<&IDCDFI|YG%R7d`V zFA{emya*CAy##7s5_X4*T|$cRtkPn!EchHFh8h|Hk4J=T=BdE~TBoE036%__x_5B< z;;|`jK z4embJ3{aMb89ga#P-fMxxR%|$ccIX7_2hikuYF_5UIal`l7NhQ=s$j#_m(f|F&&`$ zqCn>_iuUj)HO9V>8H-FkgBPc+6D|eQs>Ui_vArQnSv{2biu~N#f_&}^mT^@-v>nw| zh%Xj_HmaxZY4pnKg6Sw`9k<}rb(IS5(ZL6?f|8tOYkkYKJ!^#i20K^!kPln&ifd;p z`40#>*_sK3pA|W5az~B^WD%llUp$FDxkHk~_a#a_3h|?!48p?g3(1 zN1@i)`Ei3w(=zve`H1_!dc^&=9&tZ4pUZwbcl~nDI9MZ)htM%ARy41#*+{M-o z!%ZJlc8|9AkGV?GaJv?VCb)LARH)p9K^zKDbeX;b?Na!r<=WLe70vqj(;YO;i(e=* z)6xps-x{8dhvD;?a2ojx^kda34LLmiDt2Eu)^q+3D5x)PqL2FxAM;M z9-|Q3+#RsjvR1aFH{L~J1I(tc-(>Wadv;Qy#W^_Vo;JxGU zJ#crh(@IuBp04PK)tG7&->;D*YRjuaghSlWCyI86lmdN(I`#V&`7n5vm=iv`^#)4Q zFrI&i6w4FJni?n%%_DV z5#&;yGFfB7n$BMY0n6Q=zx+Cp7da-ZQOam=D4Rmf?2Zsu>%|`}!!f~Rg<*^kuk0|} z9+&?pqd}OD?ro*(v;GbSfNewlaN@O<*+hmlp-em@hSmMMEIFmiJ~_n;HZyz0<_jVP zY$>2H3SKamJgUiXVw5O4`##iR3M&1o@it ztez?TJLOF2-zjHG|IS-O=SF?f89X=o_Xp37{{6voqklgKqO`M+(Iv2#(#J3;*525@ z*p#m1W$8y=4tFArl7l_Sn}f~In}co7n{CCuJCWRwNhf5`?3cH{;eMVy6Z?F6fA8dpgv}Co4MyWsEIG~y2Y~WAs$Vce!P<$)F@;Uf z<_5E2#Zr}L{DN#ZVUhQxwJ3Tk1YlKH4;-Lvw%FNh>*}-%M766`KXycIRhz4#D4VrP z5N=w#K)-?UeV42a1TxSrOl|F!v1y?%{Wd`+dRK4N)6^fc&QHjpM?Irfx=AxFy-H9H zS1on3sMgenQO+fEfxgSAdNJ5M*e)CMt+OJg(8W2;4Yl)4!5@rdaQ2Sz-OzD9+0-GI zkQvWJ1WB$D5X|H<;(ot@NtN&74S9yx+VeA~_)*YjoDE@`&%WS?5BkM2m|?c6M<-uI z>|`3V1PC2wZ{L{jbNJDqdGZ2a${kP3Oknatdjv@pZ+z?%G_C#V{$`BqF3nR2QFxg? zt?x*#o1N^;pS#q_a7^aDbumWN8f&-1Qj-NTyl*>r6K(9rZ^~k@Rh(1(3!gSYSFVxX z!BRk9kYcItybG_A1-d&4&R;I7VaxlYL&ysO5@KI-8nxsYY6)vgsUn{uzbPrn@U7-(@`qo$7QLyGtIUSd=bi1$|6{0)|Dbf(x5xr zLA)qb|g&C4+*MZ>upB}a&dxpfP=5-~!|+s38|dIARsKUc@SJIKHquA`F%P-37{;XfI- zMA?-)ra5*z&9w7l*U;)94p5$trSC>qU>5FgWwBF<-1CYjO&^_Ld!w5BSAY5J51vRa zM;P?ro6W|vTEsmci=;B{KcNHhF0D)*^;^M}wsuAFXU4}u!im9*WX)%BH zKMWq8VuEs=IEnhpADQ2^lS749G=TSx`_gX_fk)!Wk^8{rX}rG}a~bpfs3B17jJ<~v zxfmLDZ7J|o556>w4`$(*j6N0-krl5TvCK^EO`E$e>NlzDWKr1nC77|=buR=*VbPj0 zW;13+6}8V9B)!9$EbujOrF3O%9Q4C&Yyyz?jxv^a9Jx+NMB&y`cgjhvd@w} z`dO$6e$cFby3p1BON4AbMOLDvIBY8zw%Xgtntxa!UtpF%$!*sgDd8qMQb_&#I zS0zssYSi4BgiN5Kwi@f&`4kftv-UL#>3E4BrhRP&n)h*japbo1hiMLR&J$!K<8Rv_{lM?%5H5D{~q1%#MB_uD<8m|k*K(=?RT zlUW&Y*%#zXz`;6BPPpqqij{M4O2C~!4>ir}Yd3D(u(5gL*Z*_moy{2!+!;p+ApHq^ zS6+w_4HdZRjg{LDYRw+UYovGkHmss@W{JJ?9Os{8HN!J&@YYpg7VXPh3u8EST$um* zz80|r{1QhXt%NN@F3qsMMO{kG%h5~pXT!T|-&;Gfv45}i3tbTS=#Kwr<-|e4%qp5b zbUjgJy_sX+TL&&kzZxq#|5R?jAG^m*%wX*8fa^;hlnCp?52VPCj|@D>Te~hp`yHsa zD1j$FRhV=VX}buAtXT1do2QyzHa4C3fx(O{FZl0L;#ZF@L9P;2aOK?N>fmwnm^%F7 z%Asm5GjKu#H?V)J3W@L7iOX?vA2Wof00s}__X3``Y!++pI9>Z%w!o@EB*M>3hriUQ zgbgFR6h2O2-?buBd(EO@QM>D456^FaboRPNHy;tEU&Ey?#-93CNbwvnY0U7|%__}! z5|pFht1th|KEOeNWaz{|z|6s-kW5o}wCj`DzXFdIEK2GaBP0TRhDsa&AvapTU=*#t z6R$}@?1nIY^?UxjBuNK~2nSO&+Z+JSfrww6$=Vn$t1!qgI#ys>(kD)YmbjnyuE@4j zkD8iisKb`9HLJ}rzz(H)5cQ&i3q^n|QzUOGB#7S4!xDb);AuoqdQowjpxJ^dgNm3t zDnb$&6aAD9De6@UBUhdcH=$5jQ#?g(d(5Vttu`(bGSzDZ>lz!~v>6lpZ<>uG?|zJ5 z-G=q8&cyRfD{P-Rwdl@exic{eME|6nikJodkQlZEJ$`T!j#|uTWHOW=Rpj4mQ5G=ADtj!cXT6hTRI<4`cv#K18W(F(Q9Bve@0-Q0wR% zn{eqe2vi2E*!?p(r1XluPm+uw+7+NZw2xzeT~51sEF(&L7p^exY`ZI|iV%05>dUWr z_BEPBr$R=FW$>@Fr#cVs9)SvU(p5GXbn7jc9?O^AT{w??rG6M~z#C%8ArzsQQ=PTM z&sM#RkJ(;WSWRX4n|I8=qShgX!?ljndl_T{LvNEur@uK|s((ERS04Edc7ZKXE6h)< z1V@_*gKJP=T9w^sEuh>|n1;r7s1Nlu!pJ12p!QnAfa8_>fvulsrIA# zlIj#*e#pZmoKEykpmMVBi=V-~>_J=<+L{Z@NeK0M5rMJ@cK{B1YLwXYyxid+vffV6 zC8h<$R!O8D5v5TBCAvtzkk$0ZUlpR}&Q^~NdLzV?q-U7xeVS3U4u+fAuTJX=4aV^! zQSYOw(#K+2wCnwaXh7UkPb$7plJu5ic0%Mqzyaz*f+mn>aqyuv7z_5Tj0m$OrbHMF z9Cgx&2hcDP9WH`PD~`?1`FnS36j!aotuj`y>VY$ zLDC_^BS%2Ywogxky}VlNwuA%P^o3;0n@6^P}4B>mPwg7Z{Jv_ z@vQAk%M$DGB4d)347z=1v(wgo{gXITPcB~GE8eUgfo6#-S7C*F7<3M3@kgX|hSlp& zK~Uyox6Had#cC#})uC$|GX1YFMP`EF0`ZW)bBCRzKgq`Ob(4RV_GOIFIc}!;fz5*BB3uKdizkkka~i^7Ktioh7rUwp7d!Q={l4$o zpQmhG8JUOP=lGSftX5G1ksOnKL7*m~Df3{6peZQW;1b~2hNy(u1%{7C5ME{R$ab%2 zL+cn#8n~iFF>rR8Li7e`QG_w>ogv`Q4I-!VaUt919^hCam~Z$C(Tm*mr3PAxq`_Nm zFRwV7z)%~h0sJDbGsO_tR5=Ef87kRs5)E%SX_QZ=e9xVw5mX1%r+#&)p>Usk>@ihm zl3jws+&v{XJnEkv)%PCrj#eXLY`|ru{&-^3s*m3P-KGd9V3;8yW?*Y+mR3cbQnP7h zwwvdleg4^q8_~QBYqa5q8-B}2^H>^w#SD#c8O;l5W}YP_i_PAZY{E#}gB!7huuC?V zFn!IdAFkQ-{>y7O_M7rj<2JZG*^v0Q%D?f><_&KOF3Ay=QE`q9wEVee|C$D9+X&}1 zvKi@axu%N*#DSGkBaW`I)-%1Z>wd|BwC&1fJA_;nr!GB(PVZ??k2gLP-fAlKLmb}? zB*I8Ekbmk(blNp}2FOvJrk_1t>IF0Xfcq4^$Ap|i5qAox>UztcA zs7*-vS{Fg)rCkix&b)EzUc>2LZx$zb3>AO$%XX}q~6=lI~jiSw&g7v#)pi4C)^JyYn7M z%nRcALzHZ-enOx>vFWKN-vp)Ac4mxK?->RQqd-b%z45fmY^J`IPm+Pnof14cyEH(Z z@g{`Lew?MINLt{Sys(5jVbGq~lr!et7Eq^$v$GHH!ec8U4ilX+On&9|*9?Q%DchvuDTQKMiASwcP29R2OW3_0Qv{$+cRLx^K6R?tPNm&Rknsk;1v}iS zX%gWNVBO`LhzwZ-+e+1f=Q?~bcz^!f+1kB6%G8+saMCB`r(h`BvGMO*fgpJ9dE^ye zk7m42IgoS;A3uUEChy~e5|?&8@ZM0*d;m)+*1WM=+fr{1`9~&7x*Zs^)f%rHD(Hv) z!~+sCAfi>0VbpN$E`*wZ!EN_R`^OS;gg&8ZO;mXlRZ_3zs0q2tjw4=AUd|7MeBg$t zQ@2;@fm64r|dy3-Wcuo>ucV5V|5(=k%Xf8 zDeeouW$HXyxk@8Cx6Fb!4nn(A4Ht@Nn$&JKg0KMdUfX`__ybfnY^1&>j0G2w*+o$! zo}Fm^^b9!xXcGr^MK^jhlG_|$hr`sTt`nYQ;v##P2|kgg79KiJ{op(n9*}-fvDj1f2fQ$N zIkOo8ebTnD9a1f?SkSS(P!p*o5QhIULqvBD*LJQ~BDLn}i~VxvWj|Pmq{-$LA#01D zf-A+W`!(w;(#-4)#O%#A8x)@fTcER@V)=RY>+Y&XH#xJmr8a%t!DwS?TN&{a7p$qzI zEW)lO(a0(lZr75!6K^^?zsxg_*23*e3*YSa9#9v;qFfpjVFes3D;8|(64B&w+{x4O z*f!$NSQK!Kwm;%c|Gf5twU4MH5h!*XdwdzGs=qv%9oOMdIFYn6M=U9#d1MLq zRR-T_B9|04s-A{cMz9*|Kzcy5{Ir3T0cZ~lwI557MF{l6;(7oLNq?0I5;2(^Qh7of z$FOSS7sfCVMkVBh-;K>Pdjup=?=bWJRp((`__Xt_WP9!(<~V#fcf-6!jU2qp3(Oi5 zoP;$FEal}q892aTB`x5FATRH`fk?;61Qn8iKHIo5m_rmX3e^kK6i7j9S*^8DZwa4u zPw2!dthC$P>L;+$efzW7wru)eH5={UwK=7IH)M+V76Q>)G%1sk(d7|2KoJb2N&cUHOvSO@y9GT{m|&A0TwtV*-$-`VU}4|VPKj4hne3Q9e#l!0q06L-bxnzlBbzr8aQ5vF zN7nyl^ZN<))91}>)qKi*5FqwEYtKrx^{|E%-66euBycx)DGiqamb6(whjB$SLqv9oOXaE;92!dU5H8w-9IxLUI_BWCBb{q zsTgl;E|8so!jOk-c$Dr~C^g2%Z>l`&)nQWc2xPW(O>|V>Vrxl@(KehF+$dNS#2Gb3 z)rR1Z{u@UxWw6Sn4~)53=8eR@)i;cQje=*7dJy8`9IVHb+*nmI@N)s0ayGFCGn|#M zM8K1F&-=oBwmEbup?kAC#1x$*_y@;Iz%sK)2tcq6I-?JtUbx!N*I>#4A%AG#gK=<- zd2f$!dGiNm=D#}NT6kY0;tQb(7?%KS$7oG(nmMpDC!S}{PdV{a(eXQrpUh+x@W`&k zyivU?RW=qv__fZ$#dE!rI6}`zv+!BOmyU?@v|z>JCsz^v5xk)}&`Z9D=8w;;sL@z; z>jmBFpfRN^>$@K|EtJQZV5;Mb5{`Cy2mD`$Y|eO(BT-CrccFT_**ozdZ~0HX+v(mv zsf({?v&h%8gawr6UZCF+F*i##HR0Mj3!^uBQ@6C2BZwzmX#_8Muoc~s2?5V^7uW`< zaIfMju5gJOMw>2E0P9V;ZW6@R5az>I7tbC6u3?>xb5gfORLy?n^y65L@elB!bpZ~n z1F%B+J)d%xcYUbQJeSituv19>@rJDjWJhw>Bb;48?gY$qzO z7aXsOi6(U3uCMc=hePp+v!rqY+9)L&TGcD(AKt?jdmLHUho4tHLXSut@a9nL_)xYw ztK$rq2uTZe=%F1EpMv|*iTk)mPpEbHn3`M`k3|F?Gif|+IW78-u;Xp@rj}WrrIOZp z)&V3Ul`oYQDi0^75%1&dKexqaO}?E=!Bypf=Zhp~d5RW>AwJ3e)$1@~n1nh*7Eq8l zigZ=aF0oCbG6$}U)3-RMz6Y;TnG`WZ>=zWj#^y+qQVpliW-11Fvu8JbsCY*DLuJ8I za4c%c2Uj5qC#{mG#V>#RtCdasLol5n5@)ACskP=GDthX=DZU7#HZq=p+Sc(z$bHW6 z8#C%}J7lmBJUTiiT+Z+-ZI<*3M5jO{d66h=EShsSi6CysaPQ)rbT3$9w~&VeuTt^K zd{&;~qUv{VunaqOSGRu2XwTXYd#Mj-DZto)xL2Rb)D$G^K_pOvC~Y~$vI`$%_K^vV zKy0NIr?3gm!@1L(-@V;Lgx$?8fIQy7afUZ{`VRa1YUEJyZ@mW0Osw=yO|PnmZgh=Vwllp%U34(In$KVn>jj0w|uRMRj>7t!GfDvk;l4lJrs zgEOy6ESgGy4b+2XvSZNqc%5jHPc z$7f8KbcoZ0Dw`Bpn%%&_V$knhR=fw1hs?Oy^Jl9b~V@+#}*HMLj4GLi=WPj zP=ze3XU52RB{ok1huDr%Iz>0M8)LWoM{ObE@wF$-)7t#87%8qo?L;W10PE&OyHwsX zc^J50BB0+9smNaI<-`?ksK=%>f8qNq_vP3u#UMTX*#5-cI*SG4vE zE>(zsANFPgWDUpWf>;`?lpndP(oGO*i11ECNWsyCqiaTusZip|?ILg^(m3w6niPzh z0*mvSPhQS6qAziKV0*>k&SP^KeF~W?{CH$I3U>&j9)slN#TugpB4g!af`|!VwS;!XVy5_HNE!$KbMv;V(H| zPKe3oz>#HmnOPzBiM|>JRO}fG`{p$B0kyO_r4E%1f@DYPo8W^YN7NhGC3%rdtn2rMwJ8!#3e|{1D~9Gv(qYsEt3Zk; z&iYlNj*v$U@?&#>rdmpb2V2SHBOVo41UBl(geRy&t6%)#?A-js@!`9Pl&hcfDU=YLdY4gQ z75!4Y>`<+K@~cNadFzo+vL;n3tp^LXoXD;-pR4M}J=X^w_q^8X^bY;;uokv;9SFz% zb&ECz25E>XsP#%E8w^H&eKVirR|am8D$Y)G2G5}-o$J#OyN*4J;0Uz3Y`zK|f}k9s zdeB@1la4ei9e6l5G6m8&*zzFYLqN0;Uf9@5_+DgpM=M%9dxB$NDJmA z+6;S$u&&R0aTh#SM;;FuvmqKr_0Pa5Venhk9ls;HpTarRNAst?SUhqINP9o1CzUdU z{HwFOP`DPU7b6%vy|FuhXLP=Z7^W$-`NbdBb7oe@qkqXrXSiI#SXimiK)QUcWMb9f zS7bT)!$%uO{%P%ok2m$J(ijd@9(kv5Ac>G6G#W;|E@@kjk=1?PSkYKZ%IYzT;|e&U zfg_R8V&C^GVT=nblyI&?4btZ+ofwk<3k@{_`*pS;jz>cZme%ejdJULEhkMb|#qLK7 zijH0VuNQ6?L;nxOnEsDa1B90h^|`0D&>z;V{g8-zzj^zek2k}^{7WrLomeII3T%1k zF77&)v_$-8Rng%@(q+5F$R?}XWM_o@|xJ=xi+K}6x{v8%9wOPRwsM9 zX$&GR8f`m2jb1LtoIKW-2*DoQcdSz?!XUvIX*sj$L#?wyz}UL7AKv+_d-WRvFPlG! zW_m<5gx9u`Z-+j3JJjJ~WYDX3Ro z^=ENy_Ps2Xz@K*(k4-`h^G`RDQ*~@?B5Le*sRhwSv)&*Y^XImJCT(k|ASO@#T$*U# z^ug6hw917!XnuzrweW;e7iIWsyp%{f=5wpqR_*wd0fZs|43%m#)Q2AiguC!T%bJvmyV=u%hOMbjc0ur$;~8D%o6mTlr7Awog-Deo1h zh$gvR#j-DJh$i-Uh$Lz$KG9$m%oBUJ!zm~=hAk-hM=g&doW|!Z`;>;kbqngOa0f(t z@?YL<(iG%d-3iX}uZwjka0XV#DdFsiGaZQngehqq+(ab14Hc+Fsl$1)Fot~@K4$DF z%GZVa_oYvk1wH&2mtTIVND#kqcli>zFwGE1C%5b}Uj8nbUKS66gSfZ+MHAUac^2yXj&IqnZ>J?`dw>oy6hv`5Z(UlSnKJyzMIE<q^7miY*+toAZJQlp-LzhHpRGNeUB!(npjZ`?uia$CY{- zAwLwP;?Ga-v08w_sZJ}l`h%%Q;e#^H_7?fJ*@&r)Q%^L6jkXH?~l(i`7FtUDHO^ZJihgA9!7 zy8Fk(#T>n~vda5aLDjrL7~a=@+K@+>=n78!6b*}v1`0&Nn5aH7Zl~GFL74{BpWjx@ z`jBO76P=7GPj;2fSz4~bp^^i2rruJvwx5k`es9gMf8CHB5jBx3%Ew&DYJxLqD28>& zX+qDFlwh|eCwRtW6a7F3SVdj89~%G)s9B_`qCxw=$a29}ILDKKB!*S#NgI^#IFXG> zMnOyMd7Cc=W&N@@IT`KRH?2RIg7V1qMPlQ8fpuPHTwBfZxiMwS6efPT*76j{|dM1@;mW#VX0VVf+Vf(QwaEy;rnc)+ub1qOpB zY&=M^6_KCCI+9-XSGd3b^MBSl`$#gF%&h7gH*Q51^4WXsH9qT^2Qe9iV_Z4A?!_7OoUE7Aa;QocIAjJG| z<}wu8pXO6rPYuA5hOn>}Cv+nibGWe|lQ(h7PRor3a=+e?P&iT@M zo}oyA9ZvD8q5`pU3HALZZIFNa4+bQeZNpUwsc|pxfXUnMe65=AeZLXNqWFLGOMhV0 zByNu&&QX$K-+}g9an0GiY4%pHOG3RiHx@VRnxsm11}s8a<7wXlYF6QRYFjI$RDI&0 z7Lq3v)Ic9Q@Eb@+B<6qI4{A2zZ~ox)UM5idGr$J<8}rBXCut%Ffbe0{*1$?S0xcA6 z*YBsCMe32rPi8^TEu5|?n}fBjma~nV(|+$elwGN0yF3V5pV0`ND1qxB#IyTh+!9CD z$OJbCUPv5^n!m8+&22lH<<&)d9jQ?|7rC@@|ErYl-LcthCm6bkYGb1HIPZfU3F@Ss z7ZfpI+!7yFgz6a5zCMMNnUrxe8Soq^IgVo-0q1&nfy4KYwBUD+*&+ z_1)k9_`l|h=1CFfcP4cO8&Y>NoZXJucHFGySrfj~M@}qWyY^J$d4RfN1k*OpronhP z9n;C;UB94s*Rr8Q6o{3y`NBYqksPG1EABYFVm$Sj+P4Fdb}P&vg70GZ zrKWtwbx4;__CK6s5bi8GCFjF4upGQSny`G6Zn3Mi_NS}3*R&s{V~yL2`~B>;;--%f zt`iPA9lPT7|8Z0n7yuf>zfb*PscZi4gKQezH{;$xK zCXF$X?I~T1-zVJ-(Ri52C4$+yqwKWd{#UKmJP4elBo+_`7R zuBTt#y5kSKckbBpG(n03&urMZabUwU13PzYeM5ypc0c{o}JuZEO}6 zdGw>^cbxA(hgL%IEmY!oz(-j6a(9Bj-n1Wve8mg{5cV2wBjga$DFxHY z67}1JqIq_6<3L%ifiIF=7xJYUY)>5qrZ_g_+ZO`O>VD#rvFxQ;N5Tl~KH8tkK3r;sw{u9T z3$AO5VSr^sCyRzme%RYjpjMUz<6rNS9~Dziyb5blaIsaf-vr9h`vG))X93nt1mB_Jc;#T(cf`hXuDs9V2k~d}#sp;AySMbFZy0 z!u~}=(}>>MOhPU5YUjg<=U7I2^ZLH_7Q^u1R#IWBGZP>W#*3bGEqd+AJy#~-qT;z+ zG=1KFA%Y9|8Oo!zokXPUOQcqlT}B?G+3JW1rXwvlht#~bn)as4T-&YfChUZ5?zPuc zD+^Xh`x(*l%#1zJ=~A(UU^GN|$4r5`uD^$ps7r$02=*v*!ynDu7OnzFNRIFcN7~*v z@{{AZTM6pyB&T8H@fmu_c5C_mc%jaLL-)-Sje{*{*XL$qZ+=lR)T?8}4ve>x zbA3avbszq+zO^StP-xoldM|E6^RwjqBW6&p<;|Pxw{H3U9!-D#;7#ZTEQh8nUnlu) zm9XV7H;&c79zNML`0|cF4na!*7A{V+Ar4lm^!8Y$MDC@x>N+#a^L$XFmi@ti=h#pc z9RK};;Us2Y<*ZYXHsU)!X)#v*E*LP-){ZJ=wSV?T^m(Kkg?n1>v|iXpK1E2(s}M=_ z685q|YGnI9D#|aVqmd&sNT%<-WcW7TC}U+KWAYp(0>3qdzNhQ`tAFr(X1vD`%LmUM z>fpU;_4VC{K9P>=4KptV4GjToz2c%Jek~Wr_{|lr5}H3xq=1O-FRJJx?Y?#4aU9NN z5Z97j8m*WY2!Qk9=N8uODex#Rn z{HXek{H*@Yo%Z+jDZGC+Gy~f-FAeQ!UV3G4>rg%qT9`VMRUQczZD?@M?dHACm2+VN zm-$c_1s%j(GtD^xFqS29ks(X>ObKeFic=X1UtgG(=5*TKFrC`St_-D7v448|WBBlH z_37reE^D;xsdWBvE5QnB<`nt6gF;d6wq*mRySJp^lk6itE?LCs1Rx5)oH?#{PM!+g zs4bc&HpdH8P2>Al?=xrA)=JP-dk1Q7^^6DFXQBbz#9I$vSie}DJdJjX^Uy-CmK2g; zFH7`=PT`#6Pt@kbC|lnA;wL}Ft3$OK44K@7htt!@;ntimCXsYv3|!A449ar#4OdH> zlm$qKKYw^{9MgYLK{1=}P|XFcmSV7fuptSjU;^LE2+#C9>&VIz zbw*(Ea};rQ_o7eMUXm8EYO?IfeR_Bn5!lq&Z;)( ziIjHC*JpGbb_&4sIro71uYQ>Az3&ZUy9F>)ag9tGe`fiU|FviM4d?dneMc&sxVEhE zsu1R(o`)y6RB+-t6#*^s0>qsmA~Gx(>60@jar*!N=AnH(15h{7%CWkMD=%BUQI5P^ zLk>Q4Krzu>EDo-kd5U1_tG5q?@W;X9dOukT2VzZwp5mF zgy7@1C~0T6W$vW$N^M3g?EH;UqF!O?A?O$*=rcGCdK0z3|cX?)zu$ zL4ZM>PEzOyV}f@ zfaxv30cY`52EtLIS}L@RcSGu%x&@IOa7tD8Q)|YU->A7QQ5|s6nvK{aHZ&A1A(!~~ z8LCeY*JeNPB5K~;w0qCcPCCkX{m{@H=aW2he(wn^Mrfcy{762= z0+Z*Vv7ha=hq;NtTl^s`Y|T2ed_Pm1n7W1dnDP)lH4zmj$ILM$Y4eHJJzU;}0d@ZR zF{wwwzJs?##FmcZ7cs;2*;^HrPP=Jecc!UelSxVwQah7K3n}2`eI9HDN4y*gOI3Ek zWd{FAR54laeI=ct%7l~PDOEy_TM2-(2fP=!aQS20QR)J_cW$KUDlz5mM8%bdUG$?m)7{E-xoCmnIaN;dMN1l}BYMsKcsf(sXKp5=#AKk?&xdUO4qC^B;3`}%R` z+~VEKYs{3eK@IkzCT6Z=9dMZ+ESk^@{X_ zU%uiDrcb$1Pw;~X92l8Dd^{ZUYE_@rK5zNjc79s|X{Ru09HsWizV=G+VNhGY{98UQsP{C={BTDD(YE9rQ0ZHM?-t@*srJKQ%)B{kg0#8XIM4m zU^f3w+b)CKZa&6Jw{Ydbli&FTt`s+pN@o^n3sLWr0%`stskcUNBEw4uAL$eGGl0E% z@|B*#>Sv>xban?uyZgV8wr_M67YHzRX}6zB+7GN~UD0hg!}xNSkz}R2P_Z@}B>zae zLa}vTyX(XWFId|Z(RA5CokD#rbW+NlrxDQIEOS`0#=lHE0-UWv%ttm%_};HFspYSm zXMftvQ>OL=0cV8|2&6q=rL~VD`?gB4?oV9f&{yJ}$2B24dUxVOlu84f8sK7g!2DJf zRw`E^7Cz^H%Gg zkU{Y5=VoY1pCqFUf12K@!!IrK`R59YJ0yF-L1upyqS?D*152Fk@ks#gl^xrOwxntv zgjJ3no@fQD9PqK*YrdI>OhG&=M$9ZbCR+WSqd^zJ$NO#;>e+vxz0WxdUz=rj;>c}* zA4&2I+X=Nmd5#9jE(`;ae&f#?V4CE4D)!wx z|I5Fl#>ZX?0U!{9w;#^jcg{qh8Rbm60npOM7)dBE#j+ z!@$GH-~E!4zCM3un7K9o_z%Be61i%-q_eq3VAzrcsWDUK0di8P@Gwy_5=210Zo*Y= zj`$CAXo!+dhSFX(Gid(H^S|7+2V^!MEXLY4X-8t#tAb4eziCGDuS4+XKnUmb;;84EAxlP zGS-{iLwK~5fnq%TOcx(~8hK4YoWTwFy|f__>D40pGOxmu!|DI>|9(MxlXLWEz!>-YR7|}UQ=&|PH4E!UXId#PU)>;wH`#FM3W>ojRi z&O^Bj!q8WGjjEJ{_n4?dps#hOZ`a@Go#aRrQT-rE9d>OHC#7Q)&`qCeUKn^WF}Vv7 zL7y#Vr8A)|_#oKO3)MCN30#a4Q5;bYDmrX*BZ|jbrRJy?cwG^`(-MKBt%(;A@%(1(uXt3$Ce1ojkDlqG_<-jmsAH+_+g|s=`FX$h$xXxeaB|8 z6-j@mE)%eZFN1U6B4#d3-;Cu&%vI*Z3-Q}5CfZs&H+w^*_i=mdtScCoKR9=ZFADHK zPBtNV+~KvY4ssrDH+7jT0Dp^q^1L>%@Q2EK0KYqPj5L{WmS}?G!zjLFE|(O(a4qWy zq*A>lhUdrs1P5f2`*L$6U-(A%cund zVLDSt1n3*mbRiFf{?lUs1@{ZSiydvD75MX$FLWKa`c9fE;UYK*&vPVFUz_@m} zhNA+vNfm$LW1i}^wBuyj-PZ3U|0-kNX`<+SRWWCHXBY3>T)aavxQG{2$5B&qVBr$s zH7PmKjRSt`B+?&B&N&F2bEpB*Ey)q_i(g&0QvoCDRpcLZ7Yd*}ehU_oDdEudKW9hL z8-BMJPdxh>fx6#iI{)W)9r)|W-tP{SpK(Ip_1OSEYx;~gEsqnQ$@0@kK^K?uR;|;z zP2BE?9AEt%-nz;OKJ9Gby^k_%DBks+vfmEkUvgrcP>r&B&#Sg$2~RhQiV*?jik9+0 z%!DMJ#IID1-|C+Pec`LckqLCud_}XBpRm~?0{3qyIXx+8NKQgTWqeC}SIZ3N;=Kk0 zrc|3Hj~tENv#m+X=403(2rzsIe9WDN!=yoO6-?{@(Wl&N{}75IbFx_Ri%_ind-<23 zF^E?0x7`wYzaR15-8{TIF4m1~D{QkWFf-i5~l<<;x!7-9LWMv_BA?V4WUOPLw3^ulY8>sVt6 z?U}A2RZ$GRIQ-7yiTA`?(lB(Ax)qVm##meGlw*jgO5Y&H@~WhKvz;&|ceOlc(R@+D=E#x`Mg-3E6ak%;QB z;7l6Xp0@o81dr5*@1DdY6(fe&mJntJ+H51t)56RpGUJ9>j`(3Er4PCWmSS@iQan2; zol0^3)y~l1?CtKvQ6VZaBwhkDouF|>r^3i#i61*PKQj%0Eqto|R9Ep8%Y+aw7P+gA z#V0OPo2p5eIt+Bz-;?v`{SOw7O)VThs^y|qppX(dQS)Dwac{i&rn>1kar!zp!cKiy z!o^{RCJ~~9s+zdtC!g5;RCMYUM`^;aB*bsyfZPtpm$Y6UIj5<}?BI{d*AY71-fzk@ z<&M`T!rkH1VdH(YJuqT6%a1T>lpdyT<-c4WTS9g{9X^reIf!hwO7YKQ`A6mU`R8_i*kF3R^dx;yBEF zMX81{z;f{_HvC|u+5-=eDX^(5Z*T7iY|)Ux970|2v+-B4g9k>c-70s~l8#Yp+2r=o zK{UG;#!@|z;{!tHZe(LQu$X1`OMctNmGAowy}$7RZiS&yx8_6=_eVTBFw%!J+IAPV z4kLgImT|J`0NZ`!uSVu%Y4~u1R@SV?W8jO$eQ%q?h06y~WIhOdWsuU>u5Z%Ic6b*4 zajj)2QTAr7H*}yfK?8okMO_P?Q^X?|*4;E~*Snkbyo#tw6~7vM zS;(-QJG5;aX6@3Gk-n|% zEz@W!mwTH;C?63dGqDvEPfI4ht_|qIAG}ZAJrL2Qq60gzFv7hmxYn zM0BIwpGmVYEZx-Obv|US6f3PuNbbV2H5z%#+_b2N$)33NvX0=8A(QBA^32ObV%V}n zZIiX;f-zv0GDn|+(xC9(DS>=wOoesg&>%DLJK^Mkfv!g=qX#)PT1J=gYHLRDhE)#DvmO#n>^ z`UHbUWv6EC!ua&U_?K%N8}Hcbs{sDF6lWt&MBw5XDUscQWBs%2$YCm!SH-B|;Ngz{ zxI7@y)E(4+Y zYR{N=Pqv1wfvtCmA?^$Aq*%e4e|+i3qH8b=-Qy#R_&}X}cP&>K9(k?(Iw)AwK^qDy z-@R~AgSJw`8A7zD2+G)1MnCSgj6}E|N0|ZVhB+E5-lSVC@LPN6lPc3DJb78_`>OK_ z1tQD~*@dgrXJ%XH({rWDw13Ri#7R8jrEAU4nkO;FZTjPmt*=psVb_*dHVyr7L$G+Q zPbE2wV;mm!r@Bf-BaR$TPr09HP0%w+ngNs|RgDls0Y@*-s?WrbHG9KBiJ)uXHFm$Y zbLWm-dp2zwB%$&aDnyh#%wfP=@iuHrzaM;MsMikXLi75SwULix@Ghi`o|vOl$hHKOn8r?fw(}v;@@X)v(m5046k+mxyy`m zt4K2=i36ze1k2&)HNM~!TtzeEM%tucUz!&OcahzC9mZCfO$S~|Q(jYSsY83V4DBj5 z`ks-!YI>G|jcdtOaG1X~gMHfIw`*wY;GQjijrm&0_>ZzJeM z^&MOf;9c2Eq;AB8uu)FbW2rX)^j}V*P6sw*RLD8-B`L-=}1VLuL^hl@VBxP-Dic2bFo?@IuRS2BZqXhr4^hd zRKK#DPC|AR#&GUHQ*)Ywnbxvj_>QbKwh?M8EFpwFyio1b&0VLp_}&L|NjzFTN;vjh z?c3wssdJV8Jag?&fy(&p+1e+yW7=f`8kptAe|q^x&@Aw_+eSWPyqFm=x>>Vm~ur z^!%oD*i%)=xu0}{_uC87kJYA`hM(79j#hJ@uRGbgV8$T`%-1Kset z0vs1_os*nNY3#kDj7wJI{5f?@(}>Uj+UVcrktmroJR`=8vUrhjx7o65tI=XqP%yvs z;3{t6F&jA|aXun74@jIOeoK3UAZoPAM#wfo8MC{G6n7iO;FxmwFfCr7qzu_K&iK|c z4>VW+glxyw2=BYg%Bqe8_Tn9`L+T91u76#ZY=_q6qBt1zCNXYZ)Y+!ClLC|Pqu)K}|aMN9})t#NyQ z&Kr?Q?)HIU=S~3oXg4|M2w0#03ZpQNTGwlPyNhXNhY#TvCn|LeMTQ?UdEQt&*POkJ zSsF2M(_TmiRl_xOL^6B6YHf_gw58n%mu~BLXv$WaB>SyrQ{NVG{G2@BDa6B4SpiC! zh5KJJL+hHP>oZYw2>ihyDBy?BB%2Ai&25Z_qQ z48f{|m`mJj?Db|>iJbByI>`yPiQ=l`aS|K7ImEgI282q7_f0E_>HH_ z#akxa>;|x^UdF1#9z(>9aX3|VSVra{eKxye9g?`o09D~NQZJmF=0>RT=*OkyxDLqv zAKHy&swf{S%#beUFs=amOi6TUzmb@Th#OzmZUh^LQ2iZ1wYYfWg4E(i$Dk@qqS34i zeQD94ap=8tVD{rGk_^gOs!-X$l4!FrQV;A><~3c`I9*gC&!|56`SZW>ZlqKW zYZBE1eah|-FBEE*#{kq<#1HGjfhTsSa2BEa1Wzaf@Rj2%Mdpn3lnuc}>n#Q4ANh%H$xw<(RoWw8Dv+!Yptb)z2W8DgKI$zo*~v;;s~4Vnq=2HR;@P*+wL7WMU#CaIEAW+> zWgn+kHr|sg>Bq~`fl(b91O>yV6cC^8uL`DhrV8`ZM`a3tz=at>fPMCJVg#0voVX>( z#-X}iI&v5i*yF(P#JP{Z^aorL@fs6o`Hl&qg|l6DkfNBx+r$e-5SqZhZe$V_iH-FF z8X}*tG%1@UrHGl;k#J&&z`%}~KR)eA{EyNN1X7}zkDd7lW#NfBwU2+qG6MTUVbfgt z@WEH}2hU4#MZgWag3YM5L@*}cj`OFcD8m|sbkM$p5GzcEfC3_L$d(MwXx0isG!$EV zC0fafdSr<9iQKKDJV0wFxep-O7)r zWSQk;t{jH-d^r8SS)@G8sY~XB7zaqxjzkt9^zMA3@Tn0?#D}lgHzf&$Q>&W~S@>*j z@%98;uj1N<5lrhdN9B(Z?daQBorg;!AMjAfJp604e`6=aLsLTsOG}hskcc&XghOA} zKOfT7;v5x%&bnt164ySN8bTYQb|8zuB}%s&pQZ57aktE^de4BeA3EQ}_akM9ws}>a zf`;FgbNb5}o+fS*G><%nfhcoZ33$761{VEE7EKYJMo<;;4o|I$C=gP*?@lU16t5HG zf-b^a&RD{Aoout_acWcS0{jBp1)nSpAMV~g>}KJCBL76$fw79m9Ra+-!EV3$ zR>*&BwXI06lNFmF3Le>18KWV<;1Qe95`z)Fto>^#C@gyQD1Ov9?w&o$iJ3Q&xK~UQ zv8RD`Q$m`$EWw*P9!brR0zp#;ul{ueeldrw>062qqr@sAyr@B25D%e?{g%ib3B!=u zB}iP9-|m_Qes9G8YitLW#|K!mD9?m{B2eU;MfOB3_%sJ`aT4xp)&ySvRIGVc|Rhy1dE_Lx$-sNE>$Tp3qKQrS8NR5OG~# z{5JBs?O)Xu0BTBp*NcKJ7=OrAI8D$U#uI%HvTMC<`(1OW=0xowkN&`5&2u|{Wrr8$a^ZwD%Hny@z>S`&^0Sc<83of-!- zfF?93BaVMY@M_*Ok}-rV#I_mb^1b0t7OZeh(TpGUu{4m6^F5fyjz!wBk50?qsW_fW z+Cdiw)A#-XGI5xYFpG^plo=`&Xo$Bn7xB)3{aPBH?0$G?038$?LAwo4KeK+r)8Eeq z3n%VV6GflrgQc1Gc%U^PvM4jGxvRvP|s(;2#wq~X(@p6~&yCz87!7gb8vSnYpgf3AAA z9NNVdDd~86KR$dQeZ)Q{y>$OD3zk?Lb1PPvgFr2KAdW8t$E2xvi-++OO%e7__P$j$ zmf2Vml8)j5^4&yKhrjy3qEt)3iV6}vAOZqQcsZP}7$gb+VWTQu@MLVn$47I)&5UZo z8px4ZhY#vT9hFah@13~;zxZ2pA^2U7Q~SVj=FflnBI~t~p8R(xnC;I;&+P@xe5eeM zf%N!DtYF0E$7ucCK3-RJFV?X-d z^HzRhZNABIh$qW>u383lArx6+|B{H6_#AOxQFj^~ZViej)5~}Q9&`Hv)TWd>61Be=;Y|)2kas&eK7`7Ck_l_#}%YYIj*U*P^eX9LLO!q{1-1>q=D7c4yDl?Sd7#Fkxv%) zBVx8PygfLy$>yObu!h}-q8rtI7WG7u_&b--J|cm0sk%48NOLz zz=ciqIcoH_DYnAGa%*fW`Kz=%Aps?uZ|nL5Fyfmv zy0a8qi3rQuy>&36Lie@7Z55ctvFm=_LBFP*d$kzr^`Odoc=se?fA`Eez+M`r)0gXk ztVz6_xDvy6L5}PR7!wp{r1^BG4rT|t!ahx7LI+dUw_4G+#=9O z4)K-|GW7=A1;4EW3_Yt>*1h>Dx*bp`a4xI~7Po*7Gxy-0tjH2+f`JY$v@PH^&yeIN z?C7v9a06_$NJiussf)JoK7Wsj=fe?UD7P|LGmeq2l_$tdZfvtyTt%meDY$meYq#sK z8__}bcU7gnZH8s2g3v;(Y%no8?YP!*{(_Qt^LlDu?umfkFFz6DDpJ~-t<(V_Kz24rJ!K3o<8 zS{%MOI2>u_AB;Ly+fIM=mcgDtv2l9*TL#Q-jC8nq6c3N ztOdmNe1R`ACDkXHYX$z`ml&>T*1pJ$nwS3d_gi-D-ebiesT#KJ9NIOw=e1o!Z>?>- z5z_IX77NdD%Zs`IrwJa4T=XkfPirMEqtXtz`Otpz>gm}HzMFg>)}_5FE@xeq5a#$W zH)h$gKnar*&A)CPWUAp8xSKpmn|4uy>n%3*Usrjwb?}X$U7NPQw(YGD;Q3U)-+Zgs zqx-jr`6zEQYhClR*ZH%3aBJ() z-~VxF*Q@GGUZVY_v!uj0ez;Q0ulX&*G9Fu!im2RBydRb3?i~mTXFCsqZ!*1ONZ8R zuX=*t0txDdry7&6%gCD`LuP>@R#r3PV%(_DO5%`7P1DE~h4%sAx0^o2{ys+i zpj1eQh}SqP=J%lIDet*2})IabuFH#j8ZwPotIbS=qgn z4mdD@Y^Y!C)-38gevn{(sIz5^M~(w1JF;=xHWpzUBum71o-M7;bMUjIklD6PI~_~` z<4{05K9~8hG<8k@P+iPD`KIfnQ4q`xptnG3_<}V~-(}sU;ezjpO zE5X-P9S37z+e?X=hHJjKa30hw4@nWI2Xnfnv%{7s#hwzIT7)~q+CpIY0)dzaGCHoR zQVD-iPOSALlkm0obLq1$x@V6+dOxFPs%}%1bx&mX)d(yJTVyIe;}Q*?{Ug^HlFDp`9%mYItq1z_KH@UP&0Wf#AucZ43Gst*zQ6*3!%LUNs3mrQ+agI{Z{0`kaUUJ_ zLZjs29<^}J&Z}M=zvl8UkH6}SdDeE=_v;562$z8e-MEo|fKQjJ^VtaUQ`=imX@79Pz^!P#aF94yYO=C(f~}I)@-qqT=bycma!qvIey)05a2dCSN{F zj-JXk;iAJyumjSp6!n@T^w|)Jq0alZZ<4fJ?x!}Rt2Jf$U|k8cOCw*+Ke%kkqoU^QKiiYHHHtJUax{jDH^eUtzPxp4)9(kjZ)!34 z1V=^BeS4JFbGw{A#x}L4-I}$h)4%jpSEVN3YNE>yN@vS?ek6@CA+_k^R-P?m{M#Jn zUu{L!8rY2yOlS?ZNvAGflrhOTIIPCFQBaE;?LZuo4964aF{1jW8J+}{q}9f4H@qD& z^SX@3d?bnEtsKC~&NX>h1e}B(7p_9I1PJW!vf0!t=lFHq$uM1WcYTBK2Y@bGUvG;D z4d|;uH||(n zrm7wmC~{aQ3lRojK*qMaoGVHlyH7)GgfL5(aO!wqTvsvmh1FRKSL{E*Q)*2`=NPuB zX$8mFaD(TqIIvdu6O&%!UPUA#wLEiIqn15Uo})y2(6P@Xy0;NKvUmXcW*QHU%#SL_ zLcDayJktCZImhnF5_=Ea!*7R0ubE%*f!T4X-kLS_%kIR-RAGpR%^IG^OgUK?p45Vo zROFpYWQ^7=T+wI58co*Nwe;;2BZwk3tms;DN-5lH4+rOD&EkoX4M5u_KQYF&Ns-M63a>)1C>U}e)H1_g z#|>?DLY8}zEFZZI*RH+d-L7y>|`QSyP-?el%-6Mu{H z$WY+B>w7E=#s4DeK+%c&uk=bsbE>kKqN#Nn7Y;T8s_elg_4?J5k-S6feX@vn2Tp}P zI_yG;?am)rxF|p39_IBFYEf)7G&V~L*$8KzJ8cJu%FwH7vco$Fc8OPpu8{?}W?S*P;1i0jdv zBoY-AL4XRGfx9oG0vqQlKylgXP1Ak%gpCH49^`=8B{bNAh0+DEn2egeMvfD6P0f2)EsT(l;r1Ej+669 zp9{qY!`ph!-oOHTwQPy69s>z^e0hOaER31x^XoTAPL_)CRuMtPNlDo~ za{-~(0tG$T8mi0Q3ZhW|Z)d76A7Bt3<;aabrPld&rMRl1krPiVP%t;Le}3Dlo`wXG z7tFi8Y6_A~OoN0qT%j}Sh4b9D6K0)Y1Y@JtW5bwJE!MZ*6+lhCMbIyBt-KBvEu6zb zwel<_U$4OQjF*1F*5z{s;ChNY7Ne&*A7Fw#HOW~xb?o8&Ng7D&(+UC>XAzgMexj3( zj6UvGs3`a-dehyBK@C_mXqx{^h1G;@VDXeO3a^~QK}-1vTlkkBQkYa-hR&m2!6=9> zr?1krHB^G@mYrDx(0^;kR;-%L$Gugz*2SFQfU{SE4^}LkzLg&@GG1$bqjyEXTe<)$ z)}qd0f6xnT)IY0eoJWuwOQ7NO0Wfr?^W-c-c~NmAoj2}X%h^cz-VIt&BTixZ2&X31 z1J9Uo&jS`fih7vs?KWL_II9o5OFo7e08xGl1M(qyG00Wu5WP73PEFe1Yt7KKwnBVq z^GoMrKsR9W-J(r-JHe+9!uDgT*JX5MN+P-dQ`JHWAW5638j^2!UH< zC6qGmjGFScFM1|)*Tl(;;?&Rd+ z-1Y9=Q2@5)Phh^5eJl@VyyUgWn{n)V)r>)b5P;Y>>l}saivD!r#!VrB2;%T@kd6}^ z%;kks6&L6DB)YHe0v=fz#GF4#n8b)qS6$UDVTu#V)%G69H&AggT5Qyti#GdKj zGxE>Y&6S_8Y_$n2akoQSe#B_y;Fgb855jg`jw;<6Fo*j>`OEKOk^SDIEwcZ*W&4&r z?ZhZ=Q3ES1mYdNLw@kO2cKrVLyNC9yZ2#7G*Ra9x5Dl3&NVQ^%hd7*YasT?^--4qJ zNg}NE!3W5DaA{a1A=b2#-{NSj`11mF@t`wyYPONC#Pm6m*~;a66l)^jgMsM_6RmET4fT=ch(HVytBKR~fSK$OlAz&2oX3D4u>$EA5IL8$a^St(aalnz+J$$lKa$8br6|X~X<8G3 zh*7C>@(5F(El%7ZU!ROECr0a4wiB+9WK4B_G_sIH&WE@#vyR+ky=Zp_Na{8#4A(X~ItA%r99|qAUHar0NtP@R zWnbyN#Fn8vL~|qBqY~g%$%dSTbETa?c?(;h9<8=ARycA}9>P?p{B(HX*rY$?^7w3O zB!cBYP$mPLxQbne(Zu<%xHSQ@^voS{+zp>FbWBOye&sKoAV3b}X1^;yEck{2>wTgq zlQl^F6StW6_;dF$GG9kwc=~^>xmOWR8$gh62#K!f#m?Eu7nBgBponqua4H*;sWZcw zjyW~P9Y)ByeGzx5jSFQPDt1&})+s=8IV$6G8dz@u-4tZURgE2r{M4l%j*ynAAD-2e0%Ni? zb`iMgP3H7o?Nnqo^-lNZ;|cIR1Z)}O-8Ur$@sz4A8pBm>VRvhA4GjOoh;!E@eXon$ zi!$HRSf-6??B&Y-8Xfp$xWON@woR|ba6W+NI_HYg+MJa$v7%%VUFOkNGX47~Xf;nL`GAxHO!*l|LcLRf*=CoIVox~3-toD+!Sg+yO zxU0ppPZoH%3P$34(W=n#S)8^?y*L^aAzSMOeO5w+kLQ@mboH+~eC-n*Q57*#h*S~V zM5{2Q!3<*IMW+0ijBq$oemEc1BT(`qqb**Q(rfXm;*FTQ78QKE77@l)&mEzDe)8b_ zEau5RE)3Q`l@dWYfw&3}-mA70yD_S7vpiul9H?X3CQD}SVc^$-YuaPr<*A;DqT7D5MJ?hxHm(0P55O6tvT!oa2swCG;G*&+Kq;(|K9Ku18mf zP{b)Q_^ zy)F-ge)=@bEX3%iYU-I+-ImmaE04=CDk*OWH(vSK<-J310<<<#wFAb|4aHw-!yy&KAx_(^_3As?fWT;% zD@qdH33kE58%1jPLU^^up^HStiFd1gG&k+QA9E`u;m`shLxs2IrWJ2Bu|SfFbv+}m z)ljOtO6B#vE82g3Z#^$}oh5xcAhzzk3~mu`7^S^aT@l2LwxR4eS=EW$WYv2MuF97w z@nI;yB^;omx%1`1Oxi)%kUXTjDhh6ORATKoT^bni{QFQl6B3s0WA4ct=cbhtmg-gG z`wB`pAcIATA4t(XQoq)(gtO3;{PMrO*oS}+b{WTCus*fwAsW*3f3VWl1z1u5n*B4# z^>ybtORp0N`{~haglV=Z>AG(?cT2qkYRg^)NbA>7*XVJyk@q z1czIYH0rkU3nV974H#8@+CvrDJ20=Y>caRvq{SpR;LM;~aWcVFRpuGG=s+Zt0Iv8| z9Qmrkqmg0;Q-K`z<4=YVyhsRv79OlLOpf&k8A8C#!W}z21-;RnGb5R~q9r`M+Q*O> z#EFA;WALF__4>A^N3@)+HMBJ}wNrM?a8cHlOwwv02`i@r%mYta;-fWSQbF~cAM1JJ z&->0zt|cH=qv8t-{ulZBD*MYLK=><+*#cZ8Qnutb9HV04~Lve6Y zuu3iY*zE#4L0|xaqR6oYz1JrE*K;*xV*&NY1Dc35`TxNrVprI)m0$u#S7QL+*p_Qp zxovxP>>(GmqeouZ@!Ix1JbQI;_oja#jAGNC9se@4D3K7+H@&>$_21F%^>zH`jdj}wU*}(gufOrnLc%rT zgu6?D+imLarznJX{Go9b1Hq%6U!oqCQIOR~1%*c9E4hM&dwa~0D-255kWtP{+=hvWATtXtFVO!Zz^L3h7puPGQDao2f z(md%}g!Tk;+_TV4Dy;Fed-h$7m1rcNH2camQ>_Ql#+DaZLynDS!RlfWB5Jgb&?8<8 z=RSg8HRD@ZhGL@-3B_5OEg9en_nAEGY+2MVM*OT_{3mK+G&6zjT#jFBfVejAwYbpr23E^U73DX%bXq`!cQ~|M<4?+x?g)dlLt6oIwVs=Q0c6m^L z(tXYyR)#U2W_hUHBw18VT4u1OXKhEqKmi@!6qj&OwBQ{*McC-YYm~7M-fMWYB6*(E z%)?}jwUR!$VV+p_aYr&+>Q%{)%CU*HXlXiFg*cL|)S>I}6JEVGZE7Fsl3hoEiKli@ z^yU1h5^EheCU8@9XNdwuzoFBZy}xki6!j3$;qje+TDYr@iQ2lzYohJ`aE!P9FYTEp znar#dm% zO`-KW@*wnnOX{M2aBZKzOKIUq%Hx@K`u;WBz;{>~l7Mv(^F$#NL?1oVVNakk@~lJJ!$$o^xlbUn zidH&%-Rmn;j3#{oGYV6L%{^c=r=Q4n+~!2gN!^7^)0P_Q6hN~-%Xv=n7;e@r}^LW9|Djg_bLO@ zks@hqxV(%Y@BHDTA?1o3tz_xHe>H!Y+s|fJ{N)vI>$kFT^CszAC$W=e`+=Wy+Fpl2 zOUA#1Tqb5?Pup0_Y*bFuZpBtC;I_wT`NAhoHc4S_FDW0{c-P^N40t4qb5;^yh@^)w zN=ewmY08QqPG4+5O^4zh9 zU#+U{{g3LDY^X)of>k2sb86b>+ra@-#1mUbM22-##fS{`)TkH!4<{Bb3rouQig35L zW`Rbotqlht2Uq83Ir%QO_Q)4sRUwNPRkC)VS6Mc4m1}K`p^CEmW*DRQ!-%s3SOly| zovX}JjAvf~a?ObOj_RAeSAmTXfXNhukQ>*g^<`f7M}Mgg7UpIauf13PbdQfhT|4|g zrJEtExntON^yb#Rd{Z{ES4sBz85lq8ek4l6A}rQAJiDm?BF~sGADMD1AOOF*NcJLy zfU}ROAt-Bx^_cah5#hRQ9}dk@QmhucIteK8PbD4VOs5y7N9q8F+89 z@@@rcS_dk9c$f0S2ce;Yebj~H2R(fvN;Fm=Y_UGojPMlD#90s?a1^*;xy+s$EQWZ+ z=g^d`Q+t)zed@;IEg1*0dHbF7zQ?;ria_?U_vGUeKbDT1 zz|#`kIxA_cBx?bItZbwnjDpHV4qcMk2Je|qm1-yqJe-AX_Y8PU@=OFtWy*FSHj!gI zjordinEIUX5r4mPX!{Gl$V@VQuiQtR&G~&xAALwNcgc*VP*L>_R>qG=SatuZS*&cO z^T8S+vN%Sri35?$! z5Ozm^9m0t@6P|*3#mPoq&}MMg=GV4t-yt{8idgii8sRt{xTgHZ!uaWh?tTgz#e1_$ zARkSA=Hs|P7bhHG`A=T(y2{G7xkuRgzJ7s@6AU?&8`c1Mf;v;=cyz9OyubIx^! z5AV*9cR@GAQ{nn`p8e@B24DW=E()S8T|CR%yqLk}K~d&E-ZwvT+eF2q=pn@rj$h%< zN~0S8uGcv>WLONog<2@TvLMaV@ri56JYL#MNb2I=)78zoqXP?dh{>OYvs{(+$(2tJ zy#4{zqQ8;@-x+lOSGeM^kYFJ9pCT+HCkJ+Z(&##eFT86JT~WZ6M_xt_oE$Ukl0VE? zFJg%%?q^=M?%~r5w?68mb}Fcwxo&?UWN?_AYp1(s&a3`KGr)hx8wZ-H${E#E$M!Cr zJVLUa-Z7F27B-Dijc~*qNRIAwgW_4VQ-rF`o#{?Ybq`(c9s^nlLnw7^szZ%UdbZmI zH%OL7v3=-x5ME;gwH#AB-^GCGd@Ju#; zVG2Ns0GVrKT><}{#H&mE>Cd#2cuf!)GkvOevEsTk&nIJ2PQUm@5q%N0o7%;c*-_n< zR^+CDZ&tYta<K8f4ce9%5Ju; z_H0|PX_4>Y;XVgDs%uZBzNjwQp!G|hphgEr=buF4x|?_LADJK=qEeW2=R*@3A^6_d zAidXoj(pYem-V-sg1!!Bh5ASyot9{zHk>DPY*)Wxw91wTP`8%4cOSmv4m~usRde-KUR9bF^H_|Mc;HD~0&b$?yq~#X z%xRLYL0S_SsqP`tCWg@ zcYLmUNl7>wxm$dE-{)w>Va@m0>16|TVswhO;78T*kLJh!_={is>{ltG+3P~t`Fi5k znX{I-o-zi~`L+8ovyko@8BMcXep?k&c*{*&jHtf0>yW!1g%*3bCXk~#n!h@wBsGza zHn*VD{oM<_XPX&* zc#pCL=c33|(b1wCfW*QQ`|uoh46T%T@T)thd#zs+TAfMPLAMbXU6Q^*Q(*Z31)K2f zV#1uzW7=m2&PEn9#J3cU!&MYYjF#2jB>oaWMh;l`=(>8Jx(7rsFh)NPN>}La>BWy# z76;N@y$?i0oMYSVBU2$8Kxq;_5t~be&HEpLP&f>}?Kx?-9SGxO?thR>QGBf|tfi8? zmWKa7+1XsTqa;f*vJ&Gt5he(GafEh`?XnenPT&BhV0^0ZwiB4&8O(F4&H=?(Y$BAP*%6lr)tl! z#u?8SWs2}eWS;NTVOg;c238`nT4d!A!R2e#?~^nPQ;uUxCU0GUEx}jt1jyi2VA`(P?&{pxFGn25ypJ>;|FLPWBqL$C*b9A%%S(xarSN-hBAr zlBFn`X0AG-=5=xb-t#>~G%QwGX|MK9j zKAE}IGkycnvvB|uT{#Z{L->U?n}@dU8SH7>t5=wI@Ei9_inU1gq+N@Y698=8T%8`7 zQ}Cd}l|Oi!z;PvCP26x`LBySlN>~p1cr?SoviJ)2`Y(a^OW|dg;zIFwK;l_CA?~3> zso`aR%M=MnF)UhXHCw}$(vOO8L8iVRC=rjPif&N2Mh!YV2JY| zT#{7f;j8Yqn42<|j@CX2FVeJOdYW zILP`ac>csmcP%}sDrL3wq2!GO|>Fpbni=GC{Y8nzhp6+a}lj zYCm5wGaqd)qqO)i5{;A-l9up`3r0+NE3H=r$pmQ<9(|vDF-}oZri>~fTbDW`x?3?{ z@n|vqI%Vc7io0TtUI!GnqIu!kn0V3zO*T21X^vFxGbN*gWa5^;Z0Z-}cXdXX!w%)Fty1ne6bQ-tLp)0gU0<>{{cMcRhE%)xjJl+M+6UY?9c+)lT*iCf}_xUxmvd= zqD8T5N7CGMPHYP%bUO5LS{a05E2XN4jPocNND$~yC@>uO4Q>QU&ZBkxK;I$^sbrq-EOdOl#g(}O$(?w z-*WRrH4af)i10u~=Gwc3nb}`hc!Ub#uql9FxMRw#fwxwdOXvKq=n~I5W1=Ip?w_AWMfnAl2F6np$On<4n}~f& zx`n%k0G&6A*M0`gV+KiQLg%2B#Q?gD;nHQ|l@-NE6?6SPc=tbdW#}qqj`l4sN+CID zS=$&(60tLli-M!ndzFY7sjzg9&RlSNO|gWB2oHv@lV)bWGKA{nRV|``%2B!=7}0gY zmKR3Xg^AnUVac+_^4f{nVZX9&K~yg|S@lc(Qs;`SM{D|C0AQ*L@1ZVwm zsg*oyF|LrB9A&G(u1jZX*txUv51`D=nMnK+bB%4t@;u%J?r+FO_Ppb}NIic?8EU64 z!Ror`qa`Zd_Id89HxK|+%lbg4bWANW+cR@}aZW{`Iz}<^=hz8?n)ENc^w?B!Yr)j% zk%+7OEI*SvgzqC%TuOIg`#Yaf!8Jn^v7Ffu;Esz@gdnxrz5j(e%bFbZc2cdx#!* z;-8gzM+6l1uW)b^!kCzP{>Lu?$Irj?d~1M%P#Rbex?33k>f!8N7?*{)4@n$BOD=y> zmQY|UzI$WwaAc;HZhc~E{^R5G#)Dx!KpTDxH_rJe*w+#IC!L|I;9Y%3IRN{k2$6Fm zzkzX_h{{n_CQ6mj+~*6U%Ij$nNCeRc73bbi7~2WY$XsuO-CsI6DS#RI2(J&g6>ZuY zVZZPQcE{a=dlx87eqdDAN0DrHX!NGExMvkM|8VX?cjTI@-Dj}tWR&S3{~L*^)6`vo zcK*&M@|U~xKA$$fZgT0rMj9-weI`x0rptUVjeUkTjVD*X_7KlS-tJ+Z}hcg$Gp$hI!bUV@rTWmmV=b9 z=qYX&sj&*eOr8#=8u2Ochz%a})o zTj}AX{&CJw4HUV*dtk_D@6OryZ-JImloIXE4I!kKLPInY6#~Bgp~tW{gN6|zpF6R% z??6?PNIAy_&MEROO}UPqT$UtB>}t>hrc(#c_;RUC*+DtLPIiy=ITGt_VP9jicO;-UL*{2q}Cv1{&L(t49kxR#69G7KNE;S>l+Dx56J%AL zcB8j<;QsJ&lE2`6>@q?L&F-yLu@iY51qC+=8J>6=Rydi@?gZ7?6lqwQXo1ofB)=jj zzY5Oyh`)I>qgfTB0Q*nvV<0MLl{h!;9`hqtf03O9>S1xzaXgq4%#EFqXLCflTeeGK zj({>svxj)Aa|Jp^N%1ph=@NZOcjPvH{rxj!yx^gYGR=<4)_5Nm<|)z0aCgvD!;P1Z ztByp~ZB$(3)uAnacy-TP>l!NaY~8wP^U(I)TlT#17J*9FsP_E{!Z2U4!o@iy1=KQZ zx^8~AhtOscJ8j$f&+D4sy)iVnOMkcR*uLjg{bTds8~XF=j@SHr%l6my4C%@4p;vZn z->iQT60N#A{FB^KJ73#F>hP^Y+bKfu)`};aULM>%^p-LoK)j-un?W!5Fdg{mR=$Bq zv||;kPB~ojdS5~-9SxJwM#j1zN+*+4IdU9Cgj7UWgE0}HIdO1!9_YZUUz$w@7PFl- zfu^bPEwgJtl#L~WoW4*^E4lDMWN|=yEJdt0ScFNMfhfM`vlY?w$BcZ zvT1}H%(6mT)p#gKBBC6nW8@rgQN%S;kcT7pGFLEK%h*v&p%vB*&drZxcD6fQ9l*v8 zwi$V|J&AUMnDw16y*k*icG=}>JX+(;6IV2PvyN=kqejm>!BDaDSpR@R$~XsFV$Lj2 z*gHbeXzGvcx`bW}4=cW8hQ?67Br&DnFKZA27)!VE{zo`XEq!(a9<}Gku5EV|ey~Z& zp#Xx%g6Gg{XFLh0tg~m|+Mc5UgZIxT00Iw|hrKU)S@jJpN_}#@;e-+60(CK%NhNDR ze?plLSfl5+Zv7!@vBgVpg|g41VIADM^VPwDmxuNY`Vl=#9zo-I_njYdd|(~_h#^6# zWVIhr^*Qn!E`9JI%m~tKfIN-4(a3<{Vd0cBgmP!o`(q_mU`A|u#r9^t{h5vDNw3Jh z)bbTHjo~hY4m7fDx!t$>UV9Ww36oE<1;Zb?Zj2Yv#`x5=Wgnf!6V%N#|8M-bep#g$ z2@Ih`MndT8NaMSVvj&tebL_3}f2mR(AqtlSuaPnaF2dG42fb*+QOv{FO&_Vc^PH!; z4+EMkOyC97pl8lg-#6i<6fSNuTHbkp!UCWUek+^)XSX}QMP-Oau!G&ifeF8rMfR)f zDT@AfJxYAMcI^MyYvqVE?nOtGa_Um~<7sz{p0K?tql|7&hI!n7!$DDKR0Z(^-W27h){JdL1oa`WO~v#)1Y@(JUVa@CL5i6 zWUTVW0h+E`pqB6=X5~JXu(ZZ8B>M05aEpj&c8H#AAWqj94xR&6Q^2#K%jLUX>~|&s z`*>e>_%h=X%frwNB*wU~F3!=$l8`IZ##ZXeFa#lJr7;auH__?N4I|@*D`TN_^QXro zK_5PZ@@X#^$!@_YS>Ag%J4-bq)e!AoxM--0FJseP%z}{>Iq?K_f|cz?{|Yl(RJs6Z z_CJ=E{nV{x&w{gcc2T`)JM&q~PB*I!114uMOFaG>WOEce&+YensHN=q|)GRNU84zh?NE_Q&bRl zr|`P&ILmzp7tHRlD{}U4zZH~w({YXut6j&6*8CHEfPLZGQ|o&h_k5MN>7<&9+o}o< z*Z1teIAWD=0WyF@DZoIvha6jHeC6vPro`kEPKTT@I<{cKwS0%BI{1#OLE3E~82&`Z3OhuyVPr#H%)O%+k@Kk!J5HWdC1FjEAE$2R8(g@$;}5LQO#fG( zgGYfv=7vNdGFZpJ!Gg|o%<6X%G1~*#ALpYWU3sp41dU=iy2-D!qqD<(O%|_3_(8iP zPqMF-BI~Z=xfn`{cH6v;IfK0?&>!Z9fH=woe1FLZ>Z@b#PbYopR7FMWUm#FLiro2x z9mNc|^#0Z79AN^kd$jw~IvMr#T}Z!u-x&?fUx!D)vHxm%y1}rZ(IkdnW&o7VsQ`jQ zemFh7_!Xq@M25!vVc-=m6me1e2kZjcc{qKE_yZuumg)`w1LEs^!(w$=2^v<8OvO6= zn?}v7b)1g>yVky3Abmh9)%Ky}cL>h6jiK?(3vyrX6UMHzPHBeZ&5|7z(_`IWE<6uq zWxUNQ^JCvi+O=eNtL*L=p|!kM!mq1WFz@_1s|7Sy`s4)u(62)Pb05)LKhAHPkc zFWKB8Qv~MgHHcp#pV{G#Y#5No{J!-(fUaoH!-KiAZ5#hE?<04_Lw) z>tAxejdz-D+n%P$!0z}@{Um??>C1ThC!#;IFMh{E?v5!^{^6lDp19rVHg=ZYzcH}z z!ELtWoq^mIsTl6wP5BT+jy|{f?ce1QY~+;cU>H`x3Zv|Ttb=wH+8a!l5Ogp7X{tbECY2&}f)v1n z28#H|#D`eEQ4w0vi{cpSzfk$kPvRkdX+|V0CAM;`t>2`S!o}dIs`Zm}+r zpurvh;sjEqDh#MMG}qgDGgIuBj={zoc_*Y^llGD7ltk5GFoTpS4ltKqZc0P95| z;2NmtiFN{gJ5i&ggXnZrlJwe0A)AvQE?hd;sgCQ#Pd$A-!&_aPWr-P<#{ef$c|7rd zVts9Gg8_s&Y`^zgJN%eEG*}9ua4v!QY?3qP_>Q5;MZjdZFoS{!PXtu(Q-SEarBt!# qOl85HtfQxk2b%_mAY<6)x!{!+iq7kAyxBl6xuiHI&jWmY-> literal 0 HcmV?d00001 diff --git a/resources/localization/zh_TW_copy/SuperSlicer.mo b/resources/localization/zh_TW_copy/SuperSlicer.mo new file mode 100644 index 0000000000000000000000000000000000000000..badf5dae8c8f058d5571008846d3cf93dc2205ce GIT binary patch literal 103368 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 literal 0 HcmV?d00001 diff --git a/version.inc b/version.inc index cc0adc21cd9..974fbd8e917 100644 --- a/version.inc +++ b/version.inc @@ -10,7 +10,7 @@ set(SLIC3R_APP_CMD "superslicer") # versions set(SLIC3R_VERSION "2.5.59") set(SLIC3R_VERSION_FULL "2.5.60.0") -set(SLIC3R_BUILD_ID "${SLIC3R_APP_KEY}_${SLIC3R_VERSION_FULL}+UNKNOWN") +set(SLIC3R_BUILD_ID "${SLIC3R_APP_KEY}_${SLIC3R_VERSION_FULL}_2024-07-01") set(SLIC3R_RC_VERSION "2,5,60,0") set(SLIC3R_RC_VERSION_DOTS "${SLIC3R_VERSION_FULL}") From d2759a81a723a2ab7102293e382cc5575219633e Mon Sep 17 00:00:00 2001 From: Wolfgang Schadow Date: Fri, 5 Jul 2024 16:30:59 +0200 Subject: [PATCH 05/10] cleaning (wip) --- cmake/CPackConfig.cmake | 70 ------- .../add_on/contextmgr/contextmgr.cpp | 19 +- .../scriptdictionary/scriptdictionary.cpp | 188 +++++++++--------- .../add_on/scriptmath/scriptmath.cpp | 158 ++++++++------- .../scriptstdstring/scriptstdstring_utils.cpp | 9 +- src/avrdude/avr.c | 4 +- src/avrdude/buspirate.c | 91 ++++++--- src/slic3r/GUI/ConfigWizard.cpp | 4 +- src/slic3r/GUI/DoubleSlider.cpp | 3 +- src/slic3r/GUI/Jobs/ArrangeJob.cpp | 2 +- src/slic3r/GUI/Mouse3DController.cpp | 6 - src/slic3r/GUI/ScriptExecutor.cpp | 36 ++-- src/slic3r/GUI/Search.cpp | 4 +- src/slic3r/GUI/UnsavedChangesDialog.cpp | 27 +-- 14 files changed, 281 insertions(+), 340 deletions(-) delete mode 100644 cmake/CPackConfig.cmake diff --git a/cmake/CPackConfig.cmake b/cmake/CPackConfig.cmake deleted file mode 100644 index 940f88b8ca9..00000000000 --- a/cmake/CPackConfig.cmake +++ /dev/null @@ -1,70 +0,0 @@ -# This file will be configured to contain variables for CPack. These variables -# should be set in the CMake list file of the project before CPack module is -# included. The list of available CPACK_xxx variables and their associated -# documentation may be obtained using -# cpack --help-variable-list -# -# Some variables are common to all generators (e.g. CPACK_PACKAGE_NAME) -# and some are specific to a generator -# (e.g. CPACK_NSIS_EXTRA_INSTALL_COMMANDS). The generator specific variables -# usually begin with CPACK__xxxx. - - -set(CPACK_BUILD_SOURCE_DIRS "/home/wschadow/github/Software/Slicer/SuperSlicer;/home/wschadow/github/Software/Slicer/SuperSlicer/build") -set(CPACK_CMAKE_GENERATOR "Unix Makefiles") -set(CPACK_COMPONENTS_ALL "Devel;Unspecified") -set(CPACK_COMPONENT_UNSPECIFIED_HIDDEN "TRUE") -set(CPACK_COMPONENT_UNSPECIFIED_REQUIRED "TRUE") -set(CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE "/usr/share/cmake-3.25/Templates/CPack.GenericDescription.txt") -set(CPACK_DEFAULT_PACKAGE_DESCRIPTION_SUMMARY "Slic3r built using CMake") -set(CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE "ON") -set(CPACK_GENERATOR "STGZ;TGZ;TZ") -set(CPACK_INSTALL_CMAKE_PROJECTS "/home/wschadow/github/Software/Slicer/SuperSlicer/build;Slic3r;ALL;/") -set(CPACK_INSTALL_PREFIX "/usr/local") -set(CPACK_MODULE_PATH "/home/wschadow/github/Software/Slicer/SuperSlicer/cmake/modules/") -set(CPACK_NSIS_DISPLAY_NAME "SuperSlicer 2.5.59") -set(CPACK_NSIS_DISPLAY_NAME_SET "TRUE") -set(CPACK_NSIS_INSTALLER_ICON_CODE "") -set(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "") -set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") -set(CPACK_NSIS_PACKAGE_NAME "SuperSlicer 2.5.59") -set(CPACK_NSIS_UNINSTALL_NAME "Uninstall") -set(CPACK_OBJCOPY_EXECUTABLE "/usr/bin/objcopy") -set(CPACK_OBJDUMP_EXECUTABLE "/usr/bin/objdump") -set(CPACK_OUTPUT_CONFIG_FILE "/home/wschadow/github/Software/Slicer/SuperSlicer/cmake/CPackConfig.cmake") -set(CPACK_PACKAGE_DEFAULT_LOCATION "/") -set(CPACK_PACKAGE_DESCRIPTION_FILE "/home/wschadow/github/Software/Slicer/SuperSlicer/README.md") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CMake is a build tool") -set(CPACK_PACKAGE_EXECUTABLES "superslicer") -set(CPACK_PACKAGE_FILE_NAME "SuperSlicer-2.5.59-Linux-x86_64") -set(CPACK_PACKAGE_INSTALL_DIRECTORY "SuperSlicer 2.5.59") -set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "SuperSlicer_2.5.60.0_2024-07-01") -set(CPACK_PACKAGE_NAME "SuperSlicer") -set(CPACK_PACKAGE_RELOCATABLE "true") -set(CPACK_PACKAGE_VENDOR "SuperSlicer") -set(CPACK_PACKAGE_VERSION "2.5.60.0") -set(CPACK_PACKAGE_VERSION_MAJOR "2") -set(CPACK_PACKAGE_VERSION_MINOR "0") -set(CPACK_PACKAGE_VERSION_PATCH "0") -set(CPACK_READELF_EXECUTABLE "/usr/bin/readelf") -set(CPACK_RESOURCE_FILE_LICENSE "/home/wschadow/github/Software/Slicer/SuperSlicer/LICENSE") -set(CPACK_RESOURCE_FILE_README "/home/wschadow/github/Software/Slicer/SuperSlicer/README.md") -set(CPACK_RESOURCE_FILE_WELCOME "/home/wschadow/github/Software/Slicer/SuperSlicer/README.md") -set(CPACK_SET_DESTDIR "OFF") -set(CPACK_SOURCE_GENERATOR "TGZ;TZ") -set(CPACK_SOURCE_OUTPUT_CONFIG_FILE "/home/wschadow/github/Software/Slicer/SuperSlicer/build/CPackSourceConfig.cmake") -set(CPACK_SOURCE_PACKAGE_FILE_NAME "SuperSlicer-2.5.60.0") -set(CPACK_SOURCE_STRIP_FILES "") -set(CPACK_STRIP_FILES "bin/superslicer") -set(CPACK_SYSTEM_NAME "Linux-x86_64") -set(CPACK_THREADS "1") -set(CPACK_TOPLEVEL_TAG "Linux-x86_64") -set(CPACK_WIX_SIZEOF_VOID_P "8") - -if(NOT CPACK_PROPERTIES_FILE) - set(CPACK_PROPERTIES_FILE "/home/wschadow/github/Software/Slicer/SuperSlicer/build/CPackProperties.cmake") -endif() - -if(EXISTS ${CPACK_PROPERTIES_FILE}) - include(${CPACK_PROPERTIES_FILE}) -endif() diff --git a/src/angelscript/add_on/contextmgr/contextmgr.cpp b/src/angelscript/add_on/contextmgr/contextmgr.cpp index 091f8c555d4..6064b547451 100644 --- a/src/angelscript/add_on/contextmgr/contextmgr.cpp +++ b/src/angelscript/add_on/contextmgr/contextmgr.cpp @@ -269,7 +269,7 @@ void CContextMgr::AbortAll() asIScriptContext *CContextMgr::AddContext(asIScriptEngine *engine, asIScriptFunction *func, bool keepCtxAfterExec) { - // Use RequestContext instead of CreateContext so we can take + // 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 ) @@ -364,32 +364,29 @@ void CContextMgr::SetSleeping(asIScriptContext *ctx, asUINT 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 ); + 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->GetTypeInfoByDecl("dictionary") ); #ifndef AS_MAX_PORTABILITY - 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 ); + engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterFuncdef("void coroutine(dictionary@)"); + engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine), asCALL_CDECL); assert( r >= 0 ); #else - r = engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterFuncdef("void coroutine(dictionary@)"); - r = engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterFuncdef("void coroutine(dictionary@)"); + engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine_generic), asCALL_GENERIC); assert( r >= 0 ); #endif } diff --git a/src/angelscript/add_on/scriptdictionary/scriptdictionary.cpp b/src/angelscript/add_on/scriptdictionary/scriptdictionary.cpp index 2ae53057caa..596ff172568 100644 --- a/src/angelscript/add_on/scriptdictionary/scriptdictionary.cpp +++ b/src/angelscript/add_on/scriptdictionary/scriptdictionary.cpp @@ -1068,77 +1068,76 @@ void RegisterScriptDictionary(asIScriptEngine *engine) void RegisterScriptDictionary_Native(asIScriptEngine *engine) { - int r; // The array type must be available assert( engine->GetTypeInfoByDecl("array") ); #if AS_CAN_USE_CPP11 // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class - r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); + engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); #else - r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); + engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); #endif - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictValue, EnumReferences), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictValue, FreeValue), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictValue, EnumReferences), asCALL_THISCALL); assert(r >= 0); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictValue, FreeValue), asCALL_THISCALL); assert(r >= 0); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert(r >= 0); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); // Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,void*,int),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,void*,int),void), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const double&),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const double&),void), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &) const, const CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &) const, const CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); // Register GC behaviours - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 ); #if AS_USE_STLNAMES == 1 // Same as isEmpty - r = engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); // Same as getSize - r = engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); // Same as delete - r = engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); // Same as deleteAll - r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); #endif // Cache some things the dictionary will need at runtime @@ -1147,66 +1146,65 @@ void RegisterScriptDictionary_Native(asIScriptEngine *engine) void RegisterScriptDictionary_Generic(asIScriptEngine *engine) { - int r; // Register the cleanup callback for the object type cache engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); #if AS_CAN_USE_CPP11 // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class - r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); + engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); #else r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); #endif - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_FreeValue_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_FreeValue_Generic), asCALL_GENERIC); assert(r >= 0); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 ); // Register GC behaviours - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); // Cache some things the dictionary will need at runtime SDictionaryCache::Setup(engine); diff --git a/src/angelscript/add_on/scriptmath/scriptmath.cpp b/src/angelscript/add_on/scriptmath/scriptmath.cpp index c5b86c38a02..4b62a7bf1f5 100644 --- a/src/angelscript/add_on/scriptmath/scriptmath.cpp +++ b/src/angelscript/add_on/scriptmath/scriptmath.cpp @@ -132,69 +132,68 @@ bool closeTo(double a, double b, double epsilon) void RegisterScriptMath_Native(asIScriptEngine *engine) { - int r; // Conversion between floating point and IEEE bits representations - r = engine->RegisterGlobalFunction("float fpFromIEEE(uint)", asFUNCTIONPR(fpFromIEEE, (asUINT), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("uint fpToIEEE(float)", asFUNCTIONPR(fpToIEEE, (float), asUINT), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double fpFromIEEE(uint64)", asFUNCTIONPR(fpFromIEEE, (asQWORD), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("uint64 fpToIEEE(double)", asFUNCTIONPR(fpToIEEE, (double), asQWORD), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float fpFromIEEE(uint)", asFUNCTIONPR(fpFromIEEE, (asUINT), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("uint fpToIEEE(float)", asFUNCTIONPR(fpToIEEE, (float), asUINT), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double fpFromIEEE(uint64)", asFUNCTIONPR(fpFromIEEE, (asQWORD), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("uint64 fpToIEEE(double)", asFUNCTIONPR(fpToIEEE, (double), asQWORD), asCALL_CDECL); assert( r >= 0 ); // Close to comparison with epsilon - r = engine->RegisterGlobalFunction("bool closeTo(float, float, float = 0.00001f)", asFUNCTIONPR(closeTo, (float, float, float), bool), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("bool closeTo(double, double, double = 0.0000000001)", asFUNCTIONPR(closeTo, (double, double, double), bool), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("bool closeTo(float, float, float = 0.00001f)", asFUNCTIONPR(closeTo, (float, float, float), bool), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("bool closeTo(double, double, double = 0.0000000001)", asFUNCTIONPR(closeTo, (double, double, double), bool), asCALL_CDECL); assert( r >= 0 ); #if AS_USE_FLOAT // Trigonometric functions - r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTIONPR(cosf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTIONPR(sinf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTIONPR(tanf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float cos(float)", asFUNCTIONPR(cosf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sin(float)", asFUNCTIONPR(sinf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float tan(float)", asFUNCTIONPR(tanf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTIONPR(acosf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTIONPR(asinf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTIONPR(atanf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTIONPR(atan2f, (float, float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float acos(float)", asFUNCTIONPR(acosf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float asin(float)", asFUNCTIONPR(asinf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float atan(float)", asFUNCTIONPR(atanf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTIONPR(atan2f, (float, float), float), asCALL_CDECL); assert( r >= 0 ); // Hyberbolic functions - r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTIONPR(coshf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTIONPR(sinhf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTIONPR(tanhf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float cosh(float)", asFUNCTIONPR(coshf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sinh(float)", asFUNCTIONPR(sinhf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float tanh(float)", asFUNCTIONPR(tanhf, (float), float), asCALL_CDECL); assert( r >= 0 ); // Exponential and logarithmic functions - r = engine->RegisterGlobalFunction("float log(float)", asFUNCTIONPR(logf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTIONPR(log10f, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float log(float)", asFUNCTIONPR(logf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float log10(float)", asFUNCTIONPR(log10f, (float), float), asCALL_CDECL); assert( r >= 0 ); // Power functions - r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTIONPR(powf, (float, float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTIONPR(sqrtf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTIONPR(powf, (float, float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTIONPR(sqrtf, (float), float), asCALL_CDECL); assert( r >= 0 ); // Nearest integer, absolute value, and remainder functions - r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTIONPR(ceilf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTIONPR(fabsf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTIONPR(floorf, (float), float), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTIONPR(fractionf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float ceil(float)", asFUNCTIONPR(ceilf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float abs(float)", asFUNCTIONPR(fabsf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float floor(float)", asFUNCTIONPR(floorf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float fraction(float)", asFUNCTIONPR(fractionf, (float), float), asCALL_CDECL); assert( r >= 0 ); // Don't register modf because AngelScript already supports the % operator #else // double versions of the same - r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTIONPR(cos, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTIONPR(sin, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTIONPR(tan, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTIONPR(acos, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTIONPR(asin, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTIONPR(atan, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTIONPR(atan2, (double, double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTIONPR(cosh, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTIONPR(sinh, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTIONPR(tanh, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double log(double)", asFUNCTIONPR(log, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTIONPR(log10, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTIONPR(pow, (double, double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTIONPR(sqrt, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTIONPR(ceil, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTIONPR(fabs, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double cos(double)", asFUNCTIONPR(cos, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sin(double)", asFUNCTIONPR(sin, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double tan(double)", asFUNCTIONPR(tan, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double acos(double)", asFUNCTIONPR(acos, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double asin(double)", asFUNCTIONPR(asin, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double atan(double)", asFUNCTIONPR(atan, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTIONPR(atan2, (double, double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double cosh(double)", asFUNCTIONPR(cosh, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sinh(double)", asFUNCTIONPR(sinh, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double tanh(double)", asFUNCTIONPR(tanh, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double log(double)", asFUNCTIONPR(log, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double log10(double)", asFUNCTIONPR(log10, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTIONPR(pow, (double, double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTIONPR(sqrt, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double ceil(double)", asFUNCTIONPR(ceil, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double abs(double)", asFUNCTIONPR(fabs, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 ); #endif } @@ -278,59 +277,58 @@ void atan2_generic(asIScriptGeneric *gen) #endif void RegisterScriptMath_Generic(asIScriptEngine *engine) { - int r; #if AS_USE_FLOAT // Trigonometric functions - r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTION(tanf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float tan(float)", asFUNCTION(tanf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTION(acosf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTION(asinf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTION(atanf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTION(atan2f_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float acos(float)", asFUNCTION(acosf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float asin(float)", asFUNCTION(asinf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float atan(float)", asFUNCTION(atanf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTION(atan2f_generic), asCALL_GENERIC); assert( r >= 0 ); // Hyberbolic functions - r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTION(coshf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTION(sinhf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTION(tanhf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float cosh(float)", asFUNCTION(coshf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sinh(float)", asFUNCTION(sinhf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float tanh(float)", asFUNCTION(tanhf_generic), asCALL_GENERIC); assert( r >= 0 ); // Exponential and logarithmic functions - r = engine->RegisterGlobalFunction("float log(float)", asFUNCTION(logf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTION(log10f_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float log(float)", asFUNCTION(logf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float log10(float)", asFUNCTION(log10f_generic), asCALL_GENERIC); assert( r >= 0 ); // Power functions - r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTION(powf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTION(sqrtf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTION(powf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTION(sqrtf_generic), asCALL_GENERIC); assert( r >= 0 ); // Nearest integer, absolute value, and remainder functions - r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTION(fabsf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTION(fractionf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float abs(float)", asFUNCTION(fabsf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float fraction(float)", asFUNCTION(fractionf_generic), asCALL_GENERIC); assert( r >= 0 ); // Don't register modf because AngelScript already supports the % operator #else // double versions of the same - r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTION(cos_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTION(sin_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTION(tan_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTION(acos_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTION(asin_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTION(atan_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTION(atan2_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTION(cosh_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTION(sinh_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTION(tanh_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double log(double)", asFUNCTION(log_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTION(log10_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTION(pow_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTION(sqrt_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTION(ceil_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTION(fabs_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double cos(double)", asFUNCTION(cos_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sin(double)", asFUNCTION(sin_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double tan(double)", asFUNCTION(tan_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double acos(double)", asFUNCTION(acos_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double asin(double)", asFUNCTION(asin_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double atan(double)", asFUNCTION(atan_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTION(atan2_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double cosh(double)", asFUNCTION(cosh_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sinh(double)", asFUNCTION(sinh_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double tanh(double)", asFUNCTION(tanh_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double log(double)", asFUNCTION(log_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double log10(double)", asFUNCTION(log10_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTION(pow_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTION(sqrt_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double ceil(double)", asFUNCTION(ceil_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double abs(double)", asFUNCTION(fabs_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 ); #endif } diff --git a/src/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp b/src/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp index 54662aa05e2..930681f39ca 100644 --- a/src/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp +++ b/src/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp @@ -112,17 +112,16 @@ static void StringJoin_Generic(asIScriptGeneric *gen) // The string type must have been registered first. void RegisterStdStringUtils(asIScriptEngine *engine) { - int r; if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { - r = engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0); + engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0); + engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0); } else { - r = engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0); + engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0); + engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0); } } diff --git a/src/avrdude/avr.c b/src/avrdude/avr.c index defae75d50c..dc050c7a5f6 100644 --- a/src/avrdude/avr.c +++ b/src/avrdude/avr.c @@ -83,7 +83,9 @@ int avr_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p) 0xFF }; - while (avr_tpi_poll_nvmbsy(pgm)); + while (avr_tpi_poll_nvmbsy(pgm)){ + + }; err = pgm->cmd_tpi(pgm, cmd, sizeof(cmd), NULL, 0); if(err) diff --git a/src/avrdude/buspirate.c b/src/avrdude/buspirate.c index dc8c68fbebd..42b4c25213e 100644 --- a/src/avrdude/buspirate.c +++ b/src/avrdude/buspirate.c @@ -490,36 +490,69 @@ static void buspirate_reset_from_binmode(struct programmer_t *pgm) static int buspirate_start_mode_bin(struct programmer_t *pgm) { - const struct submode { - const char *name; /* Name of mode for user messages */ - char enter; /* Command to enter from base binary mode */ - const char *entered_format; /* Response, for "scanf" */ - char config; /* Command to setup submode parameters */ - } *submode; - - if (pgm->flag & BP_FLAG_XPARM_RAWFREQ) { - submode = &(const struct submode){ - .name = "Raw-wire", - .enter = 0x05, - .entered_format = "RAW%1d", - .config = 0x8C, - }; - pgm->flag |= BP_FLAG_NOPAGEDWRITE; - pgm->flag |= BP_FLAG_NOPAGEDREAD; - } else { - submode = &(const struct submode){ - .name = "SPI", - .enter = 0x01, - .entered_format = "SPI%1d", + // const struct submode { + // const char *name; /* Name of mode for user messages */ + // char enter; /* Command to enter from base binary mode */ + // const char *entered_format; /* Response, for "scanf" */ + // char config; /* Command to setup submode parameters */ + // } *submode; + + // if (pgm->flag & BP_FLAG_XPARM_RAWFREQ) { + // submode = &(const struct submode){ + // .name = "Raw-wire", + // .enter = 0x05, + // .entered_format = "RAW%1d", + // .config = 0x8C, + // }; + // pgm->flag |= BP_FLAG_NOPAGEDWRITE; + // pgm->flag |= BP_FLAG_NOPAGEDREAD; + // } else { + // submode = &(const struct submode){ + // .name = "SPI", + // .enter = 0x01, + // .entered_format = "SPI%1d", - /* 1000wxyz - SPI config, w=HiZ(0)/3.3v(1), x=CLK idle, y=CLK edge, z=SMP sample - * we want: 3.3V(1), idle low(0), data change on - * trailing edge (1), sample in the middle - * of the pulse (0) - * => 0b10001010 = 0x8a */ - .config = 0x8A, - }; - } + // /* 1000wxyz - SPI config, w=HiZ(0)/3.3v(1), x=CLK idle, y=CLK edge, z=SMP sample + // * we want: 3.3V(1), idle low(0), data change on + // * trailing edge (1), sample in the middle + // * of the pulse (0) + // * => 0b10001010 = 0x8a */ + // .config = 0x8A, + // }; + // } + +const struct submode { + const char *name; /* Name of mode for user messages */ + char enter; /* Command to enter from base binary mode */ + const char *entered_format; /* Response, for "scanf" */ + char config; /* Command to setup submode parameters */ +} *submode; + +// Define static submodes +static const struct submode rawWireSubmode = { + .name = "Raw-wire", + .enter = 0x05, + .entered_format = "RAW%1d", + .config = 0x8C, +}; + +static const struct submode spiSubmode = { + .name = "SPI", + .enter = 0x01, + .entered_format = "SPI%1d", + .config = 0x8A, +}; + +// Point to the appropriate submode based on the condition +if (pgm->flag & BP_FLAG_XPARM_RAWFREQ) { + submode = &rawWireSubmode; + pgm->flag |= BP_FLAG_NOPAGEDWRITE; + pgm->flag |= BP_FLAG_NOPAGEDREAD; +} else { + submode = &spiSubmode; +} + + unsigned char buf[20] = { '\0' }; diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index ec18e65d2c8..760fd9683d3 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -145,7 +145,7 @@ BundleMap BundleMap::load() } } } - catch (std::exception e) { + catch (const std::exception& e) { MessageDialog msg(nullptr, format_wxstr(_L("Can't open directory '%1%'. Config bundles from here can't be loaded.\nError: %2%"), vendor_dir.string(), e.what()), _L("Error"), wxOK); msg.ShowModal(); } @@ -2590,7 +2590,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese wxString header, caption = _L("Configuration is edited in ConfigWizard"); const auto enabled_vendors = appconfig_new.vendors(); - bool suppress_sla_printer = model_has_multi_part_objects(wxGetApp().model()); + model_has_multi_part_objects(wxGetApp().model()); PrinterTechnology preferred_pt = ptAny; #ifdef ALLOW_PRUSA_FIRST auto get_preferred_printer_technology = [enabled_vendors, suppress_sla_printer](const std::string& bundle_name, const Bundle& bundle) { diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 1e588fcf63c..857294b2fa7 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -830,8 +830,7 @@ wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer nb_lines++; double layer_height = 0; if (value >= m_values.size()) { - const auto st1 = value; - const auto st2 = m_values.size(); + layer_height = m_values.empty() ? m_label_koef : m_values.back() - (m_values.size() > 1 ? m_values[m_values.size() - 2] : 0); assert(value == m_values.size()); } else if (value == 0) { diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index e41c1271f7a..3b6feb19dc0 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -204,7 +204,7 @@ void ArrangeJob::process() arrangement::ArrangeParams params = get_arrange_params(m_plater); - double min_dist_computed = min_object_distance(&m_plater->current_print()->full_print_config()); + min_object_distance(&m_plater->current_print()->full_print_config()); auto count = unsigned(m_selected.size() + m_unprintable.size()); Points bedpts = get_bed_shape(*m_plater->config()); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index b47cf74f984..de34e6b3af7 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -1127,12 +1127,6 @@ void Mouse3DController::disconnect_device() } } -// Convert a signed 16bit word from a 3DConnexion mouse HID packet into a double coordinate, apply a dead zone. -static double convert_spnav_input(int value) -{ - return (double)value/100; -} - void Mouse3DController::collect_input() { #ifdef HAVE_SPNAV diff --git a/src/slic3r/GUI/ScriptExecutor.cpp b/src/slic3r/GUI/ScriptExecutor.cpp index 3e10680e46c..db623d9e7b6 100644 --- a/src/slic3r/GUI/ScriptExecutor.cpp +++ b/src/slic3r/GUI/ScriptExecutor.cpp @@ -205,22 +205,9 @@ float as_get_float_idx(std::string& key, int idx) return val; } float as_get_float(std::string &key) { return as_get_float_idx(key, 0); } + double round(float value) { - double intpart; - if (modf(value, &intpart) == 0.0) { - // shortcut for int - return value; - } - std::stringstream ss; - //first, get the int part, to see how many digit it takes - int long10 = 0; - if (intpart > 9) - long10 = (int)std::floor(std::log10(std::abs(intpart))); - //set the usable precision: there is only ~7 decimal digit in a float (15-16 decimal digit in a double) - ss << std::fixed << std::setprecision(7 - long10) << value; - double dbl_val; - ss >> dbl_val; - return dbl_val; + return std::round(value); } void _set_float(DynamicPrintConfig& conf, const ConfigOption* opt, std::string& key, int idx, float f_val) @@ -765,7 +752,7 @@ float as_get_computed_float(std::string& key) return (float)fullconfig.get_computed_value(key, 0); //return (float)wxGetApp().plater()->fff_print().full_print_config().get_computed_value(key, 0); } - catch (Exception e) { + catch (const Exception& e) { if(wxGetApp().initialized()) BOOST_LOG_TRIVIAL(error) << "Error, can't compute fff option '" << key << "'"; } @@ -780,7 +767,7 @@ float as_get_computed_float(std::string& key) return (float)fullconfig.get_computed_value(key, 0); //return (float)wxGetApp().plater()->fff_print().full_print_config().get_computed_value(key, 0); } - catch (Exception e) { + catch (const Exception& e) { if (wxGetApp().initialized()) BOOST_LOG_TRIVIAL(error) << "Error, can't compute sla option '" << key << "'"; } @@ -1061,13 +1048,16 @@ void ScriptContainer::call_script_function_set(const ConfigOptionDef& def, const } case coEnum: { int32_t enum_idx = boost::any_cast(value); - if (enum_idx >= 0 && enum_idx < def.enum_values.size()) { + if (enum_idx >= 0 && static_cast(enum_idx) < def.enum_values.size()) { str_arg = def.enum_values[enum_idx]; ctx->SetArgAddress(0, &str_arg); ctx->SetArgDWord(1, enum_idx); } break; } + default: { + break; + } } m_need_refresh = false; m_to_update.clear(); @@ -1245,6 +1235,9 @@ boost::any ScriptContainer::call_script_function_get_value(const ConfigOptionDef case coString: case coStrings: case coEnum: ctx->SetArgObject(0, &ret_str); break; + default: { + break; + } } // init globals for script exec (TODO find a way to change that) assert(current_script == nullptr); @@ -1253,7 +1246,7 @@ boost::any ScriptContainer::call_script_function_get_value(const ConfigOptionDef current_script = this; m_need_refresh = false; // exec - int res = ctx->Execute(); + ctx->Execute(); current_script = nullptr; } int32_t ret_int; @@ -1304,7 +1297,7 @@ boost::any ScriptContainer::call_script_function_get_value(const ConfigOptionDef } case coEnum: { ret_int = ctx->GetReturnDWord(); - if (ret_int >= 0 && ret_int < def.enum_values.size()) { + if (ret_int >= 0 && static_cast(ret_int) < def.enum_values.size()) { opt_val = int32_t(ret_int); } else { opt_val = int32_t(0); @@ -1314,6 +1307,9 @@ boost::any ScriptContainer::call_script_function_get_value(const ConfigOptionDef } } break; //Choice + } + default: { + break; } } if (m_need_refresh) { diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 18ac0456057..fb884d8d310 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -355,7 +355,7 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/) //add "\n" to long tooltip lines std::wstring tooltip; int length = 0; - for (int i = 0; i < opt.tooltip_local.size(); i++) { + for (std::wstring::size_type i = 0; i < opt.tooltip_local.size(); i++) { if (length >= 80 && opt.tooltip_local[i] == u' ') { tooltip.push_back(u'\n'); } else { @@ -384,7 +384,7 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/) try { if (view_params.exact) pattern = std::wregex(wsearch, std::regex_constants::icase); - } catch (std::regex_error reg_err) { + } catch (std::regex_error& reg_err) { // Happens when std::wregex("]") or similar. => no result //TODO: add warning message 'wrong regexp' fail_pattern = true; } diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 61949061ed3..ebf91b3db52 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1063,17 +1063,6 @@ static size_t get_id_from_opt_key(std::string opt_key) return size_t(-1); } -static wxString get_full_label(std::string opt_key, const DynamicPrintConfig& config) -{ - opt_key = get_pure_opt_key(opt_key); - - if (config.option(opt_key)->is_nil()) - return _L("N/A"); - - const ConfigOptionDef* opt = config.def()->get(opt_key); - return opt->full_label.empty() ? opt->label : opt->full_label; -} - wxString graph_to_string(const GraphData &graph) { wxString str = ""; @@ -1081,6 +1070,7 @@ wxString graph_to_string(const GraphData &graph) case GraphData::GraphType::SQUARE: str = _L("Square") + ":"; break; case GraphData::GraphType::LINEAR: str = _L("Linear") + ":"; break; case GraphData::GraphType::SPLINE: str = _L("Spline") + ":"; break; + case GraphData::GraphType::COUNT: ; break; } for (const Vec2d &pt : graph.data()) { str += format_wxstr(" %1%,%2%", pt.x(), pt.y()); } return str; @@ -1196,19 +1186,21 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig& return out; } if (opt_key == "gcode_substitutions") { - if (!strings->empty()) + if (!strings->empty()){ for (size_t id = 0; id < strings->size(); id += 4) out += from_u8(strings->get_at(id)) + ";\t" + from_u8(strings->get_at(id + 1)) + ";\t" + from_u8(strings->get_at(id + 2)) + ";\t" + from_u8(strings->get_at(id + 3)) + ";\n"; + } return out; } - if (!strings->empty()) + if (!strings->empty()){ if (opt_idx < strings->size()) return from_u8(strings->get_at(opt_idx)); else return from_u8(strings->serialize()); + } } break; } @@ -1220,11 +1212,12 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig& } case coFloatsOrPercents: { const ConfigOptionFloatsOrPercents* floats_percents = config.opt(opt_key); - if (floats_percents) + if (floats_percents){ if(opt_idx < floats_percents->size()) return double_to_string(floats_percents->get_at(opt_idx).value, opt->precision) + (floats_percents->get_at(opt_idx).percent ? "%" : ""); else return from_u8(floats_percents->serialize()); + } } case coEnum: { return get_string_from_enum(opt_key, config); @@ -1241,22 +1234,24 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig& } const ConfigOptionPoints* opt_pts = config.opt(opt_key); - if (!opt_pts->empty()) + if (!opt_pts->empty()){ if (opt_idx < opt_pts->size()) return from_u8((boost::format("[%1%]") % ConfigOptionPoint(opt_pts->get_at(opt_idx)).serialize()).str()); else return from_u8(opt_pts->serialize()); + } } case coGraph: { return graph_to_string(config.option(opt_key)->value); } case coGraphs: { const ConfigOptionGraphs* opt_graphs = config.opt(opt_key); - if (!opt_graphs->empty()) + if (!opt_graphs->empty()){ if (opt_idx < opt_graphs->size()) return graph_to_string(opt_graphs->get_at(opt_idx)); else return from_u8(opt_graphs->serialize()); + } } default: break; From ec3541e9ea1fde964f5ce74319ebc287c7edfac2 Mon Sep 17 00:00:00 2001 From: Wolfgang Schadow Date: Sat, 6 Jul 2024 17:18:13 +0200 Subject: [PATCH 06/10] cleaning 2 (wip) --- src/admesh/normals.cpp | 2 +- src/admesh/shared.cpp | 8 +-- src/admesh/util.cpp | 12 ++--- .../add_on/scriptmath/scriptmath.cpp | 54 +++++++++++++------ src/avrdude/buspirate.c | 1 - src/clipper/clipper.cpp | 3 +- src/imgui/imgui_widgets.cpp | 5 +- src/libslic3r/BridgeDetector.cpp | 11 ++-- src/libslic3r/Brim.cpp | 6 +-- src/libslic3r/ClipperUtils.cpp | 4 +- src/libslic3r/Config.cpp | 26 ++++----- src/libslic3r/ExtrusionEntity.cpp | 17 +++--- src/libslic3r/Fill/FillBase.cpp | 7 +-- src/libslic3r/Fill/FillConcentric.cpp | 14 +++-- src/libslic3r/Fill/FillRectilinear.cpp | 18 ++++--- src/libslic3r/Format/3mf.cpp | 13 +++-- src/libslic3r/Format/BBConfig.cpp | 9 ++-- src/libslic3r/Format/SLAArchive.cpp | 18 +++---- src/libslic3r/Format/bbs_3mf.cpp | 49 ++++++++--------- src/libslic3r/GCode/CoolingBuffer.cpp | 2 +- src/libslic3r/GCode/FanMover.cpp | 9 ++-- src/libslic3r/GCode/PressureEqualizer.cpp | 1 - src/libslic3r/GCode/Thumbnails.cpp | 1 - src/slic3r/GUI/ConfigWizard.cpp | 2 +- src/slic3r/GUI/RammingChart.cpp | 3 +- src/slic3r/GUI/Tab.cpp | 3 +- 26 files changed, 158 insertions(+), 140 deletions(-) diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp index 3b677641f99..ba116e7d670 100644 --- a/src/admesh/normals.cpp +++ b/src/admesh/normals.cpp @@ -193,7 +193,7 @@ void stl_fix_normal_directions(stl_file *stl) norm_sw[facet_num] = 1; // Record this one as being fixed. ++ checked; } - stl_normal *temp = head->next; // Delete this facet from the list. + // Delete this facet from the list. head->next = head->next->next; // pool.destroy(temp); } else { // If we ran out of facets to fix: All of the facets in this part have been fixed. diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index a8fbc2a87db..97d65b037a7 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -103,7 +103,7 @@ void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its) traversal_reversed = true; facet_in_fan_idx = facet_idx; } - } else if (next_facet == facet_idx) { + } else if (next_facet == static_cast(facet_idx)) { // Traversed a closed fan all around. // assert(! traversal_reversed); break; @@ -139,7 +139,7 @@ bool its_write_off(const indexed_triangle_set &its, const char *file) fprintf(fp, "OFF\n"); fprintf(fp, "%d %d 0\n", (int)its.vertices.size(), (int)its.indices.size()); - for (int i = 0; i < its.vertices.size(); ++ i) + for (size_t i = 0; i < its.vertices.size(); ++i) fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); for (uint32_t i = 0; i < its.indices.size(); ++ i) fprintf(fp, "\t3 %d %d %d\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); @@ -172,8 +172,8 @@ bool its_write_vrml(const indexed_triangle_set &its, const char *file) fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n"); fprintf(fp, "\t\t\tpoint [\n"); - int i = 0; - for (; i + 1 < its.vertices.size(); ++ i) + size_t i = 0; + for (; i + 1 < its.vertices.size(); ++i) fprintf(fp, "\t\t\t\t%f %f %f,\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); fprintf(fp, "\t\t\t\t%f %f %f]\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); fprintf(fp, "\t\t}\n"); diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 644fa1834ca..190a5056c59 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -323,12 +323,12 @@ void stl_repair( stl->stats.facets_w_3_bad_edge = (stl->stats.number_of_facets - stl->stats.connected_facets_1_edge); } - if (nearby_flag || fixall_flag) { - if (! tolerance_flag) - tolerance = stl->stats.shortest_edge; - if (! increment_flag) - increment = stl->stats.bounding_diameter / 10000.0; - } + if (nearby_flag || fixall_flag) { + if (!tolerance_flag) + tolerance = stl->stats.shortest_edge; + if (!increment_flag) + increment = stl->stats.bounding_diameter / 10000.0; + } if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { int last_edges_fixed = 0; diff --git a/src/angelscript/add_on/scriptmath/scriptmath.cpp b/src/angelscript/add_on/scriptmath/scriptmath.cpp index 4b62a7bf1f5..62688b347ad 100644 --- a/src/angelscript/add_on/scriptmath/scriptmath.cpp +++ b/src/angelscript/add_on/scriptmath/scriptmath.cpp @@ -3,6 +3,7 @@ #include #include #include "scriptmath.h" +#include #ifdef __BORLANDC__ #include @@ -76,25 +77,48 @@ double fraction(double v) // functions for converting float values to IEEE 754 formatted values etc. This also allow us to // provide a platform agnostic representation to the script so the scripts don't have to worry // about whether the CPU uses IEEE 754 floats or some other representation -float fpFromIEEE(asUINT raw) -{ - // TODO: Identify CPU family to provide proper conversion - // if the CPU doesn't natively use IEEE style floats - return *reinterpret_cast(&raw); +// float fpFromIEEE(asUINT raw) +// { +// // TODO: Identify CPU family to provide proper conversion +// // if the CPU doesn't natively use IEEE style floats +// return *reinterpret_cast(&raw); +// } +// asUINT fpToIEEE(float fp) +// { +// return *reinterpret_cast(&fp); +// } +// double fpFromIEEE(asQWORD raw) +// { +// return *reinterpret_cast(&raw); +// } +// asQWORD fpToIEEE(double fp) +// { +// return *reinterpret_cast(&fp); +// } +// Convert a float to its IEEE representation as an unsigned integer +asUINT fpToIEEE(float fp) { + asUINT value; + std::memcpy(&value, &fp, sizeof(asUINT)); + return value; } -asUINT fpToIEEE(float fp) -{ - return *reinterpret_cast(&fp); +// Convert an IEEE representation (as an unsigned integer) to a float +float fpFromIEEE(asUINT raw) { + float value; + std::memcpy(&value, &raw, sizeof(float)); + return value; } -double fpFromIEEE(asQWORD raw) -{ - return *reinterpret_cast(&raw); +// Convert an IEEE representation (as an unsigned 64-bit integer) to a double +double fpFromIEEE(asQWORD raw) { + double value; + std::memcpy(&value, &raw, sizeof(double)); + return value; } -asQWORD fpToIEEE(double fp) -{ - return *reinterpret_cast(&fp); +// Convert a double to its IEEE representation as an unsigned 64-bit integer +asQWORD fpToIEEE(double fp) { + asQWORD value; + std::memcpy(&value, &fp, sizeof(asQWORD)); + return value; } - // closeTo() is used to determine if the binary representation of two numbers are // relatively close to each other. Numerical errors due to rounding errors build // up over many operations, so it is almost impossible to get exact numbers and diff --git a/src/avrdude/buspirate.c b/src/avrdude/buspirate.c index 42b4c25213e..bb7f6bed06c 100644 --- a/src/avrdude/buspirate.c +++ b/src/avrdude/buspirate.c @@ -553,7 +553,6 @@ if (pgm->flag & BP_FLAG_XPARM_RAWFREQ) { } - unsigned char buf[20] = { '\0' }; /* == Switch to binmode - send 20x '\0' == */ diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp index 1955c5242e4..158b3d5467a 100644 --- a/src/clipper/clipper.cpp +++ b/src/clipper/clipper.cpp @@ -193,7 +193,7 @@ IntPoint Centroid(const Path& poly, double area) double x_temp = 0; double y_temp = 0; - const int max = poly.size() - 1; + const size_t max = poly.size() - 1; size_t i = 0; for (; i < max; ++i) { @@ -470,6 +470,7 @@ inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt) e->Curr = Pt; e->OutIdx = Unassigned; } + //------------------------------------------------------------------------------ void InitEdge2(TEdge& e, PolyType Pt) diff --git a/src/imgui/imgui_widgets.cpp b/src/imgui/imgui_widgets.cpp index 65981d9db44..e5c89d9ce79 100644 --- a/src/imgui/imgui_widgets.cpp +++ b/src/imgui/imgui_widgets.cpp @@ -1936,14 +1936,15 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b if (format == NULL) format = type_info->ScanFmt; - if (!buf[0]) + if (!buf[0]) { if (p_default_data && data_type == ImGuiDataType_Float) { float* v = (float*)p_data; *v = (*(const float*)p_default_data); return memcmp(&data_backup, p_data, type_info->Size) != 0; } else { return false; - } + } +} // FIXME-LEGACY: The aim is to remove those operators and write a proper expression evaluator at some point.. int arg1i = 0; diff --git a/src/libslic3r/BridgeDetector.cpp b/src/libslic3r/BridgeDetector.cpp index 245de23815f..b8f9ae98193 100644 --- a/src/libslic3r/BridgeDetector.cpp +++ b/src/libslic3r/BridgeDetector.cpp @@ -170,7 +170,7 @@ bool BridgeDetector::detect_angle(double bridge_direction_override) // is anchored? size_t line_a_anchor_idx = -1; size_t line_b_anchor_idx = -1; - for (int i = 0; i < _anchor_regions.size(); ++i) { + for (std::vector::size_type i = 0; i < _anchor_regions.size(); ++i) { ExPolygon & poly = this->_anchor_regions[i]; BoundingBox &polybb = anchor_bb[i]; if (polybb.contains(line.a) && @@ -198,7 +198,7 @@ bool BridgeDetector::detect_angle(double bridge_direction_override) // candidates to ~100, here we can have hundreds of lines, so that means dozen of // thousands of calls (or more)! add some points (at least the middle) to test, it's quick Point middle_point = line.midpoint(); - for (int i = 0; i < _anchor_regions.size(); ++i) { + for (std::vector::size_type i = 0; i < _anchor_regions.size(); ++i) { ExPolygon & poly = this->_anchor_regions[i]; BoundingBox &polybb = anchor_bb[i]; if (!polybb.contains(middle_point) || @@ -215,9 +215,8 @@ bool BridgeDetector::detect_angle(double bridge_direction_override) normal *= coordf_t(spacing / 2); Point middle_point_right = line.midpoint() + normal; Point middle_point_left = line.midpoint() - normal; - for (int i = 0; i < _anchor_regions.size(); ++i) { + for (std::vector::size_type i = 0; i < _anchor_regions.size(); ++i) { ExPolygon & poly = this->_anchor_regions[i]; - BoundingBox &polybb = anchor_bb[i]; if (!poly.contains(middle_point_right) || !poly.contains(middle_point_left)) { fake_bridge = false; goto stop_fake_bridge_test; @@ -235,7 +234,7 @@ bool BridgeDetector::detect_angle(double bridge_direction_override) pts.push_back((line.a + middle_point) / 2 - normal); pts.push_back((line.b + middle_point) / 2 + normal); pts.push_back((line.b + middle_point) / 2 - normal); - for (int i = 0; i < _anchor_regions.size(); ++i) { + for (std::vector::size_type i = 0; i < _anchor_regions.size(); ++i) { ExPolygon & poly = this->_anchor_regions[i]; BoundingBox &polybb = anchor_bb[i]; for (Point &pt : pts) @@ -372,10 +371,8 @@ stop_fake_bridge_test: ; } std::sort(all_median_length.begin(), all_median_length.end()); std::sort(all_max_length.begin(), all_max_length.end()); - coordf_t median_max_length = all_max_length[all_max_length.size() / 2]; coordf_t min_max_length = all_max_length.front(); coordf_t max_max_length = all_max_length.back(); - coordf_t median_median_length = all_median_length[all_median_length.size() / 2]; coordf_t min_median_length = all_median_length.front(); coordf_t max_median_length = all_median_length.back(); diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index e68923121c9..d71c7debd07 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -761,7 +761,7 @@ void extrude_brim_from_tree(const Print& print, std::vectorchildren.size() <= cut_child_first.front().second) { + if (cut_child_first.front().first->children.size() <= static_cast(cut_child_first.front().second)) { //if no child to cut, cut ourself and pop cut_loop(*cut_child_first.front().first); cut_child_first.pop_front(); @@ -810,7 +810,7 @@ void extrude_brim_from_tree(const Print& print, std::vector* extrude_ptr; std::function extrude = [&mm3_per_mm, &width, &height, &extrude_ptr, &nextIdx](BrimLoop& to_cut, ExtrusionEntityCollection* parent) { - int idx = nextIdx++; + nextIdx++; //bool i_have_line = !to_cut.line.points.empty() && to_cut.line.is_valid(); bool i_have_line = to_cut.lines.size() > 0 && to_cut.lines.front().size() > 0 && to_cut.lines.front().is_valid(); if (!i_have_line && to_cut.children.empty()) { diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 0d2149b3b53..9df4f9ecd39 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -639,10 +639,10 @@ bool test_path(const ClipperLib::Path &path) { } void remove_small_areas(ClipperLib::Paths& paths) { - for (int idx_path = 0; idx_path < paths.size(); ++idx_path) { + for (size_t idx_path = 0; idx_path < paths.size(); ++idx_path) { if (test_path(paths[idx_path])) { paths.erase(paths.begin() + idx_path); - --idx_path; + --idx_path; // Adjust index after erase } } } diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 59e0d3cfc31..0ffb8dfe7fb 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -378,15 +378,19 @@ double GraphData::interpolate(double x_value) const{ std::vector rhs(N + 1); // let's fill in inner equations - for (int i = 1 + begin_idx; i <= N + begin_idx; ++i) h[i] = this->graph_points[i].x() - this->graph_points[i - 1].x(); + for (size_t i = 1 + begin_idx; i <= static_cast(N + begin_idx); ++i) { + h[i] = this->graph_points[i].x() - this->graph_points[i - 1].x(); + } + std::fill(diag.begin(), diag.end(), 2.f); - for (int i = 1 + begin_idx; i <= N + begin_idx - 1; ++i) { + + for (size_t i = 1 + begin_idx; i <= static_cast(N + begin_idx - 1); ++i) { mu[i] = h[i] / (h[i] + h[i + 1]); lambda[i] = 1.f - mu[i]; rhs[i] = 6 * (float(this->graph_points[i + 1].y() - this->graph_points[i].y()) / - (h[i + 1] * (this->graph_points[i + 1].x() - this->graph_points[i - 1].x())) - - float(this->graph_points[i].y() - this->graph_points[i - 1].y()) / - (h[i] * (this->graph_points[i + 1].x() - this->graph_points[i - 1].x()))); + (h[i + 1] * (this->graph_points[i + 1].x() - this->graph_points[i - 1].x())) - + float(this->graph_points[i].y() - this->graph_points[i - 1].y()) / + (h[i] * (this->graph_points[i + 1].x() - this->graph_points[i - 1].x()))); } // now fill in the first and last equations, according to boundary conditions: @@ -1087,8 +1091,9 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex const ConfigOption* opt_extruder_id = nullptr; if ((opt_extruder_id = this->option("extruder")) == nullptr) if ((opt_extruder_id = this->option("current_extruder")) == nullptr - || opt_extruder_id->get_int() < 0 || opt_extruder_id->get_int() >= vector_opt->size()) { - std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " need to has the extuder id to get the right value, but it's not available"; + || opt_extruder_id->get_int() < 0 || static_cast(opt_extruder_id->get_int()) >= vector_opt->size()) { + std::stringstream ss; + ss << "ConfigBase::get_abs_value(): " << opt_key << " need to have the extruder id to get the right value, but it's not available"; throw ConfigurationError(ss.str()); } extruder_id = opt_extruder_id->get_int(); @@ -1330,9 +1335,6 @@ size_t ConfigBase::load_from_gcode_string_legacy(ConfigBase& config, const char* return 0; // Walk line by line in reverse until a non-configuration key appears. - const char *data_start = str; - // boost::nowide::ifstream seems to cook the text data somehow, so less then the 64k of characters may be retrieved. - const char *end = data_start + strlen(str); size_t num_key_value_pairs = 0; for (auto [key, value] : load_gcode_string_legacy(str)) { try { @@ -1660,7 +1662,7 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option opts[t] = oit.first; bool parse_options = true; - for (size_t i = 1; i < argc; ++ i) { + for (size_t i = 1; i < static_cast(argc); ++i) { std::string token = argv[i]; // Store non-option arguments in the provided vector. if (! parse_options || ! boost::starts_with(token, "-")) { @@ -1714,7 +1716,7 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option // If the option type expects a value and it was not already provided, // look for it in the next token. if (value.empty() && optdef.type != coBool && optdef.type != coBools) { - if (i == argc-1) { + if (i == static_cast(argc) - 1) { boost::nowide::cerr << "No value supplied for --" << token.c_str() << std::endl; return false; } diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp index 2a0ae01b766..b1e772acd83 100644 --- a/src/libslic3r/ExtrusionEntity.cpp +++ b/src/libslic3r/ExtrusionEntity.cpp @@ -160,7 +160,7 @@ bool ExtrusionLoop::split_at_vertex(const Point &point, const double scaled_epsi path->polyline.swap(p2); // swap points & fitting result } } else if (idx > 0) { - if (idx < path->size() - 1) { + if (static_cast(idx) < path->size() - 1) { // new paths list starts with the second half of current path ExtrusionPaths new_paths; PolylineOrArc p1, p2; @@ -466,7 +466,7 @@ std::string looprole_to_code(ExtrusionLoopRole looprole) void ExtrusionPrinter::use(const ExtrusionPath &path) { ss << (json?"\"":"") << "ExtrusionPath" << (path.can_reverse()?"":"Oriented") << (json?"_":":") << role_to_code(path.role()) << (json?"\":":"") << "["; - for (int i = 0; i < path.polyline.size(); i++) { + for (size_t i = 0; i < path.polyline.size(); i++) { if (i != 0) ss << ","; double x = (mult * (path.polyline.get_points()[i].x())); double y = (mult * (path.polyline.get_points()[i].y())); @@ -476,7 +476,7 @@ void ExtrusionPrinter::use(const ExtrusionPath &path) { } void ExtrusionPrinter::use(const ExtrusionPath3D &path3D) { ss << (json?"\"":"") << "ExtrusionPath3D" << (path3D.can_reverse()?"":"Oriented") << (json?"_":":") << role_to_code(path3D.role()) << (json?"\":":"") << "["; - for (int i = 0; i < path3D.polyline.size();i++){ + for (size_t i = 0; i < path3D.polyline.size(); i++) { if (i != 0) ss << ","; double x = (mult * (path3D.polyline.get_points()[i].x())); double y = (mult * (path3D.polyline.get_points()[i].y())); @@ -487,7 +487,7 @@ void ExtrusionPrinter::use(const ExtrusionPath3D &path3D) { } void ExtrusionPrinter::use(const ExtrusionMultiPath &multipath) { ss << (json?"\"":"") << "ExtrusionMultiPath" << (multipath.can_reverse()?"":"Oriented") << (json?"_":":") << role_to_code(multipath.role()) << (json?"\":":"") << "{"; - for (int i = 0; i < multipath.paths.size(); i++) { + for (size_t i = 0; i < multipath.paths.size(); i++) { if (i != 0) ss << ","; multipath.paths[i].visit(*this); } @@ -495,7 +495,7 @@ void ExtrusionPrinter::use(const ExtrusionMultiPath &multipath) { } void ExtrusionPrinter::use(const ExtrusionMultiPath3D &multipath3D) { ss << (json?"\"":"") << "multipath3D" << (multipath3D.can_reverse()?"":"Oriented") << (json?"_":":") << role_to_code(multipath3D.role()) << (json?"\":":"") << "{"; - for (int i = 0; i < multipath3D.paths.size(); i++) { + for (size_t i = 0; i < multipath3D.paths.size(); i++) { if (i != 0) ss << ","; multipath3D.paths[i].visit(*this); } @@ -504,7 +504,7 @@ void ExtrusionPrinter::use(const ExtrusionMultiPath3D &multipath3D) { void ExtrusionPrinter::use(const ExtrusionLoop &loop) { ss << (json?"\"":"") << "ExtrusionLoop" << (json?"_":":") << role_to_code(loop.role())<<"_" << looprole_to_code(loop.loop_role()) << (json?"\":":"") << "{"; if(!loop.can_reverse()) ss << (json?"\"":"") << "oriented" << (json?"\":":"=") << "true,"; - for (int i = 0; i < loop.paths.size(); i++) { + for (size_t i = 0; i < loop.paths.size(); i++) { if (i != 0) ss << ","; loop.paths[i].visit(*this); } @@ -514,17 +514,16 @@ void ExtrusionPrinter::use(const ExtrusionEntityCollection &collection) { ss << (json?"\"":"") << "ExtrusionEntityCollection" << (json?"_":":") << role_to_code(collection.role()) << (json?"\":":"") << "{"; if(!collection.can_sort()) ss << (json?"\"":"") << "no_sort" << (json?"\":":"=") << "true,"; if(!collection.can_reverse()) ss << (json?"\"":"") << "oriented" << (json?"\":":"=") << "true,"; - for (int i = 0; i < collection.entities().size(); i++) { + for (size_t i = 0; i < collection.entities().size(); i++) { if (i != 0) ss << ","; collection.entities()[i]->visit(*this); } ss << "}"; } - void ExtrusionLength::default_use(const ExtrusionEntity& entity) { dist += entity.length(); }; void ExtrusionLength::use(const ExtrusionEntityCollection& collection) { - for (int i = 0; i < collection.entities().size(); i++) { + for (size_t i = 0; i < collection.entities().size(); i++) { collection.entities()[i]->visit(*this); } } diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index a6b2798aa31..4525c7e4925 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -324,7 +324,6 @@ Fill::do_gap_fill(const ExPolygons& gapfill_areas, const FillParams& params, Ext ThickPolylines polylines_gapfill; double min = 0.4 * scale_(params.flow.nozzle_diameter()) * (1 - INSET_OVERLAP_TOLERANCE); - double max = 2. * params.flow.scaled_width(); // collapse //be sure we don't gapfill where the perimeters are already touching each other (negative spacing). min = std::max(min, double(Flow::new_from_spacing((float)EPSILON, (float)params.flow.nozzle_diameter(), (float)params.flow.height(), 1, false).scaled_width())); @@ -957,9 +956,8 @@ namespace PrusaSimpleConnect { ContourPointData& bdp = boundary_data[it_contour_and_segment->first][it_contour_and_segment->second]; bdp.segment_consumed = true; // There is no need for checking seg_pt2 as it will be checked the next time. - bool point_touching = false; if (segment_point_distance_squared(*this->pt1, *this->pt2, seg_pt1) < this->dist2_max) { - point_touching = true; + // point_touching = true; bdp.point_consumed = true; } #if 0 @@ -1155,8 +1153,6 @@ namespace PrusaSimpleConnect { std::vector connections_sorted; connections_sorted.reserve(infill_ordered.size() * 2 - 2); for (size_t idx_chain = 1; idx_chain < infill_ordered.size(); ++idx_chain) { - const Polyline& pl1 = infill_ordered[idx_chain - 1]; - const Polyline& pl2 = infill_ordered[idx_chain]; const std::pair* cp1 = &map_infill_end_point_to_boundary[(idx_chain - 1) * 2 + 1]; const std::pair* cp2 = &map_infill_end_point_to_boundary[idx_chain * 2]; if (cp1->first != boundary_idx_unconnected && cp1->first == cp2->first) { @@ -1196,7 +1192,6 @@ namespace PrusaSimpleConnect { } assert(boundary_data.size() == boundary_src.holes.size() + 1); - size_t idx_chain_last = 0; for (ConnectionCost& connection_cost : connections_sorted) { const std::pair* cp1 = &map_infill_end_point_to_boundary[connection_cost.idx_first * 2 + 1]; const std::pair* cp1prev = cp1 - 1; diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index 66262843b83..b00ffd31aee 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -28,7 +28,7 @@ FillConcentric::_fill_surface_single( Polylines &polylines_out) const { // no rotation is supported for this infill pattern - BoundingBox bounding_box = expolygon.contour.bounding_box(); + expolygon.contour.bounding_box(); coord_t distance = _line_spacing_for_density(params); if (params.density > 0.9999f && !params.dont_adjust) { @@ -110,10 +110,10 @@ FillConcentricWGapFill::fill_surface_extrusion( //polylines_out); ExPolygon expolygon = expp[i]; - coordf_t init_spacing = this->get_spacing(); + this->get_spacing(); // no rotation is supported for this infill pattern - BoundingBox bounding_box = expolygon.contour.bounding_box(); + expolygon.contour.bounding_box(); coord_t distance = _line_spacing_for_density(params); if (params.density > 0.9999f && !params.dont_adjust) { @@ -196,7 +196,7 @@ FillConcentricWGapFill::fill_surface_extrusion( assert(bunch_2_shell_2_loops.size() == bunch_2_gaps.size() || bunch_2_shell_2_loops.size() == bunch_2_gaps.size() + 1); //for each "shell" (loop to print before a gap) - for (int idx_bunch = 0; idx_bunch < bunch_2_shell_2_loops.size(); idx_bunch++) { + for (size_t idx_bunch = 0; idx_bunch < bunch_2_shell_2_loops.size(); idx_bunch++) { //we have some "starting loops". for each 'shell', we get each loop and find (by searching which one it fit inside) its island. // if there is none or multiple, then we have to start again from these new loops. @@ -289,7 +289,7 @@ FillConcentricWGapFill::fill_surface_extrusion( //TODO: move items that are alone in a collection to the upper collection. //add gapfills - if (idx_bunch < bunch_2_gaps.size() && !bunch_2_gaps[idx_bunch].empty() && params.density >= 1) { + if (static_cast(idx_bunch) < bunch_2_gaps.size() && !bunch_2_gaps[idx_bunch].empty() && params.density >= 1) { // get parameters coordf_t min = 0.2 * distance * (1 - INSET_OVERLAP_TOLERANCE); //be sure we don't gapfill where the perimeters are already touching each other (negative spacing). @@ -401,7 +401,7 @@ FillConcentricWGapFill::fill_surface_extrusion( if (gapfill_areas.size() > 0 && no_overlap_expolygons.size() > 0) { double minarea = double(params.flow.scaled_width()) * double(params.flow.scaled_width()); if (params.config != nullptr) minarea = scale_d(params.config->gap_fill_min_area.get_abs_value(params.flow.width())) * double(params.flow.scaled_width()); - for (int i = 0; i < gapfill_areas.size(); i++) { + for (size_t i = 0; i < gapfill_areas.size(); i++) { if (gapfill_areas[i].area() < minarea) { gapfill_areas.erase(gapfill_areas.begin() + i); i--; @@ -419,8 +419,6 @@ FillConcentricWGapFill::fill_surface_extrusion( // check if not over-extruding if (!params.dont_adjust && params.full_infill() && !params.flow.bridge() && params.fill_exactly) { // compute the path of the nozzle -> extruded volume - double length_tot = 0; - int nb_lines = 0; ExtrusionVolume get_volume; for (ExtrusionEntity *ee : out_to_check) ee->visit(get_volume); // compute flow to remove spacing_ratio from the equation diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 76984b8dbd6..4ea3b1d6544 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -1141,7 +1141,7 @@ static void connect_segment_intersections_by_contours( int iprev = -1; int d_prev = std::numeric_limits::max(); if (il_prev) { - for (int i = 0; i < il_prev->intersections.size(); ++i) { + for (size_t i = 0; i < il_prev->intersections.size(); ++i) { const SegmentIntersection& itsct2 = il_prev->intersections[i]; if (itsct.iContour == itsct2.iContour && itsct.type == itsct2.type) { // The intersection points lie on the same contour and have the same orientation. @@ -1240,7 +1240,7 @@ static void connect_segment_intersections_by_contours( if (same_prev && same_next) { assert(iprev != i_intersection); assert(inext != i_intersection); - if ((iprev > i_intersection) == (inext > i_intersection)) { + if ((static_cast(iprev) > i_intersection) == (static_cast(inext) > i_intersection)) { // Both closest intersections of this contour are on the same vertical line and at the same side of this point. // Ignore them when tracing the infill. itsct.prev_on_contour_quality = SegmentIntersection::LinkQuality::Invalid; @@ -1276,7 +1276,7 @@ static void connect_segment_intersections_by_contours( SegmentIntersection& it = il.intersections[i_intersection]; if (it.has_left_vertical()) { SegmentIntersection& it2 = il.intersections[it.left_vertical()]; - if (it2.left_vertical() != i_intersection) { + if (it2.left_vertical() != static_cast(i_intersection)) { // as it can happen that a vertical connection isn't symetric, if it happens, break the erroneous link it.prev_on_contour = -1; it.prev_on_contour_type = SegmentIntersection::LinkType::Phony; @@ -1284,7 +1284,7 @@ static void connect_segment_intersections_by_contours( } if (it.has_right_vertical()) { SegmentIntersection& it2 = il.intersections[it.right_vertical()]; - if (it2.right_vertical() != i_intersection) { + if (it2.right_vertical() != static_cast(i_intersection)) { // as it can happen that a vertical connection isn't symetric, if it happens, break the erroneous link it.next_on_contour = -1; it.next_on_contour_type = SegmentIntersection::LinkType::Phony; @@ -1337,9 +1337,13 @@ static void pinch_contours_insert_phony_outer_intersections(std::vectorenum_keys_map) { @@ -3252,14 +3251,14 @@ namespace Slic3r { if (option != nullptr && option->type() == ConfigOptionType::coEnum) { try{ log << "raw_int_value : " << option->get_int() << "\n"; - } catch (std::exception ex) {} + } catch (const std::exception& ex) {} log << "enum : " << option->get_int(); log << "\n"; const ConfigOptionDef* def = nullptr; try { def = print_config.get_option_def(key); } - catch (Exception) {} + catch (const Slic3r::Exception& ex) {} if (def != nullptr) { log << "map : " << "\n"; for (const auto& entry : *def->enum_keys_map) { @@ -3367,14 +3366,14 @@ namespace Slic3r { if (option != nullptr && option->type() == ConfigOptionType::coEnum) { try{ log << "raw_int_value : " << option->get_int() << "\n"; - } catch (std::exception ex) {} + } catch (const std::exception& ex) {} log << "enum : " << option->get_int(); log << "\n"; const ConfigOptionDef* def = nullptr; try { def = print_config.get_option_def(key); } - catch (Exception) {} + catch (const std::exception& ex) {} if (def != nullptr) { log << "map : " << "\n"; for (const auto& entry : *def->enum_keys_map) { diff --git a/src/libslic3r/Format/BBConfig.cpp b/src/libslic3r/Format/BBConfig.cpp index ebadab2fba5..fbf0d1800a6 100644 --- a/src/libslic3r/Format/BBConfig.cpp +++ b/src/libslic3r/Format/BBConfig.cpp @@ -560,7 +560,7 @@ bool push_into_custom_variables(DynamicPrintConfig & print_config, { if (auto it = key_custom_settings_translation_map.find(opt_key); it != key_custom_settings_translation_map.end()) { if ((it->second & bbstFFF_FILAMENT) != 0 || (it->second & bbstSLA_MATERIAL) != 0) { - for (int i = 0; i < opt_value.size(); ++i) { + for (auto i = 0u; i < opt_value.size(); ++i) { if (print_config.opt("filament_custom_variables") == nullptr) print_config.set_deserialize("filament_custom_variables", ""); const std::string &val = print_config.opt("filament_custom_variables")->get_at(i); @@ -628,8 +628,7 @@ bool read_json_file_bambu(const std_path &temp_file, std::string new_support_style; std::string is_infill_first; std::string get_wall_sequence; - bool is_project_settings = false; - + // bool is_project_settings = false; CNumericLocalesSetter locales_setter; try { @@ -650,8 +649,8 @@ bool read_json_file_bambu(const std_path &temp_file, key_values.emplace(BBL_JSON_KEY_IS_CUSTOM, it.value()); } else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) { key_values.emplace(BBL_JSON_KEY_NAME, it.value()); - if (it.value() == "project_settings") - is_project_settings = true; + // if (it.value() == "project_settings") + // is_project_settings = true; } else if (boost::iequals(it.key(), BBL_JSON_KEY_URL)) { key_values.emplace(BBL_JSON_KEY_URL, it.value()); } else if (boost::iequals(it.key(), BBL_JSON_KEY_TYPE)) { diff --git a/src/libslic3r/Format/SLAArchive.cpp b/src/libslic3r/Format/SLAArchive.cpp index 337c7f26158..124a0f6c1d1 100644 --- a/src/libslic3r/Format/SLAArchive.cpp +++ b/src/libslic3r/Format/SLAArchive.cpp @@ -5,17 +5,17 @@ using ConfMap = std::map; namespace { -std::string get_cfg_value(const DynamicPrintConfig &cfg, const std::string &key) -{ - std::string ret; +// std::string get_cfg_value(const DynamicPrintConfig &cfg, const std::string &key) +// { +// std::string ret; - if (cfg.has(key)) { - auto opt = cfg.option(key); - if (opt) ret = opt->serialize(); - } +// if (cfg.has(key)) { +// auto opt = cfg.option(key); +// if (opt) ret = opt->serialize(); +// } - return ret; -} +// return ret; +// } } // namespace diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index eb2c62b4c12..2a792490a3b 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -1595,7 +1595,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } while (it != m_plater_data.end()) { - if (it->first > m_plater_data.size()) + if (it->first > static_cast(m_plater_data.size())) { add_error("invalid plate index"); return false; @@ -1743,9 +1743,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } else { _extract_xml_from_archive(archive, sub_rels, _handle_start_relationships_element, _handle_end_relationships_element); - int index = 0; + #if 0 + int index = 0; for (auto path : m_sub_model_paths) { if (proFn) { proFn(IMPORT_STAGE_READ_FILES, ++index, 3 + m_sub_model_paths.size(), cb_cancel); @@ -1992,7 +1993,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) ObjectMetadata::VolumeMetadataList volumes; ObjectMetadata::VolumeMetadataList* volumes_ptr = nullptr; - for (int k = 0; k < object_id_list.size(); k++) + for (size_t k = 0; k < object_id_list.size(); k++) { Id object_id = object_id_list[k].object_id; volumes.emplace_back(object_id.second); @@ -2033,7 +2034,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", begin to assemble objects, size %1%\n")%m_objects.size(); //only load objects in plate_id PlateData* current_plate_data = nullptr; - if ((plate_id > 0) && (plate_id <= m_plater_data.size())) { + if ((plate_id > 0) && (static_cast(plate_id) <= m_plater_data.size())) { std::map::iterator it =m_plater_data.find(plate_id); if (it != m_plater_data.end()) { current_plate_data = it->second; @@ -2113,7 +2114,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // add the entire geometry as the single volume to generate //volumes.emplace_back(0, (int)obj_geometry->second.triangles.size() - 1); - for (int k = 0; k < object_id_list.size(); k++) + for (size_t k = 0; k < object_id_list.size(); k++) { Id object_id = object_id_list[k].object_id; volumes.emplace_back(object_id.second); @@ -2247,7 +2248,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } while (it != m_plater_data.end()) { - if (it->first > m_plater_data.size()) + if (it->first > static_cast(m_plater_data.size())) { add_error("invalid plate index"); return false; @@ -2298,27 +2299,27 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } obj_index = object_item->second; - if (obj_index >= m_model->objects.size()) { + if (static_cast(obj_index) >= m_model->objects.size()) { BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid object id %1%\n")%obj_index; map_it++; continue; } ModelObject* obj = m_model->objects[obj_index]; - if (inst_index >= obj->instances.size()) { + if (static_cast(inst_index) >= obj->instances.size()) { BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid instance id %1%\n")%inst_index; map_it++; continue; } - ModelInstance* inst = obj->instances[inst_index]; + // ModelInstance* inst = obj->instances[inst_index]; //inst->loaded_id = map_it->second.second; //Susi_not_impl map_it++; } } - if ((plate_id > 0) && (plate_id <= m_plater_data.size())) { + if ((plate_id > 0) && (static_cast(plate_id) <= m_plater_data.size())) { //remove the no need objects std::vector delete_ids; - for (int index = 0; index < m_model->objects.size(); index++) { + for (size_t index = 0; index < m_model->objects.size(); index++) { ModelObject* obj = m_model->objects[index]; if (obj->volumes.size() == 0) { //remove this model objects @@ -2347,7 +2348,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _BBS_3MF_Importer::_extract_from_archive(mz_zip_archive& archive, std::string const & path, std::function extract, bool restore) { - mz_uint num_entries = mz_zip_reader_get_num_files(&archive); + mz_zip_reader_get_num_files(&archive); mz_zip_archive_file_stat stat; std::string path2 = path; if (path2.front() == '/') path2 = path2.substr(1); @@ -3130,8 +3131,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } if (code.first == "layer") { pt::ptree tree = code.second; - double print_z = tree.get(".top_z"); - int extruder = tree.get(".extruder"); + tree.get(".top_z"); + tree.get(".extruder"); std::string color = tree.get(".color"); CustomGCode::Type type; @@ -3463,9 +3464,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // Adjust backup object/volume id std::istringstream iss(m_curr_object->uuid); int backup_id; - bool need_replace = false; + // bool need_replace = false; if (iss >> std::hex >> backup_id) { - need_replace = (m_curr_object->id != backup_id); + // need_replace = (m_curr_object->id != backup_id); m_curr_object->id = backup_id; } if (!m_curr_object->components.empty()) @@ -3474,7 +3475,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) first_id.second = 0; IdToCurrentObjectMap::iterator current_object = m_current_objects.lower_bound(first_id); IdToCurrentObjectMap new_map; - for (int index = 0; index < m_curr_object->components.size(); index++) + for (size_t index = 0; index < m_curr_object->components.size(); index++) { Component& component = m_curr_object->components[index]; Id new_id = component.object_id; @@ -3928,7 +3929,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } // Definition of read/write method for EmbossShape - static void to_xml(std::stringstream &stream, /*const EmbossShape &es, */const ModelVolume &volume, mz_zip_archive &archive); + // static void to_xml(std::stringstream &stream, /*const EmbossShape &es, */const ModelVolume &volume, mz_zip_archive &archive); //static std::optional read_emboss_shape(const char **attributes, unsigned int num_attributes); //Susi_not_impl bool _BBS_3MF_Importer::_handle_start_shape_configuration(const char **attributes, unsigned int num_attributes) @@ -3943,7 +3944,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) add_error("Can not assign mesh to a valid volume"); return false; } - ObjectMetadata::VolumeMetadata &volume = volumes.back(); + ObjectMetadata::VolumeMetadata& volume = volumes.back(); //volume.shape_configuration = read_emboss_shape(attributes, num_attributes); //if (!volume.shape_configuration.has_value()) // return false; //Susi_not_impl @@ -4158,7 +4159,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) add_error("can not find object for mesh_stats, id " + std::to_string(m_curr_config.object_id) ); return false; } - if ((m_curr_config.volume_id == -1) || ((object->second.volumes.size() - 1) < m_curr_config.volume_id)) { + if ((m_curr_config.volume_id == -1) || ((int)(object->second.volumes.size() - 1) < m_curr_config.volume_id)) { add_error("can not find part for mesh_stats"); return false; } @@ -4488,10 +4489,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } object_id = object_item->second; - Transform3d transform = bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); - Vec3d ofs2ass = bbs_get_offset_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, OFFSET_ATTR)); - if (object_id < m_model->objects.size()) { - if (instance_id < m_model->objects[object_id]->instances.size()) { + bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); + bbs_get_offset_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, OFFSET_ATTR)); + if (static_cast(object_id) < m_model->objects.size()) { + if (static_cast(instance_id) < m_model->objects[object_id]->instances.size()) { //m_model->objects[object_id]->instances[instance_id]->set_assemble_from_transform(transform); //Susi_not_impl //m_model->objects[object_id]->instances[instance_id]->set_offset_to_assembly(ofs2ass); //Susi_not_impl } diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index 3d9d48e0893..d404595a495 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -928,7 +928,7 @@ std::string CoolingBuffer::apply_layer_cooldown( { int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers); // Is the fan speed ramp enabled? - int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer); + //int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer); if (int(layer_id) >= disable_fan_first_layers) { int max_fan_speed = EXTRUDER_CONFIG(max_fan_speed); float slowdown_below_layer_time = float(EXTRUDER_CONFIG(slowdown_below_layer_time)); diff --git a/src/libslic3r/GCode/FanMover.cpp b/src/libslic3r/GCode/FanMover.cpp index f124425fd7b..577fed78d25 100644 --- a/src/libslic3r/GCode/FanMover.cpp +++ b/src/libslic3r/GCode/FanMover.cpp @@ -266,7 +266,6 @@ void FanMover::_process_T(const std::string_view command) void FanMover::_process_ACTIVATE_EXTRUDER(const std::string_view cmd) { if (size_t cmd_end = cmd.find("ACTIVATE_EXTRUDER"); cmd_end != std::string::npos) { - bool error = false; size_t extruder_pos_start = cmd.find("EXTRUDER", cmd_end + std::string_view("ACTIVATE_EXTRUDER").size()) + std::string_view("EXTRUDER").size(); assert(cmd[extruder_pos_start - 1] == 'R'); if (extruder_pos_start != std::string::npos) { @@ -471,11 +470,13 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode current_role = ExtrusionEntity::string_to_role(extrusion_string); } if (line.raw().size() > 16) { - if (line.raw().rfind("; custom gcode", 0) != std::string::npos) - if (line.raw().rfind("; custom gcode end", 0) != std::string::npos) + if (line.raw().rfind("; custom gcode", 0) != std::string::npos) { + if (line.raw().rfind("; custom gcode end", 0) != std::string::npos) { m_is_custom_gcode = false; - else + } else { m_is_custom_gcode = true; + } + } } } } diff --git a/src/libslic3r/GCode/PressureEqualizer.cpp b/src/libslic3r/GCode/PressureEqualizer.cpp index 1b9ed4be245..e396455194d 100644 --- a/src/libslic3r/GCode/PressureEqualizer.cpp +++ b/src/libslic3r/GCode/PressureEqualizer.cpp @@ -411,7 +411,6 @@ bool PressureEqualizer::process_line(const char *line, const char *line_end, GCo void PressureEqualizer::parse_activate_extruder(const std::string &line_str) { if (size_t cmd_end = line_str.find("CTIVATE_EXTRUDER"); cmd_end != std::string::npos) { - bool error = false; size_t extruder_pos_start = line_str.find("EXTRUDER", cmd_end + std::string_view("CTIVATE_EXTRUDER").size()) + std::string_view("EXTRUDER").size(); assert(line_str[extruder_pos_start - 1] == 'R'); diff --git a/src/libslic3r/GCode/Thumbnails.cpp b/src/libslic3r/GCode/Thumbnails.cpp index cfdcfff016e..3fe931d954a 100644 --- a/src/libslic3r/GCode/Thumbnails.cpp +++ b/src/libslic3r/GCode/Thumbnails.cpp @@ -53,7 +53,6 @@ std::unique_ptr compress_thumbnail_biqu(const ThumbnailDa out->size = data.height * (2 + data.width * 4) + 1; out->data = malloc(out->size); - int idx = 0; std::stringstream tohex; tohex << std::setfill('0') << std::hex; for (size_t y = 0; y < data.height; ++y) { diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 760fd9683d3..a7fd86bbddb 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -555,7 +555,7 @@ PagePrinters::PagePrinters(ConfigWizard *parent, const t_config_option_keys families = vendor.families(); for (const std::string &family : families) { const auto filter = [&](const VendorProfile::PrinterModel &model) { - return (model.technology == technology) + return (static_cast(model.technology) == static_cast(technology)) && model.family == family; }; diff --git a/src/slic3r/GUI/RammingChart.cpp b/src/slic3r/GUI/RammingChart.cpp index 9110e75f134..843f6268746 100644 --- a/src/slic3r/GUI/RammingChart.cpp +++ b/src/slic3r/GUI/RammingChart.cpp @@ -206,7 +206,6 @@ void Chart::mouse_clicked(wxMouseEvent& event) { void Chart::mouse_moved(wxMouseEvent& event) { wxPoint pos = event.GetPosition(); wxRect rect = m_rect; - size_t button_idx_hover_old = button_idx_hover; button_idx_hover = size_t(-1); rect.Deflate(side/2.); if (!(rect.Contains(pos))) { // the mouse left chart area @@ -381,7 +380,7 @@ void Chart::recalculate_line() { m_line_to_draw.push_back(points.back().y); } else { assert(curr_idx <= N); - if (curr_idx < N && points[curr_idx].x < x) { + if (curr_idx < static_cast(N) && points[curr_idx].x < x) { ++curr_idx; } if (this->m_type == Slic3r::GraphData::GraphType::SPLINE) { diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b30b2d2f485..04fb2482565 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4561,7 +4561,8 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep // Collect and set indices of depending_presets marked as compatible. wxArrayInt selections; auto *compatible_printers = dynamic_cast(m_config_base->option(deps.key_list)); - if (compatible_printers != nullptr || !compatible_printers->empty()) + // if (compatible_printers != nullptr || !compatible_printers->empty()) + if (this && compatible_printers && !compatible_printers->empty()) for (auto preset_name : compatible_printers->get_values()) for (size_t idx = 0; idx < presets.GetCount(); ++idx) if (presets[idx] == preset_name) { From eceda131fc862cabc5793c9ac66e6e51d2c4295c Mon Sep 17 00:00:00 2001 From: wschadow Date: Sun, 7 Jul 2024 23:51:01 +0200 Subject: [PATCH 07/10] cleaning 3 (wip) --- src/admesh/connect.cpp | 6 +- src/libslic3r/Fill/Fill.cpp | 2 +- src/libslic3r/Fill/FillRectilinear.cpp | 1 - src/libslic3r/Fill/FillSmooth.cpp | 1 - src/libslic3r/Format/bbs_3mf.cpp | 6 +- src/libslic3r/GCode.cpp | 103 +- .../GCode/AvoidCrossingPerimeters.cpp | 128 +-- src/libslic3r/GCode/GCodeProcessor.cpp | 20 +- src/libslic3r/GCode/SeamPlacer.cpp | 10 +- src/libslic3r/GCode/ToolOrdering.cpp | 17 +- src/libslic3r/GCodeWriter.cpp | 6 +- src/libslic3r/Geometry/Circle.cpp | 6 +- src/libslic3r/Geometry/MedialAxis.cpp | 19 +- src/libslic3r/LayerRegion.cpp | 4 +- src/libslic3r/Milling/MillingPostProcess.cpp | 10 +- src/libslic3r/Model.cpp | 2 +- src/libslic3r/PerimeterGenerator.cpp | 136 +-- src/libslic3r/Polyline.cpp | 4 +- src/libslic3r/PrintBase.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 7 +- src/libslic3r/PrintObjectSlice.cpp | 2 +- src/libslic3r/SVG.cpp | 2 +- src/libslic3r/SupportMaterial.cpp | 42 +- src/slic3r/GUI/CalibrationAbstractDialog.cpp | 1 - src/slic3r/GUI/CalibrationBridgeDialog.cpp | 12 +- src/slic3r/GUI/CalibrationCubeDialog.cpp | 8 +- .../GUI/CalibrationPressureAdvDialog.cpp | 7 +- .../GUI/CalibrationRetractionDialog.cpp | 5 - src/slic3r/GUI/CalibrationTempDialog.cpp | 6 +- src/slic3r/GUI/ConfigManipulation.cpp | 6 +- src/slic3r/GUI/CreateMMUTiledCanvas.cpp | 72 +- src/slic3r/GUI/DoubleSlider.cpp | 25 +- src/slic3r/GUI/Field.cpp | 898 +++++++++--------- src/slic3r/GUI/FreeCADDialog.cpp | 7 +- src/slic3r/GUI/GLCanvas3D.cpp | 20 +- src/slic3r/GUI/GUI_Factories.cpp | 44 +- src/slic3r/GUI/GalleryDialog.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 4 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 8 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 7 +- src/slic3r/GUI/MainFrame.cpp | 27 +- src/slic3r/GUI/OG_CustomCtrl.cpp | 34 +- src/slic3r/GUI/OptionsGroup.cpp | 11 +- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 4 +- src/slic3r/GUI/Plater.cpp | 7 +- src/slic3r/GUI/PresetComboBoxes.cpp | 27 +- src/slic3r/GUI/Tab.cpp | 83 +- src/slic3r/GUI/wxExtensions.cpp | 2 +- src/stb_dxt/stb_dxt.h | 90 +- 49 files changed, 992 insertions(+), 963 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index 8c3ab154adf..82b5460977c 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -216,7 +216,7 @@ struct HashTableEdges { // This is a match. Record result in neighbors list. match_neighbors(edge, *link->next); // Delete the matched edge from the list. - HashEdge *temp = link->next; + link->next; link->next = link->next->next; // pool.destroy(temp); #ifndef NDEBUG @@ -484,7 +484,7 @@ void stl_check_facets_nearby(stl_file *stl, float tolerance) assert(stl->stats.connected_facets_2_edge <= stl->stats.connected_facets_1_edge); assert(stl->stats.connected_facets_1_edge <= stl->stats.number_of_facets); - if (stl->stats.connected_facets_3_edge == stl->stats.number_of_facets) + if (stl->stats.connected_facets_3_edge == static_cast(stl->stats.number_of_facets)) // No need to check any further. All facets are connected. return; @@ -533,7 +533,7 @@ void stl_remove_unconnected_facets(stl_file *stl) for (int i = 0; i < 3; ++ i) if (neighbors.neighbor[i] != -1) { int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; - if (other_face_idx != stl->stats.number_of_facets) { + if (other_face_idx != static_cast(stl->stats.number_of_facets)) { BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong"; return; } diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 45c972bf414..352707f53b5 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -580,7 +580,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: // calculate flow spacing for infill pattern generation //FIXME FLOW decide if using surface_fill.params.flow.bridge() or surface_fill.params.bridge (default but deleted) - bool using_internal_flow = ! surface_fill.surface.has_fill_solid() && !surface_fill.params.flow.bridge(); + //bool using_internal_flow = ! surface_fill.surface.has_fill_solid() && !surface_fill.params.flow.bridge(); //init spacing, it may also use & modify a bit the surface_fill.params, so most of these should be set before. // note that the bridge overlap is applied here via the rectilinear init_spacing. f->init_spacing(surface_fill.params.spacing, surface_fill.params); diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 4ea3b1d6544..b73149770f0 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -1327,7 +1327,6 @@ static void pinch_contours_insert_phony_outer_intersections(std::vector 2 instead of !empty() assert(il.intersections.front().type == SegmentIntersection::OUTER_LOW); assert(il.intersections.back().type == SegmentIntersection::OUTER_HIGH); - auto end = il.intersections.end() - 1; insert_after.clear(); size_t idx = 1; while(idx < il.intersections.size()) { diff --git a/src/libslic3r/Fill/FillSmooth.cpp b/src/libslic3r/Fill/FillSmooth.cpp index 0e039f59909..cff6641d802 100644 --- a/src/libslic3r/Fill/FillSmooth.cpp +++ b/src/libslic3r/Fill/FillSmooth.cpp @@ -129,7 +129,6 @@ namespace Slic3r { void FillSmooth::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const { - coordf_t init_spacing = this->get_spacing(); //create root node ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection(); diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 2a792490a3b..1171bf0bfad 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -5142,14 +5142,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (is_bbl_3mf && boost::ends_with(current_object->uuid, OBJECT_UUID_SUFFIX) && top_importer->m_load_restore) { std::istringstream iss(current_object->uuid); int backup_id; - bool need_replace = false; + // bool need_replace = false; if (iss >> std::hex >> backup_id) { - need_replace = (current_object->id != backup_id); + // need_replace = (current_object->id != backup_id); current_object->id = backup_id; } //if (need_replace) { - for (int index = 0; index < current_object->components.size(); index++) + for (size_t index = 0; index < current_object->components.size(); index++) { int temp_id = (index + 1) << 16 | backup_id; Component& component = current_object->components[index]; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 84f8697b534..b29c9a622b6 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -88,31 +88,31 @@ static inline void check_add_eol(std::string& gcode) // Return true if tch_prefix is found in custom_gcode -static bool custom_gcode_changes_tool(const std::string& custom_gcode, const std::string& tch_prefix, unsigned next_extruder) -{ -bool ok = false; -size_t from_pos = 0; -size_t pos = 0; -while ((pos = custom_gcode.find(tch_prefix, from_pos)) != std::string::npos) { - if (pos + 1 == custom_gcode.size()) - break; - from_pos = pos + 1; - // only whitespace is allowed before the command - while (--pos < custom_gcode.size() && custom_gcode[pos] != '\n') { - if (!std::isspace(custom_gcode[pos])) - goto NEXT; - } - { - // we should also check that the extruder changes to what was expected - std::istringstream ss(custom_gcode.substr(from_pos, std::string::npos)); - unsigned num = 0; - if (ss >> num) - ok = (num == next_extruder); - } - NEXT:; - } - return ok; -} +// static bool custom_gcode_changes_tool(const std::string& custom_gcode, const std::string& tch_prefix, unsigned next_extruder) +// { +// bool ok = false; +// size_t from_pos = 0; +// size_t pos = 0; +// while ((pos = custom_gcode.find(tch_prefix, from_pos)) != std::string::npos) { +// if (pos + 1 == custom_gcode.size()) +// break; +// from_pos = pos + 1; +// // only whitespace is allowed before the command +// while (--pos < custom_gcode.size() && custom_gcode[pos] != '\n') { +// if (!std::isspace(custom_gcode[pos])) +// goto NEXT; +// } +// { +// // we should also check that the extruder changes to what was expected +// std::istringstream ss(custom_gcode.substr(from_pos, std::string::npos)); +// unsigned num = 0; +// if (ss >> num) +// ok = (num == next_extruder); +// } +// NEXT:; +// } +// return ok; +// } double get_default_acceleration(PrintConfig& config) { double max = 0; @@ -192,7 +192,7 @@ void Wipe::append(const Polyline &poly) { assert(!poly.empty()); if (!this->path.empty() && path.last_point().coincides_with_epsilon(poly.first_point())) { - int copy_start_idx = 0; + size_t copy_start_idx = 0; while (copy_start_idx < poly.size() && poly.points[copy_start_idx].distance_to(this->path.last_point()) < SCALED_EPSILON) { copy_start_idx++; } @@ -241,7 +241,7 @@ std::string Wipe::wipe(GCode& gcodegen, bool toolchange) /* Take the stored wipe path and replace first point with the current actual position (they might be different, for example, in case of loop clipping). */ Polyline wipe_path; - int copy_start_idx = 0; + size_t copy_start_idx = 0; // Compute a min dist between point, to avoid going under the precision. assert(gcodegen.m_last_width < SCALED_EPSILON); coordf_t precision = pow(10, -gcodegen.config().gcode_precision_xyz.value) * 1.5; @@ -606,7 +606,7 @@ std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower: const std::vector ColorPrintColors::Colors = { "#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6" }; #define EXTRUDER_CONFIG_WITH_DEFAULT(OPT,DEF) (m_writer.tool_is_extruder()?m_config.OPT.get_at(m_writer.tool()->id()):DEF) -#define BOOL_EXTRUDER_CONFIG(OPT) m_writer.tool_is_extruder() && m_config.OPT.get_at(m_writer.tool()->id()) +#define BOOL_EXTRUDER_CONFIG(OPT) (m_writer.tool_is_extruder() && m_config.OPT.get_at(m_writer.tool()->id())) constexpr float SMALL_PERIMETER_SPEED_RATIO_OFFSET = (-10); @@ -689,7 +689,7 @@ std::vector GCode::collect_layers_to_print(const PrintObjec || (layer_to_print.support_layer /* && layer_to_print.support_layer->has_extrusions() */)) { double extra_gap = (layer_to_print.support_layer ? bottom_cd : top_cd); - if (object.config().raft_layers.value > 0 && layer_to_print.layer()->id() <= object.config().raft_layers.value) { + if (object.config().raft_layers.value > 0 && layer_to_print.layer()->id() <= static_cast(object.config().raft_layers.value)) { extra_gap = raft_cd; } if (object.config().support_material_contact_distance_type.value == SupportZDistanceType::zdNone) { @@ -1167,7 +1167,7 @@ namespace DoExport { std::vector mm3_per_mm; for (auto object : print.objects()) { for (size_t region_id = 0; region_id < object->num_printing_regions(); ++ region_id) { - const PrintRegion ®ion = object->printing_region(region_id); + object->printing_region(region_id); for (auto layer : object->layers()) { const LayerRegion* layerm = layer->regions()[region_id]; if (compute_min_mm3_per_mm.is_compatible({ erPerimeter, erExternalPerimeter, erOverhangPerimeter })) @@ -2887,7 +2887,7 @@ std::string emit_custom_gcode_per_print_z( //update stats : length double previously_extruded = 0; for (const auto &tuple : status_emitter.stats().color_extruderid_to_used_filament) - if (tuple.first == m600_extruder_before_layer) + if (tuple.first == static_cast(m600_extruder_before_layer)) previously_extruded += tuple.second; status_emitter.stats().color_extruderid_to_used_filament.emplace_back(m600_extruder_before_layer, gcodegen.writer().get_tool(m600_extruder_before_layer)->used_filament() - previously_extruded); } @@ -3482,7 +3482,7 @@ LayerResult GCode::process_layer( //object skirt & brim use the object settings. m_config.apply(print_object->config(), true); this->set_origin(unscale(print_object->instances()[single_object_instance_idx].shift)); - if (this->m_layer != nullptr && (this->m_layer->id() < m_config.skirt_height || print.has_infinite_skirt() )) { + if (this->m_layer != nullptr && (static_cast(this->m_layer->id()) < static_cast(m_config.skirt_height) || print.has_infinite_skirt())) { if(first_layer && print.skirt_first_layer()) for (const ExtrusionEntity* ee : print_object->skirt_first_layer()->entities()) gcode += this->extrude_entity(*ee, ""); @@ -4186,7 +4186,7 @@ void GCode::split_at_seam_pos(ExtrusionLoop& loop, bool was_clockwise) #if _DEBUG ExtrusionLoop old_loop = loop; for (const ExtrusionPath &path : loop.paths) - for (int i = 1; i < path.polyline.get_points().size(); ++i) + for (size_t i = 1; i < path.polyline.get_points().size(); ++i) assert(!path.polyline.get_points()[i - 1].coincides_with_epsilon(path.polyline.get_points()[i])); for (auto it = std::next(loop.paths.begin()); it != loop.paths.end(); ++it) { assert(it->polyline.size() >= 2); @@ -4223,7 +4223,7 @@ void GCode::split_at_seam_pos(ExtrusionLoop& loop, bool was_clockwise) } #if _DEBUG for (const ExtrusionPath &path : loop.paths) - for (int i = 1; i < path.polyline.get_points().size(); ++i) + for (size_t i = 1; i < path.polyline.get_points().size(); ++i) assert(!path.polyline.get_points()[i - 1].coincides_with_epsilon(path.polyline.get_points()[i])); for (auto it = std::next(loop.paths.begin()); it != loop.paths.end(); ++it) { assert(it->polyline.size() >= 2); @@ -4267,7 +4267,7 @@ namespace check_wipe { coord_t delta = wipe_inside_depth - nozzle_width / 2; bool success = check_reduce(external_polygon, current_dist, compute_point(current_dist), nozzle_width / 2); if (!success) { - int iter = 0; + size_t iter = 0; const size_t nb_iter = size_t(std::sqrt(int(delta / nozzle_width))); for (iter = 0; iter < nb_iter; ++iter) { delta /= 2; @@ -4319,7 +4319,7 @@ void GCode::seam_notch(const ExtrusionLoop& original_loop, Point center = polygon_to_test.centroid(); double diameter_min = std::numeric_limits::max(), diameter_max = 0; double diameter_sum = 0; - for (int i = 0; i < polygon_to_test.points.size(); ++i) { + for (size_t i = 0; i < polygon_to_test.points.size(); ++i) { double dist = polygon_to_test.points[i].distance_to(center); diameter_min = std::min(diameter_min, dist); diameter_max = std::max(diameter_max, dist); @@ -4593,7 +4593,6 @@ void GCode::seam_notch(const ExtrusionLoop& original_loop, Point p1 = Line(moved_end, control_end_point).midpoint(); Point p2 = Line(p1, building_paths.back().last_point()).midpoint(); p2 = Line(p2, control_end_point).midpoint(); - float flow_ratio = 0.75f; auto check_length_clipped = [&building_paths, &end_point, length_clipped](const Point& pt_to_check) { if (length_clipped > 0) { double dist = pt_to_check.projection_onto(Line(building_paths.back().last_point(), end_point)).distance_to(end_point); @@ -4650,7 +4649,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s // next copies (if any) would not detect the correct orientation ExtrusionLoop loop_to_seam = original_loop; for (const ExtrusionPath &path : loop_to_seam.paths) - for (int i = 1; i < path.polyline.get_points().size(); ++i) + for (size_t i = 1; i < path.polyline.get_points().size(); ++i) assert(!path.polyline.get_points()[i - 1].coincides_with_epsilon(path.polyline.get_points()[i])); @@ -4665,7 +4664,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s is_hole_loop = false; } for (const ExtrusionPath &path : loop_to_seam.paths) - for (int i = 1; i < path.polyline.get_points().size(); ++i) + for (size_t i = 1; i < path.polyline.get_points().size(); ++i) assert(!path.polyline.get_points()[i - 1].coincides_with_epsilon(path.polyline.get_points()[i])); split_at_seam_pos(loop_to_seam, is_hole_loop); @@ -4684,7 +4683,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s // we discard it in that case ExtrusionPaths& building_paths = loop_to_seam.paths; for (const ExtrusionPath &path : building_paths) - for (int i = 1; i < path.polyline.get_points().size(); ++i) + for (size_t i = 1; i < path.polyline.get_points().size(); ++i) assert(!path.polyline.get_points()[i - 1].coincides_with_epsilon(path.polyline.get_points()[i])); //direction is now set, make the path unreversable for (ExtrusionPath& path : building_paths) { @@ -4732,7 +4731,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s const ExtrusionPaths& wipe_paths = building_paths; for (const ExtrusionPath &path : wipe_paths) - for (int i = 1; i < path.polyline.get_points().size(); ++i) + for (size_t i = 1; i < path.polyline.get_points().size(); ++i) assert(!path.polyline.get_points()[i - 1].coincides_with_epsilon(path.polyline.get_points()[i])); ExtrusionPaths notch_extrusion_start; @@ -4742,7 +4741,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s const ExtrusionPaths& paths = building_paths; for (const ExtrusionPath &path : paths) - for (int i = 1; i < path.polyline.get_points().size(); ++i) + for (size_t i = 1; i < path.polyline.get_points().size(); ++i) assert(!path.polyline.get_points()[i - 1].coincides_with_epsilon(path.polyline.get_points()[i])); // apply the small perimeter speed @@ -4879,7 +4878,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s coordf_t wipe_dist = scale_(dist_wipe_extra_perimeter); ExtrusionPaths paths_wipe; m_wipe.reset_path(); - for (int i = 0; i < wipe_paths.size(); i++) { + for (size_t i = 0; i < wipe_paths.size(); i++) { const ExtrusionPath& path = wipe_paths[i]; if (wipe_dist > 0) { //first, we use the polyline for wipe_extra_perimeter @@ -4979,7 +4978,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s // also shift the wipe on retract if wipe_inside_end // go to the inside (use clipper for easy shift) Polygon original_polygon = original_loop.polygon(); - for (int i = 1; i < original_polygon.points.size(); ++i) + for (size_t i = 1; i < original_polygon.points.size(); ++i) assert(!original_polygon.points[i - 1].coincides_with_epsilon(original_polygon.points[i])); Polygons polys = offset(original_polygon, -dist); if (!polys.empty()) { @@ -4989,7 +4988,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s size_t nearest_pt_idx; size_t nearest_poly_idx = size_t(-1); coordf_t best_dist_sqr = dist * dist * 100; - for (int idx_poly = 0; idx_poly < polys.size(); ++idx_poly) { + for (size_t idx_poly = 0; idx_poly < polys.size(); ++idx_poly) { Polygon &poly = polys[idx_poly]; // use projection auto [near_pt, near_idx] = poly.point_projection(pt_inside); @@ -5006,7 +5005,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s polys = offset(original_polygon, -dist / 2); assert(!polys.empty()); if (!polys.empty()) { - for (int idx_poly = 0; idx_poly < polys.size(); ++idx_poly) { + for (size_t idx_poly = 0; idx_poly < polys.size(); ++idx_poly) { Polygon &poly = polys[idx_poly]; auto [near_pt, near_idx] = poly.point_projection(pt_inside); if (coordf_t test_dist = pt_inside.distance_to_square(near_pt); @@ -5050,7 +5049,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s int pop_in = 0; Point last_pop_in; Polygon &poly = polys.front(); - for (int idxpt = 1; idxpt < poly.points.size(); ++idxpt) { + for (size_t idxpt = 1; idxpt < poly.points.size(); ++idxpt) { if (poly.points[idxpt - 1].distance_to_square(poly.points[idxpt]) < min_dist_sqr) { last_pop_in = poly.points[idxpt]; poly.points.erase(poly.points.begin() + idxpt); @@ -5068,14 +5067,14 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s } } // find nearest point - size_t best_poly_idx = 0; + // size_t best_poly_idx = 0; size_t best_pt_idx = 0; const coordf_t max_sqr_dist = dist * dist * 8; // 2*nozzle² coordf_t best_sqr_dist = max_sqr_dist; Point start_point = pt_inside; if (!polys.empty()) { Polygon &poly = polys.front(); - for (int i = 1; i < poly.points.size(); ++i) + for (size_t i = 1; i < poly.points.size(); ++i) assert(!poly.points[i - 1].coincides_with_epsilon(poly.points[i])); if (poly.is_clockwise() ^ original_polygon.is_clockwise()) poly.reverse(); @@ -5279,7 +5278,7 @@ void GCode::use(const ExtrusionEntityCollection &collection) { std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed_mm_per_sec) { std::string gcode; ExtrusionPath simplifed_path = path; - for (int i = 1; i < simplifed_path.polyline.get_points().size(); ++i) + for (size_t i = 1; i < simplifed_path.polyline.get_points().size(); ++i) assert(!simplifed_path.polyline.get_points()[i - 1].coincides_with_epsilon(simplifed_path.polyline.get_points()[i])); //check if we should reverse it @@ -5331,7 +5330,7 @@ std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &de return gcode; } - for(int i=1;i_extrude(simplifed_path, description, speed_mm_per_sec); @@ -6240,7 +6239,7 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string Polyline poly_start = this->travel_to(gcode, path.first_point(), path.role()); coordf_t length = poly_start.length(); // compute some numbers - double previous_accel = m_writer.get_acceleration(); // in mm/s² + // double previous_accel = m_writer.get_acceleration(); // in mm/s² double previous_speed = m_writer.get_speed(); // in mm/s double travel_speed = m_config.get_computed_value("travel_speed"); // first, the acceleration distance diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp index 92152ce11bd..8196e6a7abd 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp @@ -849,65 +849,65 @@ static bool any_expolygon_contains(const ExPolygons &ex_polygons, // Check if anyone of ExPolygons contains whole travel. // called by need_wipe() -static bool any_expolygon_contains(const ExPolygons &ex_polygons, const std::vector &ex_polygons_bboxes, const EdgeGrid::Grid &grid_lslice, const Polyline &travel) -{ - assert(ex_polygons.size() == ex_polygons_bboxes.size()); - if(std::any_of(travel.points.begin(), travel.points.end(), [&grid_lslice](const Point &point) { return !grid_lslice.bbox().contains(point); })) - return false; - - FirstIntersectionVisitor visitor(grid_lslice); - bool any_intersection = false; - for (size_t line_idx = 1; line_idx < travel.size(); ++line_idx) { - visitor.pt_current = &travel.points[line_idx - 1]; - visitor.pt_next = &travel.points[line_idx]; - grid_lslice.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); - any_intersection = visitor.intersect; - if (any_intersection) break; - } - - if (!any_intersection) { - for (const ExPolygon &ex_polygon : ex_polygons) { - const BoundingBox &bbox = ex_polygons_bboxes[&ex_polygon - &ex_polygons.front()]; - if (std::all_of(travel.points.begin(), travel.points.end(), [&bbox](const Point &point) { return bbox.contains(point); }) && - ex_polygon.contains(travel.points.front())) - return true; - } - } - return false; -} - -static bool need_wipe(const GCode &gcodegen, - const EdgeGrid::Grid &grid_lslice, - const Line &original_travel, - const Polyline &result_travel, - const size_t intersection_count) -{ - const ExPolygons &lslices = gcodegen.layer()->lslices; - const std::vector &lslices_bboxes = gcodegen.layer()->lslices_bboxes; - bool z_lift_enabled = gcodegen.config().retract_lift.get_at(gcodegen.writer().tool()->id()) > 0.; - bool wipe_needed = false; - - // If the original unmodified path doesn't have any intersection with boundary, then it is entirely inside the object otherwise is entirely - // outside the object. - if (intersection_count > 0) { - // The original layer is intersected with defined boundaries. Then it is necessary to make a detailed test. - // If the z-lift is enabled, then a wipe is needed when the original travel leads above the holes. - if (z_lift_enabled) { - if (any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, original_travel)) { - // Check if original_travel and result_travel are not same. - // If both are the same, then it is possible to skip testing of result_travel - wipe_needed = !(result_travel.size() > 2 && result_travel.first_point() == original_travel.a && result_travel.last_point() == original_travel.b) && - !any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, result_travel); - } else { - wipe_needed = true; - } - } else { - wipe_needed = !any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, result_travel); - } - } - - return wipe_needed; -} +// static bool any_expolygon_contains(const ExPolygons &ex_polygons, const std::vector &ex_polygons_bboxes, const EdgeGrid::Grid &grid_lslice, const Polyline &travel) +// { +// assert(ex_polygons.size() == ex_polygons_bboxes.size()); +// if(std::any_of(travel.points.begin(), travel.points.end(), [&grid_lslice](const Point &point) { return !grid_lslice.bbox().contains(point); })) +// return false; + +// FirstIntersectionVisitor visitor(grid_lslice); +// bool any_intersection = false; +// for (size_t line_idx = 1; line_idx < travel.size(); ++line_idx) { +// visitor.pt_current = &travel.points[line_idx - 1]; +// visitor.pt_next = &travel.points[line_idx]; +// grid_lslice.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); +// any_intersection = visitor.intersect; +// if (any_intersection) break; +// } + +// if (!any_intersection) { +// for (const ExPolygon &ex_polygon : ex_polygons) { +// const BoundingBox &bbox = ex_polygons_bboxes[&ex_polygon - &ex_polygons.front()]; +// if (std::all_of(travel.points.begin(), travel.points.end(), [&bbox](const Point &point) { return bbox.contains(point); }) && +// ex_polygon.contains(travel.points.front())) +// return true; +// } +// } +// return false; +// } + +// static bool need_wipe(const GCode &gcodegen, +// const EdgeGrid::Grid &grid_lslice, +// const Line &original_travel, +// const Polyline &result_travel, +// const size_t intersection_count) +// { +// const ExPolygons &lslices = gcodegen.layer()->lslices; +// const std::vector &lslices_bboxes = gcodegen.layer()->lslices_bboxes; +// bool z_lift_enabled = gcodegen.config().retract_lift.get_at(gcodegen.writer().tool()->id()) > 0.; +// bool wipe_needed = false; + +// // If the original unmodified path doesn't have any intersection with boundary, then it is entirely inside the object otherwise is entirely +// // outside the object. +// if (intersection_count > 0) { +// // The original layer is intersected with defined boundaries. Then it is necessary to make a detailed test. +// // If the z-lift is enabled, then a wipe is needed when the original travel leads above the holes. +// if (z_lift_enabled) { +// if (any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, original_travel)) { +// // Check if original_travel and result_travel are not same. +// // If both are the same, then it is possible to skip testing of result_travel +// wipe_needed = !(result_travel.size() > 2 && result_travel.first_point() == original_travel.a && result_travel.last_point() == original_travel.b) && +// !any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, result_travel); +// } else { +// wipe_needed = true; +// } +// } else { +// wipe_needed = !any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, result_travel); +// } +// } + +// return wipe_needed; +// } // Adds points around all vertices so that the offset affects only small sections around these vertices. static void resample_polygon(Polygon &polygon, double dist_from_vertex, double max_allowed_distance) @@ -950,11 +950,11 @@ static void resample_expolygon(ExPolygon &ex_polygon, double dist_from_vertex, d resample_polygon(polygon, dist_from_vertex, max_allowed_distance); } -static void resample_expolygons(ExPolygons &ex_polygons, double dist_from_vertex, double max_allowed_distance) -{ - for (ExPolygon &ex_poly : ex_polygons) - resample_expolygon(ex_poly, dist_from_vertex, max_allowed_distance); -} +// static void resample_expolygons(ExPolygons &ex_polygons, double dist_from_vertex, double max_allowed_distance) +// { +// for (ExPolygon &ex_poly : ex_polygons) +// resample_expolygon(ex_poly, dist_from_vertex, max_allowed_distance); +// } static void precompute_polygon_distances(const Polygon &polygon, std::vector &polygon_distances_out) { diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index fa0ce517ebe..c9220d71ef8 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -672,12 +672,13 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st } std::error_code err_code; - if (err_code = rename_file(out_path, filename)) { - std::string err_msg = (std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' + - "Is " + out_path + " locked? (gcp)" + err_code.message() + '\n'); - if (copy_file(out_path, filename, err_msg, true) != SUCCESS) - throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' + + if ((err_code = rename_file(out_path, filename))) { + std::string err_msg = "Failed to rename the output G-code file from " + out_path + " to " + filename + '\n' + + "Is " + out_path + " locked? (gcp)" + err_code.message() + '\n'; + if (copy_file(out_path, filename, err_msg, true) != SUCCESS) { + throw Slic3r::RuntimeError("Failed to rename the output G-code file from " + out_path + " to " + filename + '\n' + "Is " + out_path + " locked? (gcp)" + err_code.message() + '\n'); + } } } @@ -1394,7 +1395,8 @@ void GCodeProcessor::process_preamble(bool unit_mm, bool absolute_coords, bool a } { - m_origin[E] = m_end_position[E] = set_G92_value * (m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f; + m_origin[E] = m_end_position[E] = set_G92_value * ((m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f); + } } @@ -1450,7 +1452,7 @@ void GCodeProcessor::process_file(const std::string& filename, std::function SeamPlacer::sharp_angle_snapping_threshold) { @@ -1551,13 +1551,12 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: Point nearest_point; Vec3f nearest_old_point; size_t nearest_pt_idx; - size_t next_pt_idx; double nearest_sqr_dist = std::numeric_limits::max(); for (const Perimeter* lower_peri : layer2seams[current_layer_idx - 1]) { //old point Point lower_pt{ scale_t(lower_peri->final_seam_position.x()), scale_t(lower_peri->final_seam_position.y()) }; //for each segment - for (int i = perimeter.start_index; i < perimeter.end_index-1; i++) { + for (size_t i = perimeter.start_index; i < perimeter.end_index-1; i++) { Line l = Line{ Point{scale_t(points[i].position.x()), scale_t(points[i].position.y())}, Point{scale_t(points[i + 1].position.x()), scale_t(points[i + 1].position.y())} }; Point pt = lower_pt.projection_onto(l); double dist_sqr = pt.distance_to_square(lower_pt); @@ -1565,7 +1564,6 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: nearest_sqr_dist = dist_sqr; nearest_point = pt; nearest_pt_idx = i; - next_pt_idx = i + 1; nearest_old_point = lower_peri->final_seam_position; } } @@ -1577,7 +1575,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: nearest_sqr_dist = dist_sqr; nearest_point = pt; nearest_pt_idx = perimeter.end_index - 1; - next_pt_idx = perimeter.start_index; + // next_pt_idx = perimeter.start_index; nearest_old_point = lower_peri->final_seam_position; } } @@ -1831,7 +1829,7 @@ std::tuple> get_seam_from_modifier(const Layer& layer, if (has_custom_seam_modifier) { Polygon polygon = loop.polygon(); polygon.densify(MINIMAL_POLYGON_SIDE); - bool was_clockwise = polygon.make_counter_clockwise(); + // bool was_clockwise = polygon.make_counter_clockwise(); // Look for all lambda-seam-modifiers below current z, choose the highest one ModelVolume* v_lambda_seam = nullptr; Vec3d lambda_pos; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 2d14e2d9615..bff72dff9d5 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -63,15 +63,18 @@ uint16_t LayerTools::extruder(const ExtrusionEntityCollection &extrusions, const assert(region.config().solid_infill_extruder.value > 0); // 1 based extruder ID. uint16_t extruder = this->extruder_override; - if (this->extruder_override == 0) - if (HasRoleVisitor::search(extrusions, HasInfillVisitor{})) - if (HasRoleVisitor::search(extrusions, HasSolidInfillVisitor{})) + if (this->extruder_override == 0) { + if (HasRoleVisitor::search(extrusions, HasInfillVisitor{})) { + if (HasRoleVisitor::search(extrusions, HasSolidInfillVisitor{})) { extruder = region.config().solid_infill_extruder; - else + } else { extruder = region.config().infill_extruder; - else + } + } else { extruder = region.config().perimeter_extruder.value; - return (extruder == 0) ? 0 : extruder - 1; + } + } + return (extruder == 0) ? 0 : extruder - 1; } static double calc_max_layer_height(const PrintConfig &config, double max_object_layer_height) @@ -420,7 +423,7 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ // and maybe other problems. We will therefore go through layer_tools and detect and fix this. // So, if there is a non-object layer starting with different extruder than the last one ended with (or containing more than one extruder), // we'll mark it with has_wipe tower. - for (uint16_t i=0; i+1(temperature) == static_cast(m_last_bed_temperature) && (!wait || m_last_bed_temperature_reached)) return std::string(); m_last_bed_temperature = temperature; @@ -271,7 +271,7 @@ std::string GCodeWriter::set_bed_temperature(uint32_t temperature, bool wait) std::string GCodeWriter::set_chamber_temperature(uint32_t temperature, bool wait) { - if (temperature == m_last_chamber_temperature && !wait) + if (static_cast(temperature) == static_cast(m_last_chamber_temperature) && !wait) return std::string(); if (FLAVOR_IS(gcfMarlinFirmware) || FLAVOR_IS(gcfRepRap) || FLAVOR_IS(gcfMachinekit)) { @@ -580,7 +580,7 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment) we don't perform the move but we only adjust the nominal Z by reducing the lift amount that will be used for unlift. */ // note that if we move but it's lower and we are lifted, we can wait a bit for unlifting, to avoid possible dance on layer change. - if (!this->will_move_z(z) || z < m_pos.z() && m_lifted > EPSILON) { + if (!this->will_move_z(z) || (z < m_pos.z() && std::fabs(m_lifted) > EPSILON)){ double nominal_z = m_pos.z() - m_lifted; m_lifted -= (z - nominal_z); if (std::abs(m_lifted) < EPSILON) diff --git a/src/libslic3r/Geometry/Circle.cpp b/src/libslic3r/Geometry/Circle.cpp index 3d0e026f61d..d1dc3c23047 100644 --- a/src/libslic3r/Geometry/Circle.cpp +++ b/src/libslic3r/Geometry/Circle.cpp @@ -207,7 +207,7 @@ bool ArcCircle::try_create_circle(const Points& points, const double max_radius, double least_deviation; bool found_circle = false; double current_deviation; - for (int index = 1; index < count - 1; index++) + for (size_t index = 1; index < count - 1; index++) { if (index == middle_index) // BBS: We already checked this one, and it failed. don't need to do again @@ -290,7 +290,7 @@ bool ArcCircle::get_deviation_sum_squared(const Points& points, const double tol Point temp; double distance_from_center, deviation; // BBS: skip the first and last points since they are on the circle - for (int index = 1; index < points.size() - 1; index++) + for (size_t index = 1; index < points.size() - 1; index++) { //BBS: make sure the length from the center of our circle to the test point is // at or below our max distance. @@ -304,7 +304,7 @@ bool ArcCircle::get_deviation_sum_squared(const Points& points, const double tol } Point closest_point; //BBS: check the point perpendicular from the segment to the circle's center - for (int index = 0; index < points.size() - 1; index++) + for (size_t index = 0; index < points.size() - 1; index++) { if (get_closest_perpendicular_point(points[index], points[(size_t)index + 1], center, closest_point)) { temp = closest_point - center; diff --git a/src/libslic3r/Geometry/MedialAxis.cpp b/src/libslic3r/Geometry/MedialAxis.cpp index d08c8136dba..baac818b88b 100644 --- a/src/libslic3r/Geometry/MedialAxis.cpp +++ b/src/libslic3r/Geometry/MedialAxis.cpp @@ -1345,7 +1345,7 @@ MedialAxis::remove_bits(ThickPolylines& pp) //check if is smaller or the other ones are not endpoits int nb_better_than_me = 0; - for (int i = 0; i < crosspoint.size(); i++) { + for (size_t i = 0; i < crosspoint.size(); i++) { if (!pp[crosspoint[0]].endpoints.second || length <= pp[crosspoint[0]].length()) nb_better_than_me++; } @@ -1353,7 +1353,7 @@ MedialAxis::remove_bits(ThickPolylines& pp) //check if the length of the polyline is small vs width of the other lines coord_t local_max_width = 0; - for (int i = 0; i < crosspoint.size(); i++) { + for (size_t i = 0; i < crosspoint.size(); i++) { local_max_width = std::max(local_max_width, pp[crosspoint[i]].points_width[0]); } if (length > coordf_t(local_max_width + this->m_min_width)) @@ -2160,7 +2160,7 @@ MedialAxis::concatenate_small_polylines(ThickPolylines& pp) } //be far enough int far_idx = 1; - while (far_idx < best_candidate->points.size() && polyline.last_point().coincides_with_epsilon(best_candidate->points[far_idx])) + while (far_idx < static_cast(best_candidate->points.size()) && polyline.last_point().coincides_with_epsilon(best_candidate->points[far_idx])) far_idx++; polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + far_idx, best_candidate->points.end()); polyline.points_width.insert(polyline.points_width.end(), best_candidate->points_width.begin() + far_idx, best_candidate->points_width.end()); @@ -2244,7 +2244,7 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp) } //be far enough int far_idx = 1; - while (far_idx < best_candidate->points.size() && polyline.last_point().coincides_with_epsilon(best_candidate->points[far_idx])) + while (far_idx < static_cast(best_candidate->points.size()) && polyline.last_point().coincides_with_epsilon(best_candidate->points[far_idx])) far_idx++; polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + far_idx, best_candidate->points.end()); polyline.points_width.insert(polyline.points_width.end(), best_candidate->points_width.begin() + far_idx, best_candidate->points_width.end()); @@ -2466,7 +2466,6 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp) changes = true; while (changes) { changes = false; - size_t shortest_idx = -1; for (size_t polyidx = 0; polyidx < pp.size(); ++polyidx) { ThickPolyline& tp = pp[polyidx]; for (size_t pt_idx = 1; pt_idx < tp.points.size() - 1; pt_idx++) { @@ -2610,7 +2609,7 @@ MedialAxis::grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchor 1, false).scaled_width(); //ensure the width is not lower than min_width. for (ThickPolyline& polyline : pp) { - for (int i = 0; i < polyline.points.size(); ++i) { + for (size_t i = 0; i < polyline.points.size(); ++i) { bool is_anchored = false; for (const ExPolygon& poly : anchors) { if (poly.contains(polyline.points[i])) { @@ -2680,7 +2679,7 @@ check_circular(ExPolygon& expolygon, coord_t max_variation) { // Computing circle center Point center = expolygon.contour.centroid(); coordf_t radius_min = std::numeric_limits::max(), radius_max = 0; - for (int i = 0; i < expolygon.contour.points.size(); ++i) { + for (size_t i = 0; i < expolygon.contour.points.size(); ++i) { coordf_t dist = expolygon.contour.points[i].distance_to(center); radius_min = std::min(radius_min, dist); radius_max = std::max(radius_max, dist); @@ -2729,7 +2728,7 @@ MedialAxis::build(ThickPolylines& polylines_out) thickPoly.points.push_back(thickPoly.points.front()); thickPoly.endpoints.first = false; thickPoly.endpoints.second = false; - for (int i = 0; i < thickPoly.points.size(); i++) { + for (size_t i = 0; i < thickPoly.points.size(); i++) { thickPoly.points_width.push_back(radius); } polylines_out.insert(polylines_out.end(), thickPoly); @@ -2745,7 +2744,7 @@ MedialAxis::build(ThickPolylines& polylines_out) { double ori_area = 0; for (ThickPolyline& tp : pp) { - for (int i = 1; i < tp.points.size(); i++) { + for (size_t i = 1; i < tp.points.size(); i++) { ori_area += (tp.points_width[i - 1] + tp.points_width[i]) * tp.points[i - 1].distance_to(tp.points[i]) / 2; } } @@ -2762,7 +2761,7 @@ MedialAxis::build(ThickPolylines& polylines_out) this->polyline_from_voronoi(fixPoly, &pp_stopgap); double fix_area = 0; for (ThickPolyline& tp : pp_stopgap) { - for (int i = 1; i < tp.points.size(); i++) { + for (size_t i = 1; i < tp.points.size(); i++) { fix_area += (tp.points_width[i - 1] + tp.points_width[i]) * tp.points[i - 1].distance_to(tp.points[i]) / 2; } } diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 6341a12b13b..3b7584ed7fd 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -161,7 +161,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly if ((this->region().config().perimeters > 0)) { max_margin = this->flow(frExternalPerimeter).scaled_width() + this->flow(frPerimeter).scaled_spacing() * (this->region().config().perimeters.value - 1); } - const Surfaces &surfaces = this->fill_surfaces.surfaces; + const bool has_infill = this->region().config().fill_density.value > 0.; coord_t margin = scale_t(this->region().config().external_infill_margin.get_abs_value(unscaled(max_margin))); coord_t margin_bridged = scale_t(this->region().config().bridged_infill_margin.get_abs_value(this->flow(frExternalPerimeter).width())); @@ -551,7 +551,7 @@ void LayerRegion::prepare_fill_surfaces() //not possible ot have multiple intersect no cut from a single expoly. assert(!cut.empty()); surface->expolygon = std::move(intersect[0]); - for (int i = 1; i < intersect.size(); i++) { + for (size_t i = 1; i < intersect.size(); i++) { srfs_to_add.emplace_back(*surface, std::move(intersect[i])); } for (ExPolygon& expoly : cut) { diff --git a/src/libslic3r/Milling/MillingPostProcess.cpp b/src/libslic3r/Milling/MillingPostProcess.cpp index 98e2e4b1d21..bf883ef1e90 100644 --- a/src/libslic3r/Milling/MillingPostProcess.cpp +++ b/src/libslic3r/Milling/MillingPostProcess.cpp @@ -24,7 +24,7 @@ namespace Slic3r { int32_t first_point_idx = -1; const coordf_t dist_max_square = coordf_t(milling_diameter) * coordf_t(milling_diameter / 4); coordf_t best_dist = dist_max_square; - for (int32_t idx = 0; idx < poly.points.size(); idx++) { + for (size_t idx = 0; idx < poly.points.size(); idx++) { if (poly.points[idx].distance_to_square(best_polyline.points[first_point_extract_idx]) < best_dist) { best_dist = poly.points[idx].distance_to_square(best_polyline.points[first_point_extract_idx]); first_point_idx = idx; @@ -33,7 +33,7 @@ namespace Slic3r { if (first_point_idx > -1) { //now search the second one int32_t second_point_idx = -1; - for (int32_t idx = first_point_idx +1; idx < poly.points.size(); idx++) { + for (size_t idx = first_point_idx +1; idx < poly.points.size(); idx++) { if (poly.points[idx].distance_to_square(poly.points[first_point_idx]) > dist_max_square) { second_point_idx = idx; break; @@ -53,7 +53,7 @@ namespace Slic3r { } else { //now see if an other extract point is nearer best_dist = poly.points[second_point_idx].distance_to_square(best_polyline.points[second_point_extract_idx]); - for (int32_t idx = 0; idx < best_polyline.points.size(); idx++) { + for (size_t idx = 0; idx < best_polyline.points.size(); idx++) { if (poly.points[second_point_idx].distance_to_square(best_polyline.points[idx]) < best_dist) { best_dist = poly.points[second_point_idx].distance_to_square(best_polyline.points[idx]); second_point_extract_idx = idx; @@ -66,11 +66,11 @@ namespace Slic3r { contour.width = (float)this->print_config->milling_diameter.get_at(0); contour.height = (float)layer->height; contour.polyline.append(best_polyline.points[first_point_extract_idx]); - for (int32_t idx = first_point_idx; idx < poly.points.size(); idx++) { + for (size_t idx = first_point_idx; idx < poly.points.size(); idx++) { contour.polyline.append(poly.points[idx]); } if (second_point_idx <= first_point_idx) { - for (int32_t idx = 0; idx < poly.points.size(); idx++) { + for (size_t idx = 0; idx < poly.points.size(); idx++) { contour.polyline.append(poly.points[idx]); } } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 721bbe60ab5..4de256ca39c 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -113,7 +113,7 @@ bool Model::equals(const Model& rhs) const { // check objects if (this->objects.size() != rhs.objects.size()) return false; - for (int i = 0; i < rhs.objects.size(); i++) { + for (size_t i = 0; i < rhs.objects.size(); i++) { // Copy including the ID, leave ID set to invalid (zero). if (rhs.objects[i]->equals(*objects[i])) return false; diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index a9a030e91ac..e3bf3c643d1 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -106,49 +106,49 @@ static void fuzzy_polygon(Polygon& poly, coordf_t fuzzy_skin_thickness, coordf_t // Thanks Cura developers for this function. //supermerill: doesn't work -static void fuzzy_extrusion_line(Arachne::ExtrusionLine &ext_lines, double fuzzy_skin_thickness, double fuzzy_skin_point_dist) -{ - const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value - const double range_random_point_dist = fuzzy_skin_point_dist / 2.; - double dist_left_over = double(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point - - auto *p0 = &ext_lines.front(); - std::vector out; - out.reserve(ext_lines.size()); - for (auto &p1 : ext_lines) { - if (p0->p == p1.p) { // Connect endpoints. - out.emplace_back(p1.p, p1.w, p1.perimeter_index); - continue; - } - - // 'a' is the (next) new point between p0 and p1 - Vec2d p0p1 = (p1.p - p0->p).cast(); - double p0p1_size = p0p1.norm(); - // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size - double dist_last_point = dist_left_over + p0p1_size * 2.; - for (double p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + double(rand()) * range_random_point_dist / double(RAND_MAX)) { - double r = double(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness; - out.emplace_back(p0->p + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast(), p1.w, p1.perimeter_index); - dist_last_point = p0pa_dist; - } - dist_left_over = p0p1_size - dist_last_point; - p0 = &p1; - } - - while (out.size() < 3) { - size_t point_idx = ext_lines.size() - 2; - out.emplace_back(ext_lines[point_idx].p, ext_lines[point_idx].w, ext_lines[point_idx].perimeter_index); - if (point_idx == 0) - break; - -- point_idx; - } - - if (ext_lines.back().p == ext_lines.front().p) // Connect endpoints. - out.front().p = out.back().p; - - if (out.size() >= 3) - ext_lines.junctions = std::move(out); -} +// static void fuzzy_extrusion_line(Arachne::ExtrusionLine &ext_lines, double fuzzy_skin_thickness, double fuzzy_skin_point_dist) +// { +// const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value +// const double range_random_point_dist = fuzzy_skin_point_dist / 2.; +// double dist_left_over = double(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point + +// auto *p0 = &ext_lines.front(); +// std::vector out; +// out.reserve(ext_lines.size()); +// for (auto &p1 : ext_lines) { +// if (p0->p == p1.p) { // Connect endpoints. +// out.emplace_back(p1.p, p1.w, p1.perimeter_index); +// continue; +// } + +// // 'a' is the (next) new point between p0 and p1 +// Vec2d p0p1 = (p1.p - p0->p).cast(); +// double p0p1_size = p0p1.norm(); +// // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size +// double dist_last_point = dist_left_over + p0p1_size * 2.; +// for (double p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + double(rand()) * range_random_point_dist / double(RAND_MAX)) { +// double r = double(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness; +// out.emplace_back(p0->p + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast(), p1.w, p1.perimeter_index); +// dist_last_point = p0pa_dist; +// } +// dist_left_over = p0p1_size - dist_last_point; +// p0 = &p1; +// } + +// while (out.size() < 3) { +// size_t point_idx = ext_lines.size() - 2; +// out.emplace_back(ext_lines[point_idx].p, ext_lines[point_idx].w, ext_lines[point_idx].perimeter_index); +// if (point_idx == 0) +// break; +// -- point_idx; +// } + +// if (ext_lines.back().p == ext_lines.front().p) // Connect endpoints. +// out.front().p = out.back().p; + +// if (out.size() >= 3) +// ext_lines.junctions = std::move(out); +// } void convert_to_clipperpath(const Polygons& source, ClipperLib_Z::Paths& dest) { dest.clear(); @@ -774,7 +774,7 @@ void PerimeterGenerator::process() if (nb_loop_contour < 0) nb_loop_contour = std::max(0, nb_loop_holes); - if (nb_loop_holes < 0) + if (nb_loop_holes < 0) { nb_loop_holes = std::max(0, nb_loop_contour); if (print_config->spiral_vase) { @@ -782,8 +782,8 @@ void PerimeterGenerator::process() nb_loop_contour = 1; nb_loop_holes = 0; } - } - + } +} if ((layer->id() == 0 && this->config->only_one_perimeter_first_layer) || (this->config->only_one_perimeter_top && this->upper_slices == NULL)) { nb_loop_contour = std::min(nb_loop_contour, 1); @@ -915,7 +915,7 @@ void PerimeterGenerator::processs_no_bridge(Surfaces& all_surfaces) { if (!unsupported.empty()) { //only consider the part that can be bridged (really, by the bridge algorithm) //first, separate into islands (ie, each ExPlolygon) - int numploy = 0; + // int numploy = 0; //only consider the bottom layer that intersect unsupported, to be sure it's only on our island. ExPolygonCollection lower_island(support); //a detector per island @@ -1035,7 +1035,7 @@ void PerimeterGenerator::processs_no_bridge(Surfaces& all_surfaces) { //ExPolygons no_bridge = diff_ex(offset_ex(unbridgeable, ext_perimeter_width * 3 / 2), last); //bridges_temp = diff_ex(bridges_temp, no_bridge); coordf_t offset_to_do = bridged_infill_margin; - bool first = true; + //bool first = true; unbridgeable = diff_ex(unbridgeable, offset_ex(bridges_temp, ext_perimeter_width)); while (offset_to_do > ext_perimeter_width * 1.5) { unbridgeable = offset2_ex(unbridgeable, -ext_perimeter_width / 4, ext_perimeter_width * 2.25, ClipperLib::jtSquare); @@ -1043,7 +1043,7 @@ void PerimeterGenerator::processs_no_bridge(Surfaces& all_surfaces) { bridges_temp = offset_ex(bridges_temp, ext_perimeter_width, ClipperLib::jtMiter, 6.); unbridgeable = diff_ex(unbridgeable, offset_ex(bridges_temp, ext_perimeter_width)); offset_to_do -= ext_perimeter_width; - first = false; + //first = false; } unbridgeable = offset_ex(unbridgeable, ext_perimeter_width + offset_to_do, ClipperLib::jtSquare); bridges_temp = diff_ex(bridges_temp, unbridgeable); @@ -1081,7 +1081,7 @@ void PerimeterGenerator::processs_no_bridge(Surfaces& all_surfaces) { // store the results last = diff_ex(last, unsupported_filtered, ApplySafetyOffset::Yes); //remove "thin air" polygons (note: it assumes that all polygons below will be extruded) - for (int i = 0; i < last.size(); i++) { + for (size_t i = 0; i < last.size(); i++) { if (intersection_ex(support, ExPolygons() = { last[i] }).empty()) { this->fill_surfaces->append( ExPolygons() = { last[i] }, @@ -1127,7 +1127,7 @@ Polygons as_contour(const Polygons &holes) { Polygons get_holes_as_contour(const ExPolygon &expoly) { Polygons polys; - for(const Polygon hole : expoly.holes){ + for(const Polygon& hole : expoly.holes) { assert(hole.is_clockwise()); polys.push_back(hole); polys.back().make_counter_clockwise(); @@ -1138,7 +1138,7 @@ Polygons get_holes_as_contour(const ExPolygon &expoly) { Polygons get_holes_as_contour(const ExPolygons &expolys) { Polygons polys; for(const ExPolygon &expoly : expolys) - for(const Polygon hole : expoly.holes){ + for (const Polygon &hole : expoly.holes) { assert(hole.is_clockwise()); polys.push_back(hole); polys.back().make_counter_clockwise(); @@ -1473,8 +1473,8 @@ ProcessSurfaceResult PerimeterGenerator::process_classic(int& contour_count, int // compute next onion // the minimum thickness of a single loop is: // ext_width/2 + ext_spacing/2 + spacing/2 + width/2 - coordf_t good_spacing = ext_perimeter_width / 2; - coordf_t overlap_spacing = (1 - thin_perimeter) * ext_perimeter_spacing / 2; + // coordf_t good_spacing = ext_perimeter_width / 2; + // coordf_t overlap_spacing = (1 - thin_perimeter) * ext_perimeter_spacing / 2; if (holes_count == 0 || contour_count == 0) { if (holes_count == 0) { @@ -2094,7 +2094,7 @@ ProcessSurfaceResult PerimeterGenerator::process_classic(int& contour_count, int //if the shrink split the area in multipe bits if (expoly_after_shrink_test.size() > 1) { //remove too small bits - for (int exp_idx = 0; exp_idx < expoly_after_shrink_test.size(); exp_idx++) { + for (size_t exp_idx = 0; exp_idx < expoly_after_shrink_test.size(); exp_idx++) { if (expoly_after_shrink_test[exp_idx].area() < (SCALED_EPSILON * SCALED_EPSILON * 4)) { expoly_after_shrink_test.erase(expoly_after_shrink_test.begin() + exp_idx); exp_idx--; @@ -2109,7 +2109,7 @@ ProcessSurfaceResult PerimeterGenerator::process_classic(int& contour_count, int //maybe some areas are a just bit too thin, try with just a little more offset to remove them. const coordf_t offset_test_2 = min * 0.8; ExPolygons expoly_after_shrink_test2 = offset_ex(ExPolygons{expoly}, -offset_test_2); - for (int exp_idx = 0; exp_idx < expoly_after_shrink_test2.size(); exp_idx++) { + for (size_t exp_idx = 0; exp_idx < expoly_after_shrink_test2.size(); exp_idx++) { if (expoly_after_shrink_test2[exp_idx].area() < (SCALED_EPSILON * SCALED_EPSILON * 4)) { expoly_after_shrink_test2.erase(expoly_after_shrink_test2.begin() + exp_idx); exp_idx--; @@ -2385,13 +2385,13 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const Polyline& loop_polygon if(!paths.empty()) chain_and_reorder_extrusion_paths(paths, &paths.front().first_point()); - bool has_normal = !ok_polylines.empty(); - bool has_speed = !small_speed.empty() || !big_speed.empty(); - bool has_flow = !small_flow.empty() || !big_flow.empty(); + // bool has_normal = !ok_polylines.empty(); + // bool has_speed = !small_speed.empty() || !big_speed.empty(); + // bool has_flow = !small_flow.empty() || !big_flow.empty(); std::function&)> foreach = [](ExtrusionPaths &paths, const std::function& doforeach) { if (paths.size() > 2) - for (int i = 1; i < paths.size() - 1; i++) { + for (size_t i = 1; i < paths.size() - 1; i++) { if (doforeach(paths[i - 1], paths[i], paths[i + 1])) { paths.erase(paths.begin() + i); i--; @@ -2872,7 +2872,7 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar //check if evvrything is okay (it can fail) bool not_sorted_enough = false; - for (int i = 1; i < paths.size(); i++) { + for (size_t i = 1; i < paths.size(); i++) { if (!paths[i - 1].last_point().coincides_with_epsilon(paths[i].first_point())) { not_sorted_enough = true; break; @@ -2885,7 +2885,7 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar paths.erase(paths.end()-1); paths.insert(paths.begin(), path); bool not_sorted_enough = false; - for (int i = 1; i < paths.size(); i++) { + for (size_t i = 1; i < paths.size(); i++) { if (paths[i - 1].last_point().coincides_with_epsilon(paths[i].first_point())) { not_sorted_enough = true; break; @@ -2898,7 +2898,7 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar } } - for (int i = 1; i < paths.size(); i++) { + for (size_t i = 1; i < paths.size(); i++) { // diff/inter can generate points with ~3-5 unit of diff. if (paths[i - 1].last_point() != paths[i].first_point()) { assert(paths[i - 1].last_point().coincides_with_epsilon(paths[i].first_point())); @@ -2913,13 +2913,13 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& ar } #endif - bool has_normal = !ok_polylines.empty(); - bool has_speed = !small_speed.empty() || !big_speed.empty(); - bool has_flow = !small_flow.empty() || !big_flow.empty(); + // bool has_normal = !ok_polylines.empty(); + // bool has_speed = !small_speed.empty() || !big_speed.empty(); + // bool has_flow = !small_flow.empty() || !big_flow.empty(); std::function&)> foreach = [is_loop](ExtrusionPaths& paths, const std::function& doforeach) { if (paths.size() > 2) - for (int i = 1; i < paths.size() - 1; i++) { + for (size_t i = 1; i < paths.size() - 1; i++) { if (doforeach(paths[i - 1], paths[i], paths[i + 1])) { paths.erase(paths.begin() + i); i--; @@ -4032,7 +4032,7 @@ PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, co if(direction_polyline.size() == 0 || direction_polyline.points.back() != path.first_point()) direction_polyline.points.insert(direction_polyline.points.end(), path.polyline.get_points().begin(), path.polyline.get_points().end()); } - for (int i = 0; i < direction_polyline.points.size() - 1; i++) + for (size_t i = 0; i < direction_polyline.points.size() - 1; i++) assert(direction_polyline.points[i] != direction_polyline.points[i + 1]); if (direction_polyline.length() > perimeter_flow.scaled_width() / 8) { direction_polyline.clip_start(perimeter_flow.scaled_width() / 20); diff --git a/src/libslic3r/Polyline.cpp b/src/libslic3r/Polyline.cpp index c7662d8a47a..739e52c7e10 100644 --- a/src/libslic3r/Polyline.cpp +++ b/src/libslic3r/Polyline.cpp @@ -412,7 +412,7 @@ void concatThickPolylines(ThickPolylines& pp) { // removes the given distance from the end of the polyline void PolylineOrArc::clip_end(coordf_t distance) { - bool last_point_inserted = false; + // bool last_point_inserted = false; size_t remove_after_index = MultiPoint::size(); while (distance > 0) { Vec2d last_point = this->last_point().cast(); @@ -426,7 +426,7 @@ void PolylineOrArc::clip_end(coordf_t distance) coordf_t lsqr = v.squaredNorm(); if (lsqr > distance * distance) { this->points.emplace_back((last_point + v * (distance / sqrt(lsqr))).cast()); - last_point_inserted = true; + // last_point_inserted = true; break; } distance -= sqrt(lsqr); diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index 60e40644cb8..f309f243ba4 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -105,7 +105,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str try { filename = std::regex_replace(filename, std::regex(forbidden_base), "_"); regexp_used = true; - }catch(std::exception){} + } catch(const std::exception& ex) {} } if (!regexp_used) { for(size_t i = 0; i < forbidden_base.size(); i++) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index fab433df5fe..8ef2c0b0cf6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -8219,12 +8219,13 @@ void _deserialize_maybe_from_prusa(const std::maphas(opt_key) || (check_prusa && prusa_import_to_review_keys.find(opt_key) != prusa_import_to_review_keys.end())) { unknown_keys.emplace(key, value); } else { config.set_deserialize(opt_key, opt_value, config_substitutions); } + } } catch (UnknownOptionException & /* e */) { // log & ignore if (config_substitutions.rule != ForwardCompatibilitySubstitutionRule::Disable) @@ -8805,7 +8806,7 @@ std::map PrintConfigDef::to_prusa(t_config_option_key& const ConfigOptionFloats *nozzle_diameters = all_conf.option("nozzle_diameter"); assert(current_opt && nozzle_diameters); assert(current_opt->size() == nozzle_diameters->size()); - for (int i = 0; i < current_opt->size(); i++) { + for (size_t i = 0; i < current_opt->size(); i++) { computed_opt.set_at(current_opt->get_abs_value(i, nozzle_diameters->get_at(i)), i); } assert(computed_opt.size() == nozzle_diameters->size()); @@ -9542,7 +9543,7 @@ std::set DynamicPrintConfig::value_changed(const t_co // this->set_key_value("skirt_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(flow.spacing() * 10000) / 10000, false)); // something_changed = true; //} - } catch (FlowErrorNegativeSpacing) { + } catch (const FlowErrorNegativeSpacing& e) { if (spacing_option != nullptr) { width_option->set_phony(true); spacing_option->set_phony(false); diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index aefb502ed25..4d25de40fb1 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -820,7 +820,7 @@ void PrintObject::_transform_hole_to_polyholes() Point center = hole.centroid(); double diameter_min = std::numeric_limits::max(), diameter_max = 0; double diameter_sum = 0; - for (int i = 0; i < hole.points.size(); ++i) { + for (size_t i = 0; i < hole.points.size(); ++i) { double dist = hole.points[i].distance_to(center); diameter_min = std::min(diameter_min, dist); diameter_max = std::max(diameter_max, dist); diff --git a/src/libslic3r/SVG.cpp b/src/libslic3r/SVG.cpp index 893cbdd9569..eeda2458ebc 100644 --- a/src/libslic3r/SVG.cpp +++ b/src/libslic3r/SVG.cpp @@ -204,7 +204,7 @@ void SVG::draw(const ThickPolylines& thickpolylines, const float scale, const st if (poly.points.size() < 2) continue; Line l{ poly.points.front(), poly.points[1] }; this->draw(Line{ poly.points.front(), l.midpoint() }, stroke, poly.points_width.front() * scale); - for (int i = 1; i < poly.points.size()-1; ++i) { + for (size_t i = 1; i < poly.points.size()-1; ++i) { Point first_point = l.midpoint(); l=Line{ poly.points[i], poly.points[i+1] }; this->draw(Line{ first_point, l.midpoint() }, stroke, poly.points_width[i] * scale); diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index cbb272af3ee..6bfd3ede098 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -360,7 +360,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object m_support_params.support_layer_height_min = 1000000.; const ConfigOptionFloatsOrPercents& min_layer_height = m_print_config->min_layer_height; const ConfigOptionFloats& nozzle_diameter = m_print_config->nozzle_diameter; - for (int extr_id = 0; extr_id < min_layer_height.size(); ++extr_id) { + for (size_t extr_id = 0; extr_id < min_layer_height.size(); ++extr_id) { double min_from_extr = min_layer_height.get_abs_value(extr_id, nozzle_diameter.get_at(extr_id)); if(min_from_extr > 0) m_support_params.support_layer_height_min = std::min(m_support_params.support_layer_height_min, min_from_extr); @@ -370,7 +370,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object m_support_params.support_layer_height_min = std::min(m_support_params.support_layer_height_min, layer->height); } if (m_support_params.support_layer_height_min >= 1000000.) { - for (int extr_id = 0; extr_id < min_layer_height.size(); ++extr_id) { + for (size_t extr_id = 0; extr_id < min_layer_height.size(); ++extr_id) { m_support_params.support_layer_height_min = std::min(m_support_params.support_layer_height_min, nozzle_diameter.get_at(extr_id) / 10); } } @@ -429,24 +429,29 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object m_support_params.interface_fill_pattern = (m_support_params.interface_density > 0.95 ? ipRectilinear : ipSupportBase); m_support_params.contact_top_fill_pattern = m_object_config->support_material_top_interface_pattern; m_support_params.contact_bottom_fill_pattern = m_object_config->support_material_bottom_interface_pattern; - if (m_support_params.contact_top_fill_pattern == ipAuto) - if (m_slicing_params->soluble_interface) + if (m_support_params.contact_top_fill_pattern == ipAuto) { + if (m_slicing_params->soluble_interface) { m_support_params.contact_top_fill_pattern = ipConcentric; - else if (m_support_params.interface_density > 0.95) + } else if (m_support_params.interface_density > 0.95) { m_support_params.contact_top_fill_pattern = ipRectilinear; - else + } else { m_support_params.contact_top_fill_pattern = ipSupportBase; - if (m_support_params.contact_bottom_fill_pattern == ipAuto) - if(m_support_params.contact_top_fill_pattern != ipHilbertCurve + } + } + + if (m_support_params.contact_bottom_fill_pattern == ipAuto) { + if (m_support_params.contact_top_fill_pattern != ipHilbertCurve && m_support_params.contact_top_fill_pattern != ipSmooth - && m_support_params.contact_top_fill_pattern != ipSawtooth) + && m_support_params.contact_top_fill_pattern != ipSawtooth) { m_support_params.contact_bottom_fill_pattern = m_support_params.contact_top_fill_pattern; - else if (m_slicing_params->soluble_interface) + } else if (m_slicing_params->soluble_interface) { m_support_params.contact_bottom_fill_pattern = ipConcentric; - else if (m_support_params.interface_density > 0.95) + } else if (m_support_params.interface_density > 0.95) { m_support_params.contact_bottom_fill_pattern = ipRectilinear; - else + } else { m_support_params.contact_bottom_fill_pattern = ipSupportBase; + } + } } // Using the std::deque as an allocator. @@ -1275,10 +1280,12 @@ class SupportGridPattern namespace SupportMaterialInternal { static inline bool has_bridging_perimeters(const ExtrusionLoop &loop) { - for (const ExtrusionPath &ep : loop.paths) - if (ep.role() == erOverhangPerimeter && ! ep.polyline.empty()) + for (const ExtrusionPath &ep : loop.paths) { + if (ep.role() == erOverhangPerimeter && !ep.polyline.empty()) { return int(ep.size()) >= (ep.is_closed() ? 3 : 2); - return false; + } + } + return false; } static bool has_bridging_perimeters(const ExtrusionEntityCollection &perimeters) { @@ -2708,8 +2715,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int size_t n_layers_total = 0; coordf_t step_interface = support_interface_layer_height; coordf_t step = 0; - auto compute_step = []() { - }; + // auto compute_step = []() {}; { n_layers_top = m_object_config->support_material_interface_layers.value; coordf_t height_top_interface = std::max(0., support_interface_layer_height * n_layers_top); @@ -4487,7 +4493,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( assert(! base_layer.layer->bridging); auto flow = m_support_params.support_material_flow.with_height(float(base_layer.layer->height)); float density = float(m_support_params.support_density); - bool sheath = m_support_params.with_sheath; + // bool sheath = m_support_params.with_sheath; if (base_layer.layer->bottom_z < EPSILON) { filler = filler_first_layer_ptr.get(); filler->angle = Geometry::deg2rad(float(m_object_config->support_material_angle.value + 90.)); diff --git a/src/slic3r/GUI/CalibrationAbstractDialog.cpp b/src/slic3r/GUI/CalibrationAbstractDialog.cpp index f3eaebbb664..0b3d0f163bc 100644 --- a/src/slic3r/GUI/CalibrationAbstractDialog.cpp +++ b/src/slic3r/GUI/CalibrationAbstractDialog.cpp @@ -40,7 +40,6 @@ namespace GUI { // fonts const wxFont& font = wxGetApp().normal_font(); - const wxFont& bold_font = wxGetApp().bold_font(); SetFont(font); } diff --git a/src/slic3r/GUI/CalibrationBridgeDialog.cpp b/src/slic3r/GUI/CalibrationBridgeDialog.cpp index 35440027ee8..9788a8311a5 100644 --- a/src/slic3r/GUI/CalibrationBridgeDialog.cpp +++ b/src/slic3r/GUI/CalibrationBridgeDialog.cpp @@ -74,7 +74,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool } std::vector items; - for (size_t i = 0; i < nb_items; i++) + for (size_t i = 0; i < static_cast(nb_items); i++) items.emplace_back((boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "bridge_flow" / "bridge_test.amf").string()); std::vector objs_idx = plat->load_files(items, true, false, false, false); @@ -96,7 +96,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool float z_scale = nozzle_diameter / 0.4; //do scaling if (z_scale < 0.9 || 1.2 < z_scale) { - for (size_t i = 0; i < nb_items; i++) + for (size_t i = 0; i < static_cast(nb_items); i++) model.objects[objs_idx[i]]->scale(1, 1, z_scale); } else { z_scale = 1; @@ -116,7 +116,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool const ConfigOptionPercent* bridge_flow_ratio = print_config->option(setting_to_test); int start = bridge_flow_ratio->value; float zshift = 2.3 * (1 - z_scale); - for (size_t i = 0; i < nb_items; i++) { + for (size_t i = 0; i < static_cast(nb_items); i++) { int step_num = (start + (add ? 1 : -1) * i * step); if (step_num < 180 && step_num > 20 && step_num%5 == 0) { add_part(model.objects[objs_idx[i]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "bridge_flow" / ("f" + std::to_string(step_num) + ".amf")).string(), Vec3d{ -10, 0, zshift + 4.6 * z_scale }, Vec3d{ 1,1,z_scale }); @@ -149,7 +149,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool } /// --- custom config --- - for (size_t i = 0; i < nb_items; i++) { + for (size_t i = 0; i < static_cast(nb_items); i++) { model.objects[objs_idx[i]]->config.set_key_value("brim_width", new ConfigOptionFloat(brim_width)); model.objects[objs_idx[i]]->config.set_key_value("brim_ears", new ConfigOptionBool(false)); model.objects[objs_idx[i]]->config.set_key_value("perimeters", new ConfigOptionInt(2)); @@ -170,10 +170,10 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool z_step = 0.1; double max_height = full_print_config.get_computed_value("max_layer_height",0); if (max_height > first_layer_height + z_step) - for (size_t i = 0; i < nb_items; i++) + for (size_t i = 0; i < static_cast(nb_items); i++) model.objects[objs_idx[i]]->config.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(first_layer_height + z_step, false)); else - for (size_t i = 0; i < nb_items; i++) + for (size_t i = 0; i < static_cast(nb_items); i++) model.objects[objs_idx[i]]->config.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(first_layer_height - z_step, false)); } diff --git a/src/slic3r/GUI/CalibrationCubeDialog.cpp b/src/slic3r/GUI/CalibrationCubeDialog.cpp index 65bb5c27363..cb8cb91f118 100644 --- a/src/slic3r/GUI/CalibrationCubeDialog.cpp +++ b/src/slic3r/GUI/CalibrationCubeDialog.cpp @@ -66,19 +66,15 @@ void CalibrationCubeDialog::create_geometry(std::string calibration_path) { (boost::filesystem::path(Slic3r::resources_dir()) / "calibration"/"cube"/ calibration_path).string()}, true, false, false, false); assert(objs_idx.size() == 1); - const DynamicPrintConfig* printConfig = this->gui_app->get_tab(Preset::TYPE_FFF_PRINT)->get_config(); - const DynamicPrintConfig* filamentConfig = this->gui_app->get_tab(Preset::TYPE_FFF_FILAMENT)->get_config(); const DynamicPrintConfig* printerConfig = this->gui_app->get_tab(Preset::TYPE_PRINTER)->get_config(); /// --- scale --- //model is created for a 0.4 nozzle, scale xy with nozzle size. - const ConfigOptionFloats* nozzle_diameter_config = printerConfig->option("nozzle_diameter"); - assert(nozzle_diameter_config->size() > 0); - float nozzle_diameter = nozzle_diameter_config->get_at(0); + assert(nozzle_diameter_config->size() > 0); float cube_size = 30; if (calibration_path == "xyzCalibration_cube.amf") cube_size = 20; - int idx_scale = scale->GetSelection(); + scale->GetSelection(); double xyzScale = 20; if (!scale->GetValue().ToDouble(&xyzScale)) { xyzScale = 20; diff --git a/src/slic3r/GUI/CalibrationPressureAdvDialog.cpp b/src/slic3r/GUI/CalibrationPressureAdvDialog.cpp index 3f6332e9d46..3710f65d568 100644 --- a/src/slic3r/GUI/CalibrationPressureAdvDialog.cpp +++ b/src/slic3r/GUI/CalibrationPressureAdvDialog.cpp @@ -391,7 +391,8 @@ struct ExtrusionSettings {// think a struct is better instead of all the maps ? er_width = std::round(er_width * 100.0) / 100.0; // Change number to percentage and round } else{ - for (int i = 0; i < sizeof(choice_extrusion_role) / sizeof(choice_extrusion_role[0]); i++) { + for (int i = 0; i < static_cast(sizeof(choice_extrusion_role) / sizeof(choice_extrusion_role[0])); i++) { + if (er_width_ToOptionKey.find(extrusion_role) != er_width_ToOptionKey.end()) { @@ -546,7 +547,7 @@ struct ExtrusionSettings {// think a struct is better instead of all the maps ? const double extra_size_x = xy_scaled_number_x; const double magical_transformation_x_pos = 20.6;//what is this, and how is this calculated ? >:( - const double magical_transformation_y_pos = 10.47;//load a model without moving its pos to find see what it is.the number doesn't seem to change regardless of layer heights/nozzle size +// const double magical_transformation_y_pos = 10.47;//load a model without moving its pos to find see what it is.the number doesn't seem to change regardless of layer heights/nozzle size Eigen::Vector3d bend_pos_first = bend_90_positions[0]; Eigen::Vector3d bend_pos_mid = bend_90_positions[countincrements/2]; Eigen::Vector3d bend_pos_last = bend_90_positions[countincrements-1]; @@ -608,7 +609,7 @@ struct ExtrusionSettings {// think a struct is better instead of all the maps ? Eigen::Vector3d bend_90_pos = bend_90_positions[nb_bends]; const double magical_transformation_y_pos = 10.47; const double magical_transformation_num_x_pos = 1.03; - const double magical_transformation_num_y_pos = 2.06;// -2.03 +// const double magical_transformation_num_y_pos = 2.06;// -2.03 const double magical_transformation_z_pos = 0.12;//0.1 is the transformation value, but set slightly higher so numbers would be "inside" right border this might be dependant on z_scale_factor double bend_90_y = bend_90_pos.y() + magical_transformation_y_pos + (xy_scaled_90_bend_y/2); diff --git a/src/slic3r/GUI/CalibrationRetractionDialog.cpp b/src/slic3r/GUI/CalibrationRetractionDialog.cpp index b630c07e849..98be117612f 100644 --- a/src/slic3r/GUI/CalibrationRetractionDialog.cpp +++ b/src/slic3r/GUI/CalibrationRetractionDialog.cpp @@ -160,7 +160,6 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) { const ConfigOptionFloats* nozzle_diameter_config = printer_config->option("nozzle_diameter"); assert(nozzle_diameter_config->size() > 0); float nozzle_diameter = nozzle_diameter_config->get_at(0); - float xyScale = nozzle_diameter / 0.4; //scale z to have 6 layers const ConfigOptionFloatOrPercent* first_layer_height_setting = print_config->option("first_layer_height"); double first_layer_height = first_layer_height_setting->get_abs_value(nozzle_diameter); @@ -199,19 +198,15 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) { /// --- translate ---; bool has_to_arrange = plat->config()->opt_float("init_z_rotate") != 0; - const ConfigOptionFloat* extruder_clearance_radius = print_config->option("extruder_clearance_radius"); const ConfigOptionPoints* bed_shape = printer_config->option("bed_shape"); - const float brim_width = std::max(print_config->option("brim_width")->value, nozzle_diameter * 5.); Vec2d bed_size = BoundingBoxf(bed_shape->get_values()).size(); Vec2d bed_min = BoundingBoxf(bed_shape->get_values()).min; - float offset = 4 + 26 * scale * 1 + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0); if (nb_items == 1) { model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, zscale_number }); } else { has_to_arrange = true; } - /// --- custom config --- assert(filament_temp_item_name.size() == nb_items); assert(model.objects.size() == nb_items); diff --git a/src/slic3r/GUI/CalibrationTempDialog.cpp b/src/slic3r/GUI/CalibrationTempDialog.cpp index 7708c13111f..d5e22bcc7dc 100644 --- a/src/slic3r/GUI/CalibrationTempDialog.cpp +++ b/src/slic3r/GUI/CalibrationTempDialog.cpp @@ -122,14 +122,13 @@ void CalibrationTempDialog::create_geometry(wxCommandEvent& event_args) { }; //add 8 others - float zshift = (1 - xyzScale) / 2; if (temperature > 175 && temperature < 290 && temperature%5==0) { Vec3d translate{ 0 - xyzScale * 3.75, -xyzScale * 2.7, xyzScale * (0 * 10 - 2.45) }; add_part(model.objects[objs_idx[0]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_temp" / ("t"+std::to_string(temperature)+".amf")).string(), translate, Vec3d{ xyzScale, xyzScale, xyzScale * 0.43 }); translate_from_rotation(0, translate); } - for (int16_t i = 1; i < nb_items; i++) { + for (int16_t i = 1; i < static_cast(nb_items); i++) { add_part(model.objects[objs_idx[0]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_temp" / ("Smart_compact_temperature_calibration_item.amf")).string(), Vec3d{ 0,0, i * 10 * xyzScale }, Vec3d{ xyzScale, xyzScale * 0.5, xyzScale }); int sub_temp = temperature - i * step_temp; @@ -158,11 +157,10 @@ void CalibrationTempDialog::create_geometry(wxCommandEvent& event_args) { /// -- generate the heat change gcode //std::string str_layer_gcode = "{if layer_num > 0 and layer_z <= " + std::to_string(2 * xyzScale) + "}\nM104 S" + std::to_string(temperature - (int8_t)nb_delta * 5); // double print_z, std::string gcode,int extruder, std::string color - double firstChangeHeight = print_config->get_abs_value("first_layer_height", nozzle_diameter); //model.custom_gcode_per_print_z.gcodes.emplace_back(CustomGCode::Item{ firstChangeHeight + nozzle_diameter/2, CustomGCode::Type::Custom, -1, "", "M104 S" + std::to_string(temperature) + " ; ground floor temp tower set" }); model.objects[objs_idx[0]]->config.set_key_value("print_temperature", new ConfigOptionInt(temperature)); model.objects[objs_idx[0]]->config.set_key_value("print_first_layer_temperature", new ConfigOptionInt(first_layer_temperature)); - for (int16_t i = 1; i < nb_items; i++) { + for (int16_t i = 1; i < static_cast(nb_items); i++) { model.custom_gcode_per_print_z.gcodes.emplace_back(CustomGCode::Item{ (i * 10 * xyzScale), CustomGCode::Type::Custom , -1, "", "M104 S" + std::to_string(temperature - i * step_temp) + " ; floor " + std::to_string(i) + " of the temp tower set" }); //str_layer_gcode += "\n{ elsif layer_z >= " + std::to_string(i * 10 * xyzScale) + " and layer_z <= " + std::to_string((1 + i * 10) * xyzScale) + " }\nM104 S" + std::to_string(temperature - (int8_t)nb_delta * 5 + i * 5); } diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 4503a947eb0..210e75450a1 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -256,7 +256,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con } } - static bool support_material_overhangs_queried = false; + // static bool support_material_overhangs_queried = false; // Check "support_material" and "overhangs" relations only on global settings level if (is_global_config && config->opt_bool("support_material")) { @@ -279,7 +279,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con } else if (answer == wxID_CANCEL) { // Disable supports. new_conf.set_key_value("support_material", new ConfigOptionBool(false)); - support_material_overhangs_queried = false; + // support_material_overhangs_queried = false; } apply(config, &new_conf); } @@ -651,8 +651,6 @@ void ConfigManipulation::update_printer_fff_config(DynamicPrintConfig *config, } void ConfigManipulation::toggle_printer_fff_options(DynamicPrintConfig *config, DynamicPrintConfig &full_config) { - Field* field; - size_t extruder_count = config->option("nozzle_diameter")->size(); toggle_field("toolchange_gcode", extruder_count > 1); toggle_field("single_extruder_multi_material", extruder_count > 1); diff --git a/src/slic3r/GUI/CreateMMUTiledCanvas.cpp b/src/slic3r/GUI/CreateMMUTiledCanvas.cpp index c638c77646b..95fac4f8aa4 100644 --- a/src/slic3r/GUI/CreateMMUTiledCanvas.cpp +++ b/src/slic3r/GUI/CreateMMUTiledCanvas.cpp @@ -253,7 +253,7 @@ namespace GUI { color = c.widget_spool->get_print_color()->get_printed_color(use_spool_colors); } //get nearest - for (int i = 0; i < parent->m_used_colors.size(); i++) { + for (size_t i = 0; i < parent->m_used_colors.size(); i++) { if (parent->m_used_colors[i]->get_printed_color(use_spool_colors) == color) { idx_extruder = i; break; @@ -330,7 +330,7 @@ namespace GUI { timestamp += (second->GetValue()); timestamp += delta; //it's ordered - int idx = 0; + size_t idx = 0; while (idx < rplace_timestamp.size() && timestamp > rplace_timestamp[idx]) { idx++; } //if after the last or ( if not found, and it not before the begin, and only if we don't want the next.) if (idx >= rplace_timestamp.size() || (timestamp != rplace_timestamp[idx] && idx > 0 && delta<=0)) idx--; @@ -428,27 +428,27 @@ void CreateMMUTiledCanvas::recompute_colors() wxSize offset(std::min(int(offset_dbl.x()), std::max(0, bmp.GetSize().x - 1)), std::min(int(offset_dbl.y()), std::max(0, bmp.GetSize().y - 1))); Vec2d size_dbl = m_config.option("size")->value; wxSize size(std::min(int(size_dbl.x()), bmp.GetSize().x - offset.x), std::min(int(size_dbl.y()), bmp.GetSize().y - offset.y)); - Vec2d pixel_size = m_config.option("size_px")->value; - double separation = m_config.opt_float("separation_xy"); + //Vec2d pixel_size = m_config.option("size_px")->value; + //double separation = m_config.opt_float("separation_xy"); //compute pixel per mm - double max_x_mm = (size.x * (pixel_size.x() + separation) - separation); - double max_y_mm = (size.y * (pixel_size.y() + separation) - separation); - float mm_per_pixel = std::max(max_x_mm / (GetSize().x - 4), max_y_mm / (GetSize().y - 4)); + //double max_x_mm = (size.x * (pixel_size.x() + separation) - separation); + //double max_y_mm = (size.y * (pixel_size.y() + separation) - separation); + //float mm_per_pixel = std::max(max_x_mm / (GetSize().x - 4), max_y_mm / (GetSize().y - 4)); //compute pixel per tile & per separation - int pixels_separation = int(separation / mm_per_pixel) + (separation - int(separation / mm_per_pixel) > mm_per_pixel / 2 ? 1 : 0); - int ratiox = std::min(1, int(pixel_size.x() / pixel_size.y())); - int ratioy = std::min(1, int(pixel_size.y() / pixel_size.x())); - int pixels_reste_x = (GetSize().x - 4 - pixels_separation * (size.x - 1)); - int pixels_reste_y = (GetSize().y - 4 - pixels_separation * (size.y - 1)); - double pixels_per_tile_dbl_x = (pixels_reste_x / double(size.x * (pixel_size.x() / pixel_size.y()))); - double pixels_per_tile_dbl_y = (pixels_reste_y / double(size.y * (pixel_size.y() / pixel_size.x()))); - double pixels_per_tile = std::min(pixels_per_tile_dbl_x, pixels_per_tile_dbl_y); - int pixels_per_tile_x = std::max(1, int(pixels_per_tile * ratiox)); - int pixels_per_tile_y = std::max(1, int(pixels_per_tile * ratioy)); - - bool show_original = m_config.option("original")->value; + //int pixels_separation = int(separation / mm_per_pixel) + (separation - int(separation / mm_per_pixel) > mm_per_pixel / 2 ? 1 : 0); + //int ratiox = std::min(1, int(pixel_size.x() / pixel_size.y())); + //int ratioy = std::min(1, int(pixel_size.y() / pixel_size.x())); + //int pixels_reste_x = (GetSize().x - 4 - pixels_separation * (size.x - 1)); + //int pixels_reste_y = (GetSize().y - 4 - pixels_separation * (size.y - 1)); + //double pixels_per_tile_dbl_x = (pixels_reste_x / double(size.x * (pixel_size.x() / pixel_size.y()))); + //double pixels_per_tile_dbl_y = (pixels_reste_y / double(size.y * (pixel_size.y() / pixel_size.x()))); + //double pixels_per_tile = std::min(pixels_per_tile_dbl_x, pixels_per_tile_dbl_y); + //int pixels_per_tile_x = std::max(1, int(pixels_per_tile * ratiox)); + //int pixels_per_tile_y = std::max(1, int(pixels_per_tile * ratioy)); + + m_config.option("original")->value; wxColour background_color{ wxString{ m_config.option("background_color")->value } }; for (ColorEntry& col : m_pixel_colors) { @@ -458,7 +458,7 @@ void CreateMMUTiledCanvas::recompute_colors() //create background color { int idx = -1; - for (int i = 0; i < m_pixel_colors.size(); i++) { + for (size_t i = 0; i < m_pixel_colors.size(); i++) { if (m_pixel_colors[i].real_color == background_color) { idx = i; break; @@ -484,7 +484,7 @@ void CreateMMUTiledCanvas::recompute_colors() for (int x = 0; x < size.x; x++, ++p) { wxColour color(p.Red(), p.Green(), p.Blue()); int idx = -1; - for (int i = 0; i < m_pixel_colors.size(); i++) { + for (size_t i = 0; i < m_pixel_colors.size(); i++) { if (m_pixel_colors[i].real_color == color) { idx = i; break; @@ -525,7 +525,7 @@ void CreateMMUTiledCanvas::recompute_colors() c->printing_color->nb_pixels_real += c->nb_pixels_sum; } else { c->printing_color = &m_spools[0]; - for (int i = 1; i < m_spools.size(); i++) { + for (size_t i = 1; i < m_spools.size(); i++) { if ((color_dist(color_algo, m_spools[i].get_printed_color(use_spool), c->real_color) < color_dist(color_algo, c->printing_color->get_printed_color(use_spool), c->real_color))) { c->printing_color = &m_spools[i]; } @@ -546,10 +546,10 @@ void CreateMMUTiledCanvas::recompute_colors() // merge until nb_extruder is enough std::sort(m_used_colors.begin(), m_used_colors.end(), [](ColorEntry* e1, ColorEntry* e2) { return e1->nb_pixels_sum > e2->nb_pixels_sum; }); - while (use_near_color && m_used_colors.size() > nb_extruders) { + while (use_near_color && m_used_colors.size() > static_cast::size_type>(nb_extruders)) { //move the smallest color into the nearest one int idx_extruder = 0; - for (int i = 1; i < m_used_colors.size() - 1; i++) { + for (size_t i = 1; i < m_used_colors.size() - 1; i++) { if ((color_dist(color_algo, m_used_colors[i]->real_color, m_used_colors.back()->real_color) < color_dist(color_algo, m_used_colors[idx_extruder]->real_color, m_used_colors.back()->real_color))) { idx_extruder = i; } @@ -1048,7 +1048,7 @@ void CreateMMUTiledCanvas::create_main_tab(wxPanel* tab) #endif } } - catch (Exception) {} + catch (const Slic3r::Exception& ex){} } })); m_filename_ctrl = new wxTextCtrl(tab, wxID_ANY, ""); @@ -1240,7 +1240,7 @@ class MywxColourPickerCtrl : public wxColourPickerCtrl { })); clr_bt->GetPickerCtrl()->Bind(wxEVT_RIGHT_DOWN, ([clr_bt, sizer](wxMouseEvent& e) { //remove this color - for (int i = 0; i < s_main_app->m_spools.size(); i++) { + for (size_t i = 0; i < s_main_app->m_spools.size(); i++) { if (s_main_app->m_spools[i].widget == clr_bt && sizer->GetItem(i)->GetWindow() == clr_bt) { s_main_app->m_spools.erase(s_main_app->m_spools.begin() + i); s_main_app->refresh_color_conversion(i, false); @@ -1312,7 +1312,7 @@ class MywxOwnerDrawnComboBox : public wxOwnerDrawnComboBox, public CmbColorAssoc dc.SetBrush(*wxBLACK_BRUSH); dc.DrawLabel(_L("Automatic"), rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL); } else { - if (item-1 < m_main_app->m_spools.size()) { + if (static_castm_spools.size())>(item - 1) < m_main_app->m_spools.size()) { dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(m_main_app->m_spools[item-1].get_printed_color())); dc.DrawRectangle(rect); } else { @@ -1346,7 +1346,7 @@ int CreateMMUTiledCanvas::find_extruder(wxColour color) { const int color_algo = m_config.option("color_comp")->value; bool use_near_color = m_config.option("near_color")->value; int idx_extruder = 0; - for (int i = 0; i < m_used_colors.size() && i < nb_extruders; i++) { + for (size_t i = 0; i < m_used_colors.size() && static_cast(i) < nb_extruders; i++) { if (m_used_colors[i]->get_printed_color() == color) { idx_extruder = 1 + i; break; @@ -1373,7 +1373,7 @@ void CreateMMUTiledCanvas::recreate_color_conversion() MywxOwnerDrawnComboBox* clr_set = new MywxOwnerDrawnComboBox(this, line, _L("Automatic"), index); clr_set->Append(_L("Automatic")); - for (int i = 0; i < this->m_spools.size(); i++) { + for (size_t i = 0; i < this->m_spools.size(); i++) { clr_set->Append(std::to_string(i + 1)); } clr_set->SetSelection(0); @@ -1391,7 +1391,7 @@ void CreateMMUTiledCanvas::recreate_color_conversion() }; std::vector used; - for (int idx = 0; idx < m_pixel_colors.size(); idx++) { + for (size_t idx = 0; idx < m_pixel_colors.size(); idx++) { ColorEntry& c = m_pixel_colors[idx]; if (c.nb_pixels_real > 0) { used.push_back(&c); @@ -1417,7 +1417,7 @@ void CreateMMUTiledCanvas::recreate_color_conversion() //refresh color from comboboxes & destroyed links void CreateMMUTiledCanvas::refresh_color_conversion(int del_idx, bool is_add_not_del) { - for (int i = 0; i < m_pixel_colors.size(); i++) { + for (size_t i = 0; i < m_pixel_colors.size(); i++) { ColorEntry& c = m_pixel_colors[i]; if (c.widget_spool && !c.widget_spool->is_detached()) { MywxOwnerDrawnComboBox* clr_set = (MywxOwnerDrawnComboBox*)c.widget_spool->get_widget(); @@ -1476,7 +1476,7 @@ void CreateMMUTiledCanvas::create_color_tab(wxPanel* tab) //row of available colors //group_colors->append_single_option_line(group_colors->get_option("available_colors")); ConfigOptionStrings* available_colors = m_config.option("available_colors"); - for (int i = 0; i < available_colors->size(); i++) { + for (size_t i = 0; i < available_colors->size(); i++) { MywxColourPickerCtrl::add_color_bt(available_colors->get_at(i), color_row_sizer); } tab->Refresh(); @@ -1576,7 +1576,7 @@ void CreateMMUTiledCanvas::create_geometry(wxCommandEvent& event_args) { plat->set_project_filename(L("Mosaic")); const DynamicPrintConfig* print_config = this->m_gui_app->get_tab(Preset::TYPE_FFF_PRINT)->get_config(); - const DynamicPrintConfig* filament_config = this->m_gui_app->get_tab(Preset::TYPE_FFF_FILAMENT)->get_config(); + //const DynamicPrintConfig* filament_config = this->m_gui_app->get_tab(Preset::TYPE_FFF_FILAMENT)->get_config(); const DynamicPrintConfig* printer_config = this->m_gui_app->get_tab(Preset::TYPE_PRINTER)->get_config(); Vec2d offset_dbl = m_config.option("offset")->value; @@ -1618,7 +1618,7 @@ void CreateMMUTiledCanvas::create_geometry(wxCommandEvent& event_args) { if (use_near_color) { //find extruder wxColor color (background_color); - for (int i = 0; i < m_used_colors.size() && i < nb_extruders; i++) { + for (size_t i = 0; i < m_used_colors.size() && i < static_cast(nb_extruders); i++) { if (idx_extruder_base <= 0 || (color_dist(color_algo, m_used_colors[i]->get_printed_color(use_spool_colors), color) < color_dist(color_algo, m_used_colors[idx_extruder_base - 1]->get_printed_color(use_spool_colors), color))) { idx_extruder_base = 1 + i; } @@ -1633,7 +1633,7 @@ void CreateMMUTiledCanvas::create_geometry(wxCommandEvent& event_args) { #ifdef _DEBUG check_model_ids_validity(model); #endif /* _DEBUG */ - auto bb = mesh.bounding_box(); + // auto bb = mesh.bounding_box(); ModelObject* new_object = model.add_object(); new_object->name = into_u8(_L("Base Tile")); new_object->add_instance(); // each object should have at list one instance @@ -1763,7 +1763,7 @@ void CreateMMUTiledCanvas::create_geometry(wxCommandEvent& event_args) { //{m_impl=L"#800040" m_convertedToChar={m_str=0x0000000000000000 m_len=0 } } const ConfigOptionStrings* color_conf = printer_config->option("extruder_colour"); ConfigOptionStrings* new_color_conf = static_cast(color_conf->clone()); - for(int idx_col = 0; idx_col < this->m_used_colors.size() && idx_col < new_color_conf->size(); idx_col++){ + for(size_t idx_col = 0; idx_col < this->m_used_colors.size() && idx_col < new_color_conf->size(); idx_col++){ wxColour col = this->m_used_colors[idx_col]->get_printed_color(use_spool_colors); new_color_conf->get_at(idx_col) = "#" + AppConfig::int2hex(col.GetRGB()); } diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 857294b2fa7..2ba4ea49dd0 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -595,10 +595,12 @@ bool Control::is_wipe_tower_layer(int tick) const return false; if (tick == 0 || (tick == (int)m_values.size() - 1 && m_values[tick] > m_values[tick - 1])) return false; - if (m_values.size() > tick + 1 && (m_values[tick - 1] == m_values[tick + 1] && m_values[tick] < m_values[tick + 1]) || - (tick > 0 && m_values[tick] < m_values[tick - 1]) ) // if there is just one wiping on the layer + if ((m_values.size() > static_cast(tick + 1)) && + (((m_values[tick - 1] == m_values[tick + 1]) && (m_values[tick] < m_values[tick + 1])) || + ((m_values.size() > static_cast(tick + 1)) && + ((m_values[tick - 1] == m_values[tick + 1]) && (m_values[tick] > m_values[tick + 1]))))) { return true; - + } return false; } @@ -1225,8 +1227,7 @@ void Control::draw_ruler(wxDC& dc) assert(current_tick < m_values.size()); assert(max_tick < m_values.size()); assert(max_tick <= m_max_tick); - double current_value = m_values[current_tick]; - while (current_tick + m_ruler.short_step <= max_tick) { + while (current_tick + m_ruler.short_step <= max_tick) { wxCoord pos = get_position_from_tick(current_tick); draw_ticks_pair(dc, pos, mid, 2); // go to next value @@ -1253,7 +1254,6 @@ void Control::draw_ruler(wxDC& dc) } int prev_y_pos = -1; wxCoord label_height = dc.GetMultiLineTextExtent("0").y - 2; - int values_size = (int)m_values.size(); assert(m_values.size() > m_max_tick); //iterate on all layer z values while (tick <= m_max_tick) { @@ -1602,8 +1602,7 @@ wxString Control::get_tooltip(int tick/*=-1*/) assert(tick < m_values.size() && !m_values.empty()); // If tick is marked as a conflict (exclamation icon), // we should to explain why - ConflictType conflict = m_ticks.is_conflict_tick(*tick_code_it, m_mode, m_only_extruder, tick < m_values.size() ? m_values[tick] : m_values.back()); - if (conflict != ctNone) + ConflictType conflict = m_ticks.is_conflict_tick(*tick_code_it, m_mode, m_only_extruder, tick < static_cast(m_values.size()) ? m_values[tick] : m_values.back()); if (conflict != ctNone) tooltip += "\n\n" + _L("Note") + "! "; if (conflict == ctModeConflict) tooltip += _L("G-code associated to this tick mark is in a conflict with print mode.\n" @@ -1763,8 +1762,7 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren if (extruders_cnt > 1) { int tick = m_selection == ssLower ? m_lower_tick : m_higher_tick; assert(tick < m_values.size() && !m_values.empty()); - std::set used_extruders_for_tick = m_ticks.get_used_extruders_for_tick(tick, m_only_extruder, tick < m_values.size() ? m_values[tick] : m_values.back()); - + std::set used_extruders_for_tick = m_ticks.get_used_extruders_for_tick(tick, m_only_extruder, tick < static_cast(m_values.size()) ? m_values[tick] : m_values.back()); wxMenu* add_color_change_menu = new wxMenu(); for (int i = 1; i <= extruders_cnt; i++) { @@ -2386,8 +2384,8 @@ static std::string get_custom_code(const std::string& code_in, double height) bool valid = true; std::string value; do { - if (dlg.ShowModal() != wxID_OK) - return ""; + if (dlg.ShowModal() != wxID_OK) + return ""; value = into_u8(dlg.GetValue()); valid = GUI::Tab::validate_custom_gcode("Custom G-code", value); @@ -2446,8 +2444,7 @@ void Control::add_code_as_tick(Type type, int selected_extruder/* = -1*/) if ( it == m_ticks.ticks.end() ) { // try to add tick assert(tick < m_values.size() && !m_values.empty()); - if (!m_ticks.add_tick(tick, type, extruder, tick < m_values.size() ? m_values[tick] : m_values.back())) - return; + if (!m_ticks.add_tick(tick, type, extruder, tick < static_cast(m_values.size()) ? m_values[tick] : m_values.back())) return; } else if (type == ToolChange || type == ColorChange) { // try to switch tick code to ToolChange or ColorChange accordingly diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 0325d8c336f..78165d66cc0 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -42,31 +42,31 @@ namespace Slic3r { namespace GUI { wxString double_to_string(double const value, const int max_precision /*= 6*/) { // Style_NoTrailingZeroes does not work on OSX. It also does not work correctly with some locales on Windows. -// return wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_NoTrailingZeroes); +// return wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_NoTrailingZeroes); - wxString s = wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_None); + wxString s = wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_None); - // The following code comes from wxNumberFormatter::RemoveTrailingZeroes(wxString& s) - // with the exception that here one sets the decimal separator explicitely to dot. + // The following code comes from wxNumberFormatter::RemoveTrailingZeroes(wxString& s) + // with the exception that here one sets the decimal separator explicitely to dot. // If number is in scientific format, trailing zeroes belong to the exponent and cannot be removed. if (s.find_first_of("eE") == wxString::npos) { char dec_sep = is_decimal_separator_point() ? '.' : ','; const size_t posDecSep = s.find(dec_sep); - // No decimal point => removing trailing zeroes irrelevant for integer number. - if (posDecSep != wxString::npos) { - // Find the last character to keep. - size_t posLastNonZero = s.find_last_not_of("0"); + // No decimal point => removing trailing zeroes irrelevant for integer number. + if (posDecSep != wxString::npos) { + // Find the last character to keep. + size_t posLastNonZero = s.find_last_not_of("0"); // If it's the decimal separator itself, don't keep it either. - if (posLastNonZero == posDecSep) - -- posLastNonZero; - s.erase(posLastNonZero + 1); - // Remove sign from orphaned zero. - if (s.compare("-0") == 0) - s = "0"; + if (posLastNonZero == posDecSep) + -- posLastNonZero; + s.erase(posLastNonZero + 1); + // Remove sign from orphaned zero. + if (s.compare("-0") == 0) + s = "0"; if (s.Last() == '.') s.erase(s.length() -1); - } - } + } + } return s; } @@ -74,10 +74,10 @@ wxString double_to_string(double const value, const int max_precision /*= 6*/) wxString get_points_string(const std::vector& values) { wxString ret_str; - for (size_t i = 0; i < values.size(); ++ i) { - const Vec2d& el = values[i]; - ret_str += wxString::Format((i == 0) ? "%ix%i" : ", %ix%i", int(el[0]), int(el[1])); - } + for (size_t i = 0; i < values.size(); ++ i) { + const Vec2d& el = values[i]; + ret_str += wxString::Format((i == 0) ? "%ix%i" : ", %ix%i", int(el[0]), int(el[1])); + } return ret_str; } @@ -112,55 +112,55 @@ std::pair get_strings_points(const wxString &str, double min, double Field::~Field() { - if (m_on_kill_focus) - m_on_kill_focus = nullptr; - if (m_on_change) - m_on_change = nullptr; - if (m_back_to_initial_value) - m_back_to_initial_value = nullptr; - if (m_back_to_sys_value) - m_back_to_sys_value = nullptr; - if (getWindow()) { - wxWindow* win = getWindow(); - win->Destroy(); - win = nullptr; - } + if (m_on_kill_focus) + m_on_kill_focus = nullptr; + if (m_on_change) + m_on_change = nullptr; + if (m_back_to_initial_value) + m_back_to_initial_value = nullptr; + if (m_back_to_sys_value) + m_back_to_sys_value = nullptr; + if (getWindow()) { + wxWindow* win = getWindow(); + win->Destroy(); + win = nullptr; + } } void Field::PostInitialize() { - auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - - switch (m_opt.type) - { - case coPercents: - case coFloats: - case coFloatsOrPercents: - case coStrings: - case coBools: - case coPoints: - case coInts: { - auto tag_pos = m_opt_id.find("#"); - if (tag_pos != std::string::npos) - m_opt_idx = stoi(m_opt_id.substr(tag_pos + 1, m_opt_id.size())); + auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + + switch (m_opt.type) + { + case coPercents: + case coFloats: + case coFloatsOrPercents: + case coStrings: + case coBools: + case coPoints: + case coInts: { + auto tag_pos = m_opt_id.find("#"); + if (tag_pos != std::string::npos) + m_opt_idx = stoi(m_opt_id.substr(tag_pos + 1, m_opt_id.size())); else m_opt_idx = -1; // no index, ie full vector in serialized form - break; - } - default: - break; - } + break; + } + default: + break; + } // initialize m_unit_value m_em_unit = em_unit(m_parent); parent_is_custom_ctrl = dynamic_cast(m_parent) != nullptr; - BUILD(); + BUILD(); - // For the mode, when settings are in non-modal dialog, neither dialog nor tabpanel doesn't receive wxEVT_KEY_UP event, when some field is selected. - // So, like a workaround check wxEVT_KEY_UP event for the Filed and switch between tabs if Ctrl+(1-6) was pressed - if (getWindow()) - getWindow()->Bind(wxEVT_KEY_UP, [](wxKeyEvent& evt) { + // For the mode, when settings are in non-modal dialog, neither dialog nor tabpanel doesn't receive wxEVT_KEY_UP event, when some field is selected. + // So, like a workaround check wxEVT_KEY_UP event for the Filed and switch between tabs if Ctrl+(1-6) was pressed + if (getWindow()) + getWindow()->Bind(wxEVT_KEY_UP, [](wxKeyEvent& evt) { if ((evt.GetModifiers() & wxMOD_CONTROL) != 0 && (evt.GetModifiers() & wxMOD_ALT) == 0) { MainFrame::ETabType tab_id = MainFrame::ETabType::Any; switch (evt.GetKeyCode()) { @@ -171,13 +171,13 @@ void Field::PostInitialize() case '5': { tab_id = MainFrame::ETabType::FilamentSettings; break; } case '6': { tab_id = MainFrame::ETabType::PrinterSettings; break; } #ifdef __APPLE__ - case 'f': + case 'f': #else /* __APPLE__ */ - case WXK_CONTROL_F: + case WXK_CONTROL_F: #endif /* __APPLE__ */ - case 'F': { wxGetApp().plater()->search(false); break; } - default: break; - } + case 'F': { wxGetApp().plater()->search(false); break; } + default: break; + } if (tab_id < MainFrame::ETabType::Any) { wxGetApp().mainframe->select_tab(tab_id); if (wxGetApp().mainframe->get_layout() == MainFrame::ESettingsLayout::Tabs @@ -186,20 +186,20 @@ void Field::PostInitialize() // tab panel should be focused for correct navigation between tabs wxGetApp().tab_panel()->SetFocus(); } - } + } - evt.Skip(); - }); + evt.Skip(); + }); } // Values of width to alignments of fields -int Field::def_width() { return 8; } -int Field::def_width_wider() { return 16; } -int Field::def_width_thinner() { return 4; } +int Field::def_width() { return 8; } +int Field::def_width_wider() { return 16; } +int Field::def_width_thinner() { return 4; } void Field::on_kill_focus() { - // call the registered function if it is available + // call the registered function if it is available if (m_on_kill_focus!=nullptr) m_on_kill_focus(m_opt_id); } @@ -214,20 +214,20 @@ void Field::on_change_field() void Field::on_back_to_initial_value() { - if (m_back_to_initial_value != nullptr && m_is_modified_value) - m_back_to_initial_value(m_opt_id); + if (m_back_to_initial_value != nullptr && m_is_modified_value) + m_back_to_initial_value(m_opt_id); } void Field::on_back_to_sys_value() { - if (m_back_to_sys_value != nullptr && m_is_nonsys_value) - m_back_to_sys_value(m_opt_id); + if (m_back_to_sys_value != nullptr && m_is_nonsys_value) + m_back_to_sys_value(m_opt_id); } wxString Field::get_tooltip_text(const wxString& default_string) { - wxString tooltip_text(""); - wxString tooltip = _(m_opt.tooltip); + wxString tooltip_text(""); + wxString tooltip = _(m_opt.tooltip); update_Slic3r_string(tooltip); std::string opt_id = m_opt_id; @@ -237,12 +237,12 @@ wxString Field::get_tooltip_text(const wxString& default_string) opt_id += "]"; } - if (tooltip.length() > 0) + if (tooltip.length() > 0) tooltip_text = tooltip + "\n" + _(L("default value")) + "\t: " + (boost::iends_with(opt_id, "_gcode") ? "\n" : "") + default_string + "\n" + _(L("parameter name")) + "\t: " + opt_id; - return tooltip_text; + return tooltip_text; } wxString Field::get_rich_tooltip_text(const wxString& default_string) @@ -262,7 +262,7 @@ wxString Field::get_rich_tooltip_text(const wxString& default_string) //add "\n" to long tooltip lines int length = 0; - for (int i = 0; i < wtooltip.size(); i++) { + for (size_t i = 0; i < wtooltip.size(); i++) { if (length >= 80 && wtooltip[i] == u' ') wtooltip_text.push_back(u'\n'); else @@ -363,8 +363,8 @@ void RichTooltipTimer::Notify() { bool Field::is_matched(const std::string &string, const std::string &pattern) { - std::regex regex_pattern(pattern, std::regex_constants::icase); // use ::icase to make the matching case insensitive like /i in perl - return std::regex_match(string, regex_pattern); + std::regex regex_pattern(pattern, std::regex_constants::icase); // use ::icase to make the matching case insensitive like /i in perl + return std::regex_match(string, regex_pattern); } static wxString na_value() { return _L("N/A"); } @@ -504,6 +504,9 @@ std::pair any_to_wxstring(const boost::any &value, const ConfigO text_value = get_points_string({boost::any_cast(value)}); break; } + default: { + break; + } } return {text_value, has_nil}; } @@ -527,7 +530,7 @@ bool TextField::get_vector_value(const wxString &str, ConfigOptionVectorBase &re boost::replace_all(vector_str, ";", ","); try { reader.deserialize(vector_str); - } catch (std::exception) {} + } catch (const std::exception& ex){} std::string good_str = reader.serialize(); // replace ',' by ';' boost::replace_all(good_str, ",", ";"); @@ -920,15 +923,15 @@ void TextField::get_value_by_opt_type(wxString &str, const bool check_value /* = void Field::msw_rescale() { - // update em_unit value - m_em_unit = em_unit(m_parent); + // update em_unit value + m_em_unit = em_unit(m_parent); } void Field::sys_color_changed() { #ifdef _WIN32 - if (wxWindow* win = this->getWindow()) - wxGetApp().UpdateDarkUI(win); + if (wxWindow* win = this->getWindow()) + wxGetApp().UpdateDarkUI(win); #endif } @@ -945,7 +948,7 @@ void TextCtrl::BUILD() { if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit); if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); - wxString text_value = wxString(""); + wxString text_value = wxString(""); boost::any anyval = m_opt.default_value->get_any(m_opt_idx); text_value = any_to_wxstring(m_opt.default_value->get_any(m_opt_idx), m_opt, m_opt_idx).first; @@ -960,7 +963,7 @@ void TextCtrl::BUILD() { long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER; #ifdef _WIN32 - style |= wxBORDER_SIMPLE; + style |= wxBORDER_SIMPLE; #endif wxTextCtrl* temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style); if (parent_is_custom_ctrl && m_opt.height < 0) @@ -968,12 +971,12 @@ void TextCtrl::BUILD() { temp->SetFont(m_opt.is_code ? Slic3r::GUI::wxGetApp().code_font(): Slic3r::GUI::wxGetApp().normal_font()); - wxGetApp().UpdateDarkUI(temp); + wxGetApp().UpdateDarkUI(temp); if (! m_opt.multiline && !wxOSX) - // Only disable background refresh for single line input fields, as they are completely painted over by the edit control. - // This does not apply to the multi-line edit field, where the last line and a narrow frame around the text is not cleared. - temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + // Only disable background refresh for single line input fields, as they are completely painted over by the edit control. + // This does not apply to the multi-line edit field, where the last line and a narrow frame around the text is not cleared. + temp->SetBackgroundStyle(wxBG_STYLE_PAINT); #ifdef __WXOSX__ temp->OSXDisableAllSmartSubstitutions(); #endif // __WXOSX__ @@ -990,36 +993,36 @@ void TextCtrl::BUILD() { }), temp->GetId()); } - temp->Bind(wxEVT_LEFT_DOWN, ([temp](wxEvent& event) - { - //! to allow the default handling - event.Skip(); - //! eliminating the g-code pop up text description - bool flag = false; + temp->Bind(wxEVT_LEFT_DOWN, ([temp](wxEvent& event) + { + //! to allow the default handling + event.Skip(); + //! eliminating the g-code pop up text description + bool flag = false; #ifdef __WXGTK__ - // I have no idea why, but on GTK flag works in other way - flag = true; + // I have no idea why, but on GTK flag works in other way + flag = true; #endif // __WXGTK__ - temp->GetToolTip()->Enable(flag); - }), temp->GetId()); + temp->GetToolTip()->Enable(flag); + }), temp->GetId()); - temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e) - { - e.Skip(); + temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e) + { + e.Skip(); #if !defined(__WXGTK__) - temp->GetToolTip()->Enable(true); + temp->GetToolTip()->Enable(true); #endif // __WXGTK__ if (!bEnterPressed) propagate_value(); - }), temp->GetId()); + }), temp->GetId()); /* - // select all text using Ctrl+A - temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event) - { - if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL)) - temp->SetSelection(-1, -1); //select all - event.Skip(); - })); + // select all text using Ctrl+A + temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event) + { + if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL)) + temp->SetSelection(-1, -1); //select all + event.Skip(); + })); */ // recast as a wxWindow to fit the calling convention window = dynamic_cast(temp); @@ -1123,11 +1126,11 @@ bool TextCtrl::value_was_changed() void TextCtrl::propagate_value() { - if (!is_defined_input_value(window, m_opt.type) ) - // on_kill_focus() cause a call of OptionsGroup::reload_config(), - // Thus, do it only when it's really needed (when undefined value was input) + if (!is_defined_input_value(window, m_opt.type) ) + // on_kill_focus() cause a call of OptionsGroup::reload_config(), + // Thus, do it only when it's really needed (when undefined value was input) on_kill_focus(); - else if (value_was_changed()) + else if (value_was_changed()) on_change_field(); //update m_last_meaningful_value ? if (!m_value.empty() && dynamic_cast(window)->GetValue() != na_value()) @@ -1178,11 +1181,11 @@ void TextCtrl::set_na_value() boost::any& TextCtrl::get_value() { - wxString ret_str = static_cast(window)->GetValue(); - // update m_value - get_value_by_opt_type(ret_str); + wxString ret_str = static_cast(window)->GetValue(); + // update m_value + get_value_by_opt_type(ret_str); - return m_value; + return m_value; } void TextCtrl::msw_rescale() @@ -1214,7 +1217,7 @@ void TextCtrl::disable() { dynamic_cast(window)->Disable(); dynamic void TextCtrl::change_field_value(wxEvent& event) { if ((bChangedValueEvent = (event.GetEventType()==wxEVT_KEY_UP))) - on_change_field(); + on_change_field(); event.Skip(); }; #endif //__WXGTK__ @@ -1258,8 +1261,8 @@ void CheckBox::BUILD() { window = dynamic_cast(temp); } window->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - if (!wxOSX) window->SetBackgroundStyle(wxBG_STYLE_PAINT); - if (m_opt.readonly) window->Enable(false); + if (!wxOSX) window->SetBackgroundStyle(wxBG_STYLE_PAINT); + if (m_opt.readonly) window->Enable(false); //set value (need the window for the set_value) @@ -1338,7 +1341,7 @@ void CheckBox::set_na_value() boost::any& CheckBox::get_value() { -// boost::any m_value; +// boost::any m_value; bool value = false; wxCheckBox* chk = dynamic_cast(window); if (chk != nullptr) { @@ -1351,11 +1354,11 @@ boost::any& CheckBox::get_value() if (tgl) value = tgl->GetValue(); } #endif - if (m_opt.type == coBool) - m_value = static_cast(value); - else - m_value = m_is_na_val ? ConfigOptionBoolsNullable::NIL_VALUE() : static_cast(value); - return m_value; + if (m_opt.type == coBool) + m_value = static_cast(value); + else + m_value = m_is_na_val ? ConfigOptionBoolsNullable::NIL_VALUE() : static_cast(value); + return m_value; } void CheckBox::msw_rescale() @@ -1377,32 +1380,32 @@ void CheckBox::msw_rescale() void SpinCtrl::BUILD() { - auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord); + auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord); if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit); if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); - wxString text_value = wxString(""); - int default_value = 0; - - switch (m_opt.type) { - case coInt: - default_value = m_opt.default_value->get_int(); - text_value = wxString::Format(_T("%i"), default_value); - break; - case coInts: - { - const ConfigOptionInts *vec = m_opt.get_default_value(); - if (vec == nullptr || vec->empty()) break; - for (size_t id = 0; id < vec->size(); ++id) - { - default_value = vec->get_at(id); - text_value += wxString::Format(_T("%i"), default_value); - } - break; - } - default: - break; - } + wxString text_value = wxString(""); + int default_value = 0; + + switch (m_opt.type) { + case coInt: + default_value = m_opt.default_value->get_int(); + text_value = wxString::Format(_T("%i"), default_value); + break; + case coInts: + { + const ConfigOptionInts *vec = m_opt.get_default_value(); + if (vec == nullptr || vec->empty()) break; + for (size_t id = 0; id < vec->size(); ++id) + { + default_value = vec->get_at(id); + text_value += wxString::Format(_T("%i"), default_value); + } + break; + } + default: + break; + } const int min_val = m_opt.min == INT_MIN #ifdef __WXOSX__ @@ -1414,23 +1417,23 @@ void SpinCtrl::BUILD() { || m_opt.min > 0 #endif ? 0 : m_opt.min; - const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647; + const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647; - auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, - wxTE_PROCESS_ENTER | wxSP_ARROW_KEYS + auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, + wxTE_PROCESS_ENTER | wxSP_ARROW_KEYS #ifdef _WIN32 - | wxBORDER_SIMPLE + | wxBORDER_SIMPLE #endif - , min_val, max_val, default_value); + , min_val, max_val, default_value); #ifdef __WXGTK3__ - wxSize best_sz = temp->GetBestSize(); - if (best_sz.x > size.x) - temp->SetSize(wxSize(size.x + 2 * best_sz.y, best_sz.y)); + wxSize best_sz = temp->GetBestSize(); + if (best_sz.x > size.x) + temp->SetSize(wxSize(size.x + 2 * best_sz.y, best_sz.y)); #endif //__WXGTK3__ - temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); - wxGetApp().UpdateDarkUI(temp); + wxGetApp().UpdateDarkUI(temp); if (m_opt.height < 0 && parent_is_custom_ctrl) opt_height = (double)temp->GetSize().GetHeight() / m_em_unit; @@ -1439,11 +1442,11 @@ void SpinCtrl::BUILD() { // the kill focus event is not propagated to the encompassing widget, // so we need to bind it on the inner text widget instead. (Ugh.) #ifdef __WXOSX__ - temp->GetText()->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) + temp->GetText()->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) #else - temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) + temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) #endif - { + { e.Skip(); if (bEnterPressed) { bEnterPressed = false; @@ -1451,7 +1454,7 @@ void SpinCtrl::BUILD() { } propagate_value(); - })); + })); temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent& e) { propagate_value(); }), temp->GetId()); @@ -1462,16 +1465,16 @@ void SpinCtrl::BUILD() { bEnterPressed = true; }), temp->GetId()); - temp->Bind(wxEVT_TEXT, ([this, temp](wxCommandEvent& e) - { -// # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value -// # when it was changed from the text control, so the on_change callback -// # gets the old one, and on_kill_focus resets the control to the old value. -// # As a workaround, we get the new value from $event->GetString and store -// # here temporarily so that we can return it from get_value() - - long value; - const bool parsed = e.GetString().ToLong(&value); + temp->Bind(wxEVT_TEXT, ([this, temp](wxCommandEvent& e) + { +// # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value +// # when it was changed from the text control, so the on_change callback +// # gets the old one, and on_kill_focus resets the control to the old value. +// # As a workaround, we get the new value from $event->GetString and store +// # here temporarily so that we can return it from get_value() + + long value; + const bool parsed = e.GetString().ToLong(&value); if (!parsed || value < INT_MIN || value > INT_MAX) tmp_value = UNDEF_VALUE; else { @@ -1494,10 +1497,10 @@ void SpinCtrl::BUILD() { } #endif } - }), temp->GetId()); + }), temp->GetId()); - // recast as a wxWindow to fit the calling convention - window = dynamic_cast(temp); + // recast as a wxWindow to fit the calling convention + window = dynamic_cast(temp); //problem: it has 2 windows, with a child: the mouse enter event won't fire if in children! (also it need the windoww, so put it after) this->set_tooltip(text_value); @@ -1511,7 +1514,7 @@ void SpinCtrl::propagate_value() if (tmp_value == UNDEF_VALUE) { on_kill_focus(); - } else { + } else { #ifdef __WXOSX__ // check input value for minimum if (m_opt.min > 0 && tmp_value < m_opt.min) { @@ -1554,7 +1557,7 @@ void Choice::BUILD() { if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit); if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); - choice_ctrl* temp; + choice_ctrl* temp; if (m_opt.gui_type != ConfigOptionDef::GUIType::undefined && m_opt.gui_type != ConfigOptionDef::GUIType::select_open) { m_is_editable = true; temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxTE_PROCESS_ENTER); @@ -1579,24 +1582,24 @@ void Choice::BUILD() { temp->SetSize(best_sz); #endif //__WXGTK3__ - temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); - // recast as a wxWindow to fit the calling convention - window = dynamic_cast(temp); - - if (! m_opt.enum_labels.empty() || ! m_opt.enum_values.empty()) { - if (m_opt.enum_labels.empty()) { - // Append non-localized enum_values - for (auto el : m_opt.enum_values) - temp->Append(el); - } else { - // Append localized enum_labels - for (auto el : m_opt.enum_labels) - temp->Append(_(el)); - } - set_selection(); - } + // recast as a wxWindow to fit the calling convention + window = dynamic_cast(temp); + + if (! m_opt.enum_labels.empty() || ! m_opt.enum_values.empty()) { + if (m_opt.enum_labels.empty()) { + // Append non-localized enum_values + for (auto el : m_opt.enum_values) + temp->Append(el); + } else { + // Append localized enum_labels + for (auto el : m_opt.enum_labels) + temp->Append(_(el)); + } + set_selection(); + } this->suppress_scroll(); temp->Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent& e) { if (m_suppress_scroll && !m_is_dropped) @@ -1683,66 +1686,66 @@ void Choice::set_selection() */ m_disable_change_event = true; - wxString text_value = wxString(""); + wxString text_value = wxString(""); choice_ctrl* field = dynamic_cast(window); - switch (m_opt.type) { - case coEnum:{ + switch (m_opt.type) { + case coEnum:{ field->SetSelection(m_opt.default_value->get_int()); - break; - } - case coFloat: - case coPercent: { - double val = m_opt.default_value->get_float(); - text_value = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 1); - break; - } - case coInt:{ - text_value = wxString::Format(_T("%i"), int(m_opt.default_value->get_int())); - break; - } - case coStrings:{ - text_value = m_opt.get_default_value()->get_at(m_opt_idx); - break; - } - case coFloatOrPercent: { - text_value = double_to_string(m_opt.default_value->get_float(), m_opt.precision); - if (m_opt.get_default_value()->percent) - text_value += "%"; - break; - } + break; + } + case coFloat: + case coPercent: { + double val = m_opt.default_value->get_float(); + text_value = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 1); + break; + } + case coInt:{ + text_value = wxString::Format(_T("%i"), int(m_opt.default_value->get_int())); + break; + } + case coStrings:{ + text_value = m_opt.get_default_value()->get_at(m_opt_idx); + break; + } + case coFloatOrPercent: { + text_value = double_to_string(m_opt.default_value->get_float(), m_opt.precision); + if (m_opt.get_default_value()->percent) + text_value += "%"; + break; + } default: break; - } + } - if (!text_value.IsEmpty()) { + if (!text_value.IsEmpty()) { size_t idx = 0; - for (auto el : m_opt.enum_values) { - if (el == text_value) - break; - ++idx; - } - idx == m_opt.enum_values.size() ? field->SetValue(text_value) : field->SetSelection(idx); - } + for (auto el : m_opt.enum_values) { + if (el == text_value) + break; + ++idx; + } + idx == m_opt.enum_values.size() ? field->SetValue(text_value) : field->SetSelection(idx); + } } void Choice::set_text_value(const std::string &value, bool change_event) //! Redundant? { - m_disable_change_event = !change_event; + m_disable_change_event = !change_event; - size_t idx=0; - for (auto el : m_opt.enum_values) - { - if (el == value) - break; - ++idx; - } + size_t idx=0; + for (auto el : m_opt.enum_values) + { + if (el == value) + break; + ++idx; + } choice_ctrl* field = dynamic_cast(window); - idx == m_opt.enum_values.size() ? - field->SetValue(value) : - field->SetSelection(idx); + idx == m_opt.enum_values.size() ? + field->SetValue(value) : + field->SetSelection(idx); - m_disable_change_event = false; + m_disable_change_event = false; } int32_t Choice::idx_from_enum_value(int32_t val) { @@ -1780,27 +1783,27 @@ void Choice::set_any_value(const boost::any &value, bool change_event) assert(m_opt.type == coEnum || m_opt.gui_type == ConfigOptionDef::GUIType::select_open || m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open); - m_disable_change_event = !change_event; + m_disable_change_event = !change_event; choice_ctrl* field = dynamic_cast(window); - switch (m_opt.type) { - case coInt: - case coFloat: - case coPercent: - case coFloatOrPercent: - case coString: - case coStrings: { + switch (m_opt.type) { + case coInt: + case coFloat: + case coPercent: + case coFloatOrPercent: + case coString: + case coStrings: { auto [/*wxString*/ text_value, /*bool*/ has_nil] = any_to_wxstring(value, m_opt, m_opt_idx); size_t idx = 0; const std::vector& enums = m_opt.enum_values.empty() ? m_opt.enum_labels : m_opt.enum_values; - for (auto el : enums) - { - if (el == text_value) - break; - ++idx; - } + for (auto el : enums) + { + if (el == text_value) + break; + ++idx; + } if (idx == enums.size()) { // For editable Combobox under OSX is needed to set selection to -1 explicitly, // otherwise selection doesn't be changed @@ -1808,7 +1811,7 @@ void Choice::set_any_value(const boost::any &value, bool change_event) field->SetValue(text_value); } else - field->SetSelection(idx); + field->SetSelection(idx); // merill note: i don't like hacks like that. makes the code spagetti if (!m_value.empty() && m_opt.opt_key == "fill_density") { @@ -1819,20 +1822,20 @@ void Choice::set_any_value(const boost::any &value, bool change_event) m_value = val; } - break; - } - case coEnum: { + break; + } + case coEnum: { int32_t val = boost::any_cast(value); val = idx_from_enum_value(val); - BOOST_LOG_TRIVIAL(debug) << "Set field from key "<< m_opt_id << " as int " << boost::any_cast(value) << " modified to " << val; - field->SetSelection(val); - break; - } - default: - break; - } + BOOST_LOG_TRIVIAL(debug) << "Set field from key "<< m_opt_id << " as int " << boost::any_cast(value) << " modified to " << val; + field->SetSelection(val); + break; + } + default: + break; + } - m_disable_change_event = false; + m_disable_change_event = false; } //! it's needed for _update_serial_ports() @@ -1840,21 +1843,21 @@ void Choice::set_any_value(const boost::any &value, bool change_event) void Choice::set_values(const std::vector& values) { assert(m_opt.type != coEnum); - if (values.empty()) - return; - m_disable_change_event = true; + if (values.empty()) + return; + m_disable_change_event = true; -// # it looks that Clear() also clears the text field in recent wxWidgets versions, -// # but we want to preserve it - auto ww = dynamic_cast(window); - auto value = ww->GetValue(); - ww->Clear(); - ww->Append(""); - for (const auto &el : values) - ww->Append(wxString(el)); - ww->SetValue(value); +// # it looks that Clear() also clears the text field in recent wxWidgets versions, +// # but we want to preserve it + auto ww = dynamic_cast(window); + auto value = ww->GetValue(); + ww->Clear(); + ww->Append(""); + for (const auto &el : values) + ww->Append(wxString(el)); + ww->SetValue(value); - m_disable_change_event = false; + m_disable_change_event = false; } void Choice::convert_to_enum_value(int32_t ret_enum) { @@ -1873,48 +1876,47 @@ void Choice::convert_to_enum_value(int32_t ret_enum) { void Choice::set_values(const wxArrayString &values) { assert(m_opt.type != coEnum); - if (values.empty()) - return; + if (values.empty()) + return; - m_disable_change_event = true; + m_disable_change_event = true; - // # it looks that Clear() also clears the text field in recent wxWidgets versions, - // # but we want to preserve it - auto ww = dynamic_cast(window); - auto value = ww->GetValue(); - ww->Clear(); -// ww->Append(""); - for (const auto &el : values) - ww->Append(el); - ww->SetValue(value); + // # it looks that Clear() also clears the text field in recent wxWidgets versions, + // # but we want to preserve it + auto ww = dynamic_cast(window); + auto value = ww->GetValue(); + ww->Clear(); +// ww->Append(""); + for (const auto &el : values) + ww->Append(el); + ww->SetValue(value); - m_disable_change_event = false; + m_disable_change_event = false; } boost::any& Choice::get_value() { choice_ctrl* field = dynamic_cast(window); - wxString ret_str = field->GetValue(); + wxString ret_str = field->GetValue(); - // options from right panel - std::vector right_panel_options{ "support", "pad", "scale_unit" }; - for (auto rp_option: right_panel_options) - if (m_opt_id == rp_option) - return m_value = boost::any(ret_str); + // options from right panel + std::vector right_panel_options{ "support", "pad", "scale_unit" }; + for (auto rp_option: right_panel_options) + if (m_opt_id == rp_option) + return m_value = boost::any(ret_str); - if (m_opt.type == coEnum) + if (m_opt.type == coEnum) { int ret_enum = field->GetSelection(); convert_to_enum_value(ret_enum); } else if (m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open) { const int ret_enum = field->GetSelection(); - if (!m_opt.enum_values.empty() && (m_opt.type == coString || m_opt.type == coStrings) && ret_enum >=0 && ret_enum < m_opt.enum_values.size()) { - m_value = m_opt.enum_values[ret_enum]; + if (!m_opt.enum_values.empty() && (m_opt.type == coString || m_opt.type == coStrings) && static_cast(ret_enum) < m_opt.enum_values.size()) { m_value = m_opt.enum_values[ret_enum]; } else if (ret_enum < 0 || m_opt.enum_values.empty() || m_opt.type == coStrings || (ret_str != m_opt.enum_values[ret_enum] && ret_str != _(m_opt.enum_labels[ret_enum]))) - // modifies ret_string! + // modifies ret_string! get_value_by_opt_type(ret_str); else if (m_opt.type == coFloatOrPercent) { m_value = FloatOrPercent{string_to_double_decimal_point(m_opt.enum_values[ret_enum]), @@ -1924,11 +1926,11 @@ boost::any& Choice::get_value() else m_value = string_to_double_decimal_point(m_opt.enum_values[ret_enum]); } - else - // modifies ret_string! + else + // modifies ret_string! get_value_by_opt_type(ret_str); - return m_value; + return m_value; } void Choice::enable() { dynamic_cast(window)->Enable(); } @@ -1942,12 +1944,12 @@ void Choice::msw_rescale() #ifdef __WXOSX__ const wxString selection = field->GetValue();// field->GetString(index); - /* To correct scaling (set new controll size) of a wxBitmapCombobox - * we need to refill control with new bitmaps. So, in our case : - * 1. clear control - * 2. add content - * 3. add scaled "empty" bitmap to the at least one item - */ + /* To correct scaling (set new controll size) of a wxBitmapCombobox + * we need to refill control with new bitmaps. So, in our case : + * 1. clear control + * 2. add content + * 3. add scaled "empty" bitmap to the at least one item + */ field->Clear(); wxSize size(wxDefaultSize); size.SetWidth((m_opt.width > 0 ? m_opt.width : def_width_wider()) * m_em_unit); @@ -1959,10 +1961,10 @@ void Choice::msw_rescale() size_t idx = 0; if (! m_opt.enum_labels.empty() || ! m_opt.enum_values.empty()) { - size_t counter = 0; - bool labels = ! m_opt.enum_labels.empty(); + size_t counter = 0; + bool labels = ! m_opt.enum_labels.empty(); for (const std::string &el : labels ? m_opt.enum_labels : m_opt.enum_values) { - wxString text = labels ? _(el) : from_u8(el); + wxString text = labels ? _(el) : from_u8(el); field->Append(text); if (text == selection) idx = counter; @@ -1990,11 +1992,11 @@ void Choice::msw_rescale() void ColourPicker::BUILD() { - auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord); + auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord); if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit); if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); - // Validate the color + // Validate the color wxColour clr = wxTransparentColour; if (m_opt.type == coStrings) clr = wxColour{wxString{ m_opt.get_default_value()->get_at(m_opt_idx) }}; @@ -2004,20 +2006,20 @@ void ColourPicker::BUILD() clr = wxColour{ (unsigned long)m_opt.get_default_value()->get_at(m_opt_idx) }; if (m_opt.type == coInt) clr = wxColour{ (unsigned long)m_opt.get_default_value()->value }; - if (!clr.IsOk()) { - clr = wxTransparentColour; - } + if (!clr.IsOk()) { + clr = wxTransparentColour; + } - auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size); + auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size); if (parent_is_custom_ctrl && m_opt.height < 0) opt_height = (double)temp->GetSize().GetHeight() / m_em_unit; temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); - wxGetApp().UpdateDarkUI(temp->GetPickerCtrl()); + wxGetApp().UpdateDarkUI(temp->GetPickerCtrl()); - // // recast as a wxWindow to fit the calling convention - window = dynamic_cast(temp); + // // recast as a wxWindow to fit the calling convention + window = dynamic_cast(temp); window->Bind(wxEVT_COLOURPICKER_CHANGED, ([this](wxCommandEvent e) { on_change_field(); }), window->GetId()); @@ -2060,21 +2062,21 @@ void ColourPicker::set_any_value(const boost::any &value, bool change_event) boost::any& ColourPicker::get_value() { - auto colour = static_cast(window)->GetColour(); + auto colour = static_cast(window)->GetColour(); if (colour == wxTransparentColour) m_value = std::string(""); else { - auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue()); - m_value = clr_str.ToStdString(); + auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue()); + m_value = clr_str.ToStdString(); } - return m_value; + return m_value; } void ColourPicker::msw_rescale() { Field::msw_rescale(); - wxColourPickerCtrl* field = dynamic_cast(window); + wxColourPickerCtrl* field = dynamic_cast(window); auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord); if (m_opt.height >= 0) size.SetHeight(m_opt.height * m_em_unit); @@ -2093,9 +2095,9 @@ void ColourPicker::msw_rescale() void ColourPicker::sys_color_changed() { #ifdef _WIN32 - if (wxWindow* win = this->getWindow()) - if (wxColourPickerCtrl* picker = dynamic_cast(win)) - wxGetApp().UpdateDarkUI(picker->GetPickerCtrl(), true); + if (wxWindow* win = this->getWindow()) + if (wxColourPickerCtrl* picker = dynamic_cast(win)) + wxGetApp().UpdateDarkUI(picker->GetPickerCtrl(), true); #endif } @@ -2171,7 +2173,7 @@ void GraphButton::set_any_value(const boost::any &value, bool change_event) assert(!graphs.empty()); if (!graphs.empty()) { assert(m_opt_idx (m_opt_idx) < graphs.size() ? static_cast(m_opt_idx) : 0]; } } else if (this->m_opt.type == coGraph || this->m_opt.type == coGraphs) { m_value = current_value = boost::any_cast(value); @@ -2214,7 +2216,7 @@ void GraphButton::sys_color_changed() void PointCtrl::BUILD() { - auto temp = new wxBoxSizer(wxHORIZONTAL); + auto temp = new wxBoxSizer(wxHORIZONTAL); const wxSize field_size(4 * m_em_unit, -1); @@ -2223,50 +2225,50 @@ void PointCtrl::BUILD() default_pt = m_opt.get_default_value()->value; else // coPoints default_pt = m_opt.get_default_value()->get_at(0); - double val = default_pt(0); - wxString X = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); - val = default_pt(1); - wxString Y = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); + double val = default_pt(0); + wxString X = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); + val = default_pt(1); + wxString Y = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); - long style = wxTE_PROCESS_ENTER; + long style = wxTE_PROCESS_ENTER; #ifdef _WIN32 - style |= wxBORDER_SIMPLE; + style |= wxBORDER_SIMPLE; #endif - x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, style); - y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, style); + x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, style); + y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, style); if (parent_is_custom_ctrl && m_opt.height < 0) opt_height = (double)x_textctrl->GetSize().GetHeight() / m_em_unit; x_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - x_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); - y_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - y_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); - - auto static_text_x = new wxStaticText(m_parent, wxID_ANY, "x : "); - auto static_text_y = new wxStaticText(m_parent, wxID_ANY, " y : "); - static_text_x->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - static_text_x->SetBackgroundStyle(wxBG_STYLE_PAINT); - static_text_y->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - static_text_y->SetBackgroundStyle(wxBG_STYLE_PAINT); - - wxGetApp().UpdateDarkUI(x_textctrl); - wxGetApp().UpdateDarkUI(y_textctrl); - wxGetApp().UpdateDarkUI(static_text_x, false, true); - wxGetApp().UpdateDarkUI(static_text_y, false, true); - - temp->Add(static_text_x, 0, wxALIGN_CENTER_VERTICAL, 0); - temp->Add(x_textctrl); - temp->Add(static_text_y, 0, wxALIGN_CENTER_VERTICAL, 0); - temp->Add(y_textctrl); + x_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); + y_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + y_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); + + auto static_text_x = new wxStaticText(m_parent, wxID_ANY, "x : "); + auto static_text_y = new wxStaticText(m_parent, wxID_ANY, " y : "); + static_text_x->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + static_text_x->SetBackgroundStyle(wxBG_STYLE_PAINT); + static_text_y->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + static_text_y->SetBackgroundStyle(wxBG_STYLE_PAINT); + + wxGetApp().UpdateDarkUI(x_textctrl); + wxGetApp().UpdateDarkUI(y_textctrl); + wxGetApp().UpdateDarkUI(static_text_x, false, true); + wxGetApp().UpdateDarkUI(static_text_y, false, true); + + temp->Add(static_text_x, 0, wxALIGN_CENTER_VERTICAL, 0); + temp->Add(x_textctrl); + temp->Add(static_text_y, 0, wxALIGN_CENTER_VERTICAL, 0); + temp->Add(y_textctrl); x_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(x_textctrl); }), x_textctrl->GetId()); - y_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(y_textctrl); }), y_textctrl->GetId()); + y_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(y_textctrl); }), y_textctrl->GetId()); x_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); propagate_value(x_textctrl); }), x_textctrl->GetId()); y_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); propagate_value(y_textctrl); }), y_textctrl->GetId()); - // // recast as a wxWindow to fit the calling convention - sizer = dynamic_cast(temp); + // // recast as a wxWindow to fit the calling convention + sizer = dynamic_cast(temp); this->set_tooltip(X + ", " + Y, x_textctrl); this->set_tooltip(X + ", " + Y, y_textctrl); @@ -2300,34 +2302,34 @@ void PointCtrl::sys_color_changed() bool PointCtrl::value_was_changed(wxTextCtrl* win) { - if (m_value.empty()) - return true; + if (m_value.empty()) + return true; - boost::any val = m_value; - // update m_value! - get_value(); + boost::any val = m_value; + // update m_value! + get_value(); - return boost::any_cast(m_value) != boost::any_cast(val); + return boost::any_cast(m_value) != boost::any_cast(val); } void PointCtrl::propagate_value(wxTextCtrl* win) { if (win->GetValue().empty()) on_kill_focus(); - else if (value_was_changed(win)) + else if (value_was_changed(win)) on_change_field(); } void PointCtrl::set_vec2d_value(const Vec2d& value, bool change_event) { - m_disable_change_event = !change_event; + m_disable_change_event = !change_event; - double val = value(0); - x_textctrl->SetValue(val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None)); - val = value(1); - y_textctrl->SetValue(val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None)); + double val = value(0); + x_textctrl->SetValue(val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None)); + val = value(1); + y_textctrl->SetValue(val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None)); - m_disable_change_event = false; + m_disable_change_event = false; } void PointCtrl::set_any_value(const boost::any &value, bool change_event) @@ -2335,50 +2337,50 @@ void PointCtrl::set_any_value(const boost::any &value, bool change_event) // can be coPoint and coPoints (with idx) assert(m_opt.type == coPoint || (m_opt.type == coPoints && m_opt_idx >= 0)); Vec2d pt = boost::any_cast(value); - set_vec2d_value(pt, change_event); + set_vec2d_value(pt, change_event); } boost::any& PointCtrl::get_value() { - double x, y; - if (!x_textctrl->GetValue().ToDouble(&x) || - !y_textctrl->GetValue().ToDouble(&y)) - { + double x, y; + if (!x_textctrl->GetValue().ToDouble(&x) || + !y_textctrl->GetValue().ToDouble(&y)) + { set_any_value(m_value.empty() ? Vec2d(0.0, 0.0) : m_value, true); show_error(m_parent, _L("Invalid numeric input.")); - } - else - if (m_opt.min > x || x > m_opt.max || - m_opt.min > y || y > m_opt.max) - { - if (m_opt.min > x) x = m_opt.min; - if (x > m_opt.max) x = m_opt.max; - if (m_opt.min > y) y = m_opt.min; - if (y > m_opt.max) y = m_opt.max; - set_vec2d_value(Vec2d(x, y), true); + } + else + if (m_opt.min > x || x > m_opt.max || + m_opt.min > y || y > m_opt.max) + { + if (m_opt.min > x) x = m_opt.min; + if (x > m_opt.max) x = m_opt.max; + if (m_opt.min > y) y = m_opt.min; + if (y > m_opt.max) y = m_opt.max; + set_vec2d_value(Vec2d(x, y), true); - show_error(m_parent, _L("Input value is out of range")); - } + show_error(m_parent, _L("Input value is out of range")); + } - return m_value = Vec2d(x, y); + return m_value = Vec2d(x, y); } void StaticText::BUILD() { - auto size = wxSize(wxDefaultSize); + auto size = wxSize(wxDefaultSize); if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit); if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); const wxString legend = from_u8(m_opt.get_default_value()->value); auto temp = new wxStaticText(m_parent, wxID_ANY, legend, wxDefaultPosition, size, wxST_ELLIPSIZE_MIDDLE); - temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + temp->SetBackgroundStyle(wxBG_STYLE_PAINT); temp->SetFont(wxGetApp().bold_font()); - wxGetApp().UpdateDarkUI(temp); + wxGetApp().UpdateDarkUI(temp); - // // recast as a wxWindow to fit the calling convention - window = dynamic_cast(temp); + // // recast as a wxWindow to fit the calling convention + window = dynamic_cast(temp); this->set_tooltip(legend); } @@ -2401,57 +2403,57 @@ void StaticText::msw_rescale() void SliderCtrl::BUILD() { - auto size = wxSize(wxDefaultSize); - if (m_opt.height >= 0) size.SetHeight(m_opt.height); - if (m_opt.width >= 0) size.SetWidth(m_opt.width); + auto size = wxSize(wxDefaultSize); + if (m_opt.height >= 0) size.SetHeight(m_opt.height); + if (m_opt.width >= 0) size.SetWidth(m_opt.width); - auto temp = new wxBoxSizer(wxHORIZONTAL); + auto temp = new wxBoxSizer(wxHORIZONTAL); - int def_val = m_opt.get_default_value()->value; + int def_val = m_opt.get_default_value()->value; int min = m_opt.min == INT_MIN ? 0 : int(m_opt.min); int max = m_opt.max == INT_MAX ? 100 : int(m_opt.max); - m_slider = new wxSlider(m_parent, wxID_ANY, def_val * m_scale, - min * m_scale, max * m_scale, - wxDefaultPosition, size); - m_slider->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - m_slider->SetBackgroundStyle(wxBG_STYLE_PAINT); - wxSize field_size(40, -1); - - m_textctrl = new wxTextCtrl(m_parent, wxID_ANY, wxString::Format("%d", m_slider->GetValue()/m_scale), - wxDefaultPosition, field_size); - m_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - m_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); - - temp->Add(m_slider, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL, 0); - temp->Add(m_textctrl, 0, wxALIGN_CENTER_VERTICAL, 0); - - m_slider->Bind(wxEVT_SLIDER, ([this](wxCommandEvent e) { - if (!m_disable_change_event) { - int val = boost::any_cast(get_value()); - m_textctrl->SetLabel(wxString::Format("%d", val)); - on_change_field(); - } - }), m_slider->GetId()); - - m_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { - std::string value = e.GetString().utf8_str().data(); - if (is_matched(value, "^-?\\d+(\\.\\d*)?$")) { - m_disable_change_event = true; - m_slider->SetValue(stoi(value)*m_scale); - m_disable_change_event = false; - on_change_field(); - } - }), m_textctrl->GetId()); - - m_sizer = dynamic_cast(temp); + m_slider = new wxSlider(m_parent, wxID_ANY, def_val * m_scale, + min * m_scale, max * m_scale, + wxDefaultPosition, size); + m_slider->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + m_slider->SetBackgroundStyle(wxBG_STYLE_PAINT); + wxSize field_size(40, -1); + + m_textctrl = new wxTextCtrl(m_parent, wxID_ANY, wxString::Format("%d", m_slider->GetValue()/m_scale), + wxDefaultPosition, field_size); + m_textctrl->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + m_textctrl->SetBackgroundStyle(wxBG_STYLE_PAINT); + + temp->Add(m_slider, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL, 0); + temp->Add(m_textctrl, 0, wxALIGN_CENTER_VERTICAL, 0); + + m_slider->Bind(wxEVT_SLIDER, ([this](wxCommandEvent e) { + if (!m_disable_change_event) { + int val = boost::any_cast(get_value()); + m_textctrl->SetLabel(wxString::Format("%d", val)); + on_change_field(); + } + }), m_slider->GetId()); + + m_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { + std::string value = e.GetString().utf8_str().data(); + if (is_matched(value, "^-?\\d+(\\.\\d*)?$")) { + m_disable_change_event = true; + m_slider->SetValue(stoi(value)*m_scale); + m_disable_change_event = false; + on_change_field(); + } + }), m_textctrl->GetId()); + + m_sizer = dynamic_cast(temp); } void SliderCtrl::set_any_value(const boost::any &value, bool change_event) { // only with ConfigOptionDef::GUIType::slider: & coFloat or coInt assert(m_opt.gui_type == ConfigOptionDef::GUIType::slider && (m_opt.type == coFloat || m_opt.type == coInt)); - m_disable_change_event = !change_event; + m_disable_change_event = !change_event; if (m_opt.type == coFloat) { m_slider->SetValue(boost::any_cast(value) * m_scale); double val = boost::any_cast(get_value()); @@ -2462,13 +2464,13 @@ void SliderCtrl::set_any_value(const boost::any &value, bool change_event) m_textctrl->SetLabel(wxString::Format("%d", val)); } - m_disable_change_event = false; + m_disable_change_event = false; } boost::any &SliderCtrl::get_value() { - // int ret_val; - // x_textctrl->GetValue().ToDouble(&val); + // int ret_val; + // x_textctrl->GetValue().ToDouble(&val); if (m_opt.type == coFloat) { return m_value = double(m_slider->GetValue() / m_scale); } else if (m_opt.type == coInt) { diff --git a/src/slic3r/GUI/FreeCADDialog.cpp b/src/slic3r/GUI/FreeCADDialog.cpp index ae97c3dd4f7..c1a7aa47543 100644 --- a/src/slic3r/GUI/FreeCADDialog.cpp +++ b/src/slic3r/GUI/FreeCADDialog.cpp @@ -333,8 +333,7 @@ bool FreeCADDialog::load_text_from_file(const boost::filesystem::path &path) { in.read(result.data(), sz); m_text->SetTextRaw(result.c_str()); in.close(); - } - catch (std::exception ex) { + } catch (std::exception& ex) { //TODO: emit error meessage on std / boost return false; } @@ -375,7 +374,7 @@ bool FreeCADDialog::write_text_in_file(const wxString &towrite, const boost::fil out << towrite; out.close(); } - catch (std::exception ex) { + catch (std::exception& ex) { return false; } return true; @@ -773,7 +772,7 @@ void FreeCADDialog::test_update_script_file(std::string &json) { get_file_from_web("https://raw.githubusercontent.com/supermerill/FreePySCAD/master/freepyscad.py", pyscad_path / "freepyscad.py"); } } - catch (std::exception ex) { + catch (std::exception& ex) { BOOST_LOG_TRIVIAL(error) << "Error, cannot parse https://api.github.com/repos/supermerill/FreePySCAD/commits/master: " << ex.what(); } } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1af0500a64d..c91c63cff7e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3298,7 +3298,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (!m_hover_volume_idxs.empty()) { if (evt.LeftDown() && m_moving_enabled && m_mouse.drag.move_volume_idx == -1) { // Only accept the initial position, if it is inside the volume bounding box. - int volume_idx = get_first_hover_volume_idx(); + size_t volume_idx = get_first_hover_volume_idx(); if (m_volumes.volumes.size() > volume_idx) { //can fail if the screen takes a bit of time to refresh BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box(); volume_bbox.offset(1.0); @@ -4217,16 +4217,17 @@ bool GLCanvas3D::_render_arrange_menu(float pos_x) if (imgui->slider_float(_L("Spacing"), &settings.distance, dist_min, 100.0f, "%5.2f") || dist_min > settings.distance) { if (dist_min > settings.distance) { const ConfigOptionFloat* dd_opt = this->m_config->option("duplicate_distance"); - if (dd_opt) - if (dd_opt->value == 0) + if (dd_opt) { + if (dd_opt->value == 0) { settings_out.distance = settings.previously_used_distance; - else + } else { settings.distance = dist_min + dd_opt->value; + } + } } settings_out.distance = settings.distance; settings_changed = true; } - if (imgui->checkbox(_L("Enable rotations (slow)"), settings.enable_rotation)) { settings_out.enable_rotation = settings.enable_rotation; settings_changed = true; @@ -4237,15 +4238,16 @@ bool GLCanvas3D::_render_arrange_menu(float pos_x) if (imgui->button(_L("Reset"))) { settings_out = ArrangeSettings{}; const ConfigOptionFloat* dd_opt = this->m_config->option("duplicate_distance"); - if (dd_opt) - if (dd_opt->value == 0) + if (dd_opt) { + if (dd_opt->value == 0) { settings_out.distance = settings.previously_used_distance; - else + } else { settings_out.distance = dist_min + dd_opt->value; + } + } settings_out.distance = std::max(dist_min, settings_out.distance); settings_changed = true; } - ImGui::SameLine(); if (imgui->button(_L("Arrange"))) { diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 74a01993080..ada692a8803 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -1172,16 +1172,45 @@ void MenuFactory::append_menu_items_instance_manipulation(wxMenu* menu) } +// void MenuFactory::update_menu_items_instance_manipulation(MenuType type) +// { +// wxMenu* menu = type == mtObjectFFF ? &m_object_menu : type == mtObjectSLA ? &m_sla_object_menu : nullptr; +// if (menu) +// return; +// // Remove/Prepend "increase/decrease instances" menu items according to the view mode. +// // Suppress to show those items for a Simple mode +// if (wxGetApp().get_mode() == comSimple) { +// if (menu->FindItem(_L("Add instance")) != wxNOT_FOUND) +// { +// // Detach an items from the menu, but don't delete them +// // so that they can be added back later +// // (after switching to the Advanced/Expert mode) +// menu->Remove(items_increase[type]); +// menu->Remove(items_decrease[type]); +// menu->Remove(items_set_number_of_copies[type]); +// } +// } +// else { +// if (menu->FindItem(_L("Add instance")) == wxNOT_FOUND) +// { +// // Prepend items to the menu, if those aren't not there +// menu->Prepend(items_set_number_of_copies[type]); +// menu->Prepend(items_decrease[type]); +// menu->Prepend(items_increase[type]); +// } +// } +// } + void MenuFactory::update_menu_items_instance_manipulation(MenuType type) { wxMenu* menu = type == mtObjectFFF ? &m_object_menu : type == mtObjectSLA ? &m_sla_object_menu : nullptr; - if (menu) + if (!menu) // Check if the menu is null return; + // Remove/Prepend "increase/decrease instances" menu items according to the view mode. // Suppress to show those items for a Simple mode if (wxGetApp().get_mode() == comSimple) { - if (menu->FindItem(_L("Add instance")) != wxNOT_FOUND) - { + if (menu->FindItem(_L("Add instance")) != wxNOT_FOUND) { // Detach an items from the menu, but don't delete them // so that they can be added back later // (after switching to the Advanced/Expert mode) @@ -1189,11 +1218,9 @@ void MenuFactory::update_menu_items_instance_manipulation(MenuType type) menu->Remove(items_decrease[type]); menu->Remove(items_set_number_of_copies[type]); } - } - else { - if (menu->FindItem(_L("Add instance")) == wxNOT_FOUND) - { - // Prepend items to the menu, if those aren't not there + } else { + if (menu->FindItem(_L("Add instance")) == wxNOT_FOUND) { + // Prepend items to the menu, if those aren't there menu->Prepend(items_set_number_of_copies[type]); menu->Prepend(items_decrease[type]); menu->Prepend(items_increase[type]); @@ -1201,6 +1228,7 @@ void MenuFactory::update_menu_items_instance_manipulation(MenuType type) } } + void MenuFactory::update_object_menu() { append_menu_items_add_volume(&m_object_menu); diff --git a/src/slic3r/GUI/GalleryDialog.cpp b/src/slic3r/GUI/GalleryDialog.cpp index 59ba45d941f..5b9aa29f012 100644 --- a/src/slic3r/GUI/GalleryDialog.cpp +++ b/src/slic3r/GUI/GalleryDialog.cpp @@ -486,8 +486,8 @@ void GalleryDialog::change_thumbnail() void GalleryDialog::select(wxListEvent& event) { - int idx = event.GetIndex(); - Item item { into_u8(m_list_ctrl->GetItemText(idx)), idx < m_sys_item_count }; + long idx = event.GetIndex(); + Item item { into_u8(m_list_ctrl->GetItemText(idx)), static_cast(idx) < m_sys_item_count }; m_selected_items.push_back(item); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 8e319ba3925..f7382055f41 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -126,7 +126,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l float caption_max = 0.f; float total_text_max = 0.f; - for (const std::string& t : {"enforce", "block", "remove"}) { + for (const std::string& t : {std::string("enforce"), std::string("block"), std::string("remove")}) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } @@ -150,7 +150,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l m_imgui->text(text); }; - for (const std::string& t : {"enforce", "block", "remove"}) + for (const std::string& t : {std::string("enforce"), std::string("block"), std::string("remove")}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); ImGui::Separator(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 5927d886e70..bedf7877d72 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -305,7 +305,11 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott float caption_max = 0.f; float total_text_max = 0.f; - for (const std::string& t : {"first_color", "second_color", "remove"}) { + const std::string first_color_str = "first_color"; + const std::string second_color_str = "second_color"; + const std::string remove_str = "remove"; + + for (const std::string& t : {first_color_str, second_color_str, remove_str}) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } @@ -328,7 +332,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(text); }; - for (const std::string& t : {"first_color", "second_color", "remove"}) + for (const std::string& t : {first_color_str, second_color_str, remove_str}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); ImGui::Separator(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index dbf2aeb25dd..eda9e785b39 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -99,7 +99,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) float caption_max = 0.f; float total_text_max = 0.f; - for (const std::string& t : {"enforce", "block", "remove"}) { + const std::string enforce = "enforce"; + const std::string block = "block"; + const std::string remove = "remove"; + for (const std::string& t : {enforce, block, remove}) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } @@ -120,7 +123,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) m_imgui->text(text); }; - for(const std::string& t : {"enforce", "block", "remove"}) + for (const std::string& t : {enforce, block, remove}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); ImGui::Separator(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 5a96894850b..31564824ced 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -294,12 +294,12 @@ void MainFrame::update_icon() { #ifndef _USE_CUSTOM_NOTEBOOK // icons for ESettingsLayout::Hidden - wxImageList* img_list = nullptr; + int icon_size = 0; try { icon_size = atoi(wxGetApp().app_config->get("tab_icon_size").c_str()); } - catch (std::exception e) {} + catch (const std::exception& e) {} switch (m_layout) { case ESettingsLayout::Unknown: @@ -509,7 +509,7 @@ void MainFrame::update_layout() if (m_plater->GetParent() != this) m_plater->Reparent(this); #ifndef _USE_CUSTOM_NOTEBOOK - for (int i = 0; i < m_tabpanel->GetPageCount(); i++) { + for (size_t i = 0; i < m_tabpanel->GetPageCount(); i++) { m_tabpanel->SetPageImage(i, -1); } m_tabpanel->SetImageList(nullptr); //clear @@ -538,7 +538,7 @@ void MainFrame::update_layout() } #else //clear if previous was tabs - for (int i = 0; i < m_tabpanel->GetPageCount() - 3; i++) + for (size_t i = 0; i < m_tabpanel->GetPageCount() - 3; i++) if (m_tabpanel->GetPage(i)->GetChildren().empty() && m_tabpanel->GetPage(i)->GetSizer()->GetItemCount() > 0) { clean_sizer(m_tabpanel->GetPage(i)->GetSizer()); } @@ -931,7 +931,7 @@ void MainFrame::change_tab(Tab* old_tab, Tab* new_tab) else #endif { - int page_id = m_tabpanel->FindPage(old_tab); + size_t page_id = m_tabpanel->FindPage(old_tab); if (page_id >= 0 && page_id < m_tabpanel->GetPageCount()) { m_tabpanel->GetPage(page_id)->Show(false); m_tabpanel->RemovePage(page_id); @@ -1014,7 +1014,7 @@ void MainFrame::init_tabpanel() try { icon_size = atoi(wxGetApp().app_config->get("tab_icon_size").c_str()); } - catch (std::exception e) {} + catch (const std::exception& e) {} // icons for m_tabpanel tabs wxImageList* img_list = nullptr; if (icon_size >= 8) { @@ -1054,15 +1054,15 @@ void MainFrame::init_tabpanel() std::vector& tabs_list = wxGetApp().tabs_list; int last_selected_plater_tab = m_last_selected_plater_tab; - int last_selected_setting_tab = m_last_selected_setting_tab; if (tab && std::find(tabs_list.begin(), tabs_list.end(), tab) != tabs_list.end()) { // On GTK, the wxEVT_NOTEBOOK_PAGE_CHANGED event is triggered // before the MainFrame is fully set up. tab->OnActivate(); - if (this->m_layout == ESettingsLayout::Dlg) - last_selected_setting_tab = m_tabpanel->GetSelection(); - else - last_selected_setting_tab = m_tabpanel->GetSelection() - 1; + m_tabpanel->GetSelection(); + // if (this->m_layout == ESettingsLayout::Dlg) + // m_tabpanel->GetSelection(); + // else + // m_tabpanel->GetSelection() - 1; } else if (this->m_layout == ESettingsLayout::Tabs) { #ifdef _USE_CUSTOM_NOTEBOOK int bt_idx_sel = 0; @@ -1109,7 +1109,6 @@ void MainFrame::init_tabpanel() #ifdef __APPLE__ BOOST_LOG_TRIVIAL(debug) << "I switched to tab " << m_tabpanel->GetSelection() << " and so i need to change the panel position & content\n"; #endif - size_t new_tab = m_tabpanel->GetSelection(); size_t max = 0; for (int i = 0; i < 3; i++) @@ -2480,7 +2479,11 @@ void MainFrame::select_tab(Tab* tab) case Preset::Type::TYPE_PRINTER: tab_type = ETabType::PrinterSettings; break; + default: { + break; + } } + select_tab(tab_type); } diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index 034eaa58901..4a71091c0e9 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -28,16 +28,16 @@ static wxSize get_bitmap_size(const wxBitmap& bmp) #endif } -static wxString get_url(const wxString& path_end, bool get_default = false) -{ - if (path_end.IsEmpty()) - return wxEmptyString; +// static wxString get_url(const wxString& path_end, bool get_default = false) +// { +// if (path_end.IsEmpty()) +// return wxEmptyString; - wxString language = wxGetApp().app_config->get("translation_language"); - wxString lang_marker = language.IsEmpty() ? "en" : language.BeforeFirst('_'); +// wxString language = wxGetApp().app_config->get("translation_language"); +// wxString lang_marker = language.IsEmpty() ? "en" : language.BeforeFirst('_'); - return wxString("https://help.prusa3d.com/") + lang_marker + "/article/" + path_end; -} +// return wxString("https://help.prusa3d.com/") + lang_marker + "/article/" + path_end; +// } int OG_CustomCtrl::m_has_icon = (-1); @@ -131,14 +131,14 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) line_height = win_height; }; - auto correct_horiz_pos = [this](int& h_pos, Field* field) { - if (m_max_win_width > 0 && field->getWindow()) { - int win_width = field->getWindow()->GetSize().GetWidth(); - if (dynamic_cast(field)) - win_width *= 0.5; - h_pos += m_max_win_width - win_width; - } - }; + // auto correct_horiz_pos = [this](int& h_pos, Field* field) { + // if (m_max_win_width > 0 && field->getWindow()) { + // int win_width = field->getWindow()->GetSize().GetWidth(); + // if (dynamic_cast(field)) + // win_width *= 0.5; + // h_pos += m_max_win_width - win_width; + // } + // }; for (CtrlLine& ctrl_line : ctrl_lines) { if (&ctrl_line.og_line == &line) @@ -793,7 +793,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_mode_bmp(wxDC& dc, wxCoord v_pos) ConfigOptionMode mode = og_line.get_options()[0].opt.mode; //get the easiest setting - for (int i = 1; i < og_line.get_options().size(); i++) + for (size_t i = 1; i < og_line.get_options().size(); i++) mode |= og_line.get_options()[i].opt.mode; std::string bmp_name = "mode_other"; if ((mode & ConfigOptionMode::comSimple) != 0) diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index dcde96ca493..99ce6e988f3 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -420,12 +420,13 @@ void OptionsGroup::activate_line(Line& line) // add sidetext if any if ((!option.sidetext.empty() || sidetext_width > 0) && option.sidetext_width != 0){ wxString textstring; - if(!option.sidetext.empty()) + if (!option.sidetext.empty()) { if (option.sidetext.at(option.sidetext.size() - 1) != '_') { textstring = _(option.sidetext); } else { textstring = option.sidetext.substr(0, option.sidetext.size() - 1); } + } wxSize wxsize{ -1,-1 }; if (option.sidetext_width >= 0) { if (option.sidetext_width != 0) @@ -785,7 +786,7 @@ void ConfigOptionsGroup::reload_config() const std::string &opt_key = kvp.second.first; // index in the vector option, zero for scalars int opt_index = kvp.second.second; - const ConfigOptionDef &option = m_options.at(opt_id).opt; + m_options.at(opt_id).opt; this->set_value(opt_id, m_config->option(opt_key)->get_any(opt_index)); } update_script_presets(); @@ -832,7 +833,7 @@ bool ConfigOptionsGroup::is_visible(ConfigOptionMode mode) return get_invisible_idx(m_options_mode[0], mode).empty(); size_t hidden_row_cnt = 0; - for (size_t i = 0; i < opt_mode_size; i++) { + for (size_t i = 0; i < static_cast(opt_mode_size); i++){ if ((m_options_mode[i].size() == 1 && m_options_mode[i].begin()->second.size() == 1 && m_options_mode[i].begin()->second[0] == (size_t)-1 @@ -842,7 +843,7 @@ bool ConfigOptionsGroup::is_visible(ConfigOptionMode mode) } } - return hidden_row_cnt != opt_mode_size; + return hidden_row_cnt != static_cast(opt_mode_size); } bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) @@ -874,7 +875,7 @@ bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) && (m_options_mode[i].begin()->first != comNone && (m_options_mode[i].begin()->first & mode) != mode)) || get_visible_idx(m_options_mode[i], mode).empty()) { hidden_row_cnt++; - for (size_t idx =0; idx < cols; idx++) + for (size_t idx = 0; idx < static_cast(cols); idx++) m_grid_sizer->Show(idx_item + idx, false); }else for (size_t idx : get_invisible_idx(m_options_mode[i], mode)) diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 7ca307ff9da..f96a0aefe01 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -297,7 +297,7 @@ void PhysicalPrinterDialog::update_printers() rs->disable(); } else { std::vector slugs; - for (int i = 0; i < printers.size(); i++) { + for (size_t i = 0; i < printers.size(); i++) { slugs.push_back(printers[i].ToStdString()); } @@ -314,7 +314,7 @@ void PhysicalPrinterDialog::update_printers() } rs->enable(); } - } catch (HostNetworkError error) { + } catch (const HostNetworkError& error) { show_error(this, error.what()); } } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 3eed33cb041..741039da4d3 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -508,7 +508,6 @@ void FreqChangedParams::init() PageShp page = tab_freq_sla->get_page(0); m_og_sla->copy_for_freq_settings(*(page->m_optgroups[0].get())); // hacks - Line *line_for_purge = nullptr; for (Line &l : page->m_optgroups[0]->set_lines()) { if (l.get_options().size() == 1 && l.get_options().front().opt.full_width) { l.append_widget(empty_widget); @@ -5916,7 +5915,7 @@ void Plater::export_gcode(bool prefer_removable) if (printer_technology() == ptFFF) { const ConfigOptionStrings* filaments = fff_print().full_print_config().opt("filament_settings_id"); assert(filaments->size() == fff_print().config().filament_type.size()); - for (int i = 0; i < filaments->size(); i++) { + for (size_t i = 0; i < filaments->size(); i++) { str_material += "\n" + format(_L("'%1%' of type %2%"), filaments->get_at(i), fff_print().config().filament_type.get_at(i)); } } else if (printer_technology() == ptSLA) { @@ -6187,7 +6186,7 @@ void Plater::export_platter() p->view3D->get_canvas3d()->render_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, thumbnail_params, collection, Camera::EType::Ortho); //store 3mf - bool ret = Slic3r::store_3mf(path_u8.c_str(), + Slic3r::store_3mf(path_u8.c_str(), &model_to_save, &full_config, OptionStore3mf{} @@ -6198,7 +6197,7 @@ void Plater::export_platter() ); } else if (dlg.GetFilterIndex() == 2) { //store amf - bool ret = Slic3r::store_amf(path_u8, + Slic3r::store_amf(path_u8, &model_to_save, &full_config, OptionStoreAmf{} diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 5a0f25b9b55..d6397430059 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -639,19 +639,24 @@ void PlaterPresetComboBox::OnSelect(wxCommandEvent &evt) if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) { this->SetSelection(m_last_selected); evt.StopPropagation(); - if (marker == LABEL_ITEM_MARKER) + if (marker == LABEL_ITEM_MARKER) { return; - if (marker == LABEL_ITEM_WIZARD_PRINTERS) - show_add_menu(); - else { - ConfigWizard::StartPage sp = ConfigWizard::SP_WELCOME; - switch (marker) { - case LABEL_ITEM_WIZARD_FILAMENTS: sp = ConfigWizard::SP_FILAMENTS; break; - case LABEL_ITEM_WIZARD_MATERIALS: sp = ConfigWizard::SP_MATERIALS; break; - default: break; - } - wxTheApp->CallAfter([sp]() { run_wizard(sp); }); + } else if (marker == LABEL_ITEM_WIZARD_PRINTERS) { + show_add_menu(); + } else { + ConfigWizard::StartPage sp = ConfigWizard::SP_WELCOME; + switch (marker) { + case LABEL_ITEM_WIZARD_FILAMENTS: + sp = ConfigWizard::SP_FILAMENTS; + break; + case LABEL_ITEM_WIZARD_MATERIALS: + sp = ConfigWizard::SP_MATERIALS; + break; + default: + break; } + wxTheApp->CallAfter([sp]() { run_wizard(sp); }); + } return; } else if (marker == LABEL_ITEM_PHYSICAL_PRINTER || m_last_selected != selected_item || m_collection->current_is_dirty()) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 04fb2482565..f8a4fcd31e9 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -156,7 +156,7 @@ Tab::Tab(wxBookCtrlBase* parent, const wxString& title, Preset::Type type) : try { m_script_exec.init(tab_key, this); } - catch (script::ScriptError ex) { + catch (const script::ScriptError& ex) { m_script_exec.disable(); BOOST_LOG_TRIVIAL(error) << format("An error has occured when compiling %1%/%2%.as ; The scripted widgets for this tab won't be built.", Slic3r::GUI::get_app_config()->layout_config_path().string(), tab_key); } @@ -591,8 +591,6 @@ void Tab::update_label_colours() //update options "decoration" for (const auto &opt : m_options_list) { - const std::string &opt_key = opt.first; - const int & opt_idx = opt.second.first; const int & opt_status = opt.second.second; const wxColour *color = &m_sys_label_clr; @@ -1320,23 +1318,23 @@ bool Tab::set_value(const t_config_option_key& opt_key, const boost::any& value) return changed; } -static wxString support_combo_value_for_config(const DynamicPrintConfig &config, bool is_fff) -{ - const std::string support = is_fff ? "support_material" : "supports_enable"; - const std::string buildplate_only = is_fff ? "support_material_buildplate_only" : "support_buildplate_only"; - return - ! config.opt_bool(support) ? - _("None") : - (is_fff && !config.opt_bool("support_material_auto")) ? - _("For support enforcers only") : - (config.opt_bool(buildplate_only) ? _("Support on build plate only") : - _("Everywhere")); -} - -static wxString pad_combo_value_for_config(const DynamicPrintConfig &config) -{ - return config.opt_bool("pad_enable") ? (config.opt_bool("pad_around_object") ? _("Around object") : _("Below object")) : _("None"); -} +// static wxString support_combo_value_for_config(const DynamicPrintConfig &config, bool is_fff) +// { +// const std::string support = is_fff ? "support_material" : "supports_enable"; +// const std::string buildplate_only = is_fff ? "support_material_buildplate_only" : "support_buildplate_only"; +// return +// ! config.opt_bool(support) ? +// _("None") : +// (is_fff && !config.opt_bool("support_material_auto")) ? +// _("For support enforcers only") : +// (config.opt_bool(buildplate_only) ? _("Support on build plate only") : +// _("Everywhere")); +// } + +// static wxString pad_combo_value_for_config(const DynamicPrintConfig &config) +// { +// return config.opt_bool("pad_enable") ? (config.opt_bool("pad_around_object") ? _("Around object") : _("Below object")) : _("None"); +// } void Tab::on_value_change(const std::string& opt_key, const boost::any& value) { @@ -1759,7 +1757,6 @@ std::vector Tab::create_pages(std::string setting_type_nam type_override = this->type(); } - bool no_page_yet = true; #ifdef __WXMSW__ /* Workaround for correct layout of controls inside the created page: * In some _strange_ way we should we should imitate page resizing. @@ -1799,7 +1796,6 @@ std::vector Tab::create_pages(std::string setting_type_nam // if(!no_page_yet) // layout_page(current_page); #endif - no_page_yet = false; if (in_line) { current_group->append_line(current_line); if (logs) Slic3r::slic3r_log->info("settings gui") << "add line\n"; @@ -1818,7 +1814,7 @@ std::vector Tab::create_pages(std::string setting_type_nam wxString label = _(params[params.size()-2]); - for (int i = 1; i < params.size() - 1; i++) { + for (size_t i = 1; i < params.size() - 1; i++) { if (params[i] == "idx") { label = label + " " + std::to_string(int(idx_page + 1)); @@ -1854,7 +1850,7 @@ std::vector Tab::create_pages(std::string setting_type_nam } bool no_title = false; bool no_search = false; - for (int i = 1; i < params.size() - 1; i++) { + for (size_t i = 1; i < params.size() - 1; i++) { if (params[i] == "nolabel") { no_title = true; @@ -1867,7 +1863,7 @@ std::vector Tab::create_pages(std::string setting_type_nam } current_group = current_page->new_optgroup(_(params.back()), no_title, !no_search, type_override); - for (int i = 1; i < params.size() - 1; i++) { + for (size_t i = 1; i < params.size() - 1; i++) { if (boost::starts_with(params[i], "title_width$")) { current_group->title_width = atoi(params[i].substr(strlen("title_width$")).c_str()); } @@ -2025,7 +2021,7 @@ std::vector Tab::create_pages(std::string setting_type_nam } current_line = { _L(params.empty()?"":params.back().c_str()), wxString{""} }; - for (int i = 1; i < params.size() - 1; i++) { + for (size_t i = 1; i < params.size() - 1; i++) { if (boost::starts_with(params[i], "url$")) { // only on line current_line.label_path = params[i].substr(strlen("url$")); } @@ -2066,7 +2062,7 @@ std::vector Tab::create_pages(std::string setting_type_nam } int id = -1; - for (int i = 1; i < params.size() - 1; i++) { + for (size_t i = 1; i < params.size() - 1; i++) { if (boost::starts_with(params[i], "id$")) id = atoi(params[i].substr(strlen("id$")).c_str()); else if (params[i] == "idx") @@ -2120,11 +2116,9 @@ std::vector Tab::create_pages(std::string setting_type_nam } }; - bool need_to_notified_search = false; bool colored = false; - bool custom_label = false; std::string label_path; - for (int i = 1; i < params.size() - 1; i++) { + for (size_t i = 1; i < params.size() - 1; i++) { if (params[i] == "simple") { option.opt.mode = ConfigOptionMode::comSimpleAE; @@ -2157,12 +2151,10 @@ std::vector Tab::create_pages(std::string setting_type_nam else if (params[i] == "full_label$") { option.opt.full_label = (params[i].substr(strlen("full_label$"))); - need_to_notified_search = true; } else if (params[i] == "full_label") { option.opt.label = option.opt.full_label; - need_to_notified_search = true; } else if (boost::starts_with(params[i], "label$")) { @@ -2172,7 +2164,6 @@ std::vector Tab::create_pages(std::string setting_type_nam option.opt.label = (params[i].substr(strlen("label$"))); if (is_script && option.opt.full_label.empty()) option.opt.full_label = option.opt.label; - need_to_notified_search = true; } else if (boost::starts_with(params[i], "label_width$")) { option.opt.label_width = atoi(params[i].substr(strlen("label_width$")).c_str()); @@ -2216,7 +2207,6 @@ std::vector Tab::create_pages(std::string setting_type_nam boost::replace_all(option.opt.tooltip, "\\t", "\t"); boost::replace_all(option.opt.tooltip, "\\.", ":"); boost::replace_all(option.opt.tooltip, "\\£", "$"); - need_to_notified_search = true; } else if (boost::starts_with(params[i], "max_literal$")) { @@ -2361,7 +2351,7 @@ std::vector Tab::create_pages(std::string setting_type_nam DynamicPrintConfig new_conf = *m_config; if (dialog.ShowModal() == wxID_YES) { for (size_t i = 0; i < nozzle_diameters.size(); i++) { - if (i == idx_page) + if (i == static_cast(idx_page)) continue; nozzle_diameters[i] = new_nd; } @@ -3409,8 +3399,7 @@ void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/) { size_t n_before_extruders = m_unregular_page_pos; // Count of pages before Extruder pages bool changed = false; - GCodeFlavor flavor = m_config->option>("gcode_flavor")->value; - + /* ! Freeze/Thaw in this function is needed to avoid call OnPaint() for erased pages * and be cause of application crash, when try to change Preset in moment, * when one of unregular pages is selected. @@ -3650,9 +3639,8 @@ void TabPrinter::toggle_options() int64_t z_step_Mlong = (int64_t)(z_step * 1000000.); DynamicPrintConfig new_conf; bool has_changed = false; - const std::vector& nozzle_diameters = m_config->option("nozzle_diameter")->get_values(); const std::vector& min_layer_height = m_config->option("min_layer_height")->get_values(); - for (int i = 0; i < min_layer_height.size(); i++) { + for (std::vector::size_type i = 0; i < min_layer_height.size(); i++) { if(!min_layer_height[i].percent) if (min_layer_height[i].value != 0 && (int64_t)(min_layer_height[i].value * 1000000.) % z_step_Mlong != 0) { if (!has_changed) @@ -3662,7 +3650,7 @@ void TabPrinter::toggle_options() } } std::vector max_layer_height = m_config->option("max_layer_height")->get_values(); - for (int i = 0; i < max_layer_height.size(); i++) { + for (std::vector::size_type i = 0; i < max_layer_height.size(); i++) { if (!max_layer_height[i].percent) if ((int64_t)(max_layer_height[i].value * 1000000.) % z_step_Mlong != 0) { if (!has_changed) @@ -4903,19 +4891,18 @@ wxSizer *VectorManager::init(DynamicPrintConfig *config, wxWindow *parent, PageS return line_sizer; } -bool VectorManager::is_compatibile_with_ui() -{ +bool VectorManager::is_compatibile_with_ui() { size_t values_size = m_config->option(m_opt_key)->size(); - if (int(values_size) != m_grid_sizer->GetItemCount()) { + if (values_size != static_cast(m_grid_sizer->GetItemCount())) { ErrorDialog(m_parent, std::string("Invalid compatibility between UI and BE: ") + std::to_string(values_size) + - std::string("=!=") + std::to_string(m_grid_sizer->GetItemCount()), + std::string("=!=") + std::to_string(m_grid_sizer->GetItemCount()), false) .ShowModal(); return false; } return true; -}; +} // delete substitution_id from substitutions void VectorManager::pop_back() @@ -5033,6 +5020,9 @@ void VectorManager::update_from_config() assert(false); // todo break; } + default: { + break; + } } m_parent->GetParent()->Layout(); @@ -5089,6 +5079,9 @@ void VectorManager::edit_value(int idx_value, const std::string &str_value) assert(false); // todo break; } + default: { + break; + } } call_ui_update(); } diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 1f385663d88..ab2ee8f6ff2 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -481,7 +481,7 @@ wxBitmap create_scaled_bitmap( const std::string& bmp_name_in, color_int = Slic3r::GUI::wxGetApp().app_config->create_color(0.86f, 0.93f); color = color_to_hex(color_int); } - catch (std::exception /*e*/) { + catch (const std::exception& e) { color = ""; color_int = 0xFFFFFFFF; } diff --git a/src/stb_dxt/stb_dxt.h b/src/stb_dxt/stb_dxt.h index db19110f433..a64d9a61c6c 100644 --- a/src/stb_dxt/stb_dxt.h +++ b/src/stb_dxt/stb_dxt.h @@ -852,8 +852,8 @@ void rgbToYCoCgBlock( unsigned char * dst, const unsigned char * src ) int extents = 0; int n = 0; int iY, iCo, iCg; //, r, g, b; - int blockCo[16]; - int blockCg[16]; + // int blockCo[16]; + // int blockCg[16]; int i; const unsigned char *px = src; @@ -866,8 +866,8 @@ void rgbToYCoCgBlock( unsigned char * dst, const unsigned char * src ) if(-iCg > extents) extents = -iCg; if( iCg > extents) extents = iCg; - blockCo[n] = iCo; - blockCg[n++] = iCg; + // blockCo[n] = iCo; + // blockCg[n++] = iCg; px += 4; } @@ -979,48 +979,48 @@ void rygCompressYCoCg( unsigned char *dst, unsigned char *src, int w, int h ) } -static void stbgl__compress(unsigned char *p, unsigned char *rgba, int w, int h, int isDxt5) -{ - int i,j,y,y2; - int alpha = isDxt5; +// static void stbgl__compress(unsigned char *p, unsigned char *rgba, int w, int h, int isDxt5) +// { +// int i,j,y,y2; +// int alpha = isDxt5; - for (j=0; j < w; j += 4) { - int x=4; - for (i=0; i < h; i += 4) { - unsigned char block[16*4]; - if (i+3 >= w) x = w-i; - for (y=0; y < 4; ++y) { - if (j+y >= h) break; - memcpy(block+y*16, rgba + w*4*(j+y) + i*4, x*4); - } - if (x < 4) { - switch (x) { - case 0: assert(0); - case 1: - for (y2=0; y2 < y; ++y2) { - memcpy(block+y2*16+1*4, block+y2*16+0*4, 4); - memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); - } - break; - case 2: - for (y2=0; y2 < y; ++y2) - memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); - break; - case 3: - for (y2=0; y2 < y; ++y2) - memcpy(block+y2*16+3*4, block+y2*16+1*4, 4); - break; - } - } - y2 = 0; - for(; y<4; ++y,++y2) - memcpy(block+y*16, block+y2*16, 4*4); - stb_compress_dxt_block(p, block, alpha, 10); - p += alpha ? 16 : 8; - } - } - // assert(p <= end); -} +// for (j=0; j < w; j += 4) { +// int x=4; +// for (i=0; i < h; i += 4) { +// unsigned char block[16*4]; +// if (i+3 >= w) x = w-i; +// for (y=0; y < 4; ++y) { +// if (j+y >= h) break; +// memcpy(block+y*16, rgba + w*4*(j+y) + i*4, x*4); +// } +// if (x < 4) { +// switch (x) { +// case 0: assert(0); +// case 1: +// for (y2=0; y2 < y; ++y2) { +// memcpy(block+y2*16+1*4, block+y2*16+0*4, 4); +// memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); +// } +// break; +// case 2: +// for (y2=0; y2 < y; ++y2) +// memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); +// break; +// case 3: +// for (y2=0; y2 < y; ++y2) +// memcpy(block+y2*16+3*4, block+y2*16+1*4, 4); +// break; +// } +// } +// y2 = 0; +// for(; y<4; ++y,++y2) +// memcpy(block+y*16, block+y2*16, 4*4); +// stb_compress_dxt_block(p, block, alpha, 10); +// p += alpha ? 16 : 8; +// } +// } +// // assert(p <= end); +// } static inline unsigned char linearize(unsigned char inByte) { From 3a97013ca7d0e4293227e8d9083776ceb570b538 Mon Sep 17 00:00:00 2001 From: wschadow Date: Sun, 7 Jul 2024 23:56:47 +0200 Subject: [PATCH 08/10] removes trailing blanks, replaces tabs with 4 spaces --- src/CMakeLists.txt | 14 +- src/PrusaSlicer.cpp | 60 +- src/PrusaSlicer.hpp | 22 +- src/PrusaSlicer_app_msvc.cpp | 24 +- src/Shiny/ShinyConfig.h | 20 +- src/Shiny/ShinyData.h | 58 +- src/Shiny/ShinyMacros.h | 222 +- src/Shiny/ShinyManager.c | 432 +- src/Shiny/ShinyManager.h | 126 +- src/Shiny/ShinyNode.c | 112 +- src/Shiny/ShinyNode.h | 66 +- src/Shiny/ShinyNodePool.c | 42 +- src/Shiny/ShinyNodePool.h | 12 +- src/Shiny/ShinyNodeState.c | 92 +- src/Shiny/ShinyNodeState.h | 6 +- src/Shiny/ShinyOutput.c | 168 +- src/Shiny/ShinyOutput.h | 16 +- src/Shiny/ShinyPrereqs.h | 52 +- src/Shiny/ShinyTools.c | 74 +- src/Shiny/ShinyTools.h | 6 +- src/Shiny/ShinyVersion.h | 10 +- src/Shiny/ShinyZone.c | 234 +- src/Shiny/ShinyZone.h | 28 +- src/admesh/connect.cpp | 1300 +- src/admesh/normals.cpp | 360 +- src/admesh/shared.cpp | 358 +- src/admesh/stl.h | 150 +- src/admesh/stl_io.cpp | 310 +- src/admesh/stlinit.cpp | 410 +- src/admesh/util.cpp | 578 +- src/agg/AUTHORS | 2 +- src/agg/agg_array.h | 142 +- src/agg/agg_basics.h | 104 +- src/agg/agg_bezier_arc.h | 54 +- src/agg/agg_clip_liang_barsky.h | 96 +- src/agg/agg_color_gray.h | 230 +- src/agg/agg_color_rgba.h | 246 +- src/agg/agg_config.h | 12 +- src/agg/agg_conv_transform.h | 12 +- src/agg/agg_gamma_functions.h | 4 +- src/agg/agg_gamma_lut.h | 148 +- src/agg/agg_math.h | 82 +- src/agg/agg_path_storage.h | 258 +- src/agg/agg_pixfmt_base.h | 20 +- src/agg/agg_pixfmt_gray.h | 104 +- src/agg/agg_pixfmt_rgb.h | 178 +- src/agg/agg_rasterizer_cells_aa.h | 78 +- src/agg/agg_rasterizer_scanline_aa.h | 154 +- src/agg/agg_rasterizer_scanline_aa_nogamma.h | 150 +- src/agg/agg_rasterizer_sl_clip.h | 38 +- src/agg/agg_renderer_base.h | 72 +- src/agg/agg_renderer_scanline.h | 220 +- src/agg/agg_rendering_buffer.h | 68 +- src/agg/agg_scanline_p.h | 34 +- src/agg/agg_trans_affine.h | 132 +- src/agg/copying | 62 +- src/angelscript/CMakeLists.txt | 52 +- .../add_on/autowrapper/aswrappedcall.h | 726 +- .../autowrapper/generator/generateheader.cpp | 260 +- .../autowrapper/generator/generator.sln | 26 +- .../autowrapper/generator/generator.vcproj | 466 +- .../add_on/contextmgr/contextmgr.cpp | 578 +- .../add_on/contextmgr/contextmgr.h | 124 +- src/angelscript/add_on/datetime/datetime.cpp | 256 +- src/angelscript/add_on/datetime/datetime.h | 68 +- src/angelscript/add_on/debugger/debugger.cpp | 1494 +- src/angelscript/add_on/debugger/debugger.h | 130 +- .../add_on/scriptany/scriptany.cpp | 586 +- src/angelscript/add_on/scriptany/scriptany.h | 80 +- .../add_on/scriptarray/scriptarray.cpp | 3208 +- .../add_on/scriptarray/scriptarray.h | 204 +- .../add_on/scriptbuilder/scriptbuilder.cpp | 1948 +- .../add_on/scriptbuilder/scriptbuilder.h | 296 +- .../scriptdictionary/scriptdictionary.cpp | 1598 +- .../scriptdictionary/scriptdictionary.h | 244 +- .../add_on/scriptfile/scriptfile.cpp | 754 +- .../add_on/scriptfile/scriptfile.h | 80 +- .../add_on/scriptfile/scriptfilesystem.cpp | 870 +- .../add_on/scriptfile/scriptfilesystem.h | 74 +- .../add_on/scriptgrid/scriptgrid.cpp | 1160 +- .../add_on/scriptgrid/scriptgrid.h | 118 +- .../add_on/scripthandle/scripthandle.cpp | 358 +- .../add_on/scripthandle/scripthandle.h | 82 +- .../add_on/scripthelper/scripthelper.cpp | 1846 +- .../add_on/scripthelper/scripthelper.h | 6 +- .../add_on/scriptmath/scriptmath.cpp | 322 +- .../add_on/scriptmath/scriptmath.h | 2 +- .../add_on/scriptmath/scriptmathcomplex.cpp | 164 +- .../add_on/scriptmath/scriptmathcomplex.h | 72 +- .../scriptstdstring/scriptstdstring.cpp | 1562 +- .../add_on/scriptstdstring/scriptstdstring.h | 4 +- .../scriptstdstring/scriptstdstring_utils.cpp | 130 +- .../add_on/serializer/serializer.cpp | 804 +- .../add_on/serializer/serializer.h | 214 +- src/angelscript/add_on/weakref/weakref.cpp | 500 +- src/angelscript/add_on/weakref/weakref.h | 54 +- src/angelscript/include/angelscript.h | 2840 +- src/angelscript/source/as_array.h | 624 +- src/angelscript/source/as_atomic.cpp | 68 +- src/angelscript/source/as_atomic.h | 34 +- src/angelscript/source/as_builder.cpp | 11956 +++--- src/angelscript/source/as_builder.h | 312 +- src/angelscript/source/as_bytecode.cpp | 4872 +-- src/angelscript/source/as_bytecode.h | 244 +- src/angelscript/source/as_callfunc.cpp | 1442 +- src/angelscript/source/as_callfunc.h | 152 +- src/angelscript/source/as_callfunc_arm.cpp | 1068 +- src/angelscript/source/as_callfunc_arm64.cpp | 428 +- .../source/as_callfunc_arm64_gcc.S | 12 +- src/angelscript/source/as_callfunc_arm_gcc.S | 2 +- .../source/as_callfunc_arm_msvc.asm | 6 +- .../source/as_callfunc_arm_xcode.S | 4 +- src/angelscript/source/as_callfunc_mips.cpp | 964 +- src/angelscript/source/as_callfunc_ppc.cpp | 1078 +- src/angelscript/source/as_callfunc_ppc_64.cpp | 1240 +- src/angelscript/source/as_callfunc_sh4.cpp | 518 +- .../source/as_callfunc_x64_gcc.cpp | 742 +- .../source/as_callfunc_x64_mingw.cpp | 482 +- .../source/as_callfunc_x64_msvc.cpp | 308 +- .../source/as_callfunc_x64_msvc_asm.asm | 258 +- src/angelscript/source/as_callfunc_x86.cpp | 2188 +- src/angelscript/source/as_callfunc_xenon.cpp | 1106 +- src/angelscript/source/as_compiler.cpp | 30882 ++++++++-------- src/angelscript/source/as_compiler.h | 678 +- src/angelscript/source/as_config.h | 1690 +- src/angelscript/source/as_configgroup.cpp | 248 +- src/angelscript/source/as_configgroup.h | 56 +- src/angelscript/source/as_context.cpp | 10602 +++--- src/angelscript/source/as_context.h | 330 +- src/angelscript/source/as_criticalsection.h | 80 +- src/angelscript/source/as_datatype.cpp | 766 +- src/angelscript/source/as_datatype.h | 190 +- src/angelscript/source/as_debug.h | 298 +- src/angelscript/source/as_gc.cpp | 1688 +- src/angelscript/source/as_gc.h | 186 +- src/angelscript/source/as_generic.cpp | 598 +- src/angelscript/source/as_generic.h | 100 +- src/angelscript/source/as_globalproperty.cpp | 112 +- src/angelscript/source/as_map.h | 1138 +- src/angelscript/source/as_memory.cpp | 168 +- src/angelscript/source/as_memory.h | 48 +- src/angelscript/source/as_module.cpp | 2706 +- src/angelscript/source/as_module.h | 288 +- src/angelscript/source/as_namespace.h | 66 +- src/angelscript/source/as_objecttype.cpp | 986 +- src/angelscript/source/as_objecttype.h | 200 +- src/angelscript/source/as_outputbuffer.cpp | 88 +- src/angelscript/source/as_outputbuffer.h | 48 +- src/angelscript/source/as_parser.cpp | 7732 ++-- src/angelscript/source/as_parser.h | 246 +- src/angelscript/source/as_property.h | 90 +- src/angelscript/source/as_restore.cpp | 10882 +++--- src/angelscript/source/as_restore.h | 394 +- src/angelscript/source/as_scriptcode.cpp | 180 +- src/angelscript/source/as_scriptcode.h | 42 +- src/angelscript/source/as_scriptengine.cpp | 10496 +++--- src/angelscript/source/as_scriptengine.h | 822 +- src/angelscript/source/as_scriptfunction.cpp | 2326 +- src/angelscript/source/as_scriptfunction.h | 488 +- src/angelscript/source/as_scriptnode.cpp | 224 +- src/angelscript/source/as_scriptnode.h | 150 +- src/angelscript/source/as_scriptobject.cpp | 1826 +- src/angelscript/source/as_scriptobject.h | 128 +- src/angelscript/source/as_string.cpp | 446 +- src/angelscript/source/as_string.h | 110 +- src/angelscript/source/as_string_util.cpp | 560 +- src/angelscript/source/as_string_util.h | 16 +- src/angelscript/source/as_symboltable.h | 392 +- src/angelscript/source/as_texts.h | 74 +- src/angelscript/source/as_thread.cpp | 440 +- src/angelscript/source/as_thread.h | 50 +- src/angelscript/source/as_tokendef.h | 478 +- src/angelscript/source/as_tokenizer.cpp | 732 +- src/angelscript/source/as_tokenizer.h | 46 +- src/angelscript/source/as_typeinfo.cpp | 426 +- src/angelscript/source/as_typeinfo.h | 262 +- src/angelscript/source/as_variablescope.cpp | 150 +- src/angelscript/source/as_variablescope.h | 50 +- src/avrdude/AUTHORS | 40 +- src/avrdude/COPYING | 24 +- src/avrdude/ChangeLog | 94 +- src/avrdude/ChangeLog-2001 | 708 +- src/avrdude/ChangeLog-2002 | 262 +- src/avrdude/ChangeLog-2003 | 1310 +- src/avrdude/ChangeLog-2004-2006 | 2020 +- src/avrdude/ChangeLog-2007 | 474 +- src/avrdude/ChangeLog-2008 | 252 +- src/avrdude/ChangeLog-2009 | 450 +- src/avrdude/ChangeLog-2010 | 422 +- src/avrdude/ChangeLog-2011 | 614 +- src/avrdude/ChangeLog-2012 | 980 +- src/avrdude/ChangeLog-2013 | 722 +- src/avrdude/ChangeLog-2014 | 952 +- src/avrdude/ChangeLog-2015 | 50 +- src/avrdude/Makefile.am | 236 +- src/avrdude/Makefile.standalone | 6 +- src/avrdude/NEWS | 6 +- src/avrdude/README | 4 +- src/avrdude/arduino.c | 10 +- .../atmel-docs/EDBG/common/browserDetect.js | 224 +- .../atmel-docs/EDBG/common/css/docbook.css | 54 +- .../atmel-docs/EDBG/common/css/fluid_grid.css | 84 +- .../atmel-docs/EDBG/common/css/index.css | 44 +- .../EDBG/common/css/positioning.css | 174 +- .../atmel-docs/EDBG/common/css/print.css | 24 +- .../EDBG/common/jquery/jquery.ui.all.js | 2 +- .../common/jquery/layout/jquery.layout.js | 10378 +++--- .../theme-redmond/jquery-ui-1.8.2.custom.css | 44 +- .../jquery/treeview/jquery.treeview.css | 60 +- .../jquery/treeview/jquery.treeview.min.js | 2 +- src/avrdude/atmel-docs/EDBG/common/main.js | 66 +- .../atmel-docs/EDBG/common/splitterInit.js | 50 +- .../atmel-docs/EDBG/protocoldocs/ch01s01.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch01s02.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch02s01.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch02s02.html | 396 +- .../EDBG/protocoldocs/ch02s02s01.html | 396 +- .../EDBG/protocoldocs/ch02s02s02.html | 396 +- .../EDBG/protocoldocs/ch02s02s02s01.html | 396 +- .../EDBG/protocoldocs/ch02s02s02s02.html | 396 +- .../EDBG/protocoldocs/ch02s02s03.html | 396 +- .../EDBG/protocoldocs/ch02s02s03s01.html | 396 +- .../EDBG/protocoldocs/ch02s02s03s02.html | 396 +- .../EDBG/protocoldocs/ch02s02s03s03.html | 396 +- .../EDBG/protocoldocs/ch02s02s03s04.html | 396 +- .../EDBG/protocoldocs/ch02s03s01.html | 396 +- .../EDBG/protocoldocs/ch02s03s02.html | 396 +- .../EDBG/protocoldocs/ch02s03s03.html | 396 +- .../EDBG/protocoldocs/ch02s03s04.html | 396 +- .../EDBG/protocoldocs/ch02s03s05.html | 396 +- .../EDBG/protocoldocs/ch02s03s06.html | 396 +- .../EDBG/protocoldocs/ch02s03s07.html | 396 +- .../EDBG/protocoldocs/ch02s03s08.html | 396 +- .../EDBG/protocoldocs/ch02s03s09.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch02s04.html | 396 +- .../EDBG/protocoldocs/ch02s04s01.html | 398 +- .../EDBG/protocoldocs/ch02s04s02.html | 406 +- .../EDBG/protocoldocs/ch02s04s03.html | 400 +- .../atmel-docs/EDBG/protocoldocs/ch03s01.html | 396 +- .../EDBG/protocoldocs/ch03s01s01.html | 396 +- .../EDBG/protocoldocs/ch03s01s02.html | 396 +- .../EDBG/protocoldocs/ch03s01s03.html | 396 +- .../EDBG/protocoldocs/ch03s01s03s01.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch03s02.html | 396 +- .../EDBG/protocoldocs/ch03s02s01.html | 396 +- .../EDBG/protocoldocs/ch03s02s02.html | 396 +- .../EDBG/protocoldocs/ch03s02s03.html | 396 +- .../EDBG/protocoldocs/ch03s02s04.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch04s01.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch04s02.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch04s03.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch04s04.html | 396 +- .../EDBG/protocoldocs/ch04s04s01.html | 396 +- .../EDBG/protocoldocs/ch04s04s03.html | 396 +- .../EDBG/protocoldocs/ch04s04s04.html | 396 +- .../EDBG/protocoldocs/ch04s04s05.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch04s05.html | 396 +- .../EDBG/protocoldocs/ch04s05s01.html | 396 +- .../EDBG/protocoldocs/ch04s05s03.html | 396 +- .../EDBG/protocoldocs/ch04s05s04.html | 396 +- .../EDBG/protocoldocs/ch04s05s06.html | 396 +- .../EDBG/protocoldocs/ch04s05s06s02.html | 396 +- .../EDBG/protocoldocs/ch04s05s06s03.html | 396 +- .../EDBG/protocoldocs/ch04s05s06s04.html | 396 +- .../EDBG/protocoldocs/ch04s05s06s05.html | 396 +- .../EDBG/protocoldocs/ch04s05s07.html | 396 +- .../EDBG/protocoldocs/ch04s05s07s01.html | 396 +- .../EDBG/protocoldocs/ch04s05s07s02.html | 396 +- .../EDBG/protocoldocs/ch04s05s07s03.html | 396 +- .../EDBG/protocoldocs/ch04s05s07s04.html | 396 +- .../EDBG/protocoldocs/ch04s05s08.html | 396 +- .../EDBG/protocoldocs/ch04s05s08s01.html | 396 +- .../EDBG/protocoldocs/ch04s05s08s02.html | 396 +- .../EDBG/protocoldocs/ch04s05s08s03.html | 396 +- .../EDBG/protocoldocs/ch04s05s09.html | 396 +- .../EDBG/protocoldocs/ch04s05s10.html | 408 +- .../atmel-docs/EDBG/protocoldocs/ch05s01.html | 396 +- .../EDBG/protocoldocs/ch05s01s01.html | 396 +- .../EDBG/protocoldocs/ch05s01s02.html | 396 +- .../EDBG/protocoldocs/ch05s01s03.html | 396 +- .../EDBG/protocoldocs/ch05s01s04.html | 396 +- .../EDBG/protocoldocs/ch05s01s05.html | 396 +- .../EDBG/protocoldocs/ch05s01s06.html | 396 +- .../EDBG/protocoldocs/ch05s01s07.html | 396 +- .../EDBG/protocoldocs/ch05s01s08.html | 396 +- .../EDBG/protocoldocs/ch05s01s09.html | 396 +- .../EDBG/protocoldocs/ch05s01s10.html | 396 +- .../EDBG/protocoldocs/ch05s01s11.html | 396 +- .../EDBG/protocoldocs/ch05s01s12.html | 396 +- .../EDBG/protocoldocs/ch05s01s13.html | 398 +- .../EDBG/protocoldocs/ch05s01s14.html | 396 +- .../EDBG/protocoldocs/ch05s01s15.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch05s02.html | 396 +- .../EDBG/protocoldocs/ch05s02s01.html | 396 +- .../EDBG/protocoldocs/ch05s02s02.html | 396 +- .../EDBG/protocoldocs/ch05s02s03.html | 396 +- .../EDBG/protocoldocs/ch05s02s04.html | 396 +- .../EDBG/protocoldocs/ch05s02s05.html | 396 +- .../EDBG/protocoldocs/ch05s02s06.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch05s03.html | 396 +- .../EDBG/protocoldocs/ch05s03s01.html | 396 +- .../EDBG/protocoldocs/ch05s03s02.html | 396 +- .../EDBG/protocoldocs/ch05s03s03.html | 398 +- .../atmel-docs/EDBG/protocoldocs/ch05s04.html | 402 +- .../atmel-docs/EDBG/protocoldocs/ch06s01.html | 396 +- .../EDBG/protocoldocs/ch06s01s01.html | 396 +- .../EDBG/protocoldocs/ch06s01s02.html | 396 +- .../EDBG/protocoldocs/ch06s01s03.html | 396 +- .../EDBG/protocoldocs/ch06s01s04.html | 396 +- .../EDBG/protocoldocs/ch06s01s05.html | 396 +- .../EDBG/protocoldocs/ch06s01s06.html | 396 +- .../EDBG/protocoldocs/ch06s01s07.html | 396 +- .../EDBG/protocoldocs/ch06s01s08.html | 396 +- .../EDBG/protocoldocs/ch06s01s09.html | 396 +- .../EDBG/protocoldocs/ch06s01s10.html | 396 +- .../EDBG/protocoldocs/ch06s01s11.html | 396 +- .../EDBG/protocoldocs/ch06s01s12.html | 396 +- .../EDBG/protocoldocs/ch06s01s13.html | 396 +- .../EDBG/protocoldocs/ch06s01s14.html | 396 +- .../EDBG/protocoldocs/ch06s01s15.html | 396 +- .../EDBG/protocoldocs/ch06s01s16.html | 396 +- .../EDBG/protocoldocs/ch06s01s17.html | 400 +- .../EDBG/protocoldocs/ch06s01s18.html | 400 +- .../EDBG/protocoldocs/ch06s01s19.html | 396 +- .../EDBG/protocoldocs/ch06s01s20.html | 396 +- .../EDBG/protocoldocs/ch06s01s21.html | 396 +- .../EDBG/protocoldocs/ch06s01s22.html | 398 +- .../EDBG/protocoldocs/ch06s01s23.html | 396 +- .../EDBG/protocoldocs/ch06s01s24.html | 396 +- .../EDBG/protocoldocs/ch06s01s25.html | 396 +- .../EDBG/protocoldocs/ch06s01s26.html | 396 +- .../EDBG/protocoldocs/ch06s01s27.html | 396 +- .../EDBG/protocoldocs/ch06s01s28.html | 396 +- .../EDBG/protocoldocs/ch06s01s29.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch06s02.html | 396 +- .../EDBG/protocoldocs/ch06s02s01.html | 396 +- .../EDBG/protocoldocs/ch06s02s02.html | 396 +- .../EDBG/protocoldocs/ch06s02s03.html | 396 +- .../EDBG/protocoldocs/ch06s02s04.html | 396 +- .../EDBG/protocoldocs/ch06s02s05.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch06s03.html | 396 +- .../EDBG/protocoldocs/ch06s03s01.html | 396 +- .../EDBG/protocoldocs/ch06s03s02.html | 396 +- .../EDBG/protocoldocs/ch06s04s01.html | 396 +- .../EDBG/protocoldocs/ch06s04s02.html | 396 +- .../EDBG/protocoldocs/ch06s04s03.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch06s05.html | 396 +- .../EDBG/protocoldocs/ch06s05s01.html | 396 +- .../EDBG/protocoldocs/ch06s05s02.html | 396 +- .../EDBG/protocoldocs/ch06s05s03.html | 396 +- .../EDBG/protocoldocs/ch06s05s04.html | 400 +- .../EDBG/protocoldocs/ch06s05s05.html | 398 +- .../atmel-docs/EDBG/protocoldocs/ch06s06.html | 404 +- .../atmel-docs/EDBG/protocoldocs/ch07s01.html | 396 +- .../EDBG/protocoldocs/ch07s01s01.html | 396 +- .../EDBG/protocoldocs/ch07s01s02.html | 396 +- .../EDBG/protocoldocs/ch07s01s03.html | 396 +- .../EDBG/protocoldocs/ch07s01s04.html | 398 +- .../EDBG/protocoldocs/ch07s01s05.html | 398 +- .../EDBG/protocoldocs/ch07s01s06.html | 396 +- .../EDBG/protocoldocs/ch07s01s07.html | 412 +- .../EDBG/protocoldocs/ch07s01s08.html | 396 +- .../EDBG/protocoldocs/ch07s01s09.html | 396 +- .../EDBG/protocoldocs/ch07s01s10.html | 396 +- .../EDBG/protocoldocs/ch07s01s11.html | 396 +- .../EDBG/protocoldocs/ch07s01s12.html | 398 +- .../EDBG/protocoldocs/ch07s01s13.html | 396 +- .../EDBG/protocoldocs/ch07s01s14.html | 396 +- .../EDBG/protocoldocs/ch07s01s15.html | 396 +- .../EDBG/protocoldocs/ch07s01s16.html | 396 +- .../EDBG/protocoldocs/ch07s01s17.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch07s02.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch07s03.html | 400 +- .../atmel-docs/EDBG/protocoldocs/ch08s01.html | 396 +- .../EDBG/protocoldocs/ch08s01s01.html | 396 +- .../EDBG/protocoldocs/ch08s01s02.html | 396 +- .../EDBG/protocoldocs/ch08s01s03.html | 396 +- .../EDBG/protocoldocs/ch08s01s04.html | 396 +- .../EDBG/protocoldocs/ch08s01s05.html | 396 +- .../EDBG/protocoldocs/ch08s01s06.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch08s02.html | 396 +- .../atmel-docs/EDBG/protocoldocs/ch08s03.html | 396 +- .../EDBG/protocoldocs/document.revisions.html | 396 +- .../atmel-docs/EDBG/protocoldocs/index.html | 400 +- .../atmel-docs/EDBG/protocoldocs/pr01.html | 398 +- .../protocoldocs.Introduction.html | 396 +- .../protocoldocs.avr32protocol.html | 396 +- .../protocoldocs.avr8protocol.html | 398 +- .../protocoldocs.avrispprotocol.html | 396 +- .../protocoldocs.avrprotocol.Overview.html | 396 +- .../protocoldocs/protocoldocs.cmsis_dap.html | 396 +- .../protocoldocs.edbg_ctrl_protocol.html | 398 +- .../protocoldocs.tpiprotocol.html | 396 +- .../EDBG/protocoldocs/search/nwSearchFnt.js | 486 +- .../search/stemmers/en_stemmer.js | 442 +- .../protocoldocs/section_avr32_memtypes.html | 396 +- .../section_avr32_setget_params.html | 398 +- .../protocoldocs/section_avr8_memtypes.html | 396 +- .../section_avr8_query_contexts.html | 396 +- .../section_avr8_setget_params.html | 404 +- .../section_edbg_ctrl_setget_params.html | 408 +- .../section_edbg_query_contexts.html | 396 +- .../section_housekeeping_start_session.html | 396 +- .../EDBG/protocoldocs/section_i5v_3yz_rl.html | 396 +- .../EDBG/protocoldocs/section_jdx_m11_sl.html | 396 +- .../EDBG/protocoldocs/section_qhb_x1c_sl.html | 396 +- .../protocoldocs/section_serial_trace.html | 400 +- .../EDBG/protocoldocs/section_t1f_hb1_sl.html | 396 +- src/avrdude/avr.c | 152 +- src/avrdude/avr910.c | 20 +- src/avrdude/avrdude-slic3r.conf | 4 +- src/avrdude/avrdude-slic3r.cpp | 234 +- src/avrdude/avrdude-slic3r.hpp | 122 +- src/avrdude/avrdude.1 | 86 +- src/avrdude/avrdude.conf | 4684 +-- src/avrdude/avrdude.conf.in | 4684 +-- src/avrdude/avrdude.h | 10 +- src/avrdude/avrdude.spec.in | 26 +- src/avrdude/avrftdi.c | 1854 +- src/avrdude/avrftdi_private.h | 72 +- src/avrdude/avrftdi_tpi.c | 288 +- src/avrdude/avrftdi_tpi.h | 2 +- src/avrdude/avrpart.c | 18 +- src/avrdude/bitbang.c | 30 +- src/avrdude/buspirate.c | 2116 +- src/avrdude/butterfly.c | 70 +- src/avrdude/config.c | 2 +- src/avrdude/config_gram.c | 108 +- src/avrdude/config_gram.y | 156 +- src/avrdude/configure.ac | 320 +- src/avrdude/confwin.c | 6 +- src/avrdude/crc16.c | 2 +- src/avrdude/crc16.h | 8 +- src/avrdude/doc/Makefile.am | 76 +- src/avrdude/doc/avrdude.texi | 188 +- src/avrdude/fileio.c | 90 +- src/avrdude/freebsd_ppi.h | 12 +- src/avrdude/ft245r.c | 24 +- src/avrdude/jtag3.c | 330 +- src/avrdude/jtag3.h | 10 +- src/avrdude/jtag3_private.h | 52 +- src/avrdude/jtagmkI.c | 118 +- src/avrdude/jtagmkII.c | 574 +- src/avrdude/jtagmkII.h | 2 +- src/avrdude/jtagmkII_private.h | 84 +- src/avrdude/jtagmkI_private.h | 22 +- src/avrdude/lexer.c | 1956 +- src/avrdude/lexer.l | 10 +- src/avrdude/libavrdude.h | 50 +- src/avrdude/linux_ppdev.h | 12 +- src/avrdude/linuxgpio.c | 16 +- src/avrdude/lists.c | 94 +- src/avrdude/main-standalone.cpp | 52 +- src/avrdude/main.c | 174 +- src/avrdude/par.c | 10 +- src/avrdude/pgm.c | 10 +- src/avrdude/pickit2.c | 6 +- src/avrdude/pindefs.c | 2 +- src/avrdude/ppi.c | 2 +- src/avrdude/ppiwin.c | 112 +- src/avrdude/safemode.c | 4 +- src/avrdude/ser_avrdoper.c | 52 +- src/avrdude/ser_posix.c | 16 +- src/avrdude/ser_win32.c | 928 +- src/avrdude/serbb_posix.c | 68 +- src/avrdude/serbb_win32.c | 128 +- src/avrdude/solaris_ecpp.h | 32 +- src/avrdude/stk500.c | 52 +- src/avrdude/stk500_private.h | 18 +- src/avrdude/stk500v2.c | 436 +- src/avrdude/stk500v2_private.h | 12 +- src/avrdude/term.c | 94 +- src/avrdude/tools/build-mingw32.sh | 4 +- src/avrdude/tools/get-hv-params.xsl | 2 +- src/avrdude/tools/get-stk600-cards.xsl | 10 +- src/avrdude/tools/get-stk600-devices.xsl | 10 +- src/avrdude/tpi.h | 40 +- src/avrdude/update.c | 36 +- src/avrdude/usb_hidapi.c | 114 +- src/avrdude/usb_libusb.c | 388 +- src/avrdude/usbasp.c | 186 +- src/avrdude/usbdevs.h | 12 +- src/avrdude/usbtiny.c | 176 +- src/avrdude/usbtiny.h | 40 +- src/avrdude/windows/Makefile.am | 38 +- src/avrdude/windows/getopt.h | 26 +- src/avrdude/windows/giveio.c | 94 +- src/avrdude/windows/loaddrv.c | 74 +- src/avrdude/windows/unistd.cpp | 6 +- src/avrdude/windows/utf8.c | 62 +- src/avrdude/wiring.c | 2 +- src/boost/nowide/args.hpp | 12 +- src/boost/nowide/cenv.hpp | 4 +- src/boost/nowide/config.hpp | 6 +- src/boost/nowide/convert.hpp | 20 +- src/boost/nowide/filebuf.hpp | 58 +- src/boost/nowide/fstream.hpp | 24 +- src/boost/nowide/iostream.cpp | 46 +- src/boost/nowide/iostream.hpp | 20 +- src/boost/nowide/stackstring.hpp | 18 +- src/boost/nowide/utf8_codecvt.hpp | 88 +- src/boost/nowide/windows.hpp | 2 +- src/cleanblanks.sh | 55 + src/cleantabs.sh | 55 + src/clipper/clipper.cpp | 422 +- src/clipper/clipper.hpp | 42 +- src/eigen/Eigen/IterativeLinearSolvers | 2 +- src/eigen/Eigen/MetisSupport | 2 +- src/eigen/Eigen/OrderingMethods | 52 +- src/eigen/Eigen/PaStiXSupport | 4 +- src/eigen/Eigen/PardisoSupport | 2 +- src/eigen/Eigen/SPQRSupport | 2 +- src/eigen/Eigen/SparseCholesky | 2 +- src/eigen/Eigen/SparseCore | 2 +- src/eigen/Eigen/SparseLU | 2 +- src/eigen/Eigen/SparseQR | 14 +- src/eigen/Eigen/src/Cholesky/LDLT.h | 2 +- src/eigen/Eigen/src/Cholesky/LLT_LAPACKE.h | 2 +- .../Eigen/src/CholmodSupport/CholmodSupport.h | 64 +- src/eigen/Eigen/src/Core/Array.h | 2 +- src/eigen/Eigen/src/Core/ArrayBase.h | 6 +- src/eigen/Eigen/src/Core/ArrayWrapper.h | 10 +- src/eigen/Eigen/src/Core/Assign.h | 2 +- src/eigen/Eigen/src/Core/AssignEvaluator.h | 60 +- src/eigen/Eigen/src/Core/Assign_MKL.h | 12 +- src/eigen/Eigen/src/Core/BandMatrix.h | 10 +- src/eigen/Eigen/src/Core/Block.h | 36 +- src/eigen/Eigen/src/Core/BooleanRedux.h | 6 +- src/eigen/Eigen/src/Core/CommaInitializer.h | 6 +- src/eigen/Eigen/src/Core/CoreEvaluators.h | 236 +- src/eigen/Eigen/src/Core/CoreIterators.h | 16 +- src/eigen/Eigen/src/Core/CwiseBinaryOp.h | 4 +- src/eigen/Eigen/src/Core/CwiseNullaryOp.h | 2 +- src/eigen/Eigen/src/Core/CwiseUnaryOp.h | 4 +- src/eigen/Eigen/src/Core/CwiseUnaryView.h | 2 +- src/eigen/Eigen/src/Core/DenseBase.h | 26 +- src/eigen/Eigen/src/Core/DenseCoeffsBase.h | 4 +- src/eigen/Eigen/src/Core/DenseStorage.h | 56 +- src/eigen/Eigen/src/Core/Diagonal.h | 6 +- src/eigen/Eigen/src/Core/DiagonalMatrix.h | 12 +- src/eigen/Eigen/src/Core/DiagonalProduct.h | 2 +- src/eigen/Eigen/src/Core/Dot.h | 4 +- src/eigen/Eigen/src/Core/EigenBase.h | 4 +- src/eigen/Eigen/src/Core/Fuzzy.h | 2 +- src/eigen/Eigen/src/Core/GeneralProduct.h | 6 +- src/eigen/Eigen/src/Core/GenericPacketMath.h | 6 +- src/eigen/Eigen/src/Core/GlobalFunctions.h | 10 +- src/eigen/Eigen/src/Core/IO.h | 4 +- src/eigen/Eigen/src/Core/Inverse.h | 12 +- src/eigen/Eigen/src/Core/Map.h | 2 +- src/eigen/Eigen/src/Core/MapBase.h | 2 +- src/eigen/Eigen/src/Core/MathFunctions.h | 8 +- src/eigen/Eigen/src/Core/MathFunctionsImpl.h | 2 +- src/eigen/Eigen/src/Core/Matrix.h | 10 +- src/eigen/Eigen/src/Core/NoAlias.h | 8 +- src/eigen/Eigen/src/Core/PermutationMatrix.h | 6 +- src/eigen/Eigen/src/Core/PlainObjectBase.h | 44 +- src/eigen/Eigen/src/Core/Product.h | 36 +- src/eigen/Eigen/src/Core/ProductEvaluators.h | 114 +- src/eigen/Eigen/src/Core/Random.h | 22 +- src/eigen/Eigen/src/Core/Redux.h | 24 +- src/eigen/Eigen/src/Core/Ref.h | 10 +- src/eigen/Eigen/src/Core/Replicate.h | 8 +- src/eigen/Eigen/src/Core/ReturnByValue.h | 4 +- src/eigen/Eigen/src/Core/Reverse.h | 8 +- src/eigen/Eigen/src/Core/Select.h | 2 +- src/eigen/Eigen/src/Core/SelfAdjointView.h | 18 +- src/eigen/Eigen/src/Core/SelfCwiseBinaryOp.h | 2 +- src/eigen/Eigen/src/Core/Solve.h | 20 +- src/eigen/Eigen/src/Core/SolveTriangular.h | 6 +- src/eigen/Eigen/src/Core/StableNorm.h | 18 +- src/eigen/Eigen/src/Core/Stride.h | 2 +- src/eigen/Eigen/src/Core/Swap.h | 14 +- src/eigen/Eigen/src/Core/Transpose.h | 4 +- src/eigen/Eigen/src/Core/Transpositions.h | 10 +- src/eigen/Eigen/src/Core/TriangularMatrix.h | 76 +- src/eigen/Eigen/src/Core/VectorBlock.h | 2 +- src/eigen/Eigen/src/Core/Visitor.h | 18 +- src/eigen/Eigen/src/Core/arch/AVX/Complex.h | 4 +- .../Eigen/src/Core/arch/AVX/PacketMath.h | 2 +- .../Eigen/src/Core/arch/AltiVec/Complex.h | 6 +- .../src/Core/arch/AltiVec/MathFunctions.h | 12 +- .../Eigen/src/Core/arch/AltiVec/PacketMath.h | 6 +- src/eigen/Eigen/src/Core/arch/NEON/Complex.h | 8 +- .../Eigen/src/Core/arch/NEON/PacketMath.h | 10 +- .../Eigen/src/Core/arch/SSE/PacketMath.h | 6 +- .../Eigen/src/Core/arch/ZVector/Complex.h | 2 +- .../src/Core/arch/ZVector/MathFunctions.h | 2 +- .../Eigen/src/Core/arch/ZVector/PacketMath.h | 12 +- .../src/Core/functors/AssignmentFunctors.h | 14 +- .../Eigen/src/Core/functors/BinaryFunctors.h | 6 +- .../Eigen/src/Core/functors/UnaryFunctors.h | 2 +- .../Core/products/GeneralBlockPanelKernel.h | 98 +- .../products/GeneralMatrixMatrixTriangular.h | 24 +- .../Core/products/GeneralMatrixMatrix_BLAS.h | 2 +- .../Core/products/GeneralMatrixVector_BLAS.h | 2 +- .../Core/products/SelfadjointMatrixMatrix.h | 18 +- .../products/SelfadjointMatrixMatrix_BLAS.h | 2 +- .../Core/products/SelfadjointMatrixVector.h | 24 +- .../products/SelfadjointMatrixVector_BLAS.h | 2 +- .../src/Core/products/SelfadjointProduct.h | 6 +- .../Core/products/SelfadjointRank2Update.h | 2 +- .../Core/products/TriangularMatrixMatrix.h | 12 +- .../products/TriangularMatrixMatrix_BLAS.h | 2 +- .../Core/products/TriangularMatrixVector.h | 10 +- .../products/TriangularMatrixVector_BLAS.h | 2 +- .../Core/products/TriangularSolverMatrix.h | 4 +- src/eigen/Eigen/src/Core/util/Constants.h | 52 +- src/eigen/Eigen/src/Core/util/MKL_support.h | 2 +- src/eigen/Eigen/src/Core/util/Memory.h | 26 +- src/eigen/Eigen/src/Core/util/Meta.h | 2 +- src/eigen/Eigen/src/Core/util/XprHelper.h | 12 +- .../src/Eigenvalues/ComplexEigenSolver.h | 12 +- .../Eigen/src/Eigenvalues/ComplexSchur.h | 50 +- .../src/Eigenvalues/ComplexSchur_LAPACKE.h | 2 +- src/eigen/Eigen/src/Eigenvalues/EigenSolver.h | 72 +- .../src/Eigenvalues/GeneralizedEigenSolver.h | 28 +- .../GeneralizedSelfAdjointEigenSolver.h | 2 +- .../src/Eigenvalues/HessenbergDecomposition.h | 10 +- .../src/Eigenvalues/MatrixBaseEigenvalues.h | 16 +- src/eigen/Eigen/src/Eigenvalues/RealQZ.h | 30 +- src/eigen/Eigen/src/Eigenvalues/RealSchur.h | 50 +- .../Eigen/src/Eigenvalues/RealSchur_LAPACKE.h | 2 +- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 56 +- .../SelfAdjointEigenSolver_LAPACKE.h | 4 +- .../src/Eigenvalues/Tridiagonalization.h | 10 +- src/eigen/Eigen/src/Geometry/AlignedBox.h | 4 +- src/eigen/Eigen/src/Geometry/AngleAxis.h | 8 +- src/eigen/Eigen/src/Geometry/EulerAngles.h | 18 +- src/eigen/Eigen/src/Geometry/Homogeneous.h | 10 +- src/eigen/Eigen/src/Geometry/Hyperplane.h | 4 +- src/eigen/Eigen/src/Geometry/OrthoMethods.h | 10 +- .../Eigen/src/Geometry/ParametrizedLine.h | 12 +- src/eigen/Eigen/src/Geometry/Quaternion.h | 16 +- src/eigen/Eigen/src/Geometry/Rotation2D.h | 12 +- src/eigen/Eigen/src/Geometry/RotationBase.h | 6 +- src/eigen/Eigen/src/Geometry/Scaling.h | 2 +- src/eigen/Eigen/src/Geometry/Transform.h | 50 +- src/eigen/Eigen/src/Geometry/Translation.h | 2 +- src/eigen/Eigen/src/Geometry/Umeyama.h | 14 +- .../Eigen/src/Geometry/arch/Geometry_SSE.h | 6 +- .../Eigen/src/Householder/BlockHouseholder.h | 16 +- src/eigen/Eigen/src/Householder/Householder.h | 12 +- .../src/Householder/HouseholderSequence.h | 22 +- .../BasicPreconditioners.h | 26 +- .../src/IterativeLinearSolvers/BiCGSTAB.h | 32 +- .../ConjugateGradient.h | 28 +- .../IncompleteCholesky.h | 72 +- .../IterativeLinearSolvers/IncompleteLUT.h | 94 +- .../IterativeSolverBase.h | 30 +- .../LeastSquareConjugateGradient.h | 28 +- .../IterativeLinearSolvers/SolveWithGuess.h | 12 +- src/eigen/Eigen/src/Jacobi/Jacobi.h | 6 +- src/eigen/Eigen/src/LU/Determinant.h | 2 +- src/eigen/Eigen/src/LU/FullPivLU.h | 2 +- src/eigen/Eigen/src/LU/InverseImpl.h | 18 +- src/eigen/Eigen/src/LU/PartialPivLU.h | 2 +- src/eigen/Eigen/src/LU/PartialPivLU_LAPACKE.h | 2 +- src/eigen/Eigen/src/LU/arch/Inverse_SSE.h | 12 +- .../Eigen/src/MetisSupport/MetisSupport.h | 102 +- src/eigen/Eigen/src/OrderingMethods/Amd.h | 44 +- .../Eigen/src/OrderingMethods/Eigen_Colamd.h | 578 +- .../Eigen/src/OrderingMethods/Ordering.h | 72 +- .../Eigen/src/PaStiXSupport/PaStiXSupport.h | 238 +- .../Eigen/src/PardisoSupport/PardisoSupport.h | 44 +- src/eigen/Eigen/src/QR/ColPivHouseholderQR.h | 2 +- .../src/QR/ColPivHouseholderQR_LAPACKE.h | 2 +- .../src/QR/CompleteOrthogonalDecomposition.h | 2 +- src/eigen/Eigen/src/QR/FullPivHouseholderQR.h | 30 +- src/eigen/Eigen/src/QR/HouseholderQR.h | 20 +- .../Eigen/src/QR/HouseholderQR_LAPACKE.h | 2 +- .../src/SPQRSupport/SuiteSparseQRSupport.h | 74 +- src/eigen/Eigen/src/SVD/BDCSVD.h | 218 +- src/eigen/Eigen/src/SVD/JacobiSVD.h | 12 +- src/eigen/Eigen/src/SVD/JacobiSVD_LAPACKE.h | 2 +- src/eigen/Eigen/src/SVD/SVDBase.h | 20 +- .../Eigen/src/SVD/UpperBidiagonalization.h | 38 +- .../src/SparseCholesky/SimplicialCholesky.h | 54 +- src/eigen/Eigen/src/SparseCore/AmbiVector.h | 2 +- .../Eigen/src/SparseCore/CompressedStorage.h | 2 +- .../ConservativeSparseSparseProduct.h | 10 +- .../Eigen/src/SparseCore/MappedSparseMatrix.h | 4 +- src/eigen/Eigen/src/SparseCore/SparseAssign.h | 16 +- .../Eigen/src/SparseCore/SparseColEtree.h | 128 +- .../src/SparseCore/SparseCompressedBase.h | 26 +- .../src/SparseCore/SparseCwiseBinaryOp.h | 68 +- .../Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 18 +- .../Eigen/src/SparseCore/SparseDenseProduct.h | 46 +- .../src/SparseCore/SparseDiagonalProduct.h | 30 +- src/eigen/Eigen/src/SparseCore/SparseDot.h | 4 +- src/eigen/Eigen/src/SparseCore/SparseFuzzy.h | 2 +- src/eigen/Eigen/src/SparseCore/SparseMap.h | 16 +- src/eigen/Eigen/src/SparseCore/SparseMatrix.h | 128 +- .../Eigen/src/SparseCore/SparseMatrixBase.h | 28 +- .../Eigen/src/SparseCore/SparsePermutation.h | 6 +- .../Eigen/src/SparseCore/SparseProduct.h | 4 +- src/eigen/Eigen/src/SparseCore/SparseRedux.h | 2 +- src/eigen/Eigen/src/SparseCore/SparseRef.h | 16 +- .../src/SparseCore/SparseSelfAdjointView.h | 74 +- .../Eigen/src/SparseCore/SparseSolverBase.h | 12 +- .../SparseSparseProductWithPruning.h | 6 +- .../Eigen/src/SparseCore/SparseTranspose.h | 18 +- .../src/SparseCore/SparseTriangularView.h | 30 +- src/eigen/Eigen/src/SparseCore/SparseUtil.h | 6 +- src/eigen/Eigen/src/SparseCore/SparseVector.h | 34 +- src/eigen/Eigen/src/SparseCore/SparseView.h | 22 +- .../Eigen/src/SparseCore/TriangularSolver.h | 2 +- src/eigen/Eigen/src/SparseLU/SparseLU.h | 436 +- src/eigen/Eigen/src/SparseLU/SparseLUImpl.h | 34 +- .../Eigen/src/SparseLU/SparseLU_Memory.h | 98 +- .../Eigen/src/SparseLU/SparseLU_Structs.h | 34 +- .../src/SparseLU/SparseLU_SupernodalMatrix.h | 162 +- src/eigen/Eigen/src/SparseLU/SparseLU_Utils.h | 52 +- .../Eigen/src/SparseLU/SparseLU_column_bmod.h | 140 +- .../Eigen/src/SparseLU/SparseLU_column_dfs.h | 122 +- .../src/SparseLU/SparseLU_copy_to_ucol.h | 88 +- .../Eigen/src/SparseLU/SparseLU_gemm_kernel.h | 56 +- .../src/SparseLU/SparseLU_heap_relax_snode.h | 58 +- .../Eigen/src/SparseLU/SparseLU_kernel_bmod.h | 38 +- .../Eigen/src/SparseLU/SparseLU_panel_bmod.h | 144 +- .../Eigen/src/SparseLU/SparseLU_panel_dfs.h | 204 +- .../Eigen/src/SparseLU/SparseLU_pivotL.h | 58 +- .../Eigen/src/SparseLU/SparseLU_pruneL.h | 100 +- .../Eigen/src/SparseLU/SparseLU_relax_snode.h | 30 +- src/eigen/Eigen/src/SparseQR/SparseQR.h | 192 +- src/eigen/Eigen/src/StlSupport/StdDeque.h | 4 +- src/eigen/Eigen/src/StlSupport/StdList.h | 4 +- src/eigen/Eigen/src/StlSupport/StdVector.h | 4 +- .../Eigen/src/SuperLUSupport/SuperLUSupport.h | 110 +- src/eigen/Eigen/src/misc/Image.h | 2 +- src/eigen/Eigen/src/misc/Kernel.h | 2 +- src/eigen/Eigen/src/misc/blas.h | 124 +- src/eigen/Eigen/src/misc/lapacke.h | 4 +- .../SparseExtra/BlockOfDynamicSparseMatrix.h | 2 +- .../Eigen/src/SparseExtra/BlockSparseMatrix.h | 2 +- .../src/SparseExtra/DynamicSparseMatrix.h | 14 +- .../Eigen/src/SparseExtra/MarketIO.h | 104 +- .../src/SparseExtra/MatrixMarketIterator.h | 130 +- .../Eigen/src/SparseExtra/RandomSetter.h | 2 +- src/exif/README | 2 +- src/exif/exif.c | 294 +- src/fast_float/fast_float.h | 14 +- src/glew/LICENSE.txt | 20 +- src/glew/README.md | 104 +- src/glew/include/GL/glew.h | 30 +- src/glew/include/GL/glxew.h | 98 +- src/glew/include/GL/wglew.h | 40 +- src/glew/src/glew.c | 30 +- src/glu-libtess/CMakeLists.txt | 54 +- src/glu-libtess/README | 2 +- src/glu-libtess/src/README | 106 +- src/glu-libtess/src/alg-outline | 12 +- src/glu-libtess/src/dict-list.h | 68 +- src/glu-libtess/src/dict.c | 2 +- src/glu-libtess/src/dict.h | 68 +- src/glu-libtess/src/geom.c | 24 +- src/glu-libtess/src/geom.h | 42 +- src/glu-libtess/src/gluos.h | 2 +- src/glu-libtess/src/memalloc.h | 16 +- src/glu-libtess/src/mesh.c | 44 +- src/glu-libtess/src/mesh.h | 108 +- src/glu-libtess/src/normal.c | 18 +- src/glu-libtess/src/priorityq-heap.c | 24 +- src/glu-libtess/src/priorityq-heap.h | 52 +- src/glu-libtess/src/priorityq-sort.h | 52 +- src/glu-libtess/src/priorityq.c | 44 +- src/glu-libtess/src/priorityq.h | 52 +- src/glu-libtess/src/render.c | 82 +- src/glu-libtess/src/sweep.c | 162 +- src/glu-libtess/src/sweep.h | 18 +- src/glu-libtess/src/tess.c | 112 +- src/glu-libtess/src/tess.h | 86 +- src/glu-libtess/src/tessmono.c | 30 +- src/glu-libtess/src/tessmono.h | 4 +- src/hidapi/CMakeLists.txt | 6 +- src/hidapi/include/hidapi.h | 688 +- src/hidapi/linux/hid.c | 1356 +- src/hidapi/mac/hid.c | 1554 +- src/hidapi/win/hid.c | 1450 +- src/hints/HintsToPot.cpp | 128 +- src/imgui/imgui_widgets.cpp | 2 +- src/imgui/imstb_rectpack.h | 52 +- src/imgui/imstb_textedit.h | 74 +- src/imgui/imstb_truetype.h | 148 +- src/jpeg-compressor/jpge.cpp | 2026 +- src/jpeg-compressor/jpge.h | 322 +- src/libigl/igl/AABB.h | 84 +- src/libigl/igl/ARAPEnergyType.h | 10 +- src/libigl/igl/AtA_cached.cpp | 10 +- src/libigl/igl/AtA_cached.h | 14 +- src/libigl/igl/C_STR.h | 8 +- src/libigl/igl/Camera.h | 22 +- src/libigl/igl/EPS.cpp | 8 +- src/libigl/igl/EPS.h | 8 +- src/libigl/igl/Hit.h | 12 +- src/libigl/igl/IndexComparison.h | 10 +- src/libigl/igl/LinSpaced.h | 6 +- src/libigl/igl/MeshBooleanType.h | 8 +- src/libigl/igl/NormalType.h | 8 +- src/libigl/igl/ONE.h | 8 +- src/libigl/igl/PI.h | 8 +- src/libigl/igl/REDRUM.h | 10 +- src/libigl/igl/STR.h | 10 +- ...ecomposition_Jacobi_Conjugation_Kernel.hpp | 4 +- ...r_Value_Decomposition_Main_Kernel_Body.hpp | 10 +- src/libigl/igl/SolverStatus.h | 8 +- src/libigl/igl/Timer.h | 42 +- src/libigl/igl/Viewport.h | 20 +- src/libigl/igl/WindingNumberAABB.h | 28 +- src/libigl/igl/WindingNumberMethod.h | 8 +- src/libigl/igl/WindingNumberTree.h | 68 +- src/libigl/igl/ZERO.h | 8 +- src/libigl/igl/active_set.h | 14 +- src/libigl/igl/adjacency_list.cpp | 50 +- src/libigl/igl/adjacency_list.h | 16 +- src/libigl/igl/adjacency_matrix.cpp | 10 +- src/libigl/igl/adjacency_matrix.h | 16 +- src/libigl/igl/all.cpp | 10 +- src/libigl/igl/all.h | 12 +- src/libigl/igl/all_edges.cpp | 8 +- src/libigl/igl/all_edges.h | 8 +- src/libigl/igl/all_pairs_distances.cpp | 8 +- src/libigl/igl/all_pairs_distances.h | 16 +- src/libigl/igl/ambient_occlusion.cpp | 8 +- src/libigl/igl/ambient_occlusion.h | 8 +- src/libigl/igl/angular_distance.cpp | 8 +- src/libigl/igl/angular_distance.h | 8 +- src/libigl/igl/anttweakbar/ReAntTweakBar.cpp | 118 +- src/libigl/igl/anttweakbar/ReAntTweakBar.h | 86 +- .../cocoa_key_to_anttweakbar_key.cpp | 8 +- .../cocoa_key_to_anttweakbar_key.h | 10 +- src/libigl/igl/any.cpp | 10 +- src/libigl/igl/any.h | 12 +- src/libigl/igl/any_of.cpp | 8 +- src/libigl/igl/any_of.h | 10 +- src/libigl/igl/arap.h | 10 +- src/libigl/igl/arap_dof.cpp | 184 +- src/libigl/igl/arap_dof.h | 70 +- src/libigl/igl/arap_linear_block.cpp | 20 +- src/libigl/igl/arap_linear_block.h | 12 +- src/libigl/igl/arap_rhs.cpp | 12 +- src/libigl/igl/arap_rhs.h | 14 +- src/libigl/igl/average_onto_faces.cpp | 12 +- src/libigl/igl/average_onto_faces.h | 14 +- src/libigl/igl/average_onto_vertices.h | 14 +- src/libigl/igl/avg_edge_length.cpp | 8 +- src/libigl/igl/avg_edge_length.h | 10 +- src/libigl/igl/axis_angle_to_quat.cpp | 10 +- src/libigl/igl/axis_angle_to_quat.h | 10 +- src/libigl/igl/barycentric_coordinates.cpp | 14 +- src/libigl/igl/barycentric_coordinates.h | 12 +- src/libigl/igl/barycentric_to_global.h | 20 +- src/libigl/igl/basename.cpp | 10 +- src/libigl/igl/basename.h | 8 +- src/libigl/igl/bfs_orient.cpp | 8 +- src/libigl/igl/bfs_orient.h | 8 +- src/libigl/igl/biharmonic_coordinates.cpp | 4 +- src/libigl/igl/biharmonic_coordinates.h | 8 +- .../bijective_composite_harmonic_mapping.cpp | 10 +- .../bijective_composite_harmonic_mapping.h | 14 +- src/libigl/igl/bone_parents.cpp | 8 +- src/libigl/igl/bone_parents.h | 10 +- src/libigl/igl/boundary_conditions.cpp | 8 +- src/libigl/igl/boundary_conditions.h | 8 +- src/libigl/igl/boundary_loop.h | 18 +- src/libigl/igl/bounding_box.h | 12 +- src/libigl/igl/bounding_box_diagonal.cpp | 8 +- src/libigl/igl/bounding_box_diagonal.h | 8 +- src/libigl/igl/canonical_quaternions.cpp | 8 +- src/libigl/igl/canonical_quaternions.h | 30 +- src/libigl/igl/cat.cpp | 22 +- src/libigl/igl/cat.h | 22 +- src/libigl/igl/ceil.cpp | 8 +- src/libigl/igl/ceil.h | 10 +- src/libigl/igl/centroid.cpp | 20 +- src/libigl/igl/centroid.h | 20 +- src/libigl/igl/circulation.cpp | 14 +- src/libigl/igl/circulation.h | 10 +- src/libigl/igl/circumradius.cpp | 12 +- src/libigl/igl/circumradius.h | 12 +- src/libigl/igl/collapse_edge.cpp | 12 +- src/libigl/igl/collapse_edge.h | 12 +- src/libigl/igl/collapse_small_triangles.cpp | 8 +- src/libigl/igl/collapse_small_triangles.h | 10 +- src/libigl/igl/colon.h | 22 +- src/libigl/igl/colormap.cpp | 4 +- src/libigl/igl/colormap.h | 8 +- src/libigl/igl/column_to_quats.cpp | 8 +- src/libigl/igl/columnize.cpp | 8 +- src/libigl/igl/columnize.h | 10 +- src/libigl/igl/comb_cross_field.h | 6 +- src/libigl/igl/combine.h | 22 +- src/libigl/igl/components.h | 8 +- .../igl/connect_boundary_to_infinity.cpp | 14 +- src/libigl/igl/connect_boundary_to_infinity.h | 16 +- .../cgal/BinaryWindingNumberOperations.h | 16 +- src/libigl/igl/copyleft/cgal/CSGTree.h | 14 +- .../cgal/RemeshSelfIntersectionsParam.h | 10 +- .../igl/copyleft/cgal/SelfIntersectMesh.h | 98 +- src/libigl/igl/copyleft/cgal/assign.cpp | 22 +- src/libigl/igl/copyleft/cgal/assign.h | 18 +- .../igl/copyleft/cgal/cell_adjacency.cpp | 8 +- src/libigl/igl/copyleft/cgal/cell_adjacency.h | 8 +- .../igl/copyleft/cgal/closest_facet.cpp | 40 +- src/libigl/igl/copyleft/cgal/closest_facet.h | 10 +- .../igl/copyleft/cgal/complex_to_mesh.cpp | 26 +- .../igl/copyleft/cgal/complex_to_mesh.h | 12 +- .../cgal/component_inside_component.cpp | 8 +- .../cgal/component_inside_component.h | 8 +- src/libigl/igl/copyleft/cgal/convex_hull.cpp | 8 +- src/libigl/igl/copyleft/cgal/convex_hull.h | 16 +- .../copyleft/cgal/delaunay_triangulation.cpp | 6 +- .../copyleft/cgal/delaunay_triangulation.h | 8 +- .../igl/copyleft/cgal/extract_cells.cpp | 44 +- src/libigl/igl/copyleft/cgal/extract_cells.h | 8 +- .../igl/copyleft/cgal/extract_feature.cpp | 8 +- .../igl/copyleft/cgal/extract_feature.h | 8 +- .../igl/copyleft/cgal/fast_winding_number.cpp | 10 +- .../igl/copyleft/cgal/fast_winding_number.h | 6 +- .../igl/copyleft/cgal/half_space_box.cpp | 10 +- src/libigl/igl/copyleft/cgal/hausdorff.cpp | 10 +- src/libigl/igl/copyleft/cgal/hausdorff.h | 16 +- src/libigl/igl/copyleft/cgal/incircle.cpp | 8 +- src/libigl/igl/copyleft/cgal/incircle.h | 8 +- src/libigl/igl/copyleft/cgal/insphere.cpp | 8 +- src/libigl/igl/copyleft/cgal/insphere.h | 8 +- .../igl/copyleft/cgal/intersect_other.cpp | 36 +- .../igl/copyleft/cgal/intersect_other.h | 12 +- .../copyleft/cgal/intersect_with_half_space.h | 2 +- .../cgal/lexicographic_triangulation.cpp | 8 +- .../cgal/lexicographic_triangulation.h | 8 +- src/libigl/igl/copyleft/cgal/mesh_boolean.cpp | 42 +- src/libigl/igl/copyleft/cgal/mesh_boolean.h | 10 +- .../cgal/mesh_boolean_type_to_funcs.cpp | 2 +- .../cgal/mesh_boolean_type_to_funcs.h | 2 +- .../cgal/mesh_to_cgal_triangle_list.cpp | 12 +- .../cgal/mesh_to_cgal_triangle_list.h | 8 +- .../igl/copyleft/cgal/mesh_to_polyhedron.cpp | 8 +- .../igl/copyleft/cgal/mesh_to_polyhedron.h | 8 +- .../igl/copyleft/cgal/minkowski_sum.cpp | 30 +- src/libigl/igl/copyleft/cgal/minkowski_sum.h | 12 +- .../cgal/order_facets_around_edge.cpp | 16 +- .../copyleft/cgal/order_facets_around_edge.h | 20 +- .../cgal/order_facets_around_edges.cpp | 10 +- .../copyleft/cgal/order_facets_around_edges.h | 10 +- src/libigl/igl/copyleft/cgal/orient2D.cpp | 8 +- src/libigl/igl/copyleft/cgal/orient2D.h | 8 +- src/libigl/igl/copyleft/cgal/orient3D.cpp | 8 +- src/libigl/igl/copyleft/cgal/orient3D.h | 8 +- src/libigl/igl/copyleft/cgal/outer_element.h | 8 +- src/libigl/igl/copyleft/cgal/outer_facet.cpp | 12 +- src/libigl/igl/copyleft/cgal/outer_facet.h | 8 +- src/libigl/igl/copyleft/cgal/outer_hull.h | 8 +- .../copyleft/cgal/peel_outer_hull_layers.cpp | 8 +- .../copyleft/cgal/peel_outer_hull_layers.h | 10 +- .../piecewise_constant_winding_number.cpp | 8 +- .../cgal/piecewise_constant_winding_number.h | 10 +- src/libigl/igl/copyleft/cgal/point_areas.cpp | 30 +- src/libigl/igl/copyleft/cgal/point_areas.h | 6 +- .../cgal/point_mesh_squared_distance.cpp | 26 +- .../cgal/point_mesh_squared_distance.h | 16 +- .../cgal/point_segment_squared_distance.cpp | 8 +- .../cgal/point_segment_squared_distance.h | 10 +- .../point_solid_signed_squared_distance.cpp | 8 +- .../point_solid_signed_squared_distance.h | 8 +- .../cgal/point_triangle_squared_distance.cpp | 8 +- .../cgal/point_triangle_squared_distance.h | 10 +- .../copyleft/cgal/points_inside_component.cpp | 10 +- .../copyleft/cgal/points_inside_component.h | 10 +- .../igl/copyleft/cgal/polyhedron_to_mesh.cpp | 10 +- .../igl/copyleft/cgal/polyhedron_to_mesh.h | 8 +- .../igl/copyleft/cgal/projected_delaunay.cpp | 22 +- .../igl/copyleft/cgal/projected_delaunay.h | 8 +- .../cgal/propagate_winding_numbers.cpp | 22 +- .../copyleft/cgal/propagate_winding_numbers.h | 8 +- .../cgal/relabel_small_immersed_cells.cpp | 8 +- .../cgal/relabel_small_immersed_cells.h | 8 +- .../copyleft/cgal/remesh_intersections.cpp | 76 +- .../igl/copyleft/cgal/remesh_intersections.h | 8 +- .../copyleft/cgal/remesh_self_intersections.h | 14 +- .../copyleft/cgal/resolve_intersections.cpp | 14 +- .../igl/copyleft/cgal/resolve_intersections.h | 14 +- src/libigl/igl/copyleft/cgal/row_to_point.cpp | 8 +- src/libigl/igl/copyleft/cgal/row_to_point.h | 10 +- .../cgal/segment_segment_squared_distance.cpp | 24 +- .../cgal/segment_segment_squared_distance.h | 10 +- .../cgal/signed_distance_isosurface.cpp | 16 +- .../cgal/signed_distance_isosurface.h | 10 +- .../igl/copyleft/cgal/snap_rounding.cpp | 16 +- src/libigl/igl/copyleft/cgal/snap_rounding.h | 14 +- .../cgal/string_to_mesh_boolean_type.cpp | 10 +- .../cgal/string_to_mesh_boolean_type.h | 10 +- .../igl/copyleft/cgal/subdivide_segments.cpp | 16 +- .../igl/copyleft/cgal/subdivide_segments.h | 16 +- .../igl/copyleft/cgal/submesh_aabb_tree.cpp | 14 +- .../igl/copyleft/cgal/submesh_aabb_tree.h | 10 +- .../triangle_triangle_squared_distance.cpp | 10 +- .../cgal/triangle_triangle_squared_distance.h | 10 +- .../igl/copyleft/cgal/trim_with_solid.cpp | 8 +- .../igl/copyleft/cgal/trim_with_solid.h | 8 +- src/libigl/igl/copyleft/cgal/wire_mesh.cpp | 14 +- src/libigl/igl/copyleft/cgal/wire_mesh.h | 2 +- .../igl/copyleft/cork/from_cork_mesh.cpp | 8 +- src/libigl/igl/copyleft/cork/from_cork_mesh.h | 8 +- src/libigl/igl/copyleft/cork/mesh_boolean.cpp | 8 +- src/libigl/igl/copyleft/cork/mesh_boolean.h | 8 +- src/libigl/igl/copyleft/cork/to_cork_mesh.cpp | 8 +- src/libigl/igl/copyleft/cork/to_cork_mesh.h | 8 +- src/libigl/igl/copyleft/marching_cubes.h | 6 +- .../igl/copyleft/marching_cubes_tables.h | 514 +- src/libigl/igl/copyleft/offset_surface.cpp | 4 +- src/libigl/igl/copyleft/offset_surface.h | 4 +- .../igl/copyleft/opengl2/render_to_tga.cpp | 12 +- .../igl/copyleft/opengl2/render_to_tga.h | 8 +- .../igl/copyleft/opengl2/texture_from_tga.cpp | 12 +- .../igl/copyleft/opengl2/texture_from_tga.h | 8 +- src/libigl/igl/copyleft/opengl2/tga.cpp | 64 +- src/libigl/igl/copyleft/opengl2/tga.h | 212 +- src/libigl/igl/copyleft/progressive_hulls.cpp | 8 +- src/libigl/igl/copyleft/progressive_hulls.h | 10 +- .../progressive_hulls_cost_and_placement.cpp | 12 +- .../progressive_hulls_cost_and_placement.h | 8 +- src/libigl/igl/copyleft/quadprog.cpp | 350 +- src/libigl/igl/copyleft/quadprog.h | 20 +- src/libigl/igl/copyleft/swept_volume.cpp | 2 +- src/libigl/igl/copyleft/swept_volume.h | 2 +- src/libigl/igl/copyleft/tetgen/README | 4 +- src/libigl/igl/copyleft/tetgen/cdt.cpp | 18 +- src/libigl/igl/copyleft/tetgen/cdt.h | 20 +- .../igl/copyleft/tetgen/mesh_to_tetgenio.cpp | 14 +- .../igl/copyleft/tetgen/mesh_to_tetgenio.h | 16 +- .../copyleft/tetgen/mesh_with_skeleton.cpp | 10 +- .../igl/copyleft/tetgen/mesh_with_skeleton.h | 8 +- .../copyleft/tetgen/read_into_tetgenio.cpp | 12 +- .../igl/copyleft/tetgen/read_into_tetgenio.h | 12 +- .../copyleft/tetgen/tetgenio_to_tetmesh.cpp | 12 +- .../igl/copyleft/tetgen/tetgenio_to_tetmesh.h | 16 +- .../igl/copyleft/tetgen/tetrahedralize.cpp | 78 +- .../igl/copyleft/tetgen/tetrahedralize.h | 66 +- src/libigl/igl/cotmatrix.cpp | 18 +- src/libigl/igl/cotmatrix.h | 20 +- src/libigl/igl/cotmatrix_entries.cpp | 14 +- src/libigl/igl/cotmatrix_entries.h | 12 +- src/libigl/igl/count.cpp | 12 +- src/libigl/igl/count.h | 16 +- src/libigl/igl/covariance_scatter_matrix.cpp | 12 +- src/libigl/igl/covariance_scatter_matrix.h | 12 +- src/libigl/igl/cross.cpp | 12 +- src/libigl/igl/cross.h | 8 +- src/libigl/igl/cross_field_missmatch.cpp | 4 +- src/libigl/igl/crouzeix_raviart_cotmatrix.cpp | 16 +- src/libigl/igl/crouzeix_raviart_cotmatrix.h | 16 +- .../igl/crouzeix_raviart_massmatrix.cpp | 16 +- src/libigl/igl/crouzeix_raviart_massmatrix.h | 18 +- src/libigl/igl/cumsum.cpp | 8 +- src/libigl/igl/cumsum.h | 8 +- src/libigl/igl/cut_mesh.cpp | 8 +- src/libigl/igl/cut_mesh.h | 8 +- src/libigl/igl/cut_mesh_from_singularities.h | 12 +- src/libigl/igl/cylinder.cpp | 8 +- src/libigl/igl/cylinder.h | 8 +- src/libigl/igl/dated_copy.cpp | 12 +- src/libigl/igl/dated_copy.h | 10 +- src/libigl/igl/decimate.cpp | 12 +- src/libigl/igl/decimate.h | 8 +- src/libigl/igl/deform_skeleton.cpp | 8 +- src/libigl/igl/deform_skeleton.h | 10 +- src/libigl/igl/delaunay_triangulation.h | 8 +- src/libigl/igl/deprecated.h | 12 +- src/libigl/igl/diag.h | 16 +- src/libigl/igl/dihedral_angles.cpp | 52 +- src/libigl/igl/dihedral_angles.h | 16 +- src/libigl/igl/dijkstra.cpp | 8 +- src/libigl/igl/directed_edge_orientations.cpp | 8 +- src/libigl/igl/directed_edge_orientations.h | 10 +- src/libigl/igl/directed_edge_parents.cpp | 8 +- src/libigl/igl/directed_edge_parents.h | 8 +- src/libigl/igl/dirname.cpp | 10 +- src/libigl/igl/dirname.h | 10 +- src/libigl/igl/dot.cpp | 10 +- src/libigl/igl/dot.h | 10 +- src/libigl/igl/doublearea.cpp | 6 +- src/libigl/igl/dqs.cpp | 8 +- src/libigl/igl/dqs.h | 10 +- src/libigl/igl/ears.h | 4 +- src/libigl/igl/edge_collapse_is_valid.cpp | 10 +- src/libigl/igl/edge_collapse_is_valid.h | 10 +- src/libigl/igl/edge_flaps.cpp | 8 +- src/libigl/igl/edge_flaps.h | 8 +- src/libigl/igl/edge_lengths.cpp | 2 +- src/libigl/igl/edge_lengths.h | 10 +- src/libigl/igl/edge_topology.h | 16 +- src/libigl/igl/edges.cpp | 10 +- src/libigl/igl/edges.h | 10 +- src/libigl/igl/edges_to_path.h | 4 +- src/libigl/igl/eigs.cpp | 10 +- src/libigl/igl/eigs.h | 12 +- src/libigl/igl/embree/EmbreeIntersector.h | 6 +- src/libigl/igl/embree/Embree_convenience.h | 8 +- src/libigl/igl/embree/ambient_occlusion.h | 8 +- src/libigl/igl/embree/bone_heat.cpp | 2 +- src/libigl/igl/embree/bone_visible.cpp | 22 +- src/libigl/igl/embree/bone_visible.h | 16 +- src/libigl/igl/embree/embree2/rtcore.h | 24 +- src/libigl/igl/embree/embree2/rtcore.isph | 20 +- .../igl/embree/embree2/rtcore_geometry.h | 40 +- .../igl/embree/embree2/rtcore_geometry.isph | 26 +- .../igl/embree/embree2/rtcore_geometry_user.h | 2 +- .../embree/embree2/rtcore_geometry_user.isph | 4 +- src/libigl/igl/embree/embree2/rtcore_ray.h | 50 +- src/libigl/igl/embree/embree2/rtcore_ray.isph | 28 +- src/libigl/igl/embree/embree2/rtcore_scene.h | 8 +- .../igl/embree/embree2/rtcore_scene.isph | 8 +- .../igl/embree/line_mesh_intersection.h | 18 +- .../igl/embree/reorient_facets_raycast.h | 16 +- .../igl/embree/shape_diameter_function.h | 8 +- src/libigl/igl/embree/unproject_in_mesh.h | 2 +- src/libigl/igl/embree/unproject_onto_mesh.h | 2 +- src/libigl/igl/exact_geodesic.cpp | 5504 +-- src/libigl/igl/exact_geodesic.h | 8 +- src/libigl/igl/example_fun.cpp | 8 +- src/libigl/igl/example_fun.h | 8 +- src/libigl/igl/exterior_edges.cpp | 8 +- src/libigl/igl/exterior_edges.h | 8 +- src/libigl/igl/extract_manifold_patches.cpp | 10 +- src/libigl/igl/extract_manifold_patches.h | 8 +- .../igl/extract_non_manifold_edge_curves.cpp | 8 +- .../igl/extract_non_manifold_edge_curves.h | 8 +- src/libigl/igl/face_areas.cpp | 12 +- src/libigl/igl/face_areas.h | 12 +- src/libigl/igl/face_occurrences.cpp | 8 +- src/libigl/igl/face_occurrences.h | 8 +- src/libigl/igl/faces_first.cpp | 20 +- src/libigl/igl/faces_first.h | 22 +- src/libigl/igl/facet_components.cpp | 10 +- src/libigl/igl/facet_components.h | 10 +- src/libigl/igl/fast_winding_number.cpp | 52 +- src/libigl/igl/fast_winding_number.h | 6 +- src/libigl/igl/file_contents_as_string.cpp | 10 +- src/libigl/igl/file_contents_as_string.h | 8 +- src/libigl/igl/file_dialog_open.cpp | 24 +- src/libigl/igl/file_dialog_open.h | 8 +- src/libigl/igl/file_dialog_save.cpp | 14 +- src/libigl/igl/file_dialog_save.h | 8 +- src/libigl/igl/file_exists.cpp | 8 +- src/libigl/igl/file_exists.h | 8 +- src/libigl/igl/find.cpp | 18 +- src/libigl/igl/find.h | 16 +- src/libigl/igl/find_zero.cpp | 2 +- src/libigl/igl/fit_plane.cpp | 10 +- src/libigl/igl/fit_plane.h | 10 +- src/libigl/igl/fit_rotations.cpp | 26 +- src/libigl/igl/fit_rotations.h | 14 +- src/libigl/igl/flip_avoiding_line_search.h | 14 +- src/libigl/igl/flip_edge.cpp | 8 +- src/libigl/igl/flip_edge.h | 8 +- src/libigl/igl/flood_fill.cpp | 18 +- src/libigl/igl/flood_fill.h | 10 +- src/libigl/igl/floor.h | 10 +- src/libigl/igl/for_each.h | 2 +- src/libigl/igl/forward_kinematics.cpp | 10 +- src/libigl/igl/forward_kinematics.h | 8 +- src/libigl/igl/frame_field_deformer.cpp | 240 +- src/libigl/igl/frame_to_cross_field.cpp | 16 +- src/libigl/igl/frustum.cpp | 8 +- src/libigl/igl/frustum.h | 10 +- src/libigl/igl/gaussian_curvature.cpp | 8 +- src/libigl/igl/gaussian_curvature.h | 8 +- src/libigl/igl/get_seconds.cpp | 10 +- src/libigl/igl/get_seconds.h | 10 +- src/libigl/igl/get_seconds_hires.cpp | 8 +- src/libigl/igl/get_seconds_hires.h | 8 +- src/libigl/igl/grad.cpp | 2 +- src/libigl/igl/grad.h | 92 +- src/libigl/igl/grid.cpp | 14 +- src/libigl/igl/grid.h | 14 +- src/libigl/igl/grid_search.cpp | 10 +- src/libigl/igl/grid_search.h | 12 +- src/libigl/igl/group_sum_matrix.cpp | 8 +- src/libigl/igl/group_sum_matrix.h | 12 +- src/libigl/igl/guess_extension.h | 2 +- src/libigl/igl/harmonic.h | 8 +- src/libigl/igl/harwell_boeing.cpp | 10 +- src/libigl/igl/harwell_boeing.h | 10 +- src/libigl/igl/hausdorff.cpp | 18 +- src/libigl/igl/hausdorff.h | 20 +- src/libigl/igl/hessian.h | 2 +- src/libigl/igl/hessian_energy.h | 2 +- src/libigl/igl/histc.cpp | 12 +- src/libigl/igl/histc.h | 8 +- src/libigl/igl/hsv_to_rgb.h | 14 +- src/libigl/igl/igl_inline.h | 8 +- src/libigl/igl/in_element.cpp | 8 +- .../igl/infinite_cost_stopping_condition.cpp | 14 +- .../igl/infinite_cost_stopping_condition.h | 12 +- src/libigl/igl/inradius.cpp | 14 +- src/libigl/igl/inradius.h | 12 +- src/libigl/igl/internal_angles.cpp | 12 +- src/libigl/igl/internal_angles.h | 8 +- src/libigl/igl/intersect.cpp | 10 +- src/libigl/igl/intersect.h | 8 +- src/libigl/igl/invert_diag.cpp | 10 +- src/libigl/igl/invert_diag.h | 10 +- src/libigl/igl/is_border_vertex.h | 14 +- src/libigl/igl/is_boundary_edge.cpp | 8 +- src/libigl/igl/is_boundary_edge.h | 12 +- src/libigl/igl/is_dir.cpp | 20 +- src/libigl/igl/is_dir.h | 10 +- src/libigl/igl/is_edge_manifold.h | 12 +- src/libigl/igl/is_file.cpp | 12 +- src/libigl/igl/is_file.h | 10 +- src/libigl/igl/is_planar.cpp | 8 +- src/libigl/igl/is_planar.h | 8 +- src/libigl/igl/is_readable.cpp | 8 +- src/libigl/igl/is_readable.h | 8 +- src/libigl/igl/is_sparse.cpp | 8 +- src/libigl/igl/is_sparse.h | 8 +- src/libigl/igl/is_stl.h | 4 +- src/libigl/igl/is_symmetric.cpp | 12 +- src/libigl/igl/is_symmetric.h | 8 +- src/libigl/igl/is_vertex_manifold.cpp | 8 +- src/libigl/igl/is_vertex_manifold.h | 10 +- src/libigl/igl/is_writable.cpp | 8 +- src/libigl/igl/is_writable.h | 8 +- src/libigl/igl/isdiag.cpp | 8 +- src/libigl/igl/isdiag.h | 8 +- src/libigl/igl/ismember.cpp | 8 +- src/libigl/igl/ismember.h | 8 +- src/libigl/igl/isolines.cpp | 18 +- src/libigl/igl/isolines.h | 2 +- src/libigl/igl/jet.h | 10 +- src/libigl/igl/knn.cpp | 22 +- src/libigl/igl/knn.h | 2 +- src/libigl/igl/launch_medit.cpp | 14 +- src/libigl/igl/launch_medit.h | 12 +- src/libigl/igl/lbs_matrix.cpp | 20 +- src/libigl/igl/lbs_matrix.h | 24 +- src/libigl/igl/lexicographic_triangulation.h | 8 +- src/libigl/igl/lim/lim.h | 8 +- src/libigl/igl/limit_faces.cpp | 12 +- src/libigl/igl/limit_faces.h | 12 +- src/libigl/igl/line_search.h | 12 +- src/libigl/igl/line_segment_in_rectangle.cpp | 8 +- src/libigl/igl/line_segment_in_rectangle.h | 8 +- src/libigl/igl/linprog.cpp | 8 +- src/libigl/igl/linprog.h | 10 +- src/libigl/igl/local_basis.h | 10 +- src/libigl/igl/look_at.cpp | 8 +- src/libigl/igl/look_at.h | 10 +- src/libigl/igl/loop.cpp | 40 +- src/libigl/igl/loop.h | 2 +- src/libigl/igl/lscm.cpp | 4 +- src/libigl/igl/lscm.h | 10 +- src/libigl/igl/map_vertices_to_circle.h | 4 +- src/libigl/igl/massmatrix.cpp | 20 +- src/libigl/igl/massmatrix.h | 16 +- src/libigl/igl/mat_max.cpp | 8 +- src/libigl/igl/mat_max.h | 10 +- src/libigl/igl/mat_min.cpp | 8 +- src/libigl/igl/mat_min.h | 12 +- src/libigl/igl/mat_to_quat.cpp | 18 +- src/libigl/igl/mat_to_quat.h | 8 +- src/libigl/igl/material_colors.h | 10 +- src/libigl/igl/matlab/MatlabWorkspace.h | 56 +- src/libigl/igl/matlab/MexStream.h | 24 +- src/libigl/igl/matlab/matlabinterface.cpp | 6 +- src/libigl/igl/matlab/matlabinterface.h | 28 +- src/libigl/igl/matlab/mexErrMsgTxt.cpp | 8 +- src/libigl/igl/matlab/mexErrMsgTxt.h | 8 +- src/libigl/igl/matlab/parse_rhs.cpp | 14 +- src/libigl/igl/matlab/parse_rhs.h | 16 +- src/libigl/igl/matlab/prepare_lhs.cpp | 12 +- src/libigl/igl/matlab/prepare_lhs.h | 10 +- src/libigl/igl/matlab/requires_arg.cpp | 8 +- src/libigl/igl/matlab/requires_arg.h | 10 +- src/libigl/igl/matlab/validate_arg.cpp | 8 +- src/libigl/igl/matlab/validate_arg.h | 8 +- src/libigl/igl/matlab_format.h | 10 +- src/libigl/igl/matrix_to_list.h | 14 +- src/libigl/igl/max.h | 2 +- .../igl/max_faces_stopping_condition.cpp | 14 +- src/libigl/igl/max_faces_stopping_condition.h | 12 +- src/libigl/igl/max_size.cpp | 10 +- src/libigl/igl/max_size.h | 8 +- src/libigl/igl/median.cpp | 8 +- src/libigl/igl/median.h | 8 +- src/libigl/igl/min.h | 2 +- src/libigl/igl/min_quad_dense.cpp | 16 +- src/libigl/igl/min_quad_dense.h | 10 +- src/libigl/igl/min_size.cpp | 10 +- src/libigl/igl/min_size.h | 8 +- src/libigl/igl/mod.cpp | 8 +- src/libigl/igl/mod.h | 8 +- src/libigl/igl/mode.cpp | 12 +- src/libigl/igl/mode.h | 10 +- src/libigl/igl/mosek/mosek_guarded.cpp | 10 +- src/libigl/igl/mosek/mosek_guarded.h | 10 +- src/libigl/igl/mosek/mosek_linprog.cpp | 18 +- src/libigl/igl/mosek/mosek_linprog.h | 10 +- src/libigl/igl/mosek/mosek_quadprog.cpp | 16 +- src/libigl/igl/mosek/mosek_quadprog.h | 18 +- src/libigl/igl/mvc.cpp | 48 +- src/libigl/igl/mvc.h | 24 +- src/libigl/igl/nchoosek.h | 4 +- src/libigl/igl/next_filename.cpp | 10 +- src/libigl/igl/next_filename.h | 12 +- src/libigl/igl/normal_derivative.h | 14 +- src/libigl/igl/normalize_quat.cpp | 8 +- src/libigl/igl/normalize_quat.h | 8 +- src/libigl/igl/normalize_row_lengths.cpp | 8 +- src/libigl/igl/normalize_row_lengths.h | 8 +- src/libigl/igl/normalize_row_sums.cpp | 8 +- src/libigl/igl/normalize_row_sums.h | 8 +- src/libigl/igl/null.cpp | 8 +- src/libigl/igl/null.h | 10 +- src/libigl/igl/octree.cpp | 42 +- src/libigl/igl/octree.h | 2 +- src/libigl/igl/on_boundary.h | 8 +- src/libigl/igl/opengl/ViewerCore.cpp | 2 +- src/libigl/igl/opengl/ViewerData.h | 2 +- .../igl/opengl/bind_vertex_attrib_array.cpp | 6 +- .../igl/opengl/bind_vertex_attrib_array.h | 6 +- src/libigl/igl/opengl/create_index_vbo.cpp | 8 +- src/libigl/igl/opengl/create_index_vbo.h | 8 +- src/libigl/igl/opengl/create_mesh_vbo.cpp | 8 +- src/libigl/igl/opengl/create_mesh_vbo.h | 14 +- .../igl/opengl/create_shader_program.cpp | 8 +- src/libigl/igl/opengl/create_shader_program.h | 8 +- src/libigl/igl/opengl/create_vector_vbo.cpp | 8 +- src/libigl/igl/opengl/create_vector_vbo.h | 8 +- .../igl/opengl/destroy_shader_program.cpp | 8 +- .../igl/opengl/destroy_shader_program.h | 12 +- src/libigl/igl/opengl/gl_type_size.cpp | 8 +- src/libigl/igl/opengl/gl_type_size.h | 8 +- .../igl/opengl/glfw/imgui/ImGuiHelpers.h | 34 +- .../igl/opengl/init_render_to_texture.h | 6 +- src/libigl/igl/opengl/load_shader.cpp | 8 +- src/libigl/igl/opengl/load_shader.h | 14 +- .../igl/opengl/print_program_info_log.cpp | 12 +- .../igl/opengl/print_program_info_log.h | 8 +- .../igl/opengl/print_shader_info_log.cpp | 10 +- src/libigl/igl/opengl/print_shader_info_log.h | 8 +- src/libigl/igl/opengl/report_gl_error.cpp | 8 +- src/libigl/igl/opengl/report_gl_error.h | 12 +- .../igl/opengl/uniform_type_to_string.cpp | 8 +- .../igl/opengl/uniform_type_to_string.h | 8 +- src/libigl/igl/opengl/vertex_array.cpp | 2 +- src/libigl/igl/opengl2/MouseController.h | 38 +- src/libigl/igl/opengl2/RotateWidget.h | 34 +- src/libigl/igl/opengl2/TranslateWidget.h | 12 +- src/libigl/igl/opengl2/draw_beach_ball.cpp | 10 +- src/libigl/igl/opengl2/draw_beach_ball.h | 8 +- src/libigl/igl/opengl2/draw_floor.cpp | 8 +- src/libigl/igl/opengl2/draw_floor.h | 22 +- src/libigl/igl/opengl2/draw_mesh.cpp | 10 +- src/libigl/igl/opengl2/draw_mesh.h | 14 +- src/libigl/igl/opengl2/draw_point.cpp | 12 +- src/libigl/igl/opengl2/draw_point.h | 10 +- src/libigl/igl/opengl2/draw_skeleton_3d.h | 2 +- src/libigl/igl/opengl2/flare_textures.h | 8 +- src/libigl/igl/opengl2/glext.h | 12 +- src/libigl/igl/opengl2/glu.h | 10 +- src/libigl/igl/opengl2/lens_flare.cpp | 10 +- src/libigl/igl/opengl2/lens_flare.h | 16 +- src/libigl/igl/opengl2/model_proj_viewport.h | 4 +- src/libigl/igl/opengl2/print_gl_get.cpp | 8 +- src/libigl/igl/opengl2/print_gl_get.h | 8 +- src/libigl/igl/opengl2/right_axis.cpp | 8 +- src/libigl/igl/opengl2/right_axis.h | 14 +- src/libigl/igl/opengl2/shine_textures.h | 8 +- src/libigl/igl/opengl2/sort_triangles.cpp | 8 +- src/libigl/igl/opengl2/sort_triangles.h | 8 +- .../igl/opengl2/unproject_to_zero_plane.cpp | 10 +- .../igl/opengl2/unproject_to_zero_plane.h | 8 +- src/libigl/igl/opengl2/up_axis.cpp | 8 +- src/libigl/igl/opengl2/up_axis.h | 14 +- src/libigl/igl/opengl2/view_axis.cpp | 8 +- src/libigl/igl/opengl2/view_axis.h | 14 +- src/libigl/igl/orient_outward.cpp | 16 +- src/libigl/igl/orient_outward.h | 16 +- src/libigl/igl/orientable_patches.cpp | 12 +- src/libigl/igl/orientable_patches.h | 18 +- src/libigl/igl/oriented_facets.cpp | 8 +- src/libigl/igl/oriented_facets.h | 8 +- src/libigl/igl/orth.cpp | 12 +- src/libigl/igl/orth.h | 20 +- src/libigl/igl/ortho.cpp | 8 +- src/libigl/igl/ortho.h | 10 +- src/libigl/igl/outer_element.cpp | 14 +- src/libigl/igl/outer_element.h | 8 +- src/libigl/igl/parallel_for.h | 46 +- src/libigl/igl/parallel_transport_angles.cpp | 8 +- src/libigl/igl/partition.cpp | 8 +- src/libigl/igl/partition.h | 12 +- src/libigl/igl/parula.h | 14 +- src/libigl/igl/path_to_executable.cpp | 8 +- src/libigl/igl/path_to_executable.h | 10 +- src/libigl/igl/pathinfo.cpp | 10 +- src/libigl/igl/per_corner_normals.cpp | 12 +- src/libigl/igl/per_corner_normals.h | 22 +- src/libigl/igl/per_edge_normals.cpp | 24 +- src/libigl/igl/per_edge_normals.h | 20 +- src/libigl/igl/per_face_normals.h | 8 +- .../igl/per_vertex_attribute_smoothing.h | 8 +- src/libigl/igl/per_vertex_normals.h | 14 +- .../per_vertex_point_to_plane_quadrics.cpp | 26 +- .../igl/per_vertex_point_to_plane_quadrics.h | 8 +- .../igl/piecewise_constant_winding_number.cpp | 8 +- .../igl/piecewise_constant_winding_number.h | 8 +- src/libigl/igl/pinv.cpp | 4 +- src/libigl/igl/pinv.h | 2 +- src/libigl/igl/planarize_quad_mesh.cpp | 48 +- src/libigl/igl/planarize_quad_mesh.h | 12 +- src/libigl/igl/ply.h | 412 +- src/libigl/igl/png/render_to_png.h | 8 +- src/libigl/igl/png/render_to_png_async.h | 8 +- src/libigl/igl/png/texture_from_file.cpp | 2 +- src/libigl/igl/png/texture_from_file.h | 8 +- src/libigl/igl/point_in_circle.cpp | 12 +- src/libigl/igl/point_in_circle.h | 12 +- src/libigl/igl/point_in_poly.cpp | 14 +- src/libigl/igl/point_in_poly.h | 18 +- src/libigl/igl/point_mesh_squared_distance.h | 10 +- .../igl/point_simplex_squared_distance.cpp | 12 +- .../igl/point_simplex_squared_distance.h | 18 +- src/libigl/igl/polar_dec.h | 8 +- src/libigl/igl/polar_svd.h | 8 +- src/libigl/igl/polar_svd3x3.h | 8 +- src/libigl/igl/principal_curvature.h | 8 +- src/libigl/igl/print_ijv.cpp | 8 +- src/libigl/igl/print_ijv.h | 10 +- src/libigl/igl/print_vector.cpp | 10 +- src/libigl/igl/print_vector.h | 10 +- src/libigl/igl/procrustes.h | 44 +- .../igl/project_isometrically_to_plane.cpp | 22 +- .../igl/project_isometrically_to_plane.h | 18 +- src/libigl/igl/project_to_line.cpp | 8 +- src/libigl/igl/project_to_line.h | 20 +- src/libigl/igl/project_to_line_segment.h | 18 +- src/libigl/igl/pseudonormal_test.cpp | 10 +- src/libigl/igl/pseudonormal_test.h | 10 +- src/libigl/igl/pso.cpp | 12 +- src/libigl/igl/pso.h | 16 +- src/libigl/igl/qslim.cpp | 8 +- src/libigl/igl/qslim.h | 8 +- .../qslim_optimal_collapse_edge_callbacks.cpp | 10 +- .../qslim_optimal_collapse_edge_callbacks.h | 12 +- src/libigl/igl/quad_planarity.cpp | 10 +- src/libigl/igl/quad_planarity.h | 8 +- .../igl/quadric_binary_plus_operator.cpp | 12 +- src/libigl/igl/quadric_binary_plus_operator.h | 12 +- src/libigl/igl/quat_conjugate.cpp | 10 +- src/libigl/igl/quat_conjugate.h | 10 +- src/libigl/igl/quat_mult.cpp | 10 +- src/libigl/igl/quat_mult.h | 10 +- src/libigl/igl/quat_to_axis_angle.cpp | 12 +- src/libigl/igl/quat_to_axis_angle.h | 12 +- src/libigl/igl/quat_to_mat.cpp | 8 +- src/libigl/igl/quat_to_mat.h | 10 +- src/libigl/igl/quats_to_column.cpp | 8 +- src/libigl/igl/quats_to_column.h | 8 +- src/libigl/igl/ramer_douglas_peucker.cpp | 4 +- src/libigl/igl/ramer_douglas_peucker.h | 4 +- src/libigl/igl/random_dir.h | 8 +- src/libigl/igl/random_points_on_mesh.cpp | 8 +- src/libigl/igl/random_points_on_mesh.h | 10 +- src/libigl/igl/random_quaternion.cpp | 10 +- src/libigl/igl/random_quaternion.h | 8 +- src/libigl/igl/random_search.cpp | 6 +- src/libigl/igl/random_search.h | 10 +- src/libigl/igl/randperm.cpp | 10 +- src/libigl/igl/randperm.h | 8 +- src/libigl/igl/ray_box_intersect.h | 8 +- src/libigl/igl/ray_mesh_intersect.cpp | 22 +- src/libigl/igl/ray_mesh_intersect.h | 16 +- src/libigl/igl/ray_sphere_intersect.cpp | 18 +- src/libigl/igl/ray_sphere_intersect.h | 16 +- src/libigl/igl/raytri.c | 78 +- src/libigl/igl/readBF.cpp | 14 +- src/libigl/igl/readBF.h | 14 +- src/libigl/igl/readCSV.cpp | 20 +- src/libigl/igl/readCSV.h | 14 +- src/libigl/igl/readDMAT.cpp | 16 +- src/libigl/igl/readDMAT.h | 12 +- src/libigl/igl/readMESH.cpp | 8 +- src/libigl/igl/readMESH.h | 12 +- src/libigl/igl/readMSH.cpp | 30 +- src/libigl/igl/readMSH.h | 10 +- src/libigl/igl/readNODE.cpp | 10 +- src/libigl/igl/readNODE.h | 8 +- src/libigl/igl/readOBJ.cpp | 8 +- src/libigl/igl/readOBJ.h | 22 +- src/libigl/igl/readOFF.h | 20 +- src/libigl/igl/readPLY.cpp | 12 +- src/libigl/igl/readPLY.h | 12 +- src/libigl/igl/readSTL.cpp | 16 +- src/libigl/igl/readSTL.h | 14 +- src/libigl/igl/readTGF.cpp | 14 +- src/libigl/igl/readTGF.h | 10 +- src/libigl/igl/readWRL.cpp | 8 +- src/libigl/igl/readWRL.h | 14 +- src/libigl/igl/read_triangle_mesh.h | 4 +- src/libigl/igl/redux.h | 2 +- src/libigl/igl/remesh_along_isoline.cpp | 8 +- src/libigl/igl/remesh_along_isoline.h | 10 +- src/libigl/igl/remove_duplicate_vertices.cpp | 20 +- src/libigl/igl/remove_duplicate_vertices.h | 22 +- src/libigl/igl/remove_duplicates.cpp | 18 +- src/libigl/igl/remove_duplicates.h | 16 +- src/libigl/igl/remove_unreferenced.h | 12 +- src/libigl/igl/reorder.cpp | 8 +- src/libigl/igl/reorder.h | 8 +- src/libigl/igl/repdiag.cpp | 8 +- src/libigl/igl/repdiag.h | 10 +- src/libigl/igl/repmat.cpp | 8 +- src/libigl/igl/repmat.h | 8 +- src/libigl/igl/resolve_duplicated_faces.cpp | 10 +- src/libigl/igl/resolve_duplicated_faces.h | 8 +- src/libigl/igl/rgb_to_hsv.cpp | 10 +- src/libigl/igl/rgb_to_hsv.h | 10 +- src/libigl/igl/rotate_by_quat.cpp | 12 +- src/libigl/igl/rotate_by_quat.h | 10 +- src/libigl/igl/rotate_vectors.cpp | 2 +- .../igl/rotation_matrix_from_directions.h | 4 +- src/libigl/igl/round.h | 8 +- src/libigl/igl/rows_to_matrix.cpp | 8 +- src/libigl/igl/rows_to_matrix.h | 10 +- src/libigl/igl/sample_edges.cpp | 8 +- src/libigl/igl/sample_edges.h | 8 +- src/libigl/igl/seam_edges.cpp | 98 +- src/libigl/igl/seam_edges.h | 14 +- src/libigl/igl/serialize.h | 396 +- src/libigl/igl/setdiff.h | 8 +- src/libigl/igl/setunion.h | 8 +- src/libigl/igl/setxor.h | 8 +- src/libigl/igl/shape_diameter_function.cpp | 8 +- src/libigl/igl/shape_diameter_function.h | 8 +- src/libigl/igl/shapeup.cpp | 68 +- src/libigl/igl/shapeup.h | 34 +- src/libigl/igl/shortest_edge_and_midpoint.cpp | 8 +- src/libigl/igl/shortest_edge_and_midpoint.h | 8 +- src/libigl/igl/signed_angle.h | 6 +- src/libigl/igl/signed_distance.cpp | 12 +- src/libigl/igl/signed_distance.h | 10 +- src/libigl/igl/simplify_polyhedron.cpp | 10 +- src/libigl/igl/simplify_polyhedron.h | 8 +- src/libigl/igl/slice.h | 18 +- src/libigl/igl/slice_cached.h | 14 +- src/libigl/igl/slice_into.h | 10 +- src/libigl/igl/slice_mask.cpp | 8 +- src/libigl/igl/slice_mask.h | 10 +- src/libigl/igl/slice_tets.cpp | 40 +- src/libigl/igl/slice_tets.h | 24 +- src/libigl/igl/slim.cpp | 16 +- src/libigl/igl/slim.h | 8 +- src/libigl/igl/snap_points.cpp | 26 +- src/libigl/igl/snap_points.h | 28 +- src/libigl/igl/snap_to_canonical_view_quat.h | 8 +- src/libigl/igl/snap_to_fixed_up.cpp | 8 +- src/libigl/igl/snap_to_fixed_up.h | 8 +- src/libigl/igl/solid_angle.cpp | 4 +- src/libigl/igl/solid_angle.h | 8 +- src/libigl/igl/sort.h | 8 +- src/libigl/igl/sort_angles.cpp | 8 +- src/libigl/igl/sort_angles.h | 8 +- src/libigl/igl/sort_triangles.cpp | 32 +- src/libigl/igl/sort_triangles.h | 8 +- src/libigl/igl/sort_vectors_ccw.cpp | 8 +- src/libigl/igl/sort_vectors_ccw.h | 2 +- src/libigl/igl/sortrows.h | 8 +- src/libigl/igl/sparse.h | 16 +- src/libigl/igl/sparse_cached.cpp | 10 +- src/libigl/igl/sparse_cached.h | 16 +- src/libigl/igl/speye.cpp | 8 +- src/libigl/igl/speye.h | 8 +- src/libigl/igl/squared_edge_lengths.cpp | 2 +- src/libigl/igl/squared_edge_lengths.h | 8 +- src/libigl/igl/stdin_to_temp.cpp | 8 +- src/libigl/igl/stdin_to_temp.h | 8 +- src/libigl/igl/straighten_seams.cpp | 18 +- src/libigl/igl/straighten_seams.h | 4 +- src/libigl/igl/sum.cpp | 12 +- src/libigl/igl/sum.h | 18 +- src/libigl/igl/svd3x3.cpp | 12 +- src/libigl/igl/svd3x3.h | 80 +- src/libigl/igl/svd3x3_avx.h | 80 +- src/libigl/igl/svd3x3_sse.cpp | 18 +- src/libigl/igl/svd3x3_sse.h | 74 +- src/libigl/igl/swept_volume_bounding_box.cpp | 8 +- src/libigl/igl/swept_volume_bounding_box.h | 10 +- .../igl/swept_volume_signed_distance.cpp | 18 +- src/libigl/igl/swept_volume_signed_distance.h | 10 +- src/libigl/igl/trackball.h | 8 +- src/libigl/igl/transpose_blocks.cpp | 8 +- src/libigl/igl/transpose_blocks.h | 10 +- src/libigl/igl/triangle/cdt.cpp | 2 +- src/libigl/igl/triangle/cdt.h | 8 +- src/libigl/igl/triangle/triangulate.cpp | 4 +- src/libigl/igl/triangle/triangulate.h | 8 +- src/libigl/igl/triangle_fan.cpp | 8 +- src/libigl/igl/triangle_fan.h | 10 +- src/libigl/igl/triangle_triangle_adjacency.h | 12 +- src/libigl/igl/triangles_from_strip.cpp | 8 +- src/libigl/igl/triangles_from_strip.h | 8 +- src/libigl/igl/two_axis_valuator_fixed_up.h | 8 +- .../igl/uniformly_sample_two_manifold.h | 14 +- src/libigl/igl/unique_edge_map.cpp | 10 +- src/libigl/igl/unique_edge_map.h | 8 +- src/libigl/igl/unique_simplices.cpp | 8 +- src/libigl/igl/unique_simplices.h | 8 +- src/libigl/igl/unproject.cpp | 2 +- src/libigl/igl/unproject_ray.h | 4 +- src/libigl/igl/unzip_corners.cpp | 8 +- src/libigl/igl/unzip_corners.h | 8 +- src/libigl/igl/upsample.cpp | 2 +- src/libigl/igl/upsample.h | 14 +- src/libigl/igl/vector_area_matrix.cpp | 4 +- src/libigl/igl/verbose.h | 8 +- src/libigl/igl/volume.h | 14 +- src/libigl/igl/voxel_grid.cpp | 14 +- src/libigl/igl/voxel_grid.h | 12 +- src/libigl/igl/winding_number.h | 8 +- src/libigl/igl/writeBF.cpp | 10 +- src/libigl/igl/writeBF.h | 10 +- src/libigl/igl/writeDMAT.cpp | 16 +- src/libigl/igl/writeDMAT.h | 14 +- src/libigl/igl/writeMESH.cpp | 16 +- src/libigl/igl/writeMESH.h | 10 +- src/libigl/igl/writeOBJ.cpp | 6 +- src/libigl/igl/writeOBJ.h | 16 +- src/libigl/igl/writeOFF.cpp | 2 +- src/libigl/igl/writeOFF.h | 10 +- src/libigl/igl/writePLY.cpp | 2 +- src/libigl/igl/writePLY.h | 10 +- src/libigl/igl/writeSTL.cpp | 8 +- src/libigl/igl/writeSTL.h | 10 +- src/libigl/igl/writeTGF.cpp | 12 +- src/libigl/igl/writeTGF.h | 10 +- src/libigl/igl/write_triangle_mesh.h | 6 +- .../igl/xml/ReAntTweakBarXMLSerialization.h | 96 +- src/libigl/igl/xml/serialization_test.skip | 160 +- src/libigl/igl/xml/serialize_xml.cpp | 290 +- src/libigl/igl/xml/write_triangle_mesh.h | 2 +- src/libnest2d/include/libnest2d/common.hpp | 18 +- .../include/libnest2d/geometry_traits.hpp | 130 +- .../include/libnest2d/geometry_traits_nfp.hpp | 10 +- src/libnest2d/include/libnest2d/libnest2d.hpp | 8 +- src/libnest2d/include/libnest2d/nester.hpp | 22 +- src/libnest2d/include/libnest2d/parallel.hpp | 4 +- .../include/libnest2d/placers/nfpplacer.hpp | 8 +- .../libnest2d/selections/djd_heuristic.hpp | 2 +- .../include/libnest2d/selections/filler.hpp | 6 +- .../include/libnest2d/selections/firstfit.hpp | 10 +- .../include/libnest2d/utils/rotcalipers.hpp | 38 +- src/libslic3r/AABBTreeIndirect.hpp | 1050 +- src/libslic3r/AppConfig.cpp | 70 +- src/libslic3r/AppConfig.hpp | 508 +- .../LimitedBeadingStrategy.cpp | 4 +- .../LimitedBeadingStrategy.hpp | 8 +- .../OuterWallInsetBeadingStrategy.hpp | 10 +- .../WideningBeadingStrategy.cpp | 2 +- .../Arachne/SkeletalTrapezoidation.cpp | 76 +- .../Arachne/SkeletalTrapezoidationGraph.cpp | 30 +- .../Arachne/SkeletalTrapezoidationGraph.hpp | 8 +- .../Arachne/utils/ExtrusionJunction.hpp | 26 +- src/libslic3r/Arachne/utils/SparseGrid.hpp | 2 +- src/libslic3r/Arachne/utils/VoronoiUtils.cpp | 12 +- src/libslic3r/Arachne/utils/linearAlg2D.hpp | 4 +- src/libslic3r/Arrange.cpp | 100 +- src/libslic3r/Arrange.hpp | 30 +- src/libslic3r/BlacklistedLibraryCheck.cpp | 4 +- src/libslic3r/BlacklistedLibraryCheck.hpp | 4 +- src/libslic3r/BoundingBox.hpp | 24 +- src/libslic3r/BridgeDetector.cpp | 40 +- src/libslic3r/BridgeDetector.hpp | 8 +- src/libslic3r/Brim.cpp | 220 +- src/libslic3r/BuildVolume.cpp | 14 +- src/libslic3r/BuildVolume.hpp | 4 +- src/libslic3r/CMakeLists.txt | 4 +- src/libslic3r/ClipperUtils.cpp | 600 +- src/libslic3r/ClipperUtils.hpp | 64 +- src/libslic3r/Config.cpp | 222 +- src/libslic3r/Config.hpp | 726 +- src/libslic3r/CustomGCode.cpp | 14 +- src/libslic3r/CustomGCode.hpp | 14 +- src/libslic3r/EdgeGrid.cpp | 2898 +- src/libslic3r/EdgeGrid.hpp | 692 +- src/libslic3r/ElephantFootCompensation.cpp | 998 +- src/libslic3r/ExPolygon.cpp | 36 +- src/libslic3r/ExPolygon.hpp | 66 +- src/libslic3r/ExPolygonCollection.hpp | 2 +- src/libslic3r/Extruder.cpp | 4 +- src/libslic3r/Extruder.hpp | 4 +- src/libslic3r/ExtrusionEntity.cpp | 24 +- src/libslic3r/ExtrusionEntity.hpp | 30 +- src/libslic3r/ExtrusionEntityCollection.cpp | 12 +- src/libslic3r/ExtrusionEntityCollection.hpp | 16 +- src/libslic3r/ExtrusionSimulator.cpp | 1556 +- src/libslic3r/ExtrusionSimulator.hpp | 22 +- src/libslic3r/Fill/Fill.cpp | 34 +- src/libslic3r/Fill/Fill.hpp | 4 +- src/libslic3r/Fill/Fill3DHoneycomb.cpp | 24 +- src/libslic3r/Fill/Fill3DHoneycomb.hpp | 12 +- src/libslic3r/Fill/FillAdaptive.cpp | 28 +- src/libslic3r/Fill/FillAdaptive.hpp | 22 +- src/libslic3r/Fill/FillBase.cpp | 154 +- src/libslic3r/Fill/FillBase.hpp | 4 +- src/libslic3r/Fill/FillConcentric.cpp | 16 +- src/libslic3r/Fill/FillGyroid.cpp | 6 +- src/libslic3r/Fill/FillGyroid.hpp | 6 +- src/libslic3r/Fill/FillHoneycomb.cpp | 10 +- src/libslic3r/Fill/FillHoneycomb.hpp | 52 +- src/libslic3r/Fill/FillLightning.hpp | 2 +- src/libslic3r/Fill/FillLine.cpp | 6 +- src/libslic3r/Fill/FillLine.hpp | 52 +- src/libslic3r/Fill/FillPlanePath.cpp | 14 +- src/libslic3r/Fill/FillPlanePath.hpp | 6 +- src/libslic3r/Fill/FillRectilinear.cpp | 322 +- src/libslic3r/Fill/FillSmooth.cpp | 16 +- src/libslic3r/Fill/FillSmooth.hpp | 2 +- .../Fill/Lightning/DistanceField.hpp | 2 +- src/libslic3r/Fill/Lightning/Generator.hpp | 2 +- src/libslic3r/Fill/Lightning/Layer.cpp | 2 +- src/libslic3r/Fill/Lightning/TreeNode.cpp | 6 +- src/libslic3r/Fill/Lightning/TreeNode.hpp | 12 +- src/libslic3r/Flow.cpp | 50 +- src/libslic3r/Flow.hpp | 28 +- src/libslic3r/Format/3mf.cpp | 104 +- src/libslic3r/Format/3mf.hpp | 2 +- src/libslic3r/Format/AMF.cpp | 64 +- src/libslic3r/Format/BBConfig.cpp | 26 +- src/libslic3r/Format/CWS.cpp | 36 +- src/libslic3r/Format/Format.cpp | 2 +- src/libslic3r/Format/Format.hpp | 2 +- src/libslic3r/Format/OBJ.cpp | 14 +- src/libslic3r/Format/SL1.cpp | 38 +- src/libslic3r/Format/SL1.hpp | 8 +- src/libslic3r/Format/SLAArchive.cpp | 10 +- src/libslic3r/Format/SLAArchive.hpp | 10 +- src/libslic3r/Format/STEP.cpp | 2 +- src/libslic3r/Format/bbs_3mf.cpp | 170 +- src/libslic3r/Format/objparser.cpp | 926 +- src/libslic3r/Format/objparser.hpp | 94 +- src/libslic3r/GCode.cpp | 482 +- src/libslic3r/GCode.hpp | 98 +- .../GCode/AvoidCrossingPerimeters.cpp | 26 +- src/libslic3r/GCode/CoolingBuffer.cpp | 42 +- src/libslic3r/GCode/CoolingBuffer.hpp | 6 +- src/libslic3r/GCode/FanMover.cpp | 2 +- src/libslic3r/GCode/FanMover.hpp | 2 +- src/libslic3r/GCode/FindReplace.cpp | 8 +- src/libslic3r/GCode/FindReplace.hpp | 2 +- src/libslic3r/GCode/GCodeProcessor.cpp | 42 +- src/libslic3r/GCode/GCodeProcessor.hpp | 8 +- src/libslic3r/GCode/PostProcessor.cpp | 126 +- src/libslic3r/GCode/PostProcessor.hpp | 4 +- src/libslic3r/GCode/PressureEqualizer.cpp | 28 +- src/libslic3r/GCode/PressureEqualizer.hpp | 14 +- src/libslic3r/GCode/PrintExtents.cpp | 10 +- src/libslic3r/GCode/SeamPlacer.cpp | 10 +- src/libslic3r/GCode/SpiralVase.cpp | 10 +- src/libslic3r/GCode/SpiralVase.hpp | 14 +- src/libslic3r/GCode/Thumbnails.cpp | 4 +- src/libslic3r/GCode/Thumbnails.hpp | 4 +- src/libslic3r/GCode/ToolOrdering.cpp | 206 +- src/libslic3r/GCode/ToolOrdering.hpp | 54 +- src/libslic3r/GCode/WipeTower.cpp | 758 +- src/libslic3r/GCode/WipeTower.hpp | 376 +- src/libslic3r/GCodeReader.cpp | 34 +- src/libslic3r/GCodeReader.hpp | 10 +- src/libslic3r/GCodeSender.cpp | 90 +- src/libslic3r/GCodeSender.hpp | 8 +- src/libslic3r/GCodeWriter.cpp | 56 +- src/libslic3r/GCodeWriter.hpp | 18 +- src/libslic3r/Geometry.cpp | 44 +- src/libslic3r/Geometry.hpp | 60 +- src/libslic3r/Geometry/ArcFitter.cpp | 2 +- src/libslic3r/Geometry/Circle.cpp | 8 +- src/libslic3r/Geometry/Circle.hpp | 68 +- src/libslic3r/Geometry/MedialAxis.cpp | 112 +- src/libslic3r/Geometry/MedialAxis.hpp | 6 +- src/libslic3r/Geometry/Voronoi.hpp | 4 +- src/libslic3r/Geometry/VoronoiOffset.cpp | 134 +- src/libslic3r/Geometry/VoronoiOffset.hpp | 132 +- src/libslic3r/I18N.hpp | 10 +- src/libslic3r/Int128.hpp | 390 +- src/libslic3r/KDTreeIndirect.hpp | 4 +- src/libslic3r/Layer.cpp | 50 +- src/libslic3r/Layer.hpp | 14 +- src/libslic3r/LayerRegion.cpp | 46 +- src/libslic3r/Line.cpp | 14 +- src/libslic3r/Line.hpp | 4 +- src/libslic3r/MTUtils.hpp | 16 +- src/libslic3r/MarchingSquares.hpp | 114 +- src/libslic3r/MeshBoolean.cpp | 22 +- src/libslic3r/MeshBoolean.hpp | 4 +- src/libslic3r/MeshSplitImpl.hpp | 10 +- src/libslic3r/Milling/MillingPostProcess.cpp | 4 +- src/libslic3r/Milling/MillingPostProcess.hpp | 2 +- src/libslic3r/MinAreaBoundingBox.hpp | 22 +- src/libslic3r/Model.cpp | 224 +- src/libslic3r/Model.hpp | 394 +- src/libslic3r/ModelArrange.cpp | 10 +- src/libslic3r/ModelArrange.hpp | 6 +- src/libslic3r/MultiMaterialSegmentation.cpp | 2 +- src/libslic3r/MultiPoint.cpp | 36 +- src/libslic3r/MultiPoint.hpp | 4 +- src/libslic3r/MutablePolygon.cpp | 8 +- src/libslic3r/MutablePolygon.hpp | 10 +- src/libslic3r/MutablePriorityQueue.hpp | 630 +- src/libslic3r/ObjectID.hpp | 96 +- src/libslic3r/OpenVDBUtils.cpp | 2 +- src/libslic3r/OpenVDBUtils.hpp | 2 +- src/libslic3r/PNGReadWrite.cpp | 2 +- src/libslic3r/PerimeterGenerator.cpp | 102 +- src/libslic3r/PerimeterGenerator.hpp | 4 +- src/libslic3r/PlaceholderParser.cpp | 216 +- src/libslic3r/PlaceholderParser.hpp | 16 +- src/libslic3r/Platform.cpp | 72 +- src/libslic3r/Platform.hpp | 20 +- src/libslic3r/Point.cpp | 28 +- src/libslic3r/Point.hpp | 118 +- src/libslic3r/Polygon.cpp | 36 +- src/libslic3r/Polygon.hpp | 30 +- src/libslic3r/PolygonTrimmer.cpp | 84 +- src/libslic3r/PolygonTrimmer.hpp | 10 +- src/libslic3r/Polyline.cpp | 10 +- src/libslic3r/Polyline.hpp | 6 +- src/libslic3r/Preset.cpp | 262 +- src/libslic3r/Preset.hpp | 108 +- src/libslic3r/PresetBundle.cpp | 400 +- src/libslic3r/PresetBundle.hpp | 20 +- src/libslic3r/Print.cpp | 204 +- src/libslic3r/Print.hpp | 92 +- src/libslic3r/PrintApply.cpp | 236 +- src/libslic3r/PrintBase.cpp | 52 +- src/libslic3r/PrintBase.hpp | 170 +- src/libslic3r/PrintConfig.cpp | 100 +- src/libslic3r/PrintConfig.hpp | 36 +- src/libslic3r/PrintObject.cpp | 68 +- src/libslic3r/PrintObjectSlice.cpp | 76 +- src/libslic3r/PrintRegion.cpp | 20 +- src/libslic3r/QuadricEdgeCollapse.cpp | 94 +- src/libslic3r/SLA/AGGRaster.hpp | 66 +- src/libslic3r/SLA/Hollowing.cpp | 10 +- src/libslic3r/SLA/Hollowing.hpp | 8 +- src/libslic3r/SLA/IndexedMesh.hpp | 26 +- src/libslic3r/SLA/JobController.hpp | 6 +- src/libslic3r/SLA/Pad.cpp | 12 +- src/libslic3r/SLA/RasterBase.cpp | 24 +- src/libslic3r/SLA/RasterBase.hpp | 28 +- src/libslic3r/SLA/RasterToPolygons.cpp | 38 +- src/libslic3r/SLA/SpatIndex.hpp | 14 +- src/libslic3r/SLA/SupportPoint.hpp | 14 +- src/libslic3r/SLA/SupportPointGenerator.cpp | 8 +- src/libslic3r/SLA/SupportPointGenerator.hpp | 64 +- src/libslic3r/SLA/SupportTree.cpp | 6 +- src/libslic3r/SLA/SupportTree.hpp | 22 +- src/libslic3r/SLA/SupportTreeBuilder.cpp | 34 +- src/libslic3r/SLA/SupportTreeBuilder.hpp | 108 +- src/libslic3r/SLA/SupportTreeBuildsteps.hpp | 12 +- src/libslic3r/SLAPrint.cpp | 58 +- src/libslic3r/SLAPrint.hpp | 74 +- src/libslic3r/SLAPrintSteps.hpp | 30 +- src/libslic3r/SVG.hpp | 30 +- src/libslic3r/Semver.hpp | 328 +- src/libslic3r/ShortestPath.cpp | 3346 +- src/libslic3r/ShortestPath.hpp | 12 +- src/libslic3r/Slicing.cpp | 140 +- src/libslic3r/Slicing.hpp | 28 +- src/libslic3r/SlicingAdaptive.cpp | 194 +- src/libslic3r/SlicingAdaptive.hpp | 20 +- src/libslic3r/SupportMaterial.cpp | 278 +- src/libslic3r/SupportMaterial.hpp | 432 +- src/libslic3r/Surface.cpp | 4 +- src/libslic3r/Surface.hpp | 56 +- src/libslic3r/SurfaceCollection.cpp | 2 +- src/libslic3r/SurfaceCollection.hpp | 8 +- src/libslic3r/Technologies.hpp | 2 +- src/libslic3r/Tesselate.cpp | 4 +- src/libslic3r/Thread.cpp | 232 +- src/libslic3r/Thread.hpp | 6 +- src/libslic3r/TriangleMesh.cpp | 32 +- src/libslic3r/TriangleMesh.hpp | 4 +- src/libslic3r/TriangleMeshSlicer.cpp | 104 +- src/libslic3r/TriangleMeshSlicer.hpp | 6 +- src/libslic3r/TriangleSelector.cpp | 2 +- src/libslic3r/TriangulateWall.cpp | 32 +- src/libslic3r/Utils.hpp | 60 +- src/libslic3r/clipper.cpp | 2 +- src/libslic3r/clipper.hpp | 4 +- src/libslic3r/clonable_ptr.hpp | 8 +- src/libslic3r/format.hpp | 48 +- src/libslic3r/libslic3r.h | 52 +- src/libslic3r/miniz_extension.hpp | 6 +- src/libslic3r/pchheader.hpp | 12 +- src/libslic3r/utils.cpp | 1174 +- src/miniz/ChangeLog.md | 364 +- src/miniz/LICENSE | 44 +- src/miniz/README-Prusa.txt | 2 +- src/miniz/miniz.c | 162 +- src/miniz/miniz.h | 24 +- src/nanosvg/nanosvg.h | 4508 +-- src/nanosvg/nanosvgrast.h | 2316 +- src/occt_wrapper/OCCTWrapper.cpp | 8 +- src/platform/msw/PrusaSlicer.manifest.in | 2 +- src/platform/msw/Slic3r.rc.in | 2 +- src/platform/msw/gcodeviewer.rc.in | 2 +- src/platform/osx/entitlements.plist | 2 +- src/platform/unix/BuildLinuxImage.sh.in | 2 +- src/qhull/Announce.txt | 2 +- src/qhull/COPYING.txt | 28 +- src/qhull/README.txt | 240 +- src/qhull/REGISTER.txt | 12 +- src/qhull/html/qhull-cpp.xml | 26 +- src/qhull/html/qhull.man | 2 +- src/qhull/html/qhull.txt | 2 +- src/qhull/html/rbox.man | 30 +- src/qhull/html/rbox.txt | 4 +- src/qhull/origCMakeLists.txt | 26 +- src/qhull/src/Changes.txt | 110 +- src/qhull/src/libqhull/DEPRECATED.txt | 26 +- src/qhull/src/libqhull/Makefile | 226 +- src/qhull/src/libqhull/Mborland | 194 +- src/qhull/src/libqhull/qhull-exports.def | 6 +- src/qhull/src/libqhull/qhull_p-exports.def | 2 +- src/qhull/src/libqhull/random.c | 2 +- src/qhull/src/libqhull/usermem.c | 4 +- src/qhull/src/libqhull_r/Makefile | 226 +- src/qhull/src/libqhull_r/geom2_r.c | 2 +- src/qhull/src/libqhull_r/libqhull_r.c | 2 +- src/qhull/src/libqhull_r/mem_r.c | 6 +- src/qhull/src/libqhull_r/qhull_r-exports.def | 4 +- src/qhull/src/libqhull_r/random_r.c | 2 +- src/qhull/src/libqhull_r/usermem_r.c | 4 +- src/qhull/src/libqhullcpp/Coordinates.h | 2 +- src/qhull/src/libqhullcpp/Qhull.h | 2 +- src/qhull/src/libqhullcpp/QhullFacet.cpp | 6 +- src/qhull/src/libqhullcpp/QhullFacetList.cpp | 2 +- src/qhull/src/libqhullcpp/QhullFacetList.h | 2 +- src/qhull/src/libqhullcpp/QhullHyperplane.cpp | 4 +- src/qhull/src/libqhullcpp/QhullPoint.cpp | 14 +- src/qhull/src/libqhullcpp/QhullQh.cpp | 2 +- src/qhull/src/libqhullcpp/QhullSet.cpp | 2 +- src/qhull/src/libqhullcpp/QhullSet.h | 8 +- src/qhull/src/libqhullcpp/QhullVertexSet.h | 2 +- src/qhull/src/libqhullcpp/libqhullcpp.pro | 2 +- src/qhull/src/qhull-all.pro | 4 +- src/qhull/src/user_eg2/user_eg2_r.c | 2 +- src/qoi/README.md | 10 +- src/qoi/qoi.h | 618 +- src/qoi/qoilib.c | 2 +- src/slic3r/CMakeLists.txt | 10 +- src/slic3r/Config/Snapshot.cpp | 284 +- src/slic3r/Config/Snapshot.hpp | 190 +- src/slic3r/Config/Version.cpp | 416 +- src/slic3r/Config/Version.hpp | 90 +- src/slic3r/GUI/2DBed.cpp | 266 +- src/slic3r/GUI/2DBed.hpp | 12 +- src/slic3r/GUI/3DBed.cpp | 6 +- src/slic3r/GUI/3DScene.cpp | 122 +- src/slic3r/GUI/3DScene.hpp | 130 +- src/slic3r/GUI/AboutDialog.cpp | 46 +- src/slic3r/GUI/AboutDialog.hpp | 12 +- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 990 +- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 378 +- src/slic3r/GUI/BedShapeDialog.cpp | 150 +- src/slic3r/GUI/BedShapeDialog.hpp | 26 +- src/slic3r/GUI/BitmapCache.cpp | 8 +- src/slic3r/GUI/BitmapCache.hpp | 70 +- src/slic3r/GUI/BitmapComboBox.cpp | 6 +- src/slic3r/GUI/BonjourDialog.cpp | 270 +- src/slic3r/GUI/BonjourDialog.hpp | 38 +- src/slic3r/GUI/ButtonsDescription.cpp | 174 +- src/slic3r/GUI/ButtonsDescription.hpp | 30 +- src/slic3r/GUI/CalibrationAbstractDialog.hpp | 4 +- src/slic3r/GUI/CalibrationBedDialog.cpp | 2 +- src/slic3r/GUI/CalibrationBedDialog.hpp | 2 +- src/slic3r/GUI/CalibrationBridgeDialog.cpp | 2 +- src/slic3r/GUI/CalibrationBridgeDialog.hpp | 4 +- src/slic3r/GUI/CalibrationCubeDialog.cpp | 2 +- src/slic3r/GUI/CalibrationCubeDialog.hpp | 4 +- src/slic3r/GUI/CalibrationFlowDialog.cpp | 10 +- src/slic3r/GUI/CalibrationFlowDialog.hpp | 4 +- .../GUI/CalibrationOverBridgeDialog.cpp | 2 +- .../GUI/CalibrationOverBridgeDialog.hpp | 4 +- .../GUI/CalibrationPressureAdvDialog.cpp | 82 +- .../GUI/CalibrationPressureAdvDialog.hpp | 6 +- .../GUI/CalibrationRetractionDialog.cpp | 8 +- .../GUI/CalibrationRetractionDialog.hpp | 4 +- src/slic3r/GUI/CalibrationTempDialog.cpp | 10 +- src/slic3r/GUI/CalibrationTempDialog.hpp | 4 +- src/slic3r/GUI/Camera.cpp | 6 +- src/slic3r/GUI/ConfigExceptions.hpp | 10 +- src/slic3r/GUI/ConfigManipulation.cpp | 30 +- src/slic3r/GUI/ConfigManipulation.hpp | 14 +- src/slic3r/GUI/ConfigSnapshotDialog.cpp | 32 +- src/slic3r/GUI/ConfigSnapshotDialog.hpp | 4 +- src/slic3r/GUI/ConfigWizard.cpp | 546 +- src/slic3r/GUI/ConfigWizard_private.hpp | 98 +- src/slic3r/GUI/CreateMMUTiledCanvas.cpp | 30 +- src/slic3r/GUI/CreateMMUTiledCanvas.hpp | 6 +- src/slic3r/GUI/DesktopIntegrationDialog.cpp | 116 +- src/slic3r/GUI/DesktopIntegrationDialog.hpp | 36 +- src/slic3r/GUI/DoubleSlider.cpp | 180 +- src/slic3r/GUI/DoubleSlider.hpp | 12 +- src/slic3r/GUI/DoubleSlider_Utils.hpp | 2 +- src/slic3r/GUI/ExtraRenderers.cpp | 22 +- src/slic3r/GUI/ExtruderSequenceDialog.cpp | 12 +- src/slic3r/GUI/ExtruderSequenceDialog.hpp | 4 +- src/slic3r/GUI/Field.cpp | 14 +- src/slic3r/GUI/Field.hpp | 566 +- src/slic3r/GUI/FirmwareDialog.cpp | 1442 +- src/slic3r/GUI/FirmwareDialog.hpp | 18 +- src/slic3r/GUI/FreeCADDialog.cpp | 24 +- src/slic3r/GUI/FreeCADDialog.hpp | 4 +- src/slic3r/GUI/GCodeViewer.cpp | 68 +- src/slic3r/GUI/GCodeViewer.hpp | 8 +- src/slic3r/GUI/GLCanvas3D.cpp | 484 +- src/slic3r/GUI/GLCanvas3D.hpp | 32 +- src/slic3r/GUI/GLSelectionRectangle.hpp | 6 +- src/slic3r/GUI/GLShader.cpp | 10 +- src/slic3r/GUI/GLShadersManager.cpp | 2 +- src/slic3r/GUI/GLTexture.cpp | 64 +- src/slic3r/GUI/GLToolbar.cpp | 10 +- src/slic3r/GUI/GUI.cpp | 388 +- src/slic3r/GUI/GUI.hpp | 12 +- src/slic3r/GUI/GUI_App.cpp | 352 +- src/slic3r/GUI/GUI_App.hpp | 50 +- src/slic3r/GUI/GUI_Factories.cpp | 38 +- src/slic3r/GUI/GUI_Factories.hpp | 2 +- src/slic3r/GUI/GUI_Init.cpp | 6 +- src/slic3r/GUI/GUI_Init.hpp | 10 +- src/slic3r/GUI/GUI_ObjectLayers.cpp | 28 +- src/slic3r/GUI/GUI_ObjectLayers.hpp | 2 +- src/slic3r/GUI/GUI_ObjectList.cpp | 344 +- src/slic3r/GUI/GUI_ObjectList.hpp | 34 +- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 164 +- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 12 +- src/slic3r/GUI/GUI_ObjectSettings.cpp | 38 +- src/slic3r/GUI/GUI_ObjectSettings.hpp | 2 +- src/slic3r/GUI/GUI_Preview.cpp | 24 +- src/slic3r/GUI/GUI_Preview.hpp | 2 +- src/slic3r/GUI/GUI_Tags.cpp | 12 +- src/slic3r/GUI/GUI_Utils.cpp | 6 +- src/slic3r/GUI/GUI_Utils.hpp | 8 +- src/slic3r/GUI/GalleryDialog.cpp | 34 +- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 30 +- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 4 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 34 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 8 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 2 +- src/slic3r/GUI/GraphDialog.cpp | 32 +- src/slic3r/GUI/HintNotification.cpp | 1762 +- src/slic3r/GUI/HintNotification.hpp | 174 +- src/slic3r/GUI/I18N.cpp | 6 +- src/slic3r/GUI/I18N.hpp | 82 +- src/slic3r/GUI/ImGuiWrapper.cpp | 34 +- src/slic3r/GUI/ImGuiWrapper.hpp | 6 +- src/slic3r/GUI/InstanceCheck.cpp | 1036 +- src/slic3r/GUI/InstanceCheck.hpp | 76 +- src/slic3r/GUI/InstanceCheckMac.mm | 92 +- src/slic3r/GUI/Jobs/ArrangeJob.cpp | 50 +- src/slic3r/GUI/Jobs/ArrangeJob.hpp | 4 +- src/slic3r/GUI/Jobs/Job.hpp | 38 +- src/slic3r/GUI/Jobs/ProgressIndicator.hpp | 6 +- src/slic3r/GUI/Jobs/RotoptimizeJob.cpp | 10 +- src/slic3r/GUI/KBShortcutsDialog.cpp | 2 +- src/slic3r/GUI/KBShortcutsDialog.hpp | 4 +- src/slic3r/GUI/MainFrame.cpp | 196 +- src/slic3r/GUI/MainFrame.hpp | 22 +- src/slic3r/GUI/MeshUtils.hpp | 2 +- src/slic3r/GUI/Mouse3DController.cpp | 348 +- src/slic3r/GUI/Mouse3DController.hpp | 104 +- src/slic3r/GUI/Mouse3DHandlerMac.mm | 2 +- src/slic3r/GUI/MsgDialog.cpp | 58 +- src/slic3r/GUI/MsgDialog.hpp | 430 +- src/slic3r/GUI/Notebook.cpp | 2 +- src/slic3r/GUI/Notebook.hpp | 4 +- src/slic3r/GUI/NotificationManager.cpp | 3446 +- src/slic3r/GUI/NotificationManager.hpp | 1448 +- src/slic3r/GUI/OG_CustomCtrl.cpp | 14 +- src/slic3r/GUI/OG_CustomCtrl.hpp | 2 +- src/slic3r/GUI/ObjectDataViewModel.cpp | 392 +- src/slic3r/GUI/ObjectDataViewModel.hpp | 40 +- src/slic3r/GUI/OpenGLManager.cpp | 44 +- src/slic3r/GUI/OpenGLManager.hpp | 4 +- src/slic3r/GUI/OptionsGroup.cpp | 460 +- src/slic3r/GUI/OptionsGroup.hpp | 380 +- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 20 +- src/slic3r/GUI/Plater.cpp | 424 +- src/slic3r/GUI/Plater.hpp | 90 +- src/slic3r/GUI/Preferences.cpp | 1674 +- src/slic3r/GUI/Preferences.hpp | 90 +- src/slic3r/GUI/PresetComboBoxes.cpp | 32 +- src/slic3r/GUI/PresetComboBoxes.hpp | 24 +- src/slic3r/GUI/PresetHints.cpp | 90 +- src/slic3r/GUI/PresetHints.hpp | 2 +- src/slic3r/GUI/PrintHostDialogs.cpp | 38 +- src/slic3r/GUI/ProgressStatusBar.cpp | 14 +- src/slic3r/GUI/ProgressStatusBar.hpp | 2 +- src/slic3r/GUI/ProjectDirtyStateManager.hpp | 2 +- src/slic3r/GUI/RammingChart.cpp | 24 +- src/slic3r/GUI/RammingChart.hpp | 36 +- src/slic3r/GUI/RemovableDriveManager.cpp | 690 +- src/slic3r/GUI/RemovableDriveManager.hpp | 158 +- src/slic3r/GUI/RemovableDriveManagerMM.mm | 32 +- src/slic3r/GUI/SavePresetDialog.cpp | 2 +- src/slic3r/GUI/SavePresetDialog.hpp | 6 +- src/slic3r/GUI/ScriptExecutor.cpp | 16 +- src/slic3r/GUI/Search.cpp | 98 +- src/slic3r/GUI/Search.hpp | 6 +- src/slic3r/GUI/Selection.cpp | 20 +- src/slic3r/GUI/Selection.hpp | 2 +- src/slic3r/GUI/SendSystemInfoDialog.cpp | 2 +- src/slic3r/GUI/SysInfoDialog.cpp | 36 +- src/slic3r/GUI/SysInfoDialog.hpp | 4 +- src/slic3r/GUI/Tab.cpp | 216 +- src/slic3r/GUI/Tab.hpp | 896 +- src/slic3r/GUI/UnsavedChangesDialog.cpp | 64 +- src/slic3r/GUI/UnsavedChangesDialog.hpp | 4 +- src/slic3r/GUI/UpdateDialogs.cpp | 420 +- src/slic3r/GUI/UpdateDialogs.hpp | 144 +- src/slic3r/GUI/WipeTowerDialog.cpp | 200 +- src/slic3r/GUI/WipeTowerDialog.hpp | 16 +- src/slic3r/GUI/format.hpp | 70 +- src/slic3r/GUI/fts_fuzzy_match.h | 78 +- src/slic3r/GUI/wxExtensions.cpp | 130 +- src/slic3r/GUI/wxExtensions.hpp | 34 +- src/slic3r/StackWalker.cpp | 2 +- src/slic3r/Utils/ASCIIFolding.cpp | 3850 +- src/slic3r/Utils/ASCIIFolding.hpp | 2 +- src/slic3r/Utils/AstroBox.hpp | 2 +- src/slic3r/Utils/Bonjour.cpp | 1192 +- src/slic3r/Utils/Bonjour.hpp | 84 +- src/slic3r/Utils/Duet.cpp | 380 +- src/slic3r/Utils/Duet.hpp | 40 +- src/slic3r/Utils/FixModelByWin10.cpp | 646 +- src/slic3r/Utils/FlashAir.cpp | 246 +- src/slic3r/Utils/FlashAir.hpp | 28 +- src/slic3r/Utils/HexFile.cpp | 156 +- src/slic3r/Utils/HexFile.hpp | 30 +- src/slic3r/Utils/Http.cpp | 644 +- src/slic3r/Utils/Http.hpp | 228 +- src/slic3r/Utils/MKS.cpp | 148 +- src/slic3r/Utils/MKS.hpp | 30 +- src/slic3r/Utils/MacDarkMode.mm | 6 +- src/slic3r/Utils/OctoPrint.cpp | 8 +- src/slic3r/Utils/PresetUpdater.cpp | 1722 +- src/slic3r/Utils/PresetUpdater.hpp | 86 +- src/slic3r/Utils/PrintHost.hpp | 4 +- src/slic3r/Utils/Process.cpp | 232 +- src/slic3r/Utils/Profile.hpp | 18 +- src/slic3r/Utils/Repetier.cpp | 10 +- src/slic3r/Utils/Repetier.hpp | 2 +- src/slic3r/Utils/RetinaHelperImpl.hmm | 4 +- src/slic3r/Utils/Serial.cpp | 644 +- src/slic3r/Utils/Serial.hpp | 102 +- src/slic3r/Utils/UndoRedo.cpp | 1844 +- src/slic3r/Utils/UndoRedo.hpp | 180 +- src/slic3r/pchheader.hpp | 26 +- src/stb_dxt/stb_dxt.h | 206 +- 2171 files changed, 195998 insertions(+), 195888 deletions(-) create mode 100755 src/cleanblanks.sh create mode 100755 src/cleantabs.sh diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bf721a76351..4da0c559341 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -93,7 +93,7 @@ if (SLIC3R_GUI) list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX expat) list(APPEND wxWidgets_LIBRARIES libexpat) endif () - + # This is an issue in the new wxWidgets cmake build, doesn't deal with librt find_library(LIBRT rt) if(LIBRT) @@ -176,10 +176,10 @@ target_link_libraries(Slic3r libslic3r_gui) endif () if (WIN32) find_library(PSAPI_LIB NAMES Psapi) - if(NOT PSAPI_LIB) + if(NOT PSAPI_LIB) message("WARNING: Psapi can't be find, trying again with hint to ${CMAKE_WINDOWS_KITS_10_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/um/x64") - find_library(PSAPI_LIB Psapi PATH "${CMAKE_WINDOWS_KITS_10_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/um/x64") - endif() + find_library(PSAPI_LIB Psapi PATH "${CMAKE_WINDOWS_KITS_10_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/um/x64") + endif() target_link_libraries(Slic3r ${PSAPI_LIB}) endif () endif () @@ -190,7 +190,7 @@ if (WIN32) if (MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") endif() - + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libslic3r/libslic3r_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/libslic3r_version.h @ONLY) add_executable(Slic3r_app_gui WIN32 PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/${SLIC3R_APP_KEY}.rc) @@ -216,7 +216,7 @@ if (WIN32) target_link_libraries(Slic3r_app_console PRIVATE boost_headeronly) add_executable(PrusaSlicer_app_gcodeviewer WIN32 PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/${SLIC3R_APP_KEY}-gcodeviewer.rc ${CMAKE_CURRENT_BINARY_DIR}/libslic3r_version.h) - target_include_directories(PrusaSlicer_app_gcodeviewer PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) + target_include_directories(PrusaSlicer_app_gcodeviewer PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) # Generate debug symbols even in release mode. if (MSVC) target_link_options(PrusaSlicer_app_gcodeviewer PUBLIC "$<$:/DEBUG>") @@ -287,7 +287,7 @@ else () endif () add_custom_command(TARGET Slic3r POST_BUILD # COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${BIN_RESOURCES_DIR}" # make[3]: stat: src/Slic3r: Too many levels of symbolic links - COMMAND cp -r "${SLIC3R_RESOURCES_DIR}" "${BIN_RESOURCES_DIR}" + COMMAND cp -r "${SLIC3R_RESOURCES_DIR}" "${BIN_RESOURCES_DIR}" COMMENT "Symlinking the resources directory into the build tree" VERBATIM) endif () diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 6fd62ddbab8..de734981b79 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -7,8 +7,8 @@ #include #include #ifdef SLIC3R_GUI - extern "C" - { + extern "C" + { // Let the NVIDIA and AMD know we want to use their graphics card // on a dual graphics card system. __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; @@ -77,40 +77,40 @@ int CLI::run(int argc, char **argv) ::setenv("GDK_BACKEND", "x11", /* replace */ true); #endif - // Switch boost::filesystem to utf8. + // Switch boost::filesystem to utf8. try { boost::nowide::nowide_filesystem(); } catch (const std::runtime_error& ex) { std::string caption = std::string(SLIC3R_APP_NAME) + " Error"; std::string text = std::string("An error occured while setting up locale.\n") + ( #if !defined(_WIN32) && !defined(__APPLE__) - // likely some linux system - "You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n" + // likely some linux system + "You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n" #endif - SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); + SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); #if defined(_WIN32) && defined(SLIC3R_GUI) if (m_actions.empty()) - // Empty actions means Slicer is executed in the GUI mode. Show a GUI message. + // Empty actions means Slicer is executed in the GUI mode. Show a GUI message. MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR); #endif boost::nowide::cerr << text.c_str() << std::endl; return 1; } - if (! this->setup(argc, argv)) - return 1; + if (! this->setup(argc, argv)) + return 1; m_extra_config.apply(m_config, true); m_extra_config.normalize_fdm(); - + PrinterTechnology printer_technology = get_printer_technology(m_config); - bool start_gui = m_actions.empty() && + bool start_gui = m_actions.empty() && // cutting transformations are setting an "export" action. std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() && std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() && std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end(); - bool start_as_gcodeviewer = + bool start_as_gcodeviewer = #ifdef _WIN32 false; #else @@ -118,7 +118,7 @@ int CLI::run(int argc, char **argv) boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), GCODEVIEWER_APP_CMD); #endif // _WIN32 - const std::vector &load_configs = m_config.option("load", true)->get_values(); + const std::vector &load_configs = m_config.option("load", true)->get_values(); const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option>("config_compatibility", true)->value; // load config files supplied via --load @@ -157,7 +157,7 @@ int CLI::run(int argc, char **argv) } m_print_config.apply(config); } - + // are we starting as gcodeviewer ? for (auto it = m_actions.begin(); it != m_actions.end(); ++it) { if (*it == "gcodeviewer") { @@ -232,7 +232,7 @@ int CLI::run(int argc, char **argv) // Initialize full print configs for both the FFF and SLA technologies. FullPrintConfig fff_print_config; SLAFullPrintConfig sla_print_config; - + // Synchronize the default parameters and the ones received on the command line. if (printer_technology == ptFFF) { fff_print_config.apply(m_print_config, true); @@ -240,17 +240,17 @@ int CLI::run(int argc, char **argv) } else { assert(printer_technology == ptSLA); sla_print_config.output_filename_format.value = "[input_filename_base].sl1"; - + // The default bed shape should reflect the default display parameters // and not the fff defaults. double w = sla_print_config.display_width.get_float(); double h = sla_print_config.display_height.get_float(); sla_print_config.bed_shape.set({ Vec2d(0, 0), Vec2d(w, 0), Vec2d(w, h), Vec2d(0, h) }); - + sla_print_config.apply(m_print_config, true); m_print_config.apply(sla_print_config, true); } - + { std::string validity = m_print_config.validate(); if (! validity.empty()) { @@ -258,12 +258,12 @@ int CLI::run(int argc, char **argv) return 1; } } - + // Loop through transform options. bool user_center_specified = false; Points bed = get_bed_shape(m_print_config); int dups = 1; - + for (auto const &opt_key : m_transforms) { if (opt_key == "merge") { Model m; @@ -288,10 +288,10 @@ int CLI::run(int argc, char **argv) model.objects.begin(), model.objects.end(), [](ModelObject* o){ return o->instances.empty(); } ); - + dups = m_config.opt_int("duplicate"); if (!all_objects_have_instances) model.add_default_instances(); - + } } else if (opt_key == "duplicate_grid") { const std::vector &ints = m_config.option("duplicate_grid")->get_values(); @@ -301,7 +301,7 @@ int CLI::run(int argc, char **argv) for (auto &model : m_models) model.duplicate_objects_grid(x, y, (distance > 0) ? distance : 6); // TODO: this is not the right place for setting a default } else if (opt_key == "center") { - user_center_specified = true; + user_center_specified = true; for (auto &model : m_models) { model.add_default_instances(); // this affects instances: @@ -505,7 +505,7 @@ int CLI::run(int argc, char **argv) }); PrintBase *print = (printer_technology == ptFFF) ? static_cast(&fff_print) : static_cast(&sla_print); - + if (! m_config.opt_bool("dont_arrange")) { ArrangeParams arrange_cfg; arrange_cfg.min_obj_distance = scaled(min_object_distance(&m_print_config)) * 2; @@ -643,7 +643,7 @@ int CLI::run(int argc, char **argv) bool CLI::setup(int argc, char **argv) { { - Slic3r::set_logging_level(1); + Slic3r::set_logging_level(1); const char *loglevel = boost::nowide::getenv("SLIC3R_LOGLEVEL"); if (loglevel != nullptr) { if (loglevel[0] >= '0' && loglevel[0] <= '9' && loglevel[1] == 0) @@ -708,7 +708,7 @@ bool CLI::setup(int argc, char **argv) if (opt_loglevel != 0) set_logging_level(opt_loglevel->value); } - + //FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet. std::string validity = m_config.validate(); @@ -718,7 +718,7 @@ bool CLI::setup(int argc, char **argv) m_config.option(optdef.first, true); set_data_dir(m_config.opt_string("datadir")); - + //FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet. if (!validity.empty()) { boost::nowide::cerr << "error: " << validity << std::endl; @@ -760,7 +760,7 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn << "\t1) Config keys from the command line, for example --fill-pattern=stars" << std::endl << "\t (highest priority, overwrites everything below)" << std::endl << "\t2) Config files loaded with --load" << std::endl - << "\t3) Config values loaded from amf or 3mf files" << std::endl; + << "\t3) Config values loaded from amf or 3mf files" << std::endl; if (include_print_options) { boost::nowide::cout << std::endl; @@ -824,8 +824,8 @@ extern "C" { __declspec(dllexport) int __stdcall slic3r_main(int argc, wchar_t **argv) { // Convert wchar_t arguments to UTF8. - std::vector argv_narrow; - std::vector argv_ptrs(argc + 1, nullptr); + std::vector argv_narrow; + std::vector argv_ptrs(argc + 1, nullptr); for (size_t i = 0; i < argc; ++ i) argv_narrow.emplace_back(boost::nowide::narrow(argv[i])); for (size_t i = 0; i < argc; ++ i) diff --git a/src/PrusaSlicer.hpp b/src/PrusaSlicer.hpp index 6be1d148b60..43383776ae6 100644 --- a/src/PrusaSlicer.hpp +++ b/src/PrusaSlicer.hpp @@ -7,12 +7,12 @@ namespace Slic3r { namespace IO { - enum ExportFormat : int { - AMF, - OBJ, - STL, - // SVG, - TMF, + enum ExportFormat : int { + AMF, + OBJ, + STL, + // SVG, + TMF, Gcode }; } @@ -25,7 +25,7 @@ class CLI { private: DynamicPrintAndCLIConfig m_config; - DynamicPrintConfig m_print_config; + DynamicPrintConfig m_print_config; DynamicPrintConfig m_extra_config; std::vector m_input_files; std::vector m_actions; @@ -33,15 +33,15 @@ class CLI { std::vector m_models; bool setup(int argc, char **argv); - + /// Prints usage of the CLI. void print_help(bool include_print_options = false, PrinterTechnology printer_technology = ptFFF | ptSLA | ptSLS) const; - + /// Exports loaded models to a file of the specified format, according to the options affecting output filename. bool export_models(IO::ExportFormat format); - + bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); } - + std::string output_filepath(const Model &model, IO::ExportFormat format) const; }; diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp index 91b1e3a71fe..32ddae7e5b0 100644 --- a/src/PrusaSlicer_app_msvc.cpp +++ b/src/PrusaSlicer_app_msvc.cpp @@ -11,8 +11,8 @@ #ifdef SLIC3R_GUI -extern "C" -{ +extern "C" +{ // Let the NVIDIA and AMD know we want to use their graphics card // on a dual graphics card system. __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; @@ -50,7 +50,7 @@ class OpenGLVersionCheck bool load_opengl_dll() { MSG msg = {0}; - WNDCLASS wc = {0}; + WNDCLASS wc = {0}; wc.lpfnWndProc = OpenGLVersionCheck::supports_opengl2_wndproc; wc.hInstance = (HINSTANCE)GetModuleHandle(nullptr); wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND); @@ -67,7 +67,7 @@ class OpenGLVersionCheck return this->success; } - void unload_opengl_dll() + void unload_opengl_dll() { if (this->hOpenGL) { BOOL released = FreeLibrary(this->hOpenGL); @@ -121,10 +121,10 @@ class OpenGLVersionCheck typedef BOOL(WINAPI* Func_wglDeleteContext)(HGLRC); typedef GLubyte* (WINAPI* Func_glGetString)(GLenum); - Func_wglCreateContext wglCreateContext = (Func_wglCreateContext)GetProcAddress(hOpenGL, "wglCreateContext"); - Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent)GetProcAddress(hOpenGL, "wglMakeCurrent"); - Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext)GetProcAddress(hOpenGL, "wglDeleteContext"); - Func_glGetString glGetString = (Func_glGetString)GetProcAddress(hOpenGL, "glGetString"); + Func_wglCreateContext wglCreateContext = (Func_wglCreateContext)GetProcAddress(hOpenGL, "wglCreateContext"); + Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent)GetProcAddress(hOpenGL, "wglMakeCurrent"); + Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext)GetProcAddress(hOpenGL, "wglDeleteContext"); + Func_glGetString glGetString = (Func_glGetString)GetProcAddress(hOpenGL, "glGetString"); if (wglCreateContext == nullptr || wglMakeCurrent == nullptr || wglDeleteContext == nullptr || glGetString == nullptr) { printf("Failed loading the system opengl32.dll: The library is invalid.\n"); @@ -153,7 +153,7 @@ class OpenGLVersionCheck HDC ourWindowHandleToDeviceContext = ::GetDC(hWnd); // Gdi32.dll - int letWindowsChooseThisPixelFormat = ::ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd); + int letWindowsChooseThisPixelFormat = ::ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd); // Gdi32.dll SetPixelFormat(ourWindowHandleToDeviceContext, letWindowsChooseThisPixelFormat, &pfd); // Opengl32.dll @@ -249,7 +249,7 @@ int wmain(int argc, wchar_t **argv) #ifdef SLIC3R_GUI OpenGLVersionCheck opengl_version_check; - bool load_mesa = + bool load_mesa = // Forced from the command line. force_mesa || // Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context. @@ -281,7 +281,7 @@ int wmain(int argc, wchar_t **argv) if (hInstance_OpenGL == nullptr) { printf("MESA OpenGL library was not loaded\n"); } else - printf("MESA OpenGL library was loaded sucessfully\n"); + printf("MESA OpenGL library was loaded sucessfully\n"); } #endif /* SLIC3R_GUI */ @@ -297,7 +297,7 @@ int wmain(int argc, wchar_t **argv) } // resolve function address here - slic3r_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r, + slic3r_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r, #ifdef _WIN64 // there is just a single calling conversion, therefore no mangling of the function name. "slic3r_main" diff --git a/src/Shiny/ShinyConfig.h b/src/Shiny/ShinyConfig.h index 54c632151b2..93cf3a28ca7 100644 --- a/src/Shiny/ShinyConfig.h +++ b/src/Shiny/ShinyConfig.h @@ -31,31 +31,31 @@ THE SOFTWARE. /* if SHINY_LOOKUP_RATE is defined to TRUE then Shiny will record the success of its hash function. This is useful for debugging. Default is FALSE. */ #ifndef SHINY_LOOKUP_RATE -// #define SHINY_LOOKUP_RATE FALSE +// #define SHINY_LOOKUP_RATE FALSE #endif /* if SHINY_HAS_ENABLED is defined to TRUE then Shiny can be enabled and disabled at runtime. TODO: bla bla... */ #ifndef SHINY_HAS_ENABLED -// #define SHINY_HAS_ENABLED FALSE +// #define SHINY_HAS_ENABLED FALSE #endif -/* TODO: +/* TODO: */ -#define SHINY_OUTPUT_MODE_FLAT 0x1 +#define SHINY_OUTPUT_MODE_FLAT 0x1 -/* TODO: +/* TODO: */ -#define SHINY_OUTPUT_MODE_TREE 0x2 +#define SHINY_OUTPUT_MODE_TREE 0x2 -/* TODO: +/* TODO: */ -#define SHINY_OUTPUT_MODE_BOTH 0x3 +#define SHINY_OUTPUT_MODE_BOTH 0x3 -/* TODO: +/* TODO: */ #ifndef SHINY_OUTPUT_MODE -#define SHINY_OUTPUT_MODE SHINY_OUTPUT_MODE_BOTH +#define SHINY_OUTPUT_MODE SHINY_OUTPUT_MODE_BOTH #endif #endif /* SHINY_CONFIG_H */ diff --git a/src/Shiny/ShinyData.h b/src/Shiny/ShinyData.h index d75d4f5bf48..e13561ed22e 100644 --- a/src/Shiny/ShinyData.h +++ b/src/Shiny/ShinyData.h @@ -34,65 +34,65 @@ extern "C" { /*---------------------------------------------------------------------------*/ typedef struct { - uint32_t entryCount; - shinytick_t selfTicks; + uint32_t entryCount; + shinytick_t selfTicks; } ShinyLastData; /*---------------------------------------------------------------------------*/ typedef struct { - shinytick_t cur; - float avg; + shinytick_t cur; + float avg; } ShinyTickData; typedef struct { - uint32_t cur; - float avg; + uint32_t cur; + float avg; } ShinyCountData; typedef struct { - ShinyCountData entryCount; - ShinyTickData selfTicks; - ShinyTickData childTicks; + ShinyCountData entryCount; + ShinyTickData selfTicks; + ShinyTickData childTicks; } ShinyData; SHINY_INLINE shinytick_t ShinyData_totalTicksCur(const ShinyData *self) { - return self->selfTicks.cur + self->childTicks.cur; + return self->selfTicks.cur + self->childTicks.cur; } SHINY_INLINE float ShinyData_totalTicksAvg(const ShinyData *self) { - return self->selfTicks.avg + self->childTicks.avg; + return self->selfTicks.avg + self->childTicks.avg; } SHINY_INLINE void ShinyData_computeAverage(ShinyData *self, float a_damping) { - self->entryCount.avg = self->entryCount.cur + - a_damping * (self->entryCount.avg - self->entryCount.cur); - self->selfTicks.avg = self->selfTicks.cur + - a_damping * (self->selfTicks.avg - self->selfTicks.cur); - self->childTicks.avg = self->childTicks.cur + - a_damping * (self->childTicks.avg - self->childTicks.cur); + self->entryCount.avg = self->entryCount.cur + + a_damping * (self->entryCount.avg - self->entryCount.cur); + self->selfTicks.avg = self->selfTicks.cur + + a_damping * (self->selfTicks.avg - self->selfTicks.cur); + self->childTicks.avg = self->childTicks.cur + + a_damping * (self->childTicks.avg - self->childTicks.cur); } SHINY_INLINE void ShinyData_copyAverage(ShinyData *self) { - self->entryCount.avg = (float) self->entryCount.cur; - self->selfTicks.avg = (float) self->selfTicks.cur; - self->childTicks.avg = (float) self->childTicks.cur; + self->entryCount.avg = (float) self->entryCount.cur; + self->selfTicks.avg = (float) self->selfTicks.cur; + self->childTicks.avg = (float) self->childTicks.cur; } SHINY_INLINE void ShinyData_clearAll(ShinyData *self) { - self->entryCount.cur = 0; - self->entryCount.avg = 0; - self->selfTicks.cur = 0; - self->selfTicks.avg = 0; - self->childTicks.cur = 0; - self->childTicks.avg = 0; + self->entryCount.cur = 0; + self->entryCount.avg = 0; + self->selfTicks.cur = 0; + self->selfTicks.avg = 0; + self->childTicks.cur = 0; + self->childTicks.avg = 0; } SHINY_INLINE void ShinyData_clearCurrent(ShinyData *self) { - self->entryCount.cur = 0; - self->selfTicks.cur = 0; - self->childTicks.cur = 0; + self->entryCount.cur = 0; + self->selfTicks.cur = 0; + self->childTicks.cur = 0; } #if __cplusplus diff --git a/src/Shiny/ShinyMacros.h b/src/Shiny/ShinyMacros.h index 79dfa438193..541b82a3773 100644 --- a/src/Shiny/ShinyMacros.h +++ b/src/Shiny/ShinyMacros.h @@ -32,167 +32,167 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_UPDATE() \ - ShinyManager_update(&Shiny_instance) +#define PROFILE_UPDATE() \ + ShinyManager_update(&Shiny_instance) -#define PROFILE_SET_DAMPING(floatfrom0to1) \ - Shiny_instance.damping = (floatfrom0to1); +#define PROFILE_SET_DAMPING(floatfrom0to1) \ + Shiny_instance.damping = (floatfrom0to1); -#define PROFILE_GET_DAMPING() \ - (Shiny_instance.damping) +#define PROFILE_GET_DAMPING() \ + (Shiny_instance.damping) -#define PROFILE_OUTPUT(filename) \ - ShinyManager_output(&Shiny_instance, (filename)) +#define PROFILE_OUTPUT(filename) \ + ShinyManager_output(&Shiny_instance, (filename)) -#define PROFILE_OUTPUT_STREAM(stream) \ - ShinyManager_outputToStream(&Shiny_instance, (stream)) +#define PROFILE_OUTPUT_STREAM(stream) \ + ShinyManager_outputToStream(&Shiny_instance, (stream)) #ifdef __cplusplus -#define PROFILE_GET_TREE_STRING() \ - ShinyManager_outputTreeToString(&Shiny_instance) +#define PROFILE_GET_TREE_STRING() \ + ShinyManager_outputTreeToString(&Shiny_instance) -#define PROFILE_GET_FLAT_STRING() \ - ShinyManager_outputFlatToString(&Shiny_instance) +#define PROFILE_GET_FLAT_STRING() \ + ShinyManager_outputFlatToString(&Shiny_instance) #endif /* __cplusplus */ -#define PROFILE_DESTROY() \ - ShinyManager_destroy(&Shiny_instance) +#define PROFILE_DESTROY() \ + ShinyManager_destroy(&Shiny_instance) -#define PROFILE_CLEAR() \ - ShinyManager_clear(&Shiny_instance) +#define PROFILE_CLEAR() \ + ShinyManager_clear(&Shiny_instance) -#define PROFILE_SORT_ZONES() \ - ShinyManager_sortZones(&Shiny_instance) +#define PROFILE_SORT_ZONES() \ + ShinyManager_sortZones(&Shiny_instance) /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_GET_TOTAL_TICKS_CUR() \ - ShinyData_totalTicksCur(&Shiny_instance.rootZone.data) +#define PROFILE_GET_TOTAL_TICKS_CUR() \ + ShinyData_totalTicksCur(&Shiny_instance.rootZone.data) -#define PROFILE_GET_TOTAL_TICKS() \ - ShinyData_totalTicksAvg(&Shiny_instance.rootZone.data) +#define PROFILE_GET_TOTAL_TICKS() \ + ShinyData_totalTicksAvg(&Shiny_instance.rootZone.data) -#define PROFILE_GET_PROFILED_TICKS_CUR() \ - (Shiny_instance.rootZone.data.selfTicks.cur) +#define PROFILE_GET_PROFILED_TICKS_CUR() \ + (Shiny_instance.rootZone.data.selfTicks.cur) -#define PROFILE_GET_PROFILED_TICKS() \ - (Shiny_instance.rootZone.data.selfTicks.avg) +#define PROFILE_GET_PROFILED_TICKS() \ + (Shiny_instance.rootZone.data.selfTicks.avg) -#define PROFILE_GET_UNPROFILED_TICKS_CUR() \ - (Shiny_instance.rootZone.data.childTicks.cur) +#define PROFILE_GET_UNPROFILED_TICKS_CUR() \ + (Shiny_instance.rootZone.data.childTicks.cur) -#define PROFILE_GET_UNPROFILED_TICKS() \ - (Shiny_instance.rootZone.data.childTicks.avg) +#define PROFILE_GET_UNPROFILED_TICKS() \ + (Shiny_instance.rootZone.data.childTicks.avg) -#define PROFILE_GET_SHARED_TOTAL_TICKS_CUR(name) \ - ShinyData_totalTicksCur(&(_PROFILE_ID_ZONE_SHARED(name).data)) +#define PROFILE_GET_SHARED_TOTAL_TICKS_CUR(name) \ + ShinyData_totalTicksCur(&(_PROFILE_ID_ZONE_SHARED(name).data)) -#define PROFILE_GET_SHARED_TOTAL_TICKS(name) \ - ShinyData_totalTicksAvg(&(_PROFILE_ID_ZONE_SHARED(name).data)) +#define PROFILE_GET_SHARED_TOTAL_TICKS(name) \ + ShinyData_totalTicksAvg(&(_PROFILE_ID_ZONE_SHARED(name).data)) -#define PROFILE_GET_SHARED_SELF_TICKS_CUR(name) \ - (_PROFILE_ID_ZONE_SHARED(name).data.selfTicks.cur) +#define PROFILE_GET_SHARED_SELF_TICKS_CUR(name) \ + (_PROFILE_ID_ZONE_SHARED(name).data.selfTicks.cur) -#define PROFILE_GET_SHARED_SELF_TICKS(name) \ - (_PROFILE_ID_ZONE_SHARED(name).data.selfTicks.avg) +#define PROFILE_GET_SHARED_SELF_TICKS(name) \ + (_PROFILE_ID_ZONE_SHARED(name).data.selfTicks.avg) /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_IS_SHARED_SELF_BELOW(name, floatfrom0to1) \ - ShinyManager_isZoneSelfTimeBelow( \ - &Shiny_instance, _PROFILE_ID_ZONE_SHARED(name), floatfrom0to1) +#define PROFILE_IS_SHARED_SELF_BELOW(name, floatfrom0to1) \ + ShinyManager_isZoneSelfTimeBelow( \ + &Shiny_instance, _PROFILE_ID_ZONE_SHARED(name), floatfrom0to1) -#define PROFILE_IS_SHARED_TOTAL_BELOW(name, floatfrom0to1) \ - ShinyManager_isZoneTotalTimeBelow( \ - &Shiny_instance, _PROFILE_ID_ZONE_SHARED(name), floatfrom0to1) +#define PROFILE_IS_SHARED_TOTAL_BELOW(name, floatfrom0to1) \ + ShinyManager_isZoneTotalTimeBelow( \ + &Shiny_instance, _PROFILE_ID_ZONE_SHARED(name), floatfrom0to1) /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_END() \ - ShinyManager_endCurNode(&Shiny_instance) +#define PROFILE_END() \ + ShinyManager_endCurNode(&Shiny_instance) /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_BEGIN( name ) \ - \ - static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE(name), #name); \ - _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE(name)) +#define PROFILE_BEGIN( name ) \ + \ + static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE(name), #name); \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE(name)) /*---------------------------------------------------------------------------*/ /* public preprocessors */ #ifdef __cplusplus -#define PROFILE_BLOCK( name ) \ - \ - _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ - PROFILE_BEGIN(name) +#define PROFILE_BLOCK( name ) \ + \ + _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ + PROFILE_BEGIN(name) #endif /* __cplusplus */ /*---------------------------------------------------------------------------*/ /* public preprocessors */ #ifdef __cplusplus -#define PROFILE_FUNC() \ - \ - _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ - static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_FUNC(), __FUNCTION__); \ - _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_FUNC()) +#define PROFILE_FUNC() \ + \ + _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ + static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_FUNC(), __FUNCTION__); \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_FUNC()) #endif /* __cplusplus */ /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_CODE( code ) \ - \ - do { \ - static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_CODE(), #code); \ - _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_CODE()); \ - { code; } \ - PROFILE_END(); \ - } while(0) +#define PROFILE_CODE( code ) \ + \ + do { \ + static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_CODE(), #code); \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_CODE()); \ + { code; } \ + PROFILE_END(); \ + } while(0) /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_SHARED_EXTERN( name ) \ - \ - _PROFILE_ZONE_DECLARE(extern, _PROFILE_ID_ZONE_SHARED(name)) +#define PROFILE_SHARED_EXTERN( name ) \ + \ + _PROFILE_ZONE_DECLARE(extern, _PROFILE_ID_ZONE_SHARED(name)) /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_SHARED_DEFINE( name ) \ - \ - _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_SHARED(name), #name) +#define PROFILE_SHARED_DEFINE( name ) \ + \ + _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_SHARED(name), #name) /*---------------------------------------------------------------------------*/ /* public preprocessors */ -#define PROFILE_SHARED_BEGIN( name ) \ - \ - _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_SHARED(name)) +#define PROFILE_SHARED_BEGIN( name ) \ + \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_SHARED(name)) /*---------------------------------------------------------------------------*/ /* public preprocessors */ #ifdef __cplusplus -#define PROFILE_SHARED_BLOCK( name ) \ - \ - _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ - _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_SHARED(name)) +#define PROFILE_SHARED_BLOCK( name ) \ + \ + _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_SHARED(name)) #endif /* __cplusplus */ @@ -200,57 +200,57 @@ THE SOFTWARE. /* public preprocessors */ #ifdef SHINY_HAS_ENABLED -#define PROFILE_SET_ENABLED( boolean ) \ - Shiny_instance.enabled = boolean +#define PROFILE_SET_ENABLED( boolean ) \ + Shiny_instance.enabled = boolean #endif /*---------------------------------------------------------------------------*/ /* internal preprocessors */ -#define _PROFILE_ID_ZONE( name ) __ShinyZone_##name -#define _PROFILE_ID_ZONE_FUNC() __ShinyZoneFunc -#define _PROFILE_ID_ZONE_CODE() __ShinyZoneCode -#define _PROFILE_ID_ZONE_SHARED( name ) name##__ShinyZoneShared -#define _PROFILE_ID_BLOCK() __ShinyBlock +#define _PROFILE_ID_ZONE( name ) __ShinyZone_##name +#define _PROFILE_ID_ZONE_FUNC() __ShinyZoneFunc +#define _PROFILE_ID_ZONE_CODE() __ShinyZoneCode +#define _PROFILE_ID_ZONE_SHARED( name ) name##__ShinyZoneShared +#define _PROFILE_ID_BLOCK() __ShinyBlock /*---------------------------------------------------------------------------*/ /* internal preprocessor */ -#define _PROFILE_ZONE_DEFINE( id, string ) \ - \ - ShinyZone id = { \ - NULL, SHINY_ZONE_STATE_HIDDEN, string, \ - { { 0, 0 }, { 0, 0 }, { 0, 0 } } \ - } +#define _PROFILE_ZONE_DEFINE( id, string ) \ + \ + ShinyZone id = { \ + NULL, SHINY_ZONE_STATE_HIDDEN, string, \ + { { 0, 0 }, { 0, 0 }, { 0, 0 } } \ + } /*---------------------------------------------------------------------------*/ /* internal preprocessor */ -#define _PROFILE_ZONE_DECLARE( prefix, id ) \ - \ - prefix ShinyZone id +#define _PROFILE_ZONE_DECLARE( prefix, id ) \ + \ + prefix ShinyZone id /*---------------------------------------------------------------------------*/ /* internal preprocessor */ -#define _PROFILE_BLOCK_DEFINE( id ) \ - \ - ShinyEndNodeOnDestruction SHINY_UNUSED id +#define _PROFILE_BLOCK_DEFINE( id ) \ + \ + ShinyEndNodeOnDestruction SHINY_UNUSED id /*---------------------------------------------------------------------------*/ /* internal preprocessor */ -#define _PROFILE_ZONE_BEGIN( id ) \ - \ - do { \ - static ShinyNodeCache cache = &_ShinyNode_dummy; \ - ShinyManager_lookupAndBeginNode(&Shiny_instance, &cache, &id); \ - } while(0) +#define _PROFILE_ZONE_BEGIN( id ) \ + \ + do { \ + static ShinyNodeCache cache = &_ShinyNode_dummy; \ + ShinyManager_lookupAndBeginNode(&Shiny_instance, &cache, &id); \ + } while(0) /*---------------------------------------------------------------------------*/ @@ -258,17 +258,17 @@ THE SOFTWARE. #define PROFILE_UPDATE() #define PROFILE_SET_DAMPING(x) -#define PROFILE_GET_DAMPING() 0.0f +#define PROFILE_GET_DAMPING() 0.0f #define PROFILE_OUTPUT(x) #define PROFILE_OUTPUT_STREAM(x) #define PROFILE_CLEAR() -#define PROFILE_GET_TREE_STRING() std::string() -#define PROFILE_GET_FLAT_STRING() std::string() +#define PROFILE_GET_TREE_STRING() std::string() +#define PROFILE_GET_FLAT_STRING() std::string() #define PROFILE_DESTROY() #define PROFILE_BEGIN(name) #define PROFILE_BLOCK(name) #define PROFILE_FUNC() -#define PROFILE_CODE(code) do { code; } while (0) +#define PROFILE_CODE(code) do { code; } while (0) #define PROFILE_SHARED_GLOBAL(name) #define PROFILE_SHARED_MEMBER(name) #define PROFILE_SHARED_DEFINE(name) diff --git a/src/Shiny/ShinyManager.c b/src/Shiny/ShinyManager.c index 6b281185136..3f050acebc3 100644 --- a/src/Shiny/ShinyManager.c +++ b/src/Shiny/ShinyManager.c @@ -33,49 +33,49 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ -#define TABLE_SIZE_INIT 256 +#define TABLE_SIZE_INIT 256 /*---------------------------------------------------------------------------*/ ShinyManager Shiny_instance = { #if SHINY_HAS_ENABLED == TRUE - /* enabled = */ false, + /* enabled = */ false, #endif - /* _lastTick = */ 0, - /* _curNode = */ &Shiny_instance.rootNode, - /* _tableMask = */ 0, - /* _nodeTable = */ _ShinyManager_dummyNodeTable, + /* _lastTick = */ 0, + /* _curNode = */ &Shiny_instance.rootNode, + /* _tableMask = */ 0, + /* _nodeTable = */ _ShinyManager_dummyNodeTable, #if SHINY_LOOKUP_RATE == TRUE - /* _lookupCount = */ 0, - /* _lookupSuccessCount = */ 0, + /* _lookupCount = */ 0, + /* _lookupSuccessCount = */ 0, #endif - /* _tableSize = */ 1, - /* nodeCount = */ 1, - /* zoneCount = */ 1, - /* _lastZone = */ &Shiny_instance.rootZone, - /* _lastNodePool = */ NULL, - /* _firstNodePool = */ NULL, - /* rootNode = */ { - /* _last = */ { 0, 0 }, - /* zone = */ &Shiny_instance.rootZone, - /* parent = */ &Shiny_instance.rootNode, - /* nextSibling = */ NULL, - /* firstChild = */ NULL, - /* lastChild = */ NULL, - /* childCount = */ 0, - /* entryLevel = */ 0, - /* _cache = */ NULL, - /* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } } - }, - /* rootZone = */ { - /* next = */ NULL, - /* _state = */ SHINY_ZONE_STATE_HIDDEN, - /* name = */ "", - /* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } } - }, - /* damping = */ 0.f, // Damping disabled, every PROFILE_UPDATE will be performed from scratch. Original value: 0.9f - /* _initialized = */ FALSE, - /* _firstUpdate = */ TRUE + /* _tableSize = */ 1, + /* nodeCount = */ 1, + /* zoneCount = */ 1, + /* _lastZone = */ &Shiny_instance.rootZone, + /* _lastNodePool = */ NULL, + /* _firstNodePool = */ NULL, + /* rootNode = */ { + /* _last = */ { 0, 0 }, + /* zone = */ &Shiny_instance.rootZone, + /* parent = */ &Shiny_instance.rootNode, + /* nextSibling = */ NULL, + /* firstChild = */ NULL, + /* lastChild = */ NULL, + /* childCount = */ 0, + /* entryLevel = */ 0, + /* _cache = */ NULL, + /* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } } + }, + /* rootZone = */ { + /* next = */ NULL, + /* _state = */ SHINY_ZONE_STATE_HIDDEN, + /* name = */ "", + /* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } } + }, + /* damping = */ 0.f, // Damping disabled, every PROFILE_UPDATE will be performed from scratch. Original value: 0.9f + /* _initialized = */ FALSE, + /* _firstUpdate = */ TRUE }; ShinyNode* _ShinyManager_dummyNodeTable[] = { NULL }; @@ -84,18 +84,18 @@ ShinyNode* _ShinyManager_dummyNodeTable[] = { NULL }; /*---------------------------------------------------------------------------*/ #if SHINY_COMPILER == SHINY_COMPILER_MSVC -# pragma warning (push) -# pragma warning (disable: 4311) +# pragma warning (push) +# pragma warning (disable: 4311) #endif /* primary hash function */ SHINY_INLINE uint32_t hash_value(void* a_pParent, void* a_pZone) { - uint32_t a = (uint32_t) a_pParent + (uint32_t) a_pZone; -// uint32_t a = *reinterpret_cast(&a_pParent) + *reinterpret_cast(&a_pZone); + uint32_t a = (uint32_t) a_pParent + (uint32_t) a_pZone; +// uint32_t a = *reinterpret_cast(&a_pParent) + *reinterpret_cast(&a_pZone); - a = (a+0x7ed55d16) + (a<<12); - a = (a^0xc761c23c) ^ (a>>19); - return a; + a = (a+0x7ed55d16) + (a<<12); + a = (a^0xc761c23c) ^ (a>>19); + return a; } /* @@ -103,23 +103,23 @@ SHINY_INLINE uint32_t hash_value(void* a_pParent, void* a_pZone) { * so it's relatively prime to the power-of-two table size */ SHINY_INLINE uint32_t hash_offset(uint32_t a) { - return ((a << 8) + (a >> 4)) | 1; + return ((a << 8) + (a >> 4)) | 1; } #if SHINY_COMPILER == SHINY_COMPILER_MSVC -# pragma warning (pop) +# pragma warning (pop) #endif /*---------------------------------------------------------------------------*/ void ShinyManager_preLoad(ShinyManager *self) { - if (!self->_initialized) { - _ShinyManager_init(self); + if (!self->_initialized) { + _ShinyManager_init(self); - _ShinyManager_createNodeTable(self, TABLE_SIZE_INIT); - _ShinyManager_createNodePool(self, TABLE_SIZE_INIT / 2); - } + _ShinyManager_createNodeTable(self, TABLE_SIZE_INIT); + _ShinyManager_createNodePool(self, TABLE_SIZE_INIT / 2); + } } @@ -127,21 +127,21 @@ void ShinyManager_preLoad(ShinyManager *self) { void ShinyManager_update(ShinyManager *self) { #if SHINY_HAS_ENABLED == TRUE - if (!enabled) return; + if (!enabled) return; #endif - _ShinyManager_appendTicksToCurNode(self); - ShinyZone_preUpdateChain(&self->rootZone); + _ShinyManager_appendTicksToCurNode(self); + ShinyZone_preUpdateChain(&self->rootZone); - if (self->_firstUpdate || self->damping == 0) { - self->_firstUpdate = FALSE; - ShinyNode_updateTreeClean(&self->rootNode); - ShinyZone_updateChainClean(&self->rootZone); + if (self->_firstUpdate || self->damping == 0) { + self->_firstUpdate = FALSE; + ShinyNode_updateTreeClean(&self->rootNode); + ShinyZone_updateChainClean(&self->rootZone); - } else { - ShinyNode_updateTree(&self->rootNode, self->damping); - ShinyZone_updateChain(&self->rootZone, self->damping); - } + } else { + ShinyNode_updateTree(&self->rootNode, self->damping); + ShinyZone_updateChain(&self->rootZone, self->damping); + } } @@ -149,296 +149,296 @@ void ShinyManager_update(ShinyManager *self) { void ShinyManager_updateClean(ShinyManager *self) { #if SHINY_HAS_ENABLED == TRUE - if (!enabled) return; + if (!enabled) return; #endif - _ShinyManager_appendTicksToCurNode(self); - ShinyZone_preUpdateChain(&self->rootZone); + _ShinyManager_appendTicksToCurNode(self); + ShinyZone_preUpdateChain(&self->rootZone); - self->_firstUpdate = FALSE; - ShinyNode_updateTreeClean(&self->rootNode); - ShinyZone_updateChainClean(&self->rootZone); + self->_firstUpdate = FALSE; + ShinyNode_updateTreeClean(&self->rootNode); + ShinyZone_updateChainClean(&self->rootZone); } /*---------------------------------------------------------------------------*/ void ShinyManager_clear(ShinyManager *self) { - ShinyManager_destroy(self); - ShinyManager_preLoad(self); + ShinyManager_destroy(self); + ShinyManager_preLoad(self); } /*---------------------------------------------------------------------------*/ void ShinyManager_destroy(ShinyManager *self) { - ShinyManager_destroyNodes(self); - ShinyManager_resetZones(self); - _ShinyManager_uninit(self); + ShinyManager_destroyNodes(self); + ShinyManager_resetZones(self); + _ShinyManager_uninit(self); } /*---------------------------------------------------------------------------*/ ShinyNode* _ShinyManager_lookupNode(ShinyManager *self, ShinyNodeCache *a_cache, ShinyZone *a_zone) { - uint32_t nHash = hash_value(self->_curNode, a_zone); - uint32_t nIndex = nHash & self->_tableMask; - ShinyNode* pNode = self->_nodeTable[nIndex]; + uint32_t nHash = hash_value(self->_curNode, a_zone); + uint32_t nIndex = nHash & self->_tableMask; + ShinyNode* pNode = self->_nodeTable[nIndex]; - _ShinyManager_incLookup(self); - _ShinyManager_incLookupSuccess(self); + _ShinyManager_incLookup(self); + _ShinyManager_incLookupSuccess(self); - if (pNode) { - uint32_t nStep; + if (pNode) { + uint32_t nStep; - if (ShinyNode_isEqual(pNode, self->_curNode, a_zone)) return pNode; /* found it! */ - - /* hash collision: */ + if (ShinyNode_isEqual(pNode, self->_curNode, a_zone)) return pNode; /* found it! */ - /* compute a secondary hash function for stepping */ - nStep = hash_offset(nHash); + /* hash collision: */ - for (;;) { - _ShinyManager_incLookup(self); + /* compute a secondary hash function for stepping */ + nStep = hash_offset(nHash); - nIndex = (nIndex + nStep) & self->_tableMask; - pNode = self->_nodeTable[nIndex]; + for (;;) { + _ShinyManager_incLookup(self); - if (!pNode) break; /* found empty slot */ - else if (ShinyNode_isEqual(pNode, self->_curNode, a_zone)) return pNode; /* found it! */ - } + nIndex = (nIndex + nStep) & self->_tableMask; + pNode = self->_nodeTable[nIndex]; - /* loop is guaranteed to end because the hash table is never full */ - } + if (!pNode) break; /* found empty slot */ + else if (ShinyNode_isEqual(pNode, self->_curNode, a_zone)) return pNode; /* found it! */ + } - if (a_zone->_state == SHINY_ZONE_STATE_HIDDEN) { /* zone is not initialized */ - ShinyZone_init(a_zone, self->_lastZone); + /* loop is guaranteed to end because the hash table is never full */ + } - self->_lastZone = a_zone; - self->zoneCount++; + if (a_zone->_state == SHINY_ZONE_STATE_HIDDEN) { /* zone is not initialized */ + ShinyZone_init(a_zone, self->_lastZone); - if (self->_initialized == FALSE) { /* first time init */ - _ShinyManager_init(self); + self->_lastZone = a_zone; + self->zoneCount++; - _ShinyManager_createNodeTable(self, TABLE_SIZE_INIT); - _ShinyManager_createNodePool(self, TABLE_SIZE_INIT / 2); + if (self->_initialized == FALSE) { /* first time init */ + _ShinyManager_init(self); - /* initialization has invalidated nIndex - * we must compute nIndex again - */ - return _ShinyManager_createNode(self, a_cache, a_zone); - } - } + _ShinyManager_createNodeTable(self, TABLE_SIZE_INIT); + _ShinyManager_createNodePool(self, TABLE_SIZE_INIT / 2); - /* Althouth nodeCount is not updated - * it includes rootNode so it adds up. - * - * check if we need to grow the table - * we keep it at most 1/2 full to be very fast - */ - if (self->_tableSize < 2 * self->nodeCount) { + /* initialization has invalidated nIndex + * we must compute nIndex again + */ + return _ShinyManager_createNode(self, a_cache, a_zone); + } + } - _ShinyManager_resizeNodeTable(self, 2 * self->_tableSize); - _ShinyManager_resizeNodePool(self, self->nodeCount - 1); + /* Althouth nodeCount is not updated + * it includes rootNode so it adds up. + * + * check if we need to grow the table + * we keep it at most 1/2 full to be very fast + */ + if (self->_tableSize < 2 * self->nodeCount) { - /* resize has invalidated nIndex - * we must compute nIndex again - */ - return _ShinyManager_createNode(self, a_cache, a_zone); - } - - self->nodeCount++; + _ShinyManager_resizeNodeTable(self, 2 * self->_tableSize); + _ShinyManager_resizeNodePool(self, self->nodeCount - 1); - { - ShinyNode* pNewNode = ShinyNodePool_newItem(self->_lastNodePool); - ShinyNode_init(pNewNode, self->_curNode, a_zone, a_cache); + /* resize has invalidated nIndex + * we must compute nIndex again + */ + return _ShinyManager_createNode(self, a_cache, a_zone); + } - self->_nodeTable[nIndex] = pNewNode; - return pNewNode; - } + self->nodeCount++; + + { + ShinyNode* pNewNode = ShinyNodePool_newItem(self->_lastNodePool); + ShinyNode_init(pNewNode, self->_curNode, a_zone, a_cache); + + self->_nodeTable[nIndex] = pNewNode; + return pNewNode; + } } /*---------------------------------------------------------------------------*/ void _ShinyManager_insertNode(ShinyManager *self, ShinyNode* a_pNode) { - uint32_t nHash = hash_value(a_pNode->parent, a_pNode->zone); - uint32_t nIndex = nHash & self->_tableMask; + uint32_t nHash = hash_value(a_pNode->parent, a_pNode->zone); + uint32_t nIndex = nHash & self->_tableMask; - if (self->_nodeTable[nIndex]) { - uint32_t nStep = hash_offset(nHash); + if (self->_nodeTable[nIndex]) { + uint32_t nStep = hash_offset(nHash); - while (self->_nodeTable[nIndex]) - nIndex = (nIndex + nStep) & self->_tableMask; - } + while (self->_nodeTable[nIndex]) + nIndex = (nIndex + nStep) & self->_tableMask; + } - self->_nodeTable[nIndex] = a_pNode; + self->_nodeTable[nIndex] = a_pNode; } /*---------------------------------------------------------------------------*/ ShinyNode* _ShinyManager_createNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_pZone) { - ShinyNode* pNewNode = ShinyNodePool_newItem(self->_lastNodePool); - ShinyNode_init(pNewNode, self->_curNode, a_pZone, a_cache); + ShinyNode* pNewNode = ShinyNodePool_newItem(self->_lastNodePool); + ShinyNode_init(pNewNode, self->_curNode, a_pZone, a_cache); - self->nodeCount++; - _ShinyManager_insertNode(self, pNewNode); - return pNewNode; + self->nodeCount++; + _ShinyManager_insertNode(self, pNewNode); + return pNewNode; } /*---------------------------------------------------------------------------*/ void _ShinyManager_createNodePool(ShinyManager *self, uint32_t a_nCount) { - self->_firstNodePool = ShinyNodePool_create(a_nCount); - self->_lastNodePool = self->_firstNodePool; + self->_firstNodePool = ShinyNodePool_create(a_nCount); + self->_lastNodePool = self->_firstNodePool; } /*---------------------------------------------------------------------------*/ void _ShinyManager_resizeNodePool(ShinyManager *self, uint32_t a_nCount) { - ShinyNodePool* pPool = ShinyNodePool_create(a_nCount); - self->_lastNodePool->nextPool = pPool; - self->_lastNodePool = pPool; + ShinyNodePool* pPool = ShinyNodePool_create(a_nCount); + self->_lastNodePool->nextPool = pPool; + self->_lastNodePool = pPool; } /*---------------------------------------------------------------------------*/ void _ShinyManager_createNodeTable(ShinyManager *self, uint32_t a_nCount) { - self->_tableSize = a_nCount; - self->_tableMask = a_nCount - 1; + self->_tableSize = a_nCount; + self->_tableMask = a_nCount - 1; - self->_nodeTable = (ShinyNodeTable*) - malloc(sizeof(ShinyNode) * a_nCount); + self->_nodeTable = (ShinyNodeTable*) + malloc(sizeof(ShinyNode) * a_nCount); - memset(self->_nodeTable, 0, a_nCount * sizeof(ShinyNode*)); + memset(self->_nodeTable, 0, a_nCount * sizeof(ShinyNode*)); } /*---------------------------------------------------------------------------*/ void _ShinyManager_resizeNodeTable(ShinyManager *self, uint32_t a_nCount) { - ShinyNodePool* pPool; + ShinyNodePool* pPool; - free(self->_nodeTable); - _ShinyManager_createNodeTable(self, a_nCount); + free(self->_nodeTable); + _ShinyManager_createNodeTable(self, a_nCount); - pPool = self->_firstNodePool; - while (pPool) { + pPool = self->_firstNodePool; + while (pPool) { - ShinyNode *pIter = ShinyNodePool_firstItem(pPool); + ShinyNode *pIter = ShinyNodePool_firstItem(pPool); - while (pIter != pPool->_nextItem) - _ShinyManager_insertNode(self, pIter++); + while (pIter != pPool->_nextItem) + _ShinyManager_insertNode(self, pIter++); - pPool = pPool->nextPool; - } + pPool = pPool->nextPool; + } } /*---------------------------------------------------------------------------*/ void ShinyManager_resetZones(ShinyManager *self) { - ShinyZone_resetChain(&self->rootZone); - self->_lastZone = &self->rootZone; - self->zoneCount = 1; + ShinyZone_resetChain(&self->rootZone); + self->_lastZone = &self->rootZone; + self->zoneCount = 1; } /*---------------------------------------------------------------------------*/ void ShinyManager_destroyNodes(ShinyManager *self) { - if (self->_firstNodePool) { - ShinyNodePool_destroy(self->_firstNodePool); - self->_firstNodePool = NULL; - } + if (self->_firstNodePool) { + ShinyNodePool_destroy(self->_firstNodePool); + self->_firstNodePool = NULL; + } - if (self->_nodeTable != _ShinyManager_dummyNodeTable) { - free(self->_nodeTable); + if (self->_nodeTable != _ShinyManager_dummyNodeTable) { + free(self->_nodeTable); - self->_nodeTable = _ShinyManager_dummyNodeTable; - self->_tableSize = 1; - self->_tableMask = 0; - } + self->_nodeTable = _ShinyManager_dummyNodeTable; + self->_tableSize = 1; + self->_tableMask = 0; + } - self->_curNode = &self->rootNode; - self->nodeCount = 1; + self->_curNode = &self->rootNode; + self->nodeCount = 1; - _ShinyManager_init(self); + _ShinyManager_init(self); } /*---------------------------------------------------------------------------*/ const char* ShinyManager_getOutputErrorString(ShinyManager *self) { - if (self->_firstUpdate) return "!!! Profile data must first be updated !!!"; - else if (!self->_initialized) return "!!! No profiles where executed !!!"; - else return NULL; + if (self->_firstUpdate) return "!!! Profile data must first be updated !!!"; + else if (!self->_initialized) return "!!! No profiles where executed !!!"; + else return NULL; } /*---------------------------------------------------------------------------*/ #if SHINY_COMPILER == SHINY_COMPILER_MSVC -# pragma warning (push) -# pragma warning (disable: 4996) +# pragma warning (push) +# pragma warning (disable: 4996) #endif int ShinyManager_output(ShinyManager *self, const char *a_filename) { - if (!a_filename) { - ShinyManager_outputToStream(self, stdout); + if (!a_filename) { + ShinyManager_outputToStream(self, stdout); - } else { - FILE *file = fopen(a_filename, "w"); - if (!file) return FALSE; - ShinyManager_outputToStream(self, file); - fclose(file); - } + } else { + FILE *file = fopen(a_filename, "w"); + if (!file) return FALSE; + ShinyManager_outputToStream(self, file); + fclose(file); + } - return TRUE; + return TRUE; } #if SHINY_COMPILER == SHINY_COMPILER_MSVC -# pragma warning (pop) +# pragma warning (pop) #endif /*---------------------------------------------------------------------------*/ void ShinyManager_outputToStream(ShinyManager *self, FILE *a_stream) { - const char *error = ShinyManager_getOutputErrorString(self); + const char *error = ShinyManager_getOutputErrorString(self); - if (error) { - fwrite(error, 1, strlen(error), a_stream); - fwrite("\n\n", 1, 2, a_stream); - return; - } + if (error) { + fwrite(error, 1, strlen(error), a_stream); + fwrite("\n\n", 1, 2, a_stream); + return; + } #if SHINY_OUTPUT_MODE & SHINY_OUTPUT_MODE_FLAT - ShinyManager_sortZones(self); - - { - int size = ShinyPrintZonesSize(self->zoneCount); - char *buffer = (char*) malloc(size); - ShinyPrintZones(buffer, &self->rootZone); - fwrite(buffer, 1, size - 1, a_stream); - fwrite("\n\n", 1, 2, a_stream); - free(buffer); - } + ShinyManager_sortZones(self); + + { + int size = ShinyPrintZonesSize(self->zoneCount); + char *buffer = (char*) malloc(size); + ShinyPrintZones(buffer, &self->rootZone); + fwrite(buffer, 1, size - 1, a_stream); + fwrite("\n\n", 1, 2, a_stream); + free(buffer); + } #endif #if SHINY_OUTPUT_MODE & SHINY_OUTPUT_MODE_TREE - { - int size = ShinyPrintNodesSize(self->nodeCount); - char *buffer = (char*) malloc(size); - ShinyPrintNodes(buffer, &self->rootNode); - fwrite(buffer, 1, size - 1, a_stream); - fwrite("\n\n", 1, 2, a_stream); - free(buffer); - } + { + int size = ShinyPrintNodesSize(self->nodeCount); + char *buffer = (char*) malloc(size); + ShinyPrintNodes(buffer, &self->rootNode); + fwrite(buffer, 1, size - 1, a_stream); + fwrite("\n\n", 1, 2, a_stream); + free(buffer); + } #endif } diff --git a/src/Shiny/ShinyManager.h b/src/Shiny/ShinyManager.h index 403e0e8782c..9e9c4f4c6d1 100644 --- a/src/Shiny/ShinyManager.h +++ b/src/Shiny/ShinyManager.h @@ -41,39 +41,39 @@ extern "C" { typedef struct { #ifdef SHINY_HAS_ENABLED - bool enabled; + bool enabled; #endif - shinytick_t _lastTick; + shinytick_t _lastTick; - ShinyNode* _curNode; + ShinyNode* _curNode; - uint32_t _tableMask; /* = _tableSize - 1 */ + uint32_t _tableMask; /* = _tableSize - 1 */ - ShinyNodeTable* _nodeTable; + ShinyNodeTable* _nodeTable; #ifdef SHINY_LOOKUP_RATE - uint64_t _lookupCount; - uint64_t _lookupSuccessCount; + uint64_t _lookupCount; + uint64_t _lookupSuccessCount; #endif - uint32_t _tableSize; + uint32_t _tableSize; - uint32_t nodeCount; - uint32_t zoneCount; + uint32_t nodeCount; + uint32_t zoneCount; - ShinyZone* _lastZone; + ShinyZone* _lastZone; - ShinyNodePool* _lastNodePool; - ShinyNodePool* _firstNodePool; + ShinyNodePool* _lastNodePool; + ShinyNodePool* _firstNodePool; - ShinyNode rootNode; - ShinyZone rootZone; + ShinyNode rootNode; + ShinyZone rootZone; - float damping; + float damping; - int _initialized; - int _firstUpdate; + int _initialized; + int _firstUpdate; } ShinyManager; @@ -87,11 +87,11 @@ extern ShinyManager Shiny_instance; /*---------------------------------------------------------------------------*/ SHINY_INLINE void _ShinyManager_appendTicksToCurNode(ShinyManager *self) { - shinytick_t curTick; - ShinyGetTicks(&curTick); + shinytick_t curTick; + ShinyGetTicks(&curTick); - ShinyNode_appendTicks(self->_curNode, curTick - self->_lastTick); - self->_lastTick = curTick; + ShinyNode_appendTicks(self->_curNode, curTick - self->_lastTick); + self->_lastTick = curTick; } SHINY_API ShinyNode* _ShinyManager_lookupNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_zone); @@ -106,19 +106,19 @@ SHINY_API ShinyNode* _ShinyManager_createNode(ShinyManager *self, ShinyNodeCache SHINY_API void _ShinyManager_insertNode(ShinyManager *self, ShinyNode* a_pNode); SHINY_INLINE void _ShinyManager_init(ShinyManager *self) { - self->_initialized = TRUE; + self->_initialized = TRUE; - self->rootNode._last.entryCount = 1; - self->rootNode._last.selfTicks = 0; - ShinyGetTicks(&self->_lastTick); + self->rootNode._last.entryCount = 1; + self->rootNode._last.selfTicks = 0; + ShinyGetTicks(&self->_lastTick); } SHINY_INLINE void _ShinyManager_uninit(ShinyManager *self) { - self->_initialized = FALSE; + self->_initialized = FALSE; - ShinyNode_clear(&self->rootNode); - self->rootNode.parent = &self->rootNode; - self->rootNode.zone = &self->rootZone; + ShinyNode_clear(&self->rootNode); + self->rootNode.parent = &self->rootNode; + self->rootNode.zone = &self->rootZone; } #ifdef SHINY_LOOKUP_RATE @@ -136,39 +136,39 @@ SHINY_API void ShinyManager_resetZones(ShinyManager *self); SHINY_API void ShinyManager_destroyNodes(ShinyManager *self); SHINY_INLINE float ShinyManager_tableUsage(const ShinyManager *self) { - return ((float) self->nodeCount) / ((float) self->_tableSize); + return ((float) self->nodeCount) / ((float) self->_tableSize); } SHINY_INLINE uint32_t ShinyManager_allocMemInBytes(const ShinyManager *self) { - return self->_tableSize * sizeof(ShinyNode*) - + (self->_firstNodePool)? ShinyNodePool_memoryUsageChain(self->_firstNodePool) : 0; + return self->_tableSize * sizeof(ShinyNode*) + + (self->_firstNodePool)? ShinyNodePool_memoryUsageChain(self->_firstNodePool) : 0; } SHINY_INLINE void ShinyManager_beginNode(ShinyManager *self, ShinyNode* a_node) { - ShinyNode_beginEntry(a_node); + ShinyNode_beginEntry(a_node); - _ShinyManager_appendTicksToCurNode(self); - self->_curNode = a_node; + _ShinyManager_appendTicksToCurNode(self); + self->_curNode = a_node; } SHINY_INLINE void ShinyManager_lookupAndBeginNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_zone) { #ifdef SHINY_HAS_ENABLED - if (!self->enabled) return; + if (!self->enabled) return; #endif - if (self->_curNode != (*a_cache)->parent) - *a_cache = _ShinyManager_lookupNode(self, a_cache, a_zone); + if (self->_curNode != (*a_cache)->parent) + *a_cache = _ShinyManager_lookupNode(self, a_cache, a_zone); - ShinyManager_beginNode(self, *a_cache); + ShinyManager_beginNode(self, *a_cache); } SHINY_INLINE void ShinyManager_endCurNode(ShinyManager *self) { #ifdef SHINY_HAS_ENABLED - if (!self->enabled) return; + if (!self->enabled) return; #endif - _ShinyManager_appendTicksToCurNode(self); - self->_curNode = self->_curNode->parent; + _ShinyManager_appendTicksToCurNode(self); + self->_curNode = self->_curNode->parent; } /**/ @@ -182,8 +182,8 @@ SHINY_API void ShinyManager_clear(ShinyManager *self); SHINY_API void ShinyManager_destroy(ShinyManager *self); SHINY_INLINE void ShinyManager_sortZones(ShinyManager *self) { - if (self->rootZone.next) - self->_lastZone = ShinyZone_sortChain(&self->rootZone.next); + if (self->rootZone.next) + self->_lastZone = ShinyZone_sortChain(&self->rootZone.next); } SHINY_API const char* ShinyManager_getOutputErrorString(ShinyManager *self); @@ -195,51 +195,51 @@ SHINY_API void ShinyManager_outputToStream(ShinyManager *self, FILE *stream); } /* end of extern "C" */ SHINY_INLINE std::string ShinyManager_outputTreeToString(ShinyManager *self) { - const char* error = ShinyManager_getOutputErrorString(self); - if (error) return error; - else return ShinyNodesToString(&self->rootNode, self->nodeCount); + const char* error = ShinyManager_getOutputErrorString(self); + if (error) return error; + else return ShinyNodesToString(&self->rootNode, self->nodeCount); } SHINY_INLINE std::string ShinyManager_outputFlatToString(ShinyManager *self) { - const char* error = ShinyManager_getOutputErrorString(self); - if (error) return error; + const char* error = ShinyManager_getOutputErrorString(self); + if (error) return error; - ShinyManager_sortZones(self); - return ShinyZonesToString(&self->rootZone, self->zoneCount); + ShinyManager_sortZones(self); + return ShinyZonesToString(&self->rootZone, self->zoneCount); } extern "C" { /* end of c++ */ #endif SHINY_INLINE int ShinyManager_isZoneSelfTimeBelow(ShinyManager *self, ShinyZone* a_zone, float a_percentage) { - return a_percentage * (float) self->rootZone.data.childTicks.cur - <= (float) a_zone->data.selfTicks.cur; + return a_percentage * (float) self->rootZone.data.childTicks.cur + <= (float) a_zone->data.selfTicks.cur; } SHINY_INLINE int ShinyManager_isZoneTotalTimeBelow(ShinyManager *self, ShinyZone* a_zone, float a_percentage) { - return a_percentage * (float) self->rootZone.data.childTicks.cur - <= (float) ShinyData_totalTicksCur(&a_zone->data); + return a_percentage * (float) self->rootZone.data.childTicks.cur + <= (float) ShinyData_totalTicksCur(&a_zone->data); } /**/ SHINY_INLINE void ShinyManager_enumerateNodes(ShinyManager *self, void (*a_func)(const ShinyNode*)) { - ShinyNode_enumerateNodes(&self->rootNode, a_func); + ShinyNode_enumerateNodes(&self->rootNode, a_func); } SHINY_INLINE void ShinyManager_enumerateZones(ShinyManager *self, void (*a_func)(const ShinyZone*)) { - ShinyZone_enumerateZones(&self->rootZone, a_func); + ShinyZone_enumerateZones(&self->rootZone, a_func); } #if __cplusplus } /* end of extern "C" */ template void ShinyManager_enumerateNodes(ShinyManager *self, T* a_this, void (T::*a_func)(const ShinyNode*)) { - ShinyNode_enumerateNodes(&self->rootNode, a_this, a_func); + ShinyNode_enumerateNodes(&self->rootNode, a_this, a_func); } template void ShinyManager_enumerateZones(ShinyManager *self, T* a_this, void (T::*a_func)(const ShinyZone*)) { - ShinyZone_enumerateZones(&self->rootZone, a_this, a_func); + ShinyZone_enumerateZones(&self->rootZone, a_this, a_func); } extern "C" { /* end of c++ */ @@ -254,9 +254,9 @@ extern "C" { /* end of c++ */ class ShinyEndNodeOnDestruction { public: - SHINY_INLINE ~ShinyEndNodeOnDestruction() { - ShinyManager_endCurNode(&Shiny_instance); - } + SHINY_INLINE ~ShinyEndNodeOnDestruction() { + ShinyManager_endCurNode(&Shiny_instance); + } }; #endif diff --git a/src/Shiny/ShinyNode.c b/src/Shiny/ShinyNode.c index 9d777073b02..57fdc9852fc 100644 --- a/src/Shiny/ShinyNode.c +++ b/src/Shiny/ShinyNode.c @@ -33,97 +33,97 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ ShinyNode _ShinyNode_dummy = { - /* _last = */ { 0, 0 }, - /* zone = */ NULL, - /* parent = */ NULL, - /* nextSibling = */ NULL, - /* firstChild = */ NULL, - /* lastChild = */ NULL + /* _last = */ { 0, 0 }, + /* zone = */ NULL, + /* parent = */ NULL, + /* nextSibling = */ NULL, + /* firstChild = */ NULL, + /* lastChild = */ NULL }; /*---------------------------------------------------------------------------*/ void ShinyNode_updateTree(ShinyNode* first, float a_damping) { - ShinyNodeState *top = NULL; - ShinyNode *node = first; - - for (;;) { - do { - top = ShinyNodeState_push(top, node); - node = node->firstChild; - } while (node); - - for (;;) { - node = ShinyNodeState_finishAndGetNext(top, a_damping); - top = ShinyNodeState_pop(top); - - if (node) break; - else if (!top) return; - } - } + ShinyNodeState *top = NULL; + ShinyNode *node = first; + + for (;;) { + do { + top = ShinyNodeState_push(top, node); + node = node->firstChild; + } while (node); + + for (;;) { + node = ShinyNodeState_finishAndGetNext(top, a_damping); + top = ShinyNodeState_pop(top); + + if (node) break; + else if (!top) return; + } + } } /*---------------------------------------------------------------------------*/ void ShinyNode_updateTreeClean(ShinyNode* first) { - ShinyNodeState *top = NULL; - ShinyNode *node = first; - - for (;;) { - do { - top = ShinyNodeState_push(top, node); - node = node->firstChild; - } while (node); - - for (;;) { - node = ShinyNodeState_finishAndGetNextClean(top); - top = ShinyNodeState_pop(top); - - if (node) break; - else if (!top) return; - } - } + ShinyNodeState *top = NULL; + ShinyNode *node = first; + + for (;;) { + do { + top = ShinyNodeState_push(top, node); + node = node->firstChild; + } while (node); + + for (;;) { + node = ShinyNodeState_finishAndGetNextClean(top); + top = ShinyNodeState_pop(top); + + if (node) break; + else if (!top) return; + } + } } /*---------------------------------------------------------------------------*/ const ShinyNode* ShinyNode_findNextInTree(const ShinyNode* self) { - if (self->firstChild) { - return self->firstChild; + if (self->firstChild) { + return self->firstChild; - } else if (self->nextSibling) { - return self->nextSibling; + } else if (self->nextSibling) { + return self->nextSibling; - } else { - ShinyNode* pParent = self->parent; + } else { + ShinyNode* pParent = self->parent; - while (!ShinyNode_isRoot(pParent)) { - if (pParent->nextSibling) return pParent->nextSibling; - else pParent = pParent->parent; - } + while (!ShinyNode_isRoot(pParent)) { + if (pParent->nextSibling) return pParent->nextSibling; + else pParent = pParent->parent; + } - return NULL; - } + return NULL; + } } /*---------------------------------------------------------------------------*/ void ShinyNode_clear(ShinyNode* self) { - memset(self, 0, sizeof(ShinyNode)); + memset(self, 0, sizeof(ShinyNode)); } /*---------------------------------------------------------------------------*/ void ShinyNode_enumerateNodes(const ShinyNode* a_node, void (*a_func)(const ShinyNode*)) { - a_func(a_node); + a_func(a_node); - if (a_node->firstChild) ShinyNode_enumerateNodes(a_node->firstChild, a_func); - if (a_node->nextSibling) ShinyNode_enumerateNodes(a_node->nextSibling, a_func); + if (a_node->firstChild) ShinyNode_enumerateNodes(a_node->firstChild, a_func); + if (a_node->nextSibling) ShinyNode_enumerateNodes(a_node->nextSibling, a_func); } #endif /* SLIC3R_PROFILE */ diff --git a/src/Shiny/ShinyNode.h b/src/Shiny/ShinyNode.h index ee5fdb0de5a..3b25710eb6d 100644 --- a/src/Shiny/ShinyNode.h +++ b/src/Shiny/ShinyNode.h @@ -36,21 +36,21 @@ extern "C" { typedef struct _ShinyNode { - ShinyLastData _last; + ShinyLastData _last; - struct _ShinyZone* zone; - struct _ShinyNode* parent; - struct _ShinyNode* nextSibling; + struct _ShinyZone* zone; + struct _ShinyNode* parent; + struct _ShinyNode* nextSibling; - struct _ShinyNode* firstChild; - struct _ShinyNode* lastChild; + struct _ShinyNode* firstChild; + struct _ShinyNode* lastChild; - uint32_t childCount; - uint32_t entryLevel; + uint32_t childCount; + uint32_t entryLevel; - ShinyNodeCache* _cache; + ShinyNodeCache* _cache; - ShinyData data; + ShinyData data; } ShinyNode; @@ -63,53 +63,53 @@ extern ShinyNode _ShinyNode_dummy; /*---------------------------------------------------------------------------*/ SHINY_INLINE void ShinyNode_addChild(ShinyNode* self, ShinyNode* a_child) { - if (self->childCount++) { - self->lastChild->nextSibling = a_child; - self->lastChild = a_child; - - } else { - self->lastChild = a_child; - self->firstChild = a_child; - } + if (self->childCount++) { + self->lastChild->nextSibling = a_child; + self->lastChild = a_child; + + } else { + self->lastChild = a_child; + self->firstChild = a_child; + } } SHINY_INLINE void ShinyNode_init(ShinyNode* self, ShinyNode* a_parent, struct _ShinyZone* a_zone, ShinyNodeCache* a_cache) { - /* NOTE: all member variables are assumed to be zero when allocated */ + /* NOTE: all member variables are assumed to be zero when allocated */ - self->zone = a_zone; - self->parent = a_parent; + self->zone = a_zone; + self->parent = a_parent; - self->entryLevel = a_parent->entryLevel + 1; - ShinyNode_addChild(a_parent, self); + self->entryLevel = a_parent->entryLevel + 1; + ShinyNode_addChild(a_parent, self); - self->_cache = a_cache; + self->_cache = a_cache; } SHINY_API void ShinyNode_updateTree(ShinyNode* self, float a_damping); SHINY_API void ShinyNode_updateTreeClean(ShinyNode* self); SHINY_INLINE void ShinyNode_destroy(ShinyNode* self) { - *(self->_cache) = &_ShinyNode_dummy; + *(self->_cache) = &_ShinyNode_dummy; } SHINY_INLINE void ShinyNode_appendTicks(ShinyNode* self, shinytick_t a_elapsedTicks) { - self->_last.selfTicks += a_elapsedTicks; + self->_last.selfTicks += a_elapsedTicks; } SHINY_INLINE void ShinyNode_beginEntry(ShinyNode* self) { - self->_last.entryCount++; + self->_last.entryCount++; } SHINY_INLINE int ShinyNode_isRoot(ShinyNode* self) { - return (self->entryLevel == 0); + return (self->entryLevel == 0); } SHINY_INLINE int ShinyNode_isDummy(ShinyNode* self) { - return (self == &_ShinyNode_dummy); + return (self == &_ShinyNode_dummy); } SHINY_INLINE int ShinyNode_isEqual(ShinyNode* self, const ShinyNode* a_parent, const struct _ShinyZone* a_zone) { - return (self->parent == a_parent && self->zone == a_zone); + return (self->parent == a_parent && self->zone == a_zone); } SHINY_API const ShinyNode* ShinyNode_findNextInTree(const ShinyNode* self); @@ -123,10 +123,10 @@ SHINY_API void ShinyNode_enumerateNodes(const ShinyNode* a_node, void (*a_func)( template void ShinyNode_enumerateNodes(const ShinyNode* a_node, T* a_this, void (T::*a_func)(const ShinyNode*)) { - (a_this->*a_func)(a_node); + (a_this->*a_func)(a_node); - if (a_node->firstChild) ShinyNode_enumerateNodes(a_node->firstChild, a_this, a_func); - if (a_node->nextSibling) ShinyNode_enumerateNodes(a_node->nextSibling, a_this, a_func); + if (a_node->firstChild) ShinyNode_enumerateNodes(a_node->firstChild, a_this, a_func); + if (a_node->nextSibling) ShinyNode_enumerateNodes(a_node->nextSibling, a_this, a_func); } #endif /* __cplusplus */ diff --git a/src/Shiny/ShinyNodePool.c b/src/Shiny/ShinyNodePool.c index f00293252cb..8b677fd409d 100644 --- a/src/Shiny/ShinyNodePool.c +++ b/src/Shiny/ShinyNodePool.c @@ -33,45 +33,45 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ ShinyNodePool* ShinyNodePool_create(uint32_t a_items) { - ShinyNodePool* pPool = (ShinyNodePool*) - malloc(sizeof(ShinyNodePool) + sizeof(ShinyNode) * (a_items - 1)); + ShinyNodePool* pPool = (ShinyNodePool*) + malloc(sizeof(ShinyNodePool) + sizeof(ShinyNode) * (a_items - 1)); - pPool->nextPool = NULL; - pPool->_nextItem = &pPool->_items[0]; - pPool->endOfItems = &pPool->_items[a_items]; + pPool->nextPool = NULL; + pPool->_nextItem = &pPool->_items[0]; + pPool->endOfItems = &pPool->_items[a_items]; - memset(&pPool->_items[0], 0, a_items * sizeof(ShinyNode)); - return pPool; + memset(&pPool->_items[0], 0, a_items * sizeof(ShinyNode)); + return pPool; } /*---------------------------------------------------------------------------*/ uint32_t ShinyNodePool_memoryUsageChain(ShinyNodePool *first) { - uint32_t bytes = (uint32_t) ((char*) first->endOfItems - (char*) first); - ShinyNodePool *pool = first->nextPool; + uint32_t bytes = (uint32_t) ((char*) first->endOfItems - (char*) first); + ShinyNodePool *pool = first->nextPool; - while (pool) { - bytes += (uint32_t) ((char*) pool->endOfItems - (char*) pool); - pool = pool->nextPool; - } + while (pool) { + bytes += (uint32_t) ((char*) pool->endOfItems - (char*) pool); + pool = pool->nextPool; + } - return bytes; + return bytes; } /*---------------------------------------------------------------------------*/ void ShinyNodePool_destroy(ShinyNodePool *self) { - ShinyNode* firstNode = ShinyNodePool_firstItem(self); - ShinyNode* lastNode = self->_nextItem; + ShinyNode* firstNode = ShinyNodePool_firstItem(self); + ShinyNode* lastNode = self->_nextItem; - while (firstNode != lastNode) - ShinyNode_destroy(firstNode++); + while (firstNode != lastNode) + ShinyNode_destroy(firstNode++); - /* TODO: make this into a loop or a tail recursion */ - if (self->nextPool) ShinyNodePool_destroy(self->nextPool); - free(self); + /* TODO: make this into a loop or a tail recursion */ + if (self->nextPool) ShinyNodePool_destroy(self->nextPool); + free(self); } #endif /* SLIC3R_PROFILE */ diff --git a/src/Shiny/ShinyNodePool.h b/src/Shiny/ShinyNodePool.h index 5e30a3306bb..91d3877153e 100644 --- a/src/Shiny/ShinyNodePool.h +++ b/src/Shiny/ShinyNodePool.h @@ -35,12 +35,12 @@ extern "C" { typedef struct _ShinyNodePool { - struct _ShinyNodePool* nextPool; + struct _ShinyNodePool* nextPool; - ShinyNode *_nextItem; - ShinyNode *endOfItems; + ShinyNode *_nextItem; + ShinyNode *endOfItems; - ShinyNode _items[1]; + ShinyNode _items[1]; } ShinyNodePool; @@ -48,11 +48,11 @@ typedef struct _ShinyNodePool { /*---------------------------------------------------------------------------*/ SHINY_INLINE ShinyNode* ShinyNodePool_firstItem(ShinyNodePool *self) { - return &(self->_items[0]); + return &(self->_items[0]); } SHINY_INLINE ShinyNode* ShinyNodePool_newItem(ShinyNodePool *self) { - return self->_nextItem++; + return self->_nextItem++; } ShinyNodePool* ShinyNodePool_create(uint32_t a_items); diff --git a/src/Shiny/ShinyNodeState.c b/src/Shiny/ShinyNodeState.c index fbf6dc8704e..6d25c6cbf82 100644 --- a/src/Shiny/ShinyNodeState.c +++ b/src/Shiny/ShinyNodeState.c @@ -33,76 +33,76 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ ShinyNodeState* ShinyNodeState_push(ShinyNodeState *a_top, ShinyNode *a_node) { - ShinyZone *zone = a_node->zone; - ShinyNodeState *self = (ShinyNodeState*) malloc(sizeof(ShinyNodeState)); - self->node = a_node; - self->_prev = a_top; - - a_node->data.selfTicks.cur = a_node->_last.selfTicks; - a_node->data.entryCount.cur = a_node->_last.entryCount; - - zone->data.selfTicks.cur += a_node->_last.selfTicks; - zone->data.entryCount.cur += a_node->_last.entryCount; - - a_node->data.childTicks.cur = 0; - a_node->_last.selfTicks = 0; - a_node->_last.entryCount = 0; - - self->zoneUpdating = zone->_state != SHINY_ZONE_STATE_UPDATING; - if (self->zoneUpdating) { - zone->_state = SHINY_ZONE_STATE_UPDATING; - } else { - zone->data.childTicks.cur -= a_node->data.selfTicks.cur; - } - - return self; + ShinyZone *zone = a_node->zone; + ShinyNodeState *self = (ShinyNodeState*) malloc(sizeof(ShinyNodeState)); + self->node = a_node; + self->_prev = a_top; + + a_node->data.selfTicks.cur = a_node->_last.selfTicks; + a_node->data.entryCount.cur = a_node->_last.entryCount; + + zone->data.selfTicks.cur += a_node->_last.selfTicks; + zone->data.entryCount.cur += a_node->_last.entryCount; + + a_node->data.childTicks.cur = 0; + a_node->_last.selfTicks = 0; + a_node->_last.entryCount = 0; + + self->zoneUpdating = zone->_state != SHINY_ZONE_STATE_UPDATING; + if (self->zoneUpdating) { + zone->_state = SHINY_ZONE_STATE_UPDATING; + } else { + zone->data.childTicks.cur -= a_node->data.selfTicks.cur; + } + + return self; } /*---------------------------------------------------------------------------*/ ShinyNodeState* ShinyNodeState_pop(ShinyNodeState *a_top) { - ShinyNodeState *prev = a_top->_prev; - free(a_top); - return prev; + ShinyNodeState *prev = a_top->_prev; + free(a_top); + return prev; } /*---------------------------------------------------------------------------*/ ShinyNode* ShinyNodeState_finishAndGetNext(ShinyNodeState *self, float a_damping) { - ShinyNode *node = self->node; - ShinyZone *zone = node->zone; + ShinyNode *node = self->node; + ShinyZone *zone = node->zone; - if (self->zoneUpdating) { - zone->data.childTicks.cur += node->data.childTicks.cur; - zone->_state = SHINY_ZONE_STATE_INITIALIZED; - } + if (self->zoneUpdating) { + zone->data.childTicks.cur += node->data.childTicks.cur; + zone->_state = SHINY_ZONE_STATE_INITIALIZED; + } - ShinyData_computeAverage(&node->data, a_damping); + ShinyData_computeAverage(&node->data, a_damping); - if (!ShinyNode_isRoot(node)) - node->parent->data.childTicks.cur += node->data.selfTicks.cur + node->data.childTicks.cur; + if (!ShinyNode_isRoot(node)) + node->parent->data.childTicks.cur += node->data.selfTicks.cur + node->data.childTicks.cur; - return node->nextSibling; + return node->nextSibling; } /*---------------------------------------------------------------------------*/ ShinyNode* ShinyNodeState_finishAndGetNextClean(ShinyNodeState *self) { - ShinyNode *node = self->node; - ShinyZone *zone = node->zone; + ShinyNode *node = self->node; + ShinyZone *zone = node->zone; - if (self->zoneUpdating) { - zone->data.childTicks.cur += node->data.childTicks.cur; - zone->_state = SHINY_ZONE_STATE_INITIALIZED; - } + if (self->zoneUpdating) { + zone->data.childTicks.cur += node->data.childTicks.cur; + zone->_state = SHINY_ZONE_STATE_INITIALIZED; + } - ShinyData_copyAverage(&node->data); + ShinyData_copyAverage(&node->data); - if (!ShinyNode_isRoot(node)) - node->parent->data.childTicks.cur += node->data.selfTicks.cur + node->data.childTicks.cur; + if (!ShinyNode_isRoot(node)) + node->parent->data.childTicks.cur += node->data.selfTicks.cur + node->data.childTicks.cur; - return node->nextSibling; + return node->nextSibling; } #endif /* SLIC3R_PROFILE */ diff --git a/src/Shiny/ShinyNodeState.h b/src/Shiny/ShinyNodeState.h index 62fdd4ba86e..9e596dbac34 100644 --- a/src/Shiny/ShinyNodeState.h +++ b/src/Shiny/ShinyNodeState.h @@ -34,10 +34,10 @@ extern "C" { /*---------------------------------------------------------------------------*/ typedef struct _ShinyNodeState { - ShinyNode *node; - int zoneUpdating; + ShinyNode *node; + int zoneUpdating; - struct _ShinyNodeState *_prev; + struct _ShinyNodeState *_prev; } ShinyNodeState; diff --git a/src/Shiny/ShinyOutput.c b/src/Shiny/ShinyOutput.c index c2c624d589b..e68a0f66228 100644 --- a/src/Shiny/ShinyOutput.c +++ b/src/Shiny/ShinyOutput.c @@ -29,161 +29,161 @@ THE SOFTWARE. #include #if SHINY_COMPILER == SHINY_COMPILER_MSVC -# pragma warning(disable: 4996) -# define snprintf _snprintf -# define TRAILING 0 +# pragma warning(disable: 4996) +# define snprintf _snprintf +# define TRAILING 0 #else -# define TRAILING 1 +# define TRAILING 1 #endif /*---------------------------------------------------------------------------*/ -#define OUTPUT_WIDTH_CALL 6 -#define OUTPUT_WIDTH_TIME (6+3) -#define OUTPUT_WIDTH_PERC (4+3) -#define OUTPUT_WIDTH_SUM 120 +#define OUTPUT_WIDTH_CALL 6 +#define OUTPUT_WIDTH_TIME (6+3) +#define OUTPUT_WIDTH_PERC (4+3) +#define OUTPUT_WIDTH_SUM 120 -#define OUTPUT_WIDTH_DATA (1+OUTPUT_WIDTH_CALL + 1 + 2*(OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1) + 1) -#define OUTPUT_WIDTH_NAME (OUTPUT_WIDTH_SUM - OUTPUT_WIDTH_DATA) +#define OUTPUT_WIDTH_DATA (1+OUTPUT_WIDTH_CALL + 1 + 2*(OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1) + 1) +#define OUTPUT_WIDTH_NAME (OUTPUT_WIDTH_SUM - OUTPUT_WIDTH_DATA) /*---------------------------------------------------------------------------*/ SHINY_INLINE char* printHeader(char *output, const char *a_title) { - snprintf(output, OUTPUT_WIDTH_SUM + TRAILING, - "%-*s %*s %*s %*s", - OUTPUT_WIDTH_NAME, a_title, - OUTPUT_WIDTH_CALL, "calls", - OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1, "self time", - OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1, "total time"); - - return output + OUTPUT_WIDTH_SUM; + snprintf(output, OUTPUT_WIDTH_SUM + TRAILING, + "%-*s %*s %*s %*s", + OUTPUT_WIDTH_NAME, a_title, + OUTPUT_WIDTH_CALL, "calls", + OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1, "self time", + OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1, "total time"); + + return output + OUTPUT_WIDTH_SUM; } /*---------------------------------------------------------------------------*/ SHINY_INLINE char* printData(char *output, const ShinyData *a_data, float a_topercent) { - float totalTicksAvg = ShinyData_totalTicksAvg(a_data); - const ShinyTimeUnit *selfUnit = ShinyGetTimeUnit(a_data->selfTicks.avg); - const ShinyTimeUnit *totalUnit = ShinyGetTimeUnit(totalTicksAvg); - - snprintf(output, OUTPUT_WIDTH_DATA + TRAILING, - " %*.1f %*.2f %-2s %*.2f%% %*.2f %-2s %*.2f%%", - OUTPUT_WIDTH_CALL, a_data->entryCount.avg, - OUTPUT_WIDTH_TIME, a_data->selfTicks.avg * selfUnit->invTickFreq, selfUnit->suffix, - OUTPUT_WIDTH_PERC, a_data->selfTicks.avg * a_topercent, - OUTPUT_WIDTH_TIME, totalTicksAvg * totalUnit->invTickFreq, totalUnit->suffix, - OUTPUT_WIDTH_PERC, totalTicksAvg * a_topercent); - - return output + OUTPUT_WIDTH_DATA; + float totalTicksAvg = ShinyData_totalTicksAvg(a_data); + const ShinyTimeUnit *selfUnit = ShinyGetTimeUnit(a_data->selfTicks.avg); + const ShinyTimeUnit *totalUnit = ShinyGetTimeUnit(totalTicksAvg); + + snprintf(output, OUTPUT_WIDTH_DATA + TRAILING, + " %*.1f %*.2f %-2s %*.2f%% %*.2f %-2s %*.2f%%", + OUTPUT_WIDTH_CALL, a_data->entryCount.avg, + OUTPUT_WIDTH_TIME, a_data->selfTicks.avg * selfUnit->invTickFreq, selfUnit->suffix, + OUTPUT_WIDTH_PERC, a_data->selfTicks.avg * a_topercent, + OUTPUT_WIDTH_TIME, totalTicksAvg * totalUnit->invTickFreq, totalUnit->suffix, + OUTPUT_WIDTH_PERC, totalTicksAvg * a_topercent); + + return output + OUTPUT_WIDTH_DATA; } /*---------------------------------------------------------------------------*/ SHINY_INLINE char* printNode(char* output, const ShinyNode *a_node, float a_topercent) { - int offset = a_node->entryLevel * 2; + int offset = a_node->entryLevel * 2; - snprintf(output, OUTPUT_WIDTH_NAME + TRAILING, "%*s%-*s", - offset, "", OUTPUT_WIDTH_NAME - offset, a_node->zone->name); + snprintf(output, OUTPUT_WIDTH_NAME + TRAILING, "%*s%-*s", + offset, "", OUTPUT_WIDTH_NAME - offset, a_node->zone->name); - output += OUTPUT_WIDTH_NAME; + output += OUTPUT_WIDTH_NAME; - output = printData(output, &a_node->data, a_topercent); - return output; + output = printData(output, &a_node->data, a_topercent); + return output; } /*---------------------------------------------------------------------------*/ SHINY_INLINE char* printZone(char* output, const ShinyZone *a_zone, float a_topercent) { - snprintf(output, OUTPUT_WIDTH_NAME + TRAILING, "%-*s", - OUTPUT_WIDTH_NAME, a_zone->name); + snprintf(output, OUTPUT_WIDTH_NAME + TRAILING, "%-*s", + OUTPUT_WIDTH_NAME, a_zone->name); - output += OUTPUT_WIDTH_NAME; + output += OUTPUT_WIDTH_NAME; - output = printData(output, &a_zone->data, a_topercent); - return output; + output = printData(output, &a_zone->data, a_topercent); + return output; } /*---------------------------------------------------------------------------*/ int ShinyPrintNodesSize(uint32_t a_count) { - return (1 + a_count) * (OUTPUT_WIDTH_SUM + 1); + return (1 + a_count) * (OUTPUT_WIDTH_SUM + 1); } /*---------------------------------------------------------------------------*/ int ShinyPrintZonesSize(uint32_t a_count) { - return (1 + a_count) * (OUTPUT_WIDTH_SUM + 1); + return (1 + a_count) * (OUTPUT_WIDTH_SUM + 1); } /*---------------------------------------------------------------------------*/ void ShinyPrintANode(char* output, const ShinyNode *a_node, const ShinyNode *a_root) { - float fTicksToPc = 100.0f / a_root->data.childTicks.avg; - output = printNode(output, a_node, fTicksToPc); - (*output++) = '\0'; + float fTicksToPc = 100.0f / a_root->data.childTicks.avg; + output = printNode(output, a_node, fTicksToPc); + (*output++) = '\0'; } /*---------------------------------------------------------------------------*/ void ShinyPrintAZone(char* output, const ShinyZone *a_zone, const ShinyZone *a_root) { - float fTicksToPc = 100.0f / a_root->data.childTicks.avg; - output = printZone(output, a_zone, fTicksToPc); - (*output++) = '\0'; + float fTicksToPc = 100.0f / a_root->data.childTicks.avg; + output = printZone(output, a_zone, fTicksToPc); + (*output++) = '\0'; } /*---------------------------------------------------------------------------*/ void ShinyPrintNodes(char* output, const ShinyNode *a_root) { - float fTicksToPc = 100.0f / a_root->data.childTicks.avg; - const ShinyNode *node = a_root; - - output = printHeader(output, "call tree"); - (*output++) = '\n'; - - for (;;) { - output = printNode(output, node, fTicksToPc); - - node = ShinyNode_findNextInTree(node); - if (node) { - (*output++) = '\n'; - } else { - (*output++) = '\0'; - return; - } - } + float fTicksToPc = 100.0f / a_root->data.childTicks.avg; + const ShinyNode *node = a_root; + + output = printHeader(output, "call tree"); + (*output++) = '\n'; + + for (;;) { + output = printNode(output, node, fTicksToPc); + + node = ShinyNode_findNextInTree(node); + if (node) { + (*output++) = '\n'; + } else { + (*output++) = '\0'; + return; + } + } } /*---------------------------------------------------------------------------*/ void ShinyPrintZones(char* output, const ShinyZone *a_root) { - float fTicksToPc = 100.0f / a_root->data.childTicks.avg; - const ShinyZone *zone = a_root; - - output = printHeader(output, "sorted list"); - (*output++) = '\n'; - - for (;;) { - output = printZone(output, zone, fTicksToPc); - - zone = zone->next; - if (zone) { - (*output++) = '\n'; - } else { - (*output++) = '\0'; - return; - } - } + float fTicksToPc = 100.0f / a_root->data.childTicks.avg; + const ShinyZone *zone = a_root; + + output = printHeader(output, "sorted list"); + (*output++) = '\n'; + + for (;;) { + output = printZone(output, zone, fTicksToPc); + + zone = zone->next; + if (zone) { + (*output++) = '\n'; + } else { + (*output++) = '\0'; + return; + } + } } #endif /* SLIC3R_PROFILE */ diff --git a/src/Shiny/ShinyOutput.h b/src/Shiny/ShinyOutput.h index 81c1783dbe6..1a9fd8b9450 100644 --- a/src/Shiny/ShinyOutput.h +++ b/src/Shiny/ShinyOutput.h @@ -51,17 +51,17 @@ SHINY_API void ShinyPrintZones(char* output, const ShinyZone *a_root); #include SHINY_INLINE std::string ShinyNodesToString(const ShinyNode *a_root, uint32_t a_count) { - std::string str; - str.resize(ShinyPrintNodesSize(a_count) - 1); - ShinyPrintNodes(&str[0], a_root); - return str; + std::string str; + str.resize(ShinyPrintNodesSize(a_count) - 1); + ShinyPrintNodes(&str[0], a_root); + return str; } SHINY_INLINE std::string ShinyZonesToString(const ShinyZone *a_root, uint32_t a_count) { - std::string str; - str.resize(ShinyPrintZonesSize(a_count) - 1); - ShinyPrintZones(&str[0], a_root); - return str; + std::string str; + str.resize(ShinyPrintZonesSize(a_count) - 1); + ShinyPrintZones(&str[0], a_root); + return str; } #endif /* __cplusplus */ diff --git a/src/Shiny/ShinyPrereqs.h b/src/Shiny/ShinyPrereqs.h index 5a3044dbce9..89f98cdc46a 100644 --- a/src/Shiny/ShinyPrereqs.h +++ b/src/Shiny/ShinyPrereqs.h @@ -31,15 +31,15 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ #ifndef FALSE -#define FALSE 0x0 +#define FALSE 0x0 #endif #ifndef TRUE -#define TRUE 0x1 +#define TRUE 0x1 #endif #ifndef NULL -#define NULL 0 +#define NULL 0 #endif #include "ShinyConfig.h" @@ -51,31 +51,31 @@ extern "C" { /*---------------------------------------------------------------------------*/ -#define SHINY_PLATFORM_WIN32 0x1 -#define SHINY_PLATFORM_POSIX 0x2 +#define SHINY_PLATFORM_WIN32 0x1 +#define SHINY_PLATFORM_POSIX 0x2 #if defined (_WIN32) -# define SHINY_PLATFORM SHINY_PLATFORM_WIN32 +# define SHINY_PLATFORM SHINY_PLATFORM_WIN32 #else /* ASSUME: POSIX-compliant OS */ -# define SHINY_PLATFORM SHINY_PLATFORM_POSIX +# define SHINY_PLATFORM SHINY_PLATFORM_POSIX #endif /*---------------------------------------------------------------------------*/ -#define SHINY_COMPILER_MSVC 0x1 -#define SHINY_COMPILER_GNUC 0x2 -#define SHINY_COMPILER_OTHER 0x3 +#define SHINY_COMPILER_MSVC 0x1 +#define SHINY_COMPILER_GNUC 0x2 +#define SHINY_COMPILER_OTHER 0x3 #if defined (_MSC_VER) -# define SHINY_COMPILER SHINY_COMPILER_MSVC +# define SHINY_COMPILER SHINY_COMPILER_MSVC #elif defined (__GNUG__) -# define SHINY_COMPILER SHINY_COMPILER_GNUC +# define SHINY_COMPILER SHINY_COMPILER_GNUC #else -# define SHINY_COMPILER SHINY_COMPILER_OTHER +# define SHINY_COMPILER SHINY_COMPILER_OTHER #endif @@ -102,34 +102,34 @@ typedef struct _ShinyNode* ShinyNodeTable; /*---------------------------------------------------------------------------*/ #if SHINY_COMPILER == SHINY_COMPILER_MSVC -# define SHINY_INLINE __inline -# define SHINY_UNUSED +# define SHINY_INLINE __inline +# define SHINY_UNUSED #elif SHINY_COMPILER == SHINY_COMPILER_GNUC -# define SHINY_INLINE inline -# define SHINY_UNUSED __attribute__((unused)) +# define SHINY_INLINE inline +# define SHINY_UNUSED __attribute__((unused)) #elif SHINY_COMPILER == SHINY_COMPILER_OTHER -# define SHINY_INLINE inline -# define SHINY_UNUSED +# define SHINY_INLINE inline +# define SHINY_UNUSED #endif /*---------------------------------------------------------------------------*/ #if SHINY_COMPILER == SHINY_COMPILER_MSVC - typedef int int32_t; - typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned int uint32_t; - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; /* #elif defined(__CYGWIN__) - typedef u_int32_t uint32_t; - typedef u_int64_t uint64_t; + typedef u_int32_t uint32_t; + typedef u_int64_t uint64_t; */ #endif - typedef uint64_t shinytick_t; + typedef uint64_t shinytick_t; #if __cplusplus } /* end of extern "C" */ diff --git a/src/Shiny/ShinyTools.c b/src/Shiny/ShinyTools.c index 4058e22853a..c349c244940 100644 --- a/src/Shiny/ShinyTools.c +++ b/src/Shiny/ShinyTools.c @@ -29,7 +29,7 @@ THE SOFTWARE. #if SHINY_PLATFORM == SHINY_PLATFORM_WIN32 #define WIN32_LEAN_AND_MEAN #ifndef NOMINMAX - #define NOMINMAX + #define NOMINMAX #endif /* NOMINMAX */ #include @@ -41,30 +41,30 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ const ShinyTimeUnit* ShinyGetTimeUnit(float ticks) { - static ShinyTimeUnit units[4] = { 0 }; - - if (units[0].tickFreq == 0) { /* auto initialize first time */ - units[0].tickFreq = ShinyGetTickFreq() / 1.0f; - units[0].invTickFreq = ShinyGetTickInvFreq() * 1.0f; - units[0].suffix = "s"; - - units[1].tickFreq = ShinyGetTickFreq() / 1000.0f; - units[1].invTickFreq = ShinyGetTickInvFreq() * 1000.0f; - units[1].suffix = "ms"; - - units[2].tickFreq = ShinyGetTickFreq() / 1000000.0f; - units[2].invTickFreq = ShinyGetTickInvFreq() * 1000000.0f; - units[2].suffix = "us"; - - units[3].tickFreq = ShinyGetTickFreq() / 1000000000.0f; - units[3].invTickFreq = ShinyGetTickInvFreq() * 1000000000.0f; - units[3].suffix = "ns"; - } - - if (units[0].tickFreq < ticks) return &units[0]; - else if (units[1].tickFreq < ticks) return &units[1]; - else if (units[2].tickFreq < ticks) return &units[2]; - else return &units[3]; + static ShinyTimeUnit units[4] = { 0 }; + + if (units[0].tickFreq == 0) { /* auto initialize first time */ + units[0].tickFreq = ShinyGetTickFreq() / 1.0f; + units[0].invTickFreq = ShinyGetTickInvFreq() * 1.0f; + units[0].suffix = "s"; + + units[1].tickFreq = ShinyGetTickFreq() / 1000.0f; + units[1].invTickFreq = ShinyGetTickInvFreq() * 1000.0f; + units[1].suffix = "ms"; + + units[2].tickFreq = ShinyGetTickFreq() / 1000000.0f; + units[2].invTickFreq = ShinyGetTickInvFreq() * 1000000.0f; + units[2].suffix = "us"; + + units[3].tickFreq = ShinyGetTickFreq() / 1000000000.0f; + units[3].invTickFreq = ShinyGetTickInvFreq() * 1000000000.0f; + units[3].suffix = "ns"; + } + + if (units[0].tickFreq < ticks) return &units[0]; + else if (units[1].tickFreq < ticks) return &units[1]; + else if (units[2].tickFreq < ticks) return &units[2]; + else return &units[3]; } @@ -73,19 +73,19 @@ const ShinyTimeUnit* ShinyGetTimeUnit(float ticks) { #if SHINY_PLATFORM == SHINY_PLATFORM_WIN32 void ShinyGetTicks(shinytick_t *p) { - QueryPerformanceCounter((LARGE_INTEGER*)(p)); + QueryPerformanceCounter((LARGE_INTEGER*)(p)); } shinytick_t ShinyGetTickFreq(void) { - static shinytick_t freq = 0; - if (freq == 0) QueryPerformanceFrequency((LARGE_INTEGER*)(&freq)); - return freq; + static shinytick_t freq = 0; + if (freq == 0) QueryPerformanceFrequency((LARGE_INTEGER*)(&freq)); + return freq; } float ShinyGetTickInvFreq(void) { - static float invfreq = 0; - if (invfreq == 0) invfreq = 1.0f / ShinyGetTickFreq(); - return invfreq; + static float invfreq = 0; + if (invfreq == 0) invfreq = 1.0f / ShinyGetTickFreq(); + return invfreq; } @@ -97,18 +97,18 @@ float ShinyGetTickInvFreq(void) { //#include void ShinyGetTicks(shinytick_t *p) { - struct timeval time; - gettimeofday(&time, NULL); + struct timeval time; + gettimeofday(&time, NULL); - *p = time.tv_sec * 1000000 + time.tv_usec; + *p = time.tv_sec * 1000000 + time.tv_usec; } shinytick_t ShinyGetTickFreq(void) { - return 1000000; + return 1000000; } float ShinyGetTickInvFreq(void) { - return 1.0f / 1000000.0f; + return 1.0f / 1000000.0f; } #endif diff --git a/src/Shiny/ShinyTools.h b/src/Shiny/ShinyTools.h index 379703ee64a..54bc3b79143 100644 --- a/src/Shiny/ShinyTools.h +++ b/src/Shiny/ShinyTools.h @@ -34,9 +34,9 @@ extern "C" { /*---------------------------------------------------------------------------*/ typedef struct { - float tickFreq; - float invTickFreq; - const char* suffix; + float tickFreq; + float invTickFreq; + const char* suffix; } ShinyTimeUnit; diff --git a/src/Shiny/ShinyVersion.h b/src/Shiny/ShinyVersion.h index fe6cd4a3388..8232230fe20 100644 --- a/src/Shiny/ShinyVersion.h +++ b/src/Shiny/ShinyVersion.h @@ -28,10 +28,10 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ -#define SHINY_VERSION "2.6 RC1" -#define SHINY_SHORTNAME "Shiny" -#define SHINY_FULLNAME "Shiny Profiler" -#define SHINY_COPYRIGHT "Copyright (C) 2007-2010 Aidin Abedi" -#define SHINY_DESCRIPTION "Shiny is a state of the art profiler designed to help finding bottlenecks in your project." +#define SHINY_VERSION "2.6 RC1" +#define SHINY_SHORTNAME "Shiny" +#define SHINY_FULLNAME "Shiny Profiler" +#define SHINY_COPYRIGHT "Copyright (C) 2007-2010 Aidin Abedi" +#define SHINY_DESCRIPTION "Shiny is a state of the art profiler designed to help finding bottlenecks in your project." #endif /* SHINY_VERSION_H */ diff --git a/src/Shiny/ShinyZone.c b/src/Shiny/ShinyZone.c index 99d90d9276d..3435e4611ee 100644 --- a/src/Shiny/ShinyZone.c +++ b/src/Shiny/ShinyZone.c @@ -31,50 +31,50 @@ THE SOFTWARE. /*---------------------------------------------------------------------------*/ void ShinyZone_preUpdateChain(ShinyZone *first) { - ShinyZone* zone = first; + ShinyZone* zone = first; - while (zone) { - ShinyData_clearCurrent(&(zone->data)); - zone = zone->next; - } + while (zone) { + ShinyData_clearCurrent(&(zone->data)); + zone = zone->next; + } } /*---------------------------------------------------------------------------*/ void ShinyZone_updateChain(ShinyZone *first, float a_damping) { - ShinyZone* zone = first; + ShinyZone* zone = first; - do { - ShinyData_computeAverage(&(zone->data), a_damping); - zone = zone->next; - } while (zone); + do { + ShinyData_computeAverage(&(zone->data), a_damping); + zone = zone->next; + } while (zone); } /*---------------------------------------------------------------------------*/ void ShinyZone_updateChainClean(ShinyZone *first) { - ShinyZone* zone = first; + ShinyZone* zone = first; - do { - ShinyData_copyAverage(&(zone->data)); - zone = zone->next; - } while (zone); + do { + ShinyData_copyAverage(&(zone->data)); + zone = zone->next; + } while (zone); } /*---------------------------------------------------------------------------*/ void ShinyZone_resetChain(ShinyZone *first) { - ShinyZone* zone = first, *temp; - - do { - zone->_state = SHINY_ZONE_STATE_HIDDEN; - temp = zone->next; - zone->next = NULL; - zone = temp; - } while (zone); + ShinyZone* zone = first, *temp; + + do { + zone->_state = SHINY_ZONE_STATE_HIDDEN; + temp = zone->next; + zone->next = NULL; + zone = temp; + } while (zone); } /*---------------------------------------------------------------------------*/ @@ -89,113 +89,113 @@ void ShinyZone_resetChain(ShinyZone *first) { ShinyZone* ShinyZone_sortChain(ShinyZone **first) /* return ptr to last zone */ { - ShinyZone *p = *first; - - unsigned base; - unsigned long block_size; - - struct tape - { - ShinyZone *first, *last; - unsigned long count; - } tape[4]; - - /* Distribute the records alternately to tape[0] and tape[1]. */ - - tape[0].count = tape[1].count = 0L; - tape[0].first = NULL; - base = 0; - while (p != NULL) - { - ShinyZone *next = p->next; - p->next = tape[base].first; - tape[base].first = p; - tape[base].count++; - p = next; - base ^= 1; - } - - /* If the list is empty or contains only a single record, then */ - /* tape[1].count == 0L and this part is vacuous. */ - - for (base = 0, block_size = 1L; tape[base+1].count != 0L; - base ^= 2, block_size <<= 1) - { - int dest; - struct tape *tape0, *tape1; - tape0 = tape + base; - tape1 = tape + base + 1; - dest = base ^ 2; - tape[dest].count = tape[dest+1].count = 0; - for (; tape0->count != 0; dest ^= 1) - { - unsigned long n0, n1; - struct tape *output_tape = tape + dest; - n0 = n1 = block_size; - while (1) - { - ShinyZone *chosen_record; - struct tape *chosen_tape; - if (n0 == 0 || tape0->count == 0) - { - if (n1 == 0 || tape1->count == 0) - break; - chosen_tape = tape1; - n1--; - } - else if (n1 == 0 || tape1->count == 0) - { - chosen_tape = tape0; - n0--; - } - else if (ShinyZone_compare(tape1->first, tape0->first) > 0) - { - chosen_tape = tape1; - n1--; - } - else - { - chosen_tape = tape0; - n0--; - } - chosen_tape->count--; - chosen_record = chosen_tape->first; - chosen_tape->first = chosen_record->next; - if (output_tape->count == 0) - output_tape->first = chosen_record; - else - output_tape->last->next = chosen_record; - output_tape->last = chosen_record; - output_tape->count++; - } - } - } - - if (tape[base].count > 1L) { - ShinyZone* last = tape[base].last; - *first = tape[base].first; - last->next = NULL; - return last; - - } else { - return NULL; - } + ShinyZone *p = *first; + + unsigned base; + unsigned long block_size; + + struct tape + { + ShinyZone *first, *last; + unsigned long count; + } tape[4]; + + /* Distribute the records alternately to tape[0] and tape[1]. */ + + tape[0].count = tape[1].count = 0L; + tape[0].first = NULL; + base = 0; + while (p != NULL) + { + ShinyZone *next = p->next; + p->next = tape[base].first; + tape[base].first = p; + tape[base].count++; + p = next; + base ^= 1; + } + + /* If the list is empty or contains only a single record, then */ + /* tape[1].count == 0L and this part is vacuous. */ + + for (base = 0, block_size = 1L; tape[base+1].count != 0L; + base ^= 2, block_size <<= 1) + { + int dest; + struct tape *tape0, *tape1; + tape0 = tape + base; + tape1 = tape + base + 1; + dest = base ^ 2; + tape[dest].count = tape[dest+1].count = 0; + for (; tape0->count != 0; dest ^= 1) + { + unsigned long n0, n1; + struct tape *output_tape = tape + dest; + n0 = n1 = block_size; + while (1) + { + ShinyZone *chosen_record; + struct tape *chosen_tape; + if (n0 == 0 || tape0->count == 0) + { + if (n1 == 0 || tape1->count == 0) + break; + chosen_tape = tape1; + n1--; + } + else if (n1 == 0 || tape1->count == 0) + { + chosen_tape = tape0; + n0--; + } + else if (ShinyZone_compare(tape1->first, tape0->first) > 0) + { + chosen_tape = tape1; + n1--; + } + else + { + chosen_tape = tape0; + n0--; + } + chosen_tape->count--; + chosen_record = chosen_tape->first; + chosen_tape->first = chosen_record->next; + if (output_tape->count == 0) + output_tape->first = chosen_record; + else + output_tape->last->next = chosen_record; + output_tape->last = chosen_record; + output_tape->count++; + } + } + } + + if (tape[base].count > 1L) { + ShinyZone* last = tape[base].last; + *first = tape[base].first; + last->next = NULL; + return last; + + } else { + return NULL; + } } /*---------------------------------------------------------------------------*/ void ShinyZone_clear(ShinyZone* self) { - memset(self, 0, sizeof(ShinyZone)); + memset(self, 0, sizeof(ShinyZone)); } /*---------------------------------------------------------------------------*/ void ShinyZone_enumerateZones(const ShinyZone* a_zone, void (*a_func)(const ShinyZone*)) { - a_func(a_zone); + a_func(a_zone); - if (a_zone->next) ShinyZone_enumerateZones(a_zone->next, a_func); + if (a_zone->next) ShinyZone_enumerateZones(a_zone->next, a_func); } #endif /* SLIC3R_PROFILE */ diff --git a/src/Shiny/ShinyZone.h b/src/Shiny/ShinyZone.h index dde0d3624a0..1ae04e57d05 100644 --- a/src/Shiny/ShinyZone.h +++ b/src/Shiny/ShinyZone.h @@ -34,31 +34,31 @@ extern "C" { /*---------------------------------------------------------------------------*/ -#define SHINY_ZONE_STATE_HIDDEN 0 -#define SHINY_ZONE_STATE_INITIALIZED 1 -#define SHINY_ZONE_STATE_UPDATING 2 +#define SHINY_ZONE_STATE_HIDDEN 0 +#define SHINY_ZONE_STATE_INITIALIZED 1 +#define SHINY_ZONE_STATE_UPDATING 2 /*---------------------------------------------------------------------------*/ typedef struct _ShinyZone { - struct _ShinyZone* next; - int _state; - const char* name; - ShinyData data; + struct _ShinyZone* next; + int _state; + const char* name; + ShinyData data; } ShinyZone; /*---------------------------------------------------------------------------*/ SHINY_INLINE void ShinyZone_init(ShinyZone *self, ShinyZone* a_prev) { - self->_state = SHINY_ZONE_STATE_INITIALIZED; - a_prev->next = self; + self->_state = SHINY_ZONE_STATE_INITIALIZED; + a_prev->next = self; } SHINY_INLINE void ShinyZone_uninit(ShinyZone *self) { - self->_state = SHINY_ZONE_STATE_HIDDEN; - self->next = NULL; + self->_state = SHINY_ZONE_STATE_HIDDEN; + self->next = NULL; } SHINY_API void ShinyZone_preUpdateChain(ShinyZone *first); @@ -70,7 +70,7 @@ SHINY_API void ShinyZone_resetChain(ShinyZone *first); SHINY_API ShinyZone* ShinyZone_sortChain(ShinyZone **first); SHINY_INLINE float ShinyZone_compare(ShinyZone *a, ShinyZone *b) { - return a->data.selfTicks.avg - b->data.selfTicks.avg; + return a->data.selfTicks.avg - b->data.selfTicks.avg; } SHINY_API void ShinyZone_clear(ShinyZone* self); @@ -82,9 +82,9 @@ SHINY_API void ShinyZone_enumerateZones(const ShinyZone* a_zone, void (*a_func)( template void ShinyZone_enumerateZones(const ShinyZone* a_zone, T* a_this, void (T::*a_func)(const ShinyZone*)) { - (a_this->*a_func)(a_zone); + (a_this->*a_func)(a_zone); - if (a_zone->next) ShinyZone_enumerateZones(a_zone->next, a_this, a_func); + if (a_zone->next) ShinyZone_enumerateZones(a_zone->next, a_this, a_func); } #endif /* __cplusplus */ diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index 82b5460977c..68e6c0dc32e 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -37,393 +37,393 @@ #include "stl.h" struct HashEdge { - // Key of a hash edge: sorted vertices of the edge. - uint32_t key[6]; - // Compare two keys. - bool operator==(const HashEdge &rhs) const { return memcmp(key, rhs.key, sizeof(key)) == 0; } - bool operator!=(const HashEdge &rhs) const { return ! (*this == rhs); } - int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; } - - // Index of a facet owning this edge. - int facet_number; - // Index of this edge inside the facet with an index of facet_number. - // If this edge is stored backwards, which_edge is increased by 3. - int which_edge; - HashEdge *next; - - void load_exact(stl_file *stl, const stl_vertex *a, const stl_vertex *b) - { - { - stl_vertex diff = (*a - *b).cwiseAbs(); - float max_diff = std::max(diff(0), std::max(diff(1), diff(2))); - stl->stats.shortest_edge = std::min(max_diff, stl->stats.shortest_edge); - } - - // Ensure identical vertex ordering of equal edges. - // This method is numerically robust. - if (vertex_lower(*a, *b)) { - } else { - // This edge is loaded backwards. - std::swap(a, b); - this->which_edge += 3; - } - memcpy(&this->key[0], a->data(), sizeof(stl_vertex)); - memcpy(&this->key[3], b->data(), sizeof(stl_vertex)); - // Switch negative zeros to positive zeros, so memcmp will consider them to be equal. - for (size_t i = 0; i < 6; ++ i) { - unsigned char *p = (unsigned char*)(this->key + i); - #if BOOST_ENDIAN_LITTLE_BYTE - if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80) - // Negative zero, switch to positive zero. - p[3] = 0; - #else /* BOOST_ENDIAN_LITTLE_BYTE */ - if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0) - // Negative zero, switch to positive zero. - p[0] = 0; - #endif /* BOOST_ENDIAN_LITTLE_BYTE */ - } - } - - bool load_nearby(const stl_file *stl, const stl_vertex &a, const stl_vertex &b, float tolerance) - { - // Index of a grid cell spaced by tolerance. - typedef Eigen::Matrix Vec3i; - Vec3i vertex1 = ((a - stl->stats.min) / tolerance).cast(); - Vec3i vertex2 = ((b - stl->stats.min) / tolerance).cast(); - static_assert(sizeof(Vec3i) == 12, "size of Vec3i incorrect"); - - if (vertex1 == vertex2) - // Both vertices hash to the same value - return false; - - // Ensure identical vertex ordering of edges, which vertices land into equal grid cells. - // This method is numerically robust. - if ((vertex1[0] != vertex2[0]) ? - (vertex1[0] < vertex2[0]) : - ((vertex1[1] != vertex2[1]) ? - (vertex1[1] < vertex2[1]) : - (vertex1[2] < vertex2[2]))) { - memcpy(&this->key[0], vertex1.data(), sizeof(stl_vertex)); - memcpy(&this->key[3], vertex2.data(), sizeof(stl_vertex)); - } else { - memcpy(&this->key[0], vertex2.data(), sizeof(stl_vertex)); - memcpy(&this->key[3], vertex1.data(), sizeof(stl_vertex)); - this->which_edge += 3; /* this edge is loaded backwards */ - } - return true; - } + // Key of a hash edge: sorted vertices of the edge. + uint32_t key[6]; + // Compare two keys. + bool operator==(const HashEdge &rhs) const { return memcmp(key, rhs.key, sizeof(key)) == 0; } + bool operator!=(const HashEdge &rhs) const { return ! (*this == rhs); } + int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; } + + // Index of a facet owning this edge. + int facet_number; + // Index of this edge inside the facet with an index of facet_number. + // If this edge is stored backwards, which_edge is increased by 3. + int which_edge; + HashEdge *next; + + void load_exact(stl_file *stl, const stl_vertex *a, const stl_vertex *b) + { + { + stl_vertex diff = (*a - *b).cwiseAbs(); + float max_diff = std::max(diff(0), std::max(diff(1), diff(2))); + stl->stats.shortest_edge = std::min(max_diff, stl->stats.shortest_edge); + } + + // Ensure identical vertex ordering of equal edges. + // This method is numerically robust. + if (vertex_lower(*a, *b)) { + } else { + // This edge is loaded backwards. + std::swap(a, b); + this->which_edge += 3; + } + memcpy(&this->key[0], a->data(), sizeof(stl_vertex)); + memcpy(&this->key[3], b->data(), sizeof(stl_vertex)); + // Switch negative zeros to positive zeros, so memcmp will consider them to be equal. + for (size_t i = 0; i < 6; ++ i) { + unsigned char *p = (unsigned char*)(this->key + i); + #if BOOST_ENDIAN_LITTLE_BYTE + if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80) + // Negative zero, switch to positive zero. + p[3] = 0; + #else /* BOOST_ENDIAN_LITTLE_BYTE */ + if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0) + // Negative zero, switch to positive zero. + p[0] = 0; + #endif /* BOOST_ENDIAN_LITTLE_BYTE */ + } + } + + bool load_nearby(const stl_file *stl, const stl_vertex &a, const stl_vertex &b, float tolerance) + { + // Index of a grid cell spaced by tolerance. + typedef Eigen::Matrix Vec3i; + Vec3i vertex1 = ((a - stl->stats.min) / tolerance).cast(); + Vec3i vertex2 = ((b - stl->stats.min) / tolerance).cast(); + static_assert(sizeof(Vec3i) == 12, "size of Vec3i incorrect"); + + if (vertex1 == vertex2) + // Both vertices hash to the same value + return false; + + // Ensure identical vertex ordering of edges, which vertices land into equal grid cells. + // This method is numerically robust. + if ((vertex1[0] != vertex2[0]) ? + (vertex1[0] < vertex2[0]) : + ((vertex1[1] != vertex2[1]) ? + (vertex1[1] < vertex2[1]) : + (vertex1[2] < vertex2[2]))) { + memcpy(&this->key[0], vertex1.data(), sizeof(stl_vertex)); + memcpy(&this->key[3], vertex2.data(), sizeof(stl_vertex)); + } else { + memcpy(&this->key[0], vertex2.data(), sizeof(stl_vertex)); + memcpy(&this->key[3], vertex1.data(), sizeof(stl_vertex)); + this->which_edge += 3; /* this edge is loaded backwards */ + } + return true; + } private: - inline bool vertex_lower(const stl_vertex &a, const stl_vertex &b) { - return (a(0) != b(0)) ? (a(0) < b(0)) : - ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2))); - } + inline bool vertex_lower(const stl_vertex &a, const stl_vertex &b) { + return (a(0) != b(0)) ? (a(0) < b(0)) : + ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2))); + } }; struct HashTableEdges { - HashTableEdges(size_t number_of_faces) { - this->M = (int)hash_size_from_nr_faces(number_of_faces); - this->heads.assign(this->M, nullptr); - this->tail = pool.construct(); - this->tail->next = this->tail; - for (int i = 0; i < this->M; ++ i) - this->heads[i] = this->tail; - } - ~HashTableEdges() { + HashTableEdges(size_t number_of_faces) { + this->M = (int)hash_size_from_nr_faces(number_of_faces); + this->heads.assign(this->M, nullptr); + this->tail = pool.construct(); + this->tail->next = this->tail; + for (int i = 0; i < this->M; ++ i) + this->heads[i] = this->tail; + } + ~HashTableEdges() { #ifndef NDEBUG - for (int i = 0; i < this->M; ++ i) - for (HashEdge *temp = this->heads[i]; temp != this->tail; temp = temp->next) - ++ this->freed; - this->tail = nullptr; + for (int i = 0; i < this->M; ++ i) + for (HashEdge *temp = this->heads[i]; temp != this->tail; temp = temp->next) + ++ this->freed; + this->tail = nullptr; #endif /* NDEBUG */ - } + } - void insert_edge_exact(stl_file *stl, const HashEdge &edge) - { - this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { record_neighbors(stl, edge1, edge2); }); - } + void insert_edge_exact(stl_file *stl, const HashEdge &edge) + { + this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { record_neighbors(stl, edge1, edge2); }); + } - void insert_edge_nearby(stl_file *stl, const HashEdge &edge) - { - this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { match_neighbors_nearby(stl, edge1, edge2); }); - } + void insert_edge_nearby(stl_file *stl, const HashEdge &edge) + { + this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { match_neighbors_nearby(stl, edge1, edge2); }); + } - // Hash table on edges - std::vector heads; - HashEdge* tail; - int M; - boost::object_pool pool; + // Hash table on edges + std::vector heads; + HashEdge* tail; + int M; + boost::object_pool pool; #ifndef NDEBUG - size_t malloced = 0; - size_t freed = 0; - size_t collisions = 0; + size_t malloced = 0; + size_t freed = 0; + size_t collisions = 0; #endif /* NDEBUG */ private: - static inline size_t hash_size_from_nr_faces(const size_t nr_faces) - { - // Good primes for addressing a cca. 30 bit space. - // https://planetmath.org/goodhashtableprimes - static std::vector primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; - // Find a prime number for 50% filling of the shared triangle edges in the mesh. - auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1); - return (it == primes.end()) ? primes.back() : *it; - } - - - // MatchNeighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) - template - void insert_edge(stl_file *stl, const HashEdge &edge, MatchNeighbors match_neighbors) - { - int chain_number = edge.hash(this->M); - HashEdge *link = this->heads[chain_number]; - if (link == this->tail) { - // This list doesn't have any edges currently in it. Add this one. - HashEdge *new_edge = pool.construct(edge); + static inline size_t hash_size_from_nr_faces(const size_t nr_faces) + { + // Good primes for addressing a cca. 30 bit space. + // https://planetmath.org/goodhashtableprimes + static std::vector primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; + // Find a prime number for 50% filling of the shared triangle edges in the mesh. + auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1); + return (it == primes.end()) ? primes.back() : *it; + } + + + // MatchNeighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) + template + void insert_edge(stl_file *stl, const HashEdge &edge, MatchNeighbors match_neighbors) + { + int chain_number = edge.hash(this->M); + HashEdge *link = this->heads[chain_number]; + if (link == this->tail) { + // This list doesn't have any edges currently in it. Add this one. + HashEdge *new_edge = pool.construct(edge); #ifndef NDEBUG - ++ this->malloced; + ++ this->malloced; #endif /* NDEBUG */ - new_edge->next = this->tail; - this->heads[chain_number] = new_edge; - } else if (edges_equal(edge, *link)) { - // This is a match. Record result in neighbors list. - match_neighbors(edge, *link); - // Delete the matched edge from the list. - this->heads[chain_number] = link->next; - // pool.destroy(link); + new_edge->next = this->tail; + this->heads[chain_number] = new_edge; + } else if (edges_equal(edge, *link)) { + // This is a match. Record result in neighbors list. + match_neighbors(edge, *link); + // Delete the matched edge from the list. + this->heads[chain_number] = link->next; + // pool.destroy(link); #ifndef NDEBUG - ++ this->freed; + ++ this->freed; #endif /* NDEBUG */ - } else { - // Continue through the rest of the list. - for (;;) { - if (link->next == this->tail) { - // This is the last item in the list. Insert a new edge. - HashEdge *new_edge = pool.construct(); + } else { + // Continue through the rest of the list. + for (;;) { + if (link->next == this->tail) { + // This is the last item in the list. Insert a new edge. + HashEdge *new_edge = pool.construct(); #ifndef NDEBUG - ++ this->malloced; + ++ this->malloced; #endif /* NDEBUG */ - *new_edge = edge; - new_edge->next = this->tail; - link->next = new_edge; + *new_edge = edge; + new_edge->next = this->tail; + link->next = new_edge; #ifndef NDEBUG - ++ this->collisions; + ++ this->collisions; #endif /* NDEBUG */ - break; - } - if (edges_equal(edge, *link->next)) { - // This is a match. Record result in neighbors list. - match_neighbors(edge, *link->next); - // Delete the matched edge from the list. - link->next; - link->next = link->next->next; - // pool.destroy(temp); + break; + } + if (edges_equal(edge, *link->next)) { + // This is a match. Record result in neighbors list. + match_neighbors(edge, *link->next); + // Delete the matched edge from the list. + link->next; + link->next = link->next->next; + // pool.destroy(temp); #ifndef NDEBUG - ++ this->freed; + ++ this->freed; #endif /* NDEBUG */ - break; - } - // This is not a match. Go to the next link. - link = link->next; + break; + } + // This is not a match. Go to the next link. + link = link->next; #ifndef NDEBUG - ++ this->collisions; + ++ this->collisions; #endif /* NDEBUG */ - } - } - } - - // Edges equal for hashing. Edgesof different facet are allowed to be matched. - static inline bool edges_equal(const HashEdge &edge_a, const HashEdge &edge_b) - { - return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b; - } - - // Connect edge_a with edge_b, update edge connection statistics. - static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) - { - // Facet a's neighbor is facet b - stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number; /* sets the .neighbor part */ - stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */ - - // Facet b's neighbor is facet a - stl->neighbors_start[edge_b.facet_number].neighbor[edge_b.which_edge % 3] = edge_a.facet_number; /* sets the .neighbor part */ - stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] = (edge_a.which_edge + 2) % 3; /* sets the .which_vertex_not part */ - - if ((edge_a.which_edge < 3 && edge_b.which_edge < 3) || (edge_a.which_edge > 2 && edge_b.which_edge > 2)) { - // These facets are oriented in opposite directions, their normals are probably messed up. - stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] += 3; - stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] += 3; - } - - // Count successful connects: - // Total connects: - stl->stats.connected_edges += 2; - // Count individual connects: - switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) { - case 1: ++ stl->stats.connected_facets_1_edge; break; - case 2: ++ stl->stats.connected_facets_2_edge; break; - case 3: ++ stl->stats.connected_facets_3_edge; break; - default: assert(false); - } - switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) { - case 1: ++ stl->stats.connected_facets_1_edge; break; - case 2: ++ stl->stats.connected_facets_2_edge; break; - case 3: ++ stl->stats.connected_facets_3_edge; break; - default: assert(false); - } - } - - static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) - { - record_neighbors(stl, edge_a, edge_b); - - // Which vertices to change - int facet1 = -1; - int facet2 = -1; - int vertex1, vertex2; - stl_vertex new_vertex1, new_vertex2; - { - int v1a; // pair 1, facet a - int v1b; // pair 1, facet b - int v2a; // pair 2, facet a - int v2b; // pair 2, facet b - // Find first pair. - if (edge_a.which_edge < 3) { - v1a = edge_a.which_edge; - v2a = (edge_a.which_edge + 1) % 3; - } else { - v2a = edge_a.which_edge % 3; - v1a = (edge_a.which_edge + 1) % 3; - } - if (edge_b.which_edge < 3) { - v1b = edge_b.which_edge; - v2b = (edge_b.which_edge + 1) % 3; - } else { - v2b = edge_b.which_edge % 3; - v1b = (edge_b.which_edge + 1) % 3; - } - - // Of the first pair, which vertex, if any, should be changed - if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) { - // These facets are different. - if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1) - && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) { - // This vertex has no neighbors. This is a good one to change. - facet1 = edge_a.facet_number; - vertex1 = v1a; - new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b]; - } else { - facet1 = edge_b.facet_number; - vertex1 = v1b; - new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a]; - } - } - - // Of the second pair, which vertex, if any, should be changed. - if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) { - // These facets are different. - if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1) - && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) { - // This vertex has no neighbors. This is a good one to change. - facet2 = edge_a.facet_number; - vertex2 = v2a; - new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b]; - } else { - facet2 = edge_b.facet_number; - vertex2 = v2b; - new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a]; - } - } - } - - auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex) - { - int first_facet = facet_num; - bool direction = false; - - for (;;) { - int pivot_vertex; - int next_edge; - if (vnot > 2) { - if (direction) { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot % 3; - } - else { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - direction = !direction; - } - else { - if (direction) { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - else { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot; - } - } - #if 0 - if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) && - stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) && - stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2)) - printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2)); - else { - if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](0), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](0)), - new_vertex(0), - *reinterpret_cast(&new_vertex(0))); - if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](1), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](1)), - new_vertex(1), - *reinterpret_cast(&new_vertex(1))); - if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](2), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](2)), - new_vertex(2), - *reinterpret_cast(&new_vertex(2))); - } - #endif - stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex; - vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; - facet_num = stl->neighbors_start[facet_num].neighbor[next_edge]; - if (facet_num == -1) - break; - - if (facet_num == first_facet) { - // back to the beginning - BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check."; - return; - } - } - }; - - if (facet1 != -1) { - int vnot1 = (facet1 == edge_a.facet_number) ? - (edge_a.which_edge + 2) % 3 : - (edge_b.which_edge + 2) % 3; - if (((vnot1 + 2) % 3) == vertex1) - vnot1 += 3; - change_vertices(facet1, vnot1, new_vertex1); - } - if (facet2 != -1) { - int vnot2 = (facet2 == edge_a.facet_number) ? - (edge_a.which_edge + 2) % 3 : - (edge_b.which_edge + 2) % 3; - if (((vnot2 + 2) % 3) == vertex2) - vnot2 += 3; - change_vertices(facet2, vnot2, new_vertex2); - } - stl->stats.edges_fixed += 2; - } + } + } + } + + // Edges equal for hashing. Edgesof different facet are allowed to be matched. + static inline bool edges_equal(const HashEdge &edge_a, const HashEdge &edge_b) + { + return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b; + } + + // Connect edge_a with edge_b, update edge connection statistics. + static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) + { + // Facet a's neighbor is facet b + stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number; /* sets the .neighbor part */ + stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */ + + // Facet b's neighbor is facet a + stl->neighbors_start[edge_b.facet_number].neighbor[edge_b.which_edge % 3] = edge_a.facet_number; /* sets the .neighbor part */ + stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] = (edge_a.which_edge + 2) % 3; /* sets the .which_vertex_not part */ + + if ((edge_a.which_edge < 3 && edge_b.which_edge < 3) || (edge_a.which_edge > 2 && edge_b.which_edge > 2)) { + // These facets are oriented in opposite directions, their normals are probably messed up. + stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] += 3; + stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] += 3; + } + + // Count successful connects: + // Total connects: + stl->stats.connected_edges += 2; + // Count individual connects: + switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) { + case 1: ++ stl->stats.connected_facets_1_edge; break; + case 2: ++ stl->stats.connected_facets_2_edge; break; + case 3: ++ stl->stats.connected_facets_3_edge; break; + default: assert(false); + } + switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) { + case 1: ++ stl->stats.connected_facets_1_edge; break; + case 2: ++ stl->stats.connected_facets_2_edge; break; + case 3: ++ stl->stats.connected_facets_3_edge; break; + default: assert(false); + } + } + + static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) + { + record_neighbors(stl, edge_a, edge_b); + + // Which vertices to change + int facet1 = -1; + int facet2 = -1; + int vertex1, vertex2; + stl_vertex new_vertex1, new_vertex2; + { + int v1a; // pair 1, facet a + int v1b; // pair 1, facet b + int v2a; // pair 2, facet a + int v2b; // pair 2, facet b + // Find first pair. + if (edge_a.which_edge < 3) { + v1a = edge_a.which_edge; + v2a = (edge_a.which_edge + 1) % 3; + } else { + v2a = edge_a.which_edge % 3; + v1a = (edge_a.which_edge + 1) % 3; + } + if (edge_b.which_edge < 3) { + v1b = edge_b.which_edge; + v2b = (edge_b.which_edge + 1) % 3; + } else { + v2b = edge_b.which_edge % 3; + v1b = (edge_b.which_edge + 1) % 3; + } + + // Of the first pair, which vertex, if any, should be changed + if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) { + // These facets are different. + if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1) + && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) { + // This vertex has no neighbors. This is a good one to change. + facet1 = edge_a.facet_number; + vertex1 = v1a; + new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b]; + } else { + facet1 = edge_b.facet_number; + vertex1 = v1b; + new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a]; + } + } + + // Of the second pair, which vertex, if any, should be changed. + if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) { + // These facets are different. + if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1) + && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) { + // This vertex has no neighbors. This is a good one to change. + facet2 = edge_a.facet_number; + vertex2 = v2a; + new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b]; + } else { + facet2 = edge_b.facet_number; + vertex2 = v2b; + new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a]; + } + } + } + + auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex) + { + int first_facet = facet_num; + bool direction = false; + + for (;;) { + int pivot_vertex; + int next_edge; + if (vnot > 2) { + if (direction) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot % 3; + } + else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + direction = !direction; + } + else { + if (direction) { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + else { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot; + } + } + #if 0 + if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) && + stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) && + stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2)) + printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2)); + else { + if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](0), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](0)), + new_vertex(0), + *reinterpret_cast(&new_vertex(0))); + if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](1), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](1)), + new_vertex(1), + *reinterpret_cast(&new_vertex(1))); + if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](2), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](2)), + new_vertex(2), + *reinterpret_cast(&new_vertex(2))); + } + #endif + stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex; + vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; + facet_num = stl->neighbors_start[facet_num].neighbor[next_edge]; + if (facet_num == -1) + break; + + if (facet_num == first_facet) { + // back to the beginning + BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check."; + return; + } + } + }; + + if (facet1 != -1) { + int vnot1 = (facet1 == edge_a.facet_number) ? + (edge_a.which_edge + 2) % 3 : + (edge_b.which_edge + 2) % 3; + if (((vnot1 + 2) % 3) == vertex1) + vnot1 += 3; + change_vertices(facet1, vnot1, new_vertex1); + } + if (facet2 != -1) { + int vnot2 = (facet2 == edge_a.facet_number) ? + (edge_a.which_edge + 2) % 3 : + (edge_b.which_edge + 2) % 3; + if (((vnot2 + 2) % 3) == vertex2) + vnot2 += 3; + change_vertices(facet2, vnot2, new_vertex2); + } + stl->stats.edges_fixed += 2; + } }; // This function builds the neighbors list. No modifications are made @@ -431,313 +431,313 @@ struct HashTableEdges { // floats of the first edge matches all six floats of the second edge. void stl_check_facets_exact(stl_file *stl) { - assert(stl->facet_start.size() == stl->neighbors_start.size()); - - stl->stats.connected_edges = 0; - stl->stats.connected_facets_1_edge = 0; - stl->stats.connected_facets_2_edge = 0; - stl->stats.connected_facets_3_edge = 0; - - // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. - // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet - // will break the references. - for (uint32_t i = 0; i < stl->stats.number_of_facets;) { - stl_facet &facet = stl->facet_start[i]; - if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { - // Remove the degenerate facet. - facet = stl->facet_start[-- stl->stats.number_of_facets]; - stl->facet_start.pop_back(); - stl->neighbors_start.pop_back(); - stl->stats.facets_removed += 1; - stl->stats.degenerate_facets += 1; - } else - ++ i; - } - - // Initialize hash table. - HashTableEdges hash_table(stl->stats.number_of_facets); - for (auto &neighbor : stl->neighbors_start) - neighbor.reset(); - - // Connect neighbor edges. - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - const stl_facet &facet = stl->facet_start[i]; - for (int j = 0; j < 3; ++ j) { - HashEdge edge; - edge.facet_number = i; - edge.which_edge = j; - edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); - hash_table.insert_edge_exact(stl, edge); - } - } + assert(stl->facet_start.size() == stl->neighbors_start.size()); + + stl->stats.connected_edges = 0; + stl->stats.connected_facets_1_edge = 0; + stl->stats.connected_facets_2_edge = 0; + stl->stats.connected_facets_3_edge = 0; + + // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. + // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet + // will break the references. + for (uint32_t i = 0; i < stl->stats.number_of_facets;) { + stl_facet &facet = stl->facet_start[i]; + if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { + // Remove the degenerate facet. + facet = stl->facet_start[-- stl->stats.number_of_facets]; + stl->facet_start.pop_back(); + stl->neighbors_start.pop_back(); + stl->stats.facets_removed += 1; + stl->stats.degenerate_facets += 1; + } else + ++ i; + } + + // Initialize hash table. + HashTableEdges hash_table(stl->stats.number_of_facets); + for (auto &neighbor : stl->neighbors_start) + neighbor.reset(); + + // Connect neighbor edges. + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + const stl_facet &facet = stl->facet_start[i]; + for (int j = 0; j < 3; ++ j) { + HashEdge edge; + edge.facet_number = i; + edge.which_edge = j; + edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); + hash_table.insert_edge_exact(stl, edge); + } + } #if 0 - printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n", - stl->stats.number_of_facets, stl->stats.number_of_facets * 3, - stl->stats.connected_edges, stl->stats.number_of_facets * 3 - stl->stats.connected_edges); + printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n", + stl->stats.number_of_facets, stl->stats.number_of_facets * 3, + stl->stats.connected_edges, stl->stats.number_of_facets * 3 - stl->stats.connected_edges); #endif } void stl_check_facets_nearby(stl_file *stl, float tolerance) { - assert(stl->stats.connected_facets_3_edge <= stl->stats.connected_facets_2_edge); - assert(stl->stats.connected_facets_2_edge <= stl->stats.connected_facets_1_edge); - assert(stl->stats.connected_facets_1_edge <= stl->stats.number_of_facets); - - if (stl->stats.connected_facets_3_edge == static_cast(stl->stats.number_of_facets)) - // No need to check any further. All facets are connected. - return; - - HashTableEdges hash_table(stl->stats.number_of_facets); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - //FIXME is the copy necessary? - stl_facet facet = stl->facet_start[i]; - for (int j = 0; j < 3; j++) { - if (stl->neighbors_start[i].neighbor[j] == -1) { - HashEdge edge; - edge.facet_number = i; - edge.which_edge = j; - if (edge.load_nearby(stl, facet.vertex[j], facet.vertex[(j + 1) % 3], tolerance)) - // Only insert edges that have different keys. - hash_table.insert_edge_nearby(stl, edge); - } - } - } + assert(stl->stats.connected_facets_3_edge <= stl->stats.connected_facets_2_edge); + assert(stl->stats.connected_facets_2_edge <= stl->stats.connected_facets_1_edge); + assert(stl->stats.connected_facets_1_edge <= stl->stats.number_of_facets); + + if (stl->stats.connected_facets_3_edge == static_cast(stl->stats.number_of_facets)) + // No need to check any further. All facets are connected. + return; + + HashTableEdges hash_table(stl->stats.number_of_facets); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + //FIXME is the copy necessary? + stl_facet facet = stl->facet_start[i]; + for (int j = 0; j < 3; j++) { + if (stl->neighbors_start[i].neighbor[j] == -1) { + HashEdge edge; + edge.facet_number = i; + edge.which_edge = j; + if (edge.load_nearby(stl, facet.vertex[j], facet.vertex[(j + 1) % 3], tolerance)) + // Only insert edges that have different keys. + hash_table.insert_edge_nearby(stl, edge); + } + } + } } void stl_remove_unconnected_facets(stl_file *stl) { - // A couple of things need to be done here. One is to remove any completely unconnected facets (0 edges connected) since these are - // useless and could be completely wrong. The second thing that needs to be done is to remove any degenerate facets that were created during - // stl_check_facets_nearby(). - auto remove_facet = [stl](int facet_number) - { - ++ stl->stats.facets_removed; - /* Update list of connected edges */ - stl_neighbors &neighbors = stl->neighbors_start[facet_number]; - // Update statistics on unconnected triangle edges. - switch (neighbors.num_neighbors()) { - case 3: -- stl->stats.connected_facets_3_edge; // fall through - case 2: -- stl->stats.connected_facets_2_edge; // fall through - case 1: -- stl->stats.connected_facets_1_edge; // fall through - case 0: break; - default: assert(false); - } - - if (facet_number < int(-- stl->stats.number_of_facets)) { - // Removing a face, which was not the last one. - // Copy the face and neighborship from the last face to facet_number. - stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; - neighbors = stl->neighbors_start[stl->stats.number_of_facets]; - // Update neighborship of faces, which used to point to the last face, now moved to facet_number. - for (int i = 0; i < 3; ++ i) - if (neighbors.neighbor[i] != -1) { - int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; - if (other_face_idx != static_cast(stl->stats.number_of_facets)) { - BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong"; - return; - } - other_face_idx = facet_number; - } - } - - stl->facet_start.pop_back(); - stl->neighbors_start.pop_back(); - }; - - auto remove_degenerate = [stl, remove_facet](int facet) - { - // Update statistics on face connectivity after one edge was disconnected on the facet "facet_num". - auto update_connects_remove_1 = [stl](int facet_num) { - switch (stl->neighbors_start[facet_num].num_neighbors()) { - case 0: assert(false); break; - case 1: -- stl->stats.connected_facets_1_edge; break; - case 2: -- stl->stats.connected_facets_2_edge; break; - case 3: -- stl->stats.connected_facets_3_edge; break; - default: assert(false); - } - }; - - int edge_to_collapse = 0; - if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) { - if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { - // All 3 vertices are equal. Collapse the edge with no neighbor if it exists. - const int *nbr = stl->neighbors_start[facet].neighbor; - edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2; - } else { - edge_to_collapse = 0; - } - } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { - edge_to_collapse = 1; - } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) { - edge_to_collapse = 2; - } else { - // No degenerate. Function shouldn't have been called. - return; - } - - int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse }; - int neighbor[] = { - stl->neighbors_start[facet].neighbor[edge[0]], - stl->neighbors_start[facet].neighbor[edge[1]], - stl->neighbors_start[facet].neighbor[edge[2]] - }; - int vnot[] = { - stl->neighbors_start[facet].which_vertex_not[edge[0]], - stl->neighbors_start[facet].which_vertex_not[edge[1]], - stl->neighbors_start[facet].which_vertex_not[edge[2]] - }; - - // Update statistics on edge connectivity. - if ((neighbor[0] == -1) && (neighbor[1] != -1)) - update_connects_remove_1(neighbor[1]); - if ((neighbor[1] == -1) && (neighbor[0] != -1)) - update_connects_remove_1(neighbor[0]); - - if (neighbor[0] >= 0) { - if (neighbor[1] >= 0) { - // Adjust the "flip" flag for the which_vertex_not values. - if (vnot[0] > 2) { - if (vnot[1] > 2) { - // The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face - // the two remaining neighbors will be oriented correctly. - vnot[0] -= 3; - vnot[1] -= 3; - } else - // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. - // After removal, the two neighbors will have their normals flipped. - vnot[1] += 3; - } else if (vnot[1] > 2) - // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. - // After removal, the two neighbors will have their normals flipped. - vnot[0] += 3; - } - stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1]; - stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1]; - } - if (neighbor[1] >= 0) { - stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0]; - stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0]; - } - if (neighbor[2] >= 0) { - update_connects_remove_1(neighbor[2]); - stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1; - } - - remove_facet(facet); - }; - - // remove degenerate facets - for (uint32_t i = 0; i < stl->stats.number_of_facets;) - if (stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] || - stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] || - stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) { - remove_degenerate(i); -// assert(stl_validate(stl)); - } else - ++ i; - - if (stl->stats.connected_facets_1_edge < (int)stl->stats.number_of_facets) { - // There are some faces with no connected edge at all. Remove completely unconnected facets. - for (uint32_t i = 0; i < stl->stats.number_of_facets;) - if (stl->neighbors_start[i].num_neighbors() == 0) { - // This facet is completely unconnected. Remove it. - remove_facet(i); - assert(stl_validate(stl)); - } else - ++ i; - } + // A couple of things need to be done here. One is to remove any completely unconnected facets (0 edges connected) since these are + // useless and could be completely wrong. The second thing that needs to be done is to remove any degenerate facets that were created during + // stl_check_facets_nearby(). + auto remove_facet = [stl](int facet_number) + { + ++ stl->stats.facets_removed; + /* Update list of connected edges */ + stl_neighbors &neighbors = stl->neighbors_start[facet_number]; + // Update statistics on unconnected triangle edges. + switch (neighbors.num_neighbors()) { + case 3: -- stl->stats.connected_facets_3_edge; // fall through + case 2: -- stl->stats.connected_facets_2_edge; // fall through + case 1: -- stl->stats.connected_facets_1_edge; // fall through + case 0: break; + default: assert(false); + } + + if (facet_number < int(-- stl->stats.number_of_facets)) { + // Removing a face, which was not the last one. + // Copy the face and neighborship from the last face to facet_number. + stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; + neighbors = stl->neighbors_start[stl->stats.number_of_facets]; + // Update neighborship of faces, which used to point to the last face, now moved to facet_number. + for (int i = 0; i < 3; ++ i) + if (neighbors.neighbor[i] != -1) { + int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; + if (other_face_idx != static_cast(stl->stats.number_of_facets)) { + BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong"; + return; + } + other_face_idx = facet_number; + } + } + + stl->facet_start.pop_back(); + stl->neighbors_start.pop_back(); + }; + + auto remove_degenerate = [stl, remove_facet](int facet) + { + // Update statistics on face connectivity after one edge was disconnected on the facet "facet_num". + auto update_connects_remove_1 = [stl](int facet_num) { + switch (stl->neighbors_start[facet_num].num_neighbors()) { + case 0: assert(false); break; + case 1: -- stl->stats.connected_facets_1_edge; break; + case 2: -- stl->stats.connected_facets_2_edge; break; + case 3: -- stl->stats.connected_facets_3_edge; break; + default: assert(false); + } + }; + + int edge_to_collapse = 0; + if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) { + if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { + // All 3 vertices are equal. Collapse the edge with no neighbor if it exists. + const int *nbr = stl->neighbors_start[facet].neighbor; + edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2; + } else { + edge_to_collapse = 0; + } + } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { + edge_to_collapse = 1; + } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) { + edge_to_collapse = 2; + } else { + // No degenerate. Function shouldn't have been called. + return; + } + + int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse }; + int neighbor[] = { + stl->neighbors_start[facet].neighbor[edge[0]], + stl->neighbors_start[facet].neighbor[edge[1]], + stl->neighbors_start[facet].neighbor[edge[2]] + }; + int vnot[] = { + stl->neighbors_start[facet].which_vertex_not[edge[0]], + stl->neighbors_start[facet].which_vertex_not[edge[1]], + stl->neighbors_start[facet].which_vertex_not[edge[2]] + }; + + // Update statistics on edge connectivity. + if ((neighbor[0] == -1) && (neighbor[1] != -1)) + update_connects_remove_1(neighbor[1]); + if ((neighbor[1] == -1) && (neighbor[0] != -1)) + update_connects_remove_1(neighbor[0]); + + if (neighbor[0] >= 0) { + if (neighbor[1] >= 0) { + // Adjust the "flip" flag for the which_vertex_not values. + if (vnot[0] > 2) { + if (vnot[1] > 2) { + // The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face + // the two remaining neighbors will be oriented correctly. + vnot[0] -= 3; + vnot[1] -= 3; + } else + // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. + // After removal, the two neighbors will have their normals flipped. + vnot[1] += 3; + } else if (vnot[1] > 2) + // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. + // After removal, the two neighbors will have their normals flipped. + vnot[0] += 3; + } + stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1]; + stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1]; + } + if (neighbor[1] >= 0) { + stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0]; + stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0]; + } + if (neighbor[2] >= 0) { + update_connects_remove_1(neighbor[2]); + stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1; + } + + remove_facet(facet); + }; + + // remove degenerate facets + for (uint32_t i = 0; i < stl->stats.number_of_facets;) + if (stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] || + stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] || + stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) { + remove_degenerate(i); +// assert(stl_validate(stl)); + } else + ++ i; + + if (stl->stats.connected_facets_1_edge < (int)stl->stats.number_of_facets) { + // There are some faces with no connected edge at all. Remove completely unconnected facets. + for (uint32_t i = 0; i < stl->stats.number_of_facets;) + if (stl->neighbors_start[i].num_neighbors() == 0) { + // This facet is completely unconnected. Remove it. + remove_facet(i); + assert(stl_validate(stl)); + } else + ++ i; + } } void stl_fill_holes(stl_file *stl) { - // Insert all unconnected edges into hash list. - HashTableEdges hash_table(stl->stats.number_of_facets); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - stl_facet facet = stl->facet_start[i]; - for (int j = 0; j < 3; ++ j) { - if(stl->neighbors_start[i].neighbor[j] != -1) - continue; - HashEdge edge; - edge.facet_number = i; - edge.which_edge = j; - edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); - hash_table.insert_edge_exact(stl, edge); - } - } - - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - stl_facet facet = stl->facet_start[i]; - int neighbors_initial[3] = { stl->neighbors_start[i].neighbor[0], stl->neighbors_start[i].neighbor[1], stl->neighbors_start[i].neighbor[2] }; - int first_facet = i; - for (int j = 0; j < 3; ++ j) { - if (stl->neighbors_start[i].neighbor[j] != -1) - continue; - - stl_facet new_facet; - new_facet.vertex[0] = facet.vertex[j]; - new_facet.vertex[1] = facet.vertex[(j + 1) % 3]; - bool direction = neighbors_initial[(j + 2) % 3] == -1; - int facet_num = i; - int vnot = (j + 2) % 3; - - for (;;) { - int pivot_vertex = 0; - int next_edge = 0; - if (vnot > 2) { - if (direction) { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot % 3; - } else { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - direction = ! direction; - } else { - if(direction == 0) { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot; - } else { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - } - - int next_facet = stl->neighbors_start[facet_num].neighbor[next_edge]; - if (next_facet == -1) { - new_facet.vertex[2] = stl->facet_start[facet_num].vertex[vnot % 3]; - stl_add_facet(stl, &new_facet); - for (int k = 0; k < 3; ++ k) { - HashEdge edge; - edge.facet_number = stl->stats.number_of_facets - 1; - edge.which_edge = k; - edge.load_exact(stl, &new_facet.vertex[k], &new_facet.vertex[(k + 1) % 3]); - hash_table.insert_edge_exact(stl, edge); - } - break; - } - - vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; - facet_num = next_facet; - - if (facet_num == first_facet) { - // back to the beginning - BOOST_LOG_TRIVIAL(info) << "Back to the first facet filling holes: probably a mobius part. Try using a smaller tolerance or don't do a nearby check."; - return; - } - } - } - } + // Insert all unconnected edges into hash list. + HashTableEdges hash_table(stl->stats.number_of_facets); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + stl_facet facet = stl->facet_start[i]; + for (int j = 0; j < 3; ++ j) { + if(stl->neighbors_start[i].neighbor[j] != -1) + continue; + HashEdge edge; + edge.facet_number = i; + edge.which_edge = j; + edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); + hash_table.insert_edge_exact(stl, edge); + } + } + + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + stl_facet facet = stl->facet_start[i]; + int neighbors_initial[3] = { stl->neighbors_start[i].neighbor[0], stl->neighbors_start[i].neighbor[1], stl->neighbors_start[i].neighbor[2] }; + int first_facet = i; + for (int j = 0; j < 3; ++ j) { + if (stl->neighbors_start[i].neighbor[j] != -1) + continue; + + stl_facet new_facet; + new_facet.vertex[0] = facet.vertex[j]; + new_facet.vertex[1] = facet.vertex[(j + 1) % 3]; + bool direction = neighbors_initial[(j + 2) % 3] == -1; + int facet_num = i; + int vnot = (j + 2) % 3; + + for (;;) { + int pivot_vertex = 0; + int next_edge = 0; + if (vnot > 2) { + if (direction) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot % 3; + } else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + direction = ! direction; + } else { + if(direction == 0) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot; + } else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + } + + int next_facet = stl->neighbors_start[facet_num].neighbor[next_edge]; + if (next_facet == -1) { + new_facet.vertex[2] = stl->facet_start[facet_num].vertex[vnot % 3]; + stl_add_facet(stl, &new_facet); + for (int k = 0; k < 3; ++ k) { + HashEdge edge; + edge.facet_number = stl->stats.number_of_facets - 1; + edge.which_edge = k; + edge.load_exact(stl, &new_facet.vertex[k], &new_facet.vertex[(k + 1) % 3]); + hash_table.insert_edge_exact(stl, edge); + } + break; + } + + vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; + facet_num = next_facet; + + if (facet_num == first_facet) { + // back to the beginning + BOOST_LOG_TRIVIAL(info) << "Back to the first facet filling holes: probably a mobius part. Try using a smaller tolerance or don't do a nearby check."; + return; + } + } + } + } } void stl_add_facet(stl_file *stl, const stl_facet *new_facet) { - assert(stl->facet_start.size() == stl->stats.number_of_facets); - assert(stl->neighbors_start.size() == stl->stats.number_of_facets); - stl->facet_start.emplace_back(*new_facet); - // note that the normal vector is not set here, just initialized to 0. - stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero(); - stl->neighbors_start.emplace_back(); - ++ stl->stats.facets_added; - ++ stl->stats.number_of_facets; + assert(stl->facet_start.size() == stl->stats.number_of_facets); + assert(stl->neighbors_start.size() == stl->stats.number_of_facets); + stl->facet_start.emplace_back(*new_facet); + // note that the normal vector is not set here, just initialized to 0. + stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero(); + stl->neighbors_start.emplace_back(); + ++ stl->stats.facets_added; + ++ stl->stats.number_of_facets; } diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp index ba116e7d670..2d9f4e2e3a4 100644 --- a/src/admesh/normals.cpp +++ b/src/admesh/normals.cpp @@ -33,207 +33,207 @@ static void reverse_facet(stl_file *stl, int facet_num) { - ++ stl->stats.facets_reversed; - - int neighbor[3] = { stl->neighbors_start[facet_num].neighbor[0], stl->neighbors_start[facet_num].neighbor[1], stl->neighbors_start[facet_num].neighbor[2] }; - int vnot[3] = { stl->neighbors_start[facet_num].which_vertex_not[0], stl->neighbors_start[facet_num].which_vertex_not[1], stl->neighbors_start[facet_num].which_vertex_not[2] }; - - // reverse the facet - stl_vertex tmp_vertex = stl->facet_start[facet_num].vertex[0]; - stl->facet_start[facet_num].vertex[0] = stl->facet_start[facet_num].vertex[1]; - stl->facet_start[facet_num].vertex[1] = tmp_vertex; - - // fix the vnots of the neighboring facets - if (neighbor[0] != -1) - stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = (stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6; - if (neighbor[1] != -1) - stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = (stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6; - if (neighbor[2] != -1) - stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] = (stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6; - - // swap the neighbors of the facet that is being reversed - stl->neighbors_start[facet_num].neighbor[1] = neighbor[2]; - stl->neighbors_start[facet_num].neighbor[2] = neighbor[1]; - - // swap the vnots of the facet that is being reversed - stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2]; - stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1]; - - // reverse the values of the vnots of the facet that is being reversed - stl->neighbors_start[facet_num].which_vertex_not[0] = (stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6; - stl->neighbors_start[facet_num].which_vertex_not[1] = (stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6; - stl->neighbors_start[facet_num].which_vertex_not[2] = (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6; + ++ stl->stats.facets_reversed; + + int neighbor[3] = { stl->neighbors_start[facet_num].neighbor[0], stl->neighbors_start[facet_num].neighbor[1], stl->neighbors_start[facet_num].neighbor[2] }; + int vnot[3] = { stl->neighbors_start[facet_num].which_vertex_not[0], stl->neighbors_start[facet_num].which_vertex_not[1], stl->neighbors_start[facet_num].which_vertex_not[2] }; + + // reverse the facet + stl_vertex tmp_vertex = stl->facet_start[facet_num].vertex[0]; + stl->facet_start[facet_num].vertex[0] = stl->facet_start[facet_num].vertex[1]; + stl->facet_start[facet_num].vertex[1] = tmp_vertex; + + // fix the vnots of the neighboring facets + if (neighbor[0] != -1) + stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = (stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6; + if (neighbor[1] != -1) + stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = (stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6; + if (neighbor[2] != -1) + stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] = (stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6; + + // swap the neighbors of the facet that is being reversed + stl->neighbors_start[facet_num].neighbor[1] = neighbor[2]; + stl->neighbors_start[facet_num].neighbor[2] = neighbor[1]; + + // swap the vnots of the facet that is being reversed + stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2]; + stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1]; + + // reverse the values of the vnots of the facet that is being reversed + stl->neighbors_start[facet_num].which_vertex_not[0] = (stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6; + stl->neighbors_start[facet_num].which_vertex_not[1] = (stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6; + stl->neighbors_start[facet_num].which_vertex_not[2] = (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6; } // Returns true if the normal was flipped. static bool check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) { - stl_facet *facet = &stl->facet_start[facet_num]; - - stl_normal normal; - stl_calculate_normal(normal, facet); - stl_normalize_vector(normal); - stl_normal normal_dif = (normal - facet->normal).cwiseAbs(); - - const float eps = 0.001f; - if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { - // Normal is within tolerance. It is not really necessary to change the values here, but just for consistency, I will. - facet->normal = normal; - return false; - } - - stl_normal test_norm = facet->normal; - stl_normalize_vector(test_norm); - normal_dif = (normal - test_norm).cwiseAbs(); - if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { - // The normal is not within tolerance, but direction is OK. - if (normal_fix_flag) { - facet->normal = normal; - ++ stl->stats.normals_fixed; - } - return false; - } - - test_norm *= -1.f; - normal_dif = (normal - test_norm).cwiseAbs(); - if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { - // The normal is not within tolerance and backwards. - if (normal_fix_flag) { - facet->normal = normal; - ++ stl->stats.normals_fixed; - } - return true; - } - if (normal_fix_flag) { - facet->normal = normal; - ++ stl->stats.normals_fixed; - } - // Status is unknown. - return false; + stl_facet *facet = &stl->facet_start[facet_num]; + + stl_normal normal; + stl_calculate_normal(normal, facet); + stl_normalize_vector(normal); + stl_normal normal_dif = (normal - facet->normal).cwiseAbs(); + + const float eps = 0.001f; + if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { + // Normal is within tolerance. It is not really necessary to change the values here, but just for consistency, I will. + facet->normal = normal; + return false; + } + + stl_normal test_norm = facet->normal; + stl_normalize_vector(test_norm); + normal_dif = (normal - test_norm).cwiseAbs(); + if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { + // The normal is not within tolerance, but direction is OK. + if (normal_fix_flag) { + facet->normal = normal; + ++ stl->stats.normals_fixed; + } + return false; + } + + test_norm *= -1.f; + normal_dif = (normal - test_norm).cwiseAbs(); + if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { + // The normal is not within tolerance and backwards. + if (normal_fix_flag) { + facet->normal = normal; + ++ stl->stats.normals_fixed; + } + return true; + } + if (normal_fix_flag) { + facet->normal = normal; + ++ stl->stats.normals_fixed; + } + // Status is unknown. + return false; } void stl_fix_normal_directions(stl_file *stl) { - // This may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209 - if (stl->stats.number_of_facets == 0) - return; - - struct stl_normal { - int facet_num; - stl_normal *next; - }; - - // Initialize linked list. - boost::object_pool pool; - stl_normal *head = pool.construct(); - stl_normal *tail = pool.construct(); - head->next = tail; - tail->next = tail; - - // Initialize list that keeps track of already fixed facets. - std::vector norm_sw(stl->stats.number_of_facets, 0); - // Initialize list that keeps track of reversed facets. + // This may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209 + if (stl->stats.number_of_facets == 0) + return; + + struct stl_normal { + int facet_num; + stl_normal *next; + }; + + // Initialize linked list. + boost::object_pool pool; + stl_normal *head = pool.construct(); + stl_normal *tail = pool.construct(); + head->next = tail; + tail->next = tail; + + // Initialize list that keeps track of already fixed facets. + std::vector norm_sw(stl->stats.number_of_facets, 0); + // Initialize list that keeps track of reversed facets. std::vector reversed_ids; reversed_ids.reserve(stl->stats.number_of_facets); - int facet_num = 0; - // If normal vector is not within tolerance and backwards: + int facet_num = 0; + // If normal vector is not within tolerance and backwards: // Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances // of it being wrong randomly are low if most of the triangles are right: - if (check_normal_vector(stl, 0, 0)) { - reverse_facet(stl, 0); - reversed_ids.emplace_back(0); - } - - // Say that we've fixed this facet: - norm_sw[facet_num] = 1; - int checked = 1; - - for (;;) { - // Add neighbors_to_list. Add unconnected neighbors to the list. - bool force_exit = false; - for (int j = 0; j < 3; ++ j) { - // Reverse the neighboring facets if necessary. - if (stl->neighbors_start[facet_num].which_vertex_not[j] > 2) { - // If the facet has a neighbor that is -1, it means that edge isn't shared by another facet - if (stl->neighbors_start[facet_num].neighbor[j] != -1) { - if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) { - // trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) - for (int id = int(reversed_ids.size()) - 1; id >= 0; -- id) - reverse_facet(stl, reversed_ids[id]); - force_exit = true; - break; - } - reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]); - reversed_ids.emplace_back(stl->neighbors_start[facet_num].neighbor[j]); - } - } - // If this edge of the facet is connected: - if (stl->neighbors_start[facet_num].neighbor[j] != -1) { - // If we haven't fixed this facet yet, add it to the list: - if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) { - // Add node to beginning of list. - stl_normal *newn = pool.construct(); - newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; - newn->next = head->next; - head->next = newn; - } - } - } - - // an error occourred, quit the for loop and exit - if (force_exit) - break; - - // Get next facet to fix from top of list. - if (head->next != tail) { - facet_num = head->next->facet_num; + if (check_normal_vector(stl, 0, 0)) { + reverse_facet(stl, 0); + reversed_ids.emplace_back(0); + } + + // Say that we've fixed this facet: + norm_sw[facet_num] = 1; + int checked = 1; + + for (;;) { + // Add neighbors_to_list. Add unconnected neighbors to the list. + bool force_exit = false; + for (int j = 0; j < 3; ++ j) { + // Reverse the neighboring facets if necessary. + if (stl->neighbors_start[facet_num].which_vertex_not[j] > 2) { + // If the facet has a neighbor that is -1, it means that edge isn't shared by another facet + if (stl->neighbors_start[facet_num].neighbor[j] != -1) { + if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) { + // trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) + for (int id = int(reversed_ids.size()) - 1; id >= 0; -- id) + reverse_facet(stl, reversed_ids[id]); + force_exit = true; + break; + } + reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]); + reversed_ids.emplace_back(stl->neighbors_start[facet_num].neighbor[j]); + } + } + // If this edge of the facet is connected: + if (stl->neighbors_start[facet_num].neighbor[j] != -1) { + // If we haven't fixed this facet yet, add it to the list: + if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) { + // Add node to beginning of list. + stl_normal *newn = pool.construct(); + newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; + newn->next = head->next; + head->next = newn; + } + } + } + + // an error occourred, quit the for loop and exit + if (force_exit) + break; + + // Get next facet to fix from top of list. + if (head->next != tail) { + facet_num = head->next->facet_num; assert(facet_num < stl->stats.number_of_facets); - if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times - norm_sw[facet_num] = 1; // Record this one as being fixed. - ++ checked; - } - // Delete this facet from the list. - head->next = head->next->next; - // pool.destroy(temp); - } else { // If we ran out of facets to fix: All of the facets in this part have been fixed. - ++ stl->stats.number_of_parts; - if (checked >= int(stl->stats.number_of_facets)) - // All of the facets have been checked. Bail out. - break; - // There is another part here. Find it and continue. - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - if (norm_sw[i] == 0) { - // This is the first facet of the next part. - facet_num = i; - if (check_normal_vector(stl, i, 0)) { - reverse_facet(stl, i); - reversed_ids.emplace_back(i); - } - norm_sw[facet_num] = 1; - ++ checked; - break; - } - } - } - - // pool.destroy(head); - // pool.destroy(tail); + if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times + norm_sw[facet_num] = 1; // Record this one as being fixed. + ++ checked; + } + // Delete this facet from the list. + head->next = head->next->next; + // pool.destroy(temp); + } else { // If we ran out of facets to fix: All of the facets in this part have been fixed. + ++ stl->stats.number_of_parts; + if (checked >= int(stl->stats.number_of_facets)) + // All of the facets have been checked. Bail out. + break; + // There is another part here. Find it and continue. + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + if (norm_sw[i] == 0) { + // This is the first facet of the next part. + facet_num = i; + if (check_normal_vector(stl, i, 0)) { + reverse_facet(stl, i); + reversed_ids.emplace_back(i); + } + norm_sw[facet_num] = 1; + ++ checked; + break; + } + } + } + + // pool.destroy(head); + // pool.destroy(tail); } void stl_fix_normal_values(stl_file *stl) { - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - check_normal_vector(stl, i, 1); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + check_normal_vector(stl, i, 1); } void stl_reverse_all_facets(stl_file *stl) { - stl_normal normal; - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - reverse_facet(stl, i); - stl_calculate_normal(normal, &stl->facet_start[i]); - stl_normalize_vector(normal); - stl->facet_start[i].normal = normal; - } + stl_normal normal; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + reverse_facet(stl, i); + stl_calculate_normal(normal, &stl->facet_start[i]); + stl_normalize_vector(normal); + stl->facet_start[i].normal = normal; + } } diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index 97d65b037a7..b0afcf8778e 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -34,230 +34,230 @@ void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its) { - // 3 indices to vertex per face - its.indices.assign(stl->stats.number_of_facets, stl_triangle_vertex_indices(-1, -1, -1)); - // Shared vertices (3D coordinates) - its.vertices.clear(); - its.vertices.reserve(stl->stats.number_of_facets / 2); + // 3 indices to vertex per face + its.indices.assign(stl->stats.number_of_facets, stl_triangle_vertex_indices(-1, -1, -1)); + // Shared vertices (3D coordinates) + its.vertices.clear(); + its.vertices.reserve(stl->stats.number_of_facets / 2); - // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop - // while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal - // are marked with a unique fan_traversal_stamp. - unsigned int fan_traversal_stamp = 0; - std::vector fan_traversal_facet_visited(stl->stats.number_of_facets, 0); + // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop + // while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal + // are marked with a unique fan_traversal_stamp. + unsigned int fan_traversal_stamp = 0; + std::vector fan_traversal_facet_visited(stl->stats.number_of_facets, 0); - for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) { - for (int j = 0; j < 3; ++ j) { - if (its.indices[facet_idx][j] != -1) - // Shared vertex was already assigned. - continue; - // Create a new shared vertex. - its.vertices.emplace_back(stl->facet_start[facet_idx].vertex[j]); - // Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan. - int facet_in_fan_idx = facet_idx; - bool edge_direction = false; - bool traversal_reversed = false; - int vnot = (j + 2) % 3; - // Increase the - ++ fan_traversal_stamp; - for (;;) { - // Next edge on facet_in_fan_idx to be traversed. The edge is indexed by its starting vertex index. - int next_edge = 0; - // Vertex index in facet_in_fan_idx, which is being pivoted around, and which is being assigned a new shared vertex. - int pivot_vertex = 0; - if (vnot > 2) { - // The edge of facet_in_fan_idx opposite to vnot is equally oriented, therefore - // the neighboring facet is flipped. - if (! edge_direction) { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } else { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot % 3; - } - edge_direction = ! edge_direction; - } else { - // The neighboring facet is correctly oriented. - if (! edge_direction) { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot; - } else { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - } - its.indices[facet_in_fan_idx][pivot_vertex] = its.vertices.size() - 1; - fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp; + for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) { + for (int j = 0; j < 3; ++ j) { + if (its.indices[facet_idx][j] != -1) + // Shared vertex was already assigned. + continue; + // Create a new shared vertex. + its.vertices.emplace_back(stl->facet_start[facet_idx].vertex[j]); + // Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan. + int facet_in_fan_idx = facet_idx; + bool edge_direction = false; + bool traversal_reversed = false; + int vnot = (j + 2) % 3; + // Increase the + ++ fan_traversal_stamp; + for (;;) { + // Next edge on facet_in_fan_idx to be traversed. The edge is indexed by its starting vertex index. + int next_edge = 0; + // Vertex index in facet_in_fan_idx, which is being pivoted around, and which is being assigned a new shared vertex. + int pivot_vertex = 0; + if (vnot > 2) { + // The edge of facet_in_fan_idx opposite to vnot is equally oriented, therefore + // the neighboring facet is flipped. + if (! edge_direction) { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } else { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot % 3; + } + edge_direction = ! edge_direction; + } else { + // The neighboring facet is correctly oriented. + if (! edge_direction) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot; + } else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + } + its.indices[facet_in_fan_idx][pivot_vertex] = its.vertices.size() - 1; + fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp; - // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! - int next_facet = stl->neighbors_start[facet_in_fan_idx].neighbor[next_edge]; - if (next_facet == -1) { - // No neighbor going in the current direction. - if (traversal_reversed) { - // Went to one limit, then turned back and reached the other limit. Quit the fan traversal. - break; - } else { - // Reached the first limit. Now try to reverse and traverse up to the other limit. - edge_direction = true; - vnot = (j + 1) % 3; - traversal_reversed = true; - facet_in_fan_idx = facet_idx; - } - } else if (next_facet == static_cast(facet_idx)) { - // Traversed a closed fan all around. -// assert(! traversal_reversed); - break; - } else if (next_facet >= (int)stl->stats.number_of_facets) { - // The mesh is not valid! - // assert(false); - break; - } else if (fan_traversal_facet_visited[next_facet] == fan_traversal_stamp) { - // Traversed a closed fan all around, but did not reach the starting face. - // This indicates an invalid geometry (non-manifold). - //assert(false); - break; - } else { - // Continue traversal. - // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! - vnot = stl->neighbors_start[facet_in_fan_idx].which_vertex_not[next_edge]; - facet_in_fan_idx = next_facet; - } - } - } - } + // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! + int next_facet = stl->neighbors_start[facet_in_fan_idx].neighbor[next_edge]; + if (next_facet == -1) { + // No neighbor going in the current direction. + if (traversal_reversed) { + // Went to one limit, then turned back and reached the other limit. Quit the fan traversal. + break; + } else { + // Reached the first limit. Now try to reverse and traverse up to the other limit. + edge_direction = true; + vnot = (j + 1) % 3; + traversal_reversed = true; + facet_in_fan_idx = facet_idx; + } + } else if (next_facet == static_cast(facet_idx)) { + // Traversed a closed fan all around. +// assert(! traversal_reversed); + break; + } else if (next_facet >= (int)stl->stats.number_of_facets) { + // The mesh is not valid! + // assert(false); + break; + } else if (fan_traversal_facet_visited[next_facet] == fan_traversal_stamp) { + // Traversed a closed fan all around, but did not reach the starting face. + // This indicates an invalid geometry (non-manifold). + //assert(false); + break; + } else { + // Continue traversal. + // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! + vnot = stl->neighbors_start[facet_in_fan_idx].which_vertex_not[next_edge]; + facet_in_fan_idx = next_facet; + } + } + } + } } bool its_write_off(const indexed_triangle_set &its, const char *file) { Slic3r::CNumericLocalesSetter locales_setter; - /* Open the file */ - FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing"; - return false; - } + /* Open the file */ + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing"; + return false; + } - fprintf(fp, "OFF\n"); - fprintf(fp, "%d %d 0\n", (int)its.vertices.size(), (int)its.indices.size()); - for (size_t i = 0; i < its.vertices.size(); ++i) - fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); - for (uint32_t i = 0; i < its.indices.size(); ++ i) - fprintf(fp, "\t3 %d %d %d\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); - fclose(fp); - return true; + fprintf(fp, "OFF\n"); + fprintf(fp, "%d %d 0\n", (int)its.vertices.size(), (int)its.indices.size()); + for (size_t i = 0; i < its.vertices.size(); ++i) + fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); + for (uint32_t i = 0; i < its.indices.size(); ++ i) + fprintf(fp, "\t3 %d %d %d\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); + fclose(fp); + return true; } bool its_write_vrml(const indexed_triangle_set &its, const char *file) { Slic3r::CNumericLocalesSetter locales_setter; - /* Open the file */ - FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_write_vrml: Couldn't open " << file << " for writing"; - return false; - } + /* Open the file */ + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_vrml: Couldn't open " << file << " for writing"; + return false; + } - fprintf(fp, "#VRML V1.0 ascii\n\n"); - fprintf(fp, "Separator {\n"); - fprintf(fp, "\tDEF STLShape ShapeHints {\n"); - fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n"); - fprintf(fp, "\t\tfaceType CONVEX\n"); - fprintf(fp, "\t\tshapeType SOLID\n"); - fprintf(fp, "\t\tcreaseAngle 0.0\n"); - fprintf(fp, "\t}\n"); - fprintf(fp, "\tDEF STLModel Separator {\n"); - fprintf(fp, "\t\tDEF STLColor Material {\n"); - fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n"); - fprintf(fp, "\t\t}\n"); - fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n"); - fprintf(fp, "\t\t\tpoint [\n"); + fprintf(fp, "#VRML V1.0 ascii\n\n"); + fprintf(fp, "Separator {\n"); + fprintf(fp, "\tDEF STLShape ShapeHints {\n"); + fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n"); + fprintf(fp, "\t\tfaceType CONVEX\n"); + fprintf(fp, "\t\tshapeType SOLID\n"); + fprintf(fp, "\t\tcreaseAngle 0.0\n"); + fprintf(fp, "\t}\n"); + fprintf(fp, "\tDEF STLModel Separator {\n"); + fprintf(fp, "\t\tDEF STLColor Material {\n"); + fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n"); + fprintf(fp, "\t\t}\n"); + fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n"); + fprintf(fp, "\t\t\tpoint [\n"); - size_t i = 0; - for (; i + 1 < its.vertices.size(); ++i) - fprintf(fp, "\t\t\t\t%f %f %f,\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); - fprintf(fp, "\t\t\t\t%f %f %f]\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); - fprintf(fp, "\t\t}\n"); - fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n"); - fprintf(fp, "\t\t\tcoordIndex [\n"); + size_t i = 0; + for (; i + 1 < its.vertices.size(); ++i) + fprintf(fp, "\t\t\t\t%f %f %f,\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); + fprintf(fp, "\t\t\t\t%f %f %f]\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); + fprintf(fp, "\t\t}\n"); + fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n"); + fprintf(fp, "\t\t\tcoordIndex [\n"); - for (size_t i = 0; i + 1 < its.indices.size(); ++ i) - fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); - fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); - fprintf(fp, "\t\t}\n"); - fprintf(fp, "\t}\n"); - fprintf(fp, "}\n"); - fclose(fp); - return true; + for (size_t i = 0; i + 1 < its.indices.size(); ++ i) + fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); + fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); + fprintf(fp, "\t\t}\n"); + fprintf(fp, "\t}\n"); + fprintf(fp, "}\n"); + fclose(fp); + return true; } bool its_write_obj(const indexed_triangle_set &its, const char *file) { Slic3r::CNumericLocalesSetter locales_setter; - FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing"; - return false; - } + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing"; + return false; + } - for (size_t i = 0; i < its.vertices.size(); ++ i) - fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); - for (size_t i = 0; i < its.indices.size(); ++ i) - fprintf(fp, "f %d %d %d\n", its.indices[i][0]+1, its.indices[i][1]+1, its.indices[i][2]+1); - fclose(fp); - return true; + for (size_t i = 0; i < its.vertices.size(); ++ i) + fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); + for (size_t i = 0; i < its.indices.size(); ++ i) + fprintf(fp, "f %d %d %d\n", its.indices[i][0]+1, its.indices[i][1]+1, its.indices[i][2]+1); + fclose(fp); + return true; } // Check validity of the mesh, assert on error. bool stl_validate(const stl_file *stl, const indexed_triangle_set &its) { - assert(! stl->facet_start.empty()); - assert(stl->facet_start.size() == stl->stats.number_of_facets); - assert(stl->neighbors_start.size() == stl->stats.number_of_facets); - assert(stl->facet_start.size() == stl->neighbors_start.size()); - assert(! stl->neighbors_start.empty()); - assert((its.indices.empty()) == (its.vertices.empty())); - assert(stl->stats.number_of_facets > 0); - assert(its.vertices.empty() || its.indices.size() == stl->stats.number_of_facets); + assert(! stl->facet_start.empty()); + assert(stl->facet_start.size() == stl->stats.number_of_facets); + assert(stl->neighbors_start.size() == stl->stats.number_of_facets); + assert(stl->facet_start.size() == stl->neighbors_start.size()); + assert(! stl->neighbors_start.empty()); + assert((its.indices.empty()) == (its.vertices.empty())); + assert(stl->stats.number_of_facets > 0); + assert(its.vertices.empty() || its.indices.size() == stl->stats.number_of_facets); #ifdef _DEBUG // Verify validity of neighborship data. for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) { - const stl_neighbors &nbr = stl->neighbors_start[facet_idx]; - const int *vertices = its.indices.empty() ? nullptr : its.indices[facet_idx].data(); + const stl_neighbors &nbr = stl->neighbors_start[facet_idx]; + const int *vertices = its.indices.empty() ? nullptr : its.indices[facet_idx].data(); for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) { int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx]; assert(nbr_face < (int)stl->stats.number_of_facets); if (nbr_face != -1) { - int nbr_vnot = nbr.which_vertex_not[nbr_idx]; - assert(nbr_vnot >= 0 && nbr_vnot < 6); - // Neighbor of the neighbor is the original face. - assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx); - int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3]; - assert(vnot_back >= 0 && vnot_back < 6); - assert((nbr_vnot < 3) == (vnot_back < 3)); - assert(vnot_back % 3 == (nbr_idx + 2) % 3); - if (vertices != nullptr) { - // Has shared vertices. - if (nbr_vnot < 3) { - // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented. - assert((its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[nbr_idx])); - } else { - // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped. - assert((its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[nbr_idx])); - } - } + int nbr_vnot = nbr.which_vertex_not[nbr_idx]; + assert(nbr_vnot >= 0 && nbr_vnot < 6); + // Neighbor of the neighbor is the original face. + assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx); + int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3]; + assert(vnot_back >= 0 && vnot_back < 6); + assert((nbr_vnot < 3) == (vnot_back < 3)); + assert(vnot_back % 3 == (nbr_idx + 2) % 3); + if (vertices != nullptr) { + // Has shared vertices. + if (nbr_vnot < 3) { + // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented. + assert((its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[nbr_idx])); + } else { + // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped. + assert((its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[nbr_idx])); + } + } } } } #endif /* _DEBUG */ - return true; + return true; } // Check validity of the mesh, assert on error. bool stl_validate(const stl_file *stl) { - indexed_triangle_set its; - return stl_validate(stl, its); + indexed_triangle_set its; + return stl_validate(stl, its); } diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 516f86ba914..308975d4e6e 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -28,7 +28,7 @@ #include #include -#include +#include // Size of the binary STL header, free form. #define LABEL_SIZE 80 @@ -46,18 +46,18 @@ static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect"); static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect"); struct stl_facet { - stl_normal normal; - stl_vertex vertex[3]; - char extra[2]; - - stl_facet rotated(const Eigen::Quaternion &rot) const { - stl_facet out; - out.normal = rot * this->normal; - out.vertex[0] = rot * this->vertex[0]; - out.vertex[1] = rot * this->vertex[1]; - out.vertex[2] = rot * this->vertex[2]; - return out; - } + stl_normal normal; + stl_vertex vertex[3]; + char extra[2]; + + stl_facet rotated(const Eigen::Quaternion &rot) const { + stl_facet out; + out.normal = rot * this->normal; + out.vertex[0] = rot * this->vertex[0]; + out.vertex[1] = rot * this->vertex[1]; + out.vertex[2] = rot * this->vertex[2]; + return out; + } }; #define SIZEOF_STL_FACET 50 @@ -70,21 +70,21 @@ static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrec typedef enum {binary, ascii, inmemory} stl_type; struct stl_neighbors { - stl_neighbors() { reset(); } - void reset() { - neighbor[0] = -1; - neighbor[1] = -1; - neighbor[2] = -1; - which_vertex_not[0] = -1; - which_vertex_not[1] = -1; - which_vertex_not[2] = -1; - } - int num_neighbors() const { return 3 - ((this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1)); } - - // Index of a neighbor facet. - int neighbor[3]; - // Index of an opposite vertex at the neighbor face. - char which_vertex_not[3]; + stl_neighbors() { reset(); } + void reset() { + neighbor[0] = -1; + neighbor[1] = -1; + neighbor[2] = -1; + which_vertex_not[0] = -1; + which_vertex_not[1] = -1; + which_vertex_not[2] = -1; + } + int num_neighbors() const { return 3 - ((this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1)); } + + // Index of a neighbor facet. + int neighbor[3]; + // Index of an opposite vertex at the neighbor face. + char which_vertex_not[3]; }; struct stl_stats { @@ -135,34 +135,34 @@ struct stl_stats { }; struct stl_file { - stl_file() {} + stl_file() {} - void clear() { - this->facet_start.clear(); - this->neighbors_start.clear(); + void clear() { + this->facet_start.clear(); + this->neighbors_start.clear(); this->stats.clear(); - } + } - size_t memsize() const { - return sizeof(*this) + sizeof(stl_facet) * facet_start.size() + sizeof(stl_neighbors) * neighbors_start.size(); - } + size_t memsize() const { + return sizeof(*this) + sizeof(stl_facet) * facet_start.size() + sizeof(stl_neighbors) * neighbors_start.size(); + } - std::vector facet_start; - std::vector neighbors_start; - // Statistics - stl_stats stats; + std::vector facet_start; + std::vector neighbors_start; + // Statistics + stl_stats stats; }; struct indexed_triangle_set { - void clear() { indices.clear(); vertices.clear(); } + void clear() { indices.clear(); vertices.clear(); } - size_t memsize() const { - return sizeof(*this) + sizeof(stl_triangle_vertex_indices) * indices.size() + sizeof(stl_vertex) * vertices.size(); - } + size_t memsize() const { + return sizeof(*this) + sizeof(stl_triangle_vertex_indices) * indices.size() + sizeof(stl_vertex) * vertices.size(); + } - std::vector indices; - std::vector vertices; + std::vector indices; + std::vector vertices; bool empty() const { return indices.empty() || vertices.empty(); } }; @@ -212,18 +212,18 @@ extern void stl_transform(stl_file *stl, T *trafo3x4) } Eigen::Matrix r = trafo3x3.inverse().transpose(); for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) { - stl_facet &face = stl->facet_start[i_face]; - for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) { - stl_vertex &v_dst = face.vertex[i_vertex]; - stl_vertex v_src = v_dst; - v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); - v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); - v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); - } + stl_facet &face = stl->facet_start[i_face]; + for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) { + stl_vertex &v_dst = face.vertex[i_vertex]; + stl_vertex v_src = v_dst; + v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); + v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); + v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); + } face.normal = (r * face.normal.template cast()).template cast().eval(); } - stl_get_size(stl); + stl_get_size(stl); } */ @@ -232,13 +232,13 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform r = t.matrix().template block<3, 3>(0, 0).inverse().transpose(); for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { - stl_facet &f = stl->facet_start[i]; - for (size_t j = 0; j < 3; ++j) - f.vertex[j] = (t * f.vertex[j].template cast()).template cast().eval(); - f.normal = (r * f.normal.template cast()).template cast().eval(); - } + stl_facet &f = stl->facet_start[i]; + for (size_t j = 0; j < 3; ++j) + f.vertex[j] = (t * f.vertex[j].template cast()).template cast().eval(); + f.normal = (r * f.normal.template cast()).template cast().eval(); + } - stl_get_size(stl); + stl_get_size(stl); } template @@ -246,13 +246,13 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix r = m.inverse().transpose(); for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { - stl_facet &f = stl->facet_start[i]; - for (size_t j = 0; j < 3; ++j) - f.vertex[j] = (m * f.vertex[j].template cast()).template cast().eval(); + stl_facet &f = stl->facet_start[i]; + for (size_t j = 0; j < 3; ++j) + f.vertex[j] = (m * f.vertex[j].template cast()).template cast().eval(); f.normal = (r * f.normal.template cast()).template cast().eval(); } - stl_get_size(stl); + stl_get_size(stl); } template @@ -265,20 +265,20 @@ inline void its_translate(indexed_triangle_set &its, const V v) template inline void its_transform(indexed_triangle_set &its, T *trafo3x4) { - for (stl_vertex &v_dst : its.vertices) { - stl_vertex v_src = v_dst; - v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); - v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); - v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); - } + for (stl_vertex &v_dst : its.vertices) { + stl_vertex v_src = v_dst; + v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); + v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); + v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); + } } template inline void its_transform(indexed_triangle_set &its, const Eigen::Transform& t, bool fix_left_handed = false) { - //const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); - for (stl_vertex &v : its.vertices) - v = (t * v.template cast()).template cast().eval(); + //const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); + for (stl_vertex &v : its.vertices) + v = (t * v.template cast()).template cast().eval(); if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) for (stl_triangle_vertex_indices &i : its.indices) std::swap(i[0], i[1]); @@ -288,7 +288,7 @@ template inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix& m, bool fix_left_handed = false) { for (stl_vertex &v : its.vertices) - v = (m * v.template cast()).template cast().eval(); + v = (m * v.template cast()).template cast().eval(); if (fix_left_handed && m.determinant() < 0.) for (stl_triangle_vertex_indices &i : its.indices) std::swap(i[0], i[1]); diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp index 26f5dc3212c..1c16fd04d41 100644 --- a/src/admesh/stl_io.cpp +++ b/src/admesh/stl_io.cpp @@ -31,77 +31,77 @@ void stl_stats_out(stl_file *stl, FILE *file, char *input_file) { - // This is here for Slic3r, without our config.h it won't use this part of the code anyway. + // This is here for Slic3r, without our config.h it won't use this part of the code anyway. #ifndef VERSION #define VERSION "unknown" #endif - fprintf(file, "\n================= Results produced by ADMesh version " VERSION " ================\n"); - fprintf(file, "Input file : %s\n", input_file); - if (stl->stats.type == binary) - fprintf(file, "File type : Binary STL file\n"); - else - fprintf(file, "File type : ASCII STL file\n"); - fprintf(file, "Header : %s\n", stl->stats.header); - fprintf(file, "============== Size ==============\n"); - fprintf(file, "Min X = % f, Max X = % f\n", stl->stats.min(0), stl->stats.max(0)); - fprintf(file, "Min Y = % f, Max Y = % f\n", stl->stats.min(1), stl->stats.max(1)); - fprintf(file, "Min Z = % f, Max Z = % f\n", stl->stats.min(2), stl->stats.max(2)); - fprintf(file, "========= Facet Status ========== Original ============ Final ====\n"); - fprintf(file, "Number of facets : %5d %5d\n", stl->stats.original_num_facets, stl->stats.number_of_facets); - fprintf(file, "Facets with 1 disconnected edge : %5d %5d\n", - stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge); - fprintf(file, "Facets with 2 disconnected edges : %5d %5d\n", - stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge); - fprintf(file, "Facets with 3 disconnected edges : %5d %5d\n", + fprintf(file, "\n================= Results produced by ADMesh version " VERSION " ================\n"); + fprintf(file, "Input file : %s\n", input_file); + if (stl->stats.type == binary) + fprintf(file, "File type : Binary STL file\n"); + else + fprintf(file, "File type : ASCII STL file\n"); + fprintf(file, "Header : %s\n", stl->stats.header); + fprintf(file, "============== Size ==============\n"); + fprintf(file, "Min X = % f, Max X = % f\n", stl->stats.min(0), stl->stats.max(0)); + fprintf(file, "Min Y = % f, Max Y = % f\n", stl->stats.min(1), stl->stats.max(1)); + fprintf(file, "Min Z = % f, Max Z = % f\n", stl->stats.min(2), stl->stats.max(2)); + fprintf(file, "========= Facet Status ========== Original ============ Final ====\n"); + fprintf(file, "Number of facets : %5d %5d\n", stl->stats.original_num_facets, stl->stats.number_of_facets); + fprintf(file, "Facets with 1 disconnected edge : %5d %5d\n", + stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge); + fprintf(file, "Facets with 2 disconnected edges : %5d %5d\n", + stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge); + fprintf(file, "Facets with 3 disconnected edges : %5d %5d\n", stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_1_edge); - fprintf(file, "Total disconnected facets : %5d %5d\n", - stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge + stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_3_edge); - fprintf(file, "=== Processing Statistics === ===== Other Statistics =====\n"); - fprintf(file, "Number of parts : %5d Volume : %f\n", stl->stats.number_of_parts, stl->stats.volume); - fprintf(file, "Degenerate facets : %5d\n", stl->stats.degenerate_facets); - fprintf(file, "Edges fixed : %5d\n", stl->stats.edges_fixed); - fprintf(file, "Facets removed : %5d\n", stl->stats.facets_removed); - fprintf(file, "Facets added : %5d\n", stl->stats.facets_added); - fprintf(file, "Facets reversed : %5d\n", stl->stats.facets_reversed); - fprintf(file, "Backwards edges : %5d\n", stl->stats.backwards_edges); - fprintf(file, "Normals fixed : %5d\n", stl->stats.normals_fixed); + fprintf(file, "Total disconnected facets : %5d %5d\n", + stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge + stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_3_edge); + fprintf(file, "=== Processing Statistics === ===== Other Statistics =====\n"); + fprintf(file, "Number of parts : %5d Volume : %f\n", stl->stats.number_of_parts, stl->stats.volume); + fprintf(file, "Degenerate facets : %5d\n", stl->stats.degenerate_facets); + fprintf(file, "Edges fixed : %5d\n", stl->stats.edges_fixed); + fprintf(file, "Facets removed : %5d\n", stl->stats.facets_removed); + fprintf(file, "Facets added : %5d\n", stl->stats.facets_added); + fprintf(file, "Facets reversed : %5d\n", stl->stats.facets_reversed); + fprintf(file, "Backwards edges : %5d\n", stl->stats.backwards_edges); + fprintf(file, "Normals fixed : %5d\n", stl->stats.normals_fixed); } bool stl_write_ascii(stl_file *stl, const char *file, const char *label) { - FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing"; - return false; - } - - fprintf(fp, "solid %s\n", label); - - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - fprintf(fp, " facet normal % .8E % .8E % .8E\n", stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), stl->facet_start[i].normal(2)); - fprintf(fp, " outer loop\n"); - fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2)); - fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2)); - fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); - fprintf(fp, " endloop\n"); - fprintf(fp, " endfacet\n"); - } - - fprintf(fp, "endsolid %s\n", label); - fclose(fp); - return true; + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing"; + return false; + } + + fprintf(fp, "solid %s\n", label); + + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + fprintf(fp, " facet normal % .8E % .8E % .8E\n", stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), stl->facet_start[i].normal(2)); + fprintf(fp, " outer loop\n"); + fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2)); + fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2)); + fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); + fprintf(fp, " endloop\n"); + fprintf(fp, " endfacet\n"); + } + + fprintf(fp, "endsolid %s\n", label); + fclose(fp); + return true; } bool stl_print_neighbors(stl_file *stl, char *file) { - FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing"; - return false; - } - - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n", + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing"; + return false; + } + + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n", i, stl->neighbors_start[i].neighbor[0], (int)stl->neighbors_start[i].which_vertex_not[0], @@ -109,62 +109,62 @@ bool stl_print_neighbors(stl_file *stl, char *file) (int)stl->neighbors_start[i].which_vertex_not[1], stl->neighbors_start[i].neighbor[2], (int)stl->neighbors_start[i].which_vertex_not[2]); - } - fclose(fp); - return true; + } + fclose(fp); + return true; } #if BOOST_ENDIAN_BIG_BYTE // Swap a buffer of 32bit data from little endian to big endian and vice versa. void stl_internal_reverse_quads(char *buf, size_t cnt) { - for (size_t i = 0; i < cnt; i += 4) { - std::swap(buf[i], buf[i+3]); - std::swap(buf[i+1], buf[i+2]); - } + for (size_t i = 0; i < cnt; i += 4) { + std::swap(buf[i], buf[i+3]); + std::swap(buf[i+1], buf[i+2]); + } } #endif bool stl_write_binary(stl_file *stl, const char *file, const char *label) { - FILE *fp = boost::nowide::fopen(file, "wb"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing"; - return false; - } + FILE *fp = boost::nowide::fopen(file, "wb"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing"; + return false; + } - fprintf(fp, "%s", label); - for (size_t i = strlen(label); i < LABEL_SIZE; ++ i) - putc(0, fp); + fprintf(fp, "%s", label); + for (size_t i = strlen(label); i < LABEL_SIZE; ++ i) + putc(0, fp); #if !defined(SEEK_SET) - #define SEEK_SET 0 + #define SEEK_SET 0 #endif - fseek(fp, LABEL_SIZE, SEEK_SET); + fseek(fp, LABEL_SIZE, SEEK_SET); #if BOOST_ENDIAN_LITTLE_BYTE - fwrite(&stl->stats.number_of_facets, 4, 1, fp); - for (const stl_facet &facet : stl->facet_start) - fwrite(&facet, SIZEOF_STL_FACET, 1, fp); + fwrite(&stl->stats.number_of_facets, 4, 1, fp); + for (const stl_facet &facet : stl->facet_start) + fwrite(&facet, SIZEOF_STL_FACET, 1, fp); #else /* BOOST_ENDIAN_LITTLE_BYTE */ - char buffer[50]; - // Convert the number of facets to little endian. - memcpy(buffer, &stl->stats.number_of_facets, 4); - stl_internal_reverse_quads(buffer, 4); - fwrite(buffer, 4, 1, fp); - for (const stl_facet &facet : stl->facet_start) { - memcpy(buffer, &facet, 50); - // Convert to little endian. - stl_internal_reverse_quads(buffer, 48); - fwrite(buffer, SIZEOF_STL_FACET, 1, fp); - } + char buffer[50]; + // Convert the number of facets to little endian. + memcpy(buffer, &stl->stats.number_of_facets, 4); + stl_internal_reverse_quads(buffer, 4); + fwrite(buffer, 4, 1, fp); + for (const stl_facet &facet : stl->facet_start) { + memcpy(buffer, &facet, 50); + // Convert to little endian. + stl_internal_reverse_quads(buffer, 48); + fwrite(buffer, SIZEOF_STL_FACET, 1, fp); + } #endif /* BOOST_ENDIAN_LITTLE_BYTE */ - fclose(fp); - return true; + fclose(fp); + return true; } void stl_write_vertex(stl_file *stl, int facet, int vertex) { - printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet, + printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet, stl->facet_start[facet].vertex[vertex](0), stl->facet_start[facet].vertex[vertex](1), stl->facet_start[facet].vertex[vertex](2)); @@ -172,80 +172,80 @@ void stl_write_vertex(stl_file *stl, int facet, int vertex) void stl_write_facet(stl_file *stl, char *label, int facet) { - printf("facet (%d)/ %s\n", facet, label); - stl_write_vertex(stl, facet, 0); - stl_write_vertex(stl, facet, 1); - stl_write_vertex(stl, facet, 2); + printf("facet (%d)/ %s\n", facet, label); + stl_write_vertex(stl, facet, 0); + stl_write_vertex(stl, facet, 1); + stl_write_vertex(stl, facet, 2); } void stl_write_neighbor(stl_file *stl, int facet) { - printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet, - stl->neighbors_start[facet].neighbor[0], - stl->neighbors_start[facet].neighbor[1], - stl->neighbors_start[facet].neighbor[2], - stl->neighbors_start[facet].which_vertex_not[0], - stl->neighbors_start[facet].which_vertex_not[1], - stl->neighbors_start[facet].which_vertex_not[2]); + printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet, + stl->neighbors_start[facet].neighbor[0], + stl->neighbors_start[facet].neighbor[1], + stl->neighbors_start[facet].neighbor[2], + stl->neighbors_start[facet].which_vertex_not[0], + stl->neighbors_start[facet].which_vertex_not[1], + stl->neighbors_start[facet].which_vertex_not[2]); } bool stl_write_quad_object(stl_file *stl, char *file) { - stl_vertex connect_color = stl_vertex::Zero(); - stl_vertex uncon_1_color = stl_vertex::Zero(); - stl_vertex uncon_2_color = stl_vertex::Zero(); - stl_vertex uncon_3_color = stl_vertex::Zero(); - stl_vertex color; - - FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing"; - return false; - } - - fprintf(fp, "CQUAD\n"); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - switch (stl->neighbors_start[i].num_neighbors()) { - case 0: - default: color = uncon_3_color; break; - case 1: color = uncon_2_color; break; - case 2: color = uncon_1_color; break; - case 3: color = connect_color; break; - } - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2), color(0), color(1), color(2)); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2), color(0), color(1), color(2)); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2)); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2)); + stl_vertex connect_color = stl_vertex::Zero(); + stl_vertex uncon_1_color = stl_vertex::Zero(); + stl_vertex uncon_2_color = stl_vertex::Zero(); + stl_vertex uncon_3_color = stl_vertex::Zero(); + stl_vertex color; + + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing"; + return false; + } + + fprintf(fp, "CQUAD\n"); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + switch (stl->neighbors_start[i].num_neighbors()) { + case 0: + default: color = uncon_3_color; break; + case 1: color = uncon_2_color; break; + case 2: color = uncon_1_color; break; + case 3: color = connect_color; break; + } + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2), color(0), color(1), color(2)); + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2), color(0), color(1), color(2)); + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2)); + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2)); } fclose(fp); return true; } -bool stl_write_dxf(stl_file *stl, const char *file, char *label) +bool stl_write_dxf(stl_file *stl, const char *file, char *label) { - FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing"; - return false; - } - - fprintf(fp, "999\n%s\n", label); - fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n"); - fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\ - 0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n"); - fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n"); - - fprintf(fp, "0\nSECTION\n2\nENTITIES\n"); - - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - fprintf(fp, "0\n3DFACE\n8\n0\n"); - fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2)); - fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2)); - fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); - fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); - } - - fprintf(fp, "0\nENDSEC\n0\nEOF\n"); - fclose(fp); - return true; + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing"; + return false; + } + + fprintf(fp, "999\n%s\n", label); + fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n"); + fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\ + 0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n"); + fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n"); + + fprintf(fp, "0\nSECTION\n2\nENTITIES\n"); + + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + fprintf(fp, "0\n3DFACE\n8\n0\n"); + fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2)); + fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2)); + fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); + fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); + } + + fprintf(fp, "0\nENDSEC\n0\nEOF\n"); + fclose(fp); + return true; } diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 29131b1c75b..8806892fc59 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -42,104 +42,104 @@ extern void stl_internal_reverse_quads(char *buf, size_t cnt); #endif /* BOOST_ENDIAN_BIG_BYTE */ -static FILE* stl_open_count_facets(stl_file *stl, const char *file) +static FILE* stl_open_count_facets(stl_file *stl, const char *file) { - // Open the file in binary mode first. - FILE *fp = boost::nowide::fopen(file, "rb"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading"; - return nullptr; - } - // Find size of file. - fseek(fp, 0, SEEK_END); - long file_size = ftell(fp); - - // Check for binary or ASCII file. - fseek(fp, HEADER_SIZE, SEEK_SET); - unsigned char chtest[128]; - if (! fread(chtest, sizeof(chtest), 1, fp)) { - BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The input is an empty file: " << file; - fclose(fp); - return nullptr; - } - stl->stats.type = ascii; - for (size_t s = 0; s < sizeof(chtest); s++) { - if (chtest[s] > 127) { - stl->stats.type = binary; - break; - } - } - rewind(fp); - - uint32_t num_facets = 0; - - // Get the header and the number of facets in the .STL file. - // If the .STL file is binary, then do the following: - if (stl->stats.type == binary) { - // Test if the STL file has the right size. - if (((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) { - BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The file " << file << " has the wrong size."; - fclose(fp); - return nullptr; - } - num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET; - - // Read the header. - if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79) - stl->stats.header[80] = '\0'; - - // Read the int following the header. This should contain # of facets. - uint32_t header_num_facets; - bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0; + // Open the file in binary mode first. + FILE *fp = boost::nowide::fopen(file, "rb"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading"; + return nullptr; + } + // Find size of file. + fseek(fp, 0, SEEK_END); + long file_size = ftell(fp); + + // Check for binary or ASCII file. + fseek(fp, HEADER_SIZE, SEEK_SET); + unsigned char chtest[128]; + if (! fread(chtest, sizeof(chtest), 1, fp)) { + BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The input is an empty file: " << file; + fclose(fp); + return nullptr; + } + stl->stats.type = ascii; + for (size_t s = 0; s < sizeof(chtest); s++) { + if (chtest[s] > 127) { + stl->stats.type = binary; + break; + } + } + rewind(fp); + + uint32_t num_facets = 0; + + // Get the header and the number of facets in the .STL file. + // If the .STL file is binary, then do the following: + if (stl->stats.type == binary) { + // Test if the STL file has the right size. + if (((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) { + BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The file " << file << " has the wrong size."; + fclose(fp); + return nullptr; + } + num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET; + + // Read the header. + if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79) + stl->stats.header[80] = '\0'; + + // Read the int following the header. This should contain # of facets. + uint32_t header_num_facets; + bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0; #if BOOST_ENDIAN_BIG_BYTE - // Convert from little endian to big endian. - stl_internal_reverse_quads((char*)&header_num_facets, 4); + // Convert from little endian to big endian. + stl_internal_reverse_quads((char*)&header_num_facets, 4); #endif /* BOOST_ENDIAN_BIG_BYTE */ - if (! header_num_faces_read || num_facets != header_num_facets) - BOOST_LOG_TRIVIAL(info) << "stl_open_count_facets: Warning: File size doesn't match number of facets in the header: " << file; - } - // Otherwise, if the .STL file is ASCII, then do the following: - else - { - // Reopen the file in text mode (for getting correct newlines on Windows) - // fix to silence a warning about unused return value. - // obviously if it fails we have problems.... - fp = boost::nowide::freopen(file, "r", fp); - - // do another null check to be safe - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading"; - fclose(fp); - return nullptr; - } - - // Find the number of facets. - char linebuf[100]; - int num_lines = 1; - while (fgets(linebuf, 100, fp) != nullptr) { - // Don't count short lines. - if (strlen(linebuf) <= 4) - continue; - // Skip solid/endsolid lines as broken STL file generators may put several of them. - if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0) - continue; - ++ num_lines; - } - - rewind(fp); - - // Get the header. - int i = 0; - for (; i < 80 && (stl->stats.header[i] = getc(fp)) != '\n'; ++ i) ; - stl->stats.header[i] = '\0'; // Lose the '\n' - stl->stats.header[80] = '\0'; - - num_facets = num_lines / ASCII_LINES_PER_FACET; - } - - stl->stats.number_of_facets += num_facets; - stl->stats.original_num_facets = stl->stats.number_of_facets; - return fp; + if (! header_num_faces_read || num_facets != header_num_facets) + BOOST_LOG_TRIVIAL(info) << "stl_open_count_facets: Warning: File size doesn't match number of facets in the header: " << file; + } + // Otherwise, if the .STL file is ASCII, then do the following: + else + { + // Reopen the file in text mode (for getting correct newlines on Windows) + // fix to silence a warning about unused return value. + // obviously if it fails we have problems.... + fp = boost::nowide::freopen(file, "r", fp); + + // do another null check to be safe + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading"; + fclose(fp); + return nullptr; + } + + // Find the number of facets. + char linebuf[100]; + int num_lines = 1; + while (fgets(linebuf, 100, fp) != nullptr) { + // Don't count short lines. + if (strlen(linebuf) <= 4) + continue; + // Skip solid/endsolid lines as broken STL file generators may put several of them. + if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0) + continue; + ++ num_lines; + } + + rewind(fp); + + // Get the header. + int i = 0; + for (; i < 80 && (stl->stats.header[i] = getc(fp)) != '\n'; ++ i) ; + stl->stats.header[i] = '\0'; // Lose the '\n' + stl->stats.header[80] = '\0'; + + num_facets = num_lines / ASCII_LINES_PER_FACET; + } + + stl->stats.number_of_facets += num_facets; + stl->stats.original_num_facets = stl->stats.number_of_facets; + return fp; } /* Reads the contents of the file pointed to by fp into the stl structure, @@ -147,135 +147,135 @@ static FILE* stl_open_count_facets(stl_file *stl, const char *file) time running this for the stl and therefore we should reset our max and min stats. */ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) { - if (stl->stats.type == binary) - fseek(fp, HEADER_SIZE, SEEK_SET); - else - rewind(fp); - - char normal_buf[3][32]; - for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) { - stl_facet facet; - - if (stl->stats.type == binary) { - // Read a single facet from a binary .STL file. We assume little-endian architecture! - if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET) - return false; + if (stl->stats.type == binary) + fseek(fp, HEADER_SIZE, SEEK_SET); + else + rewind(fp); + + char normal_buf[3][32]; + for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) { + stl_facet facet; + + if (stl->stats.type == binary) { + // Read a single facet from a binary .STL file. We assume little-endian architecture! + if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET) + return false; #if BOOST_ENDIAN_BIG_BYTE - // Convert the loaded little endian data to big endian. - stl_internal_reverse_quads((char*)&facet, 48); + // Convert the loaded little endian data to big endian. + stl_internal_reverse_quads((char*)&facet, 48); #endif /* BOOST_ENDIAN_BIG_BYTE */ - } else { - // Read a single facet from an ASCII .STL file - // skip solid/endsolid - // (in this order, otherwise it won't work when they are paired in the middle of a file) - fscanf(fp, " endsolid%*[^\n]\n"); - fscanf(fp, " solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") - // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs. - int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]); - assert(res_normal == 3); - int res_outer_loop = fscanf(fp, " outer loop"); - assert(res_outer_loop == 0); - int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); - assert(res_vertex1 == 3); - int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); - assert(res_vertex2 == 3); - // Trailing whitespace is there to eat all whitespaces and empty lines up to the next non-whitespace. - int res_vertex3 = fscanf(fp, " vertex %f %f %f ", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); - assert(res_vertex3 == 3); - // Some G-code generators tend to produce text after "endloop" and "endfacet". Just ignore it. - char buf[2048]; - fgets(buf, 2047, fp); - bool endloop_ok = strncmp(buf, "endloop", 7) == 0 && (buf[7] == '\r' || buf[7] == '\n' || buf[7] == ' ' || buf[7] == '\t'); - assert(endloop_ok); - // Skip the trailing whitespaces and empty lines. - fscanf(fp, " "); - fgets(buf, 2047, fp); - bool endfacet_ok = strncmp(buf, "endfacet", 8) == 0 && (buf[8] == '\r' || buf[8] == '\n' || buf[8] == ' ' || buf[8] == '\t'); - assert(endfacet_ok); - if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || ! endloop_ok || ! endfacet_ok) { - BOOST_LOG_TRIVIAL(error) << "Something is syntactically very wrong with this ASCII STL! "; - return false; - } - - // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition. - if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 || - sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 || - sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) { - // Normal was mangled. Maybe denormals or "not a number" were stored? - // Just reset the normal and silently ignore it. - memset(&facet.normal, 0, sizeof(facet.normal)); - } - } + } else { + // Read a single facet from an ASCII .STL file + // skip solid/endsolid + // (in this order, otherwise it won't work when they are paired in the middle of a file) + fscanf(fp, " endsolid%*[^\n]\n"); + fscanf(fp, " solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") + // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs. + int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]); + assert(res_normal == 3); + int res_outer_loop = fscanf(fp, " outer loop"); + assert(res_outer_loop == 0); + int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); + assert(res_vertex1 == 3); + int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); + assert(res_vertex2 == 3); + // Trailing whitespace is there to eat all whitespaces and empty lines up to the next non-whitespace. + int res_vertex3 = fscanf(fp, " vertex %f %f %f ", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); + assert(res_vertex3 == 3); + // Some G-code generators tend to produce text after "endloop" and "endfacet". Just ignore it. + char buf[2048]; + fgets(buf, 2047, fp); + bool endloop_ok = strncmp(buf, "endloop", 7) == 0 && (buf[7] == '\r' || buf[7] == '\n' || buf[7] == ' ' || buf[7] == '\t'); + assert(endloop_ok); + // Skip the trailing whitespaces and empty lines. + fscanf(fp, " "); + fgets(buf, 2047, fp); + bool endfacet_ok = strncmp(buf, "endfacet", 8) == 0 && (buf[8] == '\r' || buf[8] == '\n' || buf[8] == ' ' || buf[8] == '\t'); + assert(endfacet_ok); + if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || ! endloop_ok || ! endfacet_ok) { + BOOST_LOG_TRIVIAL(error) << "Something is syntactically very wrong with this ASCII STL! "; + return false; + } + + // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition. + if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 || + sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 || + sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) { + // Normal was mangled. Maybe denormals or "not a number" were stored? + // Just reset the normal and silently ignore it. + memset(&facet.normal, 0, sizeof(facet.normal)); + } + } #if 0 - // Report close to zero vertex coordinates. Due to the nature of the floating point numbers, - // close to zero values may be represented with singificantly higher precision than the rest of the vertices. - // It may be worth to round these numbers to zero during loading to reduce the number of errors reported - // during the STL import. - for (size_t j = 0; j < 3; ++ j) { - if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f) - printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0)); - if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f) - printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1)); - if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f) - printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2)); - } + // Report close to zero vertex coordinates. Due to the nature of the floating point numbers, + // close to zero values may be represented with singificantly higher precision than the rest of the vertices. + // It may be worth to round these numbers to zero during loading to reduce the number of errors reported + // during the STL import. + for (size_t j = 0; j < 3; ++ j) { + if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f) + printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0)); + if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f) + printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1)); + if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f) + printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2)); + } #endif - // Write the facet into memory. - stl->facet_start[i] = facet; - stl_facet_stats(stl, facet, first); - } - - stl->stats.size = stl->stats.max - stl->stats.min; - stl->stats.bounding_diameter = stl->stats.size.norm(); - return true; + // Write the facet into memory. + stl->facet_start[i] = facet; + stl_facet_stats(stl, facet, first); + } + + stl->stats.size = stl->stats.max - stl->stats.min; + stl->stats.bounding_diameter = stl->stats.size.norm(); + return true; } bool stl_open(stl_file *stl, const char *file) { Slic3r::CNumericLocalesSetter locales_setter; - stl->clear(); - FILE *fp = stl_open_count_facets(stl, file); - if (fp == nullptr) - return false; - stl_allocate(stl); - bool result = stl_read(stl, fp, 0, true); - fclose(fp); - return result; + stl->clear(); + FILE *fp = stl_open_count_facets(stl, file); + if (fp == nullptr) + return false; + stl_allocate(stl); + bool result = stl_read(stl, fp, 0, true); + fclose(fp); + return result; } -void stl_allocate(stl_file *stl) +void stl_allocate(stl_file *stl) { - // Allocate memory for the entire .STL file. - stl->facet_start.assign(stl->stats.number_of_facets, stl_facet()); - // Allocate memory for the neighbors list. - stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors()); + // Allocate memory for the entire .STL file. + stl->facet_start.assign(stl->stats.number_of_facets, stl_facet()); + // Allocate memory for the neighbors list. + stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors()); } -void stl_reallocate(stl_file *stl) +void stl_reallocate(stl_file *stl) { - stl->facet_start.resize(stl->stats.number_of_facets); - stl->neighbors_start.resize(stl->stats.number_of_facets); + stl->facet_start.resize(stl->stats.number_of_facets); + stl->neighbors_start.resize(stl->stats.number_of_facets); } void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first) { - // While we are going through all of the facets, let's find the - // maximum and minimum values for x, y, and z - - if (first) { - // Initialize the max and min values the first time through - stl->stats.min = facet.vertex[0]; - stl->stats.max = facet.vertex[0]; - stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs(); - stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2))); - first = false; - } - - // Now find the max and min values. - for (size_t i = 0; i < 3; ++ i) { - stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]); - stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]); - } + // While we are going through all of the facets, let's find the + // maximum and minimum values for x, y, and z + + if (first) { + // Initialize the max and min values the first time through + stl->stats.min = facet.vertex[0]; + stl->stats.max = facet.vertex[0]; + stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs(); + stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2))); + first = false; + } + + // Now find the max and min values. + for (size_t i = 0; i < 3; ++ i) { + stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]); + stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]); + } } diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 190a5056c59..fdc171fcfe4 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -31,369 +31,369 @@ void stl_verify_neighbors(stl_file *stl) { - stl->stats.backwards_edges = 0; - - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - for (int j = 0; j < 3; ++ j) { - struct stl_edge { - stl_vertex p1; - stl_vertex p2; - int facet_number; - }; - stl_edge edge_a; - edge_a.p1 = stl->facet_start[i].vertex[j]; - edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3]; - int neighbor = stl->neighbors_start[i].neighbor[j]; - if (neighbor == -1) - continue; // this edge has no neighbor... Continue. - int vnot = stl->neighbors_start[i].which_vertex_not[j]; - stl_edge edge_b; - if (vnot < 3) { - edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; - edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; - } else { - stl->stats.backwards_edges += 1; - edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; - edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; - } - if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) { - // These edges should match but they don't. Print results. - BOOST_LOG_TRIVIAL(info) << "edge " << j << " of facet " << i << " doesn't match edge " << (vnot + 1) << " of facet " << neighbor; - stl_write_facet(stl, (char*)"first facet", i); - stl_write_facet(stl, (char*)"second facet", neighbor); - } - } - } + stl->stats.backwards_edges = 0; + + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + for (int j = 0; j < 3; ++ j) { + struct stl_edge { + stl_vertex p1; + stl_vertex p2; + int facet_number; + }; + stl_edge edge_a; + edge_a.p1 = stl->facet_start[i].vertex[j]; + edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3]; + int neighbor = stl->neighbors_start[i].neighbor[j]; + if (neighbor == -1) + continue; // this edge has no neighbor... Continue. + int vnot = stl->neighbors_start[i].which_vertex_not[j]; + stl_edge edge_b; + if (vnot < 3) { + edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; + edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; + } else { + stl->stats.backwards_edges += 1; + edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; + edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; + } + if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) { + // These edges should match but they don't. Print results. + BOOST_LOG_TRIVIAL(info) << "edge " << j << " of facet " << i << " doesn't match edge " << (vnot + 1) << " of facet " << neighbor; + stl_write_facet(stl, (char*)"first facet", i); + stl_write_facet(stl, (char*)"second facet", neighbor); + } + } + } } void stl_translate(stl_file *stl, float x, float y, float z) { - stl_vertex new_min(x, y, z); - stl_vertex shift = new_min - stl->stats.min; - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - stl->facet_start[i].vertex[j] += shift; - stl->stats.min = new_min; - stl->stats.max += shift; + stl_vertex new_min(x, y, z); + stl_vertex shift = new_min - stl->stats.min; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j] += shift; + stl->stats.min = new_min; + stl->stats.max += shift; } /* Translates the stl by x,y,z, relatively from wherever it is currently */ void stl_translate_relative(stl_file *stl, float x, float y, float z) { - stl_vertex shift(x, y, z); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - stl->facet_start[i].vertex[j] += shift; - stl->stats.min += shift; - stl->stats.max += shift; + stl_vertex shift(x, y, z); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j] += shift; + stl->stats.min += shift; + stl->stats.max += shift; } void stl_scale_versor(stl_file *stl, const stl_vertex &versor) { - // Scale extents. - auto s = versor.array(); - stl->stats.min.array() *= s; - stl->stats.max.array() *= s; - // Scale size. - stl->stats.size.array() *= s; - // Scale volume. - if (stl->stats.volume > 0.0) - stl->stats.volume *= versor(0) * versor(1) * versor(2); - // Scale the mesh. - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - stl->facet_start[i].vertex[j].array() *= s; + // Scale extents. + auto s = versor.array(); + stl->stats.min.array() *= s; + stl->stats.max.array() *= s; + // Scale size. + stl->stats.size.array() *= s; + // Scale volume. + if (stl->stats.volume > 0.0) + stl->stats.volume *= versor(0) * versor(1) * versor(2); + // Scale the mesh. + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j].array() *= s; } -static void calculate_normals(stl_file *stl) +static void calculate_normals(stl_file *stl) { - stl_normal normal; - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - stl_calculate_normal(normal, &stl->facet_start[i]); - stl_normalize_vector(normal); - stl->facet_start[i].normal = normal; - } + stl_normal normal; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + stl_calculate_normal(normal, &stl->facet_start[i]); + stl_normalize_vector(normal); + stl->facet_start[i].normal = normal; + } } static inline void rotate_point_2d(float &x, float &y, const double c, const double s) { - double xold = x; - double yold = y; - x = float(c * xold - s * yold); - y = float(s * xold + c * yold); + double xold = x; + double yold = y; + x = float(c * xold - s * yold); + y = float(s * xold + c * yold); } void stl_rotate_x(stl_file *stl, float angle) { - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - rotate_point_2d(stl->facet_start[i].vertex[j](1), stl->facet_start[i].vertex[j](2), c, s); - stl_get_size(stl); - calculate_normals(stl); + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + rotate_point_2d(stl->facet_start[i].vertex[j](1), stl->facet_start[i].vertex[j](2), c, s); + stl_get_size(stl); + calculate_normals(stl); } void stl_rotate_y(stl_file *stl, float angle) { - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - rotate_point_2d(stl->facet_start[i].vertex[j](2), stl->facet_start[i].vertex[j](0), c, s); - stl_get_size(stl); - calculate_normals(stl); + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + rotate_point_2d(stl->facet_start[i].vertex[j](2), stl->facet_start[i].vertex[j](0), c, s); + stl_get_size(stl); + calculate_normals(stl); } void stl_rotate_z(stl_file *stl, float angle) { - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - rotate_point_2d(stl->facet_start[i].vertex[j](0), stl->facet_start[i].vertex[j](1), c, s); - stl_get_size(stl); - calculate_normals(stl); + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + rotate_point_2d(stl->facet_start[i].vertex[j](0), stl->facet_start[i].vertex[j](1), c, s); + stl_get_size(stl); + calculate_normals(stl); } void its_rotate_x(indexed_triangle_set &its, float angle) { - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - for (stl_vertex &v : its.vertices) - rotate_point_2d(v(1), v(2), c, s); + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (stl_vertex &v : its.vertices) + rotate_point_2d(v(1), v(2), c, s); } void its_rotate_y(indexed_triangle_set& its, float angle) { - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - for (stl_vertex& v : its.vertices) - rotate_point_2d(v(2), v(0), c, s); + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (stl_vertex& v : its.vertices) + rotate_point_2d(v(2), v(0), c, s); } void its_rotate_z(indexed_triangle_set& its, float angle) { - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - for (stl_vertex& v : its.vertices) - rotate_point_2d(v(0), v(1), c, s); + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (stl_vertex& v : its.vertices) + rotate_point_2d(v(0), v(1), c, s); } void stl_get_size(stl_file *stl) { - if (stl->stats.number_of_facets == 0) - return; - stl->stats.min = stl->facet_start[0].vertex[0]; - stl->stats.max = stl->stats.min; - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - const stl_facet &face = stl->facet_start[i]; - for (int j = 0; j < 3; ++ j) { - stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]); - stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]); - } - } - stl->stats.size = stl->stats.max - stl->stats.min; - stl->stats.bounding_diameter = stl->stats.size.norm(); + if (stl->stats.number_of_facets == 0) + return; + stl->stats.min = stl->facet_start[0].vertex[0]; + stl->stats.max = stl->stats.min; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + const stl_facet &face = stl->facet_start[i]; + for (int j = 0; j < 3; ++ j) { + stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]); + stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]); + } + } + stl->stats.size = stl->stats.max - stl->stats.min; + stl->stats.bounding_diameter = stl->stats.size.norm(); } void stl_mirror_xy(stl_file *stl) { - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - stl->facet_start[i].vertex[j](2) *= -1.0; - float temp_size = stl->stats.min(2); - stl->stats.min(2) = stl->stats.max(2); - stl->stats.max(2) = temp_size; - stl->stats.min(2) *= -1.0; - stl->stats.max(2) *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j](2) *= -1.0; + float temp_size = stl->stats.min(2); + stl->stats.min(2) = stl->stats.max(2); + stl->stats.max(2) = temp_size; + stl->stats.min(2) *= -1.0; + stl->stats.max(2) *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ } void stl_mirror_yz(stl_file *stl) { - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; j++) - stl->facet_start[i].vertex[j](0) *= -1.0; - float temp_size = stl->stats.min(0); - stl->stats.min(0) = stl->stats.max(0); - stl->stats.max(0) = temp_size; - stl->stats.min(0) *= -1.0; - stl->stats.max(0) *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; j++) + stl->facet_start[i].vertex[j](0) *= -1.0; + float temp_size = stl->stats.min(0); + stl->stats.min(0) = stl->stats.max(0); + stl->stats.max(0) = temp_size; + stl->stats.min(0) *= -1.0; + stl->stats.max(0) *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ } void stl_mirror_xz(stl_file *stl) { - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - stl->facet_start[i].vertex[j](1) *= -1.0; - float temp_size = stl->stats.min(1); - stl->stats.min(1) = stl->stats.max(1); - stl->stats.max(1) = temp_size; - stl->stats.min(1) *= -1.0; - stl->stats.max(1) *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j](1) *= -1.0; + float temp_size = stl->stats.min(1); + stl->stats.min(1) = stl->stats.max(1); + stl->stats.max(1) = temp_size; + stl->stats.min(1) *= -1.0; + stl->stats.max(1) *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats } static float get_area(stl_facet *facet) { - /* cast to double before calculating cross product because large coordinates - can result in overflowing product - (bad area is responsible for bad volume and bad facets reversal) */ - double cross[3][3]; - for (int i = 0; i < 3; i++) { - cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) - - ((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1))); - cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) - - ((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2))); - cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) - - ((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0))); - } - - stl_normal sum; - sum(0) = cross[0][0] + cross[1][0] + cross[2][0]; - sum(1) = cross[0][1] + cross[1][1] + cross[2][1]; - sum(2) = cross[0][2] + cross[1][2] + cross[2][2]; - - // This should already be done. But just in case, let's do it again. - //FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy. - stl_normal n; - stl_calculate_normal(n, facet); - stl_normalize_vector(n); - return 0.5f * n.dot(sum); + /* cast to double before calculating cross product because large coordinates + can result in overflowing product + (bad area is responsible for bad volume and bad facets reversal) */ + double cross[3][3]; + for (int i = 0; i < 3; i++) { + cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) - + ((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1))); + cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) - + ((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2))); + cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) - + ((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0))); + } + + stl_normal sum; + sum(0) = cross[0][0] + cross[1][0] + cross[2][0]; + sum(1) = cross[0][1] + cross[1][1] + cross[2][1]; + sum(2) = cross[0][2] + cross[1][2] + cross[2][2]; + + // This should already be done. But just in case, let's do it again. + //FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy. + stl_normal n; + stl_calculate_normal(n, facet); + stl_normalize_vector(n); + return 0.5f * n.dot(sum); } static float get_volume(stl_file *stl) { - // Choose a point, any point as the reference. - stl_vertex p0 = stl->facet_start[0].vertex[0]; - float volume = 0.f; - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - // Do dot product to get distance from point to plane. - float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0); - float area = get_area(&stl->facet_start[i]); - volume += (area * height) / 3.0f; - } - return volume; + // Choose a point, any point as the reference. + stl_vertex p0 = stl->facet_start[0].vertex[0]; + float volume = 0.f; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + // Do dot product to get distance from point to plane. + float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0); + float area = get_area(&stl->facet_start[i]); + volume += (area * height) / 3.0f; + } + return volume; } void stl_calculate_volume(stl_file *stl) { - stl->stats.volume = get_volume(stl); - if (stl->stats.volume < 0.0) { - stl_reverse_all_facets(stl); - stl->stats.volume = -stl->stats.volume; - } + stl->stats.volume = get_volume(stl); + if (stl->stats.volume < 0.0) { + stl_reverse_all_facets(stl); + stl->stats.volume = -stl->stats.volume; + } } void stl_repair( - stl_file *stl, - bool fixall_flag, - bool exact_flag, - bool tolerance_flag, - float tolerance, - bool increment_flag, - float increment, - bool nearby_flag, - int iterations, - bool remove_unconnected_flag, - bool fill_holes_flag, - bool normal_directions_flag, - bool normal_values_flag, - bool reverse_all_flag, - bool verbose_flag) + stl_file *stl, + bool fixall_flag, + bool exact_flag, + bool tolerance_flag, + float tolerance, + bool increment_flag, + float increment, + bool nearby_flag, + int iterations, + bool remove_unconnected_flag, + bool fill_holes_flag, + bool normal_directions_flag, + bool normal_values_flag, + bool reverse_all_flag, + bool verbose_flag) { - if (exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag || fill_holes_flag || normal_directions_flag) { - if (verbose_flag) - printf("Checking exact...\n"); - exact_flag = true; - stl_check_facets_exact(stl); - stl->stats.facets_w_1_bad_edge = (stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge); - stl->stats.facets_w_2_bad_edge = (stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge); - stl->stats.facets_w_3_bad_edge = (stl->stats.number_of_facets - stl->stats.connected_facets_1_edge); - } - - if (nearby_flag || fixall_flag) { - if (!tolerance_flag) - tolerance = stl->stats.shortest_edge; - if (!increment_flag) - increment = stl->stats.bounding_diameter / 10000.0; - } - - if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { - int last_edges_fixed = 0; - for (int i = 0; i < iterations; ++ i) { - if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { - if (verbose_flag) - printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations); - stl_check_facets_nearby(stl, tolerance); - if (verbose_flag) - printf(" Fixed %d edges.\n", stl->stats.edges_fixed - last_edges_fixed); - last_edges_fixed = stl->stats.edges_fixed; - tolerance += increment; - } else { - if (verbose_flag) - printf("All facets connected. No further nearby check necessary.\n"); - break; - } - } - } else if (verbose_flag) - printf("All facets connected. No nearby check necessary.\n"); - - if (remove_unconnected_flag || fixall_flag || fill_holes_flag) { - if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { - if (verbose_flag) - printf("Removing unconnected facets...\n"); - stl_remove_unconnected_facets(stl); - } else if (verbose_flag) - printf("No unconnected need to be removed.\n"); - } - - if (fill_holes_flag || fixall_flag) { - if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { - if (verbose_flag) - printf("Filling holes...\n"); - stl_fill_holes(stl); - } else if (verbose_flag) - printf("No holes need to be filled.\n"); - } - - if (reverse_all_flag) { - if (verbose_flag) - printf("Reversing all facets...\n"); - stl_reverse_all_facets(stl); - } - - if (normal_directions_flag || fixall_flag) { - if (verbose_flag) - printf("Checking normal directions...\n"); - stl_fix_normal_directions(stl); - } - - if (normal_values_flag || fixall_flag) { - if (verbose_flag) - printf("Checking normal values...\n"); - stl_fix_normal_values(stl); - } - - // Always calculate the volume. It shouldn't take too long. - if (verbose_flag) - printf("Calculating volume...\n"); - stl_calculate_volume(stl); - - if (exact_flag) { - if (verbose_flag) - printf("Verifying neighbors...\n"); - stl_verify_neighbors(stl); - } + if (exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag || fill_holes_flag || normal_directions_flag) { + if (verbose_flag) + printf("Checking exact...\n"); + exact_flag = true; + stl_check_facets_exact(stl); + stl->stats.facets_w_1_bad_edge = (stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge); + stl->stats.facets_w_2_bad_edge = (stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge); + stl->stats.facets_w_3_bad_edge = (stl->stats.number_of_facets - stl->stats.connected_facets_1_edge); + } + + if (nearby_flag || fixall_flag) { + if (!tolerance_flag) + tolerance = stl->stats.shortest_edge; + if (!increment_flag) + increment = stl->stats.bounding_diameter / 10000.0; + } + + if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { + int last_edges_fixed = 0; + for (int i = 0; i < iterations; ++ i) { + if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { + if (verbose_flag) + printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations); + stl_check_facets_nearby(stl, tolerance); + if (verbose_flag) + printf(" Fixed %d edges.\n", stl->stats.edges_fixed - last_edges_fixed); + last_edges_fixed = stl->stats.edges_fixed; + tolerance += increment; + } else { + if (verbose_flag) + printf("All facets connected. No further nearby check necessary.\n"); + break; + } + } + } else if (verbose_flag) + printf("All facets connected. No nearby check necessary.\n"); + + if (remove_unconnected_flag || fixall_flag || fill_holes_flag) { + if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { + if (verbose_flag) + printf("Removing unconnected facets...\n"); + stl_remove_unconnected_facets(stl); + } else if (verbose_flag) + printf("No unconnected need to be removed.\n"); + } + + if (fill_holes_flag || fixall_flag) { + if (stl->stats.connected_facets_3_edge < int(stl->stats.number_of_facets)) { + if (verbose_flag) + printf("Filling holes...\n"); + stl_fill_holes(stl); + } else if (verbose_flag) + printf("No holes need to be filled.\n"); + } + + if (reverse_all_flag) { + if (verbose_flag) + printf("Reversing all facets...\n"); + stl_reverse_all_facets(stl); + } + + if (normal_directions_flag || fixall_flag) { + if (verbose_flag) + printf("Checking normal directions...\n"); + stl_fix_normal_directions(stl); + } + + if (normal_values_flag || fixall_flag) { + if (verbose_flag) + printf("Checking normal values...\n"); + stl_fix_normal_values(stl); + } + + // Always calculate the volume. It shouldn't take too long. + if (verbose_flag) + printf("Calculating volume...\n"); + stl_calculate_volume(stl); + + if (exact_flag) { + if (verbose_flag) + printf("Verifying neighbors...\n"); + stl_verify_neighbors(stl); + } } diff --git a/src/agg/AUTHORS b/src/agg/AUTHORS index 2bb6518ec0f..5e4c0723f65 100644 --- a/src/agg/AUTHORS +++ b/src/agg/AUTHORS @@ -1,2 +1,2 @@ Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) +Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) diff --git a/src/agg/agg_array.h b/src/agg/agg_array.h index 8d56683840d..a0b94408d42 100644 --- a/src/agg/agg_array.h +++ b/src/agg/agg_array.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -27,7 +27,7 @@ namespace agg { public: typedef T value_type; - pod_array_adaptor(T* array, unsigned size) : + pod_array_adaptor(T* array, unsigned size) : m_array(array), m_size(size) {} unsigned size() const { return m_size; } @@ -88,7 +88,7 @@ namespace agg void add(const T& v) { m_array[m_size++] = v; } void push_back(const T& v) { m_array[m_size++] = v; } void inc_size(unsigned size) { m_size += size; } - + unsigned size() const { return m_size; } const T& operator [] (unsigned i) const { return m_array[i]; } T& operator [] (unsigned i) { return m_array[i]; } @@ -112,14 +112,14 @@ namespace agg ~pod_array() { pod_allocator::deallocate(m_array, m_size); } pod_array() : m_array(0), m_size(0) {} - pod_array(unsigned size) : - m_array(pod_allocator::allocate(size)), - m_size(size) + pod_array(unsigned size) : + m_array(pod_allocator::allocate(size)), + m_size(size) {} - pod_array(const self_type& v) : - m_array(pod_allocator::allocate(v.m_size)), - m_size(v.m_size) + pod_array(const self_type& v) : + m_array(pod_allocator::allocate(v.m_size)), + m_size(v.m_size) { memcpy(m_array, v.m_array, sizeof(T) * m_size); } @@ -176,8 +176,8 @@ namespace agg void capacity(unsigned cap, unsigned extra_tail=0); unsigned capacity() const { return m_capacity; } - // Allocate n elements. All data is lost, - // but elements can be accessed in range 0...size-1. + // Allocate n elements. All data is lost, + // but elements can be accessed in range 0...size-1. void allocate(unsigned size, unsigned extra_tail=0); // Resize keeping the content. @@ -216,7 +216,7 @@ namespace agg }; //------------------------------------------------------------------------ - template + template void pod_vector::capacity(unsigned cap, unsigned extra_tail) { m_size = 0; @@ -229,7 +229,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void pod_vector::allocate(unsigned size, unsigned extra_tail) { capacity(size, extra_tail); @@ -238,7 +238,7 @@ namespace agg //------------------------------------------------------------------------ - template + template void pod_vector::resize(unsigned new_size) { if(new_size > m_size) @@ -259,8 +259,8 @@ namespace agg //------------------------------------------------------------------------ template pod_vector::pod_vector(unsigned cap, unsigned extra_tail) : - m_size(0), - m_capacity(cap + extra_tail), + m_size(0), + m_capacity(cap + extra_tail), m_array(pod_allocator::allocate(m_capacity)) {} //------------------------------------------------------------------------ @@ -273,7 +273,7 @@ namespace agg } //------------------------------------------------------------------------ - template const pod_vector& + template const pod_vector& pod_vector::operator = (const pod_vector&v) { allocate(v.m_size); @@ -283,12 +283,12 @@ namespace agg //------------------------------------------------------------------------ template void pod_vector::serialize(int8u* ptr) const - { - if(m_size) memcpy(ptr, m_array, m_size * sizeof(T)); + { + if(m_size) memcpy(ptr, m_array, m_size * sizeof(T)); } //------------------------------------------------------------------------ - template + template void pod_vector::deserialize(const int8u* data, unsigned byte_size) { byte_size /= sizeof(T); @@ -297,10 +297,10 @@ namespace agg } //------------------------------------------------------------------------ - template + template void pod_vector::insert_at(unsigned pos, const T& val) { - if(pos >= m_size) + if(pos >= m_size) { m_array[m_size] = val; } @@ -314,12 +314,12 @@ namespace agg //---------------------------------------------------------------pod_bvector // A simple class template to store Plain Old Data, similar to std::deque - // It doesn't reallocate memory but instead, uses blocks of data of size - // of (1 << S), that is, power of two. The data is NOT contiguous in memory, + // It doesn't reallocate memory but instead, uses blocks of data of size + // of (1 << S), that is, power of two. The data is NOT contiguous in memory, // so the only valid access method is operator [] or curr(), prev(), next() - // - // There reallocs occure only when the pool of pointers to blocks needs - // to be extended (it happens very rarely). You can control the value + // + // There reallocs occure only when the pool of pointers to blocks needs + // to be extended (it happens very rarely). You can control the value // of increment to reallocate the pointer buffer. See the second constructor. // By default, the incremeent value equals (1 << S), i.e., the block size. //------------------------------------------------------------------------ @@ -327,7 +327,7 @@ namespace agg { public: enum block_scale_e - { + { block_shift = S, block_size = 1 << block_shift, block_mask = block_size - 1 @@ -389,17 +389,17 @@ namespace agg } const T& at(unsigned i) const - { + { return m_blocks[i >> block_shift][i & block_mask]; } - T& at(unsigned i) - { + T& at(unsigned i) + { return m_blocks[i >> block_shift][i & block_mask]; } T value_at(unsigned i) const - { + { return m_blocks[i >> block_shift][i & block_mask]; } @@ -446,10 +446,10 @@ namespace agg unsigned byte_size() const; void serialize(int8u* ptr) const; void deserialize(const int8u* data, unsigned byte_size); - void deserialize(unsigned start, const T& empty_val, + void deserialize(unsigned start, const T& empty_val, const int8u* data, unsigned byte_size); - template + template void deserialize(ByteAccessor data) { remove_all(); @@ -527,7 +527,7 @@ namespace agg //------------------------------------------------------------------------ - template + template void pod_bvector::free_tail(unsigned size) { if(size < m_size) @@ -560,7 +560,7 @@ namespace agg //------------------------------------------------------------------------ - template + template pod_bvector::pod_bvector(unsigned block_ptr_inc) : m_size(0), m_num_blocks(0), @@ -572,13 +572,13 @@ namespace agg //------------------------------------------------------------------------ - template + template pod_bvector::pod_bvector(const pod_bvector& v) : m_size(v.m_size), m_num_blocks(v.m_num_blocks), m_max_blocks(v.m_max_blocks), - m_blocks(v.m_max_blocks ? - pod_allocator::allocate(v.m_max_blocks) : + m_blocks(v.m_max_blocks ? + pod_allocator::allocate(v.m_max_blocks) : 0), m_block_ptr_inc(v.m_block_ptr_inc) { @@ -592,8 +592,8 @@ namespace agg //------------------------------------------------------------------------ - template - const pod_bvector& + template + const pod_bvector& pod_bvector::operator = (const pod_bvector& v) { unsigned i; @@ -614,14 +614,14 @@ namespace agg template void pod_bvector::allocate_block(unsigned nb) { - if(nb >= m_max_blocks) + if(nb >= m_max_blocks) { T** new_blocks = pod_allocator::allocate(m_max_blocks + m_block_ptr_inc); if(m_blocks) { - memcpy(new_blocks, - m_blocks, + memcpy(new_blocks, + m_blocks, m_num_blocks * sizeof(T*)); pod_allocator::deallocate(m_blocks, m_max_blocks); @@ -650,7 +650,7 @@ namespace agg //------------------------------------------------------------------------ - template + template inline void pod_bvector::add(const T& val) { *data_ptr() = val; @@ -659,7 +659,7 @@ namespace agg //------------------------------------------------------------------------ - template + template inline void pod_bvector::remove_last() { if(m_size) --m_size; @@ -667,7 +667,7 @@ namespace agg //------------------------------------------------------------------------ - template + template void pod_bvector::modify_last(const T& val) { remove_last(); @@ -676,7 +676,7 @@ namespace agg //------------------------------------------------------------------------ - template + template int pod_bvector::allocate_continuous_block(unsigned num_elements) { if(num_elements < block_size) @@ -706,7 +706,7 @@ namespace agg //------------------------------------------------------------------------ - template + template unsigned pod_bvector::byte_size() const { return m_size * sizeof(T); @@ -714,7 +714,7 @@ namespace agg //------------------------------------------------------------------------ - template + template void pod_bvector::serialize(int8u* ptr) const { unsigned i; @@ -726,7 +726,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void pod_bvector::deserialize(const int8u* data, unsigned byte_size) { remove_all(); @@ -743,8 +743,8 @@ namespace agg // Replace or add a number of elements starting from "start" position //------------------------------------------------------------------------ - template - void pod_bvector::deserialize(unsigned start, const T& empty_val, + template + void pod_bvector::deserialize(unsigned start, const T& empty_val, const int8u* data, unsigned byte_size) { while(m_size < start) @@ -772,11 +772,11 @@ namespace agg //---------------------------------------------------------block_allocator // Allocator for arbitrary POD data. Most usable in different cache - // systems for efficient memory allocations. + // systems for efficient memory allocations. // Memory is allocated with blocks of fixed size ("block_size" in // the constructor). If required size exceeds the block size the allocator // creates a new block of the required size. However, the most efficient - // use is when the average reqired size is much less than the block size. + // use is when the average reqired size is much less than the block size. //------------------------------------------------------------------------ class block_allocator { @@ -821,7 +821,7 @@ namespace agg m_rest(0) { } - + int8u* allocate(unsigned size, unsigned alignment=1) { @@ -831,7 +831,7 @@ namespace agg int8u* ptr = m_buf_ptr; if(alignment > 1) { - unsigned align = + unsigned align = (alignment - unsigned((size_t)ptr) % alignment) % alignment; size += align; @@ -858,15 +858,15 @@ namespace agg void allocate_block(unsigned size) { if(size < m_block_size) size = m_block_size; - if(m_num_blocks >= m_max_blocks) + if(m_num_blocks >= m_max_blocks) { - block_type* new_blocks = + block_type* new_blocks = pod_allocator::allocate(m_max_blocks + m_block_ptr_inc); if(m_blocks) { - memcpy(new_blocks, - m_blocks, + memcpy(new_blocks, + m_blocks, m_num_blocks * sizeof(block_type)); pod_allocator::deallocate(m_blocks, m_max_blocks); } @@ -875,7 +875,7 @@ namespace agg } m_blocks[m_num_blocks].size = size; - m_blocks[m_num_blocks].data = + m_blocks[m_num_blocks].data = m_buf_ptr = pod_allocator::allocate(size); @@ -905,7 +905,7 @@ namespace agg quick_sort_threshold = 9 }; - + //-----------------------------------------------------------swap_elements template inline void swap_elements(T& a, T& b) { @@ -925,7 +925,7 @@ namespace agg typename Array::value_type* e2; int stack[80]; - int* top = stack; + int* top = stack; int limit = arr.size(); int base = 0; @@ -946,16 +946,16 @@ namespace agg i = base + 1; j = limit - 1; - // now ensure that *i <= *base <= *j - e1 = &(arr[j]); + // now ensure that *i <= *base <= *j + e1 = &(arr[j]); e2 = &(arr[i]); if(less(*e1, *e2)) swap_elements(*e1, *e2); - e1 = &(arr[base]); + e1 = &(arr[base]); e2 = &(arr[i]); if(less(*e1, *e2)) swap_elements(*e1, *e2); - e1 = &(arr[j]); + e1 = &(arr[j]); e2 = &(arr[base]); if(less(*e1, *e2)) swap_elements(*e1, *e2); @@ -1024,7 +1024,7 @@ namespace agg //------------------------------------------------------remove_duplicates - // Remove duplicates from a sorted array. It doesn't cut the + // Remove duplicates from a sorted array. It doesn't cut the // tail of the array, it just returns the number of remaining elements. //----------------------------------------------------------------------- template @@ -1070,7 +1070,7 @@ namespace agg while(end - beg > 1) { unsigned mid = (end + beg) >> 1; - if(less(val, arr[mid])) end = mid; + if(less(val, arr[mid])) end = mid; else beg = mid; } diff --git a/src/agg/agg_basics.h b/src/agg/agg_basics.h index 273850ba1b6..06b8d249dcd 100644 --- a/src/agg/agg_basics.h +++ b/src/agg/agg_basics.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -25,12 +25,12 @@ #else namespace agg { - // The policy of all AGG containers and memory allocation strategy + // The policy of all AGG containers and memory allocation strategy // in general is that no allocated data requires explicit construction. // It means that the allocator can be really simple; you can even - // replace new/delete to malloc/free. The constructors and destructors - // won't be called in this case, however everything will remain working. - // The second argument of deallocate() is the size of the allocated + // replace new/delete to malloc/free. The constructors and destructors + // won't be called in this case, however everything will remain working. + // The second argument of deallocate() is the size of the allocated // block. You can use this information if you wish. //------------------------------------------------------------pod_allocator template struct pod_allocator @@ -40,8 +40,8 @@ namespace agg }; // Single object allocator. It's also can be replaced with your custom - // allocator. The difference is that it can only allocate a single - // object and the constructor and destructor must be called. + // allocator. The difference is that it can only allocate a single + // object and the constructor and destructor must be called. // In AGG there is no need to allocate an array of objects with // calling their constructors (only single ones). So that, if you // replace these new/delete to malloc/free make sure that the in-place @@ -238,23 +238,23 @@ namespace agg enum cover_scale_e { cover_shift = 8, //----cover_shift - cover_size = 1 << cover_shift, //----cover_size - cover_mask = cover_size - 1, //----cover_mask - cover_none = 0, //----cover_none - cover_full = cover_mask //----cover_full + cover_size = 1 << cover_shift, //----cover_size + cover_mask = cover_size - 1, //----cover_mask + cover_none = 0, //----cover_none + cover_full = cover_mask //----cover_full }; //----------------------------------------------------poly_subpixel_scale_e - // These constants determine the subpixel accuracy, to be more precise, - // the number of bits of the fractional part of the coordinates. + // These constants determine the subpixel accuracy, to be more precise, + // the number of bits of the fractional part of the coordinates. // The possible coordinate capacity in bits can be calculated by formula: // sizeof(int) * 8 - poly_subpixel_shift, i.e, for 32-bit integers and // 8-bits fractional part the capacity is 24 bits. enum poly_subpixel_scale_e { poly_subpixel_shift = 8, //----poly_subpixel_shift - poly_subpixel_scale = 1< struct rect_base { @@ -290,9 +290,9 @@ namespace agg rect_base(T x1_, T y1_, T x2_, T y2_) : x1(x1_), y1(y1_), x2(x2_), y2(y2_) {} - void init(T x1_, T y1_, T x2_, T y2_) + void init(T x1_, T y1_, T x2_, T y2_) { - x1 = x1_; y1 = y1_; x2 = x2_; y2 = y2_; + x1 = x1_; y1 = y1_; x2 = x2_; y2 = y2_; } const self_type& normalize() @@ -321,7 +321,7 @@ namespace agg { return (x >= x1 && x <= x2 && y >= y1 && y <= y2); } - + bool overlaps(const self_type& r) const { return !(r.x1 > x2 || r.x2 < x1 @@ -330,17 +330,17 @@ namespace agg }; //-----------------------------------------------------intersect_rectangles - template + template inline Rect intersect_rectangles(const Rect& r1, const Rect& r2) { Rect r = r1; - // First process x2,y2 because the other order - // results in Internal Compiler Error under - // Microsoft Visual C++ .NET 2003 69462-335-0000007-18038 in + // First process x2,y2 because the other order + // results in Internal Compiler Error under + // Microsoft Visual C++ .NET 2003 69462-335-0000007-18038 in // case of "Maximize Speed" optimization option. //----------------- - if(r.x2 > r2.x2) r.x2 = r2.x2; + if(r.x2 > r2.x2) r.x2 = r2.x2; if(r.y2 > r2.y2) r.y2 = r2.y2; if(r.x1 < r2.x1) r.x1 = r2.x1; if(r.y1 < r2.y1) r.y1 = r2.y1; @@ -349,7 +349,7 @@ namespace agg //---------------------------------------------------------unite_rectangles - template + template inline Rect unite_rectangles(const Rect& r1, const Rect& r2) { Rect r = r1; @@ -367,26 +367,26 @@ namespace agg //---------------------------------------------------------path_commands_e enum path_commands_e { - path_cmd_stop = 0, //----path_cmd_stop - path_cmd_move_to = 1, //----path_cmd_move_to - path_cmd_line_to = 2, //----path_cmd_line_to - path_cmd_curve3 = 3, //----path_cmd_curve3 - path_cmd_curve4 = 4, //----path_cmd_curve4 + path_cmd_stop = 0, //----path_cmd_stop + path_cmd_move_to = 1, //----path_cmd_move_to + path_cmd_line_to = 2, //----path_cmd_line_to + path_cmd_curve3 = 3, //----path_cmd_curve3 + path_cmd_curve4 = 4, //----path_cmd_curve4 path_cmd_curveN = 5, //----path_cmd_curveN path_cmd_catrom = 6, //----path_cmd_catrom path_cmd_ubspline = 7, //----path_cmd_ubspline path_cmd_end_poly = 0x0F, //----path_cmd_end_poly - path_cmd_mask = 0x0F //----path_cmd_mask + path_cmd_mask = 0x0F //----path_cmd_mask }; //------------------------------------------------------------path_flags_e enum path_flags_e { - path_flags_none = 0, //----path_flags_none - path_flags_ccw = 0x10, //----path_flags_ccw - path_flags_cw = 0x20, //----path_flags_cw + path_flags_none = 0, //----path_flags_none + path_flags_ccw = 0x10, //----path_flags_ccw + path_flags_cw = 0x20, //----path_flags_cw path_flags_close = 0x40, //----path_flags_close - path_flags_mask = 0xF0 //----path_flags_mask + path_flags_mask = 0xF0 //----path_flags_mask }; //---------------------------------------------------------------is_vertex @@ -403,7 +403,7 @@ namespace agg //-----------------------------------------------------------------is_stop inline bool is_stop(unsigned c) - { + { return c == path_cmd_stop; } @@ -447,7 +447,7 @@ namespace agg inline bool is_close(unsigned c) { return (c & ~(path_flags_cw | path_flags_ccw)) == - (path_cmd_end_poly | path_flags_close); + (path_cmd_end_poly | path_flags_close); } //------------------------------------------------------------is_next_poly @@ -471,19 +471,19 @@ namespace agg //-------------------------------------------------------------is_oriented inline bool is_oriented(unsigned c) { - return (c & (path_flags_cw | path_flags_ccw)) != 0; + return (c & (path_flags_cw | path_flags_ccw)) != 0; } //---------------------------------------------------------------is_closed inline bool is_closed(unsigned c) { - return (c & path_flags_close) != 0; + return (c & path_flags_close) != 0; } //----------------------------------------------------------get_close_flag inline unsigned get_close_flag(unsigned c) { - return c & path_flags_close; + return c & path_flags_close; } //-------------------------------------------------------clear_orientation @@ -544,28 +544,28 @@ namespace agg int x1, x2; const T* ptr; const_row_info() {} - const_row_info(int x1_, int x2_, const T* ptr_) : + const_row_info(int x1_, int x2_, const T* ptr_) : x1(x1_), x2(x2_), ptr(ptr_) {} }; //------------------------------------------------------------is_equal_eps template inline bool is_equal_eps(T v1, T v2, T epsilon) { - bool neg1 = v1 < 0.0; - bool neg2 = v2 < 0.0; + bool neg1 = v1 < 0.0; + bool neg2 = v2 < 0.0; - if (neg1 != neg2) - return std::fabs(v1) < epsilon && std::fabs(v2) < epsilon; + if (neg1 != neg2) + return std::fabs(v1) < epsilon && std::fabs(v2) < epsilon; int int1, int2; - std::frexp(v1, &int1); - std::frexp(v2, &int2); - int min12 = int1 < int2 ? int1 : int2; + std::frexp(v1, &int1); + std::frexp(v2, &int2); + int min12 = int1 < int2 ? int1 : int2; - v1 = std::ldexp(v1, -min12); - v2 = std::ldexp(v2, -min12); + v1 = std::ldexp(v1, -min12); + v2 = std::ldexp(v2, -min12); - return std::fabs(v1 - v2) < epsilon; + return std::fabs(v1 - v2) < epsilon; } } diff --git a/src/agg/agg_bezier_arc.h b/src/agg/agg_bezier_arc.h index cfd9308ea5d..6c23dad1f06 100644 --- a/src/agg/agg_bezier_arc.h +++ b/src/agg/agg_bezier_arc.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -13,7 +13,7 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e., +// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e., // 4, 7, 10, or 13 vertices. // //---------------------------------------------------------------------------- @@ -27,13 +27,13 @@ namespace agg { //----------------------------------------------------------------------- - void arc_to_bezier(double cx, double cy, double rx, double ry, + void arc_to_bezier(double cx, double cy, double rx, double ry, double start_angle, double sweep_angle, double* curve); //==============================================================bezier_arc - // + // // See implemantaion agg_bezier_arc.cpp // class bezier_arc @@ -41,18 +41,18 @@ namespace agg public: //-------------------------------------------------------------------- bezier_arc() : m_vertex(26), m_num_vertices(0), m_cmd(path_cmd_line_to) {} - bezier_arc(double x, double y, - double rx, double ry, - double start_angle, + bezier_arc(double x, double y, + double rx, double ry, + double start_angle, double sweep_angle) { init(x, y, rx, ry, start_angle, sweep_angle); } //-------------------------------------------------------------------- - void init(double x, double y, - double rx, double ry, - double start_angle, + void init(double x, double y, + double rx, double ry, + double start_angle, double sweep_angle); //-------------------------------------------------------------------- @@ -71,13 +71,13 @@ namespace agg return (m_vertex == 2) ? unsigned(path_cmd_move_to) : m_cmd; } - // Supplemantary functions. num_vertices() actually returns doubled + // Supplemantary functions. num_vertices() actually returns doubled // number of vertices. That is, for 1 vertex it returns 2. //-------------------------------------------------------------------- unsigned num_vertices() const { return m_num_vertices; } const double* vertices() const { return m_vertices; } double* vertices() { return m_vertices; } - + private: unsigned m_vertex; unsigned m_num_vertices; @@ -88,15 +88,15 @@ namespace agg //==========================================================bezier_arc_svg - // Compute an SVG-style bezier arc. + // Compute an SVG-style bezier arc. // - // Computes an elliptical arc from (x1, y1) to (x2, y2). The size and - // orientation of the ellipse are defined by two radii (rx, ry) - // and an x-axis-rotation, which indicates how the ellipse as a whole - // is rotated relative to the current coordinate system. The center - // (cx, cy) of the ellipse is calculated automatically to satisfy the - // constraints imposed by the other parameters. - // large-arc-flag and sweep-flag contribute to the automatic calculations + // Computes an elliptical arc from (x1, y1) to (x2, y2). The size and + // orientation of the ellipse are defined by two radii (rx, ry) + // and an x-axis-rotation, which indicates how the ellipse as a whole + // is rotated relative to the current coordinate system. The center + // (cx, cy) of the ellipse is calculated automatically to satisfy the + // constraints imposed by the other parameters. + // large-arc-flag and sweep-flag contribute to the automatic calculations // and help determine how the arc is drawn. class bezier_arc_svg { @@ -104,20 +104,20 @@ namespace agg //-------------------------------------------------------------------- bezier_arc_svg() : m_arc(), m_radii_ok(false) {} - bezier_arc_svg(double x1, double y1, - double rx, double ry, + bezier_arc_svg(double x1, double y1, + double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, - double x2, double y2) : + double x2, double y2) : m_arc(), m_radii_ok(false) { init(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2); } //-------------------------------------------------------------------- - void init(double x1, double y1, - double rx, double ry, + void init(double x1, double y1, + double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, @@ -138,7 +138,7 @@ namespace agg return m_arc.vertex(x, y); } - // Supplemantary functions. num_vertices() actually returns doubled + // Supplemantary functions. num_vertices() actually returns doubled // number of vertices. That is, for 1 vertex it returns 2. //-------------------------------------------------------------------- unsigned num_vertices() const { return m_arc.num_vertices(); } diff --git a/src/agg/agg_clip_liang_barsky.h b/src/agg/agg_clip_liang_barsky.h index 4b5fedbab5f..28765a79cd0 100644 --- a/src/agg/agg_clip_liang_barsky.h +++ b/src/agg/agg_clip_liang_barsky.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -13,7 +13,7 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Liang-Barsky clipping +// Liang-Barsky clipping // //---------------------------------------------------------------------------- #ifndef AGG_CLIP_LIANG_BARSKY_INCLUDED @@ -36,7 +36,7 @@ namespace agg }; //----------------------------------------------------------clipping_flags - // Determine the clipping code of the vertex according to the + // Determine the clipping code of the vertex according to the // Cyrus-Beck line clipping algorithm // // | | @@ -52,7 +52,7 @@ namespace agg // | | // clip_box.x1 clip_box.x2 // - // + // template inline unsigned clipping_flags(T x, T y, const rect_base& clip_box) { @@ -87,7 +87,7 @@ namespace agg const double nearzero = 1e-30; double deltax = x2 - x1; - double deltay = y2 - y1; + double deltay = y2 - y1; double xin; double xout; double yin; @@ -95,52 +95,52 @@ namespace agg double tinx; double tiny; double toutx; - double touty; + double touty; double tin1; double tin2; double tout1; unsigned np = 0; - if(deltax == 0.0) - { + if(deltax == 0.0) + { // bump off of the vertical deltax = (x1 > clip_box.x1) ? -nearzero : nearzero; } - if(deltay == 0.0) - { - // bump off of the horizontal + if(deltay == 0.0) + { + // bump off of the horizontal deltay = (y1 > clip_box.y1) ? -nearzero : nearzero; } - - if(deltax > 0.0) - { + + if(deltax > 0.0) + { // points to right xin = clip_box.x1; xout = clip_box.x2; } - else + else { xin = clip_box.x2; xout = clip_box.x1; } - if(deltay > 0.0) + if(deltay > 0.0) { // points up yin = clip_box.y1; yout = clip_box.y2; } - else + else { yin = clip_box.y2; yout = clip_box.y1; } - + tinx = (xin - x1) / deltax; tiny = (yin - y1) / deltay; - - if (tinx < tiny) + + if (tinx < tiny) { // hits x first tin1 = tinx; @@ -152,10 +152,10 @@ namespace agg tin1 = tiny; tin2 = tinx; } - - if(tin1 <= 1.0) + + if(tin1 <= 1.0) { - if(0.0 < tin1) + if(0.0 < tin1) { *x++ = (T)xin; *y++ = (T)yin; @@ -166,21 +166,21 @@ namespace agg { toutx = (xout - x1) / deltax; touty = (yout - y1) / deltay; - + tout1 = (toutx < touty) ? toutx : touty; - - if(tin2 > 0.0 || tout1 > 0.0) + + if(tin2 > 0.0 || tout1 > 0.0) { - if(tin2 <= tout1) + if(tin2 <= tout1) { - if(tin2 > 0.0) + if(tin2 > 0.0) { - if(tinx > tiny) + if(tinx > tiny) { *x++ = (T)xin; *y++ = (T)(y1 + tinx * deltay); } - else + else { *x++ = (T)(x1 + tiny * deltax); *y++ = (T)yin; @@ -188,34 +188,34 @@ namespace agg ++np; } - if(tout1 < 1.0) + if(tout1 < 1.0) { - if(toutx < touty) + if(toutx < touty) { *x++ = (T)xout; *y++ = (T)(y1 + toutx * deltay); } - else + else { *x++ = (T)(x1 + touty * deltax); *y++ = (T)yout; } } - else + else { *x++ = x2; *y++ = y2; } ++np; } - else + else { - if(tinx > tiny) + if(tinx > tiny) { *x++ = (T)xin; *y++ = (T)yout; } - else + else { *x++ = (T)xout; *y++ = (T)yin; @@ -231,8 +231,8 @@ namespace agg //---------------------------------------------------------------------------- template - bool clip_move_point(T x1, T y1, T x2, T y2, - const rect_base& clip_box, + bool clip_move_point(T x1, T y1, T x2, T y2, + const rect_base& clip_box, T* x, T* y, unsigned flags) { T bound; @@ -281,14 +281,14 @@ namespace agg return 0; } - if((f1 & clipping_flags_x_clipped) != 0 && + if((f1 & clipping_flags_x_clipped) != 0 && (f1 & clipping_flags_x_clipped) == (f2 & clipping_flags_x_clipped)) { // Fully clipped return 4; } - if((f1 & clipping_flags_y_clipped) != 0 && + if((f1 & clipping_flags_y_clipped) != 0 && (f1 & clipping_flags_y_clipped) == (f2 & clipping_flags_y_clipped)) { // Fully clipped @@ -299,25 +299,25 @@ namespace agg T ty1 = *y1; T tx2 = *x2; T ty2 = *y2; - if(f1) - { - if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x1, y1, f1)) + if(f1) + { + if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x1, y1, f1)) { return 4; } - if(*x1 == *x2 && *y1 == *y2) + if(*x1 == *x2 && *y1 == *y2) { return 4; } ret |= 1; } - if(f2) + if(f2) { if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x2, y2, f2)) { return 4; } - if(*x1 == *x2 && *y1 == *y2) + if(*x1 == *x2 && *y1 == *y2) { return 4; } diff --git a/src/agg/agg_color_gray.h b/src/agg/agg_color_gray.h index f66588c119e..fa8364fbe31 100644 --- a/src/agg/agg_color_gray.h +++ b/src/agg/agg_color_gray.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -13,12 +13,12 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for high precision colors has been sponsored by +// Adaptation for high precision colors has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- // // color types gray8, gray16 @@ -132,82 +132,82 @@ namespace agg } //-------------------------------------------------------------------- - template - T convert_from_sRGB() const + template + T convert_from_sRGB() const { typename T::value_type y = sRGB_conv::rgb_from_sRGB(v); return T(y, y, y, sRGB_conv::alpha_from_sRGB(a)); } - template - T convert_to_sRGB() const + template + T convert_to_sRGB() const { typename T::value_type y = sRGB_conv::rgb_to_sRGB(v); return T(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- - rgba8 make_rgba8(const linear&) const + rgba8 make_rgba8(const linear&) const { return rgba8(v, v, v, a); } - rgba8 make_rgba8(const sRGB&) const + rgba8 make_rgba8(const sRGB&) const { return convert_from_sRGB(); } - operator rgba8() const + operator rgba8() const { return make_rgba8(Colorspace()); } //-------------------------------------------------------------------- - srgba8 make_srgba8(const linear&) const + srgba8 make_srgba8(const linear&) const { return convert_to_sRGB(); } - srgba8 make_srgba8(const sRGB&) const + srgba8 make_srgba8(const sRGB&) const { return srgba8(v, v, v, a); } - operator srgba8() const + operator srgba8() const { return make_rgba8(Colorspace()); } //-------------------------------------------------------------------- - rgba16 make_rgba16(const linear&) const + rgba16 make_rgba16(const linear&) const { rgba16::value_type rgb = (v << 8) | v; return rgba16(rgb, rgb, rgb, (a << 8) | a); } - rgba16 make_rgba16(const sRGB&) const + rgba16 make_rgba16(const sRGB&) const { return convert_from_sRGB(); } - operator rgba16() const + operator rgba16() const { return make_rgba16(Colorspace()); } //-------------------------------------------------------------------- - rgba32 make_rgba32(const linear&) const + rgba32 make_rgba32(const linear&) const { rgba32::value_type v32 = v / 255.0f; return rgba32(v32, v32, v32, a / 255.0f); } - rgba32 make_rgba32(const sRGB&) const + rgba32 make_rgba32(const sRGB&) const { return convert_from_sRGB(); } - operator rgba32() const + operator rgba32() const { return make_rgba32(Colorspace()); } @@ -250,14 +250,14 @@ namespace agg //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. - static AGG_INLINE value_type multiply(value_type a, value_type b) + static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } - + //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) + static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { @@ -267,19 +267,19 @@ namespace agg { return base_mask; } - else return value_type((a * base_mask + (b >> 1)) / b); + else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template - static AGG_INLINE T downscale(T a) + static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template - static AGG_INLINE T downshift(T a, unsigned n) + static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } @@ -287,37 +287,37 @@ namespace agg //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. // Specifically for multiplying a color component by a cover. - static AGG_INLINE value_type mult_cover(value_type a, value_type b) + static AGG_INLINE value_type mult_cover(value_type a, value_type b) { return multiply(a, b); } - + //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) + static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return multiply(b, a); } - + //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } - + //-------------------------------------------------------------------- // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } - + //-------------------------------------------------------------------- self_type& clear() { v = a = 0; - return *this; + return *this; } //-------------------------------------------------------------------- @@ -333,7 +333,7 @@ namespace agg if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = (value_type)uround(a_ * double(base_mask)); - return *this; + return *this; } //-------------------------------------------------------------------- @@ -341,7 +341,7 @@ namespace agg { return double(a) / double(base_mask); } - + //-------------------------------------------------------------------- self_type& premultiply() { @@ -387,15 +387,15 @@ namespace agg calc_type cv, ca; if (cover == cover_mask) { - if (c.a == base_mask) + if (c.a == base_mask) { *this = c; return; } else { - cv = v + c.v; - ca = a + c.a; + cv = v + c.v; + ca = a + c.a; } } else @@ -490,7 +490,7 @@ namespace agg gray16(const rgba16& c) : v(luminance(c)), a(c.a) {} - + //-------------------------------------------------------------------- gray16(const gray8& c) : v((value_type(c.v) << 8) | c.v), @@ -502,42 +502,42 @@ namespace agg a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- - operator rgba8() const + operator rgba8() const { return rgba8(v >> 8, v >> 8, v >> 8, a >> 8); } //-------------------------------------------------------------------- - operator srgba8() const + operator srgba8() const { value_type y = sRGB_conv::rgb_to_sRGB(v); return srgba8(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- - operator rgba16() const + operator rgba16() const { return rgba16(v, v, v, a); } - //-------------------------------------------------------------------- - operator rgba32() const - { - rgba32::value_type v32 = v / 65535.0f; - return rgba32(v32, v32, v32, a / 65535.0f); - } + //-------------------------------------------------------------------- + operator rgba32() const + { + rgba32::value_type v32 = v / 65535.0f; + return rgba32(v32, v32, v32, a / 65535.0f); + } - //-------------------------------------------------------------------- - operator gray8() const + //-------------------------------------------------------------------- + operator gray8() const { return gray8(v >> 8, a >> 8); } //-------------------------------------------------------------------- - operator sgray8() const + operator sgray8() const { return sgray8( - sRGB_conv::rgb_to_sRGB(v), + sRGB_conv::rgb_to_sRGB(v), sRGB_conv::alpha_to_sRGB(a)); } @@ -579,14 +579,14 @@ namespace agg //-------------------------------------------------------------------- // Fixed-point multiply, exact over int16u. - static AGG_INLINE value_type multiply(value_type a, value_type b) + static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } - + //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) + static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { @@ -596,19 +596,19 @@ namespace agg { return base_mask; } - else return value_type((a * base_mask + (b >> 1)) / b); + else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template - static AGG_INLINE T downscale(T a) + static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template - static AGG_INLINE T downshift(T a, unsigned n) + static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } @@ -616,37 +616,37 @@ namespace agg //-------------------------------------------------------------------- // Fixed-point multiply, almost exact over int16u. // Specifically for multiplying a color component by a cover. - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) + static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return multiply(a, b << 8 | b); } - + //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) + static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return mult_cover(b, a) >> 8; } - + //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } - + //-------------------------------------------------------------------- // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } - + //-------------------------------------------------------------------- self_type& clear() { v = a = 0; - return *this; + return *this; } //-------------------------------------------------------------------- @@ -662,7 +662,7 @@ namespace agg if (a_ < 0) a = 0; else if(a_ > 1) a = 1; else a = (value_type)uround(a_ * double(base_mask)); - return *this; + return *this; } //-------------------------------------------------------------------- @@ -695,7 +695,7 @@ namespace agg else { calc_type v_ = (calc_type(v) * base_mask) / a; - v = (v_ > base_mask) ? value_type(base_mask) : value_type(v_); + v = (v_ > base_mask) ? value_type(base_mask) : value_type(v_); } } return *this; @@ -717,15 +717,15 @@ namespace agg calc_type cv, ca; if (cover == cover_mask) { - if (c.a == base_mask) + if (c.a == base_mask) { *this = c; return; } else { - cv = v + c.v; - ca = a + c.a; + cv = v + c.v; + ca = a + c.a; } } else @@ -817,74 +817,74 @@ namespace agg //-------------------------------------------------------------------- gray32(const gray8& c) : - v(value_type(c.v / 255.0)), + v(value_type(c.v / 255.0)), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- gray32(const sgray8& c) : - v(sRGB_conv::rgb_from_sRGB(c.v)), + v(sRGB_conv::rgb_from_sRGB(c.v)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- gray32(const gray16& c) : - v(value_type(c.v / 65535.0)), + v(value_type(c.v / 65535.0)), a(value_type(c.a / 65535.0)) {} //-------------------------------------------------------------------- - operator rgba() const + operator rgba() const { return rgba(v, v, v, a); } //-------------------------------------------------------------------- - operator gray8() const + operator gray8() const { return gray8(uround(v * 255.0), uround(a * 255.0)); } //-------------------------------------------------------------------- - operator sgray8() const + operator sgray8() const { // Return (non-premultiplied) sRGB values. return sgray8( - sRGB_conv::rgb_to_sRGB(v), + sRGB_conv::rgb_to_sRGB(v), sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- - operator gray16() const + operator gray16() const { return gray16(uround(v * 65535.0), uround(a * 65535.0)); } //-------------------------------------------------------------------- - operator rgba8() const + operator rgba8() const { rgba8::value_type y = uround(v * 255.0); return rgba8(y, y, y, uround(a * 255.0)); } //-------------------------------------------------------------------- - operator srgba8() const + operator srgba8() const { srgba8::value_type y = sRGB_conv::rgb_to_sRGB(v); return srgba8(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } - //-------------------------------------------------------------------- - operator rgba16() const - { - rgba16::value_type y = uround(v * 65535.0); - return rgba16(y, y, y, uround(a * 65535.0)); - } + //-------------------------------------------------------------------- + operator rgba16() const + { + rgba16::value_type y = uround(v * 65535.0); + return rgba16(y, y, y, uround(a * 65535.0)); + } - //-------------------------------------------------------------------- - operator rgba32() const - { + //-------------------------------------------------------------------- + operator rgba32() const + { return rgba32(v, v, v, a); - } + } - //-------------------------------------------------------------------- + //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return a; @@ -921,72 +921,72 @@ namespace agg } //-------------------------------------------------------------------- - static AGG_INLINE value_type invert(value_type x) + static AGG_INLINE value_type invert(value_type x) { return 1 - x; } //-------------------------------------------------------------------- - static AGG_INLINE value_type multiply(value_type a, value_type b) + static AGG_INLINE value_type multiply(value_type a, value_type b) { return value_type(a * b); } //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) + static AGG_INLINE value_type demultiply(value_type a, value_type b) { return (b == 0) ? 0 : value_type(a / b); } //-------------------------------------------------------------------- template - static AGG_INLINE T downscale(T a) + static AGG_INLINE T downscale(T a) { return a; } //-------------------------------------------------------------------- template - static AGG_INLINE T downshift(T a, unsigned n) + static AGG_INLINE T downshift(T a, unsigned n) { return n > 0 ? a / (1 << n) : a; } //-------------------------------------------------------------------- - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) + static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return value_type(a * b / cover_mask); } //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) + static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return cover_type(uround(a * b)); } - + //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return (1 - a) * p + q; // more accurate than "p + q - p * a" } - + //-------------------------------------------------------------------- // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { - // The form "p + a * (q - p)" avoids a multiplication, but may produce an - // inaccurate result. For example, "p + (q - p)" may not be exactly equal - // to q. Therefore, stick to the basic expression, which at least produces - // the correct result at either extreme. - return (1 - a) * p + a * q; + // The form "p + a * (q - p)" avoids a multiplication, but may produce an + // inaccurate result. For example, "p + (q - p)" may not be exactly equal + // to q. Therefore, stick to the basic expression, which at least produces + // the correct result at either extreme. + return (1 - a) * p + a * q; } - + //-------------------------------------------------------------------- self_type& clear() { v = a = 0; - return *this; + return *this; } //-------------------------------------------------------------------- @@ -1002,7 +1002,7 @@ namespace agg if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = value_type(a_); - return *this; + return *this; } //-------------------------------------------------------------------- @@ -1032,7 +1032,7 @@ namespace agg self_type gradient(self_type c, double k) const { return self_type( - value_type(v + (c.v - v) * k), + value_type(v + (c.v - v) * k), value_type(a + (c.a - a) * k)); } diff --git a/src/agg/agg_color_rgba.h b/src/agg/agg_color_rgba.h index ff33a1179cf..17b45b4f35e 100644 --- a/src/agg/agg_color_rgba.h +++ b/src/agg/agg_color_rgba.h @@ -2,19 +2,19 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // -// Adaptation for high precision colors has been sponsored by +// Adaptation for high precision colors has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com @@ -67,7 +67,7 @@ namespace agg rgba& clear() { r = g = b = a = 0; - return *this; + return *this; } //-------------------------------------------------------------------- @@ -171,7 +171,7 @@ namespace agg //-------------------------------------------------------------------- static rgba from_wavelength(double wl, double gamma = 1.0); - + //-------------------------------------------------------------------- explicit rgba(double wavelen, double gamma=1.0) { @@ -240,7 +240,7 @@ namespace agg return rgba(r, g, b, a).premultiply(); } - + //===================================================================rgba8 template struct rgba8T @@ -318,9 +318,9 @@ namespace agg //-------------------------------------------------------------------- rgba8T(unsigned r_, unsigned g_, unsigned b_, unsigned a_ = base_mask) : - r(value_type(r_)), - g(value_type(g_)), - b(value_type(b_)), + r(value_type(r_)), + g(value_type(g_)), + b(value_type(b_)), a(value_type(a_)) {} //-------------------------------------------------------------------- @@ -341,7 +341,7 @@ namespace agg } //-------------------------------------------------------------------- - operator rgba() const + operator rgba() const { rgba c; convert(c, *this); @@ -385,21 +385,21 @@ namespace agg } //-------------------------------------------------------------------- - static AGG_INLINE value_type invert(value_type x) + static AGG_INLINE value_type invert(value_type x) { return base_mask - x; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. - static AGG_INLINE value_type multiply(value_type a, value_type b) + static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } - + //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) + static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { @@ -409,19 +409,19 @@ namespace agg { return base_mask; } - else return value_type((a * base_mask + (b >> 1)) / b); + else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template - static AGG_INLINE T downscale(T a) + static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template - static AGG_INLINE T downshift(T a, unsigned n) + static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } @@ -429,39 +429,39 @@ namespace agg //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. // Specifically for multiplying a color component by a cover. - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) + static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return multiply(a, b); } - + //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) + static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return multiply(b, a); } - + //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } - + //-------------------------------------------------------------------- // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } - + //-------------------------------------------------------------------- self_type& clear() { r = g = b = a = 0; - return *this; + return *this; } - + //-------------------------------------------------------------------- self_type& transparent() { @@ -566,17 +566,17 @@ namespace agg calc_type cr, cg, cb, ca; if (cover == cover_mask) { - if (c.a == base_mask) + if (c.a == base_mask) { *this = c; return; } else { - cr = r + c.r; - cg = g + c.g; - cb = b + c.b; - ca = a + c.a; + cr = r + c.r; + cg = g + c.g; + cb = b + c.b; + ca = a + c.a; } } else @@ -683,9 +683,9 @@ namespace agg //-------------------------------------------------------------------- rgba16(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) : - r(value_type(r_)), - g(value_type(g_)), - b(value_type(b_)), + r(value_type(r_)), + g(value_type(g_)), + b(value_type(b_)), a(value_type(a_)) {} //-------------------------------------------------------------------- @@ -694,49 +694,49 @@ namespace agg //-------------------------------------------------------------------- rgba16(const rgba& c) : - r((value_type)uround(c.r * double(base_mask))), - g((value_type)uround(c.g * double(base_mask))), - b((value_type)uround(c.b * double(base_mask))), + r((value_type)uround(c.r * double(base_mask))), + g((value_type)uround(c.g * double(base_mask))), + b((value_type)uround(c.b * double(base_mask))), a((value_type)uround(c.a * double(base_mask))) {} //-------------------------------------------------------------------- rgba16(const rgba8& c) : - r(value_type((value_type(c.r) << 8) | c.r)), - g(value_type((value_type(c.g) << 8) | c.g)), - b(value_type((value_type(c.b) << 8) | c.b)), + r(value_type((value_type(c.r) << 8) | c.r)), + g(value_type((value_type(c.g) << 8) | c.g)), + b(value_type((value_type(c.b) << 8) | c.b)), a(value_type((value_type(c.a) << 8) | c.a)) {} //-------------------------------------------------------------------- rgba16(const srgba8& c) : - r(sRGB_conv::rgb_from_sRGB(c.r)), - g(sRGB_conv::rgb_from_sRGB(c.g)), - b(sRGB_conv::rgb_from_sRGB(c.b)), + r(sRGB_conv::rgb_from_sRGB(c.r)), + g(sRGB_conv::rgb_from_sRGB(c.g)), + b(sRGB_conv::rgb_from_sRGB(c.b)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- - operator rgba() const + operator rgba() const { return rgba( - r / 65535.0, - g / 65535.0, - b / 65535.0, + r / 65535.0, + g / 65535.0, + b / 65535.0, a / 65535.0); } //-------------------------------------------------------------------- - operator rgba8() const + operator rgba8() const { return rgba8(r >> 8, g >> 8, b >> 8, a >> 8); } //-------------------------------------------------------------------- - operator srgba8() const + operator srgba8() const { // Return (non-premultiplied) sRGB values. return srgba8( - sRGB_conv::rgb_to_sRGB(r), - sRGB_conv::rgb_to_sRGB(g), - sRGB_conv::rgb_to_sRGB(b), + sRGB_conv::rgb_to_sRGB(r), + sRGB_conv::rgb_to_sRGB(g), + sRGB_conv::rgb_to_sRGB(b), sRGB_conv::alpha_to_sRGB(a)); } @@ -777,21 +777,21 @@ namespace agg } //-------------------------------------------------------------------- - static AGG_INLINE value_type invert(value_type x) + static AGG_INLINE value_type invert(value_type x) { return base_mask - x; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int16u. - static AGG_INLINE value_type multiply(value_type a, value_type b) + static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } - + //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) + static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { @@ -801,19 +801,19 @@ namespace agg { return base_mask; } - else return value_type((a * base_mask + (b >> 1)) / b); + else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template - static AGG_INLINE T downscale(T a) + static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template - static AGG_INLINE T downshift(T a, unsigned n) + static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } @@ -821,39 +821,39 @@ namespace agg //-------------------------------------------------------------------- // Fixed-point multiply, almost exact over int16u. // Specifically for multiplying a color component by a cover. - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) + static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return multiply(a, (b << 8) | b); } - + //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) + static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return multiply((a << 8) | a, b) >> 8; } - + //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } - + //-------------------------------------------------------------------- // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } - + //-------------------------------------------------------------------- self_type& clear() { r = g = b = a = 0; - return *this; + return *this; } - + //-------------------------------------------------------------------- self_type& transparent() { @@ -879,7 +879,7 @@ namespace agg //-------------------------------------------------------------------- AGG_INLINE self_type& premultiply() { - if (a != base_mask) + if (a != base_mask) { if (a == 0) { @@ -958,17 +958,17 @@ namespace agg calc_type cr, cg, cb, ca; if (cover == cover_mask) { - if (c.a == base_mask) + if (c.a == base_mask) { *this = c; return; } else { - cr = r + c.r; - cg = g + c.g; - cb = b + c.b; - ca = a + c.a; + cr = r + c.r; + cg = g + c.g; + cb = b + c.b; + ca = a + c.a; } } else @@ -1057,58 +1057,58 @@ namespace agg //-------------------------------------------------------------------- rgba32(const rgba8& c) : - r(value_type(c.r / 255.0)), - g(value_type(c.g / 255.0)), - b(value_type(c.b / 255.0)), + r(value_type(c.r / 255.0)), + g(value_type(c.g / 255.0)), + b(value_type(c.b / 255.0)), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- rgba32(const srgba8& c) : - r(sRGB_conv::rgb_from_sRGB(c.r)), - g(sRGB_conv::rgb_from_sRGB(c.g)), - b(sRGB_conv::rgb_from_sRGB(c.b)), + r(sRGB_conv::rgb_from_sRGB(c.r)), + g(sRGB_conv::rgb_from_sRGB(c.g)), + b(sRGB_conv::rgb_from_sRGB(c.b)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- rgba32(const rgba16& c) : - r(value_type(c.r / 65535.0)), - g(value_type(c.g / 65535.0)), - b(value_type(c.b / 65535.0)), + r(value_type(c.r / 65535.0)), + g(value_type(c.g / 65535.0)), + b(value_type(c.b / 65535.0)), a(value_type(c.a / 65535.0)) {} //-------------------------------------------------------------------- - operator rgba() const + operator rgba() const { return rgba(r, g, b, a); } //-------------------------------------------------------------------- - operator rgba8() const + operator rgba8() const { return rgba8( - uround(r * 255.0), - uround(g * 255.0), - uround(b * 255.0), + uround(r * 255.0), + uround(g * 255.0), + uround(b * 255.0), uround(a * 255.0)); } //-------------------------------------------------------------------- - operator srgba8() const + operator srgba8() const { return srgba8( - sRGB_conv::rgb_to_sRGB(r), - sRGB_conv::rgb_to_sRGB(g), - sRGB_conv::rgb_to_sRGB(b), + sRGB_conv::rgb_to_sRGB(r), + sRGB_conv::rgb_to_sRGB(g), + sRGB_conv::rgb_to_sRGB(b), sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- - operator rgba16() const + operator rgba16() const { return rgba8( - uround(r * 65535.0), - uround(g * 65535.0), - uround(b * 65535.0), + uround(r * 65535.0), + uround(g * 65535.0), + uround(b * 65535.0), uround(a * 65535.0)); } @@ -1149,74 +1149,74 @@ namespace agg } //-------------------------------------------------------------------- - static AGG_INLINE value_type invert(value_type x) + static AGG_INLINE value_type invert(value_type x) { return 1 - x; } //-------------------------------------------------------------------- - static AGG_INLINE value_type multiply(value_type a, value_type b) + static AGG_INLINE value_type multiply(value_type a, value_type b) { return value_type(a * b); } //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) + static AGG_INLINE value_type demultiply(value_type a, value_type b) { return (b == 0) ? 0 : value_type(a / b); } //-------------------------------------------------------------------- template - static AGG_INLINE T downscale(T a) + static AGG_INLINE T downscale(T a) { return a; } //-------------------------------------------------------------------- template - static AGG_INLINE T downshift(T a, unsigned n) + static AGG_INLINE T downshift(T a, unsigned n) { return n > 0 ? a / (1 << n) : a; } //-------------------------------------------------------------------- - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) + static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return value_type(a * b / cover_mask); } //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) + static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return cover_type(uround(a * b)); } - + //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return (1 - a) * p + q; // more accurate than "p + q - p * a" } - + //-------------------------------------------------------------------- // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) + static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { - // The form "p + a * (q - p)" avoids a multiplication, but may produce an - // inaccurate result. For example, "p + (q - p)" may not be exactly equal - // to q. Therefore, stick to the basic expression, which at least produces - // the correct result at either extreme. - return (1 - a) * p + a * q; + // The form "p + a * (q - p)" avoids a multiplication, but may produce an + // inaccurate result. For example, "p + (q - p)" may not be exactly equal + // to q. Therefore, stick to the basic expression, which at least produces + // the correct result at either extreme. + return (1 - a) * p + a * q; } - + //-------------------------------------------------------------------- self_type& clear() { r = g = b = a = 0; - return *this; + return *this; } - + //-------------------------------------------------------------------- self_type& transparent() { @@ -1293,17 +1293,17 @@ namespace agg { if (cover == cover_mask) { - if (c.is_opaque()) + if (c.is_opaque()) { *this = c; return; } else { - r += c.r; - g += c.g; - b += c.b; - a += c.a; + r += c.r; + g += c.g; + b += c.b; + a += c.a; } } else diff --git a/src/agg/agg_config.h b/src/agg/agg_config.h index fa1dae2ba7b..a1c6c8a8e3b 100644 --- a/src/agg/agg_config.h +++ b/src/agg/agg_config.h @@ -5,7 +5,7 @@ //--------------------------------------- // 1. Default basic types such as: -// +// // AGG_INT8 // AGG_INT8U // AGG_INT16 @@ -15,7 +15,7 @@ // AGG_INT64 // AGG_INT64U // -// Just replace this file with new defines if necessary. +// Just replace this file with new defines if necessary. // For example, if your compiler doesn't have a 64 bit integer type // you can still use AGG if you define the follows: // @@ -23,21 +23,21 @@ // #define AGG_INT64U unsigned // // It will result in overflow in 16 bit-per-component image/pattern resampling -// but it won't result any crash and the rest of the library will remain +// but it won't result any crash and the rest of the library will remain // fully functional. //--------------------------------------- // 2. Default rendering_buffer type. Can be: // -// Provides faster access for massive pixel operations, +// Provides faster access for massive pixel operations, // such as blur, image filtering: // #define AGG_RENDERING_BUFFER row_ptr_cache -// +// // Provides cheaper creation and destruction (no mem allocs): // #define AGG_RENDERING_BUFFER row_accessor // -// You can still use both of them simultaneously in your applications +// You can still use both of them simultaneously in your applications // This #define is used only for default rendering_buffer type, // in short hand typedefs like pixfmt_rgba32. diff --git a/src/agg/agg_conv_transform.h b/src/agg/agg_conv_transform.h index 0c88a245bda..1c1591becec 100644 --- a/src/agg/agg_conv_transform.h +++ b/src/agg/agg_conv_transform.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -33,9 +33,9 @@ namespace agg m_source(&source), m_trans(&tr) {} void attach(VertexSource& source) { m_source = &source; } - void rewind(unsigned path_id) - { - m_source->rewind(path_id); + void rewind(unsigned path_id) + { + m_source->rewind(path_id); } unsigned vertex(double* x, double* y) @@ -55,7 +55,7 @@ namespace agg private: conv_transform(const conv_transform&); - const conv_transform& + const conv_transform& operator = (const conv_transform&); VertexSource* m_source; diff --git a/src/agg/agg_gamma_functions.h b/src/agg/agg_gamma_functions.h index 5d720daa9a7..4d0012e1f29 100644 --- a/src/agg/agg_gamma_functions.h +++ b/src/agg/agg_gamma_functions.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // diff --git a/src/agg/agg_gamma_lut.h b/src/agg/agg_gamma_lut.h index e30873632a0..b07ec5798ed 100644 --- a/src/agg/agg_gamma_lut.h +++ b/src/agg/agg_gamma_lut.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -22,9 +22,9 @@ namespace agg { - template class gamma_lut { public: @@ -50,8 +50,8 @@ namespace agg pod_allocator::deallocate(m_dir_gamma, gamma_size); } - gamma_lut() : - m_gamma(1.0), + gamma_lut() : + m_gamma(1.0), m_dir_gamma(pod_allocator::allocate(gamma_size)), m_inv_gamma(pod_allocator::allocate(hi_res_size)) { @@ -68,14 +68,14 @@ namespace agg } gamma_lut(double g) : - m_gamma(1.0), + m_gamma(1.0), m_dir_gamma(pod_allocator::allocate(gamma_size)), m_inv_gamma(pod_allocator::allocate(hi_res_size)) { gamma(g); } - void gamma(double g) + void gamma(double g) { m_gamma = g; @@ -99,13 +99,13 @@ namespace agg return m_gamma; } - HiResT dir(LoResT v) const - { - return m_dir_gamma[unsigned(v)]; + HiResT dir(LoResT v) const + { + return m_dir_gamma[unsigned(v)]; } - LoResT inv(HiResT v) const - { + LoResT inv(HiResT v) const + { return m_inv_gamma[unsigned(v)]; } @@ -131,32 +131,32 @@ namespace agg class sRGB_lut { public: - sRGB_lut() - { - // Generate lookup tables. - for (int i = 0; i <= 255; ++i) - { - m_dir_table[i] = float(sRGB_to_linear(i / 255.0)); - } - for (int i = 0; i <= 65535; ++i) - { - m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 65535.0)); - } - } - - float dir(int8u v) const - { - return m_dir_table[v]; - } - - int8u inv(float v) const - { - return m_inv_table[int16u(0.5 + v * 65535)]; - } - - private: - float m_dir_table[256]; - int8u m_inv_table[65536]; + sRGB_lut() + { + // Generate lookup tables. + for (int i = 0; i <= 255; ++i) + { + m_dir_table[i] = float(sRGB_to_linear(i / 255.0)); + } + for (int i = 0; i <= 65535; ++i) + { + m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 65535.0)); + } + } + + float dir(int8u v) const + { + return m_dir_table[v]; + } + + int8u inv(float v) const + { + return m_inv_table[int16u(0.5 + v * 65535)]; + } + + private: + float m_dir_table[256]; + int8u m_inv_table[65536]; }; template<> @@ -170,26 +170,26 @@ namespace agg { m_dir_table[i] = uround(65535.0 * sRGB_to_linear(i / 255.0)); } - for (int i = 0; i <= 65535; ++i) - { - m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 65535.0)); - } - } - - int16u dir(int8u v) const - { - return m_dir_table[v]; - } - - int8u inv(int16u v) const - { - return m_inv_table[v]; - } - - private: - int16u m_dir_table[256]; - int8u m_inv_table[65536]; - }; + for (int i = 0; i <= 65535; ++i) + { + m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 65535.0)); + } + } + + int16u dir(int8u v) const + { + return m_dir_table[v]; + } + + int8u inv(int16u v) const + { + return m_inv_table[v]; + } + + private: + int16u m_dir_table[256]; + int8u m_inv_table[65536]; + }; template<> class sRGB_lut @@ -197,7 +197,7 @@ namespace agg public: sRGB_lut() { - // Generate lookup tables. + // Generate lookup tables. for (int i = 0; i <= 255; ++i) { m_dir_table[i] = uround(255.0 * sRGB_to_linear(i / 255.0)); @@ -205,22 +205,22 @@ namespace agg } } - int8u dir(int8u v) const - { - return m_dir_table[v]; - } + int8u dir(int8u v) const + { + return m_dir_table[v]; + } - int8u inv(int8u v) const + int8u inv(int8u v) const { return m_inv_table[v]; } - private: - int8u m_dir_table[256]; - int8u m_inv_table[256]; - }; + private: + int8u m_dir_table[256]; + int8u m_inv_table[256]; + }; - // Common base class for sRGB_conv objects. Defines an internal + // Common base class for sRGB_conv objects. Defines an internal // sRGB_lut object so that users don't have to. template class sRGB_conv_base @@ -240,12 +240,12 @@ namespace agg static sRGB_lut lut; }; - // Definition of sRGB_conv_base::lut. Due to the fact that this a template, + // Definition of sRGB_conv_base::lut. Due to the fact that this a template, // we don't need to place the definition in a cpp file. Hurrah. template sRGB_lut sRGB_conv_base::lut; - // Wrapper for sRGB-linear conversion. + // Wrapper for sRGB-linear conversion. // Base template is undefined, specializations are provided below. template class sRGB_conv; @@ -256,7 +256,7 @@ namespace agg public: static float alpha_from_sRGB(int8u x) { - static const double y = 1 / 255.0; + static const double y = 1 / 255.0; return float(x * y); } diff --git a/src/agg/agg_math.h b/src/agg/agg_math.h index 2ec49cf3ff8..2c35c805e67 100644 --- a/src/agg/agg_math.h +++ b/src/agg/agg_math.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -12,7 +12,7 @@ // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- -// Bessel function (besj) was adapted for use in AGG library by Andy Wilk +// Bessel function (besj) was adapted for use in AGG library by Andy Wilk // Contact: castor.vulgaris@gmail.com //---------------------------------------------------------------------------- @@ -34,17 +34,17 @@ namespace agg const double intersection_epsilon = 1.0e-30; //------------------------------------------------------------cross_product - AGG_INLINE double cross_product(double x1, double y1, - double x2, double y2, + AGG_INLINE double cross_product(double x1, double y1, + double x2, double y2, double x, double y) { return (x - x2) * (y2 - y1) - (y - y2) * (x2 - x1); } //--------------------------------------------------------point_in_triangle - AGG_INLINE bool point_in_triangle(double x1, double y1, - double x2, double y2, - double x3, double y3, + AGG_INLINE bool point_in_triangle(double x1, double y1, + double x2, double y2, + double x3, double y3, double x, double y) { bool cp1 = cross_product(x1, y1, x2, y2, x, y) < 0.0; @@ -70,8 +70,8 @@ namespace agg } //------------------------------------------------calc_line_point_distance - AGG_INLINE double calc_line_point_distance(double x1, double y1, - double x2, double y2, + AGG_INLINE double calc_line_point_distance(double x1, double y1, + double x2, double y2, double x, double y) { double dx = x2-x1; @@ -85,8 +85,8 @@ namespace agg } //-------------------------------------------------------calc_line_point_u - AGG_INLINE double calc_segment_point_u(double x1, double y1, - double x2, double y2, + AGG_INLINE double calc_segment_point_u(double x1, double y1, + double x2, double y2, double x, double y) { double dx = x2 - x1; @@ -94,7 +94,7 @@ namespace agg if(dx == 0 && dy == 0) { - return 0; + return 0; } double pdx = x - x1; @@ -104,29 +104,29 @@ namespace agg } //---------------------------------------------calc_line_point_sq_distance - AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, - double x2, double y2, + AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, + double x2, double y2, double x, double y, double u) { if(u <= 0) { - return calc_sq_distance(x, y, x1, y1); + return calc_sq_distance(x, y, x1, y1); } - else + else if(u >= 1) { - return calc_sq_distance(x, y, x2, y2); + return calc_sq_distance(x, y, x2, y2); } return calc_sq_distance(x, y, x1 + u * (x2 - x1), y1 + u * (y2 - y1)); } //---------------------------------------------calc_line_point_sq_distance - AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, - double x2, double y2, + AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, + double x2, double y2, double x, double y) { - return + return calc_segment_point_sq_distance( x1, y1, x2, y2, x, y, calc_segment_point_u(x1, y1, x2, y2, x, y)); @@ -150,18 +150,18 @@ namespace agg AGG_INLINE bool intersection_exists(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { - // It's less expensive but you can't control the + // It's less expensive but you can't control the // boundary conditions: Less or LessEqual double dx1 = x2 - x1; double dy1 = y2 - y1; double dx2 = x4 - x3; double dy2 = y4 - y3; - return ((x3 - x2) * dy1 - (y3 - y2) * dx1 < 0.0) != + return ((x3 - x2) * dy1 - (y3 - y2) * dx1 < 0.0) != ((x4 - x2) * dy1 - (y4 - y2) * dx1 < 0.0) && ((x1 - x4) * dy2 - (y1 - y4) * dx2 < 0.0) != ((x2 - x4) * dy2 - (y2 - y4) * dx2 < 0.0); - // It's is more expensive but more flexible + // It's is more expensive but more flexible // in terms of boundary conditions. //-------------------- //double den = (x2-x1) * (y4-y3) - (y2-y1) * (x4-x3); @@ -181,7 +181,7 @@ namespace agg { double dx = x2 - x1; double dy = y2 - y1; - double d = sqrt(dx*dx + dy*dy); + double d = sqrt(dx*dx + dy*dy); *x = thickness * dy / d; *y = -thickness * dx / d; } @@ -194,15 +194,15 @@ namespace agg double d) { double dx1=0.0; - double dy1=0.0; + double dy1=0.0; double dx2=0.0; - double dy2=0.0; + double dy2=0.0; double dx3=0.0; - double dy3=0.0; + double dy3=0.0; double loc = cross_product(x1, y1, x2, y2, x3, y3); if(fabs(loc) > intersection_epsilon) { - if(cross_product(x1, y1, x2, y2, x3, y3) > 0.0) + if(cross_product(x1, y1, x2, y2, x3, y3) > 0.0) { d = -d; } @@ -261,8 +261,8 @@ namespace agg AGG_INLINE unsigned fast_sqrt(unsigned val) { #if defined(_M_IX86) && defined(_MSC_VER) && !defined(AGG_NO_ASM) - //For Ix86 family processors this assembler code is used. - //The key command here is bsr - determination the number of the most + //For Ix86 family processors this assembler code is used. + //The key command here is bsr - determination the number of the most //significant bit of the value. For other processors //(and maybe compilers) the pure C "#else" section is used. __asm @@ -285,15 +285,15 @@ namespace agg } #else - //This code is actually pure C and portable to most - //arcitectures including 64bit ones. + //This code is actually pure C and portable to most + //arcitectures including 64bit ones. unsigned t = val; int bit=0; unsigned shift = 11; //The following piece of code is just an emulation of the //Ix86 assembler command "bsr" (see above). However on old - //Intels (like Intel MMX 233MHz) this code is about twice + //Intels (like Intel MMX 233MHz) this code is about twice //faster (sic!) then just one "bsr". On PIII and PIV the //bsr is optimized quite well. bit = t >> 24; @@ -370,7 +370,7 @@ namespace agg } double d = 1E-6; double b = 0; - if(fabs(x) <= d) + if(fabs(x) <= d) { if(n != 0) return 0; return 1; @@ -378,29 +378,29 @@ namespace agg double b1 = 0; // b1 is the value from the previous iteration // Set up a starting order for recurrence int m1 = (int)fabs(x) + 6; - if(fabs(x) > 5) + if(fabs(x) > 5) { m1 = (int)(fabs(1.4 * x + 60 / x)); } int m2 = (int)(n + 2 + fabs(x) / 4); - if (m1 > m2) + if (m1 > m2) { m2 = m1; } - + // Apply recurrence down from curent max order - for(;;) + for(;;) { double c3 = 0; double c2 = 1E-30; double c4 = 0; int m8 = 1; - if (m2 / 2 * 2 == m2) + if (m2 / 2 * 2 == m2) { m8 = -1; } int imax = m2 - 2; - for (int i = 1; i <= imax; i++) + for (int i = 1; i <= imax; i++) { double c6 = 2 * (m2 - i) * c2 / x - c3; c3 = c2; diff --git a/src/agg/agg_path_storage.h b/src/agg/agg_path_storage.h index f55c89957bf..39393bb28ef 100644 --- a/src/agg/agg_path_storage.h +++ b/src/agg/agg_path_storage.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -92,7 +92,7 @@ namespace agg { pod_allocator::deallocate( *coord_blk, - block_size * 2 + + block_size * 2 + block_size / (sizeof(T) / sizeof(unsigned char))); --coord_blk; } @@ -137,7 +137,7 @@ namespace agg //------------------------------------------------------------------------ template - const vertex_block_storage& + const vertex_block_storage& vertex_block_storage::operator = (const vertex_block_storage& v) { remove_all(); @@ -148,7 +148,7 @@ namespace agg unsigned cmd = v.vertex(i, &x, &y); add_vertex(x, y, cmd); } - return *this; + return *this; } //------------------------------------------------------------------------ @@ -160,7 +160,7 @@ namespace agg //------------------------------------------------------------------------ template - inline void vertex_block_storage::add_vertex(double x, double y, + inline void vertex_block_storage::add_vertex(double x, double y, unsigned cmd) { T* coord_ptr = 0; @@ -172,7 +172,7 @@ namespace agg //------------------------------------------------------------------------ template - inline void vertex_block_storage::modify_vertex(unsigned idx, + inline void vertex_block_storage::modify_vertex(unsigned idx, double x, double y) { T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1); @@ -182,8 +182,8 @@ namespace agg //------------------------------------------------------------------------ template - inline void vertex_block_storage::modify_vertex(unsigned idx, - double x, double y, + inline void vertex_block_storage::modify_vertex(unsigned idx, + double x, double y, unsigned cmd) { unsigned block = idx >> block_shift; @@ -196,7 +196,7 @@ namespace agg //------------------------------------------------------------------------ template - inline void vertex_block_storage::modify_command(unsigned idx, + inline void vertex_block_storage::modify_command(unsigned idx, unsigned cmd) { m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd; @@ -277,7 +277,7 @@ namespace agg //------------------------------------------------------------------------ template - inline unsigned vertex_block_storage::vertex(unsigned idx, + inline unsigned vertex_block_storage::vertex(unsigned idx, double* x, double* y) const { unsigned nb = idx >> block_shift; @@ -298,22 +298,22 @@ namespace agg template void vertex_block_storage::allocate_block(unsigned nb) { - if(nb >= m_max_blocks) + if(nb >= m_max_blocks) { - T** new_coords = + T** new_coords = pod_allocator::allocate((m_max_blocks + block_pool) * 2); - unsigned char** new_cmds = + unsigned char** new_cmds = (unsigned char**)(new_coords + m_max_blocks + block_pool); if(m_coord_blocks) { - memcpy(new_coords, - m_coord_blocks, + memcpy(new_coords, + m_coord_blocks, m_max_blocks * sizeof(T*)); - memcpy(new_cmds, - m_cmd_blocks, + memcpy(new_cmds, + m_cmd_blocks, m_max_blocks * sizeof(unsigned char*)); pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); @@ -322,11 +322,11 @@ namespace agg m_cmd_blocks = new_cmds; m_max_blocks += block_pool; } - m_coord_blocks[nb] = - pod_allocator::allocate(block_size * 2 + + m_coord_blocks[nb] = + pod_allocator::allocate(block_size * 2 + block_size / (sizeof(T) / sizeof(unsigned char))); - m_cmd_blocks[nb] = + m_cmd_blocks[nb] = (unsigned char*)(m_coord_blocks[nb] + block_size * 2); m_total_blocks++; @@ -354,8 +354,8 @@ namespace agg public: typedef T value_type; - poly_plain_adaptor() : - m_data(0), + poly_plain_adaptor() : + m_data(0), m_ptr(0), m_end(0), m_closed(false), @@ -363,7 +363,7 @@ namespace agg {} poly_plain_adaptor(const T* data, unsigned num_points, bool closed) : - m_data(data), + m_data(data), m_ptr(data), m_end(data + num_points * 2), m_closed(closed), @@ -421,15 +421,15 @@ namespace agg public: typedef typename Container::value_type vertex_type; - poly_container_adaptor() : - m_container(0), + poly_container_adaptor() : + m_container(0), m_index(0), m_closed(false), m_stop(false) {} poly_container_adaptor(const Container& data, bool closed) : - m_container(&data), + m_container(&data), m_index(0), m_closed(closed), m_stop(false) @@ -483,15 +483,15 @@ namespace agg public: typedef typename Container::value_type vertex_type; - poly_container_reverse_adaptor() : - m_container(0), + poly_container_reverse_adaptor() : + m_container(0), m_index(-1), m_closed(false), m_stop(false) {} poly_container_reverse_adaptor(Container& data, bool closed) : - m_container(&data), + m_container(&data), m_index(-1), m_closed(closed), m_stop(false) @@ -556,7 +556,7 @@ namespace agg m_coord[2] = x2; m_coord[3] = y2; } - + void init(double x1, double y1, double x2, double y2) { m_coord[0] = x1; @@ -594,10 +594,10 @@ namespace agg //---------------------------------------------------------------path_base - // A container to store vertices with their flags. - // A path consists of a number of contours separated with "move_to" + // A container to store vertices with their flags. + // A path consists of a number of contours separated with "move_to" // commands. The path storage can keep and maintain more than one - // path. + // path. // To navigate to the beginning of a particular path, use rewind(path_id); // Where path_id is what start_new_path() returns. So, when you call // start_new_path() you need to store its return value somewhere else @@ -644,28 +644,28 @@ namespace agg bool sweep_flag, double dx, double dy); - void curve3(double x_ctrl, double y_ctrl, + void curve3(double x_ctrl, double y_ctrl, double x_to, double y_to); - void curve3_rel(double dx_ctrl, double dy_ctrl, + void curve3_rel(double dx_ctrl, double dy_ctrl, double dx_to, double dy_to); void curve3(double x_to, double y_to); void curve3_rel(double dx_to, double dy_to); - void curve4(double x_ctrl1, double y_ctrl1, - double x_ctrl2, double y_ctrl2, + void curve4(double x_ctrl1, double y_ctrl1, + double x_ctrl2, double y_ctrl2, double x_to, double y_to); - void curve4_rel(double dx_ctrl1, double dy_ctrl1, - double dx_ctrl2, double dy_ctrl2, + void curve4_rel(double dx_ctrl1, double dy_ctrl1, + double dx_ctrl2, double dy_ctrl2, double dx_to, double dy_to); - void curve4(double x_ctrl2, double y_ctrl2, + void curve4(double x_ctrl2, double y_ctrl2, double x_to, double y_to); - void curve4_rel(double x_ctrl2, double y_ctrl2, + void curve4_rel(double x_ctrl2, double y_ctrl2, double x_to, double y_to); @@ -674,8 +674,8 @@ namespace agg // Accessors //-------------------------------------------------------------------- - const container_type& vertices() const { return m_vertices; } - container_type& vertices() { return m_vertices; } + const container_type& vertices() const { return m_vertices; } + container_type& vertices() { return m_vertices; } unsigned total_vertices() const; @@ -699,9 +699,9 @@ namespace agg void rewind(unsigned path_id); unsigned vertex(double* x, double* y); - // Arrange the orientation of a polygon, all polygons in a path, - // or in all paths. After calling arrange_orientations() or - // arrange_orientations_all_paths(), all the polygons will have + // Arrange the orientation of a polygon, all polygons in a path, + // or in all paths. After calling arrange_orientations() or + // arrange_orientations_all_paths(), all the polygons will have // the same orientation, i.e. path_flags_cw or path_flags_ccw //-------------------------------------------------------------------- unsigned arrange_polygon_orientation(unsigned start, path_flags_e orientation); @@ -709,7 +709,7 @@ namespace agg void arrange_orientations_all_paths(path_flags_e orientation); void invert_polygon(unsigned start); - // Flip all vertices horizontally or vertically, + // Flip all vertices horizontally or vertically, // between x1 and x2, or between y1 and y2 respectively //-------------------------------------------------------------------- void flip_x(double x1, double x2); @@ -717,7 +717,7 @@ namespace agg // Concatenate path. The path is added as is. //-------------------------------------------------------------------- - template + template void concat_path(VertexSource& vs, unsigned path_id = 0) { double x, y; @@ -730,9 +730,9 @@ namespace agg } //-------------------------------------------------------------------- - // Join path. The path is joined with the existing one, that is, + // Join path. The path is joined with the existing one, that is, // it behaves as if the pen of a plotter was always down (drawing) - template + template void join_path(VertexSource& vs, unsigned path_id = 0) { double x, y; @@ -768,16 +768,16 @@ namespace agg } while(!is_stop(cmd = vs.vertex(&x, &y))) { - m_vertices.add_vertex(x, y, is_move_to(cmd) ? - unsigned(path_cmd_line_to) : + m_vertices.add_vertex(x, y, is_move_to(cmd) ? + unsigned(path_cmd_line_to) : cmd); } } } - // Concatenate polygon/polyline. + // Concatenate polygon/polyline. //-------------------------------------------------------------------- - template void concat_poly(const T* data, + template void concat_poly(const T* data, unsigned num_points, bool closed) { @@ -787,7 +787,7 @@ namespace agg // Join polygon/polyline continuously. //-------------------------------------------------------------------- - template void join_poly(const T* data, + template void join_poly(const T* data, unsigned num_points, bool closed) { @@ -841,7 +841,7 @@ namespace agg //-------------------------------------------------------------------- unsigned align_path(unsigned idx = 0) { - if (idx >= total_vertices() || !is_move_to(command(idx))) + if (idx >= total_vertices() || !is_move_to(command(idx))) { return total_vertices(); } @@ -882,7 +882,7 @@ namespace agg }; //------------------------------------------------------------------------ - template + template unsigned path_base::start_new_path() { if(!is_stop(m_vertices.last_command())) @@ -894,7 +894,7 @@ namespace agg //------------------------------------------------------------------------ - template + template inline void path_base::rel_to_abs(double* x, double* y) const { if(m_vertices.total_vertices()) @@ -910,14 +910,14 @@ namespace agg } //------------------------------------------------------------------------ - template + template inline void path_base::move_to(double x, double y) { m_vertices.add_vertex(x, y, path_cmd_move_to); } //------------------------------------------------------------------------ - template + template inline void path_base::move_rel(double dx, double dy) { rel_to_abs(&dx, &dy); @@ -925,14 +925,14 @@ namespace agg } //------------------------------------------------------------------------ - template + template inline void path_base::line_to(double x, double y) { m_vertices.add_vertex(x, y, path_cmd_line_to); } //------------------------------------------------------------------------ - template + template inline void path_base::line_rel(double dx, double dy) { rel_to_abs(&dx, &dy); @@ -940,14 +940,14 @@ namespace agg } //------------------------------------------------------------------------ - template + template inline void path_base::hline_to(double x) { m_vertices.add_vertex(x, last_y(), path_cmd_line_to); } //------------------------------------------------------------------------ - template + template inline void path_base::hline_rel(double dx) { double dy = 0; @@ -956,14 +956,14 @@ namespace agg } //------------------------------------------------------------------------ - template + template inline void path_base::vline_to(double y) { m_vertices.add_vertex(last_x(), y, path_cmd_line_to); } //------------------------------------------------------------------------ - template + template inline void path_base::vline_rel(double dy) { double dx = 0; @@ -972,7 +972,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::arc_to(double rx, double ry, double angle, bool large_arc_flag, @@ -991,7 +991,7 @@ namespace agg // Ensure radii are valid //------------------------- - if(rx < epsilon || ry < epsilon) + if(rx < epsilon || ry < epsilon) { line_to(x, y); return; @@ -1020,7 +1020,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::arc_rel(double rx, double ry, double angle, bool large_arc_flag, @@ -1032,8 +1032,8 @@ namespace agg } //------------------------------------------------------------------------ - template - void path_base::curve3(double x_ctrl, double y_ctrl, + template + void path_base::curve3(double x_ctrl, double y_ctrl, double x_to, double y_to) { m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); @@ -1041,8 +1041,8 @@ namespace agg } //------------------------------------------------------------------------ - template - void path_base::curve3_rel(double dx_ctrl, double dy_ctrl, + template + void path_base::curve3_rel(double dx_ctrl, double dy_ctrl, double dx_to, double dy_to) { rel_to_abs(&dx_ctrl, &dy_ctrl); @@ -1052,7 +1052,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::curve3(double x_to, double y_to) { double x0; @@ -1060,7 +1060,7 @@ namespace agg if(is_vertex(m_vertices.last_vertex(&x0, &y0))) { double x_ctrl; - double y_ctrl; + double y_ctrl; unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl); if(is_curve(cmd)) { @@ -1077,7 +1077,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::curve3_rel(double dx_to, double dy_to) { rel_to_abs(&dx_to, &dy_to); @@ -1085,9 +1085,9 @@ namespace agg } //------------------------------------------------------------------------ - template - void path_base::curve4(double x_ctrl1, double y_ctrl1, - double x_ctrl2, double y_ctrl2, + template + void path_base::curve4(double x_ctrl1, double y_ctrl1, + double x_ctrl2, double y_ctrl2, double x_to, double y_to) { m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); @@ -1096,9 +1096,9 @@ namespace agg } //------------------------------------------------------------------------ - template - void path_base::curve4_rel(double dx_ctrl1, double dy_ctrl1, - double dx_ctrl2, double dy_ctrl2, + template + void path_base::curve4_rel(double dx_ctrl1, double dy_ctrl1, + double dx_ctrl2, double dy_ctrl2, double dx_to, double dy_to) { rel_to_abs(&dx_ctrl1, &dy_ctrl1); @@ -1110,8 +1110,8 @@ namespace agg } //------------------------------------------------------------------------ - template - void path_base::curve4(double x_ctrl2, double y_ctrl2, + template + void path_base::curve4(double x_ctrl2, double y_ctrl2, double x_to, double y_to) { double x0; @@ -1119,7 +1119,7 @@ namespace agg if(is_vertex(last_vertex(&x0, &y0))) { double x_ctrl1; - double y_ctrl1; + double y_ctrl1; unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1); if(is_curve(cmd)) { @@ -1136,8 +1136,8 @@ namespace agg } //------------------------------------------------------------------------ - template - void path_base::curve4_rel(double dx_ctrl2, double dy_ctrl2, + template + void path_base::curve4_rel(double dx_ctrl2, double dy_ctrl2, double dx_to, double dy_to) { rel_to_abs(&dx_ctrl2, &dy_ctrl2); @@ -1146,7 +1146,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template inline void path_base::end_poly(unsigned flags) { if(is_vertex(m_vertices.last_command())) @@ -1156,91 +1156,91 @@ namespace agg } //------------------------------------------------------------------------ - template + template inline void path_base::close_polygon(unsigned flags) { end_poly(path_flags_close | flags); } //------------------------------------------------------------------------ - template + template inline unsigned path_base::total_vertices() const { return m_vertices.total_vertices(); } //------------------------------------------------------------------------ - template + template inline unsigned path_base::last_vertex(double* x, double* y) const { return m_vertices.last_vertex(x, y); } //------------------------------------------------------------------------ - template + template inline unsigned path_base::prev_vertex(double* x, double* y) const { return m_vertices.prev_vertex(x, y); } //------------------------------------------------------------------------ - template + template inline double path_base::last_x() const { return m_vertices.last_x(); } //------------------------------------------------------------------------ - template + template inline double path_base::last_y() const { return m_vertices.last_y(); } //------------------------------------------------------------------------ - template + template inline unsigned path_base::vertex(unsigned idx, double* x, double* y) const { return m_vertices.vertex(idx, x, y); } - + //------------------------------------------------------------------------ - template + template inline unsigned path_base::command(unsigned idx) const { return m_vertices.command(idx); } //------------------------------------------------------------------------ - template + template void path_base::modify_vertex(unsigned idx, double x, double y) { m_vertices.modify_vertex(idx, x, y); } //------------------------------------------------------------------------ - template + template void path_base::modify_vertex(unsigned idx, double x, double y, unsigned cmd) { m_vertices.modify_vertex(idx, x, y, cmd); } //------------------------------------------------------------------------ - template + template void path_base::modify_command(unsigned idx, unsigned cmd) { m_vertices.modify_command(idx, cmd); } //------------------------------------------------------------------------ - template + template inline void path_base::rewind(unsigned path_id) { m_iterator = path_id; } //------------------------------------------------------------------------ - template + template inline unsigned path_base::vertex(double* x, double* y) { if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop; @@ -1248,7 +1248,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template unsigned path_base::perceive_polygon_orientation(unsigned start, unsigned end) { @@ -1268,12 +1268,12 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::invert_polygon(unsigned start, unsigned end) { unsigned i; unsigned tmp_cmd = m_vertices.command(start); - + --end; // Make "end" inclusive // Shift all commands to one position @@ -1293,45 +1293,45 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::invert_polygon(unsigned start) { // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && + while(start < m_vertices.total_vertices() && !is_vertex(m_vertices.command(start))) ++start; // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && + while(start+1 < m_vertices.total_vertices() && is_move_to(m_vertices.command(start)) && is_move_to(m_vertices.command(start+1))) ++start; // Find the last vertex unsigned end = start + 1; - while(end < m_vertices.total_vertices() && + while(end < m_vertices.total_vertices() && !is_next_poly(m_vertices.command(end))) ++end; invert_polygon(start, end); } //------------------------------------------------------------------------ - template - unsigned path_base::arrange_polygon_orientation(unsigned start, + template + unsigned path_base::arrange_polygon_orientation(unsigned start, path_flags_e orientation) { if(orientation == path_flags_none) return start; - + // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && + while(start < m_vertices.total_vertices() && !is_vertex(m_vertices.command(start))) ++start; // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && + while(start+1 < m_vertices.total_vertices() && is_move_to(m_vertices.command(start)) && is_move_to(m_vertices.command(start+1))) ++start; // Find the last vertex unsigned end = start + 1; - while(end < m_vertices.total_vertices() && + while(end < m_vertices.total_vertices() && !is_next_poly(m_vertices.command(end))) ++end; if(end - start > 2) @@ -1341,7 +1341,7 @@ namespace agg // Invert polygon, set orientation flag, and skip all end_poly invert_polygon(start, end); unsigned cmd; - while(end < m_vertices.total_vertices() && + while(end < m_vertices.total_vertices() && is_end_poly(cmd = m_vertices.command(end))) { m_vertices.modify_command(end++, set_orientation(cmd, orientation)); @@ -1352,8 +1352,8 @@ namespace agg } //------------------------------------------------------------------------ - template - unsigned path_base::arrange_orientations(unsigned start, + template + unsigned path_base::arrange_orientations(unsigned start, path_flags_e orientation) { if(orientation != path_flags_none) @@ -1372,7 +1372,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::arrange_orientations_all_paths(path_flags_e orientation) { if(orientation != path_flags_none) @@ -1386,7 +1386,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::flip_x(double x1, double x2) { unsigned i; @@ -1402,7 +1402,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::flip_y(double y1, double y2) { unsigned i; @@ -1418,7 +1418,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::translate(double dx, double dy, unsigned path_id) { unsigned num_ver = m_vertices.total_vertices(); @@ -1437,7 +1437,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void path_base::translate_all_paths(double dx, double dy) { unsigned idx; @@ -1466,8 +1466,8 @@ namespace agg void add_vertex(double x, double y, unsigned cmd) { - m_vertices.push_back(vertex_type(value_type(x), - value_type(y), + m_vertices.push_back(vertex_type(value_type(x), + value_type(y), int8u(cmd))); } @@ -1500,8 +1500,8 @@ namespace agg unsigned last_command() const { - return m_vertices.size() ? - m_vertices[m_vertices.size() - 1].cmd : + return m_vertices.size() ? + m_vertices[m_vertices.size() - 1].cmd : path_cmd_stop; } @@ -1573,7 +1573,7 @@ namespace agg //#include //namespace agg //{ -// typedef path_base > > stl_path_storage; +// typedef path_base > > stl_path_storage; //} diff --git a/src/agg/agg_pixfmt_base.h b/src/agg/agg_pixfmt_base.h index 57ae19cfe04..36ca8af699e 100644 --- a/src/agg/agg_pixfmt_base.h +++ b/src/agg/agg_pixfmt_base.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -35,7 +35,7 @@ namespace agg }; //--------------------------------------------------------------blender_base - template + template struct blender_base { typedef ColorT color_type; @@ -47,9 +47,9 @@ namespace agg if (cover > cover_none) { rgba c( - color_type::to_double(r), - color_type::to_double(g), - color_type::to_double(b), + color_type::to_double(r), + color_type::to_double(g), + color_type::to_double(b), color_type::to_double(a)); if (cover < cover_full) @@ -69,10 +69,10 @@ namespace agg static rgba get(const value_type* p, cover_type cover = cover_full) { return get( - p[order_type::R], - p[order_type::G], - p[order_type::B], - p[order_type::A], + p[order_type::R], + p[order_type::G], + p[order_type::B], + p[order_type::A], cover); } diff --git a/src/agg/agg_pixfmt_gray.h b/src/agg/agg_pixfmt_gray.h index d03dc865017..1cc634b77c0 100644 --- a/src/agg/agg_pixfmt_gray.h +++ b/src/agg/agg_pixfmt_gray.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -13,12 +13,12 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for high precision colors has been sponsored by +// Adaptation for high precision colors has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- #ifndef AGG_PIXFMT_GRAY_INCLUDED @@ -30,7 +30,7 @@ namespace agg { - + //============================================================blender_gray template struct blender_gray { @@ -43,13 +43,13 @@ namespace agg // compositing function. Since the render buffer is opaque we skip the // initial premultiply and final demultiply. - static AGG_INLINE void blend_pix(value_type* p, + static AGG_INLINE void blend_pix(value_type* p, value_type cv, value_type alpha, cover_type cover) { blend_pix(p, cv, color_type::mult_cover(alpha, cover)); } - static AGG_INLINE void blend_pix(value_type* p, + static AGG_INLINE void blend_pix(value_type* p, value_type cv, value_type alpha) { *p = color_type::lerp(*p, cv, alpha); @@ -66,21 +66,21 @@ namespace agg typedef typename color_type::long_type long_type; // Blend pixels using the premultiplied form of Alvy-Ray Smith's - // compositing function. + // compositing function. - static AGG_INLINE void blend_pix(value_type* p, + static AGG_INLINE void blend_pix(value_type* p, value_type cv, value_type alpha, cover_type cover) { blend_pix(p, color_type::mult_cover(cv, cover), color_type::mult_cover(alpha, cover)); } - static AGG_INLINE void blend_pix(value_type* p, + static AGG_INLINE void blend_pix(value_type* p, value_type cv, value_type alpha) { *p = color_type::prelerp(*p, cv, alpha); } }; - + //=====================================================apply_gamma_dir_gray @@ -134,7 +134,7 @@ namespace agg typedef int order_type; // A fake one typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; - enum + enum { num_components = 1, pix_width = sizeof(value_type) * Step, @@ -188,8 +188,8 @@ namespace agg private: //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(pixel_type* p, - value_type v, value_type a, + AGG_INLINE void blend_pix(pixel_type* p, + value_type v, value_type a, unsigned cover) { blender_type::blend_pix(p->c, v, a, cover); @@ -260,7 +260,7 @@ namespace agg if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) { int stride = pixf.stride(); - m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), + m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), (r.x2 - r.x1) + 1, (r.y2 - r.y1) + 1, stride); @@ -280,37 +280,37 @@ namespace agg row_data row(int y) const { return m_rbuf->row(y); } //-------------------------------------------------------------------- - AGG_INLINE int8u* pix_ptr(int x, int y) - { + AGG_INLINE int8u* pix_ptr(int x, int y) + { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); } - AGG_INLINE const int8u* pix_ptr(int x, int y) const - { + AGG_INLINE const int8u* pix_ptr(int x, int y) const + { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); } // Return pointer to pixel value, forcing row to be allocated. - AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) + AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) { return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset)); } // Return pointer to pixel value, or null if row not allocated. - AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const + AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const { int8u* p = m_rbuf->row_ptr(y); return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0; } // Get pixel pointer from raw buffer pointer. - AGG_INLINE static pixel_type* pix_value_ptr(void* p) + AGG_INLINE static pixel_type* pix_value_ptr(void* p) { return (pixel_type*)((value_type*)p + pix_offset); } // Get pixel pointer from raw buffer pointer. - AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) + AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { return (const pixel_type*)((const value_type*)p + pix_offset); } @@ -358,8 +358,8 @@ namespace agg } //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, + AGG_INLINE void copy_hline(int x, int y, + unsigned len, const color_type& c) { pixel_type* p = pix_value_ptr(x, y, len); @@ -374,7 +374,7 @@ namespace agg //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, - unsigned len, + unsigned len, const color_type& c) { do @@ -387,7 +387,7 @@ namespace agg //-------------------------------------------------------------------- void blend_hline(int x, int y, - unsigned len, + unsigned len, const color_type& c, int8u cover) { @@ -419,7 +419,7 @@ namespace agg //-------------------------------------------------------------------- void blend_vline(int x, int y, - unsigned len, + unsigned len, const color_type& c, int8u cover) { @@ -447,7 +447,7 @@ namespace agg //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, - unsigned len, + unsigned len, const color_type& c, const int8u* covers) { @@ -455,7 +455,7 @@ namespace agg { pixel_type* p = pix_value_ptr(x, y, len); - do + do { if (c.is_opaque() && *covers == cover_mask) { @@ -475,13 +475,13 @@ namespace agg //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, - unsigned len, + unsigned len, const color_type& c, const int8u* covers) { if (!c.is_transparent()) { - do + do { pixel_type* p = pix_value_ptr(x, y++, 1); @@ -502,12 +502,12 @@ namespace agg //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors) { pixel_type* p = pix_value_ptr(x, y, len); - do + do { p->set(*colors++); p = p->next(); @@ -518,10 +518,10 @@ namespace agg //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors) { - do + do { pix_value_ptr(x, y++, 1)->set(*colors++); } @@ -531,7 +531,7 @@ namespace agg //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors, const int8u* covers, int8u cover) @@ -540,7 +540,7 @@ namespace agg if (covers) { - do + do { copy_or_blend_pix(p, *colors++, *covers++); p = p->next(); @@ -551,7 +551,7 @@ namespace agg { if (cover == cover_mask) { - do + do { copy_or_blend_pix(p, *colors++); p = p->next(); @@ -560,7 +560,7 @@ namespace agg } else { - do + do { copy_or_blend_pix(p, *colors++, cover); p = p->next(); @@ -569,18 +569,18 @@ namespace agg } } } - + //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors, const int8u* covers, int8u cover) { if (covers) { - do + do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); } @@ -590,7 +590,7 @@ namespace agg { if (cover == cover_mask) { - do + do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); } @@ -598,7 +598,7 @@ namespace agg } else { - do + do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); } @@ -642,15 +642,15 @@ namespace agg //-------------------------------------------------------------------- template - void copy_from(const RenBuf2& from, + void copy_from(const RenBuf2& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len) { if (const int8u* p = from.row_ptr(ysrc)) { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, + memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, + p + xsrc * pix_width, len * pix_width); } } @@ -658,7 +658,7 @@ namespace agg //-------------------------------------------------------------------- // Blend from single color, using grayscale surface as alpha channel. template - void blend_from_color(const SrcPixelFormatRenderer& from, + void blend_from_color(const SrcPixelFormatRenderer& from, const color_type& color, int xdst, int ydst, int xsrc, int ysrc, @@ -672,7 +672,7 @@ namespace agg { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); - do + do { copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); psrc = psrc->next(); @@ -686,7 +686,7 @@ namespace agg // Blend from color table, using grayscale surface as indexes into table. // Obviously, this only works for integer value types. template - void blend_from_lut(const SrcPixelFormatRenderer& from, + void blend_from_lut(const SrcPixelFormatRenderer& from, const color_type* color_lut, int xdst, int ydst, int xsrc, int ysrc, @@ -699,7 +699,7 @@ namespace agg { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); - do + do { copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); psrc = psrc->next(); diff --git a/src/agg/agg_pixfmt_rgb.h b/src/agg/agg_pixfmt_rgb.h index 6fa8772ce06..d06e79d5365 100644 --- a/src/agg/agg_pixfmt_rgb.h +++ b/src/agg/agg_pixfmt_rgb.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -13,12 +13,12 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for high precision colors has been sponsored by +// Adaptation for high precision colors has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- #ifndef AGG_PIXFMT_RGB_INCLUDED @@ -73,7 +73,7 @@ namespace agg //=========================================================blender_rgb - template + template struct blender_rgb { typedef ColorT color_type; @@ -87,14 +87,14 @@ namespace agg // initial premultiply and final demultiply. //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, + static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); } - + //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, + static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { p[Order::R] = color_type::lerp(p[Order::R], cr, alpha); @@ -104,7 +104,7 @@ namespace agg }; //======================================================blender_rgb_pre - template + template struct blender_rgb_pre { typedef ColorT color_type; @@ -114,21 +114,21 @@ namespace agg typedef typename color_type::long_type long_type; // Blend pixels using the premultiplied form of Alvy-Ray Smith's - // compositing function. + // compositing function. //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, + static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { - blend_pix(p, - color_type::mult_cover(cr, cover), - color_type::mult_cover(cg, cover), - color_type::mult_cover(cb, cover), + blend_pix(p, + color_type::mult_cover(cr, cover), + color_type::mult_cover(cg, cover), + color_type::mult_cover(cb, cover), color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, + static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { p[Order::R] = color_type::prelerp(p[Order::R], cr, alpha); @@ -138,7 +138,7 @@ namespace agg }; //===================================================blender_rgb_gamma - template + template class blender_rgb_gamma : public blender_base { public: @@ -154,14 +154,14 @@ namespace agg void gamma(const gamma_type& g) { m_gamma = &g; } //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(value_type* p, + AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); } - + //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(value_type* p, + AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { calc_type r = m_gamma->dir(p[Order::R]); @@ -171,14 +171,14 @@ namespace agg p[Order::G] = m_gamma->inv(color_type::downscale((m_gamma->dir(cg) - g) * alpha) + g); p[Order::B] = m_gamma->inv(color_type::downscale((m_gamma->dir(cb) - b) * alpha) + b); } - + private: const gamma_type* m_gamma; }; //==================================================pixfmt_alpha_blend_rgb - template + template class pixfmt_alpha_blend_rgb { public: @@ -190,7 +190,7 @@ namespace agg typedef typename blender_type::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; - enum + enum { num_components = 3, pix_step = Step, @@ -223,8 +223,8 @@ namespace agg color_type get() const { return color_type( - c[order_type::R], - c[order_type::G], + c[order_type::R], + c[order_type::G], c[order_type::B]); } @@ -251,15 +251,15 @@ namespace agg private: //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(pixel_type* p, - value_type r, value_type g, value_type b, value_type a, + AGG_INLINE void blend_pix(pixel_type* p, + value_type r, value_type g, value_type b, value_type a, unsigned cover) { m_blender.blend_pix(p->c, r, g, b, a, cover); } //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(pixel_type* p, + AGG_INLINE void blend_pix(pixel_type* p, value_type r, value_type g, value_type b, value_type a) { m_blender.blend_pix(p->c, r, g, b, a); @@ -324,7 +324,7 @@ namespace agg if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) { int stride = pixf.stride(); - m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), + m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), (r.x2 - r.x1) + 1, (r.y2 - r.y1) + 1, stride); @@ -347,37 +347,37 @@ namespace agg AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } //-------------------------------------------------------------------- - AGG_INLINE int8u* pix_ptr(int x, int y) - { + AGG_INLINE int8u* pix_ptr(int x, int y) + { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); } - AGG_INLINE const int8u* pix_ptr(int x, int y) const - { + AGG_INLINE const int8u* pix_ptr(int x, int y) const + { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); } // Return pointer to pixel value, forcing row to be allocated. - AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) + AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) { return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset)); } // Return pointer to pixel value, or null if row not allocated. - AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const + AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const { int8u* p = m_rbuf->row_ptr(y); return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0; } // Get pixel pointer from raw buffer pointer. - AGG_INLINE static pixel_type* pix_value_ptr(void* p) + AGG_INLINE static pixel_type* pix_value_ptr(void* p) { return (pixel_type*)((value_type*)p + pix_offset); } // Get pixel pointer from raw buffer pointer. - AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) + AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { return (const pixel_type*)((const value_type*)p + pix_offset); } @@ -425,8 +425,8 @@ namespace agg } //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, + AGG_INLINE void copy_hline(int x, int y, + unsigned len, const color_type& c) { pixel_type* p = pix_value_ptr(x, y, len); @@ -441,7 +441,7 @@ namespace agg //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, - unsigned len, + unsigned len, const color_type& c) { do @@ -453,7 +453,7 @@ namespace agg //-------------------------------------------------------------------- void blend_hline(int x, int y, - unsigned len, + unsigned len, const color_type& c, int8u cover) { @@ -485,7 +485,7 @@ namespace agg //-------------------------------------------------------------------- void blend_vline(int x, int y, - unsigned len, + unsigned len, const color_type& c, int8u cover) { @@ -512,7 +512,7 @@ namespace agg //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, - unsigned len, + unsigned len, const color_type& c, const int8u* covers) { @@ -520,7 +520,7 @@ namespace agg { pixel_type* p = pix_value_ptr(x, y, len); - do + do { if (c.is_opaque() && *covers == cover_mask) { @@ -540,13 +540,13 @@ namespace agg //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, - unsigned len, + unsigned len, const color_type& c, const int8u* covers) { if (!c.is_transparent()) { - do + do { pixel_type* p = pix_value_ptr(x, y++, 1); @@ -566,12 +566,12 @@ namespace agg //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors) { pixel_type* p = pix_value_ptr(x, y, len); - do + do { p->set(*colors++); p = p->next(); @@ -582,10 +582,10 @@ namespace agg //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors) { - do + do { pix_value_ptr(x, y++, 1)->set(*colors++); } @@ -594,7 +594,7 @@ namespace agg //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors, const int8u* covers, int8u cover) @@ -603,7 +603,7 @@ namespace agg if (covers) { - do + do { copy_or_blend_pix(p, *colors++, *covers++); p = p->next(); @@ -614,7 +614,7 @@ namespace agg { if (cover == cover_mask) { - do + do { copy_or_blend_pix(p, *colors++); p = p->next(); @@ -623,7 +623,7 @@ namespace agg } else { - do + do { copy_or_blend_pix(p, *colors++, cover); p = p->next(); @@ -635,14 +635,14 @@ namespace agg //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors, const int8u* covers, int8u cover) { if (covers) { - do + do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); } @@ -652,7 +652,7 @@ namespace agg { if (cover == cover_mask) { - do + do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); } @@ -660,7 +660,7 @@ namespace agg } else { - do + do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); } @@ -703,15 +703,15 @@ namespace agg //-------------------------------------------------------------------- template - void copy_from(const RenBuf2& from, + void copy_from(const RenBuf2& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len) { if (const int8u* p = from.row_ptr(ysrc)) { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, + memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, + p + xsrc * pix_width, len * pix_width); } } @@ -719,7 +719,7 @@ namespace agg //-------------------------------------------------------------------- // Blend from an RGBA surface. template - void blend_from(const SrcPixelFormatRenderer& from, + void blend_from(const SrcPixelFormatRenderer& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len, @@ -734,7 +734,7 @@ namespace agg if (cover == cover_mask) { - do + do { value_type alpha = psrc->c[src_order::A]; if (alpha <= color_type::empty_value()) @@ -747,7 +747,7 @@ namespace agg } else { - blend_pix(pdst, + blend_pix(pdst, psrc->c[src_order::R], psrc->c[src_order::G], psrc->c[src_order::B], @@ -761,7 +761,7 @@ namespace agg } else { - do + do { copy_or_blend_pix(pdst, psrc->get(), cover); psrc = psrc->next(); @@ -775,7 +775,7 @@ namespace agg //-------------------------------------------------------------------- // Blend from single color, using grayscale surface as alpha channel. template - void blend_from_color(const SrcPixelFormatRenderer& from, + void blend_from_color(const SrcPixelFormatRenderer& from, const color_type& color, int xdst, int ydst, int xsrc, int ysrc, @@ -789,7 +789,7 @@ namespace agg { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); - do + do { copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); psrc = psrc->next(); @@ -800,10 +800,10 @@ namespace agg } //-------------------------------------------------------------------- - // Blend from color table, using grayscale surface as indexes into table. + // Blend from color table, using grayscale surface as indexes into table. // Obviously, this only works for integer value types. template - void blend_from_lut(const SrcPixelFormatRenderer& from, + void blend_from_lut(const SrcPixelFormatRenderer& from, const color_type* color_lut, int xdst, int ydst, int xsrc, int ysrc, @@ -818,7 +818,7 @@ namespace agg if (cover == cover_mask) { - do + do { const color_type& color = color_lut[psrc->c[0]]; blend_pix(pdst, color); @@ -829,7 +829,7 @@ namespace agg } else { - do + do { copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); psrc = psrc->next(); @@ -844,7 +844,7 @@ namespace agg rbuf_type* m_rbuf; Blender m_blender; }; - + //----------------------------------------------------------------------- typedef blender_rgb blender_rgb24; typedef blender_rgb blender_bgr24; @@ -915,80 +915,80 @@ namespace agg typedef pixfmt_alpha_blend_rgb pixfmt_xrgb128_pre; typedef pixfmt_alpha_blend_rgb pixfmt_xbgr128_pre; typedef pixfmt_alpha_blend_rgb pixfmt_bgrx128_pre; - + //-----------------------------------------------------pixfmt_rgb24_gamma - template class pixfmt_rgb24_gamma : + template class pixfmt_rgb24_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_rgb24_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; - + //-----------------------------------------------------pixfmt_srgb24_gamma - template class pixfmt_srgb24_gamma : + template class pixfmt_srgb24_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_srgb24_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; - + //-----------------------------------------------------pixfmt_bgr24_gamma - template class pixfmt_bgr24_gamma : + template class pixfmt_bgr24_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_bgr24_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_sbgr24_gamma - template class pixfmt_sbgr24_gamma : + template class pixfmt_sbgr24_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_sbgr24_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_rgb48_gamma - template class pixfmt_rgb48_gamma : + template class pixfmt_rgb48_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_rgb48_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; - + //-----------------------------------------------------pixfmt_bgr48_gamma - template class pixfmt_bgr48_gamma : + template class pixfmt_bgr48_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_bgr48_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; - + } #endif diff --git a/src/agg/agg_rasterizer_cells_aa.h b/src/agg/agg_rasterizer_cells_aa.h index 1147148fa75..8c1aa174ae8 100644 --- a/src/agg/agg_rasterizer_cells_aa.h +++ b/src/agg/agg_rasterizer_cells_aa.h @@ -2,15 +2,15 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // -// The author gratefully acknowleges the support of David Turner, -// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType +// The author gratefully acknowleges the support of David Turner, +// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType // libray - in producing this work. See http://www.freetype.org for details. // //---------------------------------------------------------------------------- @@ -19,12 +19,12 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for 32-bit screen coordinates has been sponsored by +// Adaptation for 32-bit screen coordinates has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- #ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED #define AGG_RASTERIZER_CELLS_AA_INCLUDED @@ -77,19 +77,19 @@ namespace agg void sort_cells(); - unsigned total_cells() const + unsigned total_cells() const { return m_num_cells; } - unsigned scanline_num_cells(unsigned y) const - { - return m_sorted_y[y - m_min_y].num; + unsigned scanline_num_cells(unsigned y) const + { + return m_sorted_y[y - m_min_y].num; } const cell_type* const* scanline_cells(unsigned y) const - { - return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start; + { + return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start; } bool sorted() const { return m_sorted; } @@ -102,7 +102,7 @@ namespace agg void add_curr_cell(); void render_hline(int ey, int x1, int y1, int x2, int y2); void allocate_block(); - + private: unsigned m_num_blocks; unsigned m_max_blocks; @@ -125,7 +125,7 @@ namespace agg //------------------------------------------------------------------------ - template + template rasterizer_cells_aa::~rasterizer_cells_aa() { if(m_num_blocks) @@ -141,7 +141,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template rasterizer_cells_aa::rasterizer_cells_aa() : m_num_blocks(0), m_max_blocks(0), @@ -162,10 +162,10 @@ namespace agg } //------------------------------------------------------------------------ - template + template void rasterizer_cells_aa::reset() { - m_num_cells = 0; + m_num_cells = 0; m_curr_block = 0; m_curr_cell.initial(); m_style_cell.initial(); @@ -177,7 +177,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template AGG_INLINE void rasterizer_cells_aa::add_curr_cell() { if(m_curr_cell.area | m_curr_cell.cover) @@ -193,7 +193,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template AGG_INLINE void rasterizer_cells_aa::set_curr_cell(int x, int y) { if(m_curr_cell.not_equal(x, y, m_style_cell)) @@ -208,9 +208,9 @@ namespace agg } //------------------------------------------------------------------------ - template - AGG_INLINE void rasterizer_cells_aa::render_hline(int ey, - int x1, int y1, + template + AGG_INLINE void rasterizer_cells_aa::render_hline(int ey, + int x1, int y1, int x2, int y2) { int ex1 = x1 >> poly_subpixel_shift; @@ -307,14 +307,14 @@ namespace agg } //------------------------------------------------------------------------ - template + template AGG_INLINE void rasterizer_cells_aa::style(const cell_type& style_cell) - { - m_style_cell.style(style_cell); + { + m_style_cell.style(style_cell); } //------------------------------------------------------------------------ - template + template void rasterizer_cells_aa::line(int x1, int y1, int x2, int y2) { enum dx_limit_e { dx_limit = 16384 << poly_subpixel_shift }; @@ -361,7 +361,7 @@ namespace agg //Vertical line - we have to calculate start and end cells, //and then - the common values of the area and coverage for - //all cells of the line. We know exactly there's only one + //all cells of the line. We know exactly there's only one //cell, so, we don't have to call render_hline(). incr = 1; if(dx == 0) @@ -466,15 +466,15 @@ namespace agg } //------------------------------------------------------------------------ - template + template void rasterizer_cells_aa::allocate_block() { if(m_curr_block >= m_num_blocks) { if(m_num_blocks >= m_max_blocks) { - cell_type** new_cells = - pod_allocator::allocate(m_max_blocks + + cell_type** new_cells = + pod_allocator::allocate(m_max_blocks + cell_block_pool); if(m_cells) @@ -486,7 +486,7 @@ namespace agg m_max_blocks += cell_block_pool; } - m_cells[m_num_blocks++] = + m_cells[m_num_blocks++] = pod_allocator::allocate(cell_block_size); } @@ -516,7 +516,7 @@ namespace agg void qsort_cells(Cell** start, unsigned num) { Cell** stack[80]; - Cell*** top; + Cell*** top; Cell** limit; Cell** base; @@ -541,7 +541,7 @@ namespace agg i = base + 1; j = limit - 1; - // now ensure that *i <= *base <= *j + // now ensure that *i <= *base <= *j if((*j)->x < (*i)->x) { swap_cells(i, j); @@ -622,7 +622,7 @@ namespace agg //------------------------------------------------------------------------ - template + template void rasterizer_cells_aa::sort_cells() { if(m_sorted) return; //Perform sort only the first time. @@ -639,9 +639,9 @@ namespace agg //for(unsigned nc = 0; nc < m_num_cells; nc++) //{ // cell_type* cell = m_cells[nc >> cell_block_shift] + (nc & cell_block_mask); -// if(cell->x < m_min_x || -// cell->y < m_min_y || -// cell->x > m_max_x || +// if(cell->x < m_min_x || +// cell->y < m_min_y || +// cell->x > m_max_x || // cell->y > m_max_y) // { // cell = cell; // Breakpoint here @@ -664,7 +664,7 @@ namespace agg cell_ptr = *block_ptr++; i = (nb > cell_block_size) ? unsigned(cell_block_size) : nb; nb -= i; - while(i--) + while(i--) { m_sorted_y[cell_ptr->y - m_min_y].start++; ++cell_ptr; @@ -696,7 +696,7 @@ namespace agg ++cell_ptr; } } - + // Finally arrange the X-arrays for(i = 0; i < m_sorted_y.size(); i++) { diff --git a/src/agg/agg_rasterizer_scanline_aa.h b/src/agg/agg_rasterizer_scanline_aa.h index 4925ca20924..4d324457851 100644 --- a/src/agg/agg_rasterizer_scanline_aa.h +++ b/src/agg/agg_rasterizer_scanline_aa.h @@ -2,15 +2,15 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // -// The author gratefully acknowleges the support of David Turner, -// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType +// The author gratefully acknowleges the support of David Turner, +// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType // libray - in producing this work. See http://www.freetype.org for details. // //---------------------------------------------------------------------------- @@ -19,12 +19,12 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for 32-bit screen coordinates has been sponsored by +// Adaptation for 32-bit screen coordinates has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED @@ -38,10 +38,10 @@ namespace agg { //==================================================rasterizer_scanline_aa - // Polygon rasterizer that is used to render filled polygons with - // high-quality Anti-Aliasing. Internally, by default, the class uses - // integer coordinates in format 24.8, i.e. 24 bits for integer part - // and 8 bits for fractional - see poly_subpixel_shift. This class can be + // Polygon rasterizer that is used to render filled polygons with + // high-quality Anti-Aliasing. Internally, by default, the class uses + // integer coordinates in format 24.8, i.e. 24 bits for integer part + // and 8 bits for fractional - see poly_subpixel_shift. This class can be // used in the following way: // // 1. filling_rule(filling_rule_e ft) - optional. @@ -50,20 +50,20 @@ namespace agg // // 3. reset() // - // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create + // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create // more than one contour, but each contour must consist of at least 3 // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3); // is the absolute minimum of vertices that define a triangle. // The algorithm does not check either the number of vertices nor - // coincidence of their coordinates, but in the worst case it just + // coincidence of their coordinates, but in the worst case it just // won't draw anything. - // The orger of the vertices (clockwise or counterclockwise) + // The orger of the vertices (clockwise or counterclockwise) // is important when using the non-zero filling rule (fill_non_zero). // In this case the vertex order of all the contours must be the same // if you want your intersecting polygons to be without "holes". - // You actually can use different vertices order. If the contours do not - // intersect each other the order is not important anyway. If they do, - // contours with the same vertex order will be rendered without "holes" + // You actually can use different vertices order. If the contours do not + // intersect each other the order is not important anyway. If they do, + // contours with the same vertex order will be rendered without "holes" // while the intersecting contours with different orders will have "holes". // // filling_rule() and gamma() can be called anytime before "sweeping". @@ -93,7 +93,7 @@ namespace agg }; //-------------------------------------------------------------------- - rasterizer_scanline_aa() : + rasterizer_scanline_aa() : m_outline(), m_clipper(), m_filling_rule(fill_non_zero), @@ -107,8 +107,8 @@ namespace agg } //-------------------------------------------------------------------- - template - rasterizer_scanline_aa(const GammaF& gamma_function) : + template + rasterizer_scanline_aa(const GammaF& gamma_function) : m_outline(), m_clipper(m_outline), m_filling_rule(fill_non_zero), @@ -121,7 +121,7 @@ namespace agg } //-------------------------------------------------------------------- - void reset(); + void reset(); void reset_clipping(); void clip_box(double x1, double y1, double x2, double y2); void filling_rule(filling_rule_e filling_rule); @@ -129,7 +129,7 @@ namespace agg //-------------------------------------------------------------------- template void gamma(const GammaF& gamma_function) - { + { int i; for(i = 0; i < aa_scale; i++) { @@ -138,9 +138,9 @@ namespace agg } //-------------------------------------------------------------------- - unsigned apply_gamma(unsigned cover) const - { - return m_gamma[cover]; + unsigned apply_gamma(unsigned cover) const + { + return m_gamma[cover]; } //-------------------------------------------------------------------- @@ -169,7 +169,7 @@ namespace agg add_vertex(x, y, cmd); } } - + //-------------------------------------------------------------------- int min_x() const { return m_outline.min_x(); } int min_y() const { return m_outline.min_y(); } @@ -247,7 +247,7 @@ namespace agg } } } - + if(sl.num_spans()) break; ++m_scan_y; } @@ -265,7 +265,7 @@ namespace agg //-------------------------------------------------------------------- // Disable copying rasterizer_scanline_aa(const rasterizer_scanline_aa&); - const rasterizer_scanline_aa& + const rasterizer_scanline_aa& operator = (const rasterizer_scanline_aa&); private: @@ -292,32 +292,32 @@ namespace agg //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::reset() - { - m_outline.reset(); + template + void rasterizer_scanline_aa::reset() + { + m_outline.reset(); m_status = status_initial; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::filling_rule(filling_rule_e filling_rule) - { - m_filling_rule = filling_rule; + template + void rasterizer_scanline_aa::filling_rule(filling_rule_e filling_rule) + { + m_filling_rule = filling_rule; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::clip_box(double x1, double y1, + template + void rasterizer_scanline_aa::clip_box(double x1, double y1, double x2, double y2) { reset(); - m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), + m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), conv_type::upscale(x2), conv_type::upscale(y2)); } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::reset_clipping() { reset(); @@ -325,7 +325,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::close_polygon() { if(m_status == status_line_to) @@ -336,56 +336,56 @@ namespace agg } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::move_to(int x, int y) { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); - m_clipper.move_to(m_start_x = conv_type::downscale(x), + m_clipper.move_to(m_start_x = conv_type::downscale(x), m_start_y = conv_type::downscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::line_to(int x, int y) { - m_clipper.line_to(m_outline, - conv_type::downscale(x), + m_clipper.line_to(m_outline, + conv_type::downscale(x), conv_type::downscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::move_to_d(double x, double y) - { + template + void rasterizer_scanline_aa::move_to_d(double x, double y) + { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); - m_clipper.move_to(m_start_x = conv_type::upscale(x), - m_start_y = conv_type::upscale(y)); + m_clipper.move_to(m_start_x = conv_type::upscale(x), + m_start_y = conv_type::upscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::line_to_d(double x, double y) - { - m_clipper.line_to(m_outline, - conv_type::upscale(x), - conv_type::upscale(y)); + template + void rasterizer_scanline_aa::line_to_d(double x, double y) + { + m_clipper.line_to(m_outline, + conv_type::upscale(x), + conv_type::upscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::add_vertex(double x, double y, unsigned cmd) { - if(is_move_to(cmd)) + if(is_move_to(cmd)) { move_to_d(x, y); } - else + else if(is_vertex(cmd)) { line_to_d(x, y); @@ -398,32 +398,32 @@ namespace agg } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::edge(int x1, int y1, int x2, int y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); - m_clipper.line_to(m_outline, - conv_type::downscale(x2), + m_clipper.line_to(m_outline, + conv_type::downscale(x2), conv_type::downscale(y2)); m_status = status_move_to; } - + //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::edge_d(double x1, double y1, + template + void rasterizer_scanline_aa::edge_d(double x1, double y1, double x2, double y2) { if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); - m_clipper.line_to(m_outline, - conv_type::upscale(x2), - conv_type::upscale(y2)); + m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); + m_clipper.line_to(m_outline, + conv_type::upscale(x2), + conv_type::upscale(y2)); m_status = status_move_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::sort() { if(m_auto_close) close_polygon(); @@ -431,12 +431,12 @@ namespace agg } //------------------------------------------------------------------------ - template + template AGG_INLINE bool rasterizer_scanline_aa::rewind_scanlines() { if(m_auto_close) close_polygon(); m_outline.sort_cells(); - if(m_outline.total_cells() == 0) + if(m_outline.total_cells() == 0) { return false; } @@ -446,14 +446,14 @@ namespace agg //------------------------------------------------------------------------ - template + template AGG_INLINE bool rasterizer_scanline_aa::navigate_scanline(int y) { if(m_auto_close) close_polygon(); m_outline.sort_cells(); - if(m_outline.total_cells() == 0 || - y < m_outline.min_y() || - y > m_outline.max_y()) + if(m_outline.total_cells() == 0 || + y < m_outline.min_y() || + y > m_outline.max_y()) { return false; } @@ -462,7 +462,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template bool rasterizer_scanline_aa::hit_test(int tx, int ty) { if(!navigate_scanline(ty)) return false; diff --git a/src/agg/agg_rasterizer_scanline_aa_nogamma.h b/src/agg/agg_rasterizer_scanline_aa_nogamma.h index 9a809aa5ae3..d66620fd163 100644 --- a/src/agg/agg_rasterizer_scanline_aa_nogamma.h +++ b/src/agg/agg_rasterizer_scanline_aa_nogamma.h @@ -2,15 +2,15 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // -// The author gratefully acknowleges the support of David Turner, -// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType +// The author gratefully acknowleges the support of David Turner, +// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType // libray - in producing this work. See http://www.freetype.org for details. // //---------------------------------------------------------------------------- @@ -19,12 +19,12 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for 32-bit screen coordinates has been sponsored by +// Adaptation for 32-bit screen coordinates has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- #ifndef AGG_RASTERIZER_SCANLINE_AA_NOGAMMA_INCLUDED #define AGG_RASTERIZER_SCANLINE_AA_NOGAMMA_INCLUDED @@ -39,8 +39,8 @@ namespace agg //-----------------------------------------------------------------cell_aa - // A pixel cell. There're no constructors defined and it was done - // intentionally in order to avoid extra overhead when allocating an + // A pixel cell. There're no constructors defined and it was done + // intentionally in order to avoid extra overhead when allocating an // array of cells. struct cell_aa { @@ -67,10 +67,10 @@ namespace agg //==================================================rasterizer_scanline_aa_nogamma - // Polygon rasterizer that is used to render filled polygons with - // high-quality Anti-Aliasing. Internally, by default, the class uses - // integer coordinates in format 24.8, i.e. 24 bits for integer part - // and 8 bits for fractional - see poly_subpixel_shift. This class can be + // Polygon rasterizer that is used to render filled polygons with + // high-quality Anti-Aliasing. Internally, by default, the class uses + // integer coordinates in format 24.8, i.e. 24 bits for integer part + // and 8 bits for fractional - see poly_subpixel_shift. This class can be // used in the following way: // // 1. filling_rule(filling_rule_e ft) - optional. @@ -79,20 +79,20 @@ namespace agg // // 3. reset() // - // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create + // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create // more than one contour, but each contour must consist of at least 3 // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3); // is the absolute minimum of vertices that define a triangle. // The algorithm does not check either the number of vertices nor - // coincidence of their coordinates, but in the worst case it just + // coincidence of their coordinates, but in the worst case it just // won't draw anything. - // The orger of the vertices (clockwise or counterclockwise) + // The orger of the vertices (clockwise or counterclockwise) // is important when using the non-zero filling rule (fill_non_zero). // In this case the vertex order of all the contours must be the same // if you want your intersecting polygons to be without "holes". - // You actually can use different vertices order. If the contours do not - // intersect each other the order is not important anyway. If they do, - // contours with the same vertex order will be rendered without "holes" + // You actually can use different vertices order. If the contours do not + // intersect each other the order is not important anyway. If they do, + // contours with the same vertex order will be rendered without "holes" // while the intersecting contours with different orders will have "holes". // // filling_rule() and gamma() can be called anytime before "sweeping". @@ -122,7 +122,7 @@ namespace agg }; //-------------------------------------------------------------------- - rasterizer_scanline_aa_nogamma() : + rasterizer_scanline_aa_nogamma() : m_outline(), m_clipper(), m_filling_rule(fill_non_zero), @@ -134,15 +134,15 @@ namespace agg } //-------------------------------------------------------------------- - void reset(); + void reset(); void reset_clipping(); void clip_box(double x1, double y1, double x2, double y2); void filling_rule(filling_rule_e filling_rule); void auto_close(bool flag) { m_auto_close = flag; } //-------------------------------------------------------------------- - unsigned apply_gamma(unsigned cover) const - { + unsigned apply_gamma(unsigned cover) const + { return cover; } @@ -172,7 +172,7 @@ namespace agg add_vertex(x, y, cmd); } } - + //-------------------------------------------------------------------- int min_x() const { return m_outline.min_x(); } int min_y() const { return m_outline.min_y(); } @@ -250,7 +250,7 @@ namespace agg } } } - + if(sl.num_spans()) break; ++m_scan_y; } @@ -268,7 +268,7 @@ namespace agg //-------------------------------------------------------------------- // Disable copying rasterizer_scanline_aa_nogamma(const rasterizer_scanline_aa_nogamma&); - const rasterizer_scanline_aa_nogamma& + const rasterizer_scanline_aa_nogamma& operator = (const rasterizer_scanline_aa_nogamma&); private: @@ -294,32 +294,32 @@ namespace agg //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa_nogamma::reset() - { - m_outline.reset(); + template + void rasterizer_scanline_aa_nogamma::reset() + { + m_outline.reset(); m_status = status_initial; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa_nogamma::filling_rule(filling_rule_e filling_rule) - { - m_filling_rule = filling_rule; + template + void rasterizer_scanline_aa_nogamma::filling_rule(filling_rule_e filling_rule) + { + m_filling_rule = filling_rule; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa_nogamma::clip_box(double x1, double y1, + template + void rasterizer_scanline_aa_nogamma::clip_box(double x1, double y1, double x2, double y2) { reset(); - m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), + m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), conv_type::upscale(x2), conv_type::upscale(y2)); } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa_nogamma::reset_clipping() { reset(); @@ -327,7 +327,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa_nogamma::close_polygon() { if(m_status == status_line_to) @@ -338,56 +338,56 @@ namespace agg } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa_nogamma::move_to(int x, int y) { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); - m_clipper.move_to(m_start_x = conv_type::downscale(x), + m_clipper.move_to(m_start_x = conv_type::downscale(x), m_start_y = conv_type::downscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa_nogamma::line_to(int x, int y) { - m_clipper.line_to(m_outline, - conv_type::downscale(x), + m_clipper.line_to(m_outline, + conv_type::downscale(x), conv_type::downscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa_nogamma::move_to_d(double x, double y) - { + template + void rasterizer_scanline_aa_nogamma::move_to_d(double x, double y) + { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); - m_clipper.move_to(m_start_x = conv_type::upscale(x), - m_start_y = conv_type::upscale(y)); + m_clipper.move_to(m_start_x = conv_type::upscale(x), + m_start_y = conv_type::upscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa_nogamma::line_to_d(double x, double y) - { - m_clipper.line_to(m_outline, - conv_type::upscale(x), - conv_type::upscale(y)); + template + void rasterizer_scanline_aa_nogamma::line_to_d(double x, double y) + { + m_clipper.line_to(m_outline, + conv_type::upscale(x), + conv_type::upscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa_nogamma::add_vertex(double x, double y, unsigned cmd) { - if(is_move_to(cmd)) + if(is_move_to(cmd)) { move_to_d(x, y); } - else + else if(is_vertex(cmd)) { line_to_d(x, y); @@ -400,32 +400,32 @@ namespace agg } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa_nogamma::edge(int x1, int y1, int x2, int y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); - m_clipper.line_to(m_outline, - conv_type::downscale(x2), + m_clipper.line_to(m_outline, + conv_type::downscale(x2), conv_type::downscale(y2)); m_status = status_move_to; } - + //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa_nogamma::edge_d(double x1, double y1, + template + void rasterizer_scanline_aa_nogamma::edge_d(double x1, double y1, double x2, double y2) { if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); - m_clipper.line_to(m_outline, - conv_type::upscale(x2), - conv_type::upscale(y2)); + m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); + m_clipper.line_to(m_outline, + conv_type::upscale(x2), + conv_type::upscale(y2)); m_status = status_move_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa_nogamma::sort() { if(m_auto_close) close_polygon(); @@ -433,12 +433,12 @@ namespace agg } //------------------------------------------------------------------------ - template + template AGG_INLINE bool rasterizer_scanline_aa_nogamma::rewind_scanlines() { if(m_auto_close) close_polygon(); m_outline.sort_cells(); - if(m_outline.total_cells() == 0) + if(m_outline.total_cells() == 0) { return false; } @@ -448,14 +448,14 @@ namespace agg //------------------------------------------------------------------------ - template + template AGG_INLINE bool rasterizer_scanline_aa_nogamma::navigate_scanline(int y) { if(m_auto_close) close_polygon(); m_outline.sort_cells(); - if(m_outline.total_cells() == 0 || - y < m_outline.min_y() || - y > m_outline.max_y()) + if(m_outline.total_cells() == 0 || + y < m_outline.min_y() || + y > m_outline.max_y()) { return false; } @@ -464,7 +464,7 @@ namespace agg } //------------------------------------------------------------------------ - template + template bool rasterizer_scanline_aa_nogamma::hit_test(int tx, int ty) { if(!navigate_scanline(ty)) return false; diff --git a/src/agg/agg_rasterizer_sl_clip.h b/src/agg/agg_rasterizer_sl_clip.h index 3a7f3a1033d..d3031c97111 100644 --- a/src/agg/agg_rasterizer_sl_clip.h +++ b/src/agg/agg_rasterizer_sl_clip.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -24,7 +24,7 @@ namespace agg { poly_max_coord = (1 << 30) - 1 //----poly_max_coord }; - + //------------------------------------------------------------ras_conv_int struct ras_conv_int { @@ -49,9 +49,9 @@ namespace agg } static int xi(int v) { return v; } static int yi(int v) { return v; } - static int upscale(double v) - { - return saturation::iround(v * poly_subpixel_scale); + static int upscale(double v) + { + return saturation::iround(v * poly_subpixel_scale); } static int downscale(int v) { return v; } }; @@ -111,12 +111,12 @@ namespace agg typedef rect_base rect_type; //-------------------------------------------------------------------- - rasterizer_sl_clip() : + rasterizer_sl_clip() : m_clip_box(0,0,0,0), m_x1(0), m_y1(0), m_f1(0), - m_clipping(false) + m_clipping(false) {} //-------------------------------------------------------------------- @@ -145,8 +145,8 @@ namespace agg //------------------------------------------------------------------------ template AGG_INLINE void line_clip_y(Rasterizer& ras, - coord_type x1, coord_type y1, - coord_type x2, coord_type y2, + coord_type x1, coord_type y1, + coord_type x2, coord_type y2, unsigned f1, unsigned f2) const { f1 &= 10; @@ -154,7 +154,7 @@ namespace agg if((f1 | f2) == 0) { // Fully visible - ras.line(Conv::xi(x1), Conv::yi(y1), Conv::xi(x2), Conv::yi(y2)); + ras.line(Conv::xi(x1), Conv::yi(y1), Conv::xi(x2), Conv::yi(y2)); } else { @@ -192,8 +192,8 @@ namespace agg tx2 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1); ty2 = m_clip_box.y2; } - ras.line(Conv::xi(tx1), Conv::yi(ty1), - Conv::xi(tx2), Conv::yi(ty2)); + ras.line(Conv::xi(tx1), Conv::yi(ty1), + Conv::xi(tx2), Conv::yi(ty2)); } } @@ -288,8 +288,8 @@ namespace agg } else { - ras.line(Conv::xi(m_x1), Conv::yi(m_y1), - Conv::xi(x2), Conv::yi(y2)); + ras.line(Conv::xi(m_x1), Conv::yi(m_y1), + Conv::xi(x2), Conv::yi(y2)); } m_x1 = x2; m_y1 = y2; @@ -321,10 +321,10 @@ namespace agg void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; } template - void line_to(Rasterizer& ras, coord_type x2, coord_type y2) - { - ras.line(m_x1, m_y1, x2, y2); - m_x1 = x2; + void line_to(Rasterizer& ras, coord_type x2, coord_type y2) + { + ras.line(m_x1, m_y1, x2, y2); + m_x1 = x2; m_y1 = y2; } diff --git a/src/agg/agg_renderer_base.h b/src/agg/agg_renderer_base.h index 527c62f7891..07d739886f6 100644 --- a/src/agg/agg_renderer_base.h +++ b/src/agg/agg_renderer_base.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -49,7 +49,7 @@ namespace agg //-------------------------------------------------------------------- const pixfmt_type& ren() const { return *m_ren; } pixfmt_type& ren() { return *m_ren; } - + //-------------------------------------------------------------------- unsigned width() const { return m_ren->width(); } unsigned height() const { return m_ren->height(); } @@ -132,7 +132,7 @@ namespace agg } } } - + //-------------------------------------------------------------------- void fill(const color_type& c) @@ -146,7 +146,7 @@ namespace agg } } } - + //-------------------------------------------------------------------- void copy_pixel(int x, int y, const color_type& c) { @@ -168,7 +168,7 @@ namespace agg //-------------------------------------------------------------------- color_type pixel(int x, int y) const { - return inbox(x, y) ? + return inbox(x, y) ? m_ren->pixel(x, y) : color_type::no_color(); } @@ -204,7 +204,7 @@ namespace agg } //-------------------------------------------------------------------- - void blend_hline(int x1, int y, int x2, + void blend_hline(int x1, int y, int x2, const color_type& c, cover_type cover) { if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } @@ -220,7 +220,7 @@ namespace agg } //-------------------------------------------------------------------- - void blend_vline(int x, int y1, int y2, + void blend_vline(int x, int y1, int y2, const color_type& c, cover_type cover) { if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } @@ -252,7 +252,7 @@ namespace agg } //-------------------------------------------------------------------- - void blend_bar(int x1, int y1, int x2, int y2, + void blend_bar(int x1, int y1, int x2, int y2, const color_type& c, cover_type cover) { rect_i rc(x1, y1, x2, y2); @@ -264,16 +264,16 @@ namespace agg { m_ren->blend_hline(rc.x1, y, - unsigned(rc.x2 - rc.x1 + 1), - c, + unsigned(rc.x2 - rc.x1 + 1), + c, cover); } } } //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, int len, - const color_type& c, + void blend_solid_hspan(int x, int y, int len, + const color_type& c, const cover_type* covers) { if(y > ymax()) return; @@ -295,8 +295,8 @@ namespace agg } //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, int len, - const color_type& c, + void blend_solid_vspan(int x, int y, int len, + const color_type& c, const cover_type* covers) { if(x > xmax()) return; @@ -365,8 +365,8 @@ namespace agg //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, int len, - const color_type* colors, + void blend_color_hspan(int x, int y, int len, + const color_type* colors, const cover_type* covers, cover_type cover = agg::cover_full) { @@ -391,8 +391,8 @@ namespace agg } //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, int len, - const color_type* colors, + void blend_color_vspan(int x, int y, int len, + const color_type* colors, const cover_type* covers, cover_type cover = agg::cover_full) { @@ -462,15 +462,15 @@ namespace agg //-------------------------------------------------------------------- template - void copy_from(const RenBuf& src, - const rect_i* rect_src_ptr = 0, - int dx = 0, + void copy_from(const RenBuf& src, + const rect_i* rect_src_ptr = 0, + int dx = 0, int dy = 0) { rect_i rsrc(0, 0, src.width(), src.height()); if(rect_src_ptr) { - rsrc.x1 = rect_src_ptr->x1; + rsrc.x1 = rect_src_ptr->x1; rsrc.y1 = rect_src_ptr->y1; rsrc.x2 = rect_src_ptr->x2 + 1; rsrc.y2 = rect_src_ptr->y2 + 1; @@ -495,7 +495,7 @@ namespace agg } while(rc.y2 > 0) { - m_ren->copy_from(src, + m_ren->copy_from(src, rdst.x1, rdst.y1, rsrc.x1, rsrc.y1, rc.x2); @@ -508,16 +508,16 @@ namespace agg //-------------------------------------------------------------------- template - void blend_from(const SrcPixelFormatRenderer& src, - const rect_i* rect_src_ptr = 0, - int dx = 0, + void blend_from(const SrcPixelFormatRenderer& src, + const rect_i* rect_src_ptr = 0, + int dx = 0, int dy = 0, cover_type cover = agg::cover_full) { rect_i rsrc(0, 0, src.width(), src.height()); if(rect_src_ptr) { - rsrc.x1 = rect_src_ptr->x1; + rsrc.x1 = rect_src_ptr->x1; rsrc.y1 = rect_src_ptr->y1; rsrc.x2 = rect_src_ptr->x2 + 1; rsrc.y2 = rect_src_ptr->y2 + 1; @@ -578,17 +578,17 @@ namespace agg //-------------------------------------------------------------------- template - void blend_from_color(const SrcPixelFormatRenderer& src, + void blend_from_color(const SrcPixelFormatRenderer& src, const color_type& color, - const rect_i* rect_src_ptr = 0, - int dx = 0, + const rect_i* rect_src_ptr = 0, + int dx = 0, int dy = 0, cover_type cover = agg::cover_full) { rect_i rsrc(0, 0, src.width(), src.height()); if(rect_src_ptr) { - rsrc.x1 = rect_src_ptr->x1; + rsrc.x1 = rect_src_ptr->x1; rsrc.y1 = rect_src_ptr->y1; rsrc.x2 = rect_src_ptr->x2 + 1; rsrc.y2 = rect_src_ptr->y2 + 1; @@ -650,17 +650,17 @@ namespace agg //-------------------------------------------------------------------- template - void blend_from_lut(const SrcPixelFormatRenderer& src, + void blend_from_lut(const SrcPixelFormatRenderer& src, const color_type* color_lut, - const rect_i* rect_src_ptr = 0, - int dx = 0, + const rect_i* rect_src_ptr = 0, + int dx = 0, int dy = 0, cover_type cover = agg::cover_full) { rect_i rsrc(0, 0, src.width(), src.height()); if(rect_src_ptr) { - rsrc.x1 = rect_src_ptr->x1; + rsrc.x1 = rect_src_ptr->x1; rsrc.y1 = rect_src_ptr->y1; rsrc.x2 = rect_src_ptr->x2 + 1; rsrc.y2 = rect_src_ptr->y2 + 1; diff --git a/src/agg/agg_renderer_scanline.h b/src/agg/agg_renderer_scanline.h index 311e9f739a7..963f2d9a2bf 100644 --- a/src/agg/agg_renderer_scanline.h +++ b/src/agg/agg_renderer_scanline.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -25,9 +25,9 @@ namespace agg { //================================================render_scanline_aa_solid - template - void render_scanline_aa_solid(const Scanline& sl, - BaseRenderer& ren, + template + void render_scanline_aa_solid(const Scanline& sl, + BaseRenderer& ren, const ColorT& color) { int y = sl.y(); @@ -39,14 +39,14 @@ namespace agg int x = span->x; if(span->len > 0) { - ren.blend_solid_hspan(x, y, (unsigned)span->len, - color, + ren.blend_solid_hspan(x, y, (unsigned)span->len, + color, span->covers); } else { - ren.blend_hline(x, y, (unsigned)(x - span->len - 1), - color, + ren.blend_hline(x, y, (unsigned)(x - span->len - 1), + color, *(span->covers)); } if(--num_spans == 0) break; @@ -55,16 +55,16 @@ namespace agg } //===============================================render_scanlines_aa_solid - template - void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl, + void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, const ColorT& color) { if(ras.rewind_scanlines()) { // Explicitly convert "color" to the BaseRenderer color type. // For example, it can be called with color type "rgba", while - // "rgba8" is needed. Otherwise it will be implicitly + // "rgba8" is needed. Otherwise it will be implicitly // converted in the loop many times. //---------------------- typename BaseRenderer::color_type ren_color = color; @@ -74,7 +74,7 @@ namespace agg { //render_scanline_aa_solid(sl, ren, ren_color); - // This code is equivalent to the above call (copy/paste). + // This code is equivalent to the above call (copy/paste). // It's just a "manual" optimization for old compilers, // like Microsoft Visual C++ v6.0 //------------------------------- @@ -87,14 +87,14 @@ namespace agg int x = span->x; if(span->len > 0) { - ren.blend_solid_hspan(x, y, (unsigned)span->len, - ren_color, + ren.blend_solid_hspan(x, y, (unsigned)span->len, + ren_color, span->covers); } else { - ren.blend_hline(x, y, (unsigned)(x - span->len - 1), - ren_color, + ren.blend_hline(x, y, (unsigned)(x - span->len - 1), + ren_color, *(span->covers)); } if(--num_spans == 0) break; @@ -118,7 +118,7 @@ namespace agg { m_ren = &ren; } - + //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } @@ -131,7 +131,7 @@ namespace agg { render_scanline_aa_solid(sl, *m_ren, m_color); } - + private: base_ren_type* m_ren; color_type m_color; @@ -150,9 +150,9 @@ namespace agg //======================================================render_scanline_aa - template - void render_scanline_aa(const Scanline& sl, BaseRenderer& ren, + template + void render_scanline_aa(const Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { int y = sl.y(); @@ -168,7 +168,7 @@ namespace agg if(len < 0) len = -len; typename BaseRenderer::color_type* colors = alloc.allocate(len); span_gen.generate(colors, x, y, len); - ren.blend_color_hspan(x, y, len, colors, + ren.blend_color_hspan(x, y, len, colors, (span->len < 0) ? 0 : covers, *covers); if(--num_spans == 0) break; @@ -177,9 +177,9 @@ namespace agg } //=====================================================render_scanlines_aa - template - void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, + void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { if(ras.rewind_scanlines()) @@ -194,7 +194,7 @@ namespace agg } //====================================================renderer_scanline_aa - template + template class renderer_scanline_aa { public: @@ -204,22 +204,22 @@ namespace agg //-------------------------------------------------------------------- renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {} - renderer_scanline_aa(base_ren_type& ren, - alloc_type& alloc, + renderer_scanline_aa(base_ren_type& ren, + alloc_type& alloc, span_gen_type& span_gen) : m_ren(&ren), m_alloc(&alloc), m_span_gen(&span_gen) {} - void attach(base_ren_type& ren, - alloc_type& alloc, + void attach(base_ren_type& ren, + alloc_type& alloc, span_gen_type& span_gen) { m_ren = &ren; m_alloc = &alloc; m_span_gen = &span_gen; } - + //-------------------------------------------------------------------- void prepare() { m_span_gen->prepare(); } @@ -241,21 +241,21 @@ namespace agg //===============================================render_scanline_bin_solid - template - void render_scanline_bin_solid(const Scanline& sl, - BaseRenderer& ren, + template + void render_scanline_bin_solid(const Scanline& sl, + BaseRenderer& ren, const ColorT& color) { unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { - ren.blend_hline(span->x, - sl.y(), - span->x - 1 + ((span->len < 0) ? - -span->len : - span->len), - color, + ren.blend_hline(span->x, + sl.y(), + span->x - 1 + ((span->len < 0) ? + -span->len : + span->len), + color, cover_full); if(--num_spans == 0) break; ++span; @@ -263,16 +263,16 @@ namespace agg } //==============================================render_scanlines_bin_solid - template - void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl, + void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, const ColorT& color) { if(ras.rewind_scanlines()) { // Explicitly convert "color" to the BaseRenderer color type. // For example, it can be called with color type "rgba", while - // "rgba8" is needed. Otherwise it will be implicitly + // "rgba8" is needed. Otherwise it will be implicitly // converted in the loop many times. //---------------------- typename BaseRenderer::color_type ren_color(color); @@ -282,7 +282,7 @@ namespace agg { //render_scanline_bin_solid(sl, ren, ren_color); - // This code is equivalent to the above call (copy/paste). + // This code is equivalent to the above call (copy/paste). // It's just a "manual" optimization for old compilers, // like Microsoft Visual C++ v6.0 //------------------------------- @@ -290,12 +290,12 @@ namespace agg typename Scanline::const_iterator span = sl.begin(); for(;;) { - ren.blend_hline(span->x, - sl.y(), - span->x - 1 + ((span->len < 0) ? - -span->len : - span->len), - ren_color, + ren.blend_hline(span->x, + sl.y(), + span->x - 1 + ((span->len < 0) ? + -span->len : + span->len), + ren_color, cover_full); if(--num_spans == 0) break; ++span; @@ -318,7 +318,7 @@ namespace agg { m_ren = &ren; } - + //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } @@ -331,7 +331,7 @@ namespace agg { render_scanline_bin_solid(sl, *m_ren, m_color); } - + private: base_ren_type* m_ren; color_type m_color; @@ -345,9 +345,9 @@ namespace agg //======================================================render_scanline_bin - template - void render_scanline_bin(const Scanline& sl, BaseRenderer& ren, + template + void render_scanline_bin(const Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { int y = sl.y(); @@ -361,16 +361,16 @@ namespace agg if(len < 0) len = -len; typename BaseRenderer::color_type* colors = alloc.allocate(len); span_gen.generate(colors, x, y, len); - ren.blend_color_hspan(x, y, len, colors, 0, cover_full); + ren.blend_color_hspan(x, y, len, colors, 0, cover_full); if(--num_spans == 0) break; ++span; } } //=====================================================render_scanlines_bin - template - void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, + void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { if(ras.rewind_scanlines()) @@ -385,7 +385,7 @@ namespace agg } //====================================================renderer_scanline_bin - template + template class renderer_scanline_bin { public: @@ -395,22 +395,22 @@ namespace agg //-------------------------------------------------------------------- renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {} - renderer_scanline_bin(base_ren_type& ren, - alloc_type& alloc, + renderer_scanline_bin(base_ren_type& ren, + alloc_type& alloc, span_gen_type& span_gen) : m_ren(&ren), m_alloc(&alloc), m_span_gen(&span_gen) {} - void attach(base_ren_type& ren, - alloc_type& alloc, + void attach(base_ren_type& ren, + alloc_type& alloc, span_gen_type& span_gen) { m_ren = &ren; m_alloc = &alloc; m_span_gen = &span_gen; } - + //-------------------------------------------------------------------- void prepare() { m_span_gen->prepare(); } @@ -451,13 +451,13 @@ namespace agg } //========================================================render_all_paths - template - void render_all_paths(Rasterizer& ras, + void render_all_paths(Rasterizer& ras, Scanline& sl, - Renderer& r, - VertexSource& vs, - const ColorStorage& as, + Renderer& r, + VertexSource& vs, + const ColorStorage& as, const PathId& path_id, unsigned num_paths) { @@ -476,13 +476,13 @@ namespace agg //=============================================render_scanlines_compound - template - void render_scanlines_compound(Rasterizer& ras, + void render_scanlines_compound(Rasterizer& ras, ScanlineAA& sl_aa, ScanlineBin& sl_bin, BaseRenderer& ren, @@ -529,14 +529,14 @@ namespace agg for(;;) { len = span_aa->len; - sh.generate_span(color_span, - span_aa->x, - sl_aa.y(), - len, + sh.generate_span(color_span, + span_aa->x, + sl_aa.y(), + len, style); - ren.blend_color_hspan(span_aa->x, - sl_aa.y(), + ren.blend_color_hspan(span_aa->x, + sl_aa.y(), span_aa->len, color_span, span_aa->covers); @@ -556,8 +556,8 @@ namespace agg num_spans = sl_bin.num_spans(); for(;;) { - memset(mix_buffer + span_bin->x - min_x, - 0, + memset(mix_buffer + span_bin->x - min_x, + 0, span_bin->len * sizeof(color_type)); if(--num_spans == 0) break; @@ -589,7 +589,7 @@ namespace agg covers = span_aa->covers; do { - if(*covers == cover_full) + if(*covers == cover_full) { *colors = c; } @@ -614,15 +614,15 @@ namespace agg len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; cspan = color_span; - sh.generate_span(cspan, - span_aa->x, - sl_aa.y(), - len, + sh.generate_span(cspan, + span_aa->x, + sl_aa.y(), + len, style); covers = span_aa->covers; do { - if(*covers == cover_full) + if(*covers == cover_full) { *colors = *cspan; } @@ -648,8 +648,8 @@ namespace agg num_spans = sl_bin.num_spans(); for(;;) { - ren.blend_color_hspan(span_bin->x, - sl_bin.y(), + ren.blend_color_hspan(span_bin->x, + sl_bin.y(), span_bin->len, mix_buffer + span_bin->x - min_x, 0, @@ -664,12 +664,12 @@ namespace agg } //=======================================render_scanlines_compound_layered - template - void render_scanlines_compound_layered(Rasterizer& ras, + void render_scanlines_compound_layered(Rasterizer& ras, ScanlineAA& sl_aa, BaseRenderer& ren, SpanAllocator& alloc, @@ -715,14 +715,14 @@ namespace agg for(;;) { len = span_aa->len; - sh.generate_span(color_span, - span_aa->x, - sl_aa.y(), - len, + sh.generate_span(color_span, + span_aa->x, + sl_aa.y(), + len, style); - ren.blend_color_hspan(span_aa->x, - sl_aa.y(), + ren.blend_color_hspan(span_aa->x, + sl_aa.y(), span_aa->len, color_span, span_aa->covers); @@ -739,12 +739,12 @@ namespace agg if(sl_len) { - memset(mix_buffer + sl_start - min_x, - 0, + memset(mix_buffer + sl_start - min_x, + 0, sl_len * sizeof(color_type)); - memset(cover_buffer + sl_start - min_x, - 0, + memset(cover_buffer + sl_start - min_x, + 0, sl_len * sizeof(cover_type)); int sl_y = std::numeric_limits::max(); @@ -805,10 +805,10 @@ namespace agg len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; cspan = color_span; - sh.generate_span(cspan, - span_aa->x, - sl_aa.y(), - len, + sh.generate_span(cspan, + span_aa->x, + sl_aa.y(), + len, style); src_covers = span_aa->covers; dst_covers = cover_buffer + span_aa->x - min_x; @@ -836,8 +836,8 @@ namespace agg } } } - ren.blend_color_hspan(sl_start, - sl_y, + ren.blend_color_hspan(sl_start, + sl_y, sl_len, mix_buffer + sl_start - min_x, 0, diff --git a/src/agg/agg_rendering_buffer.h b/src/agg/agg_rendering_buffer.h index 0eff6ff27d3..4a73e1a7185 100644 --- a/src/agg/agg_rendering_buffer.h +++ b/src/agg/agg_rendering_buffer.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -60,8 +60,8 @@ namespace agg m_width = width; m_height = height; m_stride = stride; - if(stride < 0) - { + if(stride < 0) + { m_start = m_buf - int(height - 1) * stride; } } @@ -72,21 +72,21 @@ namespace agg AGG_INLINE unsigned width() const { return m_width; } AGG_INLINE unsigned height() const { return m_height; } AGG_INLINE int stride() const { return m_stride; } - AGG_INLINE unsigned stride_abs() const + AGG_INLINE unsigned stride_abs() const { - return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); + return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); } //-------------------------------------------------------------------- - AGG_INLINE T* row_ptr(int, int y, unsigned) - { - return m_start + y * m_stride; + AGG_INLINE T* row_ptr(int, int y, unsigned) + { + return m_start + y * m_stride; } AGG_INLINE T* row_ptr(int y) { return m_start + y * m_stride; } AGG_INLINE const T* row_ptr(int y) const { return m_start + y * m_stride; } - AGG_INLINE row_data row (int y) const - { - return row_data(0, m_width-1, row_ptr(y)); + AGG_INLINE row_data row (int y) const + { + return row_data(0, m_width-1, row_ptr(y)); } //-------------------------------------------------------------------- @@ -95,10 +95,10 @@ namespace agg { unsigned h = height(); if(src.height() < h) h = src.height(); - + unsigned l = stride_abs(); if(src.stride_abs() < l) l = src.stride_abs(); - + l *= sizeof(T); unsigned y; @@ -129,7 +129,7 @@ namespace agg private: //-------------------------------------------------------------------- T* m_buf; // Pointer to renrdering buffer - T* m_start; // Pointer to first pixel depending on stride + T* m_start; // Pointer to first pixel depending on stride unsigned m_width; // Width in pixels unsigned m_height; // Height in pixels int m_stride; // Number of bytes per row. Can be < 0 @@ -199,21 +199,21 @@ namespace agg AGG_INLINE unsigned width() const { return m_width; } AGG_INLINE unsigned height() const { return m_height; } AGG_INLINE int stride() const { return m_stride; } - AGG_INLINE unsigned stride_abs() const + AGG_INLINE unsigned stride_abs() const { - return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); + return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); } //-------------------------------------------------------------------- - AGG_INLINE T* row_ptr(int, int y, unsigned) - { - return m_rows[y]; + AGG_INLINE T* row_ptr(int, int y, unsigned) + { + return m_rows[y]; } AGG_INLINE T* row_ptr(int y) { return m_rows[y]; } AGG_INLINE const T* row_ptr(int y) const { return m_rows[y]; } - AGG_INLINE row_data row (int y) const - { - return row_data(0, m_width-1, m_rows[y]); + AGG_INLINE row_data row (int y) const + { + return row_data(0, m_width-1, m_rows[y]); } //-------------------------------------------------------------------- @@ -225,10 +225,10 @@ namespace agg { unsigned h = height(); if(src.height() < h) h = src.height(); - + unsigned l = stride_abs(); if(src.stride_abs() < l) l = src.stride_abs(); - + l *= sizeof(T); unsigned y; @@ -269,21 +269,21 @@ namespace agg //========================================================rendering_buffer - // - // The definition of the main type for accessing the rows in the frame - // buffer. It provides functionality to navigate to the rows in a - // rectangular matrix, from top to bottom or from bottom to top depending + // + // The definition of the main type for accessing the rows in the frame + // buffer. It provides functionality to navigate to the rows in a + // rectangular matrix, from top to bottom or from bottom to top depending // on stride. // // row_accessor is cheap to create/destroy, but performs one multiplication // when calling row_ptr(). - // - // row_ptr_cache creates an array of pointers to rows, so, the access - // via row_ptr() may be faster. But it requires memory allocation - // when creating. For example, on typical Intel Pentium hardware + // + // row_ptr_cache creates an array of pointers to rows, so, the access + // via row_ptr() may be faster. But it requires memory allocation + // when creating. For example, on typical Intel Pentium hardware // row_ptr_cache speeds span_image_filter_rgb_nn up to 10% // - // It's used only in short hand typedefs like pixfmt_rgba32 and can be + // It's used only in short hand typedefs like pixfmt_rgba32 and can be // redefined in agg_config.h // In real applications you can use both, depending on your needs //------------------------------------------------------------------------ diff --git a/src/agg/agg_scanline_p.h b/src/agg/agg_scanline_p.h index 1d1cbe72f1e..19e1e9d5cb5 100644 --- a/src/agg/agg_scanline_p.h +++ b/src/agg/agg_scanline_p.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -17,12 +17,12 @@ // //---------------------------------------------------------------------------- // -// Adaptation for 32-bit screen coordinates (scanline32_p) has been sponsored by +// Adaptation for 32-bit screen coordinates (scanline32_p) has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- #ifndef AGG_SCANLINE_P_INCLUDED #define AGG_SCANLINE_P_INCLUDED @@ -33,11 +33,11 @@ namespace agg { //=============================================================scanline_p8 - // - // This is a general purpose scaline container which supports the interface + // + // This is a general purpose scaline container which supports the interface // used in the rasterizer::render(). See description of scanline_u8 // for details. - // + // //------------------------------------------------------------------------ class scanline_p8 { @@ -122,8 +122,8 @@ namespace agg //-------------------------------------------------------------------- void add_span(int x, unsigned len, unsigned cover) { - if(x == m_last_x+1 && - m_cur_span->len < 0 && + if(x == m_last_x+1 && + m_cur_span->len < 0 && cover == *m_cur_span->covers) { m_cur_span->len -= (int16)len; @@ -140,9 +140,9 @@ namespace agg } //-------------------------------------------------------------------- - void finalize(int y) - { - m_y = y; + void finalize(int y) + { + m_y = y; } //-------------------------------------------------------------------- @@ -275,9 +275,9 @@ namespace agg //-------------------------------------------------------------------- void add_span(int x, unsigned len, unsigned cover) { - if(x == m_last_x+1 && + if(x == m_last_x+1 && m_spans.size() && - m_spans.last().len < 0 && + m_spans.last().len < 0 && cover == *m_spans.last().covers) { m_spans.last().len -= coord_type(len); @@ -291,9 +291,9 @@ namespace agg } //-------------------------------------------------------------------- - void finalize(int y) - { - m_y = y; + void finalize(int y) + { + m_y = y; } //-------------------------------------------------------------------- diff --git a/src/agg/agg_trans_affine.h b/src/agg/agg_trans_affine.h index 1a611638833..a62ef674f2e 100644 --- a/src/agg/agg_trans_affine.h +++ b/src/agg/agg_trans_affine.h @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -24,39 +24,39 @@ namespace agg { - const double affine_epsilon = 1e-14; + const double affine_epsilon = 1e-14; //============================================================trans_affine // // See Implementation agg_trans_affine.cpp // // Affine transformation are linear transformations in Cartesian coordinates - // (strictly speaking not only in Cartesian, but for the beginning we will - // think so). They are rotation, scaling, translation and skewing. - // After any affine transformation a line segment remains a line segment - // and it will never become a curve. + // (strictly speaking not only in Cartesian, but for the beginning we will + // think so). They are rotation, scaling, translation and skewing. + // After any affine transformation a line segment remains a line segment + // and it will never become a curve. // - // There will be no math about matrix calculations, since it has been + // There will be no math about matrix calculations, since it has been // described many times. Ask yourself a very simple question: - // "why do we need to understand and use some matrix stuff instead of just + // "why do we need to understand and use some matrix stuff instead of just // rotating, scaling and so on". The answers are: // // 1. Any combination of transformations can be done by only 4 multiplications // and 4 additions in floating point. // 2. One matrix transformation is equivalent to the number of consecutive - // discrete transformations, i.e. the matrix "accumulates" all transformations - // in the order of their settings. Suppose we have 4 transformations: + // discrete transformations, i.e. the matrix "accumulates" all transformations + // in the order of their settings. Suppose we have 4 transformations: // * rotate by 30 degrees, - // * scale X to 2.0, - // * scale Y to 1.5, - // * move to (100, 100). - // The result will depend on the order of these transformations, + // * scale X to 2.0, + // * scale Y to 1.5, + // * move to (100, 100). + // The result will depend on the order of these transformations, // and the advantage of matrix is that the sequence of discret calls: - // rotate(30), scaleX(2.0), scaleY(1.5), move(100,100) + // rotate(30), scaleX(2.0), scaleY(1.5), move(100,100) // will have exactly the same result as the following matrix transformations: - // + // // affine_matrix m; - // m *= rotate_matrix(30); + // m *= rotate_matrix(30); // m *= scaleX_matrix(2.0); // m *= scaleY_matrix(1.5); // m *= move_matrix(100,100); @@ -64,7 +64,7 @@ namespace agg // m.transform_my_point_at_last(x, y); // // What is the good of it? In real life we will set-up the matrix only once - // and then transform many points, let alone the convenience to set any + // and then transform many points, let alone the convenience to set any // combination of transformations. // // So, how to use it? Very easy - literally as it's shown above. Not quite, @@ -77,9 +77,9 @@ namespace agg // m.transform(&x, &y); // // The affine matrix is all you need to perform any linear transformation, - // but all transformations have origin point (0,0). It means that we need to + // but all transformations have origin point (0,0). It means that we need to // use 2 translations if we want to rotate someting around (100,100): - // + // // m *= agg::trans_affine_translation(-100.0, -100.0); // move to (0,0) // m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate // m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100) @@ -95,7 +95,7 @@ namespace agg {} // Custom matrix. Usually used in derived classes - trans_affine(double v0, double v1, double v2, + trans_affine(double v0, double v1, double v2, double v3, double v4, double v5) : sx(v0), shy(v1), shx(v2), sy(v3), tx(v4), ty(v5) {} @@ -106,14 +106,14 @@ namespace agg {} // Rectangle to a parallelogram. - trans_affine(double x1, double y1, double x2, double y2, + trans_affine(double x1, double y1, double x2, double y2, const double* parl) { rect_to_parl(x1, y1, x2, y2, parl); } // Parallelogram to a rectangle. - trans_affine(const double* parl, + trans_affine(const double* parl, double x1, double y1, double x2, double y2) { parl_to_rect(parl, x1, y1, x2, y2); @@ -126,25 +126,25 @@ namespace agg } //---------------------------------- Parellelogram transformations - // transform a parallelogram to another one. Src and dst are - // pointers to arrays of three points (double[6], x1,y1,...) that - // identify three corners of the parallelograms assuming implicit - // fourth point. The arguments are arrays of double[6] mapped + // transform a parallelogram to another one. Src and dst are + // pointers to arrays of three points (double[6], x1,y1,...) that + // identify three corners of the parallelograms assuming implicit + // fourth point. The arguments are arrays of double[6] mapped // to x1,y1, x2,y2, x3,y3 where the coordinates are: // *-----------------* // / (x3,y3)/ // / / // /(x1,y1) (x2,y2)/ // *-----------------* - const trans_affine& parl_to_parl(const double* src, + const trans_affine& parl_to_parl(const double* src, const double* dst); - const trans_affine& rect_to_parl(double x1, double y1, - double x2, double y2, + const trans_affine& rect_to_parl(double x1, double y1, + double x2, double y2, const double* parl); - const trans_affine& parl_to_rect(const double* parl, - double x1, double y1, + const trans_affine& parl_to_rect(const double* parl, + double x1, double y1, double x2, double y2); @@ -170,8 +170,8 @@ namespace agg // Multiply inverse of "m" to "this" and assign the result to "this" const trans_affine& premultiply_inv(const trans_affine& m); - // Invert matrix. Do not try to invert degenerate matrices, - // there's no check for validity. If you set scale to 0 and + // Invert matrix. Do not try to invert degenerate matrices, + // there's no check for validity. If you set scale to 0 and // then try to invert matrix, expect unpredictable result. const trans_affine& invert(); @@ -196,7 +196,7 @@ namespace agg } //------------------------------------------- Operators - + // Multiply the matrix by another one const trans_affine& operator *= (const trans_affine& m) { @@ -216,7 +216,7 @@ namespace agg return trans_affine(*this).multiply(m); } - // Multiply the matrix by inverse of another one + // Multiply the matrix by inverse of another one // and return the result in a separete matrix. trans_affine operator / (const trans_affine& m) const { @@ -249,9 +249,9 @@ namespace agg // Direct transformation of x and y, 2x2 matrix only, no translation void transform_2x2(double* x, double* y) const; - // Inverse transformation of x and y. It works slower than the - // direct transformation. For massive operations it's better to - // invert() the matrix and then use direct transformations. + // Inverse transformation of x and y. It works slower than the + // direct transformation. For massive operations it's better to + // invert() the matrix and then use direct transformations. void inverse_transform(double* x, double* y) const; //-------------------------------------------- Auxiliary @@ -267,7 +267,7 @@ namespace agg return 1.0 / (sx * sy - shy * shx); } - // Get the average scale (by X and Y). + // Get the average scale (by X and Y). // Basically used to calculate the approximation_scale when // decomposinting curves into line segments. double scale() const; @@ -281,7 +281,7 @@ namespace agg // Check to see if two matrices are equal bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const; - // Determine the major parameters. Use with caution considering + // Determine the major parameters. Use with caution considering // possible degenerate cases. double rotation() const; void translation(double* dx, double* dy) const; @@ -324,23 +324,23 @@ namespace agg } //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::translate(double x, double y) - { + inline const trans_affine& trans_affine::translate(double x, double y) + { tx += x; - ty += y; + ty += y; return *this; } //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::rotate(double a) + inline const trans_affine& trans_affine::rotate(double a) { - double ca = cos(a); + double ca = cos(a); double sa = sin(a); double t0 = sx * ca - shy * sa; double t2 = shx * ca - sy * sa; double t4 = tx * ca - ty * sa; shy = sx * sa + shy * ca; - sy = shx * sa + sy * ca; + sy = shx * sa + sy * ca; ty = tx * sa + ty * ca; sx = t0; shx = t2; @@ -349,10 +349,10 @@ namespace agg } //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::scale(double x, double y) + inline const trans_affine& trans_affine::scale(double x, double y) { double mm0 = x; // Possible hint for the optimizer - double mm3 = y; + double mm3 = y; sx *= mm0; shx *= mm0; tx *= mm0; @@ -363,7 +363,7 @@ namespace agg } //------------------------------------------------------------------------ - inline const trans_affine& trans_affine::scale(double s) + inline const trans_affine& trans_affine::scale(double s) { double m = s; // Possible hint for the optimizer sx *= m; @@ -401,7 +401,7 @@ namespace agg //------------------------------------------------------------------------ inline void trans_affine::scaling_abs(double* x, double* y) const { - // Used to calculate scaling coefficients in image resampling. + // Used to calculate scaling coefficients in image resampling. // When there is considerable shear this method gives us much // better estimation than just sx, sy. *x = sqrt(sx * sx + shx * shx); @@ -411,12 +411,12 @@ namespace agg //====================================================trans_affine_rotation // Rotation matrix. sin() and cos() are calculated twice for the same angle. // There's no harm because the performance of sin()/cos() is very good on all - // modern processors. Besides, this operation is not going to be invoked too + // modern processors. Besides, this operation is not going to be invoked too // often. class trans_affine_rotation : public trans_affine { public: - trans_affine_rotation(double a) : + trans_affine_rotation(double a) : trans_affine(cos(a), sin(a), -sin(a), cos(a), 0.0, 0.0) {} }; @@ -426,11 +426,11 @@ namespace agg class trans_affine_scaling : public trans_affine { public: - trans_affine_scaling(double x, double y) : + trans_affine_scaling(double x, double y) : trans_affine(x, 0.0, 0.0, y, 0.0, 0.0) {} - trans_affine_scaling(double s) : + trans_affine_scaling(double s) : trans_affine(s, 0.0, 0.0, s, 0.0, 0.0) {} }; @@ -440,7 +440,7 @@ namespace agg class trans_affine_translation : public trans_affine { public: - trans_affine_translation(double x, double y) : + trans_affine_translation(double x, double y) : trans_affine(1.0, 0.0, 0.0, 1.0, x, y) {} }; @@ -450,19 +450,19 @@ namespace agg class trans_affine_skewing : public trans_affine { public: - trans_affine_skewing(double x, double y) : + trans_affine_skewing(double x, double y) : trans_affine(1.0, tan(y), tan(x), 1.0, 0.0, 0.0) {} }; //===============================================trans_affine_line_segment - // Rotate, Scale and Translate, associating 0...dist with line segment + // Rotate, Scale and Translate, associating 0...dist with line segment // x1,y1,x2,y2 class trans_affine_line_segment : public trans_affine { public: - trans_affine_line_segment(double x1, double y1, double x2, double y2, + trans_affine_line_segment(double x1, double y1, double x2, double y2, double dist) { double dx = x2 - x1; @@ -478,24 +478,24 @@ namespace agg //============================================trans_affine_reflection_unit - // Reflection matrix. Reflect coordinates across the line through + // Reflection matrix. Reflect coordinates across the line through // the origin containing the unit vector (ux, uy). // Contributed by John Horigan class trans_affine_reflection_unit : public trans_affine { public: trans_affine_reflection_unit(double ux, double uy) : - trans_affine(2.0 * ux * ux - 1.0, - 2.0 * ux * uy, - 2.0 * ux * uy, - 2.0 * uy * uy - 1.0, + trans_affine(2.0 * ux * ux - 1.0, + 2.0 * ux * uy, + 2.0 * ux * uy, + 2.0 * uy * uy - 1.0, 0.0, 0.0) {} }; //=================================================trans_affine_reflection - // Reflection matrix. Reflect coordinates across the line through + // Reflection matrix. Reflect coordinates across the line through // the origin at the angle a or containing the non-unit vector (x, y). // Contributed by John Horigan class trans_affine_reflection : public trans_affine_reflection_unit diff --git a/src/agg/copying b/src/agg/copying index b6028e51958..801f9798776 100644 --- a/src/agg/copying +++ b/src/agg/copying @@ -2,14 +2,14 @@ The Anti-Grain Geometry Project A high quality rendering engine for C++ http://antigrain.com -Anti-Grain Geometry has dual licensing model. The Modified BSD +Anti-Grain Geometry has dual licensing model. The Modified BSD License was first added in version v2.4 just for convenience. -It is a simple, permissive non-copyleft free software license, +It is a simple, permissive non-copyleft free software license, compatible with the GNU GPL. It's well proven and recognizable. See http://www.fsf.org/licensing/licenses/index_html#ModifiedBSD for details. -Note that the Modified BSD license DOES NOT restrict your rights +Note that the Modified BSD license DOES NOT restrict your rights if you choose the Anti-Grain Geometry Public License. @@ -18,11 +18,11 @@ if you choose the Anti-Grain Geometry Public License. Anti-Grain Geometry Public License ==================================================== -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) +Anti-Grain Geometry - Version 2.4 +Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) -Permission to copy, use, modify, sell and distribute this software -is granted provided this copyright notice appears in all copies. +Permission to copy, use, modify, sell and distribute this software +is granted provided this copyright notice appears in all copies. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. @@ -32,34 +32,34 @@ warranty, and with no claim as to its suitability for any purpose. Modified BSD License ==================================================== -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) +Anti-Grain Geometry - Version 2.4 +Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/angelscript/CMakeLists.txt b/src/angelscript/CMakeLists.txt index fed80a0ad54..b25bf2e1f5b 100644 --- a/src/angelscript/CMakeLists.txt +++ b/src/angelscript/CMakeLists.txt @@ -147,7 +147,7 @@ elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm") endif() if(MSVC) - set(CMAKE_DEBUG_POSTFIX "d") + set(CMAKE_DEBUG_POSTFIX "d") endif() if(NOT BUILD_FRAMEWORK) @@ -164,13 +164,13 @@ add_library(${ANGELSCRIPT_LIBRARY_NAME} STATIC ${ANGELSCRIPT_SOURCE} ${ANGELSCRI target_include_directories(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) if(MSVC) - target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE -D_CRT_SECURE_NO_WARNINGS) + target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE -D_CRT_SECURE_NO_WARNINGS) endif() target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE -DANGELSCRIPT_EXPORT -D_LIB) if(AS_NO_EXCEPTIONS) - target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE AS_NO_EXCEPTIONS) + target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE AS_NO_EXCEPTIONS) endif() # Fix x64 issues on Linux @@ -197,7 +197,7 @@ if(BUILD_FRAMEWORK) endif() if(MSVC AND MSVC_COMPILE_FLAGS) - target_compile_options(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE "${MSVC_COMPILE_FLAGS}") + target_compile_options(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE "${MSVC_COMPILE_FLAGS}") endif() # Don't override the default runtime output path to avoid conflicts when building for multiple target platforms @@ -205,45 +205,45 @@ endif() #See https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-packages for a detailed explanation about this part install(TARGETS ${ANGELSCRIPT_LIBRARY_NAME} EXPORT AngelscriptTargets - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - INCLUDES DESTINATION include + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + INCLUDES DESTINATION include ) install(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/include/angelscript.h - DESTINATION include - COMPONENT Devel + ${CMAKE_CURRENT_SOURCE_DIR}/include/angelscript.h + DESTINATION include + COMPONENT Devel ) include(CMakePackageConfigHelpers) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion + "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion ) export(EXPORT AngelscriptTargets - FILE "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptTargets.cmake" - NAMESPACE Angelscript:: + FILE "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptTargets.cmake" + NAMESPACE Angelscript:: ) configure_file(cmake/AngelscriptConfig.cmake - "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfig.cmake" - COPYONLY + "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfig.cmake" + COPYONLY ) set(ConfigPackageLocation lib/cmake/Angelscript) install(EXPORT AngelscriptTargets - FILE AngelscriptTargets.cmake - NAMESPACE Angelscript:: - DESTINATION ${ConfigPackageLocation} + FILE AngelscriptTargets.cmake + NAMESPACE Angelscript:: + DESTINATION ${ConfigPackageLocation} ) install( - FILES - cmake/AngelscriptConfig.cmake - "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfigVersion.cmake" - DESTINATION ${ConfigPackageLocation} - COMPONENT Devel + FILES + cmake/AngelscriptConfig.cmake + "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfigVersion.cmake" + DESTINATION ${ConfigPackageLocation} + COMPONENT Devel ) diff --git a/src/angelscript/add_on/autowrapper/aswrappedcall.h b/src/angelscript/add_on/autowrapper/aswrappedcall.h index 880265ef231..81ca89e069a 100644 --- a/src/angelscript/add_on/autowrapper/aswrappedcall.h +++ b/src/angelscript/add_on/autowrapper/aswrappedcall.h @@ -1,7 +1,7 @@ #ifndef AS_GEN_WRAPPER_H #define AS_GEN_WRAPPER_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -11,15 +11,15 @@ 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 &); + 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 {}; @@ -33,519 +33,519 @@ void destroy(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { } template <> struct Wrapper { - template - static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * /*gen*/) { - ((fp)()); - } + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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(); - } + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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); - } + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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); - } + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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); - } + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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); - } + 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 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 @@ -554,12 +554,12 @@ 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 +#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 + #define TMPL #endif #define WRAP_FN(name) (::gw::id(name).TMPL f< name >()) diff --git a/src/angelscript/add_on/autowrapper/generator/generateheader.cpp b/src/angelscript/add_on/autowrapper/generator/generateheader.cpp index 277799a0eb7..d59683ff913 100644 --- a/src/angelscript/add_on/autowrapper/generator/generateheader.cpp +++ b/src/angelscript/add_on/autowrapper/generator/generateheader.cpp @@ -6,7 +6,7 @@ // 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 +// 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/ @@ -26,141 +26,141 @@ void PrintConstructor(const char *comma, const char *typeNameList, const char *t 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(AS_NAMESPACE_QUALIFIER 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; + 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(AS_NAMESPACE_QUALIFIER 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"); + 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"); + 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/src/angelscript/add_on/autowrapper/generator/generator.sln b/src/angelscript/add_on/autowrapper/generator/generator.sln index b84712a18b1..19a2e047b79 100644 --- a/src/angelscript/add_on/autowrapper/generator/generator.sln +++ b/src/angelscript/add_on/autowrapper/generator/generator.sln @@ -4,17 +4,17 @@ Microsoft Visual Studio Solution File, Format Version 10.00 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 + 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/src/angelscript/add_on/autowrapper/generator/generator.vcproj b/src/angelscript/add_on/autowrapper/generator/generator.vcproj index e663fdc1949..b22ec84d171 100644 --- a/src/angelscript/add_on/autowrapper/generator/generator.vcproj +++ b/src/angelscript/add_on/autowrapper/generator/generator.vcproj @@ -1,236 +1,236 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ProjectType="Visual C++" + Version="9,00" + Name="generator" + ProjectGUID="{086A2F1A-01B1-4EB3-A8FA-0926FF10E953}" + TargetFrameworkVersion="0" + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/angelscript/add_on/contextmgr/contextmgr.cpp b/src/angelscript/add_on/contextmgr/contextmgr.cpp index 6064b547451..6e30eafd54a 100644 --- a/src/angelscript/add_on/contextmgr/contextmgr.cpp +++ b/src/angelscript/add_on/contextmgr/contextmgr.cpp @@ -23,376 +23,376 @@ const asPWORD CONTEXT_MGR = 1002; struct SContextInfo { - asUINT sleepUntil; - vector coRoutines; - asUINT currentCoRoutine; - asIScriptContext * keepCtxAfterExecution; + asUINT sleepUntil; + vector coRoutines; + asUINT currentCoRoutine; + asIScriptContext * keepCtxAfterExecution; }; 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); - } - } + // 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(); - } - } + // 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 - } - } + 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 + } + } } #ifdef AS_MAX_PORTABILITY void ScriptYield_generic(asIScriptGeneric *) { - ScriptYield(); + ScriptYield(); } void ScriptCreateCoRoutine_generic(asIScriptGeneric *gen) { - asIScriptFunction *func = reinterpret_cast(gen->GetArgAddress(0)); - CScriptDictionary *dict = reinterpret_cast(gen->GetArgAddress(1)); - ScriptCreateCoRoutine(func, dict); + asIScriptFunction *func = reinterpret_cast(gen->GetArgAddress(0)); + CScriptDictionary *dict = reinterpret_cast(gen->GetArgAddress(1)); + ScriptCreateCoRoutine(func, dict); } #endif CContextMgr::CContextMgr() { - m_getTimeFunc = 0; - m_currentThread = 0; + m_getTimeFunc = 0; + m_currentThread = 0; - m_numExecutions = 0; - m_numGCObjectsCreated = 0; - m_numGCObjectsDestroyed = 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]; - } - } + 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 ) - { - // The context has terminated execution (for one reason or other) - // Unless the application has requested to keep the context we'll return it to the pool now - if( thread->keepCtxAfterExecution != thread->coRoutines[currentCoRoutine] ) - 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()); + // 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 ) + { + // The context has terminated execution (for one reason or other) + // Unless the application has requested to keep the context we'll return it to the pool now + if( thread->keepCtxAfterExecution != thread->coRoutines[currentCoRoutine] ) + 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::DoneWithContext(asIScriptContext *ctx) { - ctx->GetEngine()->ReturnContext(ctx); + ctx->GetEngine()->ReturnContext(ctx); } 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; + 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; + // 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, bool keepCtxAfterExec) { - // 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; - info->keepCtxAfterExecution = keepCtxAfterExec ? ctx : 0; - m_threads.push_back(info); - - return ctx; + // 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; + info->keepCtxAfterExecution = keepCtxAfterExec ? ctx : 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; + 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 ); + assert( m_getTimeFunc != 0 ); - // Find the context and update the timeStamp - // for when the context is to be continued + // Find the context and update the timeStamp + // for when the context is to be continued - // TODO: Start with the current thread + // 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; - } - } + 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) { - // Must set the get time callback function for this to work - assert( m_getTimeFunc != 0 ); + // Must set the get time callback function for this to work + assert( m_getTimeFunc != 0 ); - // Register the sleep function - engine->RegisterGlobalFunction("void sleep(uint)", asFUNCTION(ScriptSleep), asCALL_CDECL); assert( r >= 0 ); + // Register the sleep function + engine->RegisterGlobalFunction("void sleep(uint)", asFUNCTION(ScriptSleep), asCALL_CDECL); assert( r >= 0 ); - // TODO: Add support for spawning new threads, waiting for signals, etc + // TODO: Add support for spawning new threads, waiting for signals, etc } void CContextMgr::RegisterCoRoutineSupport(asIScriptEngine *engine) { - // The dictionary add-on must have been registered already - assert( engine->GetTypeInfoByDecl("dictionary") ); + // The dictionary add-on must have been registered already + assert( engine->GetTypeInfoByDecl("dictionary") ); #ifndef AS_MAX_PORTABILITY - engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterFuncdef("void coroutine(dictionary@)"); - engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterFuncdef("void coroutine(dictionary@)"); + engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine), asCALL_CDECL); assert( r >= 0 ); #else - engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterFuncdef("void coroutine(dictionary@)"); - engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterFuncdef("void coroutine(dictionary@)"); + engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine_generic), asCALL_GENERIC); assert( r >= 0 ); #endif } void CContextMgr::SetGetTimeCallback(TIMEFUNC_t func) { - m_getTimeFunc = func; + m_getTimeFunc = func; } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/contextmgr/contextmgr.h b/src/angelscript/add_on/contextmgr/contextmgr.h index f57630cfe3e..7e78cc29ce8 100644 --- a/src/angelscript/add_on/contextmgr/contextmgr.h +++ b/src/angelscript/add_on/contextmgr/contextmgr.h @@ -8,7 +8,7 @@ // OBSERVATION: This class is currently not thread safe. -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -28,69 +28,69 @@ 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. - // Set keepCtxAfterExecution to true if the application needs to retrieve - // information from the context after it the script has finished. - asIScriptContext *AddContext(asIScriptEngine *engine, asIScriptFunction *func, bool keepCtxAfterExecution = false); - - // If the context was kept after the execution, this method must be - // called when the application is done with the context so it can be - // returned to the pool for reuse. - void DoneWithContext(asIScriptContext *ctx); - - // 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(); + 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. + // Set keepCtxAfterExecution to true if the application needs to retrieve + // information from the context after it the script has finished. + asIScriptContext *AddContext(asIScriptEngine *engine, asIScriptFunction *func, bool keepCtxAfterExecution = false); + + // If the context was kept after the execution, this method must be + // called when the application is done with the context so it can be + // returned to the pool for reuse. + void DoneWithContext(asIScriptContext *ctx); + + // 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; + 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; }; diff --git a/src/angelscript/add_on/datetime/datetime.cpp b/src/angelscript/add_on/datetime/datetime.cpp index 3ea75d8f6de..eb06269e77d 100644 --- a/src/angelscript/add_on/datetime/datetime.cpp +++ b/src/angelscript/add_on/datetime/datetime.cpp @@ -13,192 +13,192 @@ BEGIN_AS_NAMESPACE static tm time_point_to_tm(const std::chrono::time_point &tp) { - time_t t = system_clock::to_time_t(tp); - tm local; - - // Use the universal timezone + time_t t = system_clock::to_time_t(tp); + tm local; + + // Use the universal timezone #ifdef _MSC_VER - gmtime_s(&local, &t); + gmtime_s(&local, &t); #else - local = *gmtime(&t); + local = *gmtime(&t); #endif - return local; + return local; } // Returns true if successful. Doesn't modify tp if not successful static bool tm_to_time_point(const tm &_tm, std::chrono::time_point &tp) { - tm localTm = _tm; - - // Do not rely on timezone, as it is not portable - // ref: https://stackoverflow.com/questions/38298261/why-there-is-no-inverse-function-for-gmtime-in-libc - // ref: https://stackoverflow.com/questions/8558919/mktime-and-tm-isdst - localTm.tm_isdst = -1; // Always use current settings, so mktime doesn't modify the time for daylight savings - time_t t = mktime(&localTm); - if (t == -1) - return false; - - // Adjust the time_t since epoch with the difference of the local timezone to the universal timezone - t += (mktime(localtime(&t)) - mktime(gmtime(&t))); - - // Verify if the members were modified, indicating an out-of-range value in input - if (localTm.tm_year != _tm.tm_year || - localTm.tm_mon != _tm.tm_mon || - localTm.tm_mday != _tm.tm_mday || - localTm.tm_hour != _tm.tm_hour || - localTm.tm_min != _tm.tm_min || - localTm.tm_sec != _tm.tm_sec) - return false; - - tp = system_clock::from_time_t(t); - return true; + tm localTm = _tm; + + // Do not rely on timezone, as it is not portable + // ref: https://stackoverflow.com/questions/38298261/why-there-is-no-inverse-function-for-gmtime-in-libc + // ref: https://stackoverflow.com/questions/8558919/mktime-and-tm-isdst + localTm.tm_isdst = -1; // Always use current settings, so mktime doesn't modify the time for daylight savings + time_t t = mktime(&localTm); + if (t == -1) + return false; + + // Adjust the time_t since epoch with the difference of the local timezone to the universal timezone + t += (mktime(localtime(&t)) - mktime(gmtime(&t))); + + // Verify if the members were modified, indicating an out-of-range value in input + if (localTm.tm_year != _tm.tm_year || + localTm.tm_mon != _tm.tm_mon || + localTm.tm_mday != _tm.tm_mday || + localTm.tm_hour != _tm.tm_hour || + localTm.tm_min != _tm.tm_min || + localTm.tm_sec != _tm.tm_sec) + return false; + + tp = system_clock::from_time_t(t); + return true; } -CDateTime::CDateTime() : tp(std::chrono::system_clock::now()) +CDateTime::CDateTime() : tp(std::chrono::system_clock::now()) { } -CDateTime::CDateTime(const CDateTime &o) : tp(o.tp) +CDateTime::CDateTime(const CDateTime &o) : tp(o.tp) { } CDateTime &CDateTime::operator=(const CDateTime &o) { - tp = o.tp; - return *this; + tp = o.tp; + return *this; } asUINT CDateTime::getYear() const { - tm local = time_point_to_tm(tp); - return local.tm_year + 1900; + tm local = time_point_to_tm(tp); + return local.tm_year + 1900; } asUINT CDateTime::getMonth() const { - tm local = time_point_to_tm(tp); - return local.tm_mon + 1; + tm local = time_point_to_tm(tp); + return local.tm_mon + 1; } asUINT CDateTime::getDay() const { - tm local = time_point_to_tm(tp); - return local.tm_mday; + tm local = time_point_to_tm(tp); + return local.tm_mday; } asUINT CDateTime::getHour() const { - tm local = time_point_to_tm(tp); - return local.tm_hour; + tm local = time_point_to_tm(tp); + return local.tm_hour; } asUINT CDateTime::getMinute() const { - tm local = time_point_to_tm(tp); - return local.tm_min; + tm local = time_point_to_tm(tp); + return local.tm_min; } asUINT CDateTime::getSecond() const { - tm local = time_point_to_tm(tp); - return local.tm_sec; + tm local = time_point_to_tm(tp); + return local.tm_sec; } bool CDateTime::setDate(asUINT year, asUINT month, asUINT day) { - tm local = time_point_to_tm(tp); - local.tm_year = int(year) - 1900; - local.tm_mon = month - 1; - local.tm_mday = day; + tm local = time_point_to_tm(tp); + local.tm_year = int(year) - 1900; + local.tm_mon = month - 1; + local.tm_mday = day; - return tm_to_time_point(local, tp); + return tm_to_time_point(local, tp); } bool CDateTime::setTime(asUINT hour, asUINT minute, asUINT second) { - tm local = time_point_to_tm(tp); - local.tm_hour = hour; - local.tm_min = minute; - local.tm_sec = second; + tm local = time_point_to_tm(tp); + local.tm_hour = hour; + local.tm_min = minute; + local.tm_sec = second; - return tm_to_time_point(local, tp); + return tm_to_time_point(local, tp); } CDateTime::CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second) { - tp = std::chrono::system_clock::now(); - setDate(year, month, day); - setTime(hour, minute, second); + tp = std::chrono::system_clock::now(); + setDate(year, month, day); + setTime(hour, minute, second); } asINT64 CDateTime::operator-(const CDateTime &dt) const { - return (tp - dt.tp).count() / std::chrono::system_clock::period::den * std::chrono::system_clock::period::num; + return (tp - dt.tp).count() / std::chrono::system_clock::period::den * std::chrono::system_clock::period::num; } CDateTime CDateTime::operator+(asINT64 seconds) const { - CDateTime dt(*this); - dt.tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num); - return dt; + CDateTime dt(*this); + dt.tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num); + return dt; } CDateTime &CDateTime::operator+=(asINT64 seconds) { - tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num); - return *this; + tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num); + return *this; } CDateTime operator+(asINT64 seconds, const CDateTime &other) { - return other + seconds; + return other + seconds; } CDateTime CDateTime::operator-(asINT64 seconds) const { - return *this + -seconds; + return *this + -seconds; } CDateTime &CDateTime::operator-=(asINT64 seconds) { - return *this += -seconds; + return *this += -seconds; } CDateTime operator-(asINT64 seconds, const CDateTime &other) { - return other + -seconds; + return other + -seconds; } bool CDateTime::operator==(const CDateTime &other) const { - return tp == other.tp; + return tp == other.tp; } bool CDateTime::operator<(const CDateTime &other) const { - return tp < other.tp; + return tp < other.tp; } static int opCmp(const CDateTime &a, const CDateTime &b) { - if (a < b) return -1; - if (a == b) return 0; - return 1; + if (a < b) return -1; + if (a == b) return 0; + return 1; } static void Construct(CDateTime *mem) { - new(mem) CDateTime(); + new(mem) CDateTime(); } static void ConstructCopy(CDateTime *mem, const CDateTime &o) { - new(mem) CDateTime(o); + new(mem) CDateTime(o); } static void ConstructSet(CDateTime *mem, asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second) { - new(mem) CDateTime(year, month, day, hour, minute, second); + new(mem) CDateTime(year, month, day, hour, minute, second); } static void ConstructSet_Generic(asIScriptGeneric *gen) @@ -215,56 +215,56 @@ static void ConstructSet_Generic(asIScriptGeneric *gen) void RegisterScriptDateTime(asIScriptEngine *engine) { - int r = engine->RegisterObjectType("datetime", sizeof(CDateTime), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits()); assert(r >= 0); - - if(strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")==0) - { - r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", asFUNCTION(ConstructCopy), asCALL_CDECL_OBJFIRST); assert(r >= 0); - r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet), asCALL_CDECL_OBJFIRST); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", asMETHOD(CDateTime, operator=), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", asMETHOD(CDateTime, getYear), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", asMETHOD(CDateTime, getMonth), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", asMETHOD(CDateTime, getDay), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", asMETHOD(CDateTime, getHour), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", asMETHOD(CDateTime, getMinute), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", asMETHOD(CDateTime, getSecond), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", asMETHOD(CDateTime, setDate), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", asMETHOD(CDateTime, setTime), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", asMETHODPR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", asMETHOD(CDateTime, operator+), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", asFUNCTIONPR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", asMETHOD(CDateTime, operator+=), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", asMETHODPR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", asFUNCTIONPR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", asMETHOD(CDateTime, operator-=), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", asMETHODPR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", asFUNCTION(opCmp), asCALL_CDECL_OBJFIRST); assert(r >= 0); - } - else - { - r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", WRAP_OBJ_LAST(Construct), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", WRAP_OBJ_FIRST(ConstructCopy), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", WRAP_MFN(CDateTime, operator=), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", WRAP_MFN(CDateTime, getYear), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", WRAP_MFN(CDateTime, getMonth), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", WRAP_MFN(CDateTime, getDay), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", WRAP_MFN(CDateTime, getHour), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", WRAP_MFN(CDateTime, getMinute), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", WRAP_MFN(CDateTime, getSecond), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", WRAP_MFN(CDateTime, setDate), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", WRAP_MFN(CDateTime, setTime), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", WRAP_MFN(CDateTime, operator+), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", WRAP_MFN(CDateTime, operator+=), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", WRAP_MFN_PR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", WRAP_MFN(CDateTime, operator-=), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", WRAP_OBJ_FIRST(opCmp), asCALL_GENERIC); assert(r >= 0); - } + int r = engine->RegisterObjectType("datetime", sizeof(CDateTime), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits()); assert(r >= 0); + + if(strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")==0) + { + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", asFUNCTION(ConstructCopy), asCALL_CDECL_OBJFIRST); assert(r >= 0); + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet), asCALL_CDECL_OBJFIRST); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", asMETHOD(CDateTime, operator=), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", asMETHOD(CDateTime, getYear), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", asMETHOD(CDateTime, getMonth), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", asMETHOD(CDateTime, getDay), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", asMETHOD(CDateTime, getHour), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", asMETHOD(CDateTime, getMinute), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", asMETHOD(CDateTime, getSecond), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", asMETHOD(CDateTime, setDate), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", asMETHOD(CDateTime, setTime), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", asMETHODPR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", asMETHOD(CDateTime, operator+), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", asFUNCTIONPR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", asMETHOD(CDateTime, operator+=), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", asMETHODPR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", asFUNCTIONPR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", asMETHOD(CDateTime, operator-=), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", asMETHODPR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", asFUNCTION(opCmp), asCALL_CDECL_OBJFIRST); assert(r >= 0); + } + else + { + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", WRAP_OBJ_LAST(Construct), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", WRAP_OBJ_FIRST(ConstructCopy), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", WRAP_MFN(CDateTime, operator=), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", WRAP_MFN(CDateTime, getYear), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", WRAP_MFN(CDateTime, getMonth), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", WRAP_MFN(CDateTime, getDay), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", WRAP_MFN(CDateTime, getHour), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", WRAP_MFN(CDateTime, getMinute), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", WRAP_MFN(CDateTime, getSecond), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", WRAP_MFN(CDateTime, setDate), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", WRAP_MFN(CDateTime, setTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", WRAP_MFN(CDateTime, operator+), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", WRAP_MFN(CDateTime, operator+=), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", WRAP_MFN_PR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", WRAP_MFN(CDateTime, operator-=), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", WRAP_OBJ_FIRST(opCmp), asCALL_GENERIC); assert(r >= 0); + } } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/datetime/datetime.h b/src/angelscript/add_on/datetime/datetime.h index 8148da9e278..2fcd26048ae 100644 --- a/src/angelscript/add_on/datetime/datetime.h +++ b/src/angelscript/add_on/datetime/datetime.h @@ -1,7 +1,7 @@ #ifndef SCRIPTDATETIME_H #define SCRIPTDATETIME_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -17,41 +17,41 @@ BEGIN_AS_NAMESPACE class CDateTime { public: - // Constructors - CDateTime(); - CDateTime(const CDateTime &other); - CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second); - - // Copy the stored value from another any object - CDateTime &operator=(const CDateTime &other); - - // Accessors - asUINT getYear() const; - asUINT getMonth() const; - asUINT getDay() const; - asUINT getHour() const; - asUINT getMinute() const; - asUINT getSecond() const; - - // Setters - // Returns true if valid - bool setDate(asUINT year, asUINT month, asUINT day); - bool setTime(asUINT hour, asUINT minute, asUINT second); - - // Operators - // Return difference in seconds - asINT64 operator-(const CDateTime &other) const; - CDateTime operator+(asINT64 seconds) const; - friend CDateTime operator+(asINT64 seconds, const CDateTime &other); - CDateTime & operator+=(asINT64 seconds); - CDateTime operator-(asINT64 seconds) const; - friend CDateTime operator-(asINT64 seconds, const CDateTime &other); - CDateTime & operator-=(asINT64 seconds); - bool operator==(const CDateTime &other) const; - bool operator<(const CDateTime &other) const; + // Constructors + CDateTime(); + CDateTime(const CDateTime &other); + CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second); + + // Copy the stored value from another any object + CDateTime &operator=(const CDateTime &other); + + // Accessors + asUINT getYear() const; + asUINT getMonth() const; + asUINT getDay() const; + asUINT getHour() const; + asUINT getMinute() const; + asUINT getSecond() const; + + // Setters + // Returns true if valid + bool setDate(asUINT year, asUINT month, asUINT day); + bool setTime(asUINT hour, asUINT minute, asUINT second); + + // Operators + // Return difference in seconds + asINT64 operator-(const CDateTime &other) const; + CDateTime operator+(asINT64 seconds) const; + friend CDateTime operator+(asINT64 seconds, const CDateTime &other); + CDateTime & operator+=(asINT64 seconds); + CDateTime operator-(asINT64 seconds) const; + friend CDateTime operator-(asINT64 seconds, const CDateTime &other); + CDateTime & operator-=(asINT64 seconds); + bool operator==(const CDateTime &other) const; + bool operator<(const CDateTime &other) const; protected: - std::chrono::system_clock::time_point tp; + std::chrono::system_clock::time_point tp; }; void RegisterScriptDateTime(asIScriptEngine *engine); diff --git a/src/angelscript/add_on/debugger/debugger.cpp b/src/angelscript/add_on/debugger/debugger.cpp index 1554d70a659..625e903e27b 100644 --- a/src/angelscript/add_on/debugger/debugger.cpp +++ b/src/angelscript/add_on/debugger/debugger.cpp @@ -10,843 +10,843 @@ BEGIN_AS_NAMESPACE CDebugger::CDebugger() { - m_action = CONTINUE; - m_lastFunction = 0; - m_engine = 0; + m_action = CONTINUE; + m_lastFunction = 0; + m_engine = 0; } CDebugger::~CDebugger() { - SetEngine(0); + SetEngine(0); } string CDebugger::ToString(void *value, asUINT typeId, int expandMembers, asIScriptEngine *engine) { - if( value == 0 ) - return ""; - - // If no engine pointer was provided use the default - if( engine == 0 ) - engine = m_engine; - - 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( value == 0 ) + return ""; + + // If no engine pointer was provided use the default + if( engine == 0 ) + engine = m_engine; + + 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 + s << "{...}"; // MSVC6 doesn't like the << operator for 64bit integer #else - s << *(asINT64*)value; + 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 ) + 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 + s << "{...}"; // MSVC6 doesn't like the << operator for 64bit integer #else - s << *(asQWORD*)value; + 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 - if( engine ) - { - asITypeInfo *t = engine->GetTypeInfoById(typeId); - for( int n = t->GetEnumValueCount(); n-- > 0; ) - { - int enumVal; - const char *enumName = t->GetEnumValueByIndex(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 > 0 ) - { - asITypeInfo *type = obj->GetObjectType(); - for( asUINT n = 0; n < obj->GetPropertyCount(); n++ ) - { - if( n == 0 ) - s << " "; - else - s << ", "; - - s << type->GetPropertyDeclaration(n) << " = " << ToString(obj->GetAddressOfProperty(n), obj->GetPropertyTypeId(n), expandMembers - 1, type->GetEngine()); - } - } - } - 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 - if( engine ) - { - asITypeInfo *type = engine->GetTypeInfoById(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 ) - { - asITypeInfo *tmplType = engine->GetTypeInfoByName(type->GetName()); - it = m_toStringCallbacks.find(tmplType); - } - } - - if( it != m_toStringCallbacks.end() ) - { - if( type->GetFlags() & asOBJ_REF ) - s << " "; - - // Invoke the callback to get the string representation of this type - string str = it->second(value, expandMembers, this); - s << str; - } - } - } - else - s << "{no engine}"; - } - - return s.str(); + 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 + if( engine ) + { + asITypeInfo *t = engine->GetTypeInfoById(typeId); + for( int n = t->GetEnumValueCount(); n-- > 0; ) + { + int enumVal; + const char *enumName = t->GetEnumValueByIndex(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 > 0 ) + { + asITypeInfo *type = obj->GetObjectType(); + for( asUINT n = 0; n < obj->GetPropertyCount(); n++ ) + { + if( n == 0 ) + s << " "; + else + s << ", "; + + s << type->GetPropertyDeclaration(n) << " = " << ToString(obj->GetAddressOfProperty(n), obj->GetPropertyTypeId(n), expandMembers - 1, type->GetEngine()); + } + } + } + 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 + if( engine ) + { + asITypeInfo *type = engine->GetTypeInfoById(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 ) + { + asITypeInfo *tmplType = engine->GetTypeInfoByName(type->GetName()); + it = m_toStringCallbacks.find(tmplType); + } + } + + if( it != m_toStringCallbacks.end() ) + { + if( type->GetFlags() & asOBJ_REF ) + s << " "; + + // Invoke the callback to get the string representation of this type + string str = it->second(value, expandMembers, this); + s << str; + } + } + } + else + s << "{no engine}"; + } + + return s.str(); } void CDebugger::RegisterToStringCallback(const asITypeInfo *ot, ToStringCallback callback) { - if( m_toStringCallbacks.find(ot) == m_toStringCallbacks.end() ) - m_toStringCallbacks.insert(map::value_type(ot, 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); + 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; + 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]; + for(;;) + { + char buf[512]; - Output("[dbg]> "); - cin.getline(buf, 512); + Output("[dbg]> "); + cin.getline(buf, 512); - if( InterpretCommand(string(buf), ctx) ) - break; - } + 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': - m_action = STEP_OVER; - m_lastCommandAtStackLevel = ctx ? ctx->GetCallstackSize() : 1; - break; - - case 'o': - m_action = STEP_OUT; - m_lastCommandAtStackLevel = ctx ? ctx->GetCallstackSize() : 0; - break; - - case 'b': - { - // Set break point - size_t p = cmd.find_first_not_of(" \t", 1); - size_t div = cmd.find(':'); - if( div != string::npos && div > 2 && p > 1 ) - { - 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 && p != string::npos && p > 1 ) - { - string func = cmd.substr(p); - - 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 - size_t p = cmd.find_first_not_of(" \t", 1); - if( cmd.length() > 2 && p != string::npos && p > 1 ) - { - 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 - bool printHelp = false; - size_t p = cmd.find_first_not_of(" \t", 1); - if( p != string::npos && p > 1 ) - { - 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.\n"); - printHelp = true; - } - } - else - { - Output("Incorrect format for list command.\n"); - printHelp = true; - } - - if( printHelp ) - { - Output("Expected format: \n" - " l \n" - "Available options: \n" - " b - breakpoints\n" - " v - local variables\n" - " m - member properties\n" - " g - global variables\n" - " s - statistics\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 && p > 1 ) - { - 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; + if( cmd.length() == 0 ) return true; + + switch( cmd[0] ) + { + case 'c': + m_action = CONTINUE; + break; + + case 's': + m_action = STEP_INTO; + break; + + case 'n': + m_action = STEP_OVER; + m_lastCommandAtStackLevel = ctx ? ctx->GetCallstackSize() : 1; + break; + + case 'o': + m_action = STEP_OUT; + m_lastCommandAtStackLevel = ctx ? ctx->GetCallstackSize() : 0; + break; + + case 'b': + { + // Set break point + size_t p = cmd.find_first_not_of(" \t", 1); + size_t div = cmd.find(':'); + if( div != string::npos && div > 2 && p > 1 ) + { + 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 && p != string::npos && p > 1 ) + { + string func = cmd.substr(p); + + 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 + size_t p = cmd.find_first_not_of(" \t", 1); + if( cmd.length() > 2 && p != string::npos && p > 1 ) + { + 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 + bool printHelp = false; + size_t p = cmd.find_first_not_of(" \t", 1); + if( p != string::npos && p > 1 ) + { + 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.\n"); + printHelp = true; + } + } + else + { + Output("Incorrect format for list command.\n"); + printHelp = true; + } + + if( printHelp ) + { + Output("Expected format: \n" + " l \n" + "Available options: \n" + " b - breakpoints\n" + " v - local variables\n" + " m - member properties\n" + " g - global variables\n" + " s - statistics\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 && p > 1 ) + { + 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(); - - // Tokenize the input string to get the variable scope and name - asUINT len = 0; - string scope; - string name; - string str = expr; - asETokenClass t = engine->ParseToken(str.c_str(), 0, &len); - while( t == asTC_IDENTIFIER || (t == asTC_KEYWORD && len == 2 && str.compare(0, 2, "::") == 0) ) - { - if( t == asTC_KEYWORD ) - { - if( scope == "" && name == "" ) - scope = "::"; // global scope - else if( scope == "::" || scope == "" ) - scope = name; // namespace - else - scope += "::" + name; // nested namespace - name = ""; - } - else if( t == asTC_IDENTIFIER ) - name.assign(str.c_str(), len); - - // Skip the parsed token and get the next one - str = str.substr(len); - t = engine->ParseToken(str.c_str(), 0, &len); - } - - if( name.size() ) - { - // Find the variable - void *ptr = 0; - int typeId = 0; - - asIScriptFunction *func = ctx->GetFunction(); - if( !func ) return; - - // skip local variables if a scope was informed - if( scope == "" ) - { - // 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 - { - asITypeInfo *type = engine->GetTypeInfoById(ctx->GetThisTypeId()); - for( asUINT n = 0; n < type->GetPropertyCount(); n++ ) - { - const char *propName = 0; - int offset = 0; - bool isReference = 0; - int compositeOffset = 0; - bool isCompositeIndirect = false; - type->GetProperty(n, &propName, &typeId, 0, 0, &offset, &isReference, 0, &compositeOffset, &isCompositeIndirect); - if( name == propName ) - { - ptr = (void*)(((asBYTE*)ctx->GetThisPointer())+compositeOffset); - if (isCompositeIndirect) ptr = *(void**)ptr; - ptr = (void*)(((asBYTE*)ptr) + offset); - if( isReference ) ptr = *(void**)ptr; - break; - } - } - } - } - } - - // Look for global variables - if( !ptr ) - { - if( scope == "" ) - { - // If no explicit scope was informed then use the namespace of the current function by default - scope = func->GetNamespace(); - } - else if( scope == "::" ) - { - // The global namespace will be empty - scope = ""; - } - - asIScriptModule *mod = func->GetModule(); - if( mod ) - { - for( asUINT n = 0; n < mod->GetGlobalVarCount(); n++ ) - { - const char *varName = 0, *nameSpace = 0; - mod->GetGlobalVar(n, &varName, &nameSpace, &typeId); - - // Check if both name and namespace match - if( name == varName && scope == nameSpace ) - { - ptr = mod->GetAddressOfGlobalVar(n); - break; - } - } - } - } - - if( ptr ) - { - // TODO: If there is a . after the identifier, check for members - // TODO: If there is a [ after the identifier try to call the 'opIndex(expr) const' method - if( str != "" ) - { - Output("Invalid expression. Expression doesn't end after symbol\n"); - } - else - { - stringstream s; - // TODO: Allow user to set if members should be expanded - // Expand members by default to 3 recursive levels only - s << ToString(ptr, typeId, 3, engine) << endl; - Output(s.str()); - } - } - else - { - Output("Invalid expression. No matching symbol\n"); - } - } - else - { - Output("Invalid expression. Expected identifier\n"); - } + if( ctx == 0 ) + { + Output("No script is running\n"); + return; + } + + asIScriptEngine *engine = ctx->GetEngine(); + + // Tokenize the input string to get the variable scope and name + asUINT len = 0; + string scope; + string name; + string str = expr; + asETokenClass t = engine->ParseToken(str.c_str(), 0, &len); + while( t == asTC_IDENTIFIER || (t == asTC_KEYWORD && len == 2 && str.compare(0, 2, "::") == 0) ) + { + if( t == asTC_KEYWORD ) + { + if( scope == "" && name == "" ) + scope = "::"; // global scope + else if( scope == "::" || scope == "" ) + scope = name; // namespace + else + scope += "::" + name; // nested namespace + name = ""; + } + else if( t == asTC_IDENTIFIER ) + name.assign(str.c_str(), len); + + // Skip the parsed token and get the next one + str = str.substr(len); + t = engine->ParseToken(str.c_str(), 0, &len); + } + + if( name.size() ) + { + // Find the variable + void *ptr = 0; + int typeId = 0; + + asIScriptFunction *func = ctx->GetFunction(); + if( !func ) return; + + // skip local variables if a scope was informed + if( scope == "" ) + { + // 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 + { + asITypeInfo *type = engine->GetTypeInfoById(ctx->GetThisTypeId()); + for( asUINT n = 0; n < type->GetPropertyCount(); n++ ) + { + const char *propName = 0; + int offset = 0; + bool isReference = 0; + int compositeOffset = 0; + bool isCompositeIndirect = false; + type->GetProperty(n, &propName, &typeId, 0, 0, &offset, &isReference, 0, &compositeOffset, &isCompositeIndirect); + if( name == propName ) + { + ptr = (void*)(((asBYTE*)ctx->GetThisPointer())+compositeOffset); + if (isCompositeIndirect) ptr = *(void**)ptr; + ptr = (void*)(((asBYTE*)ptr) + offset); + if( isReference ) ptr = *(void**)ptr; + break; + } + } + } + } + } + + // Look for global variables + if( !ptr ) + { + if( scope == "" ) + { + // If no explicit scope was informed then use the namespace of the current function by default + scope = func->GetNamespace(); + } + else if( scope == "::" ) + { + // The global namespace will be empty + scope = ""; + } + + asIScriptModule *mod = func->GetModule(); + if( mod ) + { + for( asUINT n = 0; n < mod->GetGlobalVarCount(); n++ ) + { + const char *varName = 0, *nameSpace = 0; + mod->GetGlobalVar(n, &varName, &nameSpace, &typeId); + + // Check if both name and namespace match + if( name == varName && scope == nameSpace ) + { + ptr = mod->GetAddressOfGlobalVar(n); + break; + } + } + } + } + + if( ptr ) + { + // TODO: If there is a . after the identifier, check for members + // TODO: If there is a [ after the identifier try to call the 'opIndex(expr) const' method + if( str != "" ) + { + Output("Invalid expression. Expression doesn't end after symbol\n"); + } + else + { + stringstream s; + // TODO: Allow user to set if members should be expanded + // Expand members by default to 3 recursive levels only + s << ToString(ptr, typeId, 3, engine) << endl; + Output(s.str()); + } + } + else + { + Output("Invalid expression. No matching symbol\n"); + } + } + 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()); + // 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; - // TODO: Allow user to define if members should be expanded or not - // Expand members by default to 3 recursive levels only - s << "this = " << ToString(ptr, ctx->GetThisTypeId(), 3, ctx->GetEngine()) << endl; - Output(s.str()); - } + if( ctx == 0 ) + { + Output("No script is running\n"); + return; + } + + void *ptr = ctx->GetThisPointer(); + if( ptr ) + { + stringstream s; + // TODO: Allow user to define if members should be expanded or not + // Expand members by default to 3 recursive levels only + s << "this = " << ToString(ptr, ctx->GetThisTypeId(), 3, 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) ) - { - // TODO: Allow user to set if members should be expanded or not - // Expand members by default to 3 recursive levels only - s << func->GetVarDecl(n) << " = " << ToString(ctx->GetAddressOfVar(n), ctx->GetVarTypeId(n), 3, ctx->GetEngine()) << endl; - } - } - Output(s.str()); + 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) ) + { + // TODO: Allow user to set if members should be expanded or not + // Expand members by default to 3 recursive levels only + s << func->GetVarDecl(n) << " = " << ToString(ctx->GetAddressOfVar(n), ctx->GetVarTypeId(n), 3, 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); - // TODO: Allow user to set how many recursive expansions should be done - // Expand members by default to 3 recursive levels only - s << mod->GetGlobalVarDeclaration(n) << " = " << ToString(mod->GetAddressOfGlobalVar(n), typeId, 3, ctx->GetEngine()) << endl; - } - Output(s.str()); + 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); + // TODO: Allow user to set how many recursive expansions should be done + // Expand members by default to 3 recursive levels only + s << mod->GetGlobalVarDeclaration(n) << " = " << ToString(mod->GetAddressOfGlobalVar(n), typeId, 3, 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()); + 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 ? file : "{unnamed}") << ":" << lineNbr << "; " << ctx->GetFunction(n)->GetDeclaration() << endl; - } - Output(s.str()); + 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 ? file : "{unnamed}") << ":" << 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); + // 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()); + stringstream s; + s << "Adding deferred break point for function '" << actual << "'" << endl; + Output(s.str()); - BreakPoint bp(actual, 0, true); - m_breakPoints.push_back(bp); + 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); + // 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"); + 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; + // By default we just output to stdout + cout << str; } void CDebugger::SetEngine(asIScriptEngine *engine) { - if( m_engine != engine ) - { - if( m_engine ) - m_engine->Release(); - m_engine = engine; - if( m_engine ) - m_engine->AddRef(); - } + if( m_engine != engine ) + { + if( m_engine ) + m_engine->Release(); + m_engine = engine; + if( m_engine ) + m_engine->AddRef(); + } } asIScriptEngine *CDebugger::GetEngine() { - return m_engine; + return m_engine; } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/debugger/debugger.h b/src/angelscript/add_on/debugger/debugger.h index 3bb560c7549..102beac6b6c 100644 --- a/src/angelscript/add_on/debugger/debugger.h +++ b/src/angelscript/add_on/debugger/debugger.h @@ -1,7 +1,7 @@ #ifndef DEBUGGER_H #define DEBUGGER_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -15,71 +15,71 @@ BEGIN_AS_NAMESPACE class CDebugger { public: - CDebugger(); - virtual ~CDebugger(); - - // Register callbacks to handle to-string conversions of application types - // The expandMembersLevel is a counter for how many recursive levels the members should be expanded. - // If the object that is being converted to a string has members of its own the callback should call - // the debugger's ToString passing in expandMembersLevel - 1. - typedef std::string (*ToStringCallback)(void *obj, int expandMembersLevel, CDebugger *dbg); - virtual void RegisterToStringCallback(const asITypeInfo *ti, 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, int expandMembersLevel, asIScriptEngine *engine); - - // Optionally set the engine pointer in the debugger so it can be retrieved - // by callbacks that need it. This will hold a reference to the engine. - virtual void SetEngine(asIScriptEngine *engine); - virtual asIScriptEngine *GetEngine(); - + CDebugger(); + virtual ~CDebugger(); + + // Register callbacks to handle to-string conversions of application types + // The expandMembersLevel is a counter for how many recursive levels the members should be expanded. + // If the object that is being converted to a string has members of its own the callback should call + // the debugger's ToString passing in expandMembersLevel - 1. + typedef std::string (*ToStringCallback)(void *obj, int expandMembersLevel, CDebugger *dbg); + virtual void RegisterToStringCallback(const asITypeInfo *ti, 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, int expandMembersLevel, asIScriptEngine *engine); + + // Optionally set the engine pointer in the debugger so it can be retrieved + // by callbacks that need it. This will hold a reference to the engine. + virtual void SetEngine(asIScriptEngine *engine); + virtual asIScriptEngine *GetEngine(); + 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; - - asIScriptEngine *m_engine; - - // Registered callbacks for converting types to strings - std::map m_toStringCallbacks; + 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; + + asIScriptEngine *m_engine; + + // Registered callbacks for converting types to strings + std::map m_toStringCallbacks; }; END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scriptany/scriptany.cpp b/src/angelscript/add_on/scriptany/scriptany.cpp index a7cf312a3d8..173452cbe6b 100644 --- a/src/angelscript/add_on/scriptany/scriptany.cpp +++ b/src/angelscript/add_on/scriptany/scriptany.cpp @@ -8,482 +8,482 @@ BEGIN_AS_NAMESPACE // We'll use the generic interface for the factories as we need the engine pointer static void ScriptAnyFactory_Generic(asIScriptGeneric *gen) { - asIScriptEngine *engine = gen->GetEngine(); + asIScriptEngine *engine = gen->GetEngine(); - *(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(engine); + *(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(engine); } static void ScriptAnyFactory2_Generic(asIScriptGeneric *gen) { - asIScriptEngine *engine = gen->GetEngine(); - void *ref = (void*)gen->GetArgAddress(0); - int refType = gen->GetArgTypeId(0); + asIScriptEngine *engine = gen->GetEngine(); + void *ref = (void*)gen->GetArgAddress(0); + int refType = gen->GetArgTypeId(0); - *(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(ref,refType,engine); + *(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(ref,refType,engine); } static CScriptAny &ScriptAnyAssignment(CScriptAny *other, CScriptAny *self) { - return *self = *other; + return *self = *other; } static void ScriptAnyAssignment_Generic(asIScriptGeneric *gen) { - CScriptAny *other = (CScriptAny*)gen->GetArgObject(0); - CScriptAny *self = (CScriptAny*)gen->GetObject(); + CScriptAny *other = (CScriptAny*)gen->GetArgObject(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); - *self = *other; + *self = *other; - gen->SetReturnObject(self); + gen->SetReturnObject(self); } static void ScriptAny_Store_Generic(asIScriptGeneric *gen) { - void *ref = (void*)gen->GetArgAddress(0); - int refTypeId = gen->GetArgTypeId(0); - CScriptAny *self = (CScriptAny*)gen->GetObject(); + void *ref = (void*)gen->GetArgAddress(0); + int refTypeId = gen->GetArgTypeId(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); - self->Store(ref, refTypeId); + self->Store(ref, refTypeId); } static void ScriptAny_StoreInt_Generic(asIScriptGeneric *gen) { - asINT64 *ref = (asINT64*)gen->GetArgAddress(0); - CScriptAny *self = (CScriptAny*)gen->GetObject(); + asINT64 *ref = (asINT64*)gen->GetArgAddress(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); - self->Store(*ref); + self->Store(*ref); } static void ScriptAny_StoreFlt_Generic(asIScriptGeneric *gen) { - double *ref = (double*)gen->GetArgAddress(0); - CScriptAny *self = (CScriptAny*)gen->GetObject(); + double *ref = (double*)gen->GetArgAddress(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); - self->Store(*ref); + self->Store(*ref); } static void ScriptAny_Retrieve_Generic(asIScriptGeneric *gen) { - void *ref = (void*)gen->GetArgAddress(0); - int refTypeId = gen->GetArgTypeId(0); - CScriptAny *self = (CScriptAny*)gen->GetObject(); + void *ref = (void*)gen->GetArgAddress(0); + int refTypeId = gen->GetArgTypeId(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(ref, refTypeId); + *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(ref, refTypeId); } static void ScriptAny_RetrieveInt_Generic(asIScriptGeneric *gen) { - asINT64 *ref = (asINT64*)gen->GetArgAddress(0); - CScriptAny *self = (CScriptAny*)gen->GetObject(); + asINT64 *ref = (asINT64*)gen->GetArgAddress(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref); + *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref); } static void ScriptAny_RetrieveFlt_Generic(asIScriptGeneric *gen) { - double *ref = (double*)gen->GetArgAddress(0); - CScriptAny *self = (CScriptAny*)gen->GetObject(); + double *ref = (double*)gen->GetArgAddress(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref); + *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref); } static void ScriptAny_AddRef_Generic(asIScriptGeneric *gen) { - CScriptAny *self = (CScriptAny*)gen->GetObject(); - self->AddRef(); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + self->AddRef(); } static void ScriptAny_Release_Generic(asIScriptGeneric *gen) { - CScriptAny *self = (CScriptAny*)gen->GetObject(); - self->Release(); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + self->Release(); } static void ScriptAny_GetRefCount_Generic(asIScriptGeneric *gen) { - CScriptAny *self = (CScriptAny*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); } static void ScriptAny_SetFlag_Generic(asIScriptGeneric *gen) { - CScriptAny *self = (CScriptAny*)gen->GetObject(); - self->SetFlag(); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + self->SetFlag(); } static void ScriptAny_GetFlag_Generic(asIScriptGeneric *gen) { - CScriptAny *self = (CScriptAny*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); } static void ScriptAny_EnumReferences_Generic(asIScriptGeneric *gen) { - CScriptAny *self = (CScriptAny*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); } static void ScriptAny_ReleaseAllHandles_Generic(asIScriptGeneric *gen) { - CScriptAny *self = (CScriptAny*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllHandles(engine); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllHandles(engine); } void RegisterScriptAny(asIScriptEngine *engine) { - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptAny_Generic(engine); - else - RegisterScriptAny_Native(engine); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptAny_Generic(engine); + else + RegisterScriptAny_Native(engine); } void RegisterScriptAny_Native(asIScriptEngine *engine) { - int r; - r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); - - // We'll use the generic interface for the constructor as we need the engine pointer - r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); - - r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptAny,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptAny,Release), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "void store(?&in)", asMETHODPR(CScriptAny,Store,(void*,int),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asMETHODPR(CScriptAny,Store,(asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "void store(const double&in)", asMETHODPR(CScriptAny,Store,(double&),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "bool retrieve(?&out)", asMETHODPR(CScriptAny,Retrieve,(void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out)", asMETHODPR(CScriptAny,Retrieve,(asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "bool retrieve(double&out)", asMETHODPR(CScriptAny,Retrieve,(double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); - - // Register GC behaviours - r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptAny,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptAny,SetFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptAny,GetFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptAny,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptAny,ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); + int r; + r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + + // We'll use the generic interface for the constructor as we need the engine pointer + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); + + r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptAny,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptAny,Release), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(?&in)", asMETHODPR(CScriptAny,Store,(void*,int),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asMETHODPR(CScriptAny,Store,(asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(const double&in)", asMETHODPR(CScriptAny,Store,(double&),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(?&out)", asMETHODPR(CScriptAny,Retrieve,(void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out)", asMETHODPR(CScriptAny,Retrieve,(asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(double&out)", asMETHODPR(CScriptAny,Retrieve,(double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptAny,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptAny,SetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptAny,GetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptAny,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptAny,ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); } void RegisterScriptAny_Generic(asIScriptEngine *engine) { - int r; - r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + int r; + r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); - // We'll use the generic interface for the constructor as we need the engine pointer - r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); + // We'll use the generic interface for the constructor as we need the engine pointer + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptAny_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptAny_Release_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "void store(?&in)", asFUNCTION(ScriptAny_Store_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asFUNCTION(ScriptAny_StoreInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "void store(const double&in)", asFUNCTION(ScriptAny_StoreFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "bool retrieve(?&out) const", asFUNCTION(ScriptAny_Retrieve_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out) const", asFUNCTION(ScriptAny_RetrieveInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("any", "bool retrieve(double&out) const", asFUNCTION(ScriptAny_RetrieveFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptAny_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptAny_Release_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(?&in)", asFUNCTION(ScriptAny_Store_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asFUNCTION(ScriptAny_StoreInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(const double&in)", asFUNCTION(ScriptAny_StoreFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(?&out) const", asFUNCTION(ScriptAny_Retrieve_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out) const", asFUNCTION(ScriptAny_RetrieveInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(double&out) const", asFUNCTION(ScriptAny_RetrieveFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); - // Register GC behaviours - r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptAny_GetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptAny_SetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptAny_GetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptAny_EnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptAny_ReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 ); + // Register GC behaviours + r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptAny_GetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptAny_SetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptAny_GetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptAny_EnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptAny_ReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 ); } CScriptAny &CScriptAny::operator=(const CScriptAny &other) { - // Hold on to the object type reference so it isn't destroyed too early - if( (other.value.typeId & asTYPEID_MASK_OBJECT) ) - { - asITypeInfo *ti = engine->GetTypeInfoById(other.value.typeId); - if( ti ) - ti->AddRef(); - } - - FreeObject(); - - value.typeId = other.value.typeId; - if( value.typeId & asTYPEID_OBJHANDLE ) - { - // For handles, copy the pointer and increment the reference count - value.valueObj = other.value.valueObj; - engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId)); - } - else if( value.typeId & asTYPEID_MASK_OBJECT ) - { - // Create a copy of the object - value.valueObj = engine->CreateScriptObjectCopy(other.value.valueObj, engine->GetTypeInfoById(value.typeId)); - } - else - { - // Primitives can be copied directly - value.valueInt = other.value.valueInt; - } - - return *this; + // Hold on to the object type reference so it isn't destroyed too early + if( (other.value.typeId & asTYPEID_MASK_OBJECT) ) + { + asITypeInfo *ti = engine->GetTypeInfoById(other.value.typeId); + if( ti ) + ti->AddRef(); + } + + FreeObject(); + + value.typeId = other.value.typeId; + if( value.typeId & asTYPEID_OBJHANDLE ) + { + // For handles, copy the pointer and increment the reference count + value.valueObj = other.value.valueObj; + engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId)); + } + else if( value.typeId & asTYPEID_MASK_OBJECT ) + { + // Create a copy of the object + value.valueObj = engine->CreateScriptObjectCopy(other.value.valueObj, engine->GetTypeInfoById(value.typeId)); + } + else + { + // Primitives can be copied directly + value.valueInt = other.value.valueInt; + } + + return *this; } int CScriptAny::CopyFrom(const CScriptAny *other) { - if( other == 0 ) return asINVALID_ARG; + if( other == 0 ) return asINVALID_ARG; - *this = *(CScriptAny*)other; + *this = *(CScriptAny*)other; - return 0; + return 0; } CScriptAny::CScriptAny(asIScriptEngine *engine) { - this->engine = engine; - refCount = 1; - gcFlag = false; + this->engine = engine; + refCount = 1; + gcFlag = false; - value.typeId = 0; - value.valueInt = 0; + value.typeId = 0; + value.valueInt = 0; - // Notify the garbage collector of this object - engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any")); + // Notify the garbage collector of this object + engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any")); } CScriptAny::CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine) { - this->engine = engine; - refCount = 1; - gcFlag = false; + this->engine = engine; + refCount = 1; + gcFlag = false; - value.typeId = 0; - value.valueInt = 0; + value.typeId = 0; + value.valueInt = 0; - // Notify the garbage collector of this object - engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any")); + // Notify the garbage collector of this object + engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any")); - Store(ref, refTypeId); + Store(ref, refTypeId); } CScriptAny::~CScriptAny() { - FreeObject(); + FreeObject(); } void CScriptAny::Store(void *ref, int refTypeId) { - // This method is not expected to be used for primitive types, except for bool, int64, or double - assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_VOID || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE ); - - // Hold on to the object type reference so it isn't destroyed too early - if( (refTypeId & asTYPEID_MASK_OBJECT) ) - { - asITypeInfo *ti = engine->GetTypeInfoById(refTypeId); - if( ti ) - ti->AddRef(); - } - - FreeObject(); - - value.typeId = refTypeId; - if( value.typeId & asTYPEID_OBJHANDLE ) - { - // We're receiving a reference to the handle, so we need to dereference it - value.valueObj = *(void**)ref; - engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId)); - } - else if( value.typeId & asTYPEID_MASK_OBJECT ) - { - // Create a copy of the object - value.valueObj = engine->CreateScriptObjectCopy(ref, engine->GetTypeInfoById(value.typeId)); - } - else - { - // Primitives can be copied directly - value.valueInt = 0; - - // Copy the primitive value - // We receive a pointer to the value. - int size = engine->GetSizeOfPrimitiveType(value.typeId); - memcpy(&value.valueInt, ref, size); - } + // This method is not expected to be used for primitive types, except for bool, int64, or double + assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_VOID || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE ); + + // Hold on to the object type reference so it isn't destroyed too early + if( (refTypeId & asTYPEID_MASK_OBJECT) ) + { + asITypeInfo *ti = engine->GetTypeInfoById(refTypeId); + if( ti ) + ti->AddRef(); + } + + FreeObject(); + + value.typeId = refTypeId; + if( value.typeId & asTYPEID_OBJHANDLE ) + { + // We're receiving a reference to the handle, so we need to dereference it + value.valueObj = *(void**)ref; + engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId)); + } + else if( value.typeId & asTYPEID_MASK_OBJECT ) + { + // Create a copy of the object + value.valueObj = engine->CreateScriptObjectCopy(ref, engine->GetTypeInfoById(value.typeId)); + } + else + { + // Primitives can be copied directly + value.valueInt = 0; + + // Copy the primitive value + // We receive a pointer to the value. + int size = engine->GetSizeOfPrimitiveType(value.typeId); + memcpy(&value.valueInt, ref, size); + } } void CScriptAny::Store(double &ref) { - Store(&ref, asTYPEID_DOUBLE); + Store(&ref, asTYPEID_DOUBLE); } void CScriptAny::Store(asINT64 &ref) { - Store(&ref, asTYPEID_INT64); + Store(&ref, asTYPEID_INT64); } bool CScriptAny::Retrieve(void *ref, int refTypeId) const { - // This method is not expected to be used for primitive types, except for bool, int64, or double - assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE ); - - if( refTypeId & asTYPEID_OBJHANDLE ) - { - // Is the handle type compatible with the stored value? - - // A handle can be retrieved if the stored type is a handle of same or compatible type - // or if the stored type is an object that implements the interface that the handle refer to. - if( (value.typeId & asTYPEID_MASK_OBJECT) ) - { - // Don't allow the retrieval if the stored handle is to a const object but not the wanted handle - if( (value.typeId & asTYPEID_HANDLETOCONST) && !(refTypeId & asTYPEID_HANDLETOCONST) ) - return false; - - // RefCastObject will increment the refCount of the returned pointer if successful - engine->RefCastObject(value.valueObj, engine->GetTypeInfoById(value.typeId), engine->GetTypeInfoById(refTypeId), reinterpret_cast(ref)); - if( *(asPWORD*)ref == 0 ) - return false; - return true; - } - } - else if( refTypeId & asTYPEID_MASK_OBJECT ) - { - // Is the object type compatible with the stored value? - - // Copy the object into the given reference - if( value.typeId == refTypeId ) - { - engine->AssignScriptObject(ref, value.valueObj, engine->GetTypeInfoById(value.typeId)); - return true; - } - } - else - { - // Is the primitive type compatible with the stored value? - - if( value.typeId == refTypeId ) - { - int size = engine->GetSizeOfPrimitiveType(refTypeId); - memcpy(ref, &value.valueInt, size); - return true; - } - - // We know all numbers are stored as either int64 or double, since we register overloaded functions for those - if( value.typeId == asTYPEID_INT64 && refTypeId == asTYPEID_DOUBLE ) - { - *(double*)ref = double(value.valueInt); - return true; - } - else if( value.typeId == asTYPEID_DOUBLE && refTypeId == asTYPEID_INT64 ) - { - *(asINT64*)ref = asINT64(value.valueFlt); - return true; - } - } - - return false; + // This method is not expected to be used for primitive types, except for bool, int64, or double + assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE ); + + if( refTypeId & asTYPEID_OBJHANDLE ) + { + // Is the handle type compatible with the stored value? + + // A handle can be retrieved if the stored type is a handle of same or compatible type + // or if the stored type is an object that implements the interface that the handle refer to. + if( (value.typeId & asTYPEID_MASK_OBJECT) ) + { + // Don't allow the retrieval if the stored handle is to a const object but not the wanted handle + if( (value.typeId & asTYPEID_HANDLETOCONST) && !(refTypeId & asTYPEID_HANDLETOCONST) ) + return false; + + // RefCastObject will increment the refCount of the returned pointer if successful + engine->RefCastObject(value.valueObj, engine->GetTypeInfoById(value.typeId), engine->GetTypeInfoById(refTypeId), reinterpret_cast(ref)); + if( *(asPWORD*)ref == 0 ) + return false; + return true; + } + } + else if( refTypeId & asTYPEID_MASK_OBJECT ) + { + // Is the object type compatible with the stored value? + + // Copy the object into the given reference + if( value.typeId == refTypeId ) + { + engine->AssignScriptObject(ref, value.valueObj, engine->GetTypeInfoById(value.typeId)); + return true; + } + } + else + { + // Is the primitive type compatible with the stored value? + + if( value.typeId == refTypeId ) + { + int size = engine->GetSizeOfPrimitiveType(refTypeId); + memcpy(ref, &value.valueInt, size); + return true; + } + + // We know all numbers are stored as either int64 or double, since we register overloaded functions for those + if( value.typeId == asTYPEID_INT64 && refTypeId == asTYPEID_DOUBLE ) + { + *(double*)ref = double(value.valueInt); + return true; + } + else if( value.typeId == asTYPEID_DOUBLE && refTypeId == asTYPEID_INT64 ) + { + *(asINT64*)ref = asINT64(value.valueFlt); + return true; + } + } + + return false; } bool CScriptAny::Retrieve(asINT64 &outValue) const { - return Retrieve(&outValue, asTYPEID_INT64); + return Retrieve(&outValue, asTYPEID_INT64); } bool CScriptAny::Retrieve(double &outValue) const { - return Retrieve(&outValue, asTYPEID_DOUBLE); + return Retrieve(&outValue, asTYPEID_DOUBLE); } int CScriptAny::GetTypeId() const { - return value.typeId; + return value.typeId; } void CScriptAny::FreeObject() { - // If it is a handle or a ref counted object, call release - if( value.typeId & asTYPEID_MASK_OBJECT ) - { - // Let the engine release the object - asITypeInfo *ti = engine->GetTypeInfoById(value.typeId); - engine->ReleaseScriptObject(value.valueObj, ti); + // If it is a handle or a ref counted object, call release + if( value.typeId & asTYPEID_MASK_OBJECT ) + { + // Let the engine release the object + asITypeInfo *ti = engine->GetTypeInfoById(value.typeId); + engine->ReleaseScriptObject(value.valueObj, ti); - // Release the object type info - if( ti ) - ti->Release(); + // Release the object type info + if( ti ) + ti->Release(); - value.valueObj = 0; - value.typeId = 0; - } + value.valueObj = 0; + value.typeId = 0; + } - // For primitives, there's nothing to do + // For primitives, there's nothing to do } void CScriptAny::EnumReferences(asIScriptEngine *inEngine) { - // If we're holding a reference, we'll notify the garbage collector of it - if (value.valueObj && (value.typeId & asTYPEID_MASK_OBJECT)) - { - asITypeInfo *subType = engine->GetTypeInfoById(value.typeId); - if ((subType->GetFlags() & asOBJ_REF)) - { - inEngine->GCEnumCallback(value.valueObj); - } - else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) - { - // For value types we need to forward the enum callback - // to the object so it can decide what to do - engine->ForwardGCEnumReferences(value.valueObj, subType); - } - - // The object type itself is also garbage collected - asITypeInfo *ti = inEngine->GetTypeInfoById(value.typeId); - if (ti) - inEngine->GCEnumCallback(ti); - } + // If we're holding a reference, we'll notify the garbage collector of it + if (value.valueObj && (value.typeId & asTYPEID_MASK_OBJECT)) + { + asITypeInfo *subType = engine->GetTypeInfoById(value.typeId); + if ((subType->GetFlags() & asOBJ_REF)) + { + inEngine->GCEnumCallback(value.valueObj); + } + else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + engine->ForwardGCEnumReferences(value.valueObj, subType); + } + + // The object type itself is also garbage collected + asITypeInfo *ti = inEngine->GetTypeInfoById(value.typeId); + if (ti) + inEngine->GCEnumCallback(ti); + } } void CScriptAny::ReleaseAllHandles(asIScriptEngine * /*engine*/) { - FreeObject(); + FreeObject(); } int CScriptAny::AddRef() const { - // Increase counter and clear flag set by GC - gcFlag = false; - return asAtomicInc(refCount); + // Increase counter and clear flag set by GC + gcFlag = false; + return asAtomicInc(refCount); } int CScriptAny::Release() const { - // Decrease the ref counter - gcFlag = false; - if( asAtomicDec(refCount) == 0 ) - { - // Delete this object as no more references to it exists - delete this; - return 0; - } + // Decrease the ref counter + gcFlag = false; + if( asAtomicDec(refCount) == 0 ) + { + // Delete this object as no more references to it exists + delete this; + return 0; + } - return refCount; + return refCount; } int CScriptAny::GetRefCount() { - return refCount; + return refCount; } void CScriptAny::SetFlag() { - gcFlag = true; + gcFlag = true; } bool CScriptAny::GetFlag() { - return gcFlag; + return gcFlag; } diff --git a/src/angelscript/add_on/scriptany/scriptany.h b/src/angelscript/add_on/scriptany/scriptany.h index 4b23f576703..677bb01c0b3 100644 --- a/src/angelscript/add_on/scriptany/scriptany.h +++ b/src/angelscript/add_on/scriptany/scriptany.h @@ -1,7 +1,7 @@ #ifndef SCRIPTANY_H #define SCRIPTANY_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -9,50 +9,50 @@ BEGIN_AS_NAMESPACE -class CScriptAny +class CScriptAny { public: - // Constructors - CScriptAny(asIScriptEngine *engine); - CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine); - - // Memory management - int AddRef() const; - int Release() const; - - // Copy the stored value from another any object - CScriptAny &operator=(const CScriptAny&); - int CopyFrom(const CScriptAny *other); - - // Store the value, either as variable type, integer number, or real number - void Store(void *ref, int refTypeId); - void Store(asINT64 &value); - void Store(double &value); - - // Retrieve the stored value, either as variable type, integer number, or real number - bool Retrieve(void *ref, int refTypeId) const; - bool Retrieve(asINT64 &value) const; - bool Retrieve(double &value) const; - - // Get the type id of the stored value - int GetTypeId() const; - - // GC methods - int GetRefCount(); - void SetFlag(); - bool GetFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllHandles(asIScriptEngine *engine); + // Constructors + CScriptAny(asIScriptEngine *engine); + CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine); + + // Memory management + int AddRef() const; + int Release() const; + + // Copy the stored value from another any object + CScriptAny &operator=(const CScriptAny&); + int CopyFrom(const CScriptAny *other); + + // Store the value, either as variable type, integer number, or real number + void Store(void *ref, int refTypeId); + void Store(asINT64 &value); + void Store(double &value); + + // Retrieve the stored value, either as variable type, integer number, or real number + bool Retrieve(void *ref, int refTypeId) const; + bool Retrieve(asINT64 &value) const; + bool Retrieve(double &value) const; + + // Get the type id of the stored value + int GetTypeId() const; + + // GC methods + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); protected: - virtual ~CScriptAny(); - void FreeObject(); + virtual ~CScriptAny(); + void FreeObject(); - mutable int refCount; - mutable bool gcFlag; - asIScriptEngine *engine; + mutable int refCount; + mutable bool gcFlag; + asIScriptEngine *engine; - // The structure for holding the values + // The structure for holding the values struct valueStruct { union @@ -64,7 +64,7 @@ class CScriptAny int typeId; }; - valueStruct value; + valueStruct value; }; void RegisterScriptAny(asIScriptEngine *engine); diff --git a/src/angelscript/add_on/scriptarray/scriptarray.cpp b/src/angelscript/add_on/scriptarray/scriptarray.cpp index 58512f36cec..bf44da7b2cd 100644 --- a/src/angelscript/add_on/scriptarray/scriptarray.cpp +++ b/src/angelscript/add_on/scriptarray/scriptarray.cpp @@ -24,8 +24,8 @@ static asFREEFUNC_t userFree = asFreeMem; // Allows the application to set which memory routines should be used by the array object void CScriptArray::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) { - userAlloc = allocFunc; - userFree = freeFunc; + userAlloc = allocFunc; + userFree = freeFunc; } static void RegisterScriptArray_Native(asIScriptEngine *engine); @@ -33,17 +33,17 @@ static void RegisterScriptArray_Generic(asIScriptEngine *engine); struct SArrayBuffer { - asDWORD maxElements; - asDWORD numElements; - asBYTE data[1]; + asDWORD maxElements; + asDWORD numElements; + asBYTE data[1]; }; struct SArrayCache { - asIScriptFunction *cmpFunc; - asIScriptFunction *eqFunc; - int cmpFuncReturnCode; // To allow better error message in case of multiple matches - int eqFuncReturnCode; + asIScriptFunction *cmpFunc; + asIScriptFunction *eqFunc; + int cmpFuncReturnCode; // To allow better error message in case of multiple matches + int eqFuncReturnCode; }; // We just define a number here that we assume nobody else is using for @@ -53,74 +53,74 @@ const asPWORD ARRAY_CACHE = 1000; static void CleanupTypeInfoArrayCache(asITypeInfo *type) { - SArrayCache *cache = reinterpret_cast(type->GetUserData(ARRAY_CACHE)); - if( cache ) - { - cache->~SArrayCache(); - userFree(cache); - } + SArrayCache *cache = reinterpret_cast(type->GetUserData(ARRAY_CACHE)); + if( cache ) + { + cache->~SArrayCache(); + userFree(cache); + } } CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length) { - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptArray)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); - return 0; - } + return 0; + } - // Initialize the object - CScriptArray *a = new(mem) CScriptArray(length, ti); + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(length, ti); - return a; + return a; } CScriptArray* CScriptArray::Create(asITypeInfo *ti, void *initList) { - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptArray)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); - return 0; - } + return 0; + } - // Initialize the object - CScriptArray *a = new(mem) CScriptArray(ti, initList); + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(ti, initList); - return a; + return a; } CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length, void *defVal) { - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptArray)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); - return 0; - } + return 0; + } - // Initialize the object - CScriptArray *a = new(mem) CScriptArray(length, defVal, ti); + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(length, defVal, ti); - return a; + return a; } CScriptArray* CScriptArray::Create(asITypeInfo *ti) { - return CScriptArray::Create(ti, asUINT(0)); + return CScriptArray::Create(ti, asUINT(0)); } // This optional callback is called when the template type is first used by the compiler. @@ -130,1204 +130,1204 @@ CScriptArray* CScriptArray::Create(asITypeInfo *ti) // i.e. no asOBJ_GC flag. static bool ScriptArrayTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect) { - // Make sure the subtype can be instantiated with a default factory/constructor, - // otherwise we won't be able to instantiate the elements. - int typeId = ti->GetSubTypeId(); - if( typeId == asTYPEID_VOID ) - return false; - if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) - { - asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(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 - // TODO: Should format the message to give the name of the subtype for better understanding - ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); - return false; - } - } - 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( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) - { - // Verify that there is a default factory - for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) - { - asIScriptFunction *func = subtype->GetFactoryByIndex(n); - if( func->GetParamCount() == 0 ) - { - // Found the default factory - found = true; - break; - } - } - } - - if( !found ) - { - // No default factory - // TODO: Should format the message to give the name of the subtype for better understanding - ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); - return false; - } - } - - // 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; - } - else - { - assert( typeId & asTYPEID_OBJHANDLE ); - - // It is not necessary to set the array as garbage collected for all handle types. - // If it is possible to determine that the handle cannot refer to an object type - // that can potentially form a circular reference with the array then it is not - // necessary to make the array garbage collected. - asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); - asDWORD flags = subtype->GetFlags(); - if( !(flags & asOBJ_GC) ) - { - if( (flags & asOBJ_SCRIPT_OBJECT) ) - { - // Even if a script class is by itself not garbage collected, it is possible - // that classes that derive from it may be, so it is not possible to know - // that no circular reference can occur. - if( (flags & asOBJ_NOINHERIT) ) - { - // A script class declared as final cannot be inherited from, thus - // we can be certain that the object cannot be garbage collected. - dontGarbageCollect = true; - } - } - else - { - // For application registered classes we assume the application knows - // what it is doing and don't mark the array as garbage collected unless - // the type is also garbage collected. - dontGarbageCollect = true; - } - } - } - - // The type is ok - return true; + // Make sure the subtype can be instantiated with a default factory/constructor, + // otherwise we won't be able to instantiate the elements. + int typeId = ti->GetSubTypeId(); + if( typeId == asTYPEID_VOID ) + return false; + if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) + { + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(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 + // TODO: Should format the message to give the name of the subtype for better understanding + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); + return false; + } + } + 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( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) + { + // Verify that there is a default factory + for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) + { + asIScriptFunction *func = subtype->GetFactoryByIndex(n); + if( func->GetParamCount() == 0 ) + { + // Found the default factory + found = true; + break; + } + } + } + + if( !found ) + { + // No default factory + // TODO: Should format the message to give the name of the subtype for better understanding + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); + return false; + } + } + + // 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; + } + else + { + assert( typeId & asTYPEID_OBJHANDLE ); + + // It is not necessary to set the array as garbage collected for all handle types. + // If it is possible to determine that the handle cannot refer to an object type + // that can potentially form a circular reference with the array then it is not + // necessary to make the array garbage collected. + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); + asDWORD flags = subtype->GetFlags(); + if( !(flags & asOBJ_GC) ) + { + if( (flags & asOBJ_SCRIPT_OBJECT) ) + { + // Even if a script class is by itself not garbage collected, it is possible + // that classes that derive from it may be, so it is not possible to know + // that no circular reference can occur. + if( (flags & asOBJ_NOINHERIT) ) + { + // A script class declared as final cannot be inherited from, thus + // we can be certain that the object cannot be garbage collected. + dontGarbageCollect = true; + } + } + else + { + // For application registered classes we assume the application knows + // what it is doing and don't mark the array as garbage collected unless + // the type is also garbage collected. + dontGarbageCollect = true; + } + } + } + + // The type is ok + return true; } // Registers the template array type void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray) { - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") == 0 ) - RegisterScriptArray_Native(engine); - else - RegisterScriptArray_Generic(engine); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") == 0 ) + RegisterScriptArray_Native(engine); + else + RegisterScriptArray_Generic(engine); - if( defaultArray ) - { - int r = engine->RegisterDefaultArrayType("array"); assert( r >= 0 ); - UNUSED_VAR(r); - } + if( defaultArray ) + { + int r = engine->RegisterDefaultArrayType("array"); assert( r >= 0 ); + UNUSED_VAR(r); + } } static void RegisterScriptArray_Native(asIScriptEngine *engine) { - int r = 0; - UNUSED_VAR(r); + int r = 0; + UNUSED_VAR(r); - // Register the object type user data clean up - engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); + // Register the object type user data clean up + engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); - // Register the array type as a template - r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); + // Register the array type as a template + r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); - // Register a callback for validating the subtype before it is used - r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL); assert( r >= 0 ); + // Register a callback for validating the subtype before it is used + r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL); assert( r >= 0 ); - // Templates receive the object type as the first parameter. To the script writer this is hidden - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + // Templates receive the object type as the first parameter. To the script writer this is hidden + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - // Register the factory that will be used for initialization lists - r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + // Register the factory that will be used for initialization lists + r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - // The memory management methods - r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL); assert( r >= 0 ); + // The memory management methods + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL); assert( r >= 0 ); - // The index operator returns the template subtype - r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); + // The index operator returns the template subtype + r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); - // The assignment operator - r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL); assert( r >= 0 ); + // The assignment operator + r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL); assert( r >= 0 ); - // Other methods - r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void removeLast()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asMETHOD(CScriptArray, RemoveRange), asCALL_THISCALL); assert(r >= 0); - // TODO: Should length() and resize() be deprecated as the property accessors do the same thing? - // TODO: Register as size() for consistency with other types + // Other methods + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeLast()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asMETHOD(CScriptArray, RemoveRange), asCALL_THISCALL); assert(r >= 0); + // TODO: Should length() and resize() be deprecated as the property accessors do the same thing? + // TODO: Register as size() for consistency with other types #if AS_USE_ACCESSORS != 1 - r = engine->RegisterObjectMethod("array", "uint length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "uint length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); #endif - r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asMETHOD(CScriptArray, Reserve), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void resize(uint length)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc()", asMETHODPR(CScriptArray, SortAsc, (), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc()", asMETHODPR(CScriptArray, SortDesc, (), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void reverse()", asMETHOD(CScriptArray, Reverse), asCALL_THISCALL); assert( r >= 0 ); - // The token 'if_handle_then_const' tells the engine that if the type T is a handle, then it should refer to a read-only object - r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - // TODO: It should be "int find(const T&in value, uint startAt = 0) const" - r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - // TODO: It should be "int findByRef(const T&in value, uint startAt = 0) const" - r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asMETHOD(CScriptArray, operator==), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - - // Sort with callback for comparison - r = engine->RegisterFuncdef("bool array::less(const T&in if_handle_then_const a, const T&in if_handle_then_const b)"); - r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asMETHODPR(CScriptArray, Sort, (asIScriptFunction*, asUINT, asUINT), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asMETHOD(CScriptArray, Reserve), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void resize(uint length)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc()", asMETHODPR(CScriptArray, SortAsc, (), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc()", asMETHODPR(CScriptArray, SortDesc, (), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void reverse()", asMETHOD(CScriptArray, Reverse), asCALL_THISCALL); assert( r >= 0 ); + // The token 'if_handle_then_const' tells the engine that if the type T is a handle, then it should refer to a read-only object + r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // TODO: It should be "int find(const T&in value, uint startAt = 0) const" + r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // TODO: It should be "int findByRef(const T&in value, uint startAt = 0) const" + r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asMETHOD(CScriptArray, operator==), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + + // Sort with callback for comparison + r = engine->RegisterFuncdef("bool array::less(const T&in if_handle_then_const a, const T&in if_handle_then_const b)"); + r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asMETHODPR(CScriptArray, Sort, (asIScriptFunction*, asUINT, asUINT), void), asCALL_THISCALL); assert(r >= 0); #if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 - // Register virtual properties - r = engine->RegisterObjectMethod("array", "uint get_length() const property", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + // Register virtual properties + r = engine->RegisterObjectMethod("array", "uint get_length() const property", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); #endif - // Register GC behaviours in case the array needs to be garbage collected - r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptArray, GetRefCount), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptArray, SetFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptArray, GetFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptArray, EnumReferences), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptArray, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); + // Register GC behaviours in case the array needs to be garbage collected + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptArray, GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptArray, SetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptArray, GetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptArray, EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptArray, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); #if AS_USE_STLNAMES == 1 - // Same as length - r = engine->RegisterObjectMethod("array", "uint size() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); - // Same as isEmpty - r = engine->RegisterObjectMethod("array", "bool empty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - // Same as insertLast - r = engine->RegisterObjectMethod("array", "void push_back(const T&in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert( r >= 0 ); - // Same as removeLast - r = engine->RegisterObjectMethod("array", "void pop_back()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); - // Same as insertAt - r = engine->RegisterObjectMethod("array", "void insert(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void insert(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); - // Same as removeAt - r = engine->RegisterObjectMethod("array", "void erase(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 ); + // Same as length + r = engine->RegisterObjectMethod("array", "uint size() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); + // Same as isEmpty + r = engine->RegisterObjectMethod("array", "bool empty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + // Same as insertLast + r = engine->RegisterObjectMethod("array", "void push_back(const T&in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert( r >= 0 ); + // Same as removeLast + r = engine->RegisterObjectMethod("array", "void pop_back()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); + // Same as insertAt + r = engine->RegisterObjectMethod("array", "void insert(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insert(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); + // Same as removeAt + r = engine->RegisterObjectMethod("array", "void erase(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 ); #endif } CScriptArray &CScriptArray::operator=(const CScriptArray &other) { - // Only perform the copy if the array types are the same - if( &other != this && - other.GetArrayObjectType() == GetArrayObjectType() ) - { - // Make sure the arrays are of the same size - Resize(other.buffer->numElements); + // Only perform the copy if the array types are the same + if( &other != this && + other.GetArrayObjectType() == GetArrayObjectType() ) + { + // Make sure the arrays are of the same size + Resize(other.buffer->numElements); - // Copy the value of each element - CopyBuffer(buffer, other.buffer); - } + // Copy the value of each element + CopyBuffer(buffer, other.buffer); + } - return *this; + return *this; } CScriptArray::CScriptArray(asITypeInfo *ti, void *buf) { - // The object type should be the template instance of the array - assert( ti && string(ti->GetName()) == "array" ); - - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; - - Precache(); - - asIScriptEngine *engine = ti->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 length = *(asUINT*)buf; - - // Make sure the array size isn't too large for us to handle - if( !CheckMaxSize(length) ) - { - // Don't continue with the initialization - return; - } - - // Copy the values of the array elements from the buffer - if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) - { - CreateBuffer(&buffer, length); - - // Copy the values of the primitive type into the internal buffer - if( length > 0 ) - memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); - } - else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) - { - CreateBuffer(&buffer, length); - - // Copy the handles into the internal buffer - if( length > 0 ) - memcpy(At(0), (((asUINT*)buf)+1), length * 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((((asUINT*)buf)+1), 0, length * elementSize); - } - else if( ti->GetSubType()->GetFlags() & asOBJ_REF ) - { - // Only allocate the buffer, but not the objects - subTypeId |= asTYPEID_OBJHANDLE; - CreateBuffer(&buffer, length); - subTypeId &= ~asTYPEID_OBJHANDLE; - - // Copy the handles into the internal buffer - if( length > 0 ) - memcpy(buffer->data, (((asUINT*)buf)+1), length * elementSize); - - // For ref types we can do the same as for handles, as they are - // implicitly stored as handles. - memset((((asUINT*)buf)+1), 0, length * elementSize); - } - 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, length); - - // For value types we need to call the opAssign for each individual object - for( asUINT n = 0; n < length; n++ ) - { - void *obj = At(n); - asBYTE *srcObj = (asBYTE*)buf; - srcObj += 4 + n*ti->GetSubType()->GetSize(); - engine->AssignScriptObject(obj, srcObj, ti->GetSubType()); - } - } - - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + + Precache(); + + asIScriptEngine *engine = ti->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 length = *(asUINT*)buf; + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } + + // Copy the values of the array elements from the buffer + if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) + { + CreateBuffer(&buffer, length); + + // Copy the values of the primitive type into the internal buffer + if( length > 0 ) + memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); + } + else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) + { + CreateBuffer(&buffer, length); + + // Copy the handles into the internal buffer + if( length > 0 ) + memcpy(At(0), (((asUINT*)buf)+1), length * 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((((asUINT*)buf)+1), 0, length * elementSize); + } + else if( ti->GetSubType()->GetFlags() & asOBJ_REF ) + { + // Only allocate the buffer, but not the objects + subTypeId |= asTYPEID_OBJHANDLE; + CreateBuffer(&buffer, length); + subTypeId &= ~asTYPEID_OBJHANDLE; + + // Copy the handles into the internal buffer + if( length > 0 ) + memcpy(buffer->data, (((asUINT*)buf)+1), length * elementSize); + + // For ref types we can do the same as for handles, as they are + // implicitly stored as handles. + memset((((asUINT*)buf)+1), 0, length * elementSize); + } + 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, length); + + // For value types we need to call the opAssign for each individual object + for( asUINT n = 0; n < length; n++ ) + { + void *obj = At(n); + asBYTE *srcObj = (asBYTE*)buf; + srcObj += 4 + n*ti->GetSubType()->GetSize(); + engine->AssignScriptObject(obj, srcObj, ti->GetSubType()); + } + } + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); } CScriptArray::CScriptArray(asUINT length, asITypeInfo *ti) { - // The object type should be the template instance of the array - assert( ti && string(ti->GetName()) == "array" ); + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; - Precache(); + Precache(); - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + // 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(length) ) - { - // Don't continue with the initialization - return; - } + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } - CreateBuffer(&buffer, length); + CreateBuffer(&buffer, length); - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); } CScriptArray::CScriptArray(const CScriptArray &other) { - refCount = 1; - gcFlag = false; - objType = other.objType; - objType->AddRef(); - buffer = 0; + refCount = 1; + gcFlag = false; + objType = other.objType; + objType->AddRef(); + buffer = 0; - Precache(); + Precache(); - elementSize = other.elementSize; + elementSize = other.elementSize; - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); - CreateBuffer(&buffer, 0); + CreateBuffer(&buffer, 0); - // Copy the content - *this = other; + // Copy the content + *this = other; } CScriptArray::CScriptArray(asUINT length, void *defVal, asITypeInfo *ti) { - // The object type should be the template instance of the array - assert( ti && string(ti->GetName()) == "array" ); + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; - Precache(); + Precache(); - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + // 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(length) ) - { - // Don't continue with the initialization - return; - } + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } - CreateBuffer(&buffer, length); + CreateBuffer(&buffer, length); - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + // 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 n = 0; n < GetSize(); n++ ) - SetValue(n, defVal); + // Initialize the elements with the default value + for( asUINT n = 0; n < GetSize(); n++ ) + SetValue(n, defVal); } void CScriptArray::SetValue(asUINT index, 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(index); - 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; + // At() will take care of the out-of-bounds checking, though + // if called from the application then nothing will be done + void *ptr = At(index); + 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; } CScriptArray::~CScriptArray() { - if( buffer ) - { - DeleteBuffer(buffer); - buffer = 0; - } - if( objType ) objType->Release(); + if( buffer ) + { + DeleteBuffer(buffer); + buffer = 0; + } + if( objType ) objType->Release(); } asUINT CScriptArray::GetSize() const { - return buffer->numElements; + return buffer->numElements; } bool CScriptArray::IsEmpty() const { - return buffer->numElements == 0; + return buffer->numElements == 0; } void CScriptArray::Reserve(asUINT maxElements) { - if( maxElements <= buffer->maxElements ) - return; + if( maxElements <= buffer->maxElements ) + return; - if( !CheckMaxSize(maxElements) ) - return; + if( !CheckMaxSize(maxElements) ) + return; - // Allocate memory for the buffer - SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*maxElements)); - if( newBuffer ) - { - newBuffer->numElements = buffer->numElements; - newBuffer->maxElements = maxElements; - } - else - { - // Out of memory - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - return; - } + // Allocate memory for the buffer + SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*maxElements)); + if( newBuffer ) + { + newBuffer->numElements = buffer->numElements; + newBuffer->maxElements = maxElements; + } + else + { + // Out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + return; + } - // As objects in arrays of objects are not stored inline, it is safe to use memcpy here - // since we're just copying the pointers to objects and not the actual objects. - memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize); + // As objects in arrays of objects are not stored inline, it is safe to use memcpy here + // since we're just copying the pointers to objects and not the actual objects. + memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize); - // Release the old buffer - userFree(buffer); + // Release the old buffer + userFree(buffer); - buffer = newBuffer; + buffer = newBuffer; } void CScriptArray::Resize(asUINT numElements) { - if( !CheckMaxSize(numElements) ) - return; + if( !CheckMaxSize(numElements) ) + return; - Resize((int)numElements - (int)buffer->numElements, (asUINT)-1); + Resize((int)numElements - (int)buffer->numElements, (asUINT)-1); } void CScriptArray::RemoveRange(asUINT start, asUINT count) { - if (count == 0) - return; + if (count == 0) + return; - if( buffer == 0 || start > buffer->numElements ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException("Index out of bounds"); - return; - } + if( buffer == 0 || start > buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Index out of bounds"); + return; + } - // Cap count to the end of the array - if (start + count > buffer->numElements) - count = buffer->numElements - start; + // Cap count to the end of the array + if (start + count > buffer->numElements) + count = buffer->numElements - start; - // Destroy the elements that are being removed - Destruct(buffer, start, start + count); + // Destroy the elements that are being removed + Destruct(buffer, start, start + count); - // Compact the elements - // As objects in arrays of objects are not stored inline, it is safe to use memmove here - // since we're just copying the pointers to objects and not the actual objects. - memmove(buffer->data + start*elementSize, buffer->data + (start + count)*elementSize, (buffer->numElements - start - count)*elementSize); - buffer->numElements -= count; + // Compact the elements + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + start*elementSize, buffer->data + (start + count)*elementSize, (buffer->numElements - start - count)*elementSize); + buffer->numElements -= count; } // Internal void CScriptArray::Resize(int delta, asUINT at) { - if( delta < 0 ) - { - if( -delta > (int)buffer->numElements ) - delta = -(int)buffer->numElements; - if( at > buffer->numElements + delta ) - at = buffer->numElements + delta; - } - else if( delta > 0 ) - { - // Make sure the array size isn't too large for us to handle - if( delta > 0 && !CheckMaxSize(buffer->numElements + delta) ) - return; - - if( at > buffer->numElements ) - at = buffer->numElements; - } - - if( delta == 0 ) return; - - if( buffer->maxElements < buffer->numElements + delta ) - { - // Allocate memory for the buffer - SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta))); - if( newBuffer ) - { - newBuffer->numElements = buffer->numElements + delta; - newBuffer->maxElements = newBuffer->numElements; - } - else - { - // Out of memory - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - return; - } - - // As objects in arrays of objects are not stored inline, it is safe to use memcpy here - // since we're just copying the pointers to objects and not the actual objects. - memcpy(newBuffer->data, buffer->data, at*elementSize); - if( at < buffer->numElements ) - memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize); - - // Initialize the new elements with default values - Construct(newBuffer, at, at+delta); - - // Release the old buffer - userFree(buffer); - - buffer = newBuffer; - } - else if( delta < 0 ) - { - Destruct(buffer, at, at-delta); - // As objects in arrays of objects are not stored inline, it is safe to use memmove here - // since we're just copying the pointers to objects and not the actual objects. - memmove(buffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements - (at-delta))*elementSize); - buffer->numElements += delta; - } - else - { - // As objects in arrays of objects are not stored inline, it is safe to use memmove here - // since we're just copying the pointers to objects and not the actual objects. - memmove(buffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements - at)*elementSize); - Construct(buffer, at, at+delta); - buffer->numElements += delta; - } + if( delta < 0 ) + { + if( -delta > (int)buffer->numElements ) + delta = -(int)buffer->numElements; + if( at > buffer->numElements + delta ) + at = buffer->numElements + delta; + } + else if( delta > 0 ) + { + // Make sure the array size isn't too large for us to handle + if( delta > 0 && !CheckMaxSize(buffer->numElements + delta) ) + return; + + if( at > buffer->numElements ) + at = buffer->numElements; + } + + if( delta == 0 ) return; + + if( buffer->maxElements < buffer->numElements + delta ) + { + // Allocate memory for the buffer + SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta))); + if( newBuffer ) + { + newBuffer->numElements = buffer->numElements + delta; + newBuffer->maxElements = newBuffer->numElements; + } + else + { + // Out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + return; + } + + // As objects in arrays of objects are not stored inline, it is safe to use memcpy here + // since we're just copying the pointers to objects and not the actual objects. + memcpy(newBuffer->data, buffer->data, at*elementSize); + if( at < buffer->numElements ) + memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize); + + // Initialize the new elements with default values + Construct(newBuffer, at, at+delta); + + // Release the old buffer + userFree(buffer); + + buffer = newBuffer; + } + else if( delta < 0 ) + { + Destruct(buffer, at, at-delta); + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements - (at-delta))*elementSize); + buffer->numElements += delta; + } + else + { + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements - at)*elementSize); + Construct(buffer, at, at+delta); + buffer->numElements += delta; + } } // internal bool CScriptArray::CheckMaxSize(asUINT numElements) { - // This code makes sure the size of the buffer that is allocated - // for the array doesn't overflow and becomes smaller than requested + // 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(SArrayBuffer) + 1; - if( elementSize > 0 ) - maxSize /= elementSize; + asUINT maxSize = 0xFFFFFFFFul - sizeof(SArrayBuffer) + 1; + if( elementSize > 0 ) + maxSize /= elementSize; - if( numElements > maxSize ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Too large array size"); + if( numElements > maxSize ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Too large array size"); - return false; - } + return false; + } - // OK - return true; + // OK + return true; } asITypeInfo *CScriptArray::GetArrayObjectType() const { - return objType; + return objType; } int CScriptArray::GetArrayTypeId() const { - return objType->GetTypeId(); + return objType->GetTypeId(); } int CScriptArray::GetElementTypeId() const { - return subTypeId; + return subTypeId; } void CScriptArray::InsertAt(asUINT index, void *value) { - if( index > buffer->numElements ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Index out of bounds"); - return; - } + if( index > buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return; + } - // Make room for the new element - Resize(1, index); + // Make room for the new element + Resize(1, index); - // Set the value of the new element - SetValue(index, value); + // Set the value of the new element + SetValue(index, value); } void CScriptArray::InsertAt(asUINT index, const CScriptArray &arr) { - if (index > buffer->numElements) - { - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException("Index out of bounds"); - return; - } - - if (objType != arr.objType) - { - // This shouldn't really be possible to happen when - // called from a script, but let's check for it anyway - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException("Mismatching array types"); - return; - } - - asUINT elements = arr.GetSize(); - Resize(elements, index); - if (&arr != this) - { - for (asUINT n = 0; n < arr.GetSize(); n++) - { - // This const cast is allowed, since we know the - // value will only be used to make a copy of it - void *value = const_cast(arr.At(n)); - SetValue(index + n, value); - } - } - else - { - // The array that is being inserted is the same as this one. - // So we should iterate over the elements before the index, - // and then the elements after - for (asUINT n = 0; n < index; n++) - { - // This const cast is allowed, since we know the - // value will only be used to make a copy of it - void *value = const_cast(arr.At(n)); - SetValue(index + n, value); - } - - for (asUINT n = index + elements, m = 0; n < arr.GetSize(); n++, m++) - { - // This const cast is allowed, since we know the - // value will only be used to make a copy of it - void *value = const_cast(arr.At(n)); - SetValue(index + index + m, value); - } - } + if (index > buffer->numElements) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Index out of bounds"); + return; + } + + if (objType != arr.objType) + { + // This shouldn't really be possible to happen when + // called from a script, but let's check for it anyway + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Mismatching array types"); + return; + } + + asUINT elements = arr.GetSize(); + Resize(elements, index); + if (&arr != this) + { + for (asUINT n = 0; n < arr.GetSize(); n++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + n, value); + } + } + else + { + // The array that is being inserted is the same as this one. + // So we should iterate over the elements before the index, + // and then the elements after + for (asUINT n = 0; n < index; n++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + n, value); + } + + for (asUINT n = index + elements, m = 0; n < arr.GetSize(); n++, m++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + index + m, value); + } + } } void CScriptArray::InsertLast(void *value) { - InsertAt(buffer->numElements, value); + InsertAt(buffer->numElements, value); } void CScriptArray::RemoveAt(asUINT index) { - if( index >= buffer->numElements ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Index out of bounds"); - return; - } + if( index >= buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return; + } - // Remove the element - Resize(-1, index); + // Remove the element + Resize(-1, index); } void CScriptArray::RemoveLast() { - RemoveAt(buffer->numElements-1); + RemoveAt(buffer->numElements-1); } // Return a pointer to the array element. Returns 0 if the index is out of bounds const void *CScriptArray::At(asUINT index) const { - if( buffer == 0 || index >= buffer->numElements ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Index out of bounds"); - return 0; - } + if( buffer == 0 || index >= buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return 0; + } - if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) - return *(void**)(buffer->data + elementSize*index); - else - return buffer->data + elementSize*index; + if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + return *(void**)(buffer->data + elementSize*index); + else + return buffer->data + elementSize*index; } void *CScriptArray::At(asUINT index) { - return const_cast(const_cast(this)->At(index)); + return const_cast(const_cast(this)->At(index)); } void *CScriptArray::GetBuffer() { - return buffer->data; + return buffer->data; } // internal void CScriptArray::CreateBuffer(SArrayBuffer **buf, asUINT numElements) { - *buf = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1+elementSize*numElements)); + *buf = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1+elementSize*numElements)); - if( *buf ) - { - (*buf)->numElements = numElements; - (*buf)->maxElements = numElements; - Construct(*buf, 0, numElements); - } - else - { - // Oops, out of memory - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - } + if( *buf ) + { + (*buf)->numElements = numElements; + (*buf)->maxElements = numElements; + Construct(*buf, 0, numElements); + } + else + { + // Oops, out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + } } // internal void CScriptArray::DeleteBuffer(SArrayBuffer *buf) { - Destruct(buf, 0, buf->numElements); + Destruct(buf, 0, buf->numElements); - // Free the buffer - userFree(buf); + // Free the buffer + userFree(buf); } // internal void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end) { - if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) - { - // Create an object using the default constructor/factory for each element - void **max = (void**)(buf->data + end * sizeof(void*)); - void **d = (void**)(buf->data + start * sizeof(void*)); - - asIScriptEngine *engine = objType->GetEngine(); - asITypeInfo *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; - } - } - } - else - { - // Set all elements to zero whether they are handles or primitives - void *d = (void*)(buf->data + start * elementSize); - memset(d, 0, (end-start)*elementSize); - } + if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + { + // Create an object using the default constructor/factory for each element + void **max = (void**)(buf->data + end * sizeof(void*)); + void **d = (void**)(buf->data + start * sizeof(void*)); + + asIScriptEngine *engine = objType->GetEngine(); + asITypeInfo *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; + } + } + } + else + { + // Set all elements to zero whether they are handles or primitives + void *d = (void*)(buf->data + start * elementSize); + memset(d, 0, (end-start)*elementSize); + } } // internal void CScriptArray::Destruct(SArrayBuffer *buf, asUINT start, asUINT end) { - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - asIScriptEngine *engine = objType->GetEngine(); + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + asIScriptEngine *engine = objType->GetEngine(); - void **max = (void**)(buf->data + end * sizeof(void*)); - void **d = (void**)(buf->data + start * sizeof(void*)); + void **max = (void**)(buf->data + end * sizeof(void*)); + void **d = (void**)(buf->data + start * sizeof(void*)); - for( ; d < max; d++ ) - { - if( *d ) - engine->ReleaseScriptObject(*d, objType->GetSubType()); - } - } + for( ; d < max; d++ ) + { + if( *d ) + engine->ReleaseScriptObject(*d, objType->GetSubType()); + } + } } // internal bool CScriptArray::Less(const void *a, const void *b, bool asc) { - if( !asc ) - { - // Swap items - const void *TEMP = a; - a = b; - b = TEMP; - } - - if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) - { - // Simple compare of values - switch( subTypeId ) - { - #define COMPARE(T) *((T*)a) < *((T*)b) - case asTYPEID_BOOL: return COMPARE(bool); - case asTYPEID_INT8: return COMPARE(signed char); - case asTYPEID_UINT8: return COMPARE(unsigned char); - case asTYPEID_INT16: return COMPARE(signed short); - case asTYPEID_UINT16: return COMPARE(unsigned short); - case asTYPEID_INT32: return COMPARE(signed int); - case asTYPEID_UINT32: return COMPARE(unsigned int); - case asTYPEID_FLOAT: return COMPARE(float); - case asTYPEID_DOUBLE: return COMPARE(double); - default: return COMPARE(signed int); // All enums fall in this case - #undef COMPARE - } - } - - return false; + if( !asc ) + { + // Swap items + const void *TEMP = a; + a = b; + b = TEMP; + } + + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + { + // Simple compare of values + switch( subTypeId ) + { + #define COMPARE(T) *((T*)a) < *((T*)b) + case asTYPEID_BOOL: return COMPARE(bool); + case asTYPEID_INT8: return COMPARE(signed char); + case asTYPEID_UINT8: return COMPARE(unsigned char); + case asTYPEID_INT16: return COMPARE(signed short); + case asTYPEID_UINT16: return COMPARE(unsigned short); + case asTYPEID_INT32: return COMPARE(signed int); + case asTYPEID_UINT32: return COMPARE(unsigned int); + case asTYPEID_FLOAT: return COMPARE(float); + case asTYPEID_DOUBLE: return COMPARE(double); + default: return COMPARE(signed int); // All enums fall in this case + #undef COMPARE + } + } + + return false; } void CScriptArray::Reverse() { - asUINT size = GetSize(); + asUINT size = GetSize(); - if( size >= 2 ) - { - asBYTE TEMP[16]; + if( size >= 2 ) + { + asBYTE TEMP[16]; - for( asUINT i = 0; i < size / 2; i++ ) - { - Copy(TEMP, GetArrayItemPointer(i)); - Copy(GetArrayItemPointer(i), GetArrayItemPointer(size - i - 1)); - Copy(GetArrayItemPointer(size - i - 1), TEMP); - } - } + for( asUINT i = 0; i < size / 2; i++ ) + { + Copy(TEMP, GetArrayItemPointer(i)); + Copy(GetArrayItemPointer(i), GetArrayItemPointer(size - i - 1)); + Copy(GetArrayItemPointer(size - i - 1), TEMP); + } + } } bool CScriptArray::operator==(const CScriptArray &other) const { - if( objType != other.objType ) - return false; - - if( GetSize() != other.GetSize() ) - return false; - - asIScriptContext *cmpContext = 0; - bool isNested = false; - - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - // Try to reuse the active context - cmpContext = asGetActiveContext(); - if( cmpContext ) - { - if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) - isNested = true; - else - cmpContext = 0; - } - if( cmpContext == 0 ) - { - // TODO: Ideally this context would be retrieved from a pool, so we don't have to - // create a new one everytime. We could keep a context with the array object - // but that would consume a lot of resources as each context is quite heavy. - cmpContext = objType->GetEngine()->CreateContext(); - } - } - - // Check if all elements are equal - bool isEqual = true; - SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - for( asUINT n = 0; n < GetSize(); n++ ) - if( !Equals(At(n), other.At(n), cmpContext, cache) ) - { - isEqual = false; - break; - } - - if( cmpContext ) - { - if( isNested ) - { - asEContextState state = cmpContext->GetState(); - cmpContext->PopState(); - if( state == asEXECUTION_ABORTED ) - cmpContext->Abort(); - } - else - cmpContext->Release(); - } - - return isEqual; + if( objType != other.objType ) + return false; + + if( GetSize() != other.GetSize() ) + return false; + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + { + // TODO: Ideally this context would be retrieved from a pool, so we don't have to + // create a new one everytime. We could keep a context with the array object + // but that would consume a lot of resources as each context is quite heavy. + cmpContext = objType->GetEngine()->CreateContext(); + } + } + + // Check if all elements are equal + bool isEqual = true; + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + for( asUINT n = 0; n < GetSize(); n++ ) + if( !Equals(At(n), other.At(n), cmpContext, cache) ) + { + isEqual = false; + break; + } + + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + cmpContext->Release(); + } + + return isEqual; } // internal bool CScriptArray::Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const { - if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) - { - // Simple compare of values - switch( subTypeId ) - { - #define COMPARE(T) *((T*)a) == *((T*)b) - case asTYPEID_BOOL: return COMPARE(bool); - case asTYPEID_INT8: return COMPARE(signed char); - case asTYPEID_UINT8: return COMPARE(unsigned char); - case asTYPEID_INT16: return COMPARE(signed short); - case asTYPEID_UINT16: return COMPARE(unsigned short); - case asTYPEID_INT32: return COMPARE(signed int); - case asTYPEID_UINT32: return COMPARE(unsigned int); - case asTYPEID_FLOAT: return COMPARE(float); - case asTYPEID_DOUBLE: return COMPARE(double); - default: return COMPARE(signed int); // All enums fall here - #undef COMPARE - } - } - else - { - int r = 0; - - if( subTypeId & asTYPEID_OBJHANDLE ) - { - // Allow the find to work even if the array contains null handles - if( *(void**)a == *(void**)b ) return true; - } - - // Execute object opEquals if available - if( cache && cache->eqFunc ) - { - // TODO: Add proper error handling - r = ctx->Prepare(cache->eqFunc); assert(r >= 0); - - if( subTypeId & asTYPEID_OBJHANDLE ) - { - r = ctx->SetObject(*((void**)a)); assert(r >= 0); - r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); - } - else - { - r = ctx->SetObject((void*)a); assert(r >= 0); - r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); - } - - r = ctx->Execute(); - - if( r == asEXECUTION_FINISHED ) - return ctx->GetReturnByte() != 0; - - return false; - } - - // Execute object opCmp if available - if( cache && cache->cmpFunc ) - { - // TODO: Add proper error handling - r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); - - if( subTypeId & asTYPEID_OBJHANDLE ) - { - r = ctx->SetObject(*((void**)a)); assert(r >= 0); - r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); - } - else - { - r = ctx->SetObject((void*)a); assert(r >= 0); - r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); - } - - r = ctx->Execute(); - - if( r == asEXECUTION_FINISHED ) - return (int)ctx->GetReturnDWord() == 0; - - return false; - } - } - - return false; + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + { + // Simple compare of values + switch( subTypeId ) + { + #define COMPARE(T) *((T*)a) == *((T*)b) + case asTYPEID_BOOL: return COMPARE(bool); + case asTYPEID_INT8: return COMPARE(signed char); + case asTYPEID_UINT8: return COMPARE(unsigned char); + case asTYPEID_INT16: return COMPARE(signed short); + case asTYPEID_UINT16: return COMPARE(unsigned short); + case asTYPEID_INT32: return COMPARE(signed int); + case asTYPEID_UINT32: return COMPARE(unsigned int); + case asTYPEID_FLOAT: return COMPARE(float); + case asTYPEID_DOUBLE: return COMPARE(double); + default: return COMPARE(signed int); // All enums fall here + #undef COMPARE + } + } + else + { + int r = 0; + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Allow the find to work even if the array contains null handles + if( *(void**)a == *(void**)b ) return true; + } + + // Execute object opEquals if available + if( cache && cache->eqFunc ) + { + // TODO: Add proper error handling + r = ctx->Prepare(cache->eqFunc); assert(r >= 0); + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + r = ctx->SetObject(*((void**)a)); assert(r >= 0); + r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); + } + else + { + r = ctx->SetObject((void*)a); assert(r >= 0); + r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); + } + + r = ctx->Execute(); + + if( r == asEXECUTION_FINISHED ) + return ctx->GetReturnByte() != 0; + + return false; + } + + // Execute object opCmp if available + if( cache && cache->cmpFunc ) + { + // TODO: Add proper error handling + r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + r = ctx->SetObject(*((void**)a)); assert(r >= 0); + r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); + } + else + { + r = ctx->SetObject((void*)a); assert(r >= 0); + r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); + } + + r = ctx->Execute(); + + if( r == asEXECUTION_FINISHED ) + return (int)ctx->GetReturnDWord() == 0; + + return false; + } + } + + return false; } int CScriptArray::FindByRef(void *ref) const { - return FindByRef(0, ref); + return FindByRef(0, ref); } int CScriptArray::FindByRef(asUINT startAt, void *ref) const { - // Find the matching element by its reference - asUINT size = GetSize(); - if( subTypeId & asTYPEID_OBJHANDLE ) - { - // Dereference the pointer - ref = *(void**)ref; - for( asUINT i = startAt; i < size; i++ ) - { - if( *(void**)At(i) == ref ) - return i; - } - } - else - { - // Compare the reference directly - for( asUINT i = startAt; i < size; i++ ) - { - if( At(i) == ref ) - return i; - } - } - - return -1; + // Find the matching element by its reference + asUINT size = GetSize(); + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Dereference the pointer + ref = *(void**)ref; + for( asUINT i = startAt; i < size; i++ ) + { + if( *(void**)At(i) == ref ) + return i; + } + } + else + { + // Compare the reference directly + for( asUINT i = startAt; i < size; i++ ) + { + if( At(i) == ref ) + return i; + } + } + + return -1; } int CScriptArray::Find(void *value) const { - return Find(0, value); + return Find(0, value); } int CScriptArray::Find(asUINT startAt, void *value) const { - // Check if the subtype really supports find() - // TODO: Can't this be done at compile time too by the template callback - SArrayCache *cache = 0; - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - if( !cache || (cache->cmpFunc == 0 && cache->eqFunc == 0) ) - { - asIScriptContext *ctx = asGetActiveContext(); - asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); - - // Throw an exception - if( ctx ) - { - char tmp[512]; - - if( cache && cache->eqFuncReturnCode == asMULTIPLE_FUNCTIONS ) + // Check if the subtype really supports find() + // TODO: Can't this be done at compile time too by the template callback + SArrayCache *cache = 0; + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( !cache || (cache->cmpFunc == 0 && cache->eqFunc == 0) ) + { + asIScriptContext *ctx = asGetActiveContext(); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + + // Throw an exception + if( ctx ) + { + char tmp[512]; + + if( cache && cache->eqFuncReturnCode == asMULTIPLE_FUNCTIONS ) #if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) - sprintf_s(tmp, 512, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); + sprintf_s(tmp, 512, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); #else - sprintf(tmp, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); + sprintf(tmp, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); #endif - else + else #if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) - sprintf_s(tmp, 512, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); + sprintf_s(tmp, 512, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); #else - sprintf(tmp, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); + sprintf(tmp, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); #endif - ctx->SetException(tmp); - } - - return -1; - } - } - - asIScriptContext *cmpContext = 0; - bool isNested = false; - - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - // Try to reuse the active context - cmpContext = asGetActiveContext(); - if( cmpContext ) - { - if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) - isNested = true; - else - cmpContext = 0; - } - if( cmpContext == 0 ) - { - // TODO: Ideally this context would be retrieved from a pool, so we don't have to - // create a new one everytime. We could keep a context with the array object - // but that would consume a lot of resources as each context is quite heavy. - cmpContext = objType->GetEngine()->CreateContext(); - } - } - - // Find the matching element - int ret = -1; - asUINT size = GetSize(); - - for( asUINT i = startAt; i < size; i++ ) - { - // value passed by reference - if( Equals(At(i), value, cmpContext, cache) ) - { - ret = (int)i; - break; - } - } - - if( cmpContext ) - { - if( isNested ) - { - asEContextState state = cmpContext->GetState(); - cmpContext->PopState(); - if( state == asEXECUTION_ABORTED ) - cmpContext->Abort(); - } - else - cmpContext->Release(); - } - - return ret; + ctx->SetException(tmp); + } + + return -1; + } + } + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + { + // TODO: Ideally this context would be retrieved from a pool, so we don't have to + // create a new one everytime. We could keep a context with the array object + // but that would consume a lot of resources as each context is quite heavy. + cmpContext = objType->GetEngine()->CreateContext(); + } + } + + // Find the matching element + int ret = -1; + asUINT size = GetSize(); + + for( asUINT i = startAt; i < size; i++ ) + { + // value passed by reference + if( Equals(At(i), value, cmpContext, cache) ) + { + ret = (int)i; + break; + } + } + + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + cmpContext->Release(); + } + + return ret; } // internal // Copy object handle or primitive value -// Even in arrays of objects the objects are allocated on +// Even in arrays of objects the objects are allocated on // the heap and the array stores the pointers to the objects void CScriptArray::Copy(void *dst, void *src) { - memcpy(dst, src, elementSize); + memcpy(dst, src, elementSize); } @@ -1335,543 +1335,543 @@ void CScriptArray::Copy(void *dst, void *src) // Return pointer to array item (object handle or primitive value) void *CScriptArray::GetArrayItemPointer(int index) { - return buffer->data + index * elementSize; + return buffer->data + index * elementSize; } // internal // Return pointer to data in buffer (object or primitive) void *CScriptArray::GetDataPointer(void *buf) { - if ((subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) - { - // Real address of object - return reinterpret_cast(*(size_t*)buf); - } - else - { - // Primitive is just a raw data - return buf; - } + if ((subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + { + // Real address of object + return reinterpret_cast(*(size_t*)buf); + } + else + { + // Primitive is just a raw data + return buf; + } } // Sort ascending void CScriptArray::SortAsc() { - Sort(0, GetSize(), true); + Sort(0, GetSize(), true); } // Sort ascending void CScriptArray::SortAsc(asUINT startAt, asUINT count) { - Sort(startAt, count, true); + Sort(startAt, count, true); } // Sort descending void CScriptArray::SortDesc() { - Sort(0, GetSize(), false); + Sort(0, GetSize(), false); } // Sort descending void CScriptArray::SortDesc(asUINT startAt, asUINT count) { - Sort(startAt, count, false); + Sort(startAt, count, false); } // internal void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) { - // Subtype isn't primitive and doesn't have opCmp - SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - if( !cache || cache->cmpFunc == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); - - // Throw an exception - if( ctx ) - { - char tmp[512]; - - if( cache && cache->cmpFuncReturnCode == asMULTIPLE_FUNCTIONS ) + // Subtype isn't primitive and doesn't have opCmp + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + if( !cache || cache->cmpFunc == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + + // Throw an exception + if( ctx ) + { + char tmp[512]; + + if( cache && cache->cmpFuncReturnCode == asMULTIPLE_FUNCTIONS ) #if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) - sprintf_s(tmp, 512, "Type '%s' has multiple matching opCmp methods", subType->GetName()); + sprintf_s(tmp, 512, "Type '%s' has multiple matching opCmp methods", subType->GetName()); #else - sprintf(tmp, "Type '%s' has multiple matching opCmp methods", subType->GetName()); + sprintf(tmp, "Type '%s' has multiple matching opCmp methods", subType->GetName()); #endif - else + else #if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) - sprintf_s(tmp, 512, "Type '%s' does not have a matching opCmp method", subType->GetName()); + sprintf_s(tmp, 512, "Type '%s' does not have a matching opCmp method", subType->GetName()); #else - sprintf(tmp, "Type '%s' does not have a matching opCmp method", subType->GetName()); + sprintf(tmp, "Type '%s' does not have a matching opCmp method", subType->GetName()); #endif - ctx->SetException(tmp); - } - - return; - } - } - - // No need to sort - if( count < 2 ) - { - return; - } - - int start = startAt; - int end = startAt + count; - - // Check if we could access invalid item while sorting - if( start >= (int)buffer->numElements || end > (int)buffer->numElements ) - { - asIScriptContext *ctx = asGetActiveContext(); - - // Throw an exception - if( ctx ) - { - ctx->SetException("Index out of bounds"); - } - - return; - } - - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - asIScriptContext *cmpContext = 0; - bool isNested = false; - - // Try to reuse the active context - cmpContext = asGetActiveContext(); - if( cmpContext ) - { - if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) - isNested = true; - else - cmpContext = 0; - } - if( cmpContext == 0 ) - cmpContext = objType->GetEngine()->RequestContext(); - - // Do the sorting - struct { - bool asc; - asIScriptContext *cmpContext; - asIScriptFunction *cmpFunc; - bool operator()(void *a, void *b) const - { - if( !asc ) - { - // Swap items - void *TEMP = a; - a = b; - b = TEMP; - } - - int r = 0; - - // Allow sort to work even if the array contains null handles - if( a == 0 ) return true; - if( b == 0 ) return false; - - // Execute object opCmp - if( cmpFunc ) - { - // TODO: Add proper error handling - r = cmpContext->Prepare(cmpFunc); assert(r >= 0); - r = cmpContext->SetObject(a); assert(r >= 0); - r = cmpContext->SetArgObject(0, b); assert(r >= 0); - r = cmpContext->Execute(); - - if( r == asEXECUTION_FINISHED ) - { - return (int)cmpContext->GetReturnDWord() < 0; - } - } - - return false; - } - } customLess = {asc, cmpContext, cache ? cache->cmpFunc : 0}; - std::sort((void**)GetArrayItemPointer(start), (void**)GetArrayItemPointer(end), customLess); - - // Clean up - if( cmpContext ) - { - if( isNested ) - { - asEContextState state = cmpContext->GetState(); - cmpContext->PopState(); - if( state == asEXECUTION_ABORTED ) - cmpContext->Abort(); - } - else - objType->GetEngine()->ReturnContext(cmpContext); - } - } - else - { - // TODO: Use std::sort for primitive types too - - // Insertion sort - asBYTE tmp[16]; - for( int i = start + 1; i < end; i++ ) - { - Copy(tmp, GetArrayItemPointer(i)); - - int j = i - 1; - - while( j >= start && Less(GetDataPointer(tmp), At(j), asc) ) - { - Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); - j--; - } - - Copy(GetArrayItemPointer(j + 1), tmp); - } - } + ctx->SetException(tmp); + } + + return; + } + } + + // No need to sort + if( count < 2 ) + { + return; + } + + int start = startAt; + int end = startAt + count; + + // Check if we could access invalid item while sorting + if( start >= (int)buffer->numElements || end > (int)buffer->numElements ) + { + asIScriptContext *ctx = asGetActiveContext(); + + // Throw an exception + if( ctx ) + { + ctx->SetException("Index out of bounds"); + } + + return; + } + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + asIScriptContext *cmpContext = 0; + bool isNested = false; + + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + cmpContext = objType->GetEngine()->RequestContext(); + + // Do the sorting + struct { + bool asc; + asIScriptContext *cmpContext; + asIScriptFunction *cmpFunc; + bool operator()(void *a, void *b) const + { + if( !asc ) + { + // Swap items + void *TEMP = a; + a = b; + b = TEMP; + } + + int r = 0; + + // Allow sort to work even if the array contains null handles + if( a == 0 ) return true; + if( b == 0 ) return false; + + // Execute object opCmp + if( cmpFunc ) + { + // TODO: Add proper error handling + r = cmpContext->Prepare(cmpFunc); assert(r >= 0); + r = cmpContext->SetObject(a); assert(r >= 0); + r = cmpContext->SetArgObject(0, b); assert(r >= 0); + r = cmpContext->Execute(); + + if( r == asEXECUTION_FINISHED ) + { + return (int)cmpContext->GetReturnDWord() < 0; + } + } + + return false; + } + } customLess = {asc, cmpContext, cache ? cache->cmpFunc : 0}; + std::sort((void**)GetArrayItemPointer(start), (void**)GetArrayItemPointer(end), customLess); + + // Clean up + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + objType->GetEngine()->ReturnContext(cmpContext); + } + } + else + { + // TODO: Use std::sort for primitive types too + + // Insertion sort + asBYTE tmp[16]; + for( int i = start + 1; i < end; i++ ) + { + Copy(tmp, GetArrayItemPointer(i)); + + int j = i - 1; + + while( j >= start && Less(GetDataPointer(tmp), At(j), asc) ) + { + Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); + j--; + } + + Copy(GetArrayItemPointer(j + 1), tmp); + } + } } // Sort with script callback for comparing elements void CScriptArray::Sort(asIScriptFunction *func, asUINT startAt, asUINT count) { - // No need to sort - if (count < 2) - return; - - // Check if we could access invalid item while sorting - asUINT start = startAt; - asUINT end = asQWORD(startAt) + asQWORD(count) >= (asQWORD(1)<<32) ? 0xFFFFFFFF : startAt + count; - if (end > buffer->numElements) - end = buffer->numElements; - - if (start >= buffer->numElements) - { - asIScriptContext *ctx = asGetActiveContext(); - - // Throw an exception - if (ctx) - ctx->SetException("Index out of bounds"); - - return; - } - - asIScriptContext *cmpContext = 0; - bool isNested = false; - - // Try to reuse the active context - cmpContext = asGetActiveContext(); - if (cmpContext) - { - if (cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0) - isNested = true; - else - cmpContext = 0; - } - if (cmpContext == 0) - cmpContext = objType->GetEngine()->RequestContext(); - - // Insertion sort - asBYTE tmp[16]; - for (asUINT i = start + 1; i < end; i++) - { - Copy(tmp, GetArrayItemPointer(i)); - - asUINT j = i - 1; - - while (j != 0xFFFFFFFF && j >= start ) - { - cmpContext->Prepare(func); - cmpContext->SetArgAddress(0, GetDataPointer(tmp)); - cmpContext->SetArgAddress(1, At(j)); - int r = cmpContext->Execute(); - if (r != asEXECUTION_FINISHED) - break; - if (*(bool*)(cmpContext->GetAddressOfReturnValue())) - { - Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); - j--; - } - else - break; - } - - Copy(GetArrayItemPointer(j + 1), tmp); - } - - if (cmpContext) - { - if (isNested) - { - asEContextState state = cmpContext->GetState(); - cmpContext->PopState(); - if (state == asEXECUTION_ABORTED) - cmpContext->Abort(); - } - else - objType->GetEngine()->ReturnContext(cmpContext); - } + // No need to sort + if (count < 2) + return; + + // Check if we could access invalid item while sorting + asUINT start = startAt; + asUINT end = asQWORD(startAt) + asQWORD(count) >= (asQWORD(1)<<32) ? 0xFFFFFFFF : startAt + count; + if (end > buffer->numElements) + end = buffer->numElements; + + if (start >= buffer->numElements) + { + asIScriptContext *ctx = asGetActiveContext(); + + // Throw an exception + if (ctx) + ctx->SetException("Index out of bounds"); + + return; + } + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if (cmpContext) + { + if (cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0) + isNested = true; + else + cmpContext = 0; + } + if (cmpContext == 0) + cmpContext = objType->GetEngine()->RequestContext(); + + // Insertion sort + asBYTE tmp[16]; + for (asUINT i = start + 1; i < end; i++) + { + Copy(tmp, GetArrayItemPointer(i)); + + asUINT j = i - 1; + + while (j != 0xFFFFFFFF && j >= start ) + { + cmpContext->Prepare(func); + cmpContext->SetArgAddress(0, GetDataPointer(tmp)); + cmpContext->SetArgAddress(1, At(j)); + int r = cmpContext->Execute(); + if (r != asEXECUTION_FINISHED) + break; + if (*(bool*)(cmpContext->GetAddressOfReturnValue())) + { + Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); + j--; + } + else + break; + } + + Copy(GetArrayItemPointer(j + 1), tmp); + } + + if (cmpContext) + { + if (isNested) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if (state == asEXECUTION_ABORTED) + cmpContext->Abort(); + } + else + objType->GetEngine()->ReturnContext(cmpContext); + } } // internal void CScriptArray::CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src) { - asIScriptEngine *engine = objType->GetEngine(); - if( subTypeId & asTYPEID_OBJHANDLE ) - { - // Copy the references and increase the reference counters - if( dst->numElements > 0 && src->numElements > 0 ) - { - int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; - - void **max = (void**)(dst->data + count * sizeof(void*)); - void **d = (void**)dst->data; - void **s = (void**)src->data; - - for( ; d < max; d++, s++ ) - { - void *tmp = *d; - *d = *s; - if( *d ) - engine->AddRefScriptObject(*d, objType->GetSubType()); - // Release the old ref after incrementing the new to avoid problem incase it is the same ref - if( tmp ) - engine->ReleaseScriptObject(tmp, objType->GetSubType()); - } - } - } - else - { - if( dst->numElements > 0 && src->numElements > 0 ) - { - int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - // Call the assignment operator on all of the objects - void **max = (void**)(dst->data + count * sizeof(void*)); - void **d = (void**)dst->data; - void **s = (void**)src->data; - - asITypeInfo *subType = objType->GetSubType(); - for( ; d < max; d++, s++ ) - engine->AssignScriptObject(*d, *s, subType); - } - else - { - // Primitives are copied byte for byte - memcpy(dst->data, src->data, count*elementSize); - } - } - } + asIScriptEngine *engine = objType->GetEngine(); + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Copy the references and increase the reference counters + if( dst->numElements > 0 && src->numElements > 0 ) + { + int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; + + void **max = (void**)(dst->data + count * sizeof(void*)); + void **d = (void**)dst->data; + void **s = (void**)src->data; + + for( ; d < max; d++, s++ ) + { + void *tmp = *d; + *d = *s; + if( *d ) + engine->AddRefScriptObject(*d, objType->GetSubType()); + // Release the old ref after incrementing the new to avoid problem incase it is the same ref + if( tmp ) + engine->ReleaseScriptObject(tmp, objType->GetSubType()); + } + } + } + else + { + if( dst->numElements > 0 && src->numElements > 0 ) + { + int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + // Call the assignment operator on all of the objects + void **max = (void**)(dst->data + count * sizeof(void*)); + void **d = (void**)dst->data; + void **s = (void**)src->data; + + asITypeInfo *subType = objType->GetSubType(); + for( ; d < max; d++, s++ ) + engine->AssignScriptObject(*d, *s, subType); + } + else + { + // Primitives are copied byte for byte + memcpy(dst->data, src->data, count*elementSize); + } + } + } } // internal // Precache some info void CScriptArray::Precache() { - subTypeId = objType->GetSubTypeId(); - - // Check if it is an array of objects. Only for these do we need to cache anything - // Type ids for primitives and enums only has the sequence number part - if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) - return; - - // The opCmp and opEquals methods are cached because the searching for the - // methods is quite time consuming if a lot of array objects are created. - - // First check if a cache already exists for this array type - SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - if( cache ) return; - - // We need to make sure the cache is created only once, even - // if multiple threads reach the same point at the same time - asAcquireExclusiveLock(); - - // Now that we got the lock, we need to check again to make sure the - // cache wasn't created while we were waiting for the lock - cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - if( cache ) - { - asReleaseExclusiveLock(); - return; - } - - // Create the cache - cache = reinterpret_cast(userAlloc(sizeof(SArrayCache))); - if( !cache ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - asReleaseExclusiveLock(); - return; - } - memset(cache, 0, sizeof(SArrayCache)); - - // If the sub type is a handle to const, then the methods must be const too - bool mustBeConst = (subTypeId & asTYPEID_HANDLETOCONST) ? true : false; - - asITypeInfo *subType = objType->GetEngine()->GetTypeInfoById(subTypeId); - if( subType ) - { - for( asUINT i = 0; i < subType->GetMethodCount(); i++ ) - { - asIScriptFunction *func = subType->GetMethodByIndex(i); - - if( func->GetParamCount() == 1 && (!mustBeConst || func->IsReadOnly()) ) - { - asDWORD flags = 0; - int returnTypeId = func->GetReturnTypeId(&flags); - - // The method must not return a reference - if( flags != asTM_NONE ) - continue; - - // opCmp returns an int and opEquals returns a bool - bool isCmp = false, isEq = false; - if( returnTypeId == asTYPEID_INT32 && strcmp(func->GetName(), "opCmp") == 0 ) - isCmp = true; - if( returnTypeId == asTYPEID_BOOL && strcmp(func->GetName(), "opEquals") == 0 ) - isEq = true; - - if( !isCmp && !isEq ) - continue; - - // The parameter must either be a reference to the subtype or a handle to the subtype - int paramTypeId; - func->GetParam(0, ¶mTypeId, &flags); - - if( (paramTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) != (subTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) ) - continue; - - if( (flags & asTM_INREF) ) - { - if( (paramTypeId & asTYPEID_OBJHANDLE) || (mustBeConst && !(flags & asTM_CONST)) ) - continue; - } - else if( paramTypeId & asTYPEID_OBJHANDLE ) - { - if( mustBeConst && !(paramTypeId & asTYPEID_HANDLETOCONST) ) - continue; - } - else - continue; - - if( isCmp ) - { - if( cache->cmpFunc || cache->cmpFuncReturnCode ) - { - cache->cmpFunc = 0; - cache->cmpFuncReturnCode = asMULTIPLE_FUNCTIONS; - } - else - cache->cmpFunc = func; - } - else if( isEq ) - { - if( cache->eqFunc || cache->eqFuncReturnCode ) - { - cache->eqFunc = 0; - cache->eqFuncReturnCode = asMULTIPLE_FUNCTIONS; - } - else - cache->eqFunc = func; - } - } - } - } - - if( cache->eqFunc == 0 && cache->eqFuncReturnCode == 0 ) - cache->eqFuncReturnCode = asNO_FUNCTION; - if( cache->cmpFunc == 0 && cache->cmpFuncReturnCode == 0 ) - cache->cmpFuncReturnCode = asNO_FUNCTION; - - // Set the user data only at the end so others that retrieve it will know it is complete - objType->SetUserData(cache, ARRAY_CACHE); - - asReleaseExclusiveLock(); + subTypeId = objType->GetSubTypeId(); + + // Check if it is an array of objects. Only for these do we need to cache anything + // Type ids for primitives and enums only has the sequence number part + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + return; + + // The opCmp and opEquals methods are cached because the searching for the + // methods is quite time consuming if a lot of array objects are created. + + // First check if a cache already exists for this array type + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( cache ) return; + + // We need to make sure the cache is created only once, even + // if multiple threads reach the same point at the same time + asAcquireExclusiveLock(); + + // Now that we got the lock, we need to check again to make sure the + // cache wasn't created while we were waiting for the lock + cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( cache ) + { + asReleaseExclusiveLock(); + return; + } + + // Create the cache + cache = reinterpret_cast(userAlloc(sizeof(SArrayCache))); + if( !cache ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + asReleaseExclusiveLock(); + return; + } + memset(cache, 0, sizeof(SArrayCache)); + + // If the sub type is a handle to const, then the methods must be const too + bool mustBeConst = (subTypeId & asTYPEID_HANDLETOCONST) ? true : false; + + asITypeInfo *subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + if( subType ) + { + for( asUINT i = 0; i < subType->GetMethodCount(); i++ ) + { + asIScriptFunction *func = subType->GetMethodByIndex(i); + + if( func->GetParamCount() == 1 && (!mustBeConst || func->IsReadOnly()) ) + { + asDWORD flags = 0; + int returnTypeId = func->GetReturnTypeId(&flags); + + // The method must not return a reference + if( flags != asTM_NONE ) + continue; + + // opCmp returns an int and opEquals returns a bool + bool isCmp = false, isEq = false; + if( returnTypeId == asTYPEID_INT32 && strcmp(func->GetName(), "opCmp") == 0 ) + isCmp = true; + if( returnTypeId == asTYPEID_BOOL && strcmp(func->GetName(), "opEquals") == 0 ) + isEq = true; + + if( !isCmp && !isEq ) + continue; + + // The parameter must either be a reference to the subtype or a handle to the subtype + int paramTypeId; + func->GetParam(0, ¶mTypeId, &flags); + + if( (paramTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) != (subTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) ) + continue; + + if( (flags & asTM_INREF) ) + { + if( (paramTypeId & asTYPEID_OBJHANDLE) || (mustBeConst && !(flags & asTM_CONST)) ) + continue; + } + else if( paramTypeId & asTYPEID_OBJHANDLE ) + { + if( mustBeConst && !(paramTypeId & asTYPEID_HANDLETOCONST) ) + continue; + } + else + continue; + + if( isCmp ) + { + if( cache->cmpFunc || cache->cmpFuncReturnCode ) + { + cache->cmpFunc = 0; + cache->cmpFuncReturnCode = asMULTIPLE_FUNCTIONS; + } + else + cache->cmpFunc = func; + } + else if( isEq ) + { + if( cache->eqFunc || cache->eqFuncReturnCode ) + { + cache->eqFunc = 0; + cache->eqFuncReturnCode = asMULTIPLE_FUNCTIONS; + } + else + cache->eqFunc = func; + } + } + } + } + + if( cache->eqFunc == 0 && cache->eqFuncReturnCode == 0 ) + cache->eqFuncReturnCode = asNO_FUNCTION; + if( cache->cmpFunc == 0 && cache->cmpFuncReturnCode == 0 ) + cache->cmpFuncReturnCode = asNO_FUNCTION; + + // Set the user data only at the end so others that retrieve it will know it is complete + objType->SetUserData(cache, ARRAY_CACHE); + + asReleaseExclusiveLock(); } // GC behaviour void CScriptArray::EnumReferences(asIScriptEngine *engine) { - // TODO: If garbage collection can be done from a separate thread, then this method must be - // protected so that it doesn't get lost during the iteration if the array is modified - - // If the array is holding handles, then we need to notify the GC of them - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - void **d = (void**)buffer->data; - - asITypeInfo *subType = engine->GetTypeInfoById(subTypeId); - if ((subType->GetFlags() & asOBJ_REF)) - { - // For reference types we need to notify the GC of each instance - for (asUINT n = 0; n < buffer->numElements; n++) - { - if (d[n]) - engine->GCEnumCallback(d[n]); - } - } - else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) - { - // For value types we need to forward the enum callback - // to the object so it can decide what to do - for (asUINT n = 0; n < buffer->numElements; n++) - { - if (d[n]) - engine->ForwardGCEnumReferences(d[n], subType); - } - } - } + // TODO: If garbage collection can be done from a separate thread, then this method must be + // protected so that it doesn't get lost during the iteration if the array is modified + + // If the array is holding handles, then we need to notify the GC of them + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + void **d = (void**)buffer->data; + + asITypeInfo *subType = engine->GetTypeInfoById(subTypeId); + if ((subType->GetFlags() & asOBJ_REF)) + { + // For reference types we need to notify the GC of each instance + for (asUINT n = 0; n < buffer->numElements; n++) + { + if (d[n]) + engine->GCEnumCallback(d[n]); + } + } + else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + for (asUINT n = 0; n < buffer->numElements; n++) + { + if (d[n]) + engine->ForwardGCEnumReferences(d[n], subType); + } + } + } } // GC behaviour void CScriptArray::ReleaseAllHandles(asIScriptEngine *) { - // Resizing to zero will release everything - Resize(0); + // Resizing to zero will release everything + Resize(0); } void CScriptArray::AddRef() const { - // Clear the GC flag then increase the counter - gcFlag = false; - asAtomicInc(refCount); + // Clear the GC flag then increase the counter + gcFlag = false; + asAtomicInc(refCount); } void CScriptArray::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->~CScriptArray(); - userFree(const_cast(this)); - } + // 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->~CScriptArray(); + userFree(const_cast(this)); + } } // GC behaviour int CScriptArray::GetRefCount() { - return refCount; + return refCount; } // GC behaviour void CScriptArray::SetFlag() { - gcFlag = true; + gcFlag = true; } // GC behaviour bool CScriptArray::GetFlag() { - return gcFlag; + return gcFlag; } //-------------------------------------------- @@ -1879,308 +1879,308 @@ bool CScriptArray::GetFlag() static void ScriptArrayFactory_Generic(asIScriptGeneric *gen) { - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti); } static void ScriptArrayFactory2_Generic(asIScriptGeneric *gen) { - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - asUINT length = gen->GetArgDWord(1); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + asUINT length = gen->GetArgDWord(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length); } static void ScriptArrayListFactory_Generic(asIScriptGeneric *gen) { - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - void *buf = gen->GetArgAddress(1); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + void *buf = gen->GetArgAddress(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, buf); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, buf); } static void ScriptArrayFactoryDefVal_Generic(asIScriptGeneric *gen) { - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - asUINT length = gen->GetArgDWord(1); - void *defVal = gen->GetArgAddress(2); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + asUINT length = gen->GetArgDWord(1); + void *defVal = gen->GetArgAddress(2); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length, defVal); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length, defVal); } static void ScriptArrayTemplateCallback_Generic(asIScriptGeneric *gen) { - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ti, *dontGarbageCollect); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ti, *dontGarbageCollect); } static void ScriptArrayAssignment_Generic(asIScriptGeneric *gen) { - CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - *self = *other; - gen->SetReturnObject(self); + CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *self = *other; + gen->SetReturnObject(self); } static void ScriptArrayEquals_Generic(asIScriptGeneric *gen) { - CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnByte(self->operator==(*other)); + CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnByte(self->operator==(*other)); } static void ScriptArrayFind_Generic(asIScriptGeneric *gen) { - void *value = gen->GetArgAddress(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->Find(value)); + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->Find(value)); } static void ScriptArrayFind2_Generic(asIScriptGeneric *gen) { - asUINT index = gen->GetArgDWord(0); - void *value = gen->GetArgAddress(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->Find(index, value)); + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->Find(index, value)); } static void ScriptArrayFindByRef_Generic(asIScriptGeneric *gen) { - void *value = gen->GetArgAddress(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->FindByRef(value)); + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->FindByRef(value)); } static void ScriptArrayFindByRef2_Generic(asIScriptGeneric *gen) { - asUINT index = gen->GetArgDWord(0); - void *value = gen->GetArgAddress(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->FindByRef(index, value)); + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->FindByRef(index, value)); } static void ScriptArrayAt_Generic(asIScriptGeneric *gen) { - asUINT index = gen->GetArgDWord(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); + asUINT index = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnAddress(self->At(index)); + gen->SetReturnAddress(self->At(index)); } static void ScriptArrayInsertAt_Generic(asIScriptGeneric *gen) { - asUINT index = gen->GetArgDWord(0); - void *value = gen->GetArgAddress(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->InsertAt(index, value); + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertAt(index, value); } static void ScriptArrayInsertAtArray_Generic(asIScriptGeneric *gen) { - asUINT index = gen->GetArgDWord(0); - CScriptArray *array = (CScriptArray*)gen->GetArgAddress(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->InsertAt(index, *array); + asUINT index = gen->GetArgDWord(0); + CScriptArray *array = (CScriptArray*)gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertAt(index, *array); } static void ScriptArrayRemoveAt_Generic(asIScriptGeneric *gen) { - asUINT index = gen->GetArgDWord(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->RemoveAt(index); + asUINT index = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveAt(index); } static void ScriptArrayRemoveRange_Generic(asIScriptGeneric *gen) { - asUINT start = gen->GetArgDWord(0); - asUINT count = gen->GetArgDWord(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->RemoveRange(start, count); + asUINT start = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveRange(start, count); } static void ScriptArrayInsertLast_Generic(asIScriptGeneric *gen) { - void *value = gen->GetArgAddress(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->InsertLast(value); + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertLast(value); } static void ScriptArrayRemoveLast_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->RemoveLast(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveLast(); } static void ScriptArrayLength_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->GetSize()); + gen->SetReturnDWord(self->GetSize()); } static void ScriptArrayResize_Generic(asIScriptGeneric *gen) { - asUINT size = gen->GetArgDWord(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); + asUINT size = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Resize(size); + self->Resize(size); } static void ScriptArrayReserve_Generic(asIScriptGeneric *gen) { - asUINT size = gen->GetArgDWord(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Reserve(size); + asUINT size = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Reserve(size); } static void ScriptArraySortAsc_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SortAsc(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortAsc(); } static void ScriptArrayReverse_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Reverse(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Reverse(); } static void ScriptArrayIsEmpty_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->IsEmpty(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->IsEmpty(); } static void ScriptArraySortAsc2_Generic(asIScriptGeneric *gen) { - asUINT index = gen->GetArgDWord(0); - asUINT count = gen->GetArgDWord(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SortAsc(index, count); + asUINT index = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortAsc(index, count); } static void ScriptArraySortDesc_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SortDesc(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortDesc(); } static void ScriptArraySortDesc2_Generic(asIScriptGeneric *gen) { - asUINT index = gen->GetArgDWord(0); - asUINT count = gen->GetArgDWord(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SortDesc(index, count); + asUINT index = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortDesc(index, count); } static void ScriptArraySortCallback_Generic(asIScriptGeneric *gen) { - asIScriptFunction *callback = (asIScriptFunction*)gen->GetArgAddress(0); - asUINT startAt = gen->GetArgDWord(1); - asUINT count = gen->GetArgDWord(2); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Sort(callback, startAt, count); + asIScriptFunction *callback = (asIScriptFunction*)gen->GetArgAddress(0); + asUINT startAt = gen->GetArgDWord(1); + asUINT count = gen->GetArgDWord(2); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Sort(callback, startAt, count); } static void ScriptArrayAddRef_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->AddRef(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->AddRef(); } static void ScriptArrayRelease_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Release(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Release(); } static void ScriptArrayGetRefCount_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetRefCount(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetRefCount(); } static void ScriptArraySetFlag_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SetFlag(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SetFlag(); } static void ScriptArrayGetFlag_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetFlag(); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetFlag(); } static void ScriptArrayEnumReferences_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); } static void ScriptArrayReleaseAllHandles_Generic(asIScriptGeneric *gen) { - CScriptArray *self = (CScriptArray*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllHandles(engine); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllHandles(engine); } static void RegisterScriptArray_Generic(asIScriptEngine *engine) { - int r = 0; - UNUSED_VAR(r); - - engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); - - r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTION(ScriptArrayFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTION(ScriptArrayFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTION(ScriptArrayFactoryDefVal_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in, int&in) {repeat T}", asFUNCTION(ScriptArrayListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptArrayAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptArrayRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asFUNCTION(ScriptArrayAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asFUNCTION(ScriptArrayInsertAtArray_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asFUNCTION(ScriptArrayInsertLast_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asFUNCTION(ScriptArrayRemoveAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeLast()", asFUNCTION(ScriptArrayRemoveLast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asFUNCTION(ScriptArrayRemoveRange_Generic), asCALL_GENERIC); assert(r >= 0); + int r = 0; + UNUSED_VAR(r); + + engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); + + r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTION(ScriptArrayFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTION(ScriptArrayFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTION(ScriptArrayFactoryDefVal_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in, int&in) {repeat T}", asFUNCTION(ScriptArrayListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptArrayAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptArrayRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asFUNCTION(ScriptArrayAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asFUNCTION(ScriptArrayInsertAtArray_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asFUNCTION(ScriptArrayInsertLast_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asFUNCTION(ScriptArrayRemoveAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeLast()", asFUNCTION(ScriptArrayRemoveLast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asFUNCTION(ScriptArrayRemoveRange_Generic), asCALL_GENERIC); assert(r >= 0); #if AS_USE_ACCESSORS != 1 - r = engine->RegisterObjectMethod("array", "uint length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "uint length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); #endif - r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asFUNCTION(ScriptArrayReserve_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void resize(uint length)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc()", asFUNCTION(ScriptArraySortAsc_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asFUNCTION(ScriptArraySortAsc2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc()", asFUNCTION(ScriptArraySortDesc_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asFUNCTION(ScriptArraySortDesc2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void reverse()", asFUNCTION(ScriptArrayReverse_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asFUNCTION(ScriptArrayEquals_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asFUNCTION(ScriptArrayIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterFuncdef("bool array::less(const T&in a, const T&in b)"); - r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asFUNCTION(ScriptArraySortCallback_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asFUNCTION(ScriptArrayReserve_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void resize(uint length)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc()", asFUNCTION(ScriptArraySortAsc_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asFUNCTION(ScriptArraySortAsc2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc()", asFUNCTION(ScriptArraySortDesc_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asFUNCTION(ScriptArraySortDesc2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void reverse()", asFUNCTION(ScriptArrayReverse_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asFUNCTION(ScriptArrayEquals_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asFUNCTION(ScriptArrayIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterFuncdef("bool array::less(const T&in a, const T&in b)"); + r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asFUNCTION(ScriptArraySortCallback_Generic), asCALL_GENERIC); assert(r >= 0); #if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 - r = engine->RegisterObjectMethod("array", "uint get_length() const property", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "uint get_length() const property", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); #endif - r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptArrayGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptArraySetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptArrayGetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptArrayEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptArrayReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptArrayGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptArraySetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptArrayGetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptArrayEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptArrayReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 ); } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scriptarray/scriptarray.h b/src/angelscript/add_on/scriptarray/scriptarray.h index 4903a97cb80..294942b02c4 100644 --- a/src/angelscript/add_on/scriptarray/scriptarray.h +++ b/src/angelscript/add_on/scriptarray/scriptarray.h @@ -1,7 +1,7 @@ #ifndef SCRIPTARRAY_H #define SCRIPTARRAY_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -30,109 +30,109 @@ struct SArrayCache; class CScriptArray { public: - // Set the memory functions that should be used by all CScriptArrays - static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); - - // Factory functions - static CScriptArray *Create(asITypeInfo *ot); - static CScriptArray *Create(asITypeInfo *ot, asUINT length); - static CScriptArray *Create(asITypeInfo *ot, asUINT length, void *defaultValue); - static CScriptArray *Create(asITypeInfo *ot, void *listBuffer); - - // Memory management - void AddRef() const; - void Release() const; - - // Type information - asITypeInfo *GetArrayObjectType() const; - int GetArrayTypeId() const; - int GetElementTypeId() const; - - // Get the current size - asUINT GetSize() const; - - // Returns true if the array is empty - bool IsEmpty() const; - - // Pre-allocates memory for elements - void Reserve(asUINT maxElements); - - // Resize the array - void Resize(asUINT numElements); - - // Get a pointer to an element. Returns 0 if out of bounds - void *At(asUINT index); - const void *At(asUINT index) const; - - // Set value of an element. - // The value arg should be a pointer to the value that will be copied to the element. - // Remember, if the array holds handles the value parameter should be the - // address of the handle. The refCount of the object will also be incremented - void SetValue(asUINT index, void *value); - - // Copy the contents of one array to another (only if the types are the same) - CScriptArray &operator=(const CScriptArray&); - - // Compare two arrays - bool operator==(const CScriptArray &) const; - - // Array manipulation - void InsertAt(asUINT index, void *value); - void InsertAt(asUINT index, const CScriptArray &arr); - void InsertLast(void *value); - void RemoveAt(asUINT index); - void RemoveLast(); - void RemoveRange(asUINT start, asUINT count); - void SortAsc(); - void SortDesc(); - void SortAsc(asUINT startAt, asUINT count); - void SortDesc(asUINT startAt, asUINT count); - void Sort(asUINT startAt, asUINT count, bool asc); - void Sort(asIScriptFunction *less, asUINT startAt, asUINT count); - void Reverse(); - int Find(void *value) const; - int Find(asUINT startAt, void *value) const; - int FindByRef(void *ref) const; - int FindByRef(asUINT startAt, void *ref) const; - - // Return the address of internal buffer for direct manipulation of elements - void *GetBuffer(); - - // GC methods - int GetRefCount(); - void SetFlag(); - bool GetFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllHandles(asIScriptEngine *engine); + // Set the memory functions that should be used by all CScriptArrays + static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); + + // Factory functions + static CScriptArray *Create(asITypeInfo *ot); + static CScriptArray *Create(asITypeInfo *ot, asUINT length); + static CScriptArray *Create(asITypeInfo *ot, asUINT length, void *defaultValue); + static CScriptArray *Create(asITypeInfo *ot, void *listBuffer); + + // Memory management + void AddRef() const; + void Release() const; + + // Type information + asITypeInfo *GetArrayObjectType() const; + int GetArrayTypeId() const; + int GetElementTypeId() const; + + // Get the current size + asUINT GetSize() const; + + // Returns true if the array is empty + bool IsEmpty() const; + + // Pre-allocates memory for elements + void Reserve(asUINT maxElements); + + // Resize the array + void Resize(asUINT numElements); + + // Get a pointer to an element. Returns 0 if out of bounds + void *At(asUINT index); + const void *At(asUINT index) const; + + // Set value of an element. + // The value arg should be a pointer to the value that will be copied to the element. + // Remember, if the array holds handles the value parameter should be the + // address of the handle. The refCount of the object will also be incremented + void SetValue(asUINT index, void *value); + + // Copy the contents of one array to another (only if the types are the same) + CScriptArray &operator=(const CScriptArray&); + + // Compare two arrays + bool operator==(const CScriptArray &) const; + + // Array manipulation + void InsertAt(asUINT index, void *value); + void InsertAt(asUINT index, const CScriptArray &arr); + void InsertLast(void *value); + void RemoveAt(asUINT index); + void RemoveLast(); + void RemoveRange(asUINT start, asUINT count); + void SortAsc(); + void SortDesc(); + void SortAsc(asUINT startAt, asUINT count); + void SortDesc(asUINT startAt, asUINT count); + void Sort(asUINT startAt, asUINT count, bool asc); + void Sort(asIScriptFunction *less, asUINT startAt, asUINT count); + void Reverse(); + int Find(void *value) const; + int Find(asUINT startAt, void *value) const; + int FindByRef(void *ref) const; + int FindByRef(asUINT startAt, void *ref) const; + + // Return the address of internal buffer for direct manipulation of elements + void *GetBuffer(); + + // GC methods + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); protected: - mutable int refCount; - mutable bool gcFlag; - asITypeInfo *objType; - SArrayBuffer *buffer; - int elementSize; - int subTypeId; - - // Constructors - CScriptArray(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list - CScriptArray(asUINT length, asITypeInfo *ot); - CScriptArray(asUINT length, void *defVal, asITypeInfo *ot); - CScriptArray(const CScriptArray &other); - virtual ~CScriptArray(); - - bool Less(const void *a, const void *b, bool asc); - void *GetArrayItemPointer(int index); - void *GetDataPointer(void *buffer); - void Copy(void *dst, void *src); - void Precache(); - bool CheckMaxSize(asUINT numElements); - void Resize(int delta, asUINT at); - void CreateBuffer(SArrayBuffer **buf, asUINT numElements); - void DeleteBuffer(SArrayBuffer *buf); - void CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src); - void Construct(SArrayBuffer *buf, asUINT start, asUINT end); - void Destruct(SArrayBuffer *buf, asUINT start, asUINT end); - bool Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const; + mutable int refCount; + mutable bool gcFlag; + asITypeInfo *objType; + SArrayBuffer *buffer; + int elementSize; + int subTypeId; + + // Constructors + CScriptArray(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list + CScriptArray(asUINT length, asITypeInfo *ot); + CScriptArray(asUINT length, void *defVal, asITypeInfo *ot); + CScriptArray(const CScriptArray &other); + virtual ~CScriptArray(); + + bool Less(const void *a, const void *b, bool asc); + void *GetArrayItemPointer(int index); + void *GetDataPointer(void *buffer); + void Copy(void *dst, void *src); + void Precache(); + bool CheckMaxSize(asUINT numElements); + void Resize(int delta, asUINT at); + void CreateBuffer(SArrayBuffer **buf, asUINT numElements); + void DeleteBuffer(SArrayBuffer *buf); + void CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src); + void Construct(SArrayBuffer *buf, asUINT start, asUINT end); + void Destruct(SArrayBuffer *buf, asUINT start, asUINT end); + bool Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const; }; void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray); diff --git a/src/angelscript/add_on/scriptbuilder/scriptbuilder.cpp b/src/angelscript/add_on/scriptbuilder/scriptbuilder.cpp index 97b28331727..f8a36fc7f7f 100644 --- a/src/angelscript/add_on/scriptbuilder/scriptbuilder.cpp +++ b/src/angelscript/add_on/scriptbuilder/scriptbuilder.cpp @@ -24,68 +24,68 @@ static string GetAbsolutePath(const string &path); CScriptBuilder::CScriptBuilder() { - engine = 0; - module = 0; + engine = 0; + module = 0; - includeCallback = 0; - includeParam = 0; + includeCallback = 0; + includeParam = 0; - pragmaCallback = 0; - pragmaParam = 0; + pragmaCallback = 0; + pragmaParam = 0; } void CScriptBuilder::SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam) { - includeCallback = callback; - includeParam = userParam; + includeCallback = callback; + includeParam = userParam; } void CScriptBuilder::SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam) { - pragmaCallback = callback; - pragmaParam = userParam; + pragmaCallback = callback; + pragmaParam = userParam; } int CScriptBuilder::StartNewModule(asIScriptEngine *inEngine, const char *moduleName) { - if(inEngine == 0 ) return -1; + if(inEngine == 0 ) return -1; - engine = inEngine; - module = inEngine->GetModule(moduleName, asGM_ALWAYS_CREATE); - if( module == 0 ) - return -1; + engine = inEngine; + module = inEngine->GetModule(moduleName, asGM_ALWAYS_CREATE); + if( module == 0 ) + return -1; - ClearAll(); + ClearAll(); - return 0; + return 0; } asIScriptEngine *CScriptBuilder::GetEngine() { - return engine; + return engine; } asIScriptModule *CScriptBuilder::GetModule() { - return module; + return module; } unsigned int CScriptBuilder::GetSectionCount() const { - return (unsigned int)(includedScripts.size()); + return (unsigned int)(includedScripts.size()); } string CScriptBuilder::GetSectionName(unsigned int idx) const { - if( idx >= includedScripts.size() ) return ""; + if( idx >= includedScripts.size() ) return ""; #ifdef _WIN32 - set::const_iterator it = includedScripts.begin(); + set::const_iterator it = includedScripts.begin(); #else - set::const_iterator it = includedScripts.begin(); + set::const_iterator it = includedScripts.begin(); #endif - while( idx-- > 0 ) it++; - return *it; + while( idx-- > 0 ) it++; + return *it; } // Returns 1 if the section was included @@ -93,20 +93,20 @@ string CScriptBuilder::GetSectionName(unsigned int idx) const // Returns <0 if there was an error int CScriptBuilder::AddSectionFromFile(const char *filename) { - // The file name stored in the set should be the fully resolved name because - // it is possible to name the same file in multiple ways using relative paths. - string fullpath = GetAbsolutePath(filename); - - if( IncludeIfNotAlreadyIncluded(fullpath.c_str()) ) - { - int r = LoadScriptSection(fullpath.c_str()); - if( r < 0 ) - return r; - else - return 1; - } - - return 0; + // The file name stored in the set should be the fully resolved name because + // it is possible to name the same file in multiple ways using relative paths. + string fullpath = GetAbsolutePath(filename); + + if( IncludeIfNotAlreadyIncluded(fullpath.c_str()) ) + { + int r = LoadScriptSection(fullpath.c_str()); + if( r < 0 ) + return r; + else + return 1; + } + + return 0; } // Returns 1 if the section was included @@ -114,1051 +114,1051 @@ int CScriptBuilder::AddSectionFromFile(const char *filename) // Returns <0 if there was an error int CScriptBuilder::AddSectionFromMemory(const char *sectionName, const char *scriptCode, unsigned int scriptLength, int lineOffset) { - if( IncludeIfNotAlreadyIncluded(sectionName) ) - { - int r = ProcessScriptSection(scriptCode, scriptLength, sectionName, lineOffset); - if( r < 0 ) - return r; - else - return 1; - } - - return 0; + if( IncludeIfNotAlreadyIncluded(sectionName) ) + { + int r = ProcessScriptSection(scriptCode, scriptLength, sectionName, lineOffset); + if( r < 0 ) + return r; + else + return 1; + } + + return 0; } int CScriptBuilder::BuildModule() { - return Build(); + return Build(); } void CScriptBuilder::DefineWord(const char *word) { - string sword = word; - if( definedWords.find(sword) == definedWords.end() ) - { - definedWords.insert(sword); - } + string sword = word; + if( definedWords.find(sword) == definedWords.end() ) + { + definedWords.insert(sword); + } } void CScriptBuilder::ClearAll() { - includedScripts.clear(); + includedScripts.clear(); #if AS_PROCESS_METADATA == 1 - currentClass = ""; - currentNamespace = ""; + currentClass = ""; + currentNamespace = ""; - foundDeclarations.clear(); - typeMetadataMap.clear(); - funcMetadataMap.clear(); - varMetadataMap.clear(); + foundDeclarations.clear(); + typeMetadataMap.clear(); + funcMetadataMap.clear(); + varMetadataMap.clear(); #endif } bool CScriptBuilder::IncludeIfNotAlreadyIncluded(const char *filename) { - string scriptFile = filename; - if( includedScripts.find(scriptFile) != includedScripts.end() ) - { - // Already included - return false; - } + string scriptFile = filename; + if( includedScripts.find(scriptFile) != includedScripts.end() ) + { + // Already included + return false; + } - // Add the file to the set of included sections - includedScripts.insert(scriptFile); + // Add the file to the set of included sections + includedScripts.insert(scriptFile); - return true; + return true; } int CScriptBuilder::LoadScriptSection(const char *filename) { - // Open the script file - string scriptFile = filename; + // Open the script file + string scriptFile = filename; #if _MSC_VER >= 1500 && !defined(__S3E__) - FILE *f = 0; - fopen_s(&f, scriptFile.c_str(), "rb"); + FILE *f = 0; + fopen_s(&f, scriptFile.c_str(), "rb"); #else - FILE *f = fopen(scriptFile.c_str(), "rb"); + FILE *f = fopen(scriptFile.c_str(), "rb"); #endif - if( f == 0 ) - { - // Write a message to the engine's message callback - string msg = "Failed to open script file '" + GetAbsolutePath(scriptFile) + "'"; - engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); - - // TODO: Write the file where this one was included from - - return -1; - } - - // Determine size of the file - fseek(f, 0, SEEK_END); - int len = ftell(f); - fseek(f, 0, SEEK_SET); - - // On Win32 it is possible to do the following instead - // int len = _filelength(_fileno(f)); - - // Read the entire file - string code; - size_t c = 0; - if( len > 0 ) - { - code.resize(len); - c = fread(&code[0], len, 1, f); - } - - fclose(f); - - if( c == 0 && len > 0 ) - { - // Write a message to the engine's message callback - string msg = "Failed to load script file '" + GetAbsolutePath(scriptFile) + "'"; - engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); - return -1; - } - - // Process the script section even if it is zero length so that the name is registered - return ProcessScriptSection(code.c_str(), (unsigned int)(code.length()), filename, 0); + if( f == 0 ) + { + // Write a message to the engine's message callback + string msg = "Failed to open script file '" + GetAbsolutePath(scriptFile) + "'"; + engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); + + // TODO: Write the file where this one was included from + + return -1; + } + + // Determine size of the file + fseek(f, 0, SEEK_END); + int len = ftell(f); + fseek(f, 0, SEEK_SET); + + // On Win32 it is possible to do the following instead + // int len = _filelength(_fileno(f)); + + // Read the entire file + string code; + size_t c = 0; + if( len > 0 ) + { + code.resize(len); + c = fread(&code[0], len, 1, f); + } + + fclose(f); + + if( c == 0 && len > 0 ) + { + // Write a message to the engine's message callback + string msg = "Failed to load script file '" + GetAbsolutePath(scriptFile) + "'"; + engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); + return -1; + } + + // Process the script section even if it is zero length so that the name is registered + return ProcessScriptSection(code.c_str(), (unsigned int)(code.length()), filename, 0); } int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset) { - vector includes; - - // Perform a superficial parsing of the script first to store the metadata - if( length ) - modifiedScript.assign(script, length); - else - modifiedScript = script; - - // First perform the checks for #if directives to exclude code that shouldn't be compiled - unsigned int pos = 0; - int nested = 0; - while( pos < modifiedScript.size() ) - { - asUINT len = 0; - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_UNKNOWN && modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) - { - int start = pos++; - - // Is this an #if directive? - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - - string token; - token.assign(&modifiedScript[pos], len); - - pos += len; - - if( token == "if" ) - { - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_WHITESPACE ) - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } - - if( t == asTC_IDENTIFIER ) - { - string word; - word.assign(&modifiedScript[pos], len); - - // Overwrite the #if directive with space characters to avoid compiler error - pos += len; - OverwriteCode(start, pos-start); - - // Has this identifier been defined by the application or not? - if( definedWords.find(word) == definedWords.end() ) - { - // Exclude all the code until and including the #endif - pos = ExcludeCode(pos); - } - else - { - nested++; - } - } - } - else if( token == "endif" ) - { - // Only remove the #endif if there was a matching #if - if( nested > 0 ) - { - OverwriteCode(start, pos-start); - nested--; - } - } - } - else - pos += len; - } + vector includes; + + // Perform a superficial parsing of the script first to store the metadata + if( length ) + modifiedScript.assign(script, length); + else + modifiedScript = script; + + // First perform the checks for #if directives to exclude code that shouldn't be compiled + unsigned int pos = 0; + int nested = 0; + while( pos < modifiedScript.size() ) + { + asUINT len = 0; + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_UNKNOWN && modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) + { + int start = pos++; + + // Is this an #if directive? + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + string token; + token.assign(&modifiedScript[pos], len); + + pos += len; + + if( token == "if" ) + { + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_WHITESPACE ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if( t == asTC_IDENTIFIER ) + { + string word; + word.assign(&modifiedScript[pos], len); + + // Overwrite the #if directive with space characters to avoid compiler error + pos += len; + OverwriteCode(start, pos-start); + + // Has this identifier been defined by the application or not? + if( definedWords.find(word) == definedWords.end() ) + { + // Exclude all the code until and including the #endif + pos = ExcludeCode(pos); + } + else + { + nested++; + } + } + } + else if( token == "endif" ) + { + // Only remove the #endif if there was a matching #if + if( nested > 0 ) + { + OverwriteCode(start, pos-start); + nested--; + } + } + } + else + pos += len; + } #if AS_PROCESS_METADATA == 1 - // Preallocate memory - string name, declaration; - vector metadata; - declaration.reserve(100); + // Preallocate memory + string name, declaration; + vector metadata; + declaration.reserve(100); #endif - // Then check for meta data and #include directives - pos = 0; - while( pos < modifiedScript.size() ) - { - asUINT len = 0; - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_COMMENT || t == asTC_WHITESPACE ) - { - pos += len; - continue; - } + // Then check for meta data and #include directives + pos = 0; + while( pos < modifiedScript.size() ) + { + asUINT len = 0; + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_COMMENT || t == asTC_WHITESPACE ) + { + pos += len; + continue; + } #if AS_PROCESS_METADATA == 1 - // Check if class - if( currentClass == "" && modifiedScript.substr(pos,len) == "class" ) - { - // Get the identifier after "class" - do - { - pos += len; - if( pos >= modifiedScript.size() ) - { - t = asTC_UNKNOWN; - break; - } - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } while(t == asTC_COMMENT || t == asTC_WHITESPACE); - - if( t == asTC_IDENTIFIER ) - { - currentClass = modifiedScript.substr(pos,len); - - // Search until first { or ; is encountered - while( pos < modifiedScript.length() ) - { - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - - // If start of class section encountered stop - if( modifiedScript[pos] == '{' ) - { - pos += len; - break; - } - else if (modifiedScript[pos] == ';') - { - // The class declaration has ended and there are no children - currentClass = ""; - pos += len; - break; - } - - // Check next symbol - pos += len; - } - } - - continue; - } - - // Check if end of class - if( currentClass != "" && modifiedScript[pos] == '}' ) - { - currentClass = ""; - pos += len; - continue; - } - - // Check if namespace - if( modifiedScript.substr(pos,len) == "namespace" ) - { - // Get the identifier after "namespace" - do - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } while(t == asTC_COMMENT || t == asTC_WHITESPACE); - - if( currentNamespace != "" ) - currentNamespace += "::"; - currentNamespace += modifiedScript.substr(pos,len); - - // Search until first { is encountered - while( pos < modifiedScript.length() ) - { - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - - // If start of namespace section encountered stop - if( modifiedScript[pos] == '{' ) - { - pos += len; - break; - } - - // Check next symbol - pos += len; - } - - continue; - } - - // Check if end of namespace - if( currentNamespace != "" && modifiedScript[pos] == '}' ) - { - size_t found = currentNamespace.rfind( "::" ); - if( found != string::npos ) - { - currentNamespace.erase( found ); - } - else - { - currentNamespace = ""; - } - pos += len; - continue; - } - - // Is this the start of metadata? - if( modifiedScript[pos] == '[' ) - { - // Get the metadata string - pos = ExtractMetadata(pos, metadata); - - // Determine what this metadata is for - int type; - ExtractDeclaration(pos, name, declaration, type); - - // Store away the declaration in a map for lookup after the build has completed - if( type > 0 ) - { - SMetadataDecl decl(metadata, name, declaration, type, currentClass, currentNamespace); - foundDeclarations.push_back(decl); - } - } - else + // Check if class + if( currentClass == "" && modifiedScript.substr(pos,len) == "class" ) + { + // Get the identifier after "class" + do + { + pos += len; + if( pos >= modifiedScript.size() ) + { + t = asTC_UNKNOWN; + break; + } + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while(t == asTC_COMMENT || t == asTC_WHITESPACE); + + if( t == asTC_IDENTIFIER ) + { + currentClass = modifiedScript.substr(pos,len); + + // Search until first { or ; is encountered + while( pos < modifiedScript.length() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + // If start of class section encountered stop + if( modifiedScript[pos] == '{' ) + { + pos += len; + break; + } + else if (modifiedScript[pos] == ';') + { + // The class declaration has ended and there are no children + currentClass = ""; + pos += len; + break; + } + + // Check next symbol + pos += len; + } + } + + continue; + } + + // Check if end of class + if( currentClass != "" && modifiedScript[pos] == '}' ) + { + currentClass = ""; + pos += len; + continue; + } + + // Check if namespace + if( modifiedScript.substr(pos,len) == "namespace" ) + { + // Get the identifier after "namespace" + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while(t == asTC_COMMENT || t == asTC_WHITESPACE); + + if( currentNamespace != "" ) + currentNamespace += "::"; + currentNamespace += modifiedScript.substr(pos,len); + + // Search until first { is encountered + while( pos < modifiedScript.length() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + // If start of namespace section encountered stop + if( modifiedScript[pos] == '{' ) + { + pos += len; + break; + } + + // Check next symbol + pos += len; + } + + continue; + } + + // Check if end of namespace + if( currentNamespace != "" && modifiedScript[pos] == '}' ) + { + size_t found = currentNamespace.rfind( "::" ); + if( found != string::npos ) + { + currentNamespace.erase( found ); + } + else + { + currentNamespace = ""; + } + pos += len; + continue; + } + + // Is this the start of metadata? + if( modifiedScript[pos] == '[' ) + { + // Get the metadata string + pos = ExtractMetadata(pos, metadata); + + // Determine what this metadata is for + int type; + ExtractDeclaration(pos, name, declaration, type); + + // Store away the declaration in a map for lookup after the build has completed + if( type > 0 ) + { + SMetadataDecl decl(metadata, name, declaration, type, currentClass, currentNamespace); + foundDeclarations.push_back(decl); + } + } + else #endif - // Is this a preprocessor directive? - if( modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) - { - int start = pos++; - - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_IDENTIFIER ) - { - string token; - token.assign(&modifiedScript[pos], len); - if( token == "include" ) - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_WHITESPACE ) - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } - - if( t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\'') ) - { - // Get the include file - string includefile; - includefile.assign(&modifiedScript[pos+1], len-2); - pos += len; - - // Store it for later processing - includes.push_back(includefile); - - // Overwrite the include directive with space characters to avoid compiler error - OverwriteCode(start, pos-start); - } - } - else if (token == "pragma") - { - // Read until the end of the line - pos += len; - for (; pos < modifiedScript.size() && modifiedScript[pos] != '\n'; pos++); - - // Call the pragma callback - string pragmaText(&modifiedScript[start + 7], pos - start - 7); - int r = pragmaCallback ? pragmaCallback(pragmaText, *this, pragmaParam) : -1; - if (r < 0) - { - // TODO: Report the correct line number - engine->WriteMessage(sectionname, 0, 0, asMSGTYPE_ERROR, "Invalid #pragma directive"); - return r; - } - - // Overwrite the pragma directive with space characters to avoid compiler error - OverwriteCode(start, pos - start); - } - } - } - // Don't search for metadata/includes within statement blocks or between tokens in statements - else - { - pos = SkipStatement(pos); - } - } - - // Build the actual script - engine->SetEngineProperty(asEP_COPY_SCRIPT_SECTIONS, true); - module->AddScriptSection(sectionname, modifiedScript.c_str(), modifiedScript.size(), lineOffset); - - if( includes.size() > 0 ) - { - // If the callback has been set, then call it for each included file - if( includeCallback ) - { - for( int n = 0; n < (int)includes.size(); n++ ) - { - int r = includeCallback(includes[n].c_str(), sectionname, this, includeParam); - if( r < 0 ) - return r; - } - } - else - { - // By default we try to load the included file from the relative directory of the current file - - // Determine the path of the current script so that we can resolve relative paths for includes - string path = sectionname; - size_t posOfSlash = path.find_last_of("/\\"); - if( posOfSlash != string::npos ) - path.resize(posOfSlash+1); - else - path = ""; - - // Load the included scripts - for( int n = 0; n < (int)includes.size(); n++ ) - { - // If the include is a relative path, then prepend the path of the originating script - if( includes[n].find_first_of("/\\") != 0 && - includes[n].find_first_of(":") == string::npos ) - { - includes[n] = path + includes[n]; - } - - // Include the script section - int r = AddSectionFromFile(includes[n].c_str()); - if( r < 0 ) - return r; - } - } - } - - return 0; + // Is this a preprocessor directive? + if( modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) + { + int start = pos++; + + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_IDENTIFIER ) + { + string token; + token.assign(&modifiedScript[pos], len); + if( token == "include" ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_WHITESPACE ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if( t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\'') ) + { + // Get the include file + string includefile; + includefile.assign(&modifiedScript[pos+1], len-2); + pos += len; + + // Store it for later processing + includes.push_back(includefile); + + // Overwrite the include directive with space characters to avoid compiler error + OverwriteCode(start, pos-start); + } + } + else if (token == "pragma") + { + // Read until the end of the line + pos += len; + for (; pos < modifiedScript.size() && modifiedScript[pos] != '\n'; pos++); + + // Call the pragma callback + string pragmaText(&modifiedScript[start + 7], pos - start - 7); + int r = pragmaCallback ? pragmaCallback(pragmaText, *this, pragmaParam) : -1; + if (r < 0) + { + // TODO: Report the correct line number + engine->WriteMessage(sectionname, 0, 0, asMSGTYPE_ERROR, "Invalid #pragma directive"); + return r; + } + + // Overwrite the pragma directive with space characters to avoid compiler error + OverwriteCode(start, pos - start); + } + } + } + // Don't search for metadata/includes within statement blocks or between tokens in statements + else + { + pos = SkipStatement(pos); + } + } + + // Build the actual script + engine->SetEngineProperty(asEP_COPY_SCRIPT_SECTIONS, true); + module->AddScriptSection(sectionname, modifiedScript.c_str(), modifiedScript.size(), lineOffset); + + if( includes.size() > 0 ) + { + // If the callback has been set, then call it for each included file + if( includeCallback ) + { + for( int n = 0; n < (int)includes.size(); n++ ) + { + int r = includeCallback(includes[n].c_str(), sectionname, this, includeParam); + if( r < 0 ) + return r; + } + } + else + { + // By default we try to load the included file from the relative directory of the current file + + // Determine the path of the current script so that we can resolve relative paths for includes + string path = sectionname; + size_t posOfSlash = path.find_last_of("/\\"); + if( posOfSlash != string::npos ) + path.resize(posOfSlash+1); + else + path = ""; + + // Load the included scripts + for( int n = 0; n < (int)includes.size(); n++ ) + { + // If the include is a relative path, then prepend the path of the originating script + if( includes[n].find_first_of("/\\") != 0 && + includes[n].find_first_of(":") == string::npos ) + { + includes[n] = path + includes[n]; + } + + // Include the script section + int r = AddSectionFromFile(includes[n].c_str()); + if( r < 0 ) + return r; + } + } + } + + return 0; } int CScriptBuilder::Build() { - int r = module->Build(); - if( r < 0 ) - return r; + int r = module->Build(); + if( r < 0 ) + return r; #if AS_PROCESS_METADATA == 1 - // After the script has been built, the metadata strings should be - // stored for later lookup by function id, type id, and variable index - for( int n = 0; n < (int)foundDeclarations.size(); n++ ) - { - SMetadataDecl *decl = &foundDeclarations[n]; - module->SetDefaultNamespace(decl->nameSpace.c_str()); - if( decl->type == MDT_TYPE ) - { - // Find the type id - int typeId = module->GetTypeIdByDecl(decl->declaration.c_str()); - assert( typeId >= 0 ); - if( typeId >= 0 ) - typeMetadataMap.insert(map >::value_type(typeId, decl->metadata)); - } - else if( decl->type == MDT_FUNC ) - { - if( decl->parentClass == "" ) - { - // Find the function id - asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); - assert( func ); - if( func ) - funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - else - { - // Find the method id - int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); - assert( typeId > 0 ); - map::iterator it = classMetadataMap.find(typeId); - if( it == classMetadataMap.end() ) - { - classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); - it = classMetadataMap.find(typeId); - } - - asITypeInfo *type = engine->GetTypeInfoById(typeId); - asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); - assert( func ); - if( func ) - it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - } - else if( decl->type == MDT_VIRTPROP ) - { - if( decl->parentClass == "" ) - { - // Find the global virtual property accessors - asIScriptFunction *func = module->GetFunctionByName(("get_" + decl->declaration).c_str()); - if( func ) - funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - func = module->GetFunctionByName(("set_" + decl->declaration).c_str()); - if( func ) - funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - else - { - // Find the method virtual property accessors - int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); - assert( typeId > 0 ); - map::iterator it = classMetadataMap.find(typeId); - if( it == classMetadataMap.end() ) - { - classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); - it = classMetadataMap.find(typeId); - } - - asITypeInfo *type = engine->GetTypeInfoById(typeId); - asIScriptFunction *func = type->GetMethodByName(("get_" + decl->declaration).c_str()); - if( func ) - it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - func = type->GetMethodByName(("set_" + decl->declaration).c_str()); - if( func ) - it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - } - else if( decl->type == MDT_VAR ) - { - if( decl->parentClass == "" ) - { - // Find the global variable index - int varIdx = module->GetGlobalVarIndexByName(decl->declaration.c_str()); - assert( varIdx >= 0 ); - if( varIdx >= 0 ) - varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); - } - else - { - int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); - assert( typeId > 0 ); - - // Add the classes if needed - map::iterator it = classMetadataMap.find(typeId); - if( it == classMetadataMap.end() ) - { - classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); - it = classMetadataMap.find(typeId); - } - - // Add the variable to class - asITypeInfo *objectType = engine->GetTypeInfoById(typeId); - int idx = -1; - - // Search through all properties to get proper declaration - for( asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i ) - { - const char *name; - objectType->GetProperty(i, &name); - if( decl->declaration == name ) - { - idx = i; - break; - } - } - - // If found, add it - assert( idx >= 0 ); - if( idx >= 0 ) it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); - } - } - else if (decl->type == MDT_FUNC_OR_VAR) - { - if (decl->parentClass == "") - { - // Find the global variable index - int varIdx = module->GetGlobalVarIndexByName(decl->name.c_str()); - if (varIdx >= 0) - varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); - else - { - asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); - assert(func); - if (func) - funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - } - else - { - int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); - assert(typeId > 0); - - // Add the classes if needed - map::iterator it = classMetadataMap.find(typeId); - if (it == classMetadataMap.end()) - { - classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); - it = classMetadataMap.find(typeId); - } - - // Add the variable to class - asITypeInfo *objectType = engine->GetTypeInfoById(typeId); - int idx = -1; - - // Search through all properties to get proper declaration - for (asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i) - { - const char *name; - objectType->GetProperty(i, &name); - if (decl->name == name) - { - idx = i; - break; - } - } - - // If found, add it - if (idx >= 0) - it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); - else - { - // Look for the matching method instead - asITypeInfo *type = engine->GetTypeInfoById(typeId); - asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); - assert(func); - if (func) - it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - } - } - } - module->SetDefaultNamespace(""); + // After the script has been built, the metadata strings should be + // stored for later lookup by function id, type id, and variable index + for( int n = 0; n < (int)foundDeclarations.size(); n++ ) + { + SMetadataDecl *decl = &foundDeclarations[n]; + module->SetDefaultNamespace(decl->nameSpace.c_str()); + if( decl->type == MDT_TYPE ) + { + // Find the type id + int typeId = module->GetTypeIdByDecl(decl->declaration.c_str()); + assert( typeId >= 0 ); + if( typeId >= 0 ) + typeMetadataMap.insert(map >::value_type(typeId, decl->metadata)); + } + else if( decl->type == MDT_FUNC ) + { + if( decl->parentClass == "" ) + { + // Find the function id + asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); + assert( func ); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + else + { + // Find the method id + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); + assert( func ); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else if( decl->type == MDT_VIRTPROP ) + { + if( decl->parentClass == "" ) + { + // Find the global virtual property accessors + asIScriptFunction *func = module->GetFunctionByName(("get_" + decl->declaration).c_str()); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + func = module->GetFunctionByName(("set_" + decl->declaration).c_str()); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + else + { + // Find the method virtual property accessors + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByName(("get_" + decl->declaration).c_str()); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + func = type->GetMethodByName(("set_" + decl->declaration).c_str()); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else if( decl->type == MDT_VAR ) + { + if( decl->parentClass == "" ) + { + // Find the global variable index + int varIdx = module->GetGlobalVarIndexByName(decl->declaration.c_str()); + assert( varIdx >= 0 ); + if( varIdx >= 0 ) + varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); + } + else + { + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + + // Add the classes if needed + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + // Add the variable to class + asITypeInfo *objectType = engine->GetTypeInfoById(typeId); + int idx = -1; + + // Search through all properties to get proper declaration + for( asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i ) + { + const char *name; + objectType->GetProperty(i, &name); + if( decl->declaration == name ) + { + idx = i; + break; + } + } + + // If found, add it + assert( idx >= 0 ); + if( idx >= 0 ) it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); + } + } + else if (decl->type == MDT_FUNC_OR_VAR) + { + if (decl->parentClass == "") + { + // Find the global variable index + int varIdx = module->GetGlobalVarIndexByName(decl->name.c_str()); + if (varIdx >= 0) + varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); + else + { + asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); + assert(func); + if (func) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else + { + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert(typeId > 0); + + // Add the classes if needed + map::iterator it = classMetadataMap.find(typeId); + if (it == classMetadataMap.end()) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + // Add the variable to class + asITypeInfo *objectType = engine->GetTypeInfoById(typeId); + int idx = -1; + + // Search through all properties to get proper declaration + for (asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i) + { + const char *name; + objectType->GetProperty(i, &name); + if (decl->name == name) + { + idx = i; + break; + } + } + + // If found, add it + if (idx >= 0) + it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); + else + { + // Look for the matching method instead + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); + assert(func); + if (func) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + } + } + module->SetDefaultNamespace(""); #endif - return 0; + return 0; } int CScriptBuilder::SkipStatement(int pos) { - asUINT len = 0; - - // Skip until ; or { whichever comes first - while( pos < (int)modifiedScript.length() && modifiedScript[pos] != ';' && modifiedScript[pos] != '{' ) - { - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - pos += len; - } - - // Skip entire statement block - if( pos < (int)modifiedScript.length() && modifiedScript[pos] == '{' ) - { - pos += 1; - - // Find the end of the statement block - int level = 1; - while( level > 0 && pos < (int)modifiedScript.size() ) - { - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_KEYWORD ) - { - if( modifiedScript[pos] == '{' ) - level++; - else if( modifiedScript[pos] == '}' ) - level--; - } - - pos += len; - } - } - else - pos += 1; - - return pos; + asUINT len = 0; + + // Skip until ; or { whichever comes first + while( pos < (int)modifiedScript.length() && modifiedScript[pos] != ';' && modifiedScript[pos] != '{' ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + pos += len; + } + + // Skip entire statement block + if( pos < (int)modifiedScript.length() && modifiedScript[pos] == '{' ) + { + pos += 1; + + // Find the end of the statement block + int level = 1; + while( level > 0 && pos < (int)modifiedScript.size() ) + { + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_KEYWORD ) + { + if( modifiedScript[pos] == '{' ) + level++; + else if( modifiedScript[pos] == '}' ) + level--; + } + + pos += len; + } + } + else + pos += 1; + + return pos; } // Overwrite all code with blanks until the matching #endif int CScriptBuilder::ExcludeCode(int pos) { - asUINT len = 0; - int nested = 0; - while( pos < (int)modifiedScript.size() ) - { - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( modifiedScript[pos] == '#' ) - { - modifiedScript[pos] = ' '; - pos++; - - // Is it an #if or #endif directive? - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - string token; - token.assign(&modifiedScript[pos], len); - OverwriteCode(pos, len); - - if( token == "if" ) - { - nested++; - } - else if( token == "endif" ) - { - if( nested-- == 0 ) - { - pos += len; - break; - } - } - } - else if( modifiedScript[pos] != '\n' ) - { - OverwriteCode(pos, len); - } - pos += len; - } - - return pos; + asUINT len = 0; + int nested = 0; + while( pos < (int)modifiedScript.size() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( modifiedScript[pos] == '#' ) + { + modifiedScript[pos] = ' '; + pos++; + + // Is it an #if or #endif directive? + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + string token; + token.assign(&modifiedScript[pos], len); + OverwriteCode(pos, len); + + if( token == "if" ) + { + nested++; + } + else if( token == "endif" ) + { + if( nested-- == 0 ) + { + pos += len; + break; + } + } + } + else if( modifiedScript[pos] != '\n' ) + { + OverwriteCode(pos, len); + } + pos += len; + } + + return pos; } // Overwrite all characters except line breaks with blanks void CScriptBuilder::OverwriteCode(int start, int len) { - char *code = &modifiedScript[start]; - for( int n = 0; n < len; n++ ) - { - if( *code != '\n' ) - *code = ' '; - code++; - } + char *code = &modifiedScript[start]; + for( int n = 0; n < len; n++ ) + { + if( *code != '\n' ) + *code = ' '; + code++; + } } #if AS_PROCESS_METADATA == 1 int CScriptBuilder::ExtractMetadata(int pos, vector &metadata) { - metadata.clear(); - - // Extract all metadata. They can be separated by whitespace and comments - for (;;) - { - string metadataString = ""; - - // Overwrite the metadata with space characters to allow compilation - modifiedScript[pos] = ' '; - - // Skip opening brackets - pos += 1; - - int level = 1; - asUINT len = 0; - while (level > 0 && pos < (int)modifiedScript.size()) - { - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if (t == asTC_KEYWORD) - { - if (modifiedScript[pos] == '[') - level++; - else if (modifiedScript[pos] == ']') - level--; - } - - // Copy the metadata to our buffer - if (level > 0) - metadataString.append(&modifiedScript[pos], len); - - // Overwrite the metadata with space characters to allow compilation - if (t != asTC_WHITESPACE) - OverwriteCode(pos, len); - - pos += len; - } - - metadata.push_back(metadataString); - - // Check for more metadata. Possibly separated by comments - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - while (t == asTC_COMMENT || t == asTC_WHITESPACE) - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } - - if (modifiedScript[pos] != '[') - break; - } - - return pos; + metadata.clear(); + + // Extract all metadata. They can be separated by whitespace and comments + for (;;) + { + string metadataString = ""; + + // Overwrite the metadata with space characters to allow compilation + modifiedScript[pos] = ' '; + + // Skip opening brackets + pos += 1; + + int level = 1; + asUINT len = 0; + while (level > 0 && pos < (int)modifiedScript.size()) + { + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if (t == asTC_KEYWORD) + { + if (modifiedScript[pos] == '[') + level++; + else if (modifiedScript[pos] == ']') + level--; + } + + // Copy the metadata to our buffer + if (level > 0) + metadataString.append(&modifiedScript[pos], len); + + // Overwrite the metadata with space characters to allow compilation + if (t != asTC_WHITESPACE) + OverwriteCode(pos, len); + + pos += len; + } + + metadata.push_back(metadataString); + + // Check for more metadata. Possibly separated by comments + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + while (t == asTC_COMMENT || t == asTC_WHITESPACE) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if (modifiedScript[pos] != '[') + break; + } + + return pos; } int CScriptBuilder::ExtractDeclaration(int pos, string &name, string &declaration, int &type) { - declaration = ""; - type = 0; - - int start = pos; - - std::string token; - asUINT len = 0; - asETokenClass t = asTC_WHITESPACE; - - // Skip white spaces, comments, and leading decorators - do - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - token.assign(&modifiedScript[pos], len); - } while ( t == asTC_WHITESPACE || t == asTC_COMMENT || - token == "private" || token == "protected" || - token == "shared" || token == "external" || - token == "final" || token == "abstract" ); - - // We're expecting, either a class, interface, function, or variable declaration - if( t == asTC_KEYWORD || t == asTC_IDENTIFIER ) - { - token.assign(&modifiedScript[pos], len); - if( token == "interface" || token == "class" || token == "enum" ) - { - // Skip white spaces and comments - do - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } while ( t == asTC_WHITESPACE || t == asTC_COMMENT ); - - if( t == asTC_IDENTIFIER ) - { - type = MDT_TYPE; - declaration.assign(&modifiedScript[pos], len); - pos += len; - return pos; - } - } - else - { - // For function declarations, store everything up to the start of the - // statement block, except for succeeding decorators (final, override, etc) - - // For variable declaration store just the name as there can only be one - - // We'll only know if the declaration is a variable or function declaration - // when we see the statement block, or absense of a statement block. - bool hasParenthesis = false; - int nestedParenthesis = 0; - declaration.append(&modifiedScript[pos], len); - pos += len; - for(; pos < (int)modifiedScript.size();) - { - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - token.assign(&modifiedScript[pos], len); - if (t == asTC_KEYWORD) - { - if (token == "{" && nestedParenthesis == 0) - { - if (hasParenthesis) - { - // We've found the end of a function signature - type = MDT_FUNC; - } - else - { - // We've found a virtual property. Just keep the name - declaration = name; - type = MDT_VIRTPROP; - } - return pos; - } - if ((token == "=" && !hasParenthesis) || token == ";") - { - if (hasParenthesis) - { - // The declaration is ambigous. It can be a variable with initialization, or a function prototype - type = MDT_FUNC_OR_VAR; - } - else - { - // Substitute the declaration with just the name - declaration = name; - type = MDT_VAR; - } - return pos; - } - else if (token == "(") - { - nestedParenthesis++; - - // This is the first parenthesis we encounter. If the parenthesis isn't followed - // by a statement block, then this is a variable declaration, in which case we - // should only store the type and name of the variable, not the initialization parameters. - hasParenthesis = true; - } - else if (token == ")") - { - nestedParenthesis--; - } - } - else if( t == asTC_IDENTIFIER ) - { - name = token; - } - - // Skip trailing decorators - if( !hasParenthesis || nestedParenthesis > 0 || t != asTC_IDENTIFIER || (token != "final" && token != "override") ) - declaration += token; - - pos += len; - } - } - } - - return start; + declaration = ""; + type = 0; + + int start = pos; + + std::string token; + asUINT len = 0; + asETokenClass t = asTC_WHITESPACE; + + // Skip white spaces, comments, and leading decorators + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + token.assign(&modifiedScript[pos], len); + } while ( t == asTC_WHITESPACE || t == asTC_COMMENT || + token == "private" || token == "protected" || + token == "shared" || token == "external" || + token == "final" || token == "abstract" ); + + // We're expecting, either a class, interface, function, or variable declaration + if( t == asTC_KEYWORD || t == asTC_IDENTIFIER ) + { + token.assign(&modifiedScript[pos], len); + if( token == "interface" || token == "class" || token == "enum" ) + { + // Skip white spaces and comments + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while ( t == asTC_WHITESPACE || t == asTC_COMMENT ); + + if( t == asTC_IDENTIFIER ) + { + type = MDT_TYPE; + declaration.assign(&modifiedScript[pos], len); + pos += len; + return pos; + } + } + else + { + // For function declarations, store everything up to the start of the + // statement block, except for succeeding decorators (final, override, etc) + + // For variable declaration store just the name as there can only be one + + // We'll only know if the declaration is a variable or function declaration + // when we see the statement block, or absense of a statement block. + bool hasParenthesis = false; + int nestedParenthesis = 0; + declaration.append(&modifiedScript[pos], len); + pos += len; + for(; pos < (int)modifiedScript.size();) + { + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + token.assign(&modifiedScript[pos], len); + if (t == asTC_KEYWORD) + { + if (token == "{" && nestedParenthesis == 0) + { + if (hasParenthesis) + { + // We've found the end of a function signature + type = MDT_FUNC; + } + else + { + // We've found a virtual property. Just keep the name + declaration = name; + type = MDT_VIRTPROP; + } + return pos; + } + if ((token == "=" && !hasParenthesis) || token == ";") + { + if (hasParenthesis) + { + // The declaration is ambigous. It can be a variable with initialization, or a function prototype + type = MDT_FUNC_OR_VAR; + } + else + { + // Substitute the declaration with just the name + declaration = name; + type = MDT_VAR; + } + return pos; + } + else if (token == "(") + { + nestedParenthesis++; + + // This is the first parenthesis we encounter. If the parenthesis isn't followed + // by a statement block, then this is a variable declaration, in which case we + // should only store the type and name of the variable, not the initialization parameters. + hasParenthesis = true; + } + else if (token == ")") + { + nestedParenthesis--; + } + } + else if( t == asTC_IDENTIFIER ) + { + name = token; + } + + // Skip trailing decorators + if( !hasParenthesis || nestedParenthesis > 0 || t != asTC_IDENTIFIER || (token != "final" && token != "override") ) + declaration += token; + + pos += len; + } + } + } + + return start; } vector CScriptBuilder::GetMetadataForType(int typeId) { - map >::iterator it = typeMetadataMap.find(typeId); - if( it != typeMetadataMap.end() ) - return it->second; + map >::iterator it = typeMetadataMap.find(typeId); + if( it != typeMetadataMap.end() ) + return it->second; - return vector(); + return vector(); } vector CScriptBuilder::GetMetadataForFunc(asIScriptFunction *func) { - if( func ) - { - map >::iterator it = funcMetadataMap.find(func->GetId()); - if( it != funcMetadataMap.end() ) - return it->second; - } - - return vector(); + if( func ) + { + map >::iterator it = funcMetadataMap.find(func->GetId()); + if( it != funcMetadataMap.end() ) + return it->second; + } + + return vector(); } vector CScriptBuilder::GetMetadataForVar(int varIdx) { - map >::iterator it = varMetadataMap.find(varIdx); - if( it != varMetadataMap.end() ) - return it->second; + map >::iterator it = varMetadataMap.find(varIdx); + if( it != varMetadataMap.end() ) + return it->second; - return vector(); + return vector(); } vector CScriptBuilder::GetMetadataForTypeProperty(int typeId, int varIdx) { - map::iterator typeIt = classMetadataMap.find(typeId); - if(typeIt == classMetadataMap.end()) return vector(); + map::iterator typeIt = classMetadataMap.find(typeId); + if(typeIt == classMetadataMap.end()) return vector(); - map >::iterator propIt = typeIt->second.varMetadataMap.find(varIdx); - if(propIt == typeIt->second.varMetadataMap.end()) return vector(); + map >::iterator propIt = typeIt->second.varMetadataMap.find(varIdx); + if(propIt == typeIt->second.varMetadataMap.end()) return vector(); - return propIt->second; + return propIt->second; } vector CScriptBuilder::GetMetadataForTypeMethod(int typeId, asIScriptFunction *method) { - if( method ) - { - map::iterator typeIt = classMetadataMap.find(typeId); - if (typeIt == classMetadataMap.end()) return vector(); + if( method ) + { + map::iterator typeIt = classMetadataMap.find(typeId); + if (typeIt == classMetadataMap.end()) return vector(); - map >::iterator methodIt = typeIt->second.funcMetadataMap.find(method->GetId()); - if(methodIt == typeIt->second.funcMetadataMap.end()) return vector(); + map >::iterator methodIt = typeIt->second.funcMetadataMap.find(method->GetId()); + if(methodIt == typeIt->second.funcMetadataMap.end()) return vector(); - return methodIt->second; - } + return methodIt->second; + } - return vector(); + return vector(); } #endif string GetAbsolutePath(const string &file) { - string str = file; - - // If this is a relative path, complement it with the current path - if( !((str.length() > 0 && (str[0] == '/' || str[0] == '\\')) || - str.find(":") != string::npos) ) - { - str = GetCurrentDir() + "/" + str; - } - - // Replace backslashes for forward slashes - size_t pos = 0; - while( (pos = str.find("\\", pos)) != string::npos ) - str[pos] = '/'; - - // Replace /./ with / - pos = 0; - while( (pos = str.find("/./", pos)) != string::npos ) - str.erase(pos+1, 2); - - // For each /../ remove the parent dir and the /../ - pos = 0; - while( (pos = str.find("/../")) != string::npos ) - { - size_t pos2 = str.rfind("/", pos-1); - if( pos2 != string::npos ) - str.erase(pos2, pos+3-pos2); - else - { - // The path is invalid - break; - } - } - - return str; + string str = file; + + // If this is a relative path, complement it with the current path + if( !((str.length() > 0 && (str[0] == '/' || str[0] == '\\')) || + str.find(":") != string::npos) ) + { + str = GetCurrentDir() + "/" + str; + } + + // Replace backslashes for forward slashes + size_t pos = 0; + while( (pos = str.find("\\", pos)) != string::npos ) + str[pos] = '/'; + + // Replace /./ with / + pos = 0; + while( (pos = str.find("/./", pos)) != string::npos ) + str.erase(pos+1, 2); + + // For each /../ remove the parent dir and the /../ + pos = 0; + while( (pos = str.find("/../")) != string::npos ) + { + size_t pos2 = str.rfind("/", pos-1); + if( pos2 != string::npos ) + str.erase(pos2, pos+3-pos2); + else + { + // The path is invalid + break; + } + } + + return str; } string GetCurrentDir() { - char buffer[1024]; + char buffer[1024]; #if defined(_MSC_VER) || defined(_WIN32) - #ifdef _WIN32_WCE - static TCHAR apppath[MAX_PATH] = TEXT(""); - if (!apppath[0]) - { - GetModuleFileName(NULL, apppath, MAX_PATH); - - int appLen = _tcslen(apppath); - - // Look for the last backslash in the path, which would be the end - // of the path itself and the start of the filename. We only want - // the path part of the exe's full-path filename - // Safety is that we make sure not to walk off the front of the - // array (in case the path is nothing more than a filename) - while (appLen > 1) - { - if (apppath[appLen-1] == TEXT('\\')) - break; - appLen--; - } - - // Terminate the string after the trailing backslash - apppath[appLen] = TEXT('\0'); - } - #ifdef _UNICODE - wcstombs(buffer, apppath, min(1024, wcslen(apppath)*sizeof(wchar_t))); - #else - memcpy(buffer, apppath, min(1024, strlen(apppath))); - #endif - - return buffer; - #elif defined(__S3E__) - // Marmalade uses its own portable C library - return getcwd(buffer, (int)1024); - #elif _XBOX_VER >= 200 - // XBox 360 doesn't support the getcwd function, just use the root folder - return "game:/"; - #elif defined(_M_ARM) - // TODO: How to determine current working dir on Windows Phone? - return ""; - #else - return _getcwd(buffer, (int)1024); - #endif // _MSC_VER + #ifdef _WIN32_WCE + static TCHAR apppath[MAX_PATH] = TEXT(""); + if (!apppath[0]) + { + GetModuleFileName(NULL, apppath, MAX_PATH); + + int appLen = _tcslen(apppath); + + // Look for the last backslash in the path, which would be the end + // of the path itself and the start of the filename. We only want + // the path part of the exe's full-path filename + // Safety is that we make sure not to walk off the front of the + // array (in case the path is nothing more than a filename) + while (appLen > 1) + { + if (apppath[appLen-1] == TEXT('\\')) + break; + appLen--; + } + + // Terminate the string after the trailing backslash + apppath[appLen] = TEXT('\0'); + } + #ifdef _UNICODE + wcstombs(buffer, apppath, min(1024, wcslen(apppath)*sizeof(wchar_t))); + #else + memcpy(buffer, apppath, min(1024, strlen(apppath))); + #endif + + return buffer; + #elif defined(__S3E__) + // Marmalade uses its own portable C library + return getcwd(buffer, (int)1024); + #elif _XBOX_VER >= 200 + // XBox 360 doesn't support the getcwd function, just use the root folder + return "game:/"; + #elif defined(_M_ARM) + // TODO: How to determine current working dir on Windows Phone? + return ""; + #else + return _getcwd(buffer, (int)1024); + #endif // _MSC_VER #elif defined(__APPLE__) || defined(__linux__) - return getcwd(buffer, 1024); + return getcwd(buffer, 1024); #else - return ""; + return ""; #endif } diff --git a/src/angelscript/add_on/scriptbuilder/scriptbuilder.h b/src/angelscript/add_on/scriptbuilder/scriptbuilder.h index c61435e931a..c3ed377263a 100644 --- a/src/angelscript/add_on/scriptbuilder/scriptbuilder.h +++ b/src/angelscript/add_on/scriptbuilder/scriptbuilder.h @@ -43,36 +43,36 @@ template class PtrRelease { private: - T* ptr = nullptr; + T* ptr = nullptr; public: - PtrRelease() {} - PtrRelease(const PtrRelease&) = delete; - PtrRelease& operator=(PtrRelease const&) = delete; - ~PtrRelease() { if (nullptr != ptr) ptr->Release(); } - - /// @brief this reset release its ownership and re-acquire another one - void reset(T* p) noexcept - { - assert((nullptr == p) || (ptr != p)); // auto-reset not allowed - if (nullptr != ptr) ptr->Release(); - ptr = p; - } - // underlying pointer operations : - inline T& operator*() const noexcept - { - assert(nullptr != ptr); - return *ptr; - } - inline T* operator->() const noexcept - { - assert(nullptr != ptr); - return ptr; - } - inline T* get() const noexcept - { - // no assert, can return nullptr - return ptr; - } + PtrRelease() {} + PtrRelease(const PtrRelease&) = delete; + PtrRelease& operator=(PtrRelease const&) = delete; + ~PtrRelease() { if (nullptr != ptr) ptr->Release(); } + + /// @brief this reset release its ownership and re-acquire another one + void reset(T* p) noexcept + { + assert((nullptr == p) || (ptr != p)); // auto-reset not allowed + if (nullptr != ptr) ptr->Release(); + ptr = p; + } + // underlying pointer operations : + inline T& operator*() const noexcept + { + assert(nullptr != ptr); + return *ptr; + } + inline T* operator->() const noexcept + { + assert(nullptr != ptr); + return ptr; + } + inline T* get() const noexcept + { + // no assert, can return nullptr + return ptr; + } }; class CScriptBuilder; @@ -93,158 +93,158 @@ typedef int(*PRAGMACALLBACK_t)(const std::string &pragmaText, CScriptBuilder &bu class CScriptBuilder { public: - CScriptBuilder(); + CScriptBuilder(); - // Start a new module - int StartNewModule(asIScriptEngine *engine, const char *moduleName); + // Start a new module + int StartNewModule(asIScriptEngine *engine, const char *moduleName); - // Load a script section from a file on disk - // Returns 1 if the file was included - // 0 if the file had already been included before - // <0 on error - int AddSectionFromFile(const char *filename); + // Load a script section from a file on disk + // Returns 1 if the file was included + // 0 if the file had already been included before + // <0 on error + int AddSectionFromFile(const char *filename); - // Load a script section from memory - // Returns 1 if the section was included - // 0 if a section with the same name had already been included before - // <0 on error - int AddSectionFromMemory(const char *sectionName, - const char *scriptCode, - unsigned int scriptLength = 0, - int lineOffset = 0); + // Load a script section from memory + // Returns 1 if the section was included + // 0 if a section with the same name had already been included before + // <0 on error + int AddSectionFromMemory(const char *sectionName, + const char *scriptCode, + unsigned int scriptLength = 0, + int lineOffset = 0); - // Build the added script sections - int BuildModule(); + // Build the added script sections + int BuildModule(); - // Returns the engine - asIScriptEngine *GetEngine(); + // Returns the engine + asIScriptEngine *GetEngine(); - // Returns the current module - asIScriptModule *GetModule(); + // Returns the current module + asIScriptModule *GetModule(); - // Register the callback for resolving include directive - void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam); + // Register the callback for resolving include directive + void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam); - // Register the callback for resolving pragma directive - void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam); + // Register the callback for resolving pragma directive + void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam); - // Add a pre-processor define for conditional compilation - void DefineWord(const char *word); + // Add a pre-processor define for conditional compilation + void DefineWord(const char *word); - // Enumerate included script sections - unsigned int GetSectionCount() const; - std::string GetSectionName(unsigned int idx) const; + // Enumerate included script sections + unsigned int GetSectionCount() const; + std::string GetSectionName(unsigned int idx) const; #if AS_PROCESS_METADATA == 1 - // Get metadata declared for classes, interfaces, and enums - std::vector GetMetadataForType(int typeId); + // Get metadata declared for classes, interfaces, and enums + std::vector GetMetadataForType(int typeId); - // Get metadata declared for functions - std::vector GetMetadataForFunc(asIScriptFunction *func); + // Get metadata declared for functions + std::vector GetMetadataForFunc(asIScriptFunction *func); - // Get metadata declared for global variables - std::vector GetMetadataForVar(int varIdx); + // Get metadata declared for global variables + std::vector GetMetadataForVar(int varIdx); - // Get metadata declared for class variables - std::vector GetMetadataForTypeProperty(int typeId, int varIdx); + // Get metadata declared for class variables + std::vector GetMetadataForTypeProperty(int typeId, int varIdx); - // Get metadata declared for class methods - std::vector GetMetadataForTypeMethod(int typeId, asIScriptFunction *method); + // Get metadata declared for class methods + std::vector GetMetadataForTypeMethod(int typeId, asIScriptFunction *method); #endif protected: - void ClearAll(); - int Build(); - int ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset); - int LoadScriptSection(const char *filename); - bool IncludeIfNotAlreadyIncluded(const char *filename); + void ClearAll(); + int Build(); + int ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset); + int LoadScriptSection(const char *filename); + bool IncludeIfNotAlreadyIncluded(const char *filename); - int SkipStatement(int pos); + int SkipStatement(int pos); - int ExcludeCode(int start); - void OverwriteCode(int start, int len); + int ExcludeCode(int start); + void OverwriteCode(int start, int len); - asIScriptEngine *engine; - asIScriptModule *module; - std::string modifiedScript; + asIScriptEngine *engine; + asIScriptModule *module; + std::string modifiedScript; - INCLUDECALLBACK_t includeCallback; - void *includeParam; + INCLUDECALLBACK_t includeCallback; + void *includeParam; - PRAGMACALLBACK_t pragmaCallback; - void *pragmaParam; + PRAGMACALLBACK_t pragmaCallback; + void *pragmaParam; #if AS_PROCESS_METADATA == 1 - int ExtractMetadata(int pos, std::vector &outMetadata); - int ExtractDeclaration(int pos, std::string &outName, std::string &outDeclaration, int &outType); - - enum METADATATYPE - { - MDT_TYPE = 1, - MDT_FUNC = 2, - MDT_VAR = 3, - MDT_VIRTPROP = 4, - MDT_FUNC_OR_VAR = 5 - }; - - // Temporary structure for storing metadata and declaration - struct SMetadataDecl - { - SMetadataDecl(std::vector m, std::string n, std::string d, int t, std::string c, std::string ns) : metadata(m), name(n), declaration(d), type(t), parentClass(c), nameSpace(ns) {} - std::vector metadata; - std::string name; - std::string declaration; - int type; - std::string parentClass; - std::string nameSpace; - }; - std::vector foundDeclarations; - std::string currentClass; - std::string currentNamespace; - - // Storage of metadata for global declarations - std::map > typeMetadataMap; - std::map > funcMetadataMap; - std::map > varMetadataMap; - - // Storage of metadata for class member declarations - struct SClassMetadata - { - SClassMetadata(const std::string& aName) : className(aName) {} - std::string className; - std::map > funcMetadataMap; - std::map > varMetadataMap; - }; - std::map classMetadataMap; + int ExtractMetadata(int pos, std::vector &outMetadata); + int ExtractDeclaration(int pos, std::string &outName, std::string &outDeclaration, int &outType); + + enum METADATATYPE + { + MDT_TYPE = 1, + MDT_FUNC = 2, + MDT_VAR = 3, + MDT_VIRTPROP = 4, + MDT_FUNC_OR_VAR = 5 + }; + + // Temporary structure for storing metadata and declaration + struct SMetadataDecl + { + SMetadataDecl(std::vector m, std::string n, std::string d, int t, std::string c, std::string ns) : metadata(m), name(n), declaration(d), type(t), parentClass(c), nameSpace(ns) {} + std::vector metadata; + std::string name; + std::string declaration; + int type; + std::string parentClass; + std::string nameSpace; + }; + std::vector foundDeclarations; + std::string currentClass; + std::string currentNamespace; + + // Storage of metadata for global declarations + std::map > typeMetadataMap; + std::map > funcMetadataMap; + std::map > varMetadataMap; + + // Storage of metadata for class member declarations + struct SClassMetadata + { + SClassMetadata(const std::string& aName) : className(aName) {} + std::string className; + std::map > funcMetadataMap; + std::map > varMetadataMap; + }; + std::map classMetadataMap; #endif #ifdef _WIN32 - // On Windows the filenames are case insensitive so the comparisons to - // avoid duplicate includes must also be case insensitive. True case insensitive - // is not easy as it must be language aware, but a simple implementation such - // as strcmpi should suffice in almost all cases. - // - // ref: http://www.gotw.ca/gotw/029.htm - // ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317761(v=vs.85).aspx - // ref: http://site.icu-project.org/ - - // TODO: Strings by default are treated as UTF8 encoded. If the application choses to - // use a different encoding, the comparison algorithm should be adjusted as well - - struct ci_less - { - bool operator()(const std::string &a, const std::string &b) const - { - return _stricmp(a.c_str(), b.c_str()) < 0; - } - }; - std::set includedScripts; + // On Windows the filenames are case insensitive so the comparisons to + // avoid duplicate includes must also be case insensitive. True case insensitive + // is not easy as it must be language aware, but a simple implementation such + // as strcmpi should suffice in almost all cases. + // + // ref: http://www.gotw.ca/gotw/029.htm + // ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317761(v=vs.85).aspx + // ref: http://site.icu-project.org/ + + // TODO: Strings by default are treated as UTF8 encoded. If the application choses to + // use a different encoding, the comparison algorithm should be adjusted as well + + struct ci_less + { + bool operator()(const std::string &a, const std::string &b) const + { + return _stricmp(a.c_str(), b.c_str()) < 0; + } + }; + std::set includedScripts; #else - std::set includedScripts; + std::set includedScripts; #endif - std::set definedWords; + std::set definedWords; }; END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scriptdictionary/scriptdictionary.cpp b/src/angelscript/add_on/scriptdictionary/scriptdictionary.cpp index 596ff172568..d3c64204b52 100644 --- a/src/angelscript/add_on/scriptdictionary/scriptdictionary.cpp +++ b/src/angelscript/add_on/scriptdictionary/scriptdictionary.cpp @@ -20,33 +20,33 @@ const asPWORD DICTIONARY_CACHE = 1003; // is created. struct SDictionaryCache { - asITypeInfo *dictType; - asITypeInfo *arrayType; - asITypeInfo *keyType; - - // This is called from RegisterScriptDictionary - static void Setup(asIScriptEngine *engine) - { - SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - if( cache == 0 ) - { - cache = new SDictionaryCache; - engine->SetUserData(cache, DICTIONARY_CACHE); - engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); - - cache->dictType = engine->GetTypeInfoByName("dictionary"); - cache->arrayType = engine->GetTypeInfoByDecl("array"); - cache->keyType = engine->GetTypeInfoByDecl("string"); - } - } - - // This is called from the engine when shutting down - static void Cleanup(asIScriptEngine *engine) - { - SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - if( cache ) - delete cache; - } + asITypeInfo *dictType; + asITypeInfo *arrayType; + asITypeInfo *keyType; + + // This is called from RegisterScriptDictionary + static void Setup(asIScriptEngine *engine) + { + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + if( cache == 0 ) + { + cache = new SDictionaryCache; + engine->SetUserData(cache, DICTIONARY_CACHE); + engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); + + cache->dictType = engine->GetTypeInfoByName("dictionary"); + cache->arrayType = engine->GetTypeInfoByDecl("array"); + cache->keyType = engine->GetTypeInfoByDecl("string"); + } + } + + // This is called from the engine when shutting down + static void Cleanup(asIScriptEngine *engine) + { + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + if( cache ) + delete cache; + } }; //-------------------------------------------------------------------------- @@ -54,386 +54,386 @@ struct SDictionaryCache CScriptDictionary *CScriptDictionary::Create(asIScriptEngine *engine) { - // Use the custom memory routine from AngelScript to allow application to better control how much memory is used - CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); - new(obj) CScriptDictionary(engine); - return obj; + // Use the custom memory routine from AngelScript to allow application to better control how much memory is used + CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); + new(obj) CScriptDictionary(engine); + return obj; } CScriptDictionary *CScriptDictionary::Create(asBYTE *buffer) { - // Use the custom memory routine from AngelScript to allow application to better control how much memory is used - CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); - new(obj) CScriptDictionary(buffer); - return obj; + // Use the custom memory routine from AngelScript to allow application to better control how much memory is used + CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); + new(obj) CScriptDictionary(buffer); + return obj; } CScriptDictionary::CScriptDictionary(asIScriptEngine *engine) { - Init(engine); + Init(engine); } void CScriptDictionary::Init(asIScriptEngine *e) { - // We start with one reference - refCount = 1; - gcFlag = false; + // We start with one reference + refCount = 1; + gcFlag = false; - // Keep a reference to the engine for as long as we live - // We don't increment the reference counter, because the - // engine will hold a pointer to the object in the GC. - engine = e; + // Keep a reference to the engine for as long as we live + // We don't increment the reference counter, because the + // engine will hold a pointer to the object in the GC. + engine = e; - // The dictionary object type is cached to avoid dynamically parsing it each time - SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + // The dictionary object type is cached to avoid dynamically parsing it each time + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - // Notify the garbage collector of this object - engine->NotifyGarbageCollectorOfNewObject(this, cache->dictType); + // Notify the garbage collector of this object + engine->NotifyGarbageCollectorOfNewObject(this, cache->dictType); } CScriptDictionary::CScriptDictionary(asBYTE *buffer) { - // This constructor will always be called from a script - // so we can get the engine from the active context - asIScriptContext *ctx = asGetActiveContext(); - Init(ctx->GetEngine()); - - // Determine if the dictionary key type is registered as reference type or value type - SDictionaryCache& cache = *reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - bool keyAsRef = cache.keyType->GetFlags() & asOBJ_REF ? true : false; - - // Initialize the dictionary from the buffer - asUINT length = *(asUINT*)buffer; - buffer += 4; - - while( length-- ) - { - // Align the buffer pointer on a 4 byte boundary in - // case previous value was smaller than 4 bytes - if( asPWORD(buffer) & 0x3 ) - buffer += 4 - (asPWORD(buffer) & 0x3); - - // Get the name value pair from the buffer and insert it in the dictionary - dictKey_t name; - if (keyAsRef) - { - name = **(dictKey_t**)buffer; - buffer += sizeof(dictKey_t*); - } - else - { - name = *(dictKey_t*)buffer; - buffer += sizeof(dictKey_t); - } - - // Get the type id of the value - int typeId = *(int*)buffer; - buffer += sizeof(int); - - // Depending on the type id, the value will inline in the buffer or a pointer - void *ref = (void*)buffer; - - if( typeId >= asTYPEID_INT8 && typeId <= asTYPEID_DOUBLE ) - { - // Convert primitive values to either int64 or double, so we can use the overloaded Set methods - asINT64 i64; - double d; - switch( typeId ) - { - case asTYPEID_INT8: i64 = *(char*) ref; break; - case asTYPEID_INT16: i64 = *(short*) ref; break; - case asTYPEID_INT32: i64 = *(int*) ref; break; - case asTYPEID_INT64: i64 = *(asINT64*) ref; break; - case asTYPEID_UINT8: i64 = *(unsigned char*) ref; break; - case asTYPEID_UINT16: i64 = *(unsigned short*)ref; break; - case asTYPEID_UINT32: i64 = *(unsigned int*) ref; break; - case asTYPEID_UINT64: i64 = *(asINT64*) ref; break; - case asTYPEID_FLOAT: d = *(float*) ref; break; - case asTYPEID_DOUBLE: d = *(double*) ref; break; - } - - if( typeId >= asTYPEID_FLOAT ) - Set(name, d); - else - Set(name, i64); - } - else - { - if( (typeId & asTYPEID_MASK_OBJECT) && - !(typeId & asTYPEID_OBJHANDLE) && - (engine->GetTypeInfoById(typeId)->GetFlags() & asOBJ_REF) ) - { - // Dereference the pointer to get the reference to the actual object - ref = *(void**)ref; - } - - Set(name, ref, typeId); - } - - // Advance the buffer pointer with the size of the value - if( typeId & asTYPEID_MASK_OBJECT ) - { - asITypeInfo *ti = engine->GetTypeInfoById(typeId); - if( ti->GetFlags() & asOBJ_VALUE ) - buffer += ti->GetSize(); - else - buffer += sizeof(void*); - } - else if( typeId == 0 ) - { - // null pointer - buffer += sizeof(void*); - } - else - { - buffer += engine->GetSizeOfPrimitiveType(typeId); - } - } + // This constructor will always be called from a script + // so we can get the engine from the active context + asIScriptContext *ctx = asGetActiveContext(); + Init(ctx->GetEngine()); + + // Determine if the dictionary key type is registered as reference type or value type + SDictionaryCache& cache = *reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + bool keyAsRef = cache.keyType->GetFlags() & asOBJ_REF ? true : false; + + // Initialize the dictionary from the buffer + asUINT length = *(asUINT*)buffer; + buffer += 4; + + while( length-- ) + { + // Align the buffer pointer on a 4 byte boundary in + // case previous value was smaller than 4 bytes + if( asPWORD(buffer) & 0x3 ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + // Get the name value pair from the buffer and insert it in the dictionary + dictKey_t name; + if (keyAsRef) + { + name = **(dictKey_t**)buffer; + buffer += sizeof(dictKey_t*); + } + else + { + name = *(dictKey_t*)buffer; + buffer += sizeof(dictKey_t); + } + + // Get the type id of the value + int typeId = *(int*)buffer; + buffer += sizeof(int); + + // Depending on the type id, the value will inline in the buffer or a pointer + void *ref = (void*)buffer; + + if( typeId >= asTYPEID_INT8 && typeId <= asTYPEID_DOUBLE ) + { + // Convert primitive values to either int64 or double, so we can use the overloaded Set methods + asINT64 i64; + double d; + switch( typeId ) + { + case asTYPEID_INT8: i64 = *(char*) ref; break; + case asTYPEID_INT16: i64 = *(short*) ref; break; + case asTYPEID_INT32: i64 = *(int*) ref; break; + case asTYPEID_INT64: i64 = *(asINT64*) ref; break; + case asTYPEID_UINT8: i64 = *(unsigned char*) ref; break; + case asTYPEID_UINT16: i64 = *(unsigned short*)ref; break; + case asTYPEID_UINT32: i64 = *(unsigned int*) ref; break; + case asTYPEID_UINT64: i64 = *(asINT64*) ref; break; + case asTYPEID_FLOAT: d = *(float*) ref; break; + case asTYPEID_DOUBLE: d = *(double*) ref; break; + } + + if( typeId >= asTYPEID_FLOAT ) + Set(name, d); + else + Set(name, i64); + } + else + { + if( (typeId & asTYPEID_MASK_OBJECT) && + !(typeId & asTYPEID_OBJHANDLE) && + (engine->GetTypeInfoById(typeId)->GetFlags() & asOBJ_REF) ) + { + // Dereference the pointer to get the reference to the actual object + ref = *(void**)ref; + } + + Set(name, ref, typeId); + } + + // Advance the buffer pointer with the size of the value + if( typeId & asTYPEID_MASK_OBJECT ) + { + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti->GetFlags() & asOBJ_VALUE ) + buffer += ti->GetSize(); + else + buffer += sizeof(void*); + } + else if( typeId == 0 ) + { + // null pointer + buffer += sizeof(void*); + } + else + { + buffer += engine->GetSizeOfPrimitiveType(typeId); + } + } } CScriptDictionary::~CScriptDictionary() { - // Delete all keys and values - DeleteAll(); + // Delete all keys and values + DeleteAll(); } void CScriptDictionary::AddRef() const { - // We need to clear the GC flag - gcFlag = false; - asAtomicInc(refCount); + // We need to clear the GC flag + gcFlag = false; + asAtomicInc(refCount); } void CScriptDictionary::Release() const { - // We need to clear the GC flag - gcFlag = false; - if( asAtomicDec(refCount) == 0 ) - { - this->~CScriptDictionary(); - asFreeMem(const_cast(this)); - } + // We need to clear the GC flag + gcFlag = false; + if( asAtomicDec(refCount) == 0 ) + { + this->~CScriptDictionary(); + asFreeMem(const_cast(this)); + } } int CScriptDictionary::GetRefCount() { - return refCount; + return refCount; } void CScriptDictionary::SetGCFlag() { - gcFlag = true; + gcFlag = true; } bool CScriptDictionary::GetGCFlag() { - return gcFlag; + return gcFlag; } void CScriptDictionary::EnumReferences(asIScriptEngine *inEngine) { - // TODO: If garbage collection can be done from a separate thread, then this method must be - // protected so that it doesn't get lost during the iteration if the dictionary is modified - - // Call the gc enum callback for each of the objects - dictMap_t::iterator it; - for( it = dict.begin(); it != dict.end(); it++ ) - { - if (it->second.m_typeId & asTYPEID_MASK_OBJECT) - { - asITypeInfo *subType = engine->GetTypeInfoById(it->second.m_typeId); - if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) - { - // For value types we need to forward the enum callback - // to the object so it can decide what to do - engine->ForwardGCEnumReferences(it->second.m_valueObj, subType); - } - else - { - // For others, simply notify the GC about the reference - inEngine->GCEnumCallback(it->second.m_valueObj); - } - } - } + // TODO: If garbage collection can be done from a separate thread, then this method must be + // protected so that it doesn't get lost during the iteration if the dictionary is modified + + // Call the gc enum callback for each of the objects + dictMap_t::iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + { + if (it->second.m_typeId & asTYPEID_MASK_OBJECT) + { + asITypeInfo *subType = engine->GetTypeInfoById(it->second.m_typeId); + if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + engine->ForwardGCEnumReferences(it->second.m_valueObj, subType); + } + else + { + // For others, simply notify the GC about the reference + inEngine->GCEnumCallback(it->second.m_valueObj); + } + } + } } void CScriptDictionary::ReleaseAllReferences(asIScriptEngine * /*engine*/) { - // We're being told to release all references in - // order to break circular references for dead objects - DeleteAll(); + // We're being told to release all references in + // order to break circular references for dead objects + DeleteAll(); } CScriptDictionary &CScriptDictionary::operator =(const CScriptDictionary &other) { - // Clear everything we had before - DeleteAll(); + // Clear everything we had before + DeleteAll(); - // Do a shallow copy of the dictionary - dictMap_t::const_iterator it; - for( it = other.dict.begin(); it != other.dict.end(); it++ ) - { - if( it->second.m_typeId & asTYPEID_OBJHANDLE ) - Set(it->first, (void*)&it->second.m_valueObj, it->second.m_typeId); - else if( it->second.m_typeId & asTYPEID_MASK_OBJECT ) - Set(it->first, (void*)it->second.m_valueObj, it->second.m_typeId); - else - Set(it->first, (void*)&it->second.m_valueInt, it->second.m_typeId); - } + // Do a shallow copy of the dictionary + dictMap_t::const_iterator it; + for( it = other.dict.begin(); it != other.dict.end(); it++ ) + { + if( it->second.m_typeId & asTYPEID_OBJHANDLE ) + Set(it->first, (void*)&it->second.m_valueObj, it->second.m_typeId); + else if( it->second.m_typeId & asTYPEID_MASK_OBJECT ) + Set(it->first, (void*)it->second.m_valueObj, it->second.m_typeId); + else + Set(it->first, (void*)&it->second.m_valueInt, it->second.m_typeId); + } - return *this; + return *this; } CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) { - // Return the existing value if it exists, else insert an empty value - return &dict[key]; + // Return the existing value if it exists, else insert an empty value + return &dict[key]; } const CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) const { - // Return the existing value if it exists - dictMap_t::const_iterator it; - it = dict.find(key); - if( it != dict.end() ) - return &it->second; + // Return the existing value if it exists + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return &it->second; - // Else raise an exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Invalid access to non-existing value"); + // Else raise an exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Invalid access to non-existing value"); - return 0; + return 0; } void CScriptDictionary::Set(const dictKey_t &key, void *value, int typeId) { - dictMap_t::iterator it; - it = dict.find(key); - if( it == dict.end() ) - it = dict.insert(dictMap_t::value_type(key, CScriptDictValue())).first; + dictMap_t::iterator it; + it = dict.find(key); + if( it == dict.end() ) + it = dict.insert(dictMap_t::value_type(key, CScriptDictValue())).first; - it->second.Set(engine, value, typeId); + it->second.Set(engine, value, typeId); } // This overloaded method is implemented so that all integer and // unsigned integers types will be stored in the dictionary as int64 // through implicit conversions. This simplifies the management of the -// numeric types when the script retrieves the stored value using a +// numeric types when the script retrieves the stored value using a // different type. void CScriptDictionary::Set(const dictKey_t &key, const asINT64 &value) { - Set(key, const_cast(&value), asTYPEID_INT64); + Set(key, const_cast(&value), asTYPEID_INT64); } -// This overloaded method is implemented so that all floating point types -// will be stored in the dictionary as double through implicit conversions. -// This simplifies the management of the numeric types when the script +// This overloaded method is implemented so that all floating point types +// will be stored in the dictionary as double through implicit conversions. +// This simplifies the management of the numeric types when the script // retrieves the stored value using a different type. void CScriptDictionary::Set(const dictKey_t &key, const double &value) { - Set(key, const_cast(&value), asTYPEID_DOUBLE); + Set(key, const_cast(&value), asTYPEID_DOUBLE); } // Returns true if the value was successfully retrieved bool CScriptDictionary::Get(const dictKey_t &key, void *value, int typeId) const { - dictMap_t::const_iterator it; - it = dict.find(key); - if( it != dict.end() ) - return it->second.Get(engine, value, typeId); + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return it->second.Get(engine, value, typeId); - // AngelScript has already initialized the value with a default value, - // so we don't have to do anything if we don't find the element, or if - // the element is incompatible with the requested type. + // AngelScript has already initialized the value with a default value, + // so we don't have to do anything if we don't find the element, or if + // the element is incompatible with the requested type. - return false; + return false; } // Returns the type id of the stored value int CScriptDictionary::GetTypeId(const dictKey_t &key) const { - dictMap_t::const_iterator it; - it = dict.find(key); - if( it != dict.end() ) - return it->second.m_typeId; + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return it->second.m_typeId; - return -1; + return -1; } bool CScriptDictionary::Get(const dictKey_t &key, asINT64 &value) const { - return Get(key, &value, asTYPEID_INT64); + return Get(key, &value, asTYPEID_INT64); } bool CScriptDictionary::Get(const dictKey_t &key, double &value) const { - return Get(key, &value, asTYPEID_DOUBLE); + return Get(key, &value, asTYPEID_DOUBLE); } bool CScriptDictionary::Exists(const dictKey_t &key) const { - dictMap_t::const_iterator it; - it = dict.find(key); - if( it != dict.end() ) - return true; + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return true; - return false; + return false; } bool CScriptDictionary::IsEmpty() const { - if( dict.size() == 0 ) - return true; + if( dict.size() == 0 ) + return true; - return false; + return false; } asUINT CScriptDictionary::GetSize() const { - return asUINT(dict.size()); + return asUINT(dict.size()); } bool CScriptDictionary::Delete(const dictKey_t &key) { - dictMap_t::iterator it; - it = dict.find(key); - if( it != dict.end() ) - { - it->second.FreeValue(engine); - dict.erase(it); - return true; - } + dictMap_t::iterator it; + it = dict.find(key); + if( it != dict.end() ) + { + it->second.FreeValue(engine); + dict.erase(it); + return true; + } - return false; + return false; } void CScriptDictionary::DeleteAll() { - dictMap_t::iterator it; - for( it = dict.begin(); it != dict.end(); it++ ) - it->second.FreeValue(engine); + dictMap_t::iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + it->second.FreeValue(engine); - dict.clear(); + dict.clear(); } CScriptArray* CScriptDictionary::GetKeys() const { - // Retrieve the object type for the array from the cache - SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - asITypeInfo *ti = cache->arrayType; + // Retrieve the object type for the array from the cache + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + asITypeInfo *ti = cache->arrayType; - // Create the array object - CScriptArray *array = CScriptArray::Create(ti, asUINT(dict.size())); - long current = -1; - dictMap_t::const_iterator it; - for( it = dict.begin(); it != dict.end(); it++ ) - { - current++; - *(dictKey_t*)array->At(current) = it->first; - } + // Create the array object + CScriptArray *array = CScriptArray::Create(ti, asUINT(dict.size())); + long current = -1; + dictMap_t::const_iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + { + current++; + *(dictKey_t*)array->At(current) = it->first; + } - return array; + return array; } //-------------------------------------------------------------------------- @@ -441,170 +441,170 @@ CScriptArray* CScriptDictionary::GetKeys() const void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen) { - *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(gen->GetEngine()); + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(gen->GetEngine()); } void ScriptDictionaryListFactory_Generic(asIScriptGeneric *gen) { - asBYTE *buffer = (asBYTE*)gen->GetArgAddress(0); - *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(buffer); + asBYTE *buffer = (asBYTE*)gen->GetArgAddress(0); + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(buffer); } void ScriptDictionaryAddRef_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dict->AddRef(); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->AddRef(); } void ScriptDictionaryRelease_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dict->Release(); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->Release(); } void ScriptDictionaryAssign_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - CScriptDictionary *other = *(CScriptDictionary**)gen->GetAddressOfArg(0); - *dict = *other; - *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = dict; + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + CScriptDictionary *other = *(CScriptDictionary**)gen->GetAddressOfArg(0); + *dict = *other; + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = dict; } void ScriptDictionarySet_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - int typeId = gen->GetArgTypeId(1); - dict->Set(*key, ref, typeId); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + int typeId = gen->GetArgTypeId(1); + dict->Set(*key, ref, typeId); } void ScriptDictionarySetInt_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - dict->Set(*key, *(asINT64*)ref); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + dict->Set(*key, *(asINT64*)ref); } void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - dict->Set(*key, *(double*)ref); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + dict->Set(*key, *(double*)ref); } void ScriptDictionaryGet_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - int typeId = gen->GetArgTypeId(1); - *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + int typeId = gen->GetArgTypeId(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId); } void ScriptDictionaryGetInt_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref); } void ScriptDictionaryGetFlt_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref); } void ScriptDictionaryExists_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - bool ret = dict->Exists(*key); - *(bool*)gen->GetAddressOfReturnLocation() = ret; + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + bool ret = dict->Exists(*key); + *(bool*)gen->GetAddressOfReturnLocation() = ret; } void ScriptDictionaryIsEmpty_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - bool ret = dict->IsEmpty(); - *(bool*)gen->GetAddressOfReturnLocation() = ret; + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + bool ret = dict->IsEmpty(); + *(bool*)gen->GetAddressOfReturnLocation() = ret; } void ScriptDictionaryGetSize_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - asUINT ret = dict->GetSize(); - *(asUINT*)gen->GetAddressOfReturnLocation() = ret; + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + asUINT ret = dict->GetSize(); + *(asUINT*)gen->GetAddressOfReturnLocation() = ret; } void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - *(bool*)gen->GetAddressOfReturnLocation() = dict->Delete(*key); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Delete(*key); } void ScriptDictionaryDeleteAll_Generic(asIScriptGeneric *gen) { - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dict->DeleteAll(); + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->DeleteAll(); } static void ScriptDictionaryGetRefCount_Generic(asIScriptGeneric *gen) { - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); } static void ScriptDictionarySetGCFlag_Generic(asIScriptGeneric *gen) { - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - self->SetGCFlag(); + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + self->SetGCFlag(); } static void ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric *gen) { - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag(); + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag(); } static void ScriptDictionaryEnumReferences_Generic(asIScriptGeneric *gen) { - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); } static void ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric *gen) { - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllReferences(engine); + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllReferences(engine); } static void CScriptDictionaryGetKeys_Generic(asIScriptGeneric *gen) { - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - *(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys(); + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys(); } static void CScriptDictionary_opIndex_Generic(asIScriptGeneric *gen) { - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); } static void CScriptDictionary_opIndex_const_Generic(asIScriptGeneric *gen) { - const CScriptDictionary *self = (const CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - *(const CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); + const CScriptDictionary *self = (const CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(const CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); } @@ -613,373 +613,373 @@ static void CScriptDictionary_opIndex_const_Generic(asIScriptGeneric *gen) CScriptDictValue::CScriptDictValue() { - m_valueObj = 0; - m_typeId = 0; + m_valueObj = 0; + m_typeId = 0; } CScriptDictValue::CScriptDictValue(asIScriptEngine *engine, void *value, int typeId) { - m_valueObj = 0; - m_typeId = 0; - Set(engine, value, typeId); + m_valueObj = 0; + m_typeId = 0; + Set(engine, value, typeId); } CScriptDictValue::~CScriptDictValue() { - if (m_valueObj && m_typeId) - { - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - FreeValue(ctx->GetEngine()); - else - { - // Must not hold an object when destroyed, as then the object will never be freed - assert((m_typeId & asTYPEID_MASK_OBJECT) == 0); - } - } + if (m_valueObj && m_typeId) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + FreeValue(ctx->GetEngine()); + else + { + // Must not hold an object when destroyed, as then the object will never be freed + assert((m_typeId & asTYPEID_MASK_OBJECT) == 0); + } + } } void CScriptDictValue::FreeValue(asIScriptEngine *engine) { - // If it is a handle or a ref counted object, call release - if( m_typeId & asTYPEID_MASK_OBJECT ) - { - // Let the engine release the object - engine->ReleaseScriptObject(m_valueObj, engine->GetTypeInfoById(m_typeId)); - m_valueObj = 0; - m_typeId = 0; - } + // If it is a handle or a ref counted object, call release + if( m_typeId & asTYPEID_MASK_OBJECT ) + { + // Let the engine release the object + engine->ReleaseScriptObject(m_valueObj, engine->GetTypeInfoById(m_typeId)); + m_valueObj = 0; + m_typeId = 0; + } - // For primitives, there's nothing to do + // For primitives, there's nothing to do } void CScriptDictValue::EnumReferences(asIScriptEngine *inEngine) { - // If we're holding a reference, we'll notify the garbage collector of it - if (m_valueObj) - inEngine->GCEnumCallback(m_valueObj); + // If we're holding a reference, we'll notify the garbage collector of it + if (m_valueObj) + inEngine->GCEnumCallback(m_valueObj); - // The object type itself is also garbage collected - if (m_typeId) - inEngine->GCEnumCallback(inEngine->GetTypeInfoById(m_typeId)); + // The object type itself is also garbage collected + if (m_typeId) + inEngine->GCEnumCallback(inEngine->GetTypeInfoById(m_typeId)); } void CScriptDictValue::Set(asIScriptEngine *engine, void *value, int typeId) { - FreeValue(engine); - - m_typeId = typeId; - if( typeId & asTYPEID_OBJHANDLE ) - { - // We're receiving a reference to the handle, so we need to dereference it - m_valueObj = *(void**)value; - engine->AddRefScriptObject(m_valueObj, engine->GetTypeInfoById(typeId)); - } - else if( typeId & asTYPEID_MASK_OBJECT ) - { - // Create a copy of the object - m_valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId)); - if( m_valueObj == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Cannot create copy of object"); - } - } - else - { - // Copy the primitive value - // We receive a pointer to the value. - int size = engine->GetSizeOfPrimitiveType(typeId); - memcpy(&m_valueInt, value, size); - } + FreeValue(engine); + + m_typeId = typeId; + if( typeId & asTYPEID_OBJHANDLE ) + { + // We're receiving a reference to the handle, so we need to dereference it + m_valueObj = *(void**)value; + engine->AddRefScriptObject(m_valueObj, engine->GetTypeInfoById(typeId)); + } + else if( typeId & asTYPEID_MASK_OBJECT ) + { + // Create a copy of the object + m_valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId)); + if( m_valueObj == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Cannot create copy of object"); + } + } + else + { + // Copy the primitive value + // We receive a pointer to the value. + int size = engine->GetSizeOfPrimitiveType(typeId); + memcpy(&m_valueInt, value, size); + } } void CScriptDictValue::Set(asIScriptEngine *engine, CScriptDictValue &value) { - if( value.m_typeId & asTYPEID_OBJHANDLE ) - Set(engine, (void*)&value.m_valueObj, value.m_typeId); - else if( value.m_typeId & asTYPEID_MASK_OBJECT ) - Set(engine, (void*)value.m_valueObj, value.m_typeId); - else - Set(engine, (void*)&value.m_valueInt, value.m_typeId); + if( value.m_typeId & asTYPEID_OBJHANDLE ) + Set(engine, (void*)&value.m_valueObj, value.m_typeId); + else if( value.m_typeId & asTYPEID_MASK_OBJECT ) + Set(engine, (void*)value.m_valueObj, value.m_typeId); + else + Set(engine, (void*)&value.m_valueInt, value.m_typeId); } // This overloaded method is implemented so that all integer and // unsigned integers types will be stored in the dictionary as int64 // through implicit conversions. This simplifies the management of the -// numeric types when the script retrieves the stored value using a +// numeric types when the script retrieves the stored value using a // different type. void CScriptDictValue::Set(asIScriptEngine *engine, const asINT64 &value) { - Set(engine, const_cast(&value), asTYPEID_INT64); + Set(engine, const_cast(&value), asTYPEID_INT64); } -// This overloaded method is implemented so that all floating point types -// will be stored in the dictionary as double through implicit conversions. -// This simplifies the management of the numeric types when the script +// This overloaded method is implemented so that all floating point types +// will be stored in the dictionary as double through implicit conversions. +// This simplifies the management of the numeric types when the script // retrieves the stored value using a different type. void CScriptDictValue::Set(asIScriptEngine *engine, const double &value) { - Set(engine, const_cast(&value), asTYPEID_DOUBLE); + Set(engine, const_cast(&value), asTYPEID_DOUBLE); } bool CScriptDictValue::Get(asIScriptEngine *engine, void *value, int typeId) const { - // Return the value - if( typeId & asTYPEID_OBJHANDLE ) - { - // A handle can be retrieved if the stored type is a handle of same or compatible type - // or if the stored type is an object that implements the interface that the handle refer to. - if( (m_typeId & asTYPEID_MASK_OBJECT) ) - { - // Don't allow the get if the stored handle is to a const, but the desired handle is not - if( (m_typeId & asTYPEID_HANDLETOCONST) && !(typeId & asTYPEID_HANDLETOCONST) ) - return false; - - // RefCastObject will increment the refcount if successful - engine->RefCastObject(m_valueObj, engine->GetTypeInfoById(m_typeId), engine->GetTypeInfoById(typeId), reinterpret_cast(value)); - - return true; - } - } - else if( typeId & asTYPEID_MASK_OBJECT ) - { - // Verify that the copy can be made - bool isCompatible = false; - - // Allow a handle to be value assigned if the wanted type is not a handle - if( (m_typeId & ~(asTYPEID_OBJHANDLE | asTYPEID_HANDLETOCONST) ) == typeId && m_valueObj != 0 ) - isCompatible = true; - - // Copy the object into the given reference - if( isCompatible ) - { - engine->AssignScriptObject(value, m_valueObj, engine->GetTypeInfoById(typeId)); - - return true; - } - } - else - { - if( m_typeId == typeId ) - { - int size = engine->GetSizeOfPrimitiveType(typeId); - memcpy(value, &m_valueInt, size); - return true; - } - - // We know all numbers are stored as either int64 or double, since we register overloaded functions for those - // Only bool and enums needs to be treated separately - if( typeId == asTYPEID_DOUBLE ) - { - if( m_typeId == asTYPEID_INT64 ) - *(double*)value = double(m_valueInt); - else if (m_typeId == asTYPEID_BOOL) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - char localValue; - memcpy(&localValue, &m_valueInt, sizeof(char)); - *(double*)value = localValue ? 1.0 : 0.0; - } - else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - int localValue; - memcpy(&localValue, &m_valueInt, sizeof(int)); - *(double*)value = double(localValue); // enums are 32bit - } - else - { - // The stored type is an object - // TODO: Check if the object has a conversion operator to a primitive value - *(double*)value = 0; - return false; - } - return true; - } - else if( typeId == asTYPEID_INT64 ) - { - if( m_typeId == asTYPEID_DOUBLE ) - *(asINT64*)value = asINT64(m_valueFlt); - else if (m_typeId == asTYPEID_BOOL) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - char localValue; - memcpy(&localValue, &m_valueInt, sizeof(char)); - *(asINT64*)value = localValue ? 1 : 0; - } - else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - int localValue; - memcpy(&localValue, &m_valueInt, sizeof(int)); - *(asINT64*)value = localValue; // enums are 32bit - } - else - { - // The stored type is an object - // TODO: Check if the object has a conversion operator to a primitive value - *(asINT64*)value = 0; - return false; - } - return true; - } - else if( typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0 ) - { - // The desired type is an enum. These are always 32bit integers - if( m_typeId == asTYPEID_DOUBLE ) - *(int*)value = int(m_valueFlt); - else if( m_typeId == asTYPEID_INT64 ) - *(int*)value = int(m_valueInt); - else if (m_typeId == asTYPEID_BOOL) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - char localValue; - memcpy(&localValue, &m_valueInt, sizeof(char)); - *(int*)value = localValue ? 1 : 0; - } - else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - int localValue; - memcpy(&localValue, &m_valueInt, sizeof(int)); - *(int*)value = localValue; // enums are 32bit - } - else - { - // The stored type is an object - // TODO: Check if the object has a conversion operator to a primitive value - *(int*)value = 0; - return false; - } - return true; - } - else if( typeId == asTYPEID_BOOL ) - { - if (m_typeId & asTYPEID_OBJHANDLE) - { - // TODO: Check if the object has a conversion operator to a primitive value - *(bool*)value = m_valueObj ? true : false; - } - else if( m_typeId & asTYPEID_MASK_OBJECT ) - { - // TODO: Check if the object has a conversion operator to a primitive value - *(bool*)value = true; - } - else - { - // Compare only the bytes that were actually set - asQWORD zero = 0; - int size = engine->GetSizeOfPrimitiveType(m_typeId); - *(bool*)value = memcmp(&m_valueInt, &zero, size) == 0 ? false : true; - } - return true; - } - } - - // It was not possible to retrieve the value using the desired typeId - return false; + // Return the value + if( typeId & asTYPEID_OBJHANDLE ) + { + // A handle can be retrieved if the stored type is a handle of same or compatible type + // or if the stored type is an object that implements the interface that the handle refer to. + if( (m_typeId & asTYPEID_MASK_OBJECT) ) + { + // Don't allow the get if the stored handle is to a const, but the desired handle is not + if( (m_typeId & asTYPEID_HANDLETOCONST) && !(typeId & asTYPEID_HANDLETOCONST) ) + return false; + + // RefCastObject will increment the refcount if successful + engine->RefCastObject(m_valueObj, engine->GetTypeInfoById(m_typeId), engine->GetTypeInfoById(typeId), reinterpret_cast(value)); + + return true; + } + } + else if( typeId & asTYPEID_MASK_OBJECT ) + { + // Verify that the copy can be made + bool isCompatible = false; + + // Allow a handle to be value assigned if the wanted type is not a handle + if( (m_typeId & ~(asTYPEID_OBJHANDLE | asTYPEID_HANDLETOCONST) ) == typeId && m_valueObj != 0 ) + isCompatible = true; + + // Copy the object into the given reference + if( isCompatible ) + { + engine->AssignScriptObject(value, m_valueObj, engine->GetTypeInfoById(typeId)); + + return true; + } + } + else + { + if( m_typeId == typeId ) + { + int size = engine->GetSizeOfPrimitiveType(typeId); + memcpy(value, &m_valueInt, size); + return true; + } + + // We know all numbers are stored as either int64 or double, since we register overloaded functions for those + // Only bool and enums needs to be treated separately + if( typeId == asTYPEID_DOUBLE ) + { + if( m_typeId == asTYPEID_INT64 ) + *(double*)value = double(m_valueInt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(double*)value = localValue ? 1.0 : 0.0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(double*)value = double(localValue); // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(double*)value = 0; + return false; + } + return true; + } + else if( typeId == asTYPEID_INT64 ) + { + if( m_typeId == asTYPEID_DOUBLE ) + *(asINT64*)value = asINT64(m_valueFlt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(asINT64*)value = localValue ? 1 : 0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(asINT64*)value = localValue; // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(asINT64*)value = 0; + return false; + } + return true; + } + else if( typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0 ) + { + // The desired type is an enum. These are always 32bit integers + if( m_typeId == asTYPEID_DOUBLE ) + *(int*)value = int(m_valueFlt); + else if( m_typeId == asTYPEID_INT64 ) + *(int*)value = int(m_valueInt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(int*)value = localValue ? 1 : 0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(int*)value = localValue; // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(int*)value = 0; + return false; + } + return true; + } + else if( typeId == asTYPEID_BOOL ) + { + if (m_typeId & asTYPEID_OBJHANDLE) + { + // TODO: Check if the object has a conversion operator to a primitive value + *(bool*)value = m_valueObj ? true : false; + } + else if( m_typeId & asTYPEID_MASK_OBJECT ) + { + // TODO: Check if the object has a conversion operator to a primitive value + *(bool*)value = true; + } + else + { + // Compare only the bytes that were actually set + asQWORD zero = 0; + int size = engine->GetSizeOfPrimitiveType(m_typeId); + *(bool*)value = memcmp(&m_valueInt, &zero, size) == 0 ? false : true; + } + return true; + } + } + + // It was not possible to retrieve the value using the desired typeId + return false; } const void * CScriptDictValue::GetAddressOfValue() const { - if( (m_typeId & asTYPEID_MASK_OBJECT) && !(m_typeId & asTYPEID_OBJHANDLE) ) - { - // Return the address to the object directly - return m_valueObj; - } - - // Return the address of the primitive or the pointer to the object - return reinterpret_cast(&m_valueObj); + if( (m_typeId & asTYPEID_MASK_OBJECT) && !(m_typeId & asTYPEID_OBJHANDLE) ) + { + // Return the address to the object directly + return m_valueObj; + } + + // Return the address of the primitive or the pointer to the object + return reinterpret_cast(&m_valueObj); } bool CScriptDictValue::Get(asIScriptEngine *engine, asINT64 &value) const { - return Get(engine, &value, asTYPEID_INT64); + return Get(engine, &value, asTYPEID_INT64); } bool CScriptDictValue::Get(asIScriptEngine *engine, double &value) const { - return Get(engine, &value, asTYPEID_DOUBLE); + return Get(engine, &value, asTYPEID_DOUBLE); } int CScriptDictValue::GetTypeId() const { - return m_typeId; + return m_typeId; } static void CScriptDictValue_Construct(void *mem) { - new(mem) CScriptDictValue(); + new(mem) CScriptDictValue(); } static void CScriptDictValue_Destruct(CScriptDictValue *obj) { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - asIScriptEngine *engine = ctx->GetEngine(); - obj->FreeValue(engine); - } - obj->~CScriptDictValue(); + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->FreeValue(engine); + } + obj->~CScriptDictValue(); } static CScriptDictValue &CScriptDictValue_opAssign(void *ref, int typeId, CScriptDictValue *obj) { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - asIScriptEngine *engine = ctx->GetEngine(); - obj->Set(engine, ref, typeId); - } - return *obj; + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Set(engine, ref, typeId); + } + return *obj; } static CScriptDictValue &CScriptDictValue_opAssign(const CScriptDictValue &other, CScriptDictValue *obj) { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - asIScriptEngine *engine = ctx->GetEngine(); - obj->Set(engine, const_cast(other)); - } + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Set(engine, const_cast(other)); + } - return *obj; + return *obj; } static CScriptDictValue &CScriptDictValue_opAssign(double val, CScriptDictValue *obj) { - return CScriptDictValue_opAssign(&val, asTYPEID_DOUBLE, obj); + return CScriptDictValue_opAssign(&val, asTYPEID_DOUBLE, obj); } static CScriptDictValue &CScriptDictValue_opAssign(asINT64 val, CScriptDictValue *obj) { - return CScriptDictValue_opAssign(&val, asTYPEID_INT64, obj); + return CScriptDictValue_opAssign(&val, asTYPEID_INT64, obj); } static void CScriptDictValue_opCast(void *ref, int typeId, CScriptDictValue *obj) { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - asIScriptEngine *engine = ctx->GetEngine(); - obj->Get(engine, ref, typeId); - } + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Get(engine, ref, typeId); + } } static asINT64 CScriptDictValue_opConvInt(CScriptDictValue *obj) { - asINT64 value; - CScriptDictValue_opCast(&value, asTYPEID_INT64, obj); - return value; + asINT64 value; + CScriptDictValue_opCast(&value, asTYPEID_INT64, obj); + return value; } static double CScriptDictValue_opConvDouble(CScriptDictValue *obj) { - double value; - CScriptDictValue_opCast(&value, asTYPEID_DOUBLE, obj); - return value; + double value; + CScriptDictValue_opCast(&value, asTYPEID_DOUBLE, obj); + return value; } //------------------------------------------------------------------- @@ -987,72 +987,72 @@ static double CScriptDictValue_opConvDouble(CScriptDictValue *obj) static void CScriptDictValue_opConvDouble_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - double value; - self->Get(gen->GetEngine(), value); - *(double*)gen->GetAddressOfReturnLocation() = value; + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + double value; + self->Get(gen->GetEngine(), value); + *(double*)gen->GetAddressOfReturnLocation() = value; } static void CScriptDictValue_opConvInt_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - asINT64 value; - self->Get(gen->GetEngine(), value); - *(asINT64*)gen->GetAddressOfReturnLocation() = value; + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + asINT64 value; + self->Get(gen->GetEngine(), value); + *(asINT64*)gen->GetAddressOfReturnLocation() = value; } static void CScriptDictValue_opCast_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - self->Get(gen->GetEngine(), gen->GetArgAddress(0), gen->GetArgTypeId(0)); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->Get(gen->GetEngine(), gen->GetArgAddress(0), gen->GetArgTypeId(0)); } static void CScriptDictValue_opAssign_int64_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign((asINT64)gen->GetArgQWord(0), self); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign((asINT64)gen->GetArgQWord(0), self); } static void CScriptDictValue_opAssign_double_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgDouble(0), self); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgDouble(0), self); } static void CScriptDictValue_opAssign_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgAddress(0), gen->GetArgTypeId(0), self); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgAddress(0), gen->GetArgTypeId(0), self); } static void CScriptDictValue_opCopyAssign_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(*reinterpret_cast(gen->GetArgAddress(0)), self); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(*reinterpret_cast(gen->GetArgAddress(0)), self); } static void CScriptDictValue_Construct_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - CScriptDictValue_Construct(self); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + CScriptDictValue_Construct(self); } static void CScriptDictValue_Destruct_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - CScriptDictValue_Destruct(self); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + CScriptDictValue_Destruct(self); } static void CScriptDictValue_EnumReferences_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - self->EnumReferences(gen->GetEngine()); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->EnumReferences(gen->GetEngine()); } static void CScriptDictValue_FreeValue_Generic(asIScriptGeneric *gen) { - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - self->FreeValue(gen->GetEngine()); + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->FreeValue(gen->GetEngine()); } //-------------------------------------------------------------------------- @@ -1060,154 +1060,154 @@ static void CScriptDictValue_FreeValue_Generic(asIScriptGeneric *gen) void RegisterScriptDictionary(asIScriptEngine *engine) { - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptDictionary_Generic(engine); - else - RegisterScriptDictionary_Native(engine); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptDictionary_Generic(engine); + else + RegisterScriptDictionary_Native(engine); } void RegisterScriptDictionary_Native(asIScriptEngine *engine) { - // The array type must be available - assert( engine->GetTypeInfoByDecl("array") ); + // The array type must be available + assert( engine->GetTypeInfoByDecl("array") ); #if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class - engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class + engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); #else - engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); + engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); #endif - engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictValue, EnumReferences), asCALL_THISCALL); assert(r >= 0); - engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictValue, FreeValue), asCALL_THISCALL); assert(r >= 0); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert(r >= 0); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); - // Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,void*,int),void), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const double&),void), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &) const, const CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); - - // Register GC behaviours - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictValue, EnumReferences), asCALL_THISCALL); assert(r >= 0); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictValue, FreeValue), asCALL_THISCALL); assert(r >= 0); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert(r >= 0); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + // Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,void*,int),void), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const double&),void), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &) const, const CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); + + // Register GC behaviours + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 ); #if AS_USE_STLNAMES == 1 - // Same as isEmpty - engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - // Same as getSize - engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); - // Same as delete - engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); - // Same as deleteAll - engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); + // Same as isEmpty + engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + // Same as getSize + engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); + // Same as delete + engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); + // Same as deleteAll + engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); #endif - // Cache some things the dictionary will need at runtime - SDictionaryCache::Setup(engine); + // Cache some things the dictionary will need at runtime + SDictionaryCache::Setup(engine); } void RegisterScriptDictionary_Generic(asIScriptEngine *engine) { - // Register the cleanup callback for the object type cache - engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); + // Register the cleanup callback for the object type cache + engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); #if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class - engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class + engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); #else - r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); #endif - engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); - engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_FreeValue_Generic), asCALL_GENERIC); assert(r >= 0); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 ); - - // Register GC behaviours - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - - // Cache some things the dictionary will need at runtime - SDictionaryCache::Setup(engine); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); + engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_FreeValue_Generic), asCALL_GENERIC); assert(r >= 0); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 ); + + // Register GC behaviours + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + + // Cache some things the dictionary will need at runtime + SDictionaryCache::Setup(engine); } //------------------------------------------------------------------ @@ -1215,81 +1215,81 @@ void RegisterScriptDictionary_Generic(asIScriptEngine *engine) CScriptDictionary::CIterator CScriptDictionary::begin() const { - return CIterator(*this, dict.begin()); + return CIterator(*this, dict.begin()); } CScriptDictionary::CIterator CScriptDictionary::end() const { - return CIterator(*this, dict.end()); + return CIterator(*this, dict.end()); } CScriptDictionary::CIterator CScriptDictionary::find(const dictKey_t &key) const { - return CIterator(*this, dict.find(key)); + return CIterator(*this, dict.find(key)); } CScriptDictionary::CIterator::CIterator( - const CScriptDictionary &dict, - dictMap_t::const_iterator it) - : m_it(it), m_dict(dict) + const CScriptDictionary &dict, + dictMap_t::const_iterator it) + : m_it(it), m_dict(dict) {} -void CScriptDictionary::CIterator::operator++() -{ - ++m_it; +void CScriptDictionary::CIterator::operator++() +{ + ++m_it; } -void CScriptDictionary::CIterator::operator++(int) -{ - ++m_it; +void CScriptDictionary::CIterator::operator++(int) +{ + ++m_it; - // Normally the post increment would return a copy of the object with the original state, - // but it is rarely used so we skip this extra copy to avoid unnecessary overhead + // Normally the post increment would return a copy of the object with the original state, + // but it is rarely used so we skip this extra copy to avoid unnecessary overhead } CScriptDictionary::CIterator &CScriptDictionary::CIterator::operator*() { - return *this; + return *this; } -bool CScriptDictionary::CIterator::operator==(const CIterator &other) const -{ - return m_it == other.m_it; +bool CScriptDictionary::CIterator::operator==(const CIterator &other) const +{ + return m_it == other.m_it; } -bool CScriptDictionary::CIterator::operator!=(const CIterator &other) const -{ - return m_it != other.m_it; +bool CScriptDictionary::CIterator::operator!=(const CIterator &other) const +{ + return m_it != other.m_it; } -const dictKey_t &CScriptDictionary::CIterator::GetKey() const -{ - return m_it->first; +const dictKey_t &CScriptDictionary::CIterator::GetKey() const +{ + return m_it->first; } int CScriptDictionary::CIterator::GetTypeId() const -{ - return m_it->second.m_typeId; +{ + return m_it->second.m_typeId; } bool CScriptDictionary::CIterator::GetValue(asINT64 &value) const -{ - return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64); +{ + return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64); } bool CScriptDictionary::CIterator::GetValue(double &value) const -{ - return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE); +{ + return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE); } bool CScriptDictionary::CIterator::GetValue(void *value, int typeId) const -{ - return m_it->second.Get(m_dict.engine, value, typeId); +{ + return m_it->second.Get(m_dict.engine, value, typeId); } const void *CScriptDictionary::CIterator::GetAddressOfValue() const { - return m_it->second.GetAddressOfValue(); + return m_it->second.GetAddressOfValue(); } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scriptdictionary/scriptdictionary.h b/src/angelscript/add_on/scriptdictionary/scriptdictionary.h index 062bb153469..d9209d9dd94 100644 --- a/src/angelscript/add_on/scriptdictionary/scriptdictionary.h +++ b/src/angelscript/add_on/scriptdictionary/scriptdictionary.h @@ -5,7 +5,7 @@ // string type must be registered with the engine before registering the // dictionary type -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -22,7 +22,7 @@ class CScriptDictValue; END_AS_NAMESPACE // C++11 introduced the std::unordered_map which is a hash map which is -// is generally more performatic for lookups than the std::map which is a +// is generally more performatic for lookups than the std::map which is a // binary tree. // TODO: memory: The map allocator should use the asAllocMem and asFreeMem #if AS_CAN_USE_CPP11 @@ -62,165 +62,165 @@ class CScriptDictionary; class CScriptDictValue { public: - // This class must not be declared as local variable in C++, because it needs - // to receive the script engine pointer in all operations. The engine pointer - // is not kept as member in order to keep the size down - CScriptDictValue(); - CScriptDictValue(asIScriptEngine *engine, void *value, int typeId); + // This class must not be declared as local variable in C++, because it needs + // to receive the script engine pointer in all operations. The engine pointer + // is not kept as member in order to keep the size down + CScriptDictValue(); + CScriptDictValue(asIScriptEngine *engine, void *value, int typeId); - // Destructor must not be called without first calling FreeValue, otherwise a memory leak will occur - ~CScriptDictValue(); + // Destructor must not be called without first calling FreeValue, otherwise a memory leak will occur + ~CScriptDictValue(); - // Replace the stored value - void Set(asIScriptEngine *engine, void *value, int typeId); - void Set(asIScriptEngine *engine, const asINT64 &value); - void Set(asIScriptEngine *engine, const double &value); - void Set(asIScriptEngine *engine, CScriptDictValue &value); + // Replace the stored value + void Set(asIScriptEngine *engine, void *value, int typeId); + void Set(asIScriptEngine *engine, const asINT64 &value); + void Set(asIScriptEngine *engine, const double &value); + void Set(asIScriptEngine *engine, CScriptDictValue &value); - // Gets the stored value. Returns false if the value isn't compatible with the informed typeId - bool Get(asIScriptEngine *engine, void *value, int typeId) const; - bool Get(asIScriptEngine *engine, asINT64 &value) const; - bool Get(asIScriptEngine *engine, double &value) const; + // Gets the stored value. Returns false if the value isn't compatible with the informed typeId + bool Get(asIScriptEngine *engine, void *value, int typeId) const; + bool Get(asIScriptEngine *engine, asINT64 &value) const; + bool Get(asIScriptEngine *engine, double &value) const; - // Returns the address of the stored value for inspection - const void *GetAddressOfValue() const; + // Returns the address of the stored value for inspection + const void *GetAddressOfValue() const; - // Returns the type id of the stored value - int GetTypeId() const; + // Returns the type id of the stored value + int GetTypeId() const; - // Free the stored value - void FreeValue(asIScriptEngine *engine); + // Free the stored value + void FreeValue(asIScriptEngine *engine); - // GC callback - void EnumReferences(asIScriptEngine *engine); + // GC callback + void EnumReferences(asIScriptEngine *engine); protected: - friend class CScriptDictionary; - - union - { - asINT64 m_valueInt; - double m_valueFlt; - void *m_valueObj; - }; - int m_typeId; + friend class CScriptDictionary; + + union + { + asINT64 m_valueInt; + double m_valueFlt; + void *m_valueObj; + }; + int m_typeId; }; class CScriptDictionary { public: - // Factory functions - static CScriptDictionary *Create(asIScriptEngine *engine); + // Factory functions + static CScriptDictionary *Create(asIScriptEngine *engine); - // Called from the script to instantiate a dictionary from an initialization list - static CScriptDictionary *Create(asBYTE *buffer); + // Called from the script to instantiate a dictionary from an initialization list + static CScriptDictionary *Create(asBYTE *buffer); - // Reference counting - void AddRef() const; - void Release() const; + // Reference counting + void AddRef() const; + void Release() const; - // Reassign the dictionary - CScriptDictionary &operator =(const CScriptDictionary &other); + // Reassign the dictionary + CScriptDictionary &operator =(const CScriptDictionary &other); - // Sets a key/value pair - void Set(const dictKey_t &key, void *value, int typeId); - void Set(const dictKey_t &key, const asINT64 &value); - void Set(const dictKey_t &key, const double &value); + // Sets a key/value pair + void Set(const dictKey_t &key, void *value, int typeId); + void Set(const dictKey_t &key, const asINT64 &value); + void Set(const dictKey_t &key, const double &value); - // Gets the stored value. Returns false if the value isn't compatible with the informed typeId - bool Get(const dictKey_t &key, void *value, int typeId) const; - bool Get(const dictKey_t &key, asINT64 &value) const; - bool Get(const dictKey_t &key, double &value) const; + // Gets the stored value. Returns false if the value isn't compatible with the informed typeId + bool Get(const dictKey_t &key, void *value, int typeId) const; + bool Get(const dictKey_t &key, asINT64 &value) const; + bool Get(const dictKey_t &key, double &value) const; - // Index accessors. If the dictionary is not const it inserts the value if it doesn't already exist - // If the dictionary is const then a script exception is set if it doesn't exist and a null pointer is returned - CScriptDictValue *operator[](const dictKey_t &key); - const CScriptDictValue *operator[](const dictKey_t &key) const; + // Index accessors. If the dictionary is not const it inserts the value if it doesn't already exist + // If the dictionary is const then a script exception is set if it doesn't exist and a null pointer is returned + CScriptDictValue *operator[](const dictKey_t &key); + const CScriptDictValue *operator[](const dictKey_t &key) const; - // Returns the type id of the stored value, or negative if it doesn't exist - int GetTypeId(const dictKey_t &key) const; + // Returns the type id of the stored value, or negative if it doesn't exist + int GetTypeId(const dictKey_t &key) const; - // Returns true if the key is set - bool Exists(const dictKey_t &key) const; + // Returns true if the key is set + bool Exists(const dictKey_t &key) const; - // Returns true if there are no key/value pairs in the dictionary - bool IsEmpty() const; + // Returns true if there are no key/value pairs in the dictionary + bool IsEmpty() const; - // Returns the number of key/value pairs in the dictionary - asUINT GetSize() const; + // Returns the number of key/value pairs in the dictionary + asUINT GetSize() const; - // Deletes the key - bool Delete(const dictKey_t &key); + // Deletes the key + bool Delete(const dictKey_t &key); - // Deletes all keys - void DeleteAll(); + // Deletes all keys + void DeleteAll(); - // Get an array of all keys - CScriptArray *GetKeys() const; + // Get an array of all keys + CScriptArray *GetKeys() const; - // STL style iterator - class CIterator - { - public: - void operator++(); // Pre-increment - void operator++(int); // Post-increment + // STL style iterator + class CIterator + { + public: + void operator++(); // Pre-increment + void operator++(int); // Post-increment - // This is needed to support C++11 range-for - CIterator &operator*(); + // This is needed to support C++11 range-for + CIterator &operator*(); - bool operator==(const CIterator &other) const; - bool operator!=(const CIterator &other) const; + bool operator==(const CIterator &other) const; + bool operator!=(const CIterator &other) const; - // Accessors - const dictKey_t &GetKey() const; - int GetTypeId() const; - bool GetValue(asINT64 &value) const; - bool GetValue(double &value) const; - bool GetValue(void *value, int typeId) const; - const void * GetAddressOfValue() const; + // Accessors + const dictKey_t &GetKey() const; + int GetTypeId() const; + bool GetValue(asINT64 &value) const; + bool GetValue(double &value) const; + bool GetValue(void *value, int typeId) const; + const void * GetAddressOfValue() const; - protected: - friend class CScriptDictionary; + protected: + friend class CScriptDictionary; - CIterator(); - CIterator(const CScriptDictionary &dict, - dictMap_t::const_iterator it); + CIterator(); + CIterator(const CScriptDictionary &dict, + dictMap_t::const_iterator it); - CIterator &operator=(const CIterator &) {return *this;} // Not used + CIterator &operator=(const CIterator &) {return *this;} // Not used - dictMap_t::const_iterator m_it; - const CScriptDictionary &m_dict; - }; + dictMap_t::const_iterator m_it; + const CScriptDictionary &m_dict; + }; - CIterator begin() const; - CIterator end() const; - CIterator find(const dictKey_t &key) const; + CIterator begin() const; + CIterator end() const; + CIterator find(const dictKey_t &key) const; - // Garbage collections behaviours - int GetRefCount(); - void SetGCFlag(); - bool GetGCFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllReferences(asIScriptEngine *engine); + // Garbage collections behaviours + int GetRefCount(); + void SetGCFlag(); + bool GetGCFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllReferences(asIScriptEngine *engine); protected: - // Since the dictionary uses the asAllocMem and asFreeMem functions to allocate memory - // the constructors are made protected so that the application cannot allocate it - // manually in a different way - CScriptDictionary(asIScriptEngine *engine); - CScriptDictionary(asBYTE *buffer); - - // We don't want anyone to call the destructor directly, it should be called through the Release method - virtual ~CScriptDictionary(); - - // Cache the object types needed - void Init(asIScriptEngine *engine); - - // Our properties - asIScriptEngine *engine; - mutable int refCount; - mutable bool gcFlag; - dictMap_t dict; + // Since the dictionary uses the asAllocMem and asFreeMem functions to allocate memory + // the constructors are made protected so that the application cannot allocate it + // manually in a different way + CScriptDictionary(asIScriptEngine *engine); + CScriptDictionary(asBYTE *buffer); + + // We don't want anyone to call the destructor directly, it should be called through the Release method + virtual ~CScriptDictionary(); + + // Cache the object types needed + void Init(asIScriptEngine *engine); + + // Our properties + asIScriptEngine *engine; + mutable int refCount; + mutable bool gcFlag; + dictMap_t dict; }; // This function will determine the configuration of the engine diff --git a/src/angelscript/add_on/scriptfile/scriptfile.cpp b/src/angelscript/add_on/scriptfile/scriptfile.cpp index 5c4e26c7c6c..85b84741ab6 100644 --- a/src/angelscript/add_on/scriptfile/scriptfile.cpp +++ b/src/angelscript/add_on/scriptfile/scriptfile.cpp @@ -18,152 +18,152 @@ BEGIN_AS_NAMESPACE CScriptFile *ScriptFile_Factory() { - return new CScriptFile(); + return new CScriptFile(); } void ScriptFile_Factory_Generic(asIScriptGeneric *gen) { - *(CScriptFile**)gen->GetAddressOfReturnLocation() = ScriptFile_Factory(); + *(CScriptFile**)gen->GetAddressOfReturnLocation() = ScriptFile_Factory(); } void ScriptFile_AddRef_Generic(asIScriptGeneric *gen) { - CScriptFile *file = (CScriptFile*)gen->GetObject(); - file->AddRef(); + CScriptFile *file = (CScriptFile*)gen->GetObject(); + file->AddRef(); } void ScriptFile_Release_Generic(asIScriptGeneric *gen) { - CScriptFile *file = (CScriptFile*)gen->GetObject(); - file->Release(); + 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); + 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); + 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); + 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); - string str = file->ReadString(len); - gen->SetReturnObject(&str); + CScriptFile *file = (CScriptFile*)gen->GetObject(); + int len = gen->GetArgDWord(0); + string str = file->ReadString(len); + gen->SetReturnObject(&str); } void ScriptFile_ReadLine_Generic(asIScriptGeneric *gen) { - CScriptFile *file = (CScriptFile*)gen->GetObject(); - std::string str = file->ReadLine(); - gen->SetReturnObject(&str); + CScriptFile *file = (CScriptFile*)gen->GetObject(); + std::string str = file->ReadLine(); + gen->SetReturnObject(&str); } void ScriptFile_ReadInt_Generic(asIScriptGeneric *gen) { - CScriptFile *file = (CScriptFile*)gen->GetObject(); - asUINT bytes = *(asUINT*)gen->GetAddressOfArg(0); - *(asINT64*)gen->GetAddressOfReturnLocation() = file->ReadInt(bytes); + 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); + 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(); + 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(); + 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)); + 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); + 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); + 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); + 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); + 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); + 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()); + 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)); + 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)); + CScriptFile *file = (CScriptFile*)gen->GetObject(); + int delta = (int)gen->GetArgDWord(0); + gen->SetReturnDWord(file->MovePos(delta)); } void RegisterScriptFile_Native(asIScriptEngine *engine) @@ -177,482 +177,482 @@ void RegisterScriptFile_Native(asIScriptEngine *engine) 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", "string readString(uint)", asMETHOD(CScriptFile,ReadString), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "string readLine()", 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 ); + 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", "string readString(uint)", asMETHOD(CScriptFile,ReadString), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "string readLine()", 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 ); + 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->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 ); + r = engine->RegisterObjectProperty("file", "bool mostSignificantByteFirst", asOFFSET(CScriptFile, mostSignificantByteFirst)); assert( r >= 0 ); } void RegisterScriptFile_Generic(asIScriptEngine *engine) { - int r; + 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->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", "string readString(uint)", asFUNCTION(ScriptFile_ReadString_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("file", "string readLine()", 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 ); + 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", "string readString(uint)", asFUNCTION(ScriptFile_ReadString_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "string readLine()", 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 ); + 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->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 ); + 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); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptFile_Generic(engine); + else + RegisterScriptFile_Native(engine); } CScriptFile::CScriptFile() { - refCount = 1; - file = 0; - mostSignificantByteFirst = false; + refCount = 1; + file = 0; + mostSignificantByteFirst = false; } CScriptFile::~CScriptFile() { - Close(); + Close(); } void CScriptFile::AddRef() const { - asAtomicInc(refCount); + asAtomicInc(refCount); } void CScriptFile::Release() const { - if( asAtomicDec(refCount) == 0 ) - delete this; + 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(); + // Close the previously opened file handle + if( file ) + Close(); - std::string myFilename = filename; + std::string myFilename = filename; - // Validate the mode - string m; + // Validate the mode + string m; #if AS_WRITE_OPS == 1 - if( mode != "r" && mode != "w" && mode != "a" ) + if( mode != "r" && mode != "w" && mode != "a" ) #else - if( mode != "r" ) + if( mode != "r" ) #endif - return -1; - else - m = mode; + 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'); - } + // 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); + wcstombs(buf, apppath, wcslen(apppath)+1); #else - memcpy(buf, apppath, strlen(apppath)); + memcpy(buf, apppath, strlen(apppath)); #endif - myFilename = buf + myFilename; + myFilename = buf + myFilename; #endif - // By default windows translates "\r\n" to "\n", but we want to read the file as-is. - m += "b"; + // 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()); + // 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()); + file = fopen(myFilename.c_str(), m.c_str()); #endif - if( file == 0 ) - return -1; + if( file == 0 ) + return -1; - return 0; + return 0; } int CScriptFile::Close() { - if( file == 0 ) - return -1; + if( file == 0 ) + return -1; - fclose(file); - file = 0; + fclose(file); + file = 0; - return 0; + return 0; } int CScriptFile::GetSize() const { - if( file == 0 ) - return -1; + if( file == 0 ) + return -1; - int pos = ftell(file); - fseek(file, 0, SEEK_END); - int size = ftell(file); - fseek(file, pos, SEEK_SET); + int pos = ftell(file); + fseek(file, 0, SEEK_END); + int size = ftell(file); + fseek(file, pos, SEEK_SET); - return size; + return size; } int CScriptFile::GetPos() const { - if( file == 0 ) - return -1; + if( file == 0 ) + return -1; - return ftell(file); + return ftell(file); } - + int CScriptFile::SetPos(int pos) { - if( file == 0 ) - return -1; + if( file == 0 ) + return -1; - int r = fseek(file, pos, SEEK_SET); + int r = fseek(file, pos, SEEK_SET); - // Return -1 on error - return r ? -1 : 0; + // Return -1 on error + return r ? -1 : 0; } int CScriptFile::MovePos(int delta) { - if( file == 0 ) - return -1; + if( file == 0 ) + return -1; - int r = fseek(file, delta, SEEK_CUR); + int r = fseek(file, delta, SEEK_CUR); - // Return -1 on error - return r ? -1 : 0; + // Return -1 on error + return r ? -1 : 0; } string CScriptFile::ReadString(unsigned int length) { - if( file == 0 ) - return ""; + if( file == 0 ) + return ""; - // Read the string - string str; - str.resize(length); - int size = (int)fread(&str[0], 1, length, file); - str.resize(size); + // Read the string + string str; + str.resize(length); + int size = (int)fread(&str[0], 1, length, file); + str.resize(size); - return str; + return str; } string CScriptFile::ReadLine() { - if( file == 0 ) - return ""; + if( file == 0 ) + return ""; + + // Read until the first new-line character + string str; + char buf[256]; - // Read until the first new-line character - string str; - char buf[256]; + do + { + // Get the current position so we can determine how many characters were read + int start = ftell(file); - 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; - // 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; - // 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); + // 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' ); + // Add the read characters to the output buffer + str.append(buf, end-start); + } + while( !feof(file) && buf[255] == 0 && buf[254] != '\n' ); - return str; + return str; } 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; + 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( file == 0 ) + return 0; - if( bytes > 8 ) bytes = 8; - if( bytes == 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; + 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); - } + 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; + return val; } float CScriptFile::ReadFloat() { - if( file == 0 ) - return 0; + if( file == 0 ) + return 0; - unsigned char buf[4]; - size_t r = fread(buf, 4, 1, file); - if( r == 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); - } + 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); + return *reinterpret_cast(&val); } double CScriptFile::ReadDouble() { - if( file == 0 ) - return 0; + if( file == 0 ) + return 0; - unsigned char buf[8]; - size_t r = fread(buf, 8, 1, file); - if( r == 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); - } + 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); + return *reinterpret_cast(&val); } bool CScriptFile::IsEOF() const { - if( file == 0 ) - return true; + if( file == 0 ) + return true; - return feof(file) ? true : false; + return feof(file) ? true : false; } #if AS_WRITE_OPS == 1 int CScriptFile::WriteString(const std::string &str) { - if( file == 0 ) - return -1; + if( file == 0 ) + return -1; - // Write the entire string - size_t r = fwrite(&str[0], 1, str.length(), file); + // Write the entire string + size_t r = fwrite(&str[0], 1, str.length(), file); - return int(r); + return int(r); } int CScriptFile::WriteInt(asINT64 val, asUINT bytes) { - if( file == 0 ) - return 0; + 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; - } + 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); + size_t r = fwrite(&buf, bytes, 1, file); + return int(r); } int CScriptFile::WriteUInt(asQWORD val, asUINT bytes) { - if( file == 0 ) - return 0; + 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; - } + 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); + size_t r = fwrite(&buf, bytes, 1, file); + return int(r); } int CScriptFile::WriteFloat(float f) { - if( file == 0 ) - return 0; + 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; - } + 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); + 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); + 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 diff --git a/src/angelscript/add_on/scriptfile/scriptfile.h b/src/angelscript/add_on/scriptfile/scriptfile.h index 748bba77c38..9f3e3e18a91 100644 --- a/src/angelscript/add_on/scriptfile/scriptfile.h +++ b/src/angelscript/add_on/scriptfile/scriptfile.h @@ -27,7 +27,7 @@ // Declaration // -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -40,48 +40,48 @@ 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 - std::string ReadString(unsigned int length); - std::string ReadLine(); - 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; + 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 + std::string ReadString(unsigned int length); + std::string ReadLine(); + 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(); + ~CScriptFile(); - mutable int refCount; - FILE *file; + mutable int refCount; + FILE *file; }; // This function will determine the configuration of the engine diff --git a/src/angelscript/add_on/scriptfile/scriptfilesystem.cpp b/src/angelscript/add_on/scriptfile/scriptfilesystem.cpp index 99c6277b33a..5e21718f8b5 100644 --- a/src/angelscript/add_on/scriptfile/scriptfilesystem.cpp +++ b/src/angelscript/add_on/scriptfile/scriptfilesystem.cpp @@ -24,86 +24,86 @@ BEGIN_AS_NAMESPACE CScriptFileSystem *ScriptFileSystem_Factory() { - return new CScriptFileSystem(); + return new CScriptFileSystem(); } void RegisterScriptFileSystem_Native(asIScriptEngine *engine) { - int r; - - assert( engine->GetTypeInfoByName("string") ); - assert( engine->GetTypeInfoByDecl("array") ); - assert( engine->GetTypeInfoByName("datetime") ); - - r = engine->RegisterObjectType("filesystem", 0, asOBJ_REF); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_FACTORY, "filesystem @f()", asFUNCTION(ScriptFileSystem_Factory), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptFileSystem,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptFileSystem,Release), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("filesystem", "bool changeCurrentPath(const string &in)", asMETHOD(CScriptFileSystem, ChangeCurrentPath), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "string getCurrentPath() const", asMETHOD(CScriptFileSystem, GetCurrentPath), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "array @getDirs() const", asMETHOD(CScriptFileSystem, GetDirs), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "array @getFiles() const", asMETHOD(CScriptFileSystem, GetFiles), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in) const", asMETHOD(CScriptFileSystem, IsDir), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "bool isLink(const string &in) const", asMETHOD(CScriptFileSystem, IsLink), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int64 getSize(const string &in) const", asMETHOD(CScriptFileSystem, GetSize), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int makeDir(const string &in)", asMETHOD(CScriptFileSystem, MakeDir), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int removeDir(const string &in)", asMETHOD(CScriptFileSystem, RemoveDir), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int deleteFile(const string &in)", asMETHOD(CScriptFileSystem, DeleteFile), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int copyFile(const string &in, const string &in)", asMETHOD(CScriptFileSystem, CopyFile), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int move(const string &in, const string &in)", asMETHOD(CScriptFileSystem, Move), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "datetime getCreateDateTime(const string &in) const", asMETHOD(CScriptFileSystem, GetCreateDateTime), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "datetime getModifyDateTime(const string &in) const", asMETHOD(CScriptFileSystem, GetModifyDateTime), asCALL_THISCALL); assert(r >= 0); + int r; + + assert( engine->GetTypeInfoByName("string") ); + assert( engine->GetTypeInfoByDecl("array") ); + assert( engine->GetTypeInfoByName("datetime") ); + + r = engine->RegisterObjectType("filesystem", 0, asOBJ_REF); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_FACTORY, "filesystem @f()", asFUNCTION(ScriptFileSystem_Factory), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptFileSystem,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptFileSystem,Release), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("filesystem", "bool changeCurrentPath(const string &in)", asMETHOD(CScriptFileSystem, ChangeCurrentPath), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "string getCurrentPath() const", asMETHOD(CScriptFileSystem, GetCurrentPath), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "array @getDirs() const", asMETHOD(CScriptFileSystem, GetDirs), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "array @getFiles() const", asMETHOD(CScriptFileSystem, GetFiles), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in) const", asMETHOD(CScriptFileSystem, IsDir), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "bool isLink(const string &in) const", asMETHOD(CScriptFileSystem, IsLink), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int64 getSize(const string &in) const", asMETHOD(CScriptFileSystem, GetSize), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int makeDir(const string &in)", asMETHOD(CScriptFileSystem, MakeDir), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int removeDir(const string &in)", asMETHOD(CScriptFileSystem, RemoveDir), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int deleteFile(const string &in)", asMETHOD(CScriptFileSystem, DeleteFile), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int copyFile(const string &in, const string &in)", asMETHOD(CScriptFileSystem, CopyFile), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int move(const string &in, const string &in)", asMETHOD(CScriptFileSystem, Move), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "datetime getCreateDateTime(const string &in) const", asMETHOD(CScriptFileSystem, GetCreateDateTime), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "datetime getModifyDateTime(const string &in) const", asMETHOD(CScriptFileSystem, GetModifyDateTime), asCALL_THISCALL); assert(r >= 0); } void RegisterScriptFileSystem_Generic(asIScriptEngine *engine) { - int r; - - assert( engine->GetTypeInfoByName("string") ); - assert( engine->GetTypeInfoByDecl("array") ); - assert( engine->GetTypeInfoByName("datetime") ); - - r = engine->RegisterObjectType("filesystem", 0, asOBJ_REF); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_FACTORY, "filesystem @f()", WRAP_FN(ScriptFileSystem_Factory), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_ADDREF, "void f()", WRAP_MFN(CScriptFileSystem,AddRef), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_RELEASE, "void f()", WRAP_MFN(CScriptFileSystem,Release), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("filesystem", "bool changeCurrentPath(const string &in)", WRAP_MFN(CScriptFileSystem, ChangeCurrentPath), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "string getCurrentPath() const", WRAP_MFN(CScriptFileSystem, GetCurrentPath), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "array @getDirs() const", WRAP_MFN(CScriptFileSystem, GetDirs), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "array @getFiles() const", WRAP_MFN(CScriptFileSystem, GetFiles), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in) const", WRAP_MFN(CScriptFileSystem, IsDir), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("filesystem", "bool isLink(const string &in) const", WRAP_MFN(CScriptFileSystem, IsLink), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int64 getSize(const string &in) const", WRAP_MFN(CScriptFileSystem, GetSize), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int makeDir(const string &in)", WRAP_MFN(CScriptFileSystem, MakeDir), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int removeDir(const string &in)", WRAP_MFN(CScriptFileSystem, RemoveDir), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int deleteFile(const string &in)", WRAP_MFN(CScriptFileSystem, DeleteFile), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int copyFile(const string &in, const string &in)", WRAP_MFN(CScriptFileSystem, CopyFile), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "int move(const string &in, const string &in)", WRAP_MFN(CScriptFileSystem, Move), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "datetime getCreateDateTime(const string &in) const", WRAP_MFN(CScriptFileSystem, GetCreateDateTime), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("filesystem", "datetime getModifyDateTime(const string &in) const", WRAP_MFN(CScriptFileSystem, GetModifyDateTime), asCALL_GENERIC); assert(r >= 0); + int r; + + assert( engine->GetTypeInfoByName("string") ); + assert( engine->GetTypeInfoByDecl("array") ); + assert( engine->GetTypeInfoByName("datetime") ); + + r = engine->RegisterObjectType("filesystem", 0, asOBJ_REF); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_FACTORY, "filesystem @f()", WRAP_FN(ScriptFileSystem_Factory), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_ADDREF, "void f()", WRAP_MFN(CScriptFileSystem,AddRef), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_RELEASE, "void f()", WRAP_MFN(CScriptFileSystem,Release), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("filesystem", "bool changeCurrentPath(const string &in)", WRAP_MFN(CScriptFileSystem, ChangeCurrentPath), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "string getCurrentPath() const", WRAP_MFN(CScriptFileSystem, GetCurrentPath), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "array @getDirs() const", WRAP_MFN(CScriptFileSystem, GetDirs), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "array @getFiles() const", WRAP_MFN(CScriptFileSystem, GetFiles), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in) const", WRAP_MFN(CScriptFileSystem, IsDir), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "bool isLink(const string &in) const", WRAP_MFN(CScriptFileSystem, IsLink), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int64 getSize(const string &in) const", WRAP_MFN(CScriptFileSystem, GetSize), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int makeDir(const string &in)", WRAP_MFN(CScriptFileSystem, MakeDir), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int removeDir(const string &in)", WRAP_MFN(CScriptFileSystem, RemoveDir), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int deleteFile(const string &in)", WRAP_MFN(CScriptFileSystem, DeleteFile), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int copyFile(const string &in, const string &in)", WRAP_MFN(CScriptFileSystem, CopyFile), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int move(const string &in, const string &in)", WRAP_MFN(CScriptFileSystem, Move), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "datetime getCreateDateTime(const string &in) const", WRAP_MFN(CScriptFileSystem, GetCreateDateTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "datetime getModifyDateTime(const string &in) const", WRAP_MFN(CScriptFileSystem, GetModifyDateTime), asCALL_GENERIC); assert(r >= 0); } void RegisterScriptFileSystem(asIScriptEngine *engine) { - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptFileSystem_Generic(engine); - else - RegisterScriptFileSystem_Native(engine); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptFileSystem_Generic(engine); + else + RegisterScriptFileSystem_Native(engine); } CScriptFileSystem::CScriptFileSystem() { - refCount = 1; + refCount = 1; - // Gets the application's current working directory as the starting point - // TODO: Replace backslash with slash to keep a unified naming convention - char buffer[1000]; + // Gets the application's current working directory as the starting point + // TODO: Replace backslash with slash to keep a unified naming convention + char buffer[1000]; #if defined(_WIN32) - currentPath = _getcwd(buffer, 1000); + currentPath = _getcwd(buffer, 1000); #else - currentPath = getcwd(buffer, 1000); + currentPath = getcwd(buffer, 1000); #endif } @@ -113,268 +113,268 @@ CScriptFileSystem::~CScriptFileSystem() void CScriptFileSystem::AddRef() const { - asAtomicInc(refCount); + asAtomicInc(refCount); } void CScriptFileSystem::Release() const { - if( asAtomicDec(refCount) == 0 ) - delete this; + if( asAtomicDec(refCount) == 0 ) + delete this; } CScriptArray *CScriptFileSystem::GetFiles() const { - // Obtain a pointer to the engine - asIScriptContext *ctx = asGetActiveContext(); - asIScriptEngine *engine = ctx->GetEngine(); + // Obtain a pointer to the engine + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); - // TODO: This should only be done once - // TODO: This assumes that CScriptArray was already registered - asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); + // TODO: This should only be done once + // TODO: This assumes that CScriptArray was already registered + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); - // Create the array object - CScriptArray *array = CScriptArray::Create(arrayType); + // Create the array object + CScriptArray *array = CScriptArray::Create(arrayType); #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - string searchPattern = currentPath + "/*"; - MultiByteToWideChar(CP_UTF8, 0, searchPattern.c_str(), -1, bufUTF16, 10000); - - WIN32_FIND_DATAW ffd; - HANDLE hFind = FindFirstFileW(bufUTF16, &ffd); - if( INVALID_HANDLE_VALUE == hFind ) - return array; - - do - { - // Skip directories - if( (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) - continue; - - // Convert the file name back to UTF8 - char bufUTF8[10000]; - WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, bufUTF8, 10000, 0, 0); - - // Add the file to the array - array->Resize(array->GetSize()+1); - ((string*)(array->At(array->GetSize()-1)))->assign(bufUTF8); - } - while( FindNextFileW(hFind, &ffd) != 0 ); - - FindClose(hFind); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + string searchPattern = currentPath + "/*"; + MultiByteToWideChar(CP_UTF8, 0, searchPattern.c_str(), -1, bufUTF16, 10000); + + WIN32_FIND_DATAW ffd; + HANDLE hFind = FindFirstFileW(bufUTF16, &ffd); + if( INVALID_HANDLE_VALUE == hFind ) + return array; + + do + { + // Skip directories + if( (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) + continue; + + // Convert the file name back to UTF8 + char bufUTF8[10000]; + WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, bufUTF8, 10000, 0, 0); + + // Add the file to the array + array->Resize(array->GetSize()+1); + ((string*)(array->At(array->GetSize()-1)))->assign(bufUTF8); + } + while( FindNextFileW(hFind, &ffd) != 0 ); + + FindClose(hFind); #else - dirent *ent = 0; - DIR *dir = opendir(currentPath.c_str()); - while( (ent = readdir(dir)) != NULL ) - { - const string filename = ent->d_name; - - // Skip . and .. - if( filename[0] == '.' ) - continue; - - // Skip sub directories - const string fullname = currentPath + "/" + filename; - struct stat st; - if( stat(fullname.c_str(), &st) == -1 ) - continue; - if( (st.st_mode & S_IFDIR) != 0 ) - continue; - - // Add the file to the array - array->Resize(array->GetSize()+1); - ((string*)(array->At(array->GetSize()-1)))->assign(filename); - } - closedir(dir); + dirent *ent = 0; + DIR *dir = opendir(currentPath.c_str()); + while( (ent = readdir(dir)) != NULL ) + { + const string filename = ent->d_name; + + // Skip . and .. + if( filename[0] == '.' ) + continue; + + // Skip sub directories + const string fullname = currentPath + "/" + filename; + struct stat st; + if( stat(fullname.c_str(), &st) == -1 ) + continue; + if( (st.st_mode & S_IFDIR) != 0 ) + continue; + + // Add the file to the array + array->Resize(array->GetSize()+1); + ((string*)(array->At(array->GetSize()-1)))->assign(filename); + } + closedir(dir); #endif - return array; + return array; } CScriptArray *CScriptFileSystem::GetDirs() const { - // Obtain a pointer to the engine - asIScriptContext *ctx = asGetActiveContext(); - asIScriptEngine *engine = ctx->GetEngine(); + // Obtain a pointer to the engine + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); - // TODO: This should only be done once - // TODO: This assumes that CScriptArray was already registered - asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); + // TODO: This should only be done once + // TODO: This assumes that CScriptArray was already registered + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); - // Create the array object - CScriptArray *array = CScriptArray::Create(arrayType); + // Create the array object + CScriptArray *array = CScriptArray::Create(arrayType); #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - string searchPattern = currentPath + "/*"; - MultiByteToWideChar(CP_UTF8, 0, searchPattern.c_str(), -1, bufUTF16, 10000); - - WIN32_FIND_DATAW ffd; - HANDLE hFind = FindFirstFileW(bufUTF16, &ffd); - if( INVALID_HANDLE_VALUE == hFind ) - return array; - - do - { - // Skip files - if( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) - continue; - - // Convert the file name back to UTF8 - char bufUTF8[10000]; - WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, bufUTF8, 10000, 0, 0); - - if( strcmp(bufUTF8, ".") == 0 || strcmp(bufUTF8, "..") == 0 ) - continue; - - // Add the dir to the array - array->Resize(array->GetSize()+1); - ((string*)(array->At(array->GetSize()-1)))->assign(bufUTF8); - } - while( FindNextFileW(hFind, &ffd) != 0 ); - - FindClose(hFind); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + string searchPattern = currentPath + "/*"; + MultiByteToWideChar(CP_UTF8, 0, searchPattern.c_str(), -1, bufUTF16, 10000); + + WIN32_FIND_DATAW ffd; + HANDLE hFind = FindFirstFileW(bufUTF16, &ffd); + if( INVALID_HANDLE_VALUE == hFind ) + return array; + + do + { + // Skip files + if( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) + continue; + + // Convert the file name back to UTF8 + char bufUTF8[10000]; + WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, bufUTF8, 10000, 0, 0); + + if( strcmp(bufUTF8, ".") == 0 || strcmp(bufUTF8, "..") == 0 ) + continue; + + // Add the dir to the array + array->Resize(array->GetSize()+1); + ((string*)(array->At(array->GetSize()-1)))->assign(bufUTF8); + } + while( FindNextFileW(hFind, &ffd) != 0 ); + + FindClose(hFind); #else - dirent *ent = 0; - DIR *dir = opendir(currentPath.c_str()); - while( (ent = readdir(dir)) != NULL ) - { - const string filename = ent->d_name; - - // Skip . and .. - if( filename[0] == '.' ) - continue; - - // Skip files - const string fullname = currentPath + "/" + filename; - struct stat st; - if( stat(fullname.c_str(), &st) == -1 ) - continue; - if( (st.st_mode & S_IFDIR) == 0 ) - continue; - - // Add the dir to the array - array->Resize(array->GetSize()+1); - ((string*)(array->At(array->GetSize()-1)))->assign(filename); - } - closedir(dir); + dirent *ent = 0; + DIR *dir = opendir(currentPath.c_str()); + while( (ent = readdir(dir)) != NULL ) + { + const string filename = ent->d_name; + + // Skip . and .. + if( filename[0] == '.' ) + continue; + + // Skip files + const string fullname = currentPath + "/" + filename; + struct stat st; + if( stat(fullname.c_str(), &st) == -1 ) + continue; + if( (st.st_mode & S_IFDIR) == 0 ) + continue; + + // Add the dir to the array + array->Resize(array->GetSize()+1); + ((string*)(array->At(array->GetSize()-1)))->assign(filename); + } + closedir(dir); #endif - return array; + return array; } // Doesn't change anything if the new path is not valid bool CScriptFileSystem::ChangeCurrentPath(const string &path) { - string newPath; - if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 ) - newPath = path; - else - newPath = currentPath + "/" + path; + string newPath; + if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 ) + newPath = path; + else + newPath = currentPath + "/" + path; - // TODO: Resolve internal /./ and /../ - // TODO: Replace backslash with slash to keep a unified naming convention + // TODO: Resolve internal /./ and /../ + // TODO: Replace backslash with slash to keep a unified naming convention - // Remove trailing slashes from the path - while(newPath.length() && (newPath[newPath.length()-1] == '/' || newPath[newPath.length()-1] == '\\') ) - newPath.resize(newPath.length()-1); + // Remove trailing slashes from the path + while(newPath.length() && (newPath[newPath.length()-1] == '/' || newPath[newPath.length()-1] == '\\') ) + newPath.resize(newPath.length()-1); - if (!IsDir(newPath)) - return false; + if (!IsDir(newPath)) + return false; - currentPath = newPath; - return true; + currentPath = newPath; + return true; } bool CScriptFileSystem::IsDir(const string &path) const { - string search; - if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 ) - search = path; - else - search = currentPath + "/" + path; + string search; + if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 ) + search = path; + else + search = currentPath + "/" + path; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); - - // Check if the path exists and is a directory - DWORD attrib = GetFileAttributesW(bufUTF16); - if( attrib == INVALID_FILE_ATTRIBUTES || - !(attrib & FILE_ATTRIBUTE_DIRECTORY) ) - return false; + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Check if the path exists and is a directory + DWORD attrib = GetFileAttributesW(bufUTF16); + if( attrib == INVALID_FILE_ATTRIBUTES || + !(attrib & FILE_ATTRIBUTE_DIRECTORY) ) + return false; #else - // Check if the path exists and is a directory - struct stat st; - if( stat(search.c_str(), &st) == -1 ) - return false; - if( (st.st_mode & S_IFDIR) == 0 ) - return false; + // Check if the path exists and is a directory + struct stat st; + if( stat(search.c_str(), &st) == -1 ) + return false; + if( (st.st_mode & S_IFDIR) == 0 ) + return false; #endif - return true; + return true; } bool CScriptFileSystem::IsLink(const string &path) const { - string search; - if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) - search = path; - else - search = currentPath + "/" + path; + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); - - // Check if the path exists and is a link - DWORD attrib = GetFileAttributesW(bufUTF16); - if (attrib == INVALID_FILE_ATTRIBUTES || - !(attrib & FILE_ATTRIBUTE_REPARSE_POINT)) - return false; + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Check if the path exists and is a link + DWORD attrib = GetFileAttributesW(bufUTF16); + if (attrib == INVALID_FILE_ATTRIBUTES || + !(attrib & FILE_ATTRIBUTE_REPARSE_POINT)) + return false; #else - // Check if the path exists and is a link - struct stat st; - if (stat(search.c_str(), &st) == -1) - return false; - if ((st.st_mode & S_IFLNK) == 0) - return false; + // Check if the path exists and is a link + struct stat st; + if (stat(search.c_str(), &st) == -1) + return false; + if ((st.st_mode & S_IFLNK) == 0) + return false; #endif - return true; + return true; } asINT64 CScriptFileSystem::GetSize(const string &path) const { - string search; - if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) - search = path; - else - search = currentPath + "/" + path; + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); - - // Get the size of the file - LARGE_INTEGER largeInt; - HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - BOOL success = GetFileSizeEx(file, &largeInt); - CloseHandle(file); - if( !success ) - return -1; - return asINT64(largeInt.QuadPart); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Get the size of the file + LARGE_INTEGER largeInt; + HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + BOOL success = GetFileSizeEx(file, &largeInt); + CloseHandle(file); + if( !success ) + return -1; + return asINT64(largeInt.QuadPart); #else - // Get the size of the file - struct stat st; - if (stat(search.c_str(), &st) == -1) - return -1; - return asINT64(st.st_size); + // Get the size of the file + struct stat st; + if (stat(search.c_str(), &st) == -1) + return -1; + return asINT64(st.st_size); #endif } @@ -385,244 +385,244 @@ asINT64 CScriptFileSystem::GetSize(const string &path) const // TODO: Should be able to define the permissions for the directory int CScriptFileSystem::MakeDir(const string &path) { - string search; - if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) - search = path; - else - search = currentPath + "/" + path; + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); - // Create the directory - BOOL success = CreateDirectoryW(bufUTF16, 0); - return success ? 0 : -1; + // Create the directory + BOOL success = CreateDirectoryW(bufUTF16, 0); + return success ? 0 : -1; #else - // Create the directory - int failure = mkdir(search.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - return !failure ? 0 : -1; + // Create the directory + int failure = mkdir(search.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + return !failure ? 0 : -1; #endif } -// TODO: Should be able to return different codes for +// TODO: Should be able to return different codes for // - directory doesn't exist // - directory is not empty // - access denied // TODO: Should have an option to remove the directory and all content recursively int CScriptFileSystem::RemoveDir(const string &path) { - string search; - if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) - search = path; - else - search = currentPath + "/" + path; + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); - // Remove the directory - BOOL success = RemoveDirectoryW(bufUTF16); - return success ? 0 : -1; + // Remove the directory + BOOL success = RemoveDirectoryW(bufUTF16); + return success ? 0 : -1; #else - // Remove the directory - int failure = rmdir(search.c_str()); - return !failure ? 0 : -1; + // Remove the directory + int failure = rmdir(search.c_str()); + return !failure ? 0 : -1; #endif } int CScriptFileSystem::DeleteFile(const string &path) { - string search; - if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) - search = path; - else - search = currentPath + "/" + path; + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); - // Remove the file - BOOL success = DeleteFileW(bufUTF16); - return success ? 0 : -1; + // Remove the file + BOOL success = DeleteFileW(bufUTF16); + return success ? 0 : -1; #else - // Remove the file - int failure = unlink(search.c_str()); - return !failure ? 0 : -1; + // Remove the file + int failure = unlink(search.c_str()); + return !failure ? 0 : -1; #endif } int CScriptFileSystem::CopyFile(const string &source, const string &target) { - string search1; - if (source.find(":") != string::npos || source.find("/") == 0 || source.find("\\") == 0) - search1 = source; - else - search1 = currentPath + "/" + source; - - string search2; - if (target.find(":") != string::npos || target.find("/") == 0 || target.find("\\") == 0) - search2 = target; - else - search2 = currentPath + "/" + target; + string search1; + if (source.find(":") != string::npos || source.find("/") == 0 || source.find("\\") == 0) + search1 = source; + else + search1 = currentPath + "/" + source; + + string search2; + if (target.find(":") != string::npos || target.find("/") == 0 || target.find("\\") == 0) + search2 = target; + else + search2 = currentPath + "/" + target; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16_1[10000]; - MultiByteToWideChar(CP_UTF8, 0, search1.c_str(), -1, bufUTF16_1, 10000); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16_1[10000]; + MultiByteToWideChar(CP_UTF8, 0, search1.c_str(), -1, bufUTF16_1, 10000); - wchar_t bufUTF16_2[10000]; - MultiByteToWideChar(CP_UTF8, 0, search2.c_str(), -1, bufUTF16_2, 10000); + wchar_t bufUTF16_2[10000]; + MultiByteToWideChar(CP_UTF8, 0, search2.c_str(), -1, bufUTF16_2, 10000); - // Copy the file - BOOL success = CopyFileW(bufUTF16_1, bufUTF16_2, TRUE); - return success ? 0 : -1; + // Copy the file + BOOL success = CopyFileW(bufUTF16_1, bufUTF16_2, TRUE); + return success ? 0 : -1; #else - // Copy the file manually as there is no posix function for this - bool failure = false; - FILE *src = 0, *tgt = 0; - src = fopen(search1.c_str(), "r"); - if (src == 0) failure = true; - if( !failure ) tgt = fopen(search2.c_str(), "w"); - if (tgt == 0) failure = true; - char buf[1024]; - size_t n; - while (!failure && (n = fread(buf, sizeof(char), sizeof(buf), src)) > 0) - { - if (fwrite(buf, sizeof(char), n, tgt) != n) - failure = true; - } - if (src) fclose(src); - if (tgt) fclose(tgt); - return !failure ? 0 : -1; + // Copy the file manually as there is no posix function for this + bool failure = false; + FILE *src = 0, *tgt = 0; + src = fopen(search1.c_str(), "r"); + if (src == 0) failure = true; + if( !failure ) tgt = fopen(search2.c_str(), "w"); + if (tgt == 0) failure = true; + char buf[1024]; + size_t n; + while (!failure && (n = fread(buf, sizeof(char), sizeof(buf), src)) > 0) + { + if (fwrite(buf, sizeof(char), n, tgt) != n) + failure = true; + } + if (src) fclose(src); + if (tgt) fclose(tgt); + return !failure ? 0 : -1; #endif } int CScriptFileSystem::Move(const string &source, const string &target) { - string search1; - if (source.find(":") != string::npos || source.find("/") == 0 || source.find("\\") == 0) - search1 = source; - else - search1 = currentPath + "/" + source; - - string search2; - if (target.find(":") != string::npos || target.find("/") == 0 || target.find("\\") == 0) - search2 = target; - else - search2 = currentPath + "/" + target; + string search1; + if (source.find(":") != string::npos || source.find("/") == 0 || source.find("\\") == 0) + search1 = source; + else + search1 = currentPath + "/" + source; + + string search2; + if (target.find(":") != string::npos || target.find("/") == 0 || target.find("\\") == 0) + search2 = target; + else + search2 = currentPath + "/" + target; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16_1[10000]; - MultiByteToWideChar(CP_UTF8, 0, search1.c_str(), -1, bufUTF16_1, 10000); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16_1[10000]; + MultiByteToWideChar(CP_UTF8, 0, search1.c_str(), -1, bufUTF16_1, 10000); - wchar_t bufUTF16_2[10000]; - MultiByteToWideChar(CP_UTF8, 0, search2.c_str(), -1, bufUTF16_2, 10000); + wchar_t bufUTF16_2[10000]; + MultiByteToWideChar(CP_UTF8, 0, search2.c_str(), -1, bufUTF16_2, 10000); - // Move the file or directory - BOOL success = MoveFileW(bufUTF16_1, bufUTF16_2); - return success ? 0 : -1; + // Move the file or directory + BOOL success = MoveFileW(bufUTF16_1, bufUTF16_2); + return success ? 0 : -1; #else - // Move the file or directory - int failure = rename(search1.c_str(), search2.c_str()); - return !failure ? 0 : -1; + // Move the file or directory + int failure = rename(search1.c_str(), search2.c_str()); + return !failure ? 0 : -1; #endif } string CScriptFileSystem::GetCurrentPath() const { - return currentPath; + return currentPath; } CDateTime CScriptFileSystem::GetCreateDateTime(const string &path) const { - string search; - if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) - search = path; - else - search = currentPath + "/" + path; + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); - - // Get the create date/time of the file - FILETIME createTm; - HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - BOOL success = GetFileTime(file, &createTm, 0, 0); - CloseHandle(file); - if( !success ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Failed to get file creation date/time"); - return CDateTime(); - } - SYSTEMTIME tm; - FileTimeToSystemTime(&createTm, &tm); - return CDateTime(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Get the create date/time of the file + FILETIME createTm; + HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + BOOL success = GetFileTime(file, &createTm, 0, 0); + CloseHandle(file); + if( !success ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Failed to get file creation date/time"); + return CDateTime(); + } + SYSTEMTIME tm; + FileTimeToSystemTime(&createTm, &tm); + return CDateTime(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond); #else - // Get the create date/time of the file - struct stat st; - if (stat(search.c_str(), &st) == -1) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Failed to get file creation date/time"); - return CDateTime(); - } - tm *t = localtime(&st.st_ctime); - return CDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + // Get the create date/time of the file + struct stat st; + if (stat(search.c_str(), &st) == -1) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Failed to get file creation date/time"); + return CDateTime(); + } + tm *t = localtime(&st.st_ctime); + return CDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); #endif } CDateTime CScriptFileSystem::GetModifyDateTime(const string &path) const { - string search; - if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) - search = path; - else - search = currentPath + "/" + path; + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; #if defined(_WIN32) - // Windows uses UTF16 so it is necessary to convert the string - wchar_t bufUTF16[10000]; - MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); - - // Get the last modify date/time of the file - FILETIME modifyTm; - HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - BOOL success = GetFileTime(file, 0, 0, &modifyTm); - CloseHandle(file); - if( !success ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Failed to get file modify date/time"); - return CDateTime(); - } - SYSTEMTIME tm; - FileTimeToSystemTime(&modifyTm, &tm); - return CDateTime(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond); + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Get the last modify date/time of the file + FILETIME modifyTm; + HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + BOOL success = GetFileTime(file, 0, 0, &modifyTm); + CloseHandle(file); + if( !success ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Failed to get file modify date/time"); + return CDateTime(); + } + SYSTEMTIME tm; + FileTimeToSystemTime(&modifyTm, &tm); + return CDateTime(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond); #else - // Get the last modify date/time of the file - struct stat st; - if (stat(search.c_str(), &st) == -1) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Failed to get file modify date/time"); - return CDateTime(); - } - tm *t = localtime(&st.st_mtime); - return CDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + // Get the last modify date/time of the file + struct stat st; + if (stat(search.c_str(), &st) == -1) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Failed to get file modify date/time"); + return CDateTime(); + } + tm *t = localtime(&st.st_mtime); + return CDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); #endif } diff --git a/src/angelscript/add_on/scriptfile/scriptfilesystem.h b/src/angelscript/add_on/scriptfile/scriptfilesystem.h index 5712d7ce63d..6aa8ebac3be 100644 --- a/src/angelscript/add_on/scriptfile/scriptfilesystem.h +++ b/src/angelscript/add_on/scriptfile/scriptfilesystem.h @@ -1,7 +1,7 @@ #ifndef AS_SCRIPTFILESYSTEM_H #define AS_SCRIPTFILESYSTEM_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -17,58 +17,58 @@ BEGIN_AS_NAMESPACE class CScriptFileSystem { public: - CScriptFileSystem(); + CScriptFileSystem(); - void AddRef() const; - void Release() const; + void AddRef() const; + void Release() const; - // Sets the current path that should be used in other calls when using relative paths - // It can use relative paths too, so moving up a directory is used by passing in ".." - bool ChangeCurrentPath(const std::string &path); - std::string GetCurrentPath() const; + // Sets the current path that should be used in other calls when using relative paths + // It can use relative paths too, so moving up a directory is used by passing in ".." + bool ChangeCurrentPath(const std::string &path); + std::string GetCurrentPath() const; - // Returns true if the path is a directory. Input can be either a full path or a relative path. - // This method does not return the dirs '.' and '..' - bool IsDir(const std::string &path) const; + // Returns true if the path is a directory. Input can be either a full path or a relative path. + // This method does not return the dirs '.' and '..' + bool IsDir(const std::string &path) const; - // Returns true if the path is a link. Input can be either a full path or a relative path - bool IsLink(const std::string &path) const; + // Returns true if the path is a link. Input can be either a full path or a relative path + bool IsLink(const std::string &path) const; - // Returns the size of file. Input can be either a full path or a relative path - asINT64 GetSize(const std::string &path) const; + // Returns the size of file. Input can be either a full path or a relative path + asINT64 GetSize(const std::string &path) const; - // Returns a list of the files in the current path - CScriptArray *GetFiles() const; + // Returns a list of the files in the current path + CScriptArray *GetFiles() const; - // Returns a list of the directories in the current path - CScriptArray *GetDirs() const; + // Returns a list of the directories in the current path + CScriptArray *GetDirs() const; - // Creates a new directory. Returns 0 on success - int MakeDir(const std::string &path); + // Creates a new directory. Returns 0 on success + int MakeDir(const std::string &path); - // Removes a directory. Will only remove the directory if it is empty. Returns 0 on success - int RemoveDir(const std::string &path); + // Removes a directory. Will only remove the directory if it is empty. Returns 0 on success + int RemoveDir(const std::string &path); - // Deletes a file. Returns 0 on success - int DeleteFile(const std::string &path); + // Deletes a file. Returns 0 on success + int DeleteFile(const std::string &path); - // Copies a file. Returns 0 on success - int CopyFile(const std::string &source, const std::string &target); + // Copies a file. Returns 0 on success + int CopyFile(const std::string &source, const std::string &target); - // Moves or renames a file or directory. Returns 0 on success - int Move(const std::string &source, const std::string &target); - - // Gets the date and time of the file/dir creation - CDateTime GetCreateDateTime(const std::string &path) const; + // Moves or renames a file or directory. Returns 0 on success + int Move(const std::string &source, const std::string &target); - // Gets the date and time of the file/dir modification - CDateTime GetModifyDateTime(const std::string &path) const; + // Gets the date and time of the file/dir creation + CDateTime GetCreateDateTime(const std::string &path) const; + + // Gets the date and time of the file/dir modification + CDateTime GetModifyDateTime(const std::string &path) const; protected: - ~CScriptFileSystem(); + ~CScriptFileSystem(); - mutable int refCount; - std::string currentPath; + mutable int refCount; + std::string currentPath; }; void RegisterScriptFileSystem(asIScriptEngine *engine); diff --git a/src/angelscript/add_on/scriptgrid/scriptgrid.cpp b/src/angelscript/add_on/scriptgrid/scriptgrid.cpp index f636267e430..b86e74ce44a 100644 --- a/src/angelscript/add_on/scriptgrid/scriptgrid.cpp +++ b/src/angelscript/add_on/scriptgrid/scriptgrid.cpp @@ -18,79 +18,79 @@ 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; + userAlloc = allocFunc; + userFree = freeFunc; } static void RegisterScriptGrid_Native(asIScriptEngine *engine); struct SGridBuffer { - asDWORD width; - asDWORD height; - asBYTE data[1]; + asDWORD width; + asDWORD height; + asBYTE data[1]; }; CScriptGrid *CScriptGrid::Create(asITypeInfo *ti) { - return CScriptGrid::Create(ti, 0, 0); + return CScriptGrid::Create(ti, 0, 0); } CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h) { - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptGrid)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptGrid)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); - return 0; - } + return 0; + } - // Initialize the object - CScriptGrid *a = new(mem) CScriptGrid(w, h, ti); + // Initialize the object + CScriptGrid *a = new(mem) CScriptGrid(w, h, ti); - return a; + return a; } CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, void *initList) { - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptGrid)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptGrid)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); - return 0; - } + return 0; + } - // Initialize the object - CScriptGrid *a = new(mem) CScriptGrid(ti, initList); + // Initialize the object + CScriptGrid *a = new(mem) CScriptGrid(ti, initList); - return a; + return a; } CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h, void *defVal) { - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptGrid)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptGrid)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); - return 0; - } + return 0; + } - // Initialize the object - CScriptGrid *a = new(mem) CScriptGrid(w, h, defVal, ti); + // Initialize the object + CScriptGrid *a = new(mem) CScriptGrid(w, h, defVal, ti); - return a; + return a; } // This optional callback is called when the template type is first used by the compiler. @@ -100,708 +100,708 @@ CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h, void *defV // i.e. no asOBJ_GC flag. static bool ScriptGridTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect) { - // Make sure the subtype can be instantiated with a default factory/constructor, - // otherwise we won't be able to instantiate the elements. - int typeId = ti->GetSubTypeId(); - if( typeId == asTYPEID_VOID ) - return false; - if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) - { - asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(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 - ti->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( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) - { - // Verify that there is a default factory - for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) - { - asIScriptFunction *func = subtype->GetFactoryByIndex(n); - if( func->GetParamCount() == 0 ) - { - // Found the default factory - found = true; - break; - } - } - } - - if( !found ) - { - // No default factory - ti->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; - } - else - { - assert( typeId & asTYPEID_OBJHANDLE ); - - // It is not necessary to set the array as garbage collected for all handle types. - // If it is possible to determine that the handle cannot refer to an object type - // that can potentially form a circular reference with the array then it is not - // necessary to make the array garbage collected. - asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); - asDWORD flags = subtype->GetFlags(); - if( !(flags & asOBJ_GC) ) - { - if( (flags & asOBJ_SCRIPT_OBJECT) ) - { - // Even if a script class is by itself not garbage collected, it is possible - // that classes that derive from it may be, so it is not possible to know - // that no circular reference can occur. - if( (flags & asOBJ_NOINHERIT) ) - { - // A script class declared as final cannot be inherited from, thus - // we can be certain that the object cannot be garbage collected. - dontGarbageCollect = true; - } - } - else - { - // For application registered classes we assume the application knows - // what it is doing and don't mark the array as garbage collected unless - // the type is also garbage collected. - dontGarbageCollect = true; - } - } - } - - // The type is ok - return true; + // Make sure the subtype can be instantiated with a default factory/constructor, + // otherwise we won't be able to instantiate the elements. + int typeId = ti->GetSubTypeId(); + if( typeId == asTYPEID_VOID ) + return false; + if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) + { + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(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 + ti->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( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) + { + // Verify that there is a default factory + for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) + { + asIScriptFunction *func = subtype->GetFactoryByIndex(n); + if( func->GetParamCount() == 0 ) + { + // Found the default factory + found = true; + break; + } + } + } + + if( !found ) + { + // No default factory + ti->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; + } + else + { + assert( typeId & asTYPEID_OBJHANDLE ); + + // It is not necessary to set the array as garbage collected for all handle types. + // If it is possible to determine that the handle cannot refer to an object type + // that can potentially form a circular reference with the array then it is not + // necessary to make the array garbage collected. + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); + asDWORD flags = subtype->GetFlags(); + if( !(flags & asOBJ_GC) ) + { + if( (flags & asOBJ_SCRIPT_OBJECT) ) + { + // Even if a script class is by itself not garbage collected, it is possible + // that classes that derive from it may be, so it is not possible to know + // that no circular reference can occur. + if( (flags & asOBJ_NOINHERIT) ) + { + // A script class declared as final cannot be inherited from, thus + // we can be certain that the object cannot be garbage collected. + dontGarbageCollect = true; + } + } + else + { + // For application registered classes we assume the application knows + // what it is doing and don't mark the array as garbage collected unless + // the type is also garbage collected. + 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); + // TODO: Implement the generic calling convention + RegisterScriptGrid_Native(engine); } static void RegisterScriptGrid_Native(asIScriptEngine *engine) { - int r; + int r; - // Register the grid type as a template - r = engine->RegisterObjectType("grid", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); + // 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 ); + // 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, (asITypeInfo*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("grid", asBEHAVE_FACTORY, "grid@ f(int&in, uint, uint)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, 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, (asITypeInfo*, asUINT, asUINT, void *), CScriptGrid*), 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, (asITypeInfo*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_FACTORY, "grid@ f(int&in, uint, uint)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, 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, (asITypeInfo*, 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, (asITypeInfo*, 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, (asITypeInfo*, 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 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 ); + // 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 ); + // 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 ); + // 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(asITypeInfo *ti, void *buf) { - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; - subTypeId = objType->GetSubTypeId(); - - asIScriptEngine *engine = ti->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 = height ? *(asUINT*)((char*)(buf)+4) : 0; - - // 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( (ti->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( ti->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( ti->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 - asITypeInfo *subType = ti->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); + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + subTypeId = objType->GetSubTypeId(); + + asIScriptEngine *engine = ti->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 = height ? *(asUINT*)((char*)(buf)+4) : 0; + + // 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( (ti->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( ti->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( ti->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 + asITypeInfo *subType = ti->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, asITypeInfo *ti) { - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; - subTypeId = objType->GetSubTypeId(); + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + subTypeId = objType->GetSubTypeId(); - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + // 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; - } + // 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); + CreateBuffer(&buffer, width, height); - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + // 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; + // 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; + // 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)); + 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); - } + // Replace the internal buffer + DeleteBuffer(buffer); + } - buffer = tmpBuffer; + buffer = tmpBuffer; } CScriptGrid::CScriptGrid(asUINT width, asUINT height, void *defVal, asITypeInfo *ti) { - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; - subTypeId = objType->GetSubTypeId(); + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + subTypeId = objType->GetSubTypeId(); - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + // 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; - } + // 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); + CreateBuffer(&buffer, width, height); - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + // 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); + // 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); + 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; + // 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(); + if( buffer ) + { + DeleteBuffer(buffer); + buffer = 0; + } + if( objType ) objType->Release(); } asUINT CScriptGrid::GetWidth() const { - if( buffer ) - return buffer->width; + if( buffer ) + return buffer->width; - return 0; + return 0; } asUINT CScriptGrid::GetHeight() const { - if( buffer ) - return buffer->height; + if( buffer ) + return buffer->height; - return 0; + 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 + // 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; + asUINT maxSize = 0xFFFFFFFFul - sizeof(SGridBuffer) + 1; + if( elementSize > 0 ) + maxSize /= elementSize; - asINT64 numElements = width * height; + asINT64 numElements = width * height; - if( (numElements >> 32) || numElements > maxSize ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Too large grid size"); + if( (numElements >> 32) || numElements > maxSize ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Too large grid size"); - return false; - } + return false; + } - // OK - return true; + // OK + return true; } asITypeInfo *CScriptGrid::GetGridObjectType() const { - return objType; + return objType; } int CScriptGrid::GetGridTypeId() const { - return objType->GetTypeId(); + return objType->GetTypeId(); } int CScriptGrid::GetElementTypeId() const { - return subTypeId; + return subTypeId; } void *CScriptGrid::At(asUINT x, asUINT y) { - return At(buffer, x, 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; + 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); + return const_cast(this)->At(const_cast(buffer), x, y); } // internal void CScriptGrid::CreateBuffer(SGridBuffer **buf, asUINT w, asUINT h) { - asUINT numElements = w * h; + asUINT numElements = w * h; - *buf = reinterpret_cast(userAlloc(sizeof(SGridBuffer)-1+elementSize*numElements)); + *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"); - } + 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 ); + assert( buf ); - Destruct(buf); + Destruct(buf); - // Free the buffer - userFree(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(); - asITypeInfo *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; - } - } - } + 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(); + asITypeInfo *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 ); + assert( buf ); - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - asIScriptEngine *engine = objType->GetEngine(); + 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); + 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()); - } - } + for( ; d < max; d++ ) + { + if( *d ) + engine->ReleaseScriptObject(*d, objType->GetSubType()); + } + } } // GC behaviour void CScriptGrid::EnumReferences(asIScriptEngine *engine) { - if( buffer == 0 ) return; - - // If the grid 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; - asITypeInfo *subType = engine->GetTypeInfoById(subTypeId); - if ((subType->GetFlags() & asOBJ_REF)) - { - // For reference types we need to notify the GC of each instance - for (asUINT n = 0; n < numElements; n++) - { - if (d[n]) - engine->GCEnumCallback(d[n]); - } - } - else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) - { - // For value types we need to forward the enum callback - // to the object so it can decide what to do - for (asUINT n = 0; n < numElements; n++) - { - if (d[n]) - engine->ForwardGCEnumReferences(d[n], subType); - } - } - } + if( buffer == 0 ) return; + + // If the grid 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; + asITypeInfo *subType = engine->GetTypeInfoById(subTypeId); + if ((subType->GetFlags() & asOBJ_REF)) + { + // For reference types we need to notify the GC of each instance + for (asUINT n = 0; n < numElements; n++) + { + if (d[n]) + engine->GCEnumCallback(d[n]); + } + } + else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + for (asUINT n = 0; n < numElements; n++) + { + if (d[n]) + engine->ForwardGCEnumReferences(d[n], subType); + } + } + } } // GC behaviour void CScriptGrid::ReleaseAllHandles(asIScriptEngine*) { - if( buffer == 0 ) return; + if( buffer == 0 ) return; - DeleteBuffer(buffer); - buffer = 0; + DeleteBuffer(buffer); + buffer = 0; } void CScriptGrid::AddRef() const { - // Clear the GC flag then increase the counter - gcFlag = false; - asAtomicInc(refCount); + // 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)); - } + // 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; + return refCount; } // GC behaviour void CScriptGrid::SetFlag() { - gcFlag = true; + gcFlag = true; } // GC behaviour bool CScriptGrid::GetFlag() { - return gcFlag; + return gcFlag; } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scriptgrid/scriptgrid.h b/src/angelscript/add_on/scriptgrid/scriptgrid.h index feeb167f692..b9c9749a01f 100644 --- a/src/angelscript/add_on/scriptgrid/scriptgrid.h +++ b/src/angelscript/add_on/scriptgrid/scriptgrid.h @@ -1,7 +1,7 @@ #ifndef SCRIPTGRID_H #define SCRIPTGRID_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -13,66 +13,66 @@ 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(asITypeInfo *ot); - static CScriptGrid *Create(asITypeInfo *ot, asUINT width, asUINT height); - static CScriptGrid *Create(asITypeInfo *ot, asUINT width, asUINT height, void *defaultValue); - static CScriptGrid *Create(asITypeInfo *ot, void *listBuffer); - - // Memory management - void AddRef() const; - void Release() const; - - // Type information - asITypeInfo *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); + // 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(asITypeInfo *ot); + static CScriptGrid *Create(asITypeInfo *ot, asUINT width, asUINT height); + static CScriptGrid *Create(asITypeInfo *ot, asUINT width, asUINT height, void *defaultValue); + static CScriptGrid *Create(asITypeInfo *ot, void *listBuffer); + + // Memory management + void AddRef() const; + void Release() const; + + // Type information + asITypeInfo *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; - asITypeInfo *objType; - SGridBuffer *buffer; - int elementSize; - int subTypeId; - - // Constructors - CScriptGrid(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list - CScriptGrid(asUINT w, asUINT h, asITypeInfo *ot); - CScriptGrid(asUINT w, asUINT h, void *defVal, asITypeInfo *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); + mutable int refCount; + mutable bool gcFlag; + asITypeInfo *objType; + SGridBuffer *buffer; + int elementSize; + int subTypeId; + + // Constructors + CScriptGrid(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list + CScriptGrid(asUINT w, asUINT h, asITypeInfo *ot); + CScriptGrid(asUINT w, asUINT h, void *defVal, asITypeInfo *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); diff --git a/src/angelscript/add_on/scripthandle/scripthandle.cpp b/src/angelscript/add_on/scripthandle/scripthandle.cpp index df6cbbe4589..3bd7d1bc1f7 100644 --- a/src/angelscript/add_on/scripthandle/scripthandle.cpp +++ b/src/angelscript/add_on/scripthandle/scripthandle.cpp @@ -13,347 +13,347 @@ static void Destruct(CScriptHandle *self) { self->~CScriptHandle(); } CScriptHandle::CScriptHandle() { - m_ref = 0; - m_type = 0; + m_ref = 0; + m_type = 0; } CScriptHandle::CScriptHandle(const CScriptHandle &other) { - m_ref = other.m_ref; - m_type = other.m_type; + m_ref = other.m_ref; + m_type = other.m_type; - AddRefHandle(); + AddRefHandle(); } CScriptHandle::CScriptHandle(void *ref, asITypeInfo *type) { - m_ref = ref; - m_type = type; + m_ref = ref; + m_type = type; - AddRefHandle(); + AddRefHandle(); } -// This constructor shouldn't be called from the application +// 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; + m_ref = 0; + m_type = 0; - Assign(ref, typeId); + Assign(ref, typeId); } CScriptHandle::~CScriptHandle() { - ReleaseHandle(); + ReleaseHandle(); } void CScriptHandle::ReleaseHandle() { - if( m_ref && m_type ) - { - asIScriptEngine *engine = m_type->GetEngine(); - engine->ReleaseScriptObject(m_ref, m_type); + if( m_ref && m_type ) + { + asIScriptEngine *engine = m_type->GetEngine(); + engine->ReleaseScriptObject(m_ref, m_type); - engine->Release(); + engine->Release(); - m_ref = 0; - m_type = 0; - } + 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); + 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(); - } + // 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); + Set(other.m_ref, other.m_type); - return *this; + return *this; } void CScriptHandle::Set(void *ref, asITypeInfo *type) { - if( m_ref == ref ) return; + if( m_ref == ref ) return; - ReleaseHandle(); + ReleaseHandle(); - m_ref = ref; - m_type = type; + m_ref = ref; + m_type = type; - AddRefHandle(); + AddRefHandle(); } void *CScriptHandle::GetRef() { - return m_ref; + return m_ref; } asITypeInfo *CScriptHandle::GetType() const { - return m_type; + return m_type; } int CScriptHandle::GetTypeId() const { - if( m_type == 0 ) return 0; + if( m_type == 0 ) return 0; - return m_type->GetTypeId() | asTYPEID_OBJHANDLE; + return m_type->GetTypeId() | asTYPEID_OBJHANDLE; } -// This method shouldn't be called from the application +// 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; - } + // 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; - } + // 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(); - asITypeInfo *type = engine->GetTypeInfoById(typeId); + // Get the object type + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); + asITypeInfo *type = engine->GetTypeInfoById(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; - } + // 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); + Set(ref, type); - return *this; + return *this; } bool CScriptHandle::operator==(const CScriptHandle &o) const { - if( m_ref == o.m_ref && - m_type == o.m_type ) - return true; + 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 + // 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; + return false; } bool CScriptHandle::operator!=(const CScriptHandle &o) const { - return !(*this == o); + 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; + // 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; - } + // 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 + // 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; + if( ref == m_ref ) return true; - return false; + 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 ); + // If we hold a null handle, then just return null + if( m_type == 0 ) + { + *outRef = 0; + return; + } - // Compare the type id of the actual object - typeId &= ~asTYPEID_OBJHANDLE; - asIScriptEngine *engine = m_type->GetEngine(); - asITypeInfo *type = engine->GetTypeInfoById(typeId); + // It is expected that the outRef is always a handle + assert( typeId & asTYPEID_OBJHANDLE ); - *outRef = 0; + // Compare the type id of the actual object + typeId &= ~asTYPEID_OBJHANDLE; + asIScriptEngine *engine = m_type->GetEngine(); + asITypeInfo *type = engine->GetTypeInfoById(typeId); - // RefCastObject will increment the refCount of the returned object if successful - engine->RefCastObject(m_ref, m_type, type, outRef); + *outRef = 0; + + // RefCastObject will increment the refCount of the returned object if successful + engine->RefCastObject(m_ref, m_type, type, outRef); } void CScriptHandle::EnumReferences(asIScriptEngine *inEngine) { - // If we're holding a reference, we'll notify the garbage collector of it - if (m_ref) - inEngine->GCEnumCallback(m_ref); + // If we're holding a reference, we'll notify the garbage collector of it + if (m_ref) + inEngine->GCEnumCallback(m_ref); - // The object type itself is also garbage collected - if( m_type) - inEngine->GCEnumCallback(m_type); + // The object type itself is also garbage collected + if( m_type) + inEngine->GCEnumCallback(m_type); } void CScriptHandle::ReleaseReferences(asIScriptEngine *inEngine) { - // Simply clear the content to release the references - Set(0, 0); + // Simply clear the content to release the references + Set(0, 0); } void RegisterScriptHandle_Native(asIScriptEngine *engine) { - int r; + int r; #if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class - r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); + // With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); #else - r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); #endif - 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_ENUMREFS, "void f(int&in)", asMETHOD(CScriptHandle,EnumReferences), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptHandle, ReleaseReferences), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("ref", "void opCast(?&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 ); + 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_ENUMREFS, "void f(int&in)", asMETHOD(CScriptHandle,EnumReferences), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptHandle, ReleaseReferences), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("ref", "void opCast(?&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(); + 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); + 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 *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(); + 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 **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); + 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 *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); + 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 *ref = gen->GetArgAddress(0); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + gen->SetReturnByte(self->Equals(ref, typeId)); } void CScriptHandle_EnumReferences_Generic(asIScriptGeneric *gen) { - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->EnumReferences(gen->GetEngine()); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->EnumReferences(gen->GetEngine()); } void CScriptHandle_ReleaseReferences_Generic(asIScriptGeneric *gen) { - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->ReleaseReferences(gen->GetEngine()); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->ReleaseReferences(gen->GetEngine()); } void RegisterScriptHandle_Generic(asIScriptEngine *engine) { - int r; + int r; - r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | 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_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptHandle_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptHandle_ReleaseReferences_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | 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_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptHandle_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptHandle_ReleaseReferences_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&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); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptHandle_Generic(engine); + else + RegisterScriptHandle_Native(engine); } diff --git a/src/angelscript/add_on/scripthandle/scripthandle.h b/src/angelscript/add_on/scripthandle/scripthandle.h index 7adf1b79314..abd260fed38 100644 --- a/src/angelscript/add_on/scripthandle/scripthandle.h +++ b/src/angelscript/add_on/scripthandle/scripthandle.h @@ -1,7 +1,7 @@ #ifndef SCRIPTHANDLE_H #define SCRIPTHANDLE_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -9,57 +9,57 @@ BEGIN_AS_NAMESPACE -class CScriptHandle +class CScriptHandle { public: - // Constructors - CScriptHandle(); - CScriptHandle(const CScriptHandle &other); - CScriptHandle(void *ref, asITypeInfo *type); - ~CScriptHandle(); + // Constructors + CScriptHandle(); + CScriptHandle(const CScriptHandle &other); + CScriptHandle(void *ref, asITypeInfo *type); + ~CScriptHandle(); - // Copy the stored value from another any object - CScriptHandle &operator=(const CScriptHandle &other); + // Copy the stored value from another any object + CScriptHandle &operator=(const CScriptHandle &other); - // Set the reference - void Set(void *ref, asITypeInfo *type); + // Set the reference + void Set(void *ref, asITypeInfo *type); - // Compare equalness - bool operator==(const CScriptHandle &o) const; - bool operator!=(const CScriptHandle &o) const; - bool Equals(void *ref, int typeId) const; + // 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); + // Dynamic cast to desired handle type + void Cast(void **outRef, int typeId); - // Returns the type of the reference held - asITypeInfo *GetType() const; - int GetTypeId() const; + // Returns the type of the reference held + asITypeInfo *GetType() const; + int GetTypeId() const; - // Get the reference - void *GetRef(); + // Get the reference + void *GetRef(); - // GC callback - void EnumReferences(asIScriptEngine *engine); - void ReleaseReferences(asIScriptEngine *engine); + // GC callback + void EnumReferences(asIScriptEngine *engine); + void ReleaseReferences(asIScriptEngine *engine); 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; - asITypeInfo *m_type; + // 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; + asITypeInfo *m_type; }; void RegisterScriptHandle(asIScriptEngine *engine); diff --git a/src/angelscript/add_on/scripthelper/scripthelper.cpp b/src/angelscript/add_on/scripthelper/scripthelper.cpp index 4af4fde4195..d5f2a1f7841 100644 --- a/src/angelscript/add_on/scripthelper/scripthelper.cpp +++ b/src/angelscript/add_on/scripthelper/scripthelper.cpp @@ -15,973 +15,973 @@ int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, // 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; - - asITypeInfo *ti = engine->GetTypeInfoById(typeId); - if( ti ) - { - // Check if the object type has a compatible opCmp method - for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) - { - asIScriptFunction *f = ti->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 retval = -1; + asIScriptFunction *func = 0; + + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti ) + { + // Check if the object type has a compatible opCmp method + for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) + { + asIScriptFunction *f = ti->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; - - asITypeInfo *ti = engine->GetTypeInfoById(typeId); - if( ti ) - { - // Check if the object type has a compatible opEquals method - for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) - { - asIScriptFunction *f = ti->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; + // entry in a set, then the method and context should be cached between calls. + + int retval = -1; + asIScriptFunction *func = 0; + + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti ) + { + // Check if the object type has a compatible opEquals method + for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) + { + asIScriptFunction *f = ti->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); + 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 - asITypeInfo *type = 0; - if( refTypeId & asTYPEID_MASK_OBJECT ) - { - type = engine->GetTypeInfoById(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->RequestContext(); - r = execCtx->Prepare(func); - if (r >= 0) - { - // 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->GetTypeInfoById(refTypeId)); - } - else if (refTypeId & asTYPEID_MASK_OBJECT) - { - // Use the registered assignment operator to do a value assign. - // This assumes that the ref is pointing to a valid object instance. - engine->AssignScriptObject(ref, execCtx->GetAddressOfReturnValue(), engine->GetTypeInfoById(refTypeId)); - } - else - { - // Copy the primitive value - memcpy(ref, execCtx->GetAddressOfReturnValue(), engine->GetSizeOfPrimitiveType(refTypeId)); - } - } - } - - // Clean up - func->Release(); - if( !ctx ) engine->ReturnContext(execCtx); - - return r; + // 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 + asITypeInfo *type = 0; + if( refTypeId & asTYPEID_MASK_OBJECT ) + { + type = engine->GetTypeInfoById(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->RequestContext(); + r = execCtx->Prepare(func); + if (r >= 0) + { + // 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->GetTypeInfoById(refTypeId)); + } + else if (refTypeId & asTYPEID_MASK_OBJECT) + { + // Use the registered assignment operator to do a value assign. + // This assumes that the ref is pointing to a valid object instance. + engine->AssignScriptObject(ref, execCtx->GetAddressOfReturnValue(), engine->GetTypeInfoById(refTypeId)); + } + else + { + // Copy the primitive value + memcpy(ref, execCtx->GetAddressOfReturnValue(), engine->GetSizeOfPrimitiveType(refTypeId)); + } + } + } + + // Clean up + func->Release(); + if( !ctx ) engine->ReturnContext(execCtx); + + return r; } int WriteConfigToFile(asIScriptEngine *engine, const char *filename) { - ofstream strm; - strm.open(filename); + ofstream strm; + strm.open(filename); - return WriteConfigToStream(engine, strm); + 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 = ""; - engine->SetDefaultNamespace(""); - - // 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++ ) - { - asITypeInfo *ti = engine->GetEnumByIndex(n); - asDWORD accessMask = ti->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - const char *nameSpace = ti->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - const char *enumName = ti->GetName(); - strm << "enum " << enumName << "\n"; - for( asUINT m = 0; m < ti->GetEnumValueCount(); m++ ) - { - const char *valName; - int val; - valName = ti->GetEnumValueByIndex(m, &val); - strm << "enumval " << enumName << " " << valName << " " << val << "\n"; - } - } - - // Enumerate all types - strm << "\n// Types\n"; - - // Keep a list of the template types, as the methods for these need to be exported first - set templateTypes; - - c = engine->GetObjectTypeCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *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; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - 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() & asOBJ_MASK_VALID_FLAGS) << "\n"; - - // Store the template types (but not template instances) - if( (type->GetFlags() & asOBJ_TEMPLATE) && type->GetSubType() && (type->GetSubType()->GetFlags() & asOBJ_TEMPLATE_SUBTYPE) ) - templateTypes.insert(type); - } - } - - c = engine->GetTypedefCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *ti = engine->GetTypedefByIndex(n); - const char *nameSpace = ti->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - asDWORD accessMask = ti->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "typedef " << ti->GetName() << " \"" << engine->GetTypeDeclaration(ti->GetTypedefTypeId()) << "\"\n"; - } - - c = engine->GetFuncdefCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *funcDef = engine->GetFuncdefByIndex(n); - asDWORD accessMask = funcDef->GetAccessMask(); - const char *nameSpace = funcDef->GetNamespace(); - // Child funcdefs do not have any namespace, as they belong to the parent object - if( nameSpace && nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "funcdef \"" << funcDef->GetFuncdefSignature()->GetDeclaration() << "\"\n"; - } - - // A helper for writing object type members - struct TypeWriter - { - static void Write(asIScriptEngine *engine, ostream &strm, asITypeInfo *type, string &currNamespace, asDWORD &currAccessMask) - { - const char *nameSpace = type->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - 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() << (func->IsProperty() ? " property" : "") << "\"\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() << (func->IsProperty() ? " property" : "") << "\"\n"; - } - for( m = 0; m < type->GetPropertyCount(); m++ ) - { - asDWORD accessMask; - type->GetProperty(m, 0, 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) << "\""; - - // Save information about composite properties - int compositeOffset; - bool isCompositeIndirect; - type->GetProperty(m, 0, 0, 0, 0, 0, 0, 0, &compositeOffset, &isCompositeIndirect); - strm << " " << compositeOffset << " " << (isCompositeIndirect ? "1" : "0") << "\n"; - } - } - } - }; - - // Write the members of the template types, so they can be fully registered before any other type uses them - // TODO: Order the template types based on dependency to avoid failure if one type uses instances of another - strm << "\n// Template type members\n"; - for( set::iterator it = templateTypes.begin(); it != templateTypes.end(); ++it ) - { - asITypeInfo *type = *it; - TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); - } - - // Write the object types members - strm << "\n// Type members\n"; - - c = engine->GetObjectTypeCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *type = engine->GetObjectTypeByIndex(n); - if( templateTypes.find(type) == templateTypes.end() ) - TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); - } - - // 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; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - 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() << (func->IsProperty() ? " property" : "") << "\"\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; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - strm << "prop \"" << (isConst ? "const " : "") << engine->GetTypeDeclaration(typeId) << " " << name << "\"\n"; - } - - // Write string factory - strm << "\n// String factory\n"; - - // Reset the namespace for the string factory and default array type - if ("" != currNamespace) - { - strm << "namespace \"\"\n"; - currNamespace = ""; - engine->SetDefaultNamespace(""); - } - - 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; + // 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 = ""; + engine->SetDefaultNamespace(""); + + // 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++ ) + { + asITypeInfo *ti = engine->GetEnumByIndex(n); + asDWORD accessMask = ti->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + const char *nameSpace = ti->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + const char *enumName = ti->GetName(); + strm << "enum " << enumName << "\n"; + for( asUINT m = 0; m < ti->GetEnumValueCount(); m++ ) + { + const char *valName; + int val; + valName = ti->GetEnumValueByIndex(m, &val); + strm << "enumval " << enumName << " " << valName << " " << val << "\n"; + } + } + + // Enumerate all types + strm << "\n// Types\n"; + + // Keep a list of the template types, as the methods for these need to be exported first + set templateTypes; + + c = engine->GetObjectTypeCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *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; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + 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() & asOBJ_MASK_VALID_FLAGS) << "\n"; + + // Store the template types (but not template instances) + if( (type->GetFlags() & asOBJ_TEMPLATE) && type->GetSubType() && (type->GetSubType()->GetFlags() & asOBJ_TEMPLATE_SUBTYPE) ) + templateTypes.insert(type); + } + } + + c = engine->GetTypedefCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *ti = engine->GetTypedefByIndex(n); + const char *nameSpace = ti->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + asDWORD accessMask = ti->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "typedef " << ti->GetName() << " \"" << engine->GetTypeDeclaration(ti->GetTypedefTypeId()) << "\"\n"; + } + + c = engine->GetFuncdefCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *funcDef = engine->GetFuncdefByIndex(n); + asDWORD accessMask = funcDef->GetAccessMask(); + const char *nameSpace = funcDef->GetNamespace(); + // Child funcdefs do not have any namespace, as they belong to the parent object + if( nameSpace && nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "funcdef \"" << funcDef->GetFuncdefSignature()->GetDeclaration() << "\"\n"; + } + + // A helper for writing object type members + struct TypeWriter + { + static void Write(asIScriptEngine *engine, ostream &strm, asITypeInfo *type, string &currNamespace, asDWORD &currAccessMask) + { + const char *nameSpace = type->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + 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() << (func->IsProperty() ? " property" : "") << "\"\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() << (func->IsProperty() ? " property" : "") << "\"\n"; + } + for( m = 0; m < type->GetPropertyCount(); m++ ) + { + asDWORD accessMask; + type->GetProperty(m, 0, 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) << "\""; + + // Save information about composite properties + int compositeOffset; + bool isCompositeIndirect; + type->GetProperty(m, 0, 0, 0, 0, 0, 0, 0, &compositeOffset, &isCompositeIndirect); + strm << " " << compositeOffset << " " << (isCompositeIndirect ? "1" : "0") << "\n"; + } + } + } + }; + + // Write the members of the template types, so they can be fully registered before any other type uses them + // TODO: Order the template types based on dependency to avoid failure if one type uses instances of another + strm << "\n// Template type members\n"; + for( set::iterator it = templateTypes.begin(); it != templateTypes.end(); ++it ) + { + asITypeInfo *type = *it; + TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); + } + + // Write the object types members + strm << "\n// Type members\n"; + + c = engine->GetObjectTypeCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *type = engine->GetObjectTypeByIndex(n); + if( templateTypes.find(type) == templateTypes.end() ) + TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); + } + + // 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; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + 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() << (func->IsProperty() ? " property" : "") << "\"\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; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + strm << "prop \"" << (isConst ? "const " : "") << engine->GetTypeDeclaration(typeId) << " " << name << "\"\n"; + } + + // Write string factory + strm << "\n// String factory\n"; + + // Reset the namespace for the string factory and default array type + if ("" != currNamespace) + { + strm << "namespace \"\"\n"; + currNamespace = ""; + engine->SetDefaultNamespace(""); + } + + 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, asIStringFactory *stringFactory) { - int r; - - // Some helper functions for parsing the configuration - struct in - { - static asETokenClass GetToken(asIScriptEngine *engine, string &token, const string &text, asUINT &pos) - { - asUINT len = 0; - 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() && strm.good() ); - - // 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 - if( ep != asEP_COPY_SCRIPT_SECTIONS && - ep != asEP_MAX_STACK_SIZE && - ep != asEP_INIT_GLOBAL_VARS_AFTER_BUILD && - ep != asEP_EXPAND_DEF_ARRAY_TO_TMPL && - ep != asEP_AUTO_GARBAGE_COLLECT ) - { - // Get the value for the property - in::GetToken(engine, tmp, config, pos); - stringstream s(tmp); - asPWORD value; - - s >> value; - - engine->SetEngineProperty(ep, value); - } - } - else if( token == "namespace" ) - { - string ns; - in::GetToken(engine, ns, config, pos); - ns = ns.substr(1, ns.length() - 2); - - 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 = strtoul(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); - - // Remove the $ that the engine prefixes the behaviours with - size_t n = decl.find("$"); - if( n != string::npos ) - decl[n] = ' '; - - 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, compositeOffset, isCompositeIndirect; - 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::GetToken(engine, compositeOffset, config, pos); - in::GetToken(engine, isCompositeIndirect, config, pos); - - asITypeInfo *type = engine->GetTypeInfoById(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(), compositeOffset != "0" ? type->GetPropertyCount() : 0, isCompositeIndirect != "0"); - 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(), reinterpret_cast(asPWORD(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); - - if (stringFactory == 0) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register string factory without the actual implementation"); - return -1; - } - else - { - r = engine->RegisterStringFactory(type.c_str(), stringFactory); - 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; + int r; + + // Some helper functions for parsing the configuration + struct in + { + static asETokenClass GetToken(asIScriptEngine *engine, string &token, const string &text, asUINT &pos) + { + asUINT len = 0; + 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() && strm.good() ); + + // 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 + if( ep != asEP_COPY_SCRIPT_SECTIONS && + ep != asEP_MAX_STACK_SIZE && + ep != asEP_INIT_GLOBAL_VARS_AFTER_BUILD && + ep != asEP_EXPAND_DEF_ARRAY_TO_TMPL && + ep != asEP_AUTO_GARBAGE_COLLECT ) + { + // Get the value for the property + in::GetToken(engine, tmp, config, pos); + stringstream s(tmp); + asPWORD value; + + s >> value; + + engine->SetEngineProperty(ep, value); + } + } + else if( token == "namespace" ) + { + string ns; + in::GetToken(engine, ns, config, pos); + ns = ns.substr(1, ns.length() - 2); + + 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 = strtoul(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); + + // Remove the $ that the engine prefixes the behaviours with + size_t n = decl.find("$"); + if( n != string::npos ) + decl[n] = ' '; + + 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, compositeOffset, isCompositeIndirect; + 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::GetToken(engine, compositeOffset, config, pos); + in::GetToken(engine, isCompositeIndirect, config, pos); + + asITypeInfo *type = engine->GetTypeInfoById(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(), compositeOffset != "0" ? type->GetPropertyCount() : 0, isCompositeIndirect != "0"); + 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(), reinterpret_cast(asPWORD(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); + + if (stringFactory == 0) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register string factory without the actual implementation"); + return -1; + } + else + { + r = engine->RegisterStringFactory(type.c_str(), stringFactory); + 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() ? function->GetModuleName() : "") << "\n"; - text << "sect: " << (function->GetScriptSectionName() ? 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() ? 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(); + if( ctx->GetState() != asEXECUTION_EXCEPTION ) return ""; + + stringstream text; + + const asIScriptFunction *function = ctx->GetExceptionFunction(); + text << "func: " << function->GetDeclaration() << "\n"; + text << "modl: " << (function->GetModuleName() ? function->GetModuleName() : "") << "\n"; + text << "sect: " << (function->GetScriptSectionName() ? 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() ? 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(); } void ScriptThrow(const string &msg) { - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException(msg.c_str()); + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException(msg.c_str()); } string ScriptGetExceptionInfo() { - asIScriptContext *ctx = asGetActiveContext(); - if (!ctx) - return ""; - - const char *msg = ctx->GetExceptionString(); - if (msg == 0) - return ""; - - return string(msg); + asIScriptContext *ctx = asGetActiveContext(); + if (!ctx) + return ""; + + const char *msg = ctx->GetExceptionString(); + if (msg == 0) + return ""; + + return string(msg); } void RegisterExceptionRoutines(asIScriptEngine *engine) { - int r; + int r; - // The string type must be available - assert(engine->GetTypeInfoByDecl("string")); + // The string type must be available + assert(engine->GetTypeInfoByDecl("string")); - r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0); } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scripthelper/scripthelper.h b/src/angelscript/add_on/scripthelper/scripthelper.h index dc3e0b81613..ba52acdd087 100644 --- a/src/angelscript/add_on/scripthelper/scripthelper.h +++ b/src/angelscript/add_on/scripthelper/scripthelper.h @@ -32,10 +32,10 @@ int ExecuteString(asIScriptEngine *engine, const char *code, void *ret, int retT // 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); +// 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 +// 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", asIStringFactory *stringFactory = 0); diff --git a/src/angelscript/add_on/scriptmath/scriptmath.cpp b/src/angelscript/add_on/scriptmath/scriptmath.cpp index 62688b347ad..b55a8006193 100644 --- a/src/angelscript/add_on/scriptmath/scriptmath.cpp +++ b/src/angelscript/add_on/scriptmath/scriptmath.cpp @@ -3,7 +3,7 @@ #include #include #include "scriptmath.h" -#include +#include #ifdef __BORLANDC__ #include @@ -41,10 +41,10 @@ inline float floorf (float arg) { return std::floor (arg); } // in C++Builder 2010). inline float modff (float x, float *y) { - double d; - float f = (float) modf((double) x, &d); - *y = (float) d; - return f; + double d; + float f = (float) modf((double) x, &d); + *y = (float) d; + return f; } #endif @@ -57,43 +57,43 @@ BEGIN_AS_NAMESPACE #endif #endif -// The modf function doesn't seem very intuitive, so I'm writing this +// The modf function doesn't seem very intuitive, so I'm writing this // function that simply returns the fractional part of the float value #if AS_USE_FLOAT float fractionf(float v) { - float intPart; - return modff(v, &intPart); + float intPart; + return modff(v, &intPart); } #else double fraction(double v) { - double intPart; - return modf(v, &intPart); + double intPart; + return modf(v, &intPart); } #endif // As AngelScript doesn't allow bitwise manipulation of float types we'll provide a couple of -// functions for converting float values to IEEE 754 formatted values etc. This also allow us to +// functions for converting float values to IEEE 754 formatted values etc. This also allow us to // provide a platform agnostic representation to the script so the scripts don't have to worry // about whether the CPU uses IEEE 754 floats or some other representation // float fpFromIEEE(asUINT raw) // { -// // TODO: Identify CPU family to provide proper conversion -// // if the CPU doesn't natively use IEEE style floats -// return *reinterpret_cast(&raw); +// // TODO: Identify CPU family to provide proper conversion +// // if the CPU doesn't natively use IEEE style floats +// return *reinterpret_cast(&raw); // } // asUINT fpToIEEE(float fp) // { -// return *reinterpret_cast(&fp); +// return *reinterpret_cast(&fp); // } // double fpFromIEEE(asQWORD raw) // { -// return *reinterpret_cast(&raw); +// return *reinterpret_cast(&raw); // } // asQWORD fpToIEEE(double fp) // { -// return *reinterpret_cast(&fp); +// return *reinterpret_cast(&fp); // } // Convert a float to its IEEE representation as an unsigned integer asUINT fpToIEEE(float fp) { @@ -119,105 +119,105 @@ asQWORD fpToIEEE(double fp) { std::memcpy(&value, &fp, sizeof(asQWORD)); return value; } -// closeTo() is used to determine if the binary representation of two numbers are +// closeTo() is used to determine if the binary representation of two numbers are // relatively close to each other. Numerical errors due to rounding errors build // up over many operations, so it is almost impossible to get exact numbers and // this is where closeTo() comes in. // -// It shouldn't be used to determine if two numbers are mathematically close to +// It shouldn't be used to determine if two numbers are mathematically close to // each other. // // ref: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm // ref: http://www.gamedev.net/topic/653449-scriptmath-and-closeto/ bool closeTo(float a, float b, float epsilon) { - // Equal numbers and infinity will return immediately - if( a == b ) return true; - - // When very close to 0, we can use the absolute comparison - float diff = fabsf(a - b); - if( (a == 0 || b == 0) && (diff < epsilon) ) - return true; - - // Otherwise we need to use relative comparison to account for precision - return diff / (fabs(a) + fabs(b)) < epsilon; + // Equal numbers and infinity will return immediately + if( a == b ) return true; + + // When very close to 0, we can use the absolute comparison + float diff = fabsf(a - b); + if( (a == 0 || b == 0) && (diff < epsilon) ) + return true; + + // Otherwise we need to use relative comparison to account for precision + return diff / (fabs(a) + fabs(b)) < epsilon; } bool closeTo(double a, double b, double epsilon) { - if( a == b ) return true; + if( a == b ) return true; + + double diff = fabs(a - b); + if( (a == 0 || b == 0) && (diff < epsilon) ) + return true; - double diff = fabs(a - b); - if( (a == 0 || b == 0) && (diff < epsilon) ) - return true; - - return diff / (fabs(a) + fabs(b)) < epsilon; + return diff / (fabs(a) + fabs(b)) < epsilon; } void RegisterScriptMath_Native(asIScriptEngine *engine) { - // Conversion between floating point and IEEE bits representations - engine->RegisterGlobalFunction("float fpFromIEEE(uint)", asFUNCTIONPR(fpFromIEEE, (asUINT), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("uint fpToIEEE(float)", asFUNCTIONPR(fpToIEEE, (float), asUINT), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double fpFromIEEE(uint64)", asFUNCTIONPR(fpFromIEEE, (asQWORD), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("uint64 fpToIEEE(double)", asFUNCTIONPR(fpToIEEE, (double), asQWORD), asCALL_CDECL); assert( r >= 0 ); + // Conversion between floating point and IEEE bits representations + engine->RegisterGlobalFunction("float fpFromIEEE(uint)", asFUNCTIONPR(fpFromIEEE, (asUINT), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("uint fpToIEEE(float)", asFUNCTIONPR(fpToIEEE, (float), asUINT), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double fpFromIEEE(uint64)", asFUNCTIONPR(fpFromIEEE, (asQWORD), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("uint64 fpToIEEE(double)", asFUNCTIONPR(fpToIEEE, (double), asQWORD), asCALL_CDECL); assert( r >= 0 ); - // Close to comparison with epsilon - engine->RegisterGlobalFunction("bool closeTo(float, float, float = 0.00001f)", asFUNCTIONPR(closeTo, (float, float, float), bool), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("bool closeTo(double, double, double = 0.0000000001)", asFUNCTIONPR(closeTo, (double, double, double), bool), asCALL_CDECL); assert( r >= 0 ); + // Close to comparison with epsilon + engine->RegisterGlobalFunction("bool closeTo(float, float, float = 0.00001f)", asFUNCTIONPR(closeTo, (float, float, float), bool), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("bool closeTo(double, double, double = 0.0000000001)", asFUNCTIONPR(closeTo, (double, double, double), bool), asCALL_CDECL); assert( r >= 0 ); #if AS_USE_FLOAT - // Trigonometric functions - engine->RegisterGlobalFunction("float cos(float)", asFUNCTIONPR(cosf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float sin(float)", asFUNCTIONPR(sinf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float tan(float)", asFUNCTIONPR(tanf, (float), float), asCALL_CDECL); assert( r >= 0 ); - - engine->RegisterGlobalFunction("float acos(float)", asFUNCTIONPR(acosf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float asin(float)", asFUNCTIONPR(asinf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float atan(float)", asFUNCTIONPR(atanf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTIONPR(atan2f, (float, float), float), asCALL_CDECL); assert( r >= 0 ); - - // Hyberbolic functions - engine->RegisterGlobalFunction("float cosh(float)", asFUNCTIONPR(coshf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float sinh(float)", asFUNCTIONPR(sinhf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float tanh(float)", asFUNCTIONPR(tanhf, (float), float), asCALL_CDECL); assert( r >= 0 ); - - // Exponential and logarithmic functions - engine->RegisterGlobalFunction("float log(float)", asFUNCTIONPR(logf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float log10(float)", asFUNCTIONPR(log10f, (float), float), asCALL_CDECL); assert( r >= 0 ); - - // Power functions - engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTIONPR(powf, (float, float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTIONPR(sqrtf, (float), float), asCALL_CDECL); assert( r >= 0 ); - - // Nearest integer, absolute value, and remainder functions - engine->RegisterGlobalFunction("float ceil(float)", asFUNCTIONPR(ceilf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float abs(float)", asFUNCTIONPR(fabsf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float floor(float)", asFUNCTIONPR(floorf, (float), float), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("float fraction(float)", asFUNCTIONPR(fractionf, (float), float), asCALL_CDECL); assert( r >= 0 ); - - // Don't register modf because AngelScript already supports the % operator + // Trigonometric functions + engine->RegisterGlobalFunction("float cos(float)", asFUNCTIONPR(cosf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sin(float)", asFUNCTIONPR(sinf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float tan(float)", asFUNCTIONPR(tanf, (float), float), asCALL_CDECL); assert( r >= 0 ); + + engine->RegisterGlobalFunction("float acos(float)", asFUNCTIONPR(acosf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float asin(float)", asFUNCTIONPR(asinf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float atan(float)", asFUNCTIONPR(atanf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTIONPR(atan2f, (float, float), float), asCALL_CDECL); assert( r >= 0 ); + + // Hyberbolic functions + engine->RegisterGlobalFunction("float cosh(float)", asFUNCTIONPR(coshf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sinh(float)", asFUNCTIONPR(sinhf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float tanh(float)", asFUNCTIONPR(tanhf, (float), float), asCALL_CDECL); assert( r >= 0 ); + + // Exponential and logarithmic functions + engine->RegisterGlobalFunction("float log(float)", asFUNCTIONPR(logf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float log10(float)", asFUNCTIONPR(log10f, (float), float), asCALL_CDECL); assert( r >= 0 ); + + // Power functions + engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTIONPR(powf, (float, float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTIONPR(sqrtf, (float), float), asCALL_CDECL); assert( r >= 0 ); + + // Nearest integer, absolute value, and remainder functions + engine->RegisterGlobalFunction("float ceil(float)", asFUNCTIONPR(ceilf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float abs(float)", asFUNCTIONPR(fabsf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float floor(float)", asFUNCTIONPR(floorf, (float), float), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("float fraction(float)", asFUNCTIONPR(fractionf, (float), float), asCALL_CDECL); assert( r >= 0 ); + + // Don't register modf because AngelScript already supports the % operator #else - // double versions of the same - engine->RegisterGlobalFunction("double cos(double)", asFUNCTIONPR(cos, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double sin(double)", asFUNCTIONPR(sin, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double tan(double)", asFUNCTIONPR(tan, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double acos(double)", asFUNCTIONPR(acos, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double asin(double)", asFUNCTIONPR(asin, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double atan(double)", asFUNCTIONPR(atan, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTIONPR(atan2, (double, double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double cosh(double)", asFUNCTIONPR(cosh, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double sinh(double)", asFUNCTIONPR(sinh, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double tanh(double)", asFUNCTIONPR(tanh, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double log(double)", asFUNCTIONPR(log, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double log10(double)", asFUNCTIONPR(log10, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTIONPR(pow, (double, double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTIONPR(sqrt, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double ceil(double)", asFUNCTIONPR(ceil, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double abs(double)", asFUNCTIONPR(fabs, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 ); - engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 ); + // double versions of the same + engine->RegisterGlobalFunction("double cos(double)", asFUNCTIONPR(cos, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sin(double)", asFUNCTIONPR(sin, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double tan(double)", asFUNCTIONPR(tan, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double acos(double)", asFUNCTIONPR(acos, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double asin(double)", asFUNCTIONPR(asin, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double atan(double)", asFUNCTIONPR(atan, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTIONPR(atan2, (double, double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double cosh(double)", asFUNCTIONPR(cosh, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sinh(double)", asFUNCTIONPR(sinh, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double tanh(double)", asFUNCTIONPR(tanh, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double log(double)", asFUNCTIONPR(log, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double log10(double)", asFUNCTIONPR(log10, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTIONPR(pow, (double, double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTIONPR(sqrt, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double ceil(double)", asFUNCTIONPR(ceil, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double abs(double)", asFUNCTIONPR(fabs, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 ); + engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 ); #endif } @@ -226,8 +226,8 @@ void RegisterScriptMath_Native(asIScriptEngine *engine) #define GENERICff(x) \ void x##_generic(asIScriptGeneric *gen) \ { \ - float f = *(float*)gen->GetAddressOfArg(0); \ - *(float*)gen->GetAddressOfReturnLocation() = x(f); \ + float f = *(float*)gen->GetAddressOfArg(0); \ + *(float*)gen->GetAddressOfReturnLocation() = x(f); \ } GENERICff(cosf) @@ -249,15 +249,15 @@ GENERICff(fractionf) void powf_generic(asIScriptGeneric *gen) { - float f1 = *(float*)gen->GetAddressOfArg(0); - float f2 = *(float*)gen->GetAddressOfArg(1); - *(float*)gen->GetAddressOfReturnLocation() = powf(f1, f2); + float f1 = *(float*)gen->GetAddressOfArg(0); + float f2 = *(float*)gen->GetAddressOfArg(1); + *(float*)gen->GetAddressOfReturnLocation() = powf(f1, f2); } void atan2f_generic(asIScriptGeneric *gen) { - float f1 = *(float*)gen->GetAddressOfArg(0); - float f2 = *(float*)gen->GetAddressOfArg(1); - *(float*)gen->GetAddressOfReturnLocation() = atan2f(f1, f2); + float f1 = *(float*)gen->GetAddressOfArg(0); + float f2 = *(float*)gen->GetAddressOfArg(1); + *(float*)gen->GetAddressOfReturnLocation() = atan2f(f1, f2); } #else @@ -265,8 +265,8 @@ void atan2f_generic(asIScriptGeneric *gen) #define GENERICdd(x) \ void x##_generic(asIScriptGeneric *gen) \ { \ - double f = *(double*)gen->GetAddressOfArg(0); \ - *(double*)gen->GetAddressOfReturnLocation() = x(f); \ + double f = *(double*)gen->GetAddressOfArg(0); \ + *(double*)gen->GetAddressOfReturnLocation() = x(f); \ } GENERICdd(cos) @@ -288,80 +288,80 @@ GENERICdd(fraction) void pow_generic(asIScriptGeneric *gen) { - double f1 = *(double*)gen->GetAddressOfArg(0); - double f2 = *(double*)gen->GetAddressOfArg(1); - *(double*)gen->GetAddressOfReturnLocation() = pow(f1, f2); + double f1 = *(double*)gen->GetAddressOfArg(0); + double f2 = *(double*)gen->GetAddressOfArg(1); + *(double*)gen->GetAddressOfReturnLocation() = pow(f1, f2); } void atan2_generic(asIScriptGeneric *gen) { - double f1 = *(double*)gen->GetAddressOfArg(0); - double f2 = *(double*)gen->GetAddressOfArg(1); - *(double*)gen->GetAddressOfReturnLocation() = atan2(f1, f2); + double f1 = *(double*)gen->GetAddressOfArg(0); + double f2 = *(double*)gen->GetAddressOfArg(1); + *(double*)gen->GetAddressOfReturnLocation() = atan2(f1, f2); } #endif void RegisterScriptMath_Generic(asIScriptEngine *engine) { #if AS_USE_FLOAT - // Trigonometric functions - engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float tan(float)", asFUNCTION(tanf_generic), asCALL_GENERIC); assert( r >= 0 ); - - engine->RegisterGlobalFunction("float acos(float)", asFUNCTION(acosf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float asin(float)", asFUNCTION(asinf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float atan(float)", asFUNCTION(atanf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTION(atan2f_generic), asCALL_GENERIC); assert( r >= 0 ); - - // Hyberbolic functions - engine->RegisterGlobalFunction("float cosh(float)", asFUNCTION(coshf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float sinh(float)", asFUNCTION(sinhf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float tanh(float)", asFUNCTION(tanhf_generic), asCALL_GENERIC); assert( r >= 0 ); - - // Exponential and logarithmic functions - engine->RegisterGlobalFunction("float log(float)", asFUNCTION(logf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float log10(float)", asFUNCTION(log10f_generic), asCALL_GENERIC); assert( r >= 0 ); - - // Power functions - engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTION(powf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTION(sqrtf_generic), asCALL_GENERIC); assert( r >= 0 ); - - // Nearest integer, absolute value, and remainder functions - engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float abs(float)", asFUNCTION(fabsf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("float fraction(float)", asFUNCTION(fractionf_generic), asCALL_GENERIC); assert( r >= 0 ); - - // Don't register modf because AngelScript already supports the % operator + // Trigonometric functions + engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float tan(float)", asFUNCTION(tanf_generic), asCALL_GENERIC); assert( r >= 0 ); + + engine->RegisterGlobalFunction("float acos(float)", asFUNCTION(acosf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float asin(float)", asFUNCTION(asinf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float atan(float)", asFUNCTION(atanf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTION(atan2f_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Hyberbolic functions + engine->RegisterGlobalFunction("float cosh(float)", asFUNCTION(coshf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sinh(float)", asFUNCTION(sinhf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float tanh(float)", asFUNCTION(tanhf_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Exponential and logarithmic functions + engine->RegisterGlobalFunction("float log(float)", asFUNCTION(logf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float log10(float)", asFUNCTION(log10f_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Power functions + engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTION(powf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTION(sqrtf_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Nearest integer, absolute value, and remainder functions + engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float abs(float)", asFUNCTION(fabsf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("float fraction(float)", asFUNCTION(fractionf_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Don't register modf because AngelScript already supports the % operator #else - // double versions of the same - engine->RegisterGlobalFunction("double cos(double)", asFUNCTION(cos_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double sin(double)", asFUNCTION(sin_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double tan(double)", asFUNCTION(tan_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double acos(double)", asFUNCTION(acos_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double asin(double)", asFUNCTION(asin_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double atan(double)", asFUNCTION(atan_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTION(atan2_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double cosh(double)", asFUNCTION(cosh_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double sinh(double)", asFUNCTION(sinh_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double tanh(double)", asFUNCTION(tanh_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double log(double)", asFUNCTION(log_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double log10(double)", asFUNCTION(log10_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTION(pow_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTION(sqrt_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double ceil(double)", asFUNCTION(ceil_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double abs(double)", asFUNCTION(fabs_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 ); - engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 ); + // double versions of the same + engine->RegisterGlobalFunction("double cos(double)", asFUNCTION(cos_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sin(double)", asFUNCTION(sin_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double tan(double)", asFUNCTION(tan_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double acos(double)", asFUNCTION(acos_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double asin(double)", asFUNCTION(asin_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double atan(double)", asFUNCTION(atan_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTION(atan2_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double cosh(double)", asFUNCTION(cosh_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sinh(double)", asFUNCTION(sinh_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double tanh(double)", asFUNCTION(tanh_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double log(double)", asFUNCTION(log_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double log10(double)", asFUNCTION(log10_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTION(pow_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTION(sqrt_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double ceil(double)", asFUNCTION(ceil_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double abs(double)", asFUNCTION(fabs_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 ); + engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 ); #endif } void RegisterScriptMath(asIScriptEngine *engine) { - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptMath_Generic(engine); - else - RegisterScriptMath_Native(engine); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptMath_Generic(engine); + else + RegisterScriptMath_Native(engine); } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scriptmath/scriptmath.h b/src/angelscript/add_on/scriptmath/scriptmath.h index a239e38d7cb..b737919e15d 100644 --- a/src/angelscript/add_on/scriptmath/scriptmath.h +++ b/src/angelscript/add_on/scriptmath/scriptmath.h @@ -1,7 +1,7 @@ #ifndef SCRIPTMATH_H #define SCRIPTMATH_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif diff --git a/src/angelscript/add_on/scriptmath/scriptmathcomplex.cpp b/src/angelscript/add_on/scriptmath/scriptmathcomplex.cpp index 0695b7cd90d..a6488e9161f 100644 --- a/src/angelscript/add_on/scriptmath/scriptmathcomplex.cpp +++ b/src/angelscript/add_on/scriptmath/scriptmathcomplex.cpp @@ -14,96 +14,96 @@ BEGIN_AS_NAMESPACE Complex::Complex() { - r = 0; - i = 0; + r = 0; + i = 0; } Complex::Complex(const Complex &other) { - r = other.r; - i = other.i; + r = other.r; + i = other.i; } Complex::Complex(float _r, float _i) { - r = _r; - i = _i; + r = _r; + i = _i; } bool Complex::operator==(const Complex &o) const { - return (r == o.r) && (i == o.i); + return (r == o.r) && (i == o.i); } bool Complex::operator!=(const Complex &o) const { - return !(*this == o); + return !(*this == o); } Complex &Complex::operator=(const Complex &other) { - r = other.r; - i = other.i; - return *this; + r = other.r; + i = other.i; + return *this; } Complex &Complex::operator+=(const Complex &other) { - r += other.r; - i += other.i; - return *this; + r += other.r; + i += other.i; + return *this; } Complex &Complex::operator-=(const Complex &other) { - r -= other.r; - i -= other.i; - return *this; + r -= other.r; + i -= other.i; + return *this; } Complex &Complex::operator*=(const Complex &other) { - *this = *this * other; - return *this; + *this = *this * other; + return *this; } Complex &Complex::operator/=(const Complex &other) { - *this = *this / other; - return *this; + *this = *this / other; + return *this; } float Complex::squaredLength() const { - return r*r + i*i; + return r*r + i*i; } float Complex::length() const { - return sqrtf(squaredLength()); + return sqrtf(squaredLength()); } Complex Complex::operator+(const Complex &other) const { - return Complex(r + other.r, i + other.i); + return Complex(r + other.r, i + other.i); } Complex Complex::operator-(const Complex &other) const { - return Complex(r - other.r, i + other.i); + return Complex(r - other.r, i + other.i); } Complex Complex::operator*(const Complex &other) const { - return Complex(r*other.r - i*other.i, r*other.i + i*other.r); + return Complex(r*other.r - i*other.i, r*other.i + i*other.r); } Complex Complex::operator/(const Complex &other) const { - float squaredLen = other.squaredLength(); - if( squaredLen == 0 ) return Complex(0,0); + float squaredLen = other.squaredLength(); + if( squaredLen == 0 ) return Complex(0,0); - return Complex((r*other.r + i*other.i)/squaredLen, (i*other.r - r*other.i)/squaredLen); + return Complex((r*other.r + i*other.i)/squaredLen, (i*other.r - r*other.i)/squaredLen); } //----------------------- @@ -112,20 +112,20 @@ Complex Complex::operator/(const Complex &other) const Complex Complex::get_ri() const { - return *this; + return *this; } Complex Complex::get_ir() const { - return Complex(r,i); + return Complex(r,i); } void Complex::set_ri(const Complex &o) { - *this = o; + *this = o; } void Complex::set_ir(const Complex &o) { - r = o.i; - i = o.r; + r = o.i; + i = o.r; } //----------------------- @@ -134,27 +134,27 @@ void Complex::set_ir(const Complex &o) static void ComplexDefaultConstructor(Complex *self) { - new(self) Complex(); + new(self) Complex(); } static void ComplexCopyConstructor(const Complex &other, Complex *self) { - new(self) Complex(other); + new(self) Complex(other); } static void ComplexConvConstructor(float r, Complex *self) { - new(self) Complex(r); + new(self) Complex(r); } static void ComplexInitConstructor(float r, float i, Complex *self) { - new(self) Complex(r,i); + new(self) Complex(r,i); } static void ComplexListConstructor(float *list, Complex *self) { - new(self) Complex(list[0], list[1]); + new(self) Complex(list[0], list[1]); } //-------------------------------- @@ -163,58 +163,58 @@ static void ComplexListConstructor(float *list, Complex *self) static void RegisterScriptMathComplex_Native(asIScriptEngine *engine) { - int r; + int r; - // Register the type + // Register the type #if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to determine the correct flags to represent the C++ class, except for the asOBJ_APP_CLASS_ALLFLOATS - r = engine->RegisterObjectType("complex", sizeof(Complex), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits() | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 ); + // With C++11 it is possible to use asGetTypeTraits to determine the correct flags to represent the C++ class, except for the asOBJ_APP_CLASS_ALLFLOATS + r = engine->RegisterObjectType("complex", sizeof(Complex), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits() | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 ); #else - r = engine->RegisterObjectType("complex", sizeof(Complex), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 ); + r = engine->RegisterObjectType("complex", sizeof(Complex), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 ); #endif - // Register the object properties - r = engine->RegisterObjectProperty("complex", "float r", asOFFSET(Complex, r)); assert( r >= 0 ); - r = engine->RegisterObjectProperty("complex", "float i", asOFFSET(Complex, i)); assert( r >= 0 ); - - // Register the constructors - r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ComplexDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(const complex &in)", asFUNCTION(ComplexCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(ComplexConvConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(float, float)", asFUNCTION(ComplexInitConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("complex", asBEHAVE_LIST_CONSTRUCT, "void f(const int &in) {float, float}", asFUNCTION(ComplexListConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - // Register the operator overloads - r = engine->RegisterObjectMethod("complex", "complex &opAddAssign(const complex &in)", asMETHODPR(Complex, operator+=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "complex &opSubAssign(const complex &in)", asMETHODPR(Complex, operator-=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "complex &opMulAssign(const complex &in)", asMETHODPR(Complex, operator*=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "complex &opDivAssign(const complex &in)", asMETHODPR(Complex, operator/=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "bool opEquals(const complex &in) const", asMETHODPR(Complex, operator==, (const Complex &) const, bool), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "complex opAdd(const complex &in) const", asMETHODPR(Complex, operator+, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "complex opSub(const complex &in) const", asMETHODPR(Complex, operator-, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "complex opMul(const complex &in) const", asMETHODPR(Complex, operator*, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "complex opDiv(const complex &in) const", asMETHODPR(Complex, operator/, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); - - // Register the object methods - r = engine->RegisterObjectMethod("complex", "float abs() const", asMETHOD(Complex,length), asCALL_THISCALL); assert( r >= 0 ); - - // Register the swizzle operators - r = engine->RegisterObjectMethod("complex", "complex get_ri() const property", asMETHOD(Complex, get_ri), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "complex get_ir() const property", asMETHOD(Complex, get_ir), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "void set_ri(const complex &in) property", asMETHOD(Complex, set_ri), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("complex", "void set_ir(const complex &in) property", asMETHOD(Complex, set_ir), asCALL_THISCALL); assert( r >= 0 ); + // Register the object properties + r = engine->RegisterObjectProperty("complex", "float r", asOFFSET(Complex, r)); assert( r >= 0 ); + r = engine->RegisterObjectProperty("complex", "float i", asOFFSET(Complex, i)); assert( r >= 0 ); + + // Register the constructors + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ComplexDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(const complex &in)", asFUNCTION(ComplexCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(ComplexConvConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(float, float)", asFUNCTION(ComplexInitConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_LIST_CONSTRUCT, "void f(const int &in) {float, float}", asFUNCTION(ComplexListConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Register the operator overloads + r = engine->RegisterObjectMethod("complex", "complex &opAddAssign(const complex &in)", asMETHODPR(Complex, operator+=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex &opSubAssign(const complex &in)", asMETHODPR(Complex, operator-=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex &opMulAssign(const complex &in)", asMETHODPR(Complex, operator*=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex &opDivAssign(const complex &in)", asMETHODPR(Complex, operator/=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "bool opEquals(const complex &in) const", asMETHODPR(Complex, operator==, (const Complex &) const, bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex opAdd(const complex &in) const", asMETHODPR(Complex, operator+, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex opSub(const complex &in) const", asMETHODPR(Complex, operator-, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex opMul(const complex &in) const", asMETHODPR(Complex, operator*, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex opDiv(const complex &in) const", asMETHODPR(Complex, operator/, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); + + // Register the object methods + r = engine->RegisterObjectMethod("complex", "float abs() const", asMETHOD(Complex,length), asCALL_THISCALL); assert( r >= 0 ); + + // Register the swizzle operators + r = engine->RegisterObjectMethod("complex", "complex get_ri() const property", asMETHOD(Complex, get_ri), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex get_ir() const property", asMETHOD(Complex, get_ir), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "void set_ri(const complex &in) property", asMETHOD(Complex, set_ri), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "void set_ir(const complex &in) property", asMETHOD(Complex, set_ir), asCALL_THISCALL); assert( r >= 0 ); } void RegisterScriptMathComplex(asIScriptEngine *engine) { - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - { - assert( false ); - // TODO: implement support for generic calling convention - // RegisterScriptMathComplex_Generic(engine); - } - else - RegisterScriptMathComplex_Native(engine); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + { + assert( false ); + // TODO: implement support for generic calling convention + // RegisterScriptMathComplex_Generic(engine); + } + else + RegisterScriptMathComplex_Native(engine); } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scriptmath/scriptmathcomplex.h b/src/angelscript/add_on/scriptmath/scriptmathcomplex.h index 8d33915d62f..c44032cc742 100644 --- a/src/angelscript/add_on/scriptmath/scriptmathcomplex.h +++ b/src/angelscript/add_on/scriptmath/scriptmathcomplex.h @@ -1,7 +1,7 @@ #ifndef SCRIPTMATHCOMPLEX_H #define SCRIPTMATHCOMPLEX_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -9,47 +9,47 @@ BEGIN_AS_NAMESPACE -// This class implements complex numbers and the common +// This class implements complex numbers and the common // operations that can be done with it. // // Ref: http://mathworld.wolfram.com/ComplexNumber.html struct Complex { - Complex(); - Complex(const Complex &other); - Complex(float r, float i = 0); - - // Assignment operator - Complex &operator=(const Complex &other); - - // Compound assigment operators - Complex &operator+=(const Complex &other); - Complex &operator-=(const Complex &other); - Complex &operator*=(const Complex &other); - Complex &operator/=(const Complex &other); - - float length() const; - float squaredLength() const; - - // Swizzle operators - Complex get_ri() const; - void set_ri(const Complex &in); - Complex get_ir() const; - void set_ir(const Complex &in); - - // Comparison - bool operator==(const Complex &other) const; - bool operator!=(const Complex &other) const; - - // Math operators - Complex operator+(const Complex &other) const; - Complex operator-(const Complex &other) const; - Complex operator*(const Complex &other) const; - Complex operator/(const Complex &other) const; - - float r; - float i; + Complex(); + Complex(const Complex &other); + Complex(float r, float i = 0); + + // Assignment operator + Complex &operator=(const Complex &other); + + // Compound assigment operators + Complex &operator+=(const Complex &other); + Complex &operator-=(const Complex &other); + Complex &operator*=(const Complex &other); + Complex &operator/=(const Complex &other); + + float length() const; + float squaredLength() const; + + // Swizzle operators + Complex get_ri() const; + void set_ri(const Complex &in); + Complex get_ir() const; + void set_ir(const Complex &in); + + // Comparison + bool operator==(const Complex &other) const; + bool operator!=(const Complex &other) const; + + // Math operators + Complex operator+(const Complex &other) const; + Complex operator-(const Complex &other) const; + Complex operator*(const Complex &other) const; + Complex operator/(const Complex &other) const; + + float r; + float i; }; // This function will determine the configuration of the engine diff --git a/src/angelscript/add_on/scriptstdstring/scriptstdstring.cpp b/src/angelscript/add_on/scriptstdstring/scriptstdstring.cpp index 2a96ad405c9..2d6a8d4cdc1 100644 --- a/src/angelscript/add_on/scriptstdstring/scriptstdstring.cpp +++ b/src/angelscript/add_on/scriptstdstring/scriptstdstring.cpp @@ -2,10 +2,10 @@ #include // assert() #include // std::stringstream #include // strstr() -#include // sprintf() +#include // sprintf() #include // strtod() #ifndef __psp2__ - #include // setlocale() + #include // setlocale() #endif using namespace std; @@ -32,112 +32,112 @@ BEGIN_AS_NAMESPACE class CStdStringFactory : public asIStringFactory { public: - CStdStringFactory() {} - ~CStdStringFactory() - { - // The script engine must release each string - // constant that it has requested - assert(stringCache.size() == 0); - } - - const void *GetStringConstant(const char *data, asUINT length) - { - // The string factory might be modified from multiple - // threads, so it is necessary to use a mutex. - asAcquireExclusiveLock(); - - string str(data, length); - map_t::iterator it = stringCache.find(str); - if (it != stringCache.end()) - it->second++; - else - it = stringCache.insert(map_t::value_type(str, 1)).first; - - asReleaseExclusiveLock(); - - return reinterpret_cast(&it->first); - } - - int ReleaseStringConstant(const void *str) - { - if (str == 0) - return asERROR; - - int ret = asSUCCESS; - - // The string factory might be modified from multiple - // threads, so it is necessary to use a mutex. - asAcquireExclusiveLock(); - - map_t::iterator it = stringCache.find(*reinterpret_cast(str)); - if (it == stringCache.end()) - ret = asERROR; - else - { - it->second--; - if (it->second == 0) - stringCache.erase(it); - } - - asReleaseExclusiveLock(); - - return ret; - } - - int GetRawStringData(const void *str, char *data, asUINT *length) const - { - if (str == 0) - return asERROR; - - if (length) - *length = (asUINT)reinterpret_cast(str)->length(); - - if (data) - memcpy(data, reinterpret_cast(str)->c_str(), reinterpret_cast(str)->length()); - - return asSUCCESS; - } - - // THe access to the string cache is protected with the common mutex provided by AngelScript - map_t stringCache; + CStdStringFactory() {} + ~CStdStringFactory() + { + // The script engine must release each string + // constant that it has requested + assert(stringCache.size() == 0); + } + + const void *GetStringConstant(const char *data, asUINT length) + { + // The string factory might be modified from multiple + // threads, so it is necessary to use a mutex. + asAcquireExclusiveLock(); + + string str(data, length); + map_t::iterator it = stringCache.find(str); + if (it != stringCache.end()) + it->second++; + else + it = stringCache.insert(map_t::value_type(str, 1)).first; + + asReleaseExclusiveLock(); + + return reinterpret_cast(&it->first); + } + + int ReleaseStringConstant(const void *str) + { + if (str == 0) + return asERROR; + + int ret = asSUCCESS; + + // The string factory might be modified from multiple + // threads, so it is necessary to use a mutex. + asAcquireExclusiveLock(); + + map_t::iterator it = stringCache.find(*reinterpret_cast(str)); + if (it == stringCache.end()) + ret = asERROR; + else + { + it->second--; + if (it->second == 0) + stringCache.erase(it); + } + + asReleaseExclusiveLock(); + + return ret; + } + + int GetRawStringData(const void *str, char *data, asUINT *length) const + { + if (str == 0) + return asERROR; + + if (length) + *length = (asUINT)reinterpret_cast(str)->length(); + + if (data) + memcpy(data, reinterpret_cast(str)->c_str(), reinterpret_cast(str)->length()); + + return asSUCCESS; + } + + // THe access to the string cache is protected with the common mutex provided by AngelScript + map_t stringCache; }; static CStdStringFactory *stringFactory = 0; -// TODO: Make this public so the application can also use the string +// TODO: Make this public so the application can also use the string // factory and share the string constants if so desired, or to // monitor the size of the string factory cache. CStdStringFactory *GetStdStringFactorySingleton() { - if( stringFactory == 0 ) - { - // The following instance will be destroyed by the global - // CStdStringFactoryCleaner instance upon application shutdown - stringFactory = new CStdStringFactory(); - } - return stringFactory; + if( stringFactory == 0 ) + { + // The following instance will be destroyed by the global + // CStdStringFactoryCleaner instance upon application shutdown + stringFactory = new CStdStringFactory(); + } + return stringFactory; } class CStdStringFactoryCleaner { public: - ~CStdStringFactoryCleaner() - { - if (stringFactory) - { - // Only delete the string factory if the stringCache is empty - // If it is not empty, it means that someone might still attempt - // to release string constants, so if we delete the string factory - // the application might crash. Not deleting the cache would - // lead to a memory leak, but since this is only happens when the - // application is shutting down anyway, it is not important. - if (stringFactory->stringCache.empty()) - { - delete stringFactory; - stringFactory = 0; - } - } - } + ~CStdStringFactoryCleaner() + { + if (stringFactory) + { + // Only delete the string factory if the stringCache is empty + // If it is not empty, it means that someone might still attempt + // to release string constants, so if we delete the string factory + // the application might crash. Not deleting the cache would + // lead to a memory leak, but since this is only happens when the + // application is shutting down anyway, it is not important. + if (stringFactory->stringCache.empty()) + { + delete stringFactory; + stringFactory = 0; + } + } + } }; static CStdStringFactoryCleaner cleaner; @@ -145,213 +145,213 @@ static CStdStringFactoryCleaner cleaner; static void ConstructString(string *thisPointer) { - new(thisPointer) string(); + new(thisPointer) string(); } static void CopyConstructString(const string &other, string *thisPointer) { - new(thisPointer) string(other); + new(thisPointer) string(other); } static void DestructString(string *thisPointer) { - thisPointer->~string(); + thisPointer->~string(); } static string &AddAssignStringToString(const string &str, string &dest) { - // We don't register the method directly because some compilers - // and standard libraries inline the definition, resulting in the - // linker being unable to find the declaration. - // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 - dest += str; - return dest; + // We don't register the method directly because some compilers + // and standard libraries inline the definition, resulting in the + // linker being unable to find the declaration. + // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 + dest += str; + return dest; } // bool string::isEmpty() // bool string::empty() // if AS_USE_STLNAMES == 1 static bool StringIsEmpty(const string &str) { - // We don't register the method directly because some compilers - // and standard libraries inline the definition, resulting in the - // linker being unable to find the declaration - // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 - return str.empty(); + // We don't register the method directly because some compilers + // and standard libraries inline the definition, resulting in the + // linker being unable to find the declaration + // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 + return str.empty(); } static string &AssignUInt64ToString(asQWORD i, string &dest) { - ostringstream stream; - stream << i; - dest = stream.str(); - return dest; + ostringstream stream; + stream << i; + dest = stream.str(); + return dest; } static string &AddAssignUInt64ToString(asQWORD i, string &dest) { - ostringstream stream; - stream << i; - dest += stream.str(); - return dest; + ostringstream stream; + stream << i; + dest += stream.str(); + return dest; } static string AddStringUInt64(const string &str, asQWORD i) { - ostringstream stream; - stream << i; - return str + stream.str(); + ostringstream stream; + stream << i; + return str + stream.str(); } static string AddInt64String(asINT64 i, const string &str) { - ostringstream stream; - stream << i; - return stream.str() + str; + ostringstream stream; + stream << i; + return stream.str() + str; } static string &AssignInt64ToString(asINT64 i, string &dest) { - ostringstream stream; - stream << i; - dest = stream.str(); - return dest; + ostringstream stream; + stream << i; + dest = stream.str(); + return dest; } static string &AddAssignInt64ToString(asINT64 i, string &dest) { - ostringstream stream; - stream << i; - dest += stream.str(); - return dest; + ostringstream stream; + stream << i; + dest += stream.str(); + return dest; } static string AddStringInt64(const string &str, asINT64 i) { - ostringstream stream; - stream << i; - return str + stream.str(); + ostringstream stream; + stream << i; + return str + stream.str(); } static string AddUInt64String(asQWORD i, const string &str) { - ostringstream stream; - stream << i; - return stream.str() + str; + ostringstream stream; + stream << i; + return stream.str() + str; } static string &AssignDoubleToString(double f, string &dest) { - ostringstream stream; - stream << f; - dest = stream.str(); - return dest; + ostringstream stream; + stream << f; + dest = stream.str(); + return dest; } static string &AddAssignDoubleToString(double f, string &dest) { - ostringstream stream; - stream << f; - dest += stream.str(); - return dest; + ostringstream stream; + stream << f; + dest += stream.str(); + return dest; } static string &AssignFloatToString(float f, string &dest) { - ostringstream stream; - stream << f; - dest = stream.str(); - return dest; + ostringstream stream; + stream << f; + dest = stream.str(); + return dest; } static string &AddAssignFloatToString(float f, string &dest) { - ostringstream stream; - stream << f; - dest += stream.str(); - return dest; + ostringstream stream; + stream << f; + dest += stream.str(); + return dest; } static string &AssignBoolToString(bool b, string &dest) { - ostringstream stream; - stream << (b ? "true" : "false"); - dest = stream.str(); - return dest; + ostringstream stream; + stream << (b ? "true" : "false"); + dest = stream.str(); + return dest; } static string &AddAssignBoolToString(bool b, string &dest) { - ostringstream stream; - stream << (b ? "true" : "false"); - dest += stream.str(); - return dest; + ostringstream stream; + stream << (b ? "true" : "false"); + dest += stream.str(); + return dest; } static string AddStringDouble(const string &str, double f) { - ostringstream stream; - stream << f; - return str + stream.str(); + ostringstream stream; + stream << f; + return str + stream.str(); } static string AddDoubleString(double f, const string &str) { - ostringstream stream; - stream << f; - return stream.str() + str; + ostringstream stream; + stream << f; + return stream.str() + str; } static string AddStringFloat(const string &str, float f) { - ostringstream stream; - stream << f; - return str + stream.str(); + ostringstream stream; + stream << f; + return str + stream.str(); } static string AddFloatString(float f, const string &str) { - ostringstream stream; - stream << f; - return stream.str() + str; + ostringstream stream; + stream << f; + return stream.str() + str; } static string AddStringBool(const string &str, bool b) { - ostringstream stream; - stream << (b ? "true" : "false"); - return str + stream.str(); + ostringstream stream; + stream << (b ? "true" : "false"); + return str + stream.str(); } static string AddBoolString(bool b, const string &str) { - ostringstream stream; - stream << (b ? "true" : "false"); - return stream.str() + str; + ostringstream stream; + stream << (b ? "true" : "false"); + return stream.str() + str; } static char *StringCharAt(unsigned int i, string &str) { - if( i >= str.size() ) - { - // Set a script exception - asIScriptContext *ctx = asGetActiveContext(); - ctx->SetException("Out of range"); + if( i >= str.size() ) + { + // Set a script exception + asIScriptContext *ctx = asGetActiveContext(); + ctx->SetException("Out of range"); - // Return a null pointer - return 0; - } + // Return a null pointer + return 0; + } - return &str[i]; + return &str[i]; } // AngelScript signature: // int string::opCmp(const string &in) const static int StringCmp(const string &a, const string &b) { - int cmp = 0; - if( a < b ) cmp = -1; - else if( a > b ) cmp = 1; - return cmp; + int cmp = 0; + if( a < b ) cmp = -1; + else if( a > b ) cmp = 1; + return cmp; } // This function returns the index of the first position where the substring @@ -362,8 +362,8 @@ static int StringCmp(const string &a, const string &b) // int string::findFirst(const string &in sub, uint start = 0) const static int StringFindFirst(const string &sub, asUINT start, const string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find(sub, (size_t)(start < 0 ? string::npos : start)); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find(sub, (size_t)(start < 0 ? string::npos : start)); } // This function returns the index of the first position where the one of the bytes in substring @@ -374,8 +374,8 @@ static int StringFindFirst(const string &sub, asUINT start, const string &str) // int string::findFirstOf(const string &in sub, uint start = 0) const static int StringFindFirstOf(const string &sub, asUINT start, const string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find_first_of(sub, (size_t)(start < 0 ? string::npos : start)); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_first_of(sub, (size_t)(start < 0 ? string::npos : start)); } // This function returns the index of the last position where the one of the bytes in substring @@ -386,8 +386,8 @@ static int StringFindFirstOf(const string &sub, asUINT start, const string &str) // int string::findLastOf(const string &in sub, uint start = -1) const static int StringFindLastOf(const string &sub, asUINT start, const string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find_last_of(sub, (size_t)(start < 0 ? string::npos : start)); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_last_of(sub, (size_t)(start < 0 ? string::npos : start)); } // This function returns the index of the first position where a byte other than those in substring @@ -397,8 +397,8 @@ static int StringFindLastOf(const string &sub, asUINT start, const string &str) // int string::findFirstNotOf(const string &in sub, uint start = 0) const static int StringFindFirstNotOf(const string &sub, asUINT start, const string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find_first_not_of(sub, (size_t)(start < 0 ? string::npos : start)); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_first_not_of(sub, (size_t)(start < 0 ? string::npos : start)); } // This function returns the index of the last position where a byte other than those in substring @@ -408,8 +408,8 @@ static int StringFindFirstNotOf(const string &sub, asUINT start, const string &s // int string::findLastNotOf(const string &in sub, uint start = -1) const static int StringFindLastNotOf(const string &sub, asUINT start, const string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find_last_not_of(sub, (size_t)(start < 0 ? string::npos : start)); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_last_not_of(sub, (size_t)(start < 0 ? string::npos : start)); } // This function returns the index of the last position where the substring @@ -420,24 +420,24 @@ static int StringFindLastNotOf(const string &sub, asUINT start, const string &st // int string::findLast(const string &in sub, int start = -1) const static int StringFindLast(const string &sub, int start, const string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.rfind(sub, (size_t)(start < 0 ? string::npos : start)); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.rfind(sub, (size_t)(start < 0 ? string::npos : start)); } // AngelScript signature: // void string::insert(uint pos, const string &in other) static void StringInsert(unsigned int pos, const string &other, string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - str.insert(pos, other); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.insert(pos, other); } // AngelScript signature: // void string::erase(uint pos, int count = -1) static void StringErase(unsigned int pos, int count, string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - str.erase(pos, (size_t)(count < 0 ? string::npos : count)); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.erase(pos, (size_t)(count < 0 ? string::npos : count)); } @@ -445,8 +445,8 @@ static void StringErase(unsigned int pos, int count, string &str) // uint string::length() const static asUINT StringLength(const string &str) { - // We don't register the method directly because the return type changes between 32bit and 64bit platforms - return (asUINT)str.length(); + // We don't register the method directly because the return type changes between 32bit and 64bit platforms + return (asUINT)str.length(); } @@ -454,262 +454,262 @@ static asUINT StringLength(const string &str) // void string::resize(uint l) static void StringResize(asUINT l, string &str) { - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - str.resize(l); + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.resize(l); } // AngelScript signature: // string formatInt(int64 val, const string &in options, uint width) static string formatInt(asINT64 value, const string &options, asUINT width) { - bool leftJustify = options.find("l") != string::npos; - bool padWithZero = options.find("0") != string::npos; - bool alwaysSign = options.find("+") != string::npos; - bool spaceOnSign = options.find(" ") != string::npos; - bool hexSmall = options.find("h") != string::npos; - bool hexLarge = options.find("H") != string::npos; + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool hexSmall = options.find("h") != string::npos; + bool hexLarge = options.find("H") != string::npos; - string fmt = "%"; - if( leftJustify ) fmt += "-"; - if( alwaysSign ) fmt += "+"; - if( spaceOnSign ) fmt += " "; - if( padWithZero ) fmt += "0"; + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; #ifdef _WIN32 - fmt += "*I64"; + fmt += "*I64"; #else #ifdef _LP64 - fmt += "*l"; + fmt += "*l"; #else - fmt += "*ll"; + fmt += "*ll"; #endif #endif - if( hexSmall ) fmt += "x"; - else if( hexLarge ) fmt += "X"; - else fmt += "d"; + if( hexSmall ) fmt += "x"; + else if( hexLarge ) fmt += "X"; + else fmt += "d"; - string buf; - buf.resize(width+30); + string buf; + buf.resize(width+30); #if _MSC_VER >= 1400 && !defined(__S3E__) - // MSVC 8.0 / 2005 or newer - sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); #else - sprintf(&buf[0], fmt.c_str(), width, value); + sprintf(&buf[0], fmt.c_str(), width, value); #endif - buf.resize(strlen(&buf[0])); + buf.resize(strlen(&buf[0])); - return buf; + return buf; } // AngelScript signature: // string formatUInt(uint64 val, const string &in options, uint width) static string formatUInt(asQWORD value, const string &options, asUINT width) { - bool leftJustify = options.find("l") != string::npos; - bool padWithZero = options.find("0") != string::npos; - bool alwaysSign = options.find("+") != string::npos; - bool spaceOnSign = options.find(" ") != string::npos; - bool hexSmall = options.find("h") != string::npos; - bool hexLarge = options.find("H") != string::npos; + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool hexSmall = options.find("h") != string::npos; + bool hexLarge = options.find("H") != string::npos; - string fmt = "%"; - if( leftJustify ) fmt += "-"; - if( alwaysSign ) fmt += "+"; - if( spaceOnSign ) fmt += " "; - if( padWithZero ) fmt += "0"; + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; #ifdef _WIN32 - fmt += "*I64"; + fmt += "*I64"; #else #ifdef _LP64 - fmt += "*l"; + fmt += "*l"; #else - fmt += "*ll"; + fmt += "*ll"; #endif #endif - if( hexSmall ) fmt += "x"; - else if( hexLarge ) fmt += "X"; - else fmt += "u"; + if( hexSmall ) fmt += "x"; + else if( hexLarge ) fmt += "X"; + else fmt += "u"; - string buf; - buf.resize(width+30); + string buf; + buf.resize(width+30); #if _MSC_VER >= 1400 && !defined(__S3E__) - // MSVC 8.0 / 2005 or newer - sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); #else - sprintf(&buf[0], fmt.c_str(), width, value); + sprintf(&buf[0], fmt.c_str(), width, value); #endif - buf.resize(strlen(&buf[0])); + buf.resize(strlen(&buf[0])); - return buf; + return buf; } // AngelScript signature: // string formatFloat(double val, const string &in options, uint width, uint precision) static string formatFloat(double value, const string &options, asUINT width, asUINT precision) { - bool leftJustify = options.find("l") != string::npos; - bool padWithZero = options.find("0") != string::npos; - bool alwaysSign = options.find("+") != string::npos; - bool spaceOnSign = options.find(" ") != string::npos; - bool expSmall = options.find("e") != string::npos; - bool expLarge = options.find("E") != string::npos; + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool expSmall = options.find("e") != string::npos; + bool expLarge = options.find("E") != string::npos; - string fmt = "%"; - if( leftJustify ) fmt += "-"; - if( alwaysSign ) fmt += "+"; - if( spaceOnSign ) fmt += " "; - if( padWithZero ) fmt += "0"; + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; - fmt += "*.*"; + fmt += "*.*"; - if( expSmall ) fmt += "e"; - else if( expLarge ) fmt += "E"; - else fmt += "f"; + if( expSmall ) fmt += "e"; + else if( expLarge ) fmt += "E"; + else fmt += "f"; - string buf; - buf.resize(width+precision+50); + string buf; + buf.resize(width+precision+50); #if _MSC_VER >= 1400 && !defined(__S3E__) - // MSVC 8.0 / 2005 or newer - sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, precision, value); + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, precision, value); #else - sprintf(&buf[0], fmt.c_str(), width, precision, value); + sprintf(&buf[0], fmt.c_str(), width, precision, value); #endif - buf.resize(strlen(&buf[0])); + buf.resize(strlen(&buf[0])); - return buf; + return buf; } // AngelScript signature: // int64 parseInt(const string &in val, uint base = 10, uint &out byteCount = 0) static asINT64 parseInt(const string &val, asUINT base, asUINT *byteCount) { - // Only accept base 10 and 16 - if( base != 10 && base != 16 ) - { - if( byteCount ) *byteCount = 0; - return 0; - } - - const char *end = &val[0]; - - // Determine the sign - bool sign = false; - if( *end == '-' ) - { - sign = true; - end++; - } - else if( *end == '+' ) - end++; - - asINT64 res = 0; - if( base == 10 ) - { - while( *end >= '0' && *end <= '9' ) - { - res *= 10; - res += *end++ - '0'; - } - } - else if( base == 16 ) - { - while( (*end >= '0' && *end <= '9') || - (*end >= 'a' && *end <= 'f') || - (*end >= 'A' && *end <= 'F') ) - { - res *= 16; - if( *end >= '0' && *end <= '9' ) - res += *end++ - '0'; - else if( *end >= 'a' && *end <= 'f' ) - res += *end++ - 'a' + 10; - else if( *end >= 'A' && *end <= 'F' ) - res += *end++ - 'A' + 10; - } - } - - if( byteCount ) - *byteCount = asUINT(size_t(end - val.c_str())); - - if( sign ) - res = -res; - - return res; + // Only accept base 10 and 16 + if( base != 10 && base != 16 ) + { + if( byteCount ) *byteCount = 0; + return 0; + } + + const char *end = &val[0]; + + // Determine the sign + bool sign = false; + if( *end == '-' ) + { + sign = true; + end++; + } + else if( *end == '+' ) + end++; + + asINT64 res = 0; + if( base == 10 ) + { + while( *end >= '0' && *end <= '9' ) + { + res *= 10; + res += *end++ - '0'; + } + } + else if( base == 16 ) + { + while( (*end >= '0' && *end <= '9') || + (*end >= 'a' && *end <= 'f') || + (*end >= 'A' && *end <= 'F') ) + { + res *= 16; + if( *end >= '0' && *end <= '9' ) + res += *end++ - '0'; + else if( *end >= 'a' && *end <= 'f' ) + res += *end++ - 'a' + 10; + else if( *end >= 'A' && *end <= 'F' ) + res += *end++ - 'A' + 10; + } + } + + if( byteCount ) + *byteCount = asUINT(size_t(end - val.c_str())); + + if( sign ) + res = -res; + + return res; } // AngelScript signature: // uint64 parseUInt(const string &in val, uint base = 10, uint &out byteCount = 0) static asQWORD parseUInt(const string &val, asUINT base, asUINT *byteCount) { - // Only accept base 10 and 16 - if (base != 10 && base != 16) - { - if (byteCount) *byteCount = 0; - return 0; - } - - const char *end = &val[0]; - - asQWORD res = 0; - if (base == 10) - { - while (*end >= '0' && *end <= '9') - { - res *= 10; - res += *end++ - '0'; - } - } - else if (base == 16) - { - while ((*end >= '0' && *end <= '9') || - (*end >= 'a' && *end <= 'f') || - (*end >= 'A' && *end <= 'F')) - { - res *= 16; - if (*end >= '0' && *end <= '9') - res += *end++ - '0'; - else if (*end >= 'a' && *end <= 'f') - res += *end++ - 'a' + 10; - else if (*end >= 'A' && *end <= 'F') - res += *end++ - 'A' + 10; - } - } - - if (byteCount) - *byteCount = asUINT(size_t(end - val.c_str())); - - return res; + // Only accept base 10 and 16 + if (base != 10 && base != 16) + { + if (byteCount) *byteCount = 0; + return 0; + } + + const char *end = &val[0]; + + asQWORD res = 0; + if (base == 10) + { + while (*end >= '0' && *end <= '9') + { + res *= 10; + res += *end++ - '0'; + } + } + else if (base == 16) + { + while ((*end >= '0' && *end <= '9') || + (*end >= 'a' && *end <= 'f') || + (*end >= 'A' && *end <= 'F')) + { + res *= 16; + if (*end >= '0' && *end <= '9') + res += *end++ - '0'; + else if (*end >= 'a' && *end <= 'f') + res += *end++ - 'a' + 10; + else if (*end >= 'A' && *end <= 'F') + res += *end++ - 'A' + 10; + } + } + + if (byteCount) + *byteCount = asUINT(size_t(end - val.c_str())); + + return res; } // AngelScript signature: // double parseFloat(const string &in val, uint &out byteCount = 0) double parseFloat(const string &val, asUINT *byteCount) { - char *end; + char *end; - // WinCE doesn't have setlocale. Some quick testing on my current platform - // still manages to parse the numbers such as "3.14" even if the decimal for the - // locale is ",". + // WinCE doesn't have setlocale. Some quick testing on my current platform + // still manages to parse the numbers such as "3.14" even if the decimal for the + // locale is ",". #if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) - // Set the locale to C so that we are guaranteed to parse the float value correctly - char *tmp = setlocale(LC_NUMERIC, 0); - string orig = tmp ? tmp : "C"; - setlocale(LC_NUMERIC, "C"); + // Set the locale to C so that we are guaranteed to parse the float value correctly + char *tmp = setlocale(LC_NUMERIC, 0); + string orig = tmp ? tmp : "C"; + setlocale(LC_NUMERIC, "C"); #endif - double res = strtod(val.c_str(), &end); + double res = strtod(val.c_str(), &end); #if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) - // Restore the locale - setlocale(LC_NUMERIC, orig.c_str()); + // Restore the locale + setlocale(LC_NUMERIC, orig.c_str()); #endif - if( byteCount ) - *byteCount = asUINT(size_t(end - val.c_str())); + if( byteCount ) + *byteCount = asUINT(size_t(end - val.c_str())); - return res; + return res; } // This function returns a string containing the substring of the input string @@ -719,12 +719,12 @@ double parseFloat(const string &val, asUINT *byteCount) // string string::substr(uint start = 0, int count = -1) const static string StringSubString(asUINT start, int count, const string &str) { - // Check for out-of-bounds - string ret; - if( start < str.length() && count != 0 ) - ret = str.substr(start, (size_t)(count < 0 ? string::npos : count)); + // Check for out-of-bounds + string ret; + if( start < str.length() && count != 0 ) + ret = str.substr(start, (size_t)(count < 0 ? string::npos : count)); - return ret; + return ret; } // String equality comparison. @@ -735,627 +735,627 @@ static string StringSubString(asUINT start, int count, const string &str) // makro, so this wrapper was introduced as work around. static bool StringEquals(const std::string& lhs, const std::string& rhs) { - return lhs == rhs; + return lhs == rhs; } void RegisterStdString_Native(asIScriptEngine *engine) { - int r = 0; - UNUSED_VAR(r); + int r = 0; + UNUSED_VAR(r); - // Register the string type + // Register the string type #if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags to use - r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asGetTypeTraits()); assert( r >= 0 ); + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags to use + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asGetTypeTraits()); assert( r >= 0 ); #else - r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); #endif - r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); + r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); - // Register the object operator overloads - r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asMETHODPR(string, operator =, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); - // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails - r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); -// r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asMETHODPR(string, operator+=, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); + // Register the object operator overloads + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asMETHODPR(string, operator =, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); + // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails + r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +// r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asMETHODPR(string, operator+=, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); - // Need to use a wrapper for operator== otherwise gcc 4.7 fails to compile - r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTIONPR(StringEquals, (const string &, const string &), bool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmp), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTIONPR(operator +, (const string &, const string &), string), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + // Need to use a wrapper for operator== otherwise gcc 4.7 fails to compile + r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTIONPR(StringEquals, (const string &, const string &), bool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmp), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTIONPR(operator +, (const string &, const string &), string), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - // The string length can be accessed through methods or through virtual property - // TODO: Register as size() for consistency with other types + // The string length can be accessed through methods or through virtual property + // TODO: Register as size() for consistency with other types #if AS_USE_ACCESSORS != 1 - r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); #endif - r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); #if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 - // Don't register these if STL names is used, as they conflict with the method size() - r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Don't register these if STL names is used, as they conflict with the method size() + r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); #endif - // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails -// r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asMETHOD(string, empty), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - // Register the index operator, both as a mutator and as an inspector - // Note that we don't register the operator[] directly, as it doesn't do bounds checking - r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - // Automatic conversion from values - r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddStringDouble), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDoubleString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddStringFloat), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloatString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddStringInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddStringUInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddStringBool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBoolString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - // Utilities - r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase), asCALL_CDECL_OBJLAST); assert(r >= 0); - - - r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat), asCALL_CDECL); assert(r >= 0); + // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails +// r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asMETHOD(string, empty), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Register the index operator, both as a mutator and as an inspector + // Note that we don't register the operator[] directly, as it doesn't do bounds checking + r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Automatic conversion from values + r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddStringDouble), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDoubleString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddStringFloat), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloatString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddStringInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddStringUInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddStringBool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBoolString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Utilities + r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase), asCALL_CDECL_OBJLAST); assert(r >= 0); + + + r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat), asCALL_CDECL); assert(r >= 0); #if AS_USE_STLNAMES == 1 - // Same as length - r = engine->RegisterObjectMethod("string", "uint size() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - // Same as isEmpty - r = engine->RegisterObjectMethod("string", "bool empty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - // Same as findFirst - r = engine->RegisterObjectMethod("string", "int find(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - // Same as findLast - r = engine->RegisterObjectMethod("string", "int rfind(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as length + r = engine->RegisterObjectMethod("string", "uint size() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as isEmpty + r = engine->RegisterObjectMethod("string", "bool empty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as findFirst + r = engine->RegisterObjectMethod("string", "int find(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as findLast + r = engine->RegisterObjectMethod("string", "int rfind(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); #endif - // TODO: Implement the following - // findAndReplace - replaces a text found in the string - // replaceRange - replaces a range of bytes in the string - // multiply/times/opMul/opMul_r - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----" + // TODO: Implement the following + // findAndReplace - replaces a text found in the string + // replaceRange - replaces a range of bytes in the string + // multiply/times/opMul/opMul_r - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----" } static void ConstructStringGeneric(asIScriptGeneric * gen) { - new (gen->GetObject()) string(); + new (gen->GetObject()) string(); } static void CopyConstructStringGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetArgObject(0)); - new (gen->GetObject()) string(*a); + string * a = static_cast(gen->GetArgObject(0)); + new (gen->GetObject()) string(*a); } static void DestructStringGeneric(asIScriptGeneric * gen) { - string * ptr = static_cast(gen->GetObject()); - ptr->~string(); + string * ptr = static_cast(gen->GetObject()); + ptr->~string(); } static void AssignStringGeneric(asIScriptGeneric *gen) { - string * a = static_cast(gen->GetArgObject(0)); - string * self = static_cast(gen->GetObject()); - *self = *a; - gen->SetReturnAddress(self); + string * a = static_cast(gen->GetArgObject(0)); + string * self = static_cast(gen->GetObject()); + *self = *a; + gen->SetReturnAddress(self); } static void AddAssignStringGeneric(asIScriptGeneric *gen) { - string * a = static_cast(gen->GetArgObject(0)); - string * self = static_cast(gen->GetObject()); - *self += *a; - gen->SetReturnAddress(self); + string * a = static_cast(gen->GetArgObject(0)); + string * self = static_cast(gen->GetObject()); + *self += *a; + gen->SetReturnAddress(self); } static void StringEqualsGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); - *(bool*)gen->GetAddressOfReturnLocation() = (*a == *b); + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + *(bool*)gen->GetAddressOfReturnLocation() = (*a == *b); } static void StringCmpGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); - int cmp = 0; - if( *a < *b ) cmp = -1; - else if( *a > *b ) cmp = 1; + int cmp = 0; + if( *a < *b ) cmp = -1; + else if( *a > *b ) cmp = 1; - *(int*)gen->GetAddressOfReturnLocation() = cmp; + *(int*)gen->GetAddressOfReturnLocation() = cmp; } static void StringAddGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); - string ret_val = *a + *b; - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + string ret_val = *a + *b; + gen->SetReturnObject(&ret_val); } static void StringLengthGeneric(asIScriptGeneric * gen) { - string * self = static_cast(gen->GetObject()); - *static_cast(gen->GetAddressOfReturnLocation()) = (asUINT)self->length(); + string * self = static_cast(gen->GetObject()); + *static_cast(gen->GetAddressOfReturnLocation()) = (asUINT)self->length(); } static void StringIsEmptyGeneric(asIScriptGeneric * gen) { - string * self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringIsEmpty(*self); + string * self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringIsEmpty(*self); } static void StringResizeGeneric(asIScriptGeneric * gen) { - string * self = static_cast(gen->GetObject()); - self->resize(*static_cast(gen->GetAddressOfArg(0))); + string * self = static_cast(gen->GetObject()); + self->resize(*static_cast(gen->GetAddressOfArg(0))); } static void StringInsert_Generic(asIScriptGeneric *gen) { - string * self = static_cast(gen->GetObject()); - asUINT pos = gen->GetArgDWord(0); - string *other = reinterpret_cast(gen->GetArgAddress(1)); - StringInsert(pos, *other, *self); + string * self = static_cast(gen->GetObject()); + asUINT pos = gen->GetArgDWord(0); + string *other = reinterpret_cast(gen->GetArgAddress(1)); + StringInsert(pos, *other, *self); } static void StringErase_Generic(asIScriptGeneric *gen) { - string * self = static_cast(gen->GetObject()); - asUINT pos = gen->GetArgDWord(0); - int count = int(gen->GetArgDWord(1)); - StringErase(pos, count, *self); + string * self = static_cast(gen->GetObject()); + asUINT pos = gen->GetArgDWord(0); + int count = int(gen->GetArgDWord(1)); + StringErase(pos, count, *self); } static void StringFindFirst_Generic(asIScriptGeneric * gen) { - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirst(*find, start, *self); + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirst(*find, start, *self); } static void StringFindLast_Generic(asIScriptGeneric * gen) { - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLast(*find, start, *self); + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLast(*find, start, *self); } static void StringFindFirstOf_Generic(asIScriptGeneric * gen) { - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstOf(*find, start, *self); + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstOf(*find, start, *self); } static void StringFindLastOf_Generic(asIScriptGeneric * gen) { - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastOf(*find, start, *self); + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastOf(*find, start, *self); } static void StringFindFirstNotOf_Generic(asIScriptGeneric * gen) { - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstNotOf(*find, start, *self); + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstNotOf(*find, start, *self); } static void StringFindLastNotOf_Generic(asIScriptGeneric * gen) { - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastNotOf(*find, start, *self); + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastNotOf(*find, start, *self); } static void formatInt_Generic(asIScriptGeneric * gen) { - asINT64 val = gen->GetArgQWord(0); - string *options = reinterpret_cast(gen->GetArgAddress(1)); - asUINT width = gen->GetArgDWord(2); - new(gen->GetAddressOfReturnLocation()) string(formatInt(val, *options, width)); + asINT64 val = gen->GetArgQWord(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + new(gen->GetAddressOfReturnLocation()) string(formatInt(val, *options, width)); } static void formatUInt_Generic(asIScriptGeneric * gen) { - asQWORD val = gen->GetArgQWord(0); - string *options = reinterpret_cast(gen->GetArgAddress(1)); - asUINT width = gen->GetArgDWord(2); - new(gen->GetAddressOfReturnLocation()) string(formatUInt(val, *options, width)); + asQWORD val = gen->GetArgQWord(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + new(gen->GetAddressOfReturnLocation()) string(formatUInt(val, *options, width)); } static void formatFloat_Generic(asIScriptGeneric *gen) { - double val = gen->GetArgDouble(0); - string *options = reinterpret_cast(gen->GetArgAddress(1)); - asUINT width = gen->GetArgDWord(2); - asUINT precision = gen->GetArgDWord(3); - new(gen->GetAddressOfReturnLocation()) string(formatFloat(val, *options, width, precision)); + double val = gen->GetArgDouble(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + asUINT precision = gen->GetArgDWord(3); + new(gen->GetAddressOfReturnLocation()) string(formatFloat(val, *options, width, precision)); } static void parseInt_Generic(asIScriptGeneric *gen) { - string *str = reinterpret_cast(gen->GetArgAddress(0)); - asUINT base = gen->GetArgDWord(1); - asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); - gen->SetReturnQWord(parseInt(*str,base,byteCount)); + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT base = gen->GetArgDWord(1); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); + gen->SetReturnQWord(parseInt(*str,base,byteCount)); } static void parseUInt_Generic(asIScriptGeneric *gen) { - string *str = reinterpret_cast(gen->GetArgAddress(0)); - asUINT base = gen->GetArgDWord(1); - asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); - gen->SetReturnQWord(parseUInt(*str, base, byteCount)); + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT base = gen->GetArgDWord(1); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); + gen->SetReturnQWord(parseUInt(*str, base, byteCount)); } static void parseFloat_Generic(asIScriptGeneric *gen) { - string *str = reinterpret_cast(gen->GetArgAddress(0)); - asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(1)); - gen->SetReturnDouble(parseFloat(*str,byteCount)); + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(1)); + gen->SetReturnDouble(parseFloat(*str,byteCount)); } static void StringCharAtGeneric(asIScriptGeneric * gen) { - unsigned int index = gen->GetArgDWord(0); - string * self = static_cast(gen->GetObject()); + unsigned int index = gen->GetArgDWord(0); + string * self = static_cast(gen->GetObject()); - if (index >= self->size()) - { - // Set a script exception - asIScriptContext *ctx = asGetActiveContext(); - ctx->SetException("Out of range"); + if (index >= self->size()) + { + // Set a script exception + asIScriptContext *ctx = asGetActiveContext(); + ctx->SetException("Out of range"); - gen->SetReturnAddress(0); - } - else - { - gen->SetReturnAddress(&(self->operator [](index))); - } + gen->SetReturnAddress(0); + } + else + { + gen->SetReturnAddress(&(self->operator [](index))); + } } static void AssignInt2StringGeneric(asIScriptGeneric *gen) { - asINT64 *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self = sstr.str(); - gen->SetReturnAddress(self); + asINT64 *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); } static void AssignUInt2StringGeneric(asIScriptGeneric *gen) { - asQWORD *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self = sstr.str(); - gen->SetReturnAddress(self); + asQWORD *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); } static void AssignDouble2StringGeneric(asIScriptGeneric *gen) { - double *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self = sstr.str(); - gen->SetReturnAddress(self); + double *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); } static void AssignFloat2StringGeneric(asIScriptGeneric *gen) { - float *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self = sstr.str(); - gen->SetReturnAddress(self); + float *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); } static void AssignBool2StringGeneric(asIScriptGeneric *gen) { - bool *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << (*a ? "true" : "false"); - *self = sstr.str(); - gen->SetReturnAddress(self); + bool *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false"); + *self = sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignDouble2StringGeneric(asIScriptGeneric * gen) { - double * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); + double * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignFloat2StringGeneric(asIScriptGeneric * gen) { - float * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); + float * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignInt2StringGeneric(asIScriptGeneric * gen) { - asINT64 * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); + asINT64 * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignUInt2StringGeneric(asIScriptGeneric * gen) { - asQWORD * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); + asQWORD * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddAssignBool2StringGeneric(asIScriptGeneric * gen) { - bool * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << (*a ? "true" : "false"); - *self += sstr.str(); - gen->SetReturnAddress(self); + bool * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false"); + *self += sstr.str(); + gen->SetReturnAddress(self); } static void AddString2DoubleGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - double * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + double * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddString2FloatGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - float * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + float * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddString2IntGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - asINT64 * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + asINT64 * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddString2UIntGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - asQWORD * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + asQWORD * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddString2BoolGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetObject()); - bool * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << (*b ? "true" : "false"); - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + string * a = static_cast(gen->GetObject()); + bool * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << (*b ? "true" : "false"); + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddDouble2StringGeneric(asIScriptGeneric * gen) { - double* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + double* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddFloat2StringGeneric(asIScriptGeneric * gen) { - float* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + float* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddInt2StringGeneric(asIScriptGeneric * gen) { - asINT64* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + asINT64* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddUInt2StringGeneric(asIScriptGeneric * gen) { - asQWORD* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + asQWORD* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void AddBool2StringGeneric(asIScriptGeneric * gen) { - bool* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << (*a ? "true" : "false") << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); + bool* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false") << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); } static void StringSubString_Generic(asIScriptGeneric *gen) { - // Get the arguments - string *str = (string*)gen->GetObject(); - asUINT start = *(int*)gen->GetAddressOfArg(0); - int count = *(int*)gen->GetAddressOfArg(1); + // Get the arguments + string *str = (string*)gen->GetObject(); + asUINT start = *(int*)gen->GetAddressOfArg(0); + int count = *(int*)gen->GetAddressOfArg(1); - // Return the substring - new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str)); + // Return the substring + new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str)); } void RegisterStdString_Generic(asIScriptEngine *engine) { - int r = 0; - UNUSED_VAR(r); + int r = 0; + UNUSED_VAR(r); - // Register the string type - r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); + // Register the string type + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); - r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); + r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); - // Register the object operator overloads - r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asFUNCTION(AssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + // Register the object operator overloads + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asFUNCTION(AssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTION(StringEqualsGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmpGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTION(StringAddGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTION(StringEqualsGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmpGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTION(StringAddGeneric), asCALL_GENERIC); assert( r >= 0 ); - // Register the object methods + // Register the object methods #if AS_USE_ACCESSORS != 1 - r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); #endif - r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); #if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 - r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); #endif - r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmptyGeneric), asCALL_GENERIC); assert( r >= 0 ); - - // Register the index operator, both as a mutator and as an inspector - r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); - - // Automatic conversion from values - r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddString2DoubleGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddString2FloatGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddString2BoolGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase_Generic), asCALL_GENERIC); assert(r >= 0); - - - r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmptyGeneric), asCALL_GENERIC); assert( r >= 0 ); + + // Register the index operator, both as a mutator and as an inspector + r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); + + // Automatic conversion from values + r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddString2DoubleGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddString2FloatGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddString2BoolGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase_Generic), asCALL_GENERIC); assert(r >= 0); + + + r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat_Generic), asCALL_GENERIC); assert(r >= 0); } void RegisterStdString(asIScriptEngine * engine) { - if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) - RegisterStdString_Generic(engine); - else - RegisterStdString_Native(engine); + if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) + RegisterStdString_Generic(engine); + else + RegisterStdString_Native(engine); } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/scriptstdstring/scriptstdstring.h b/src/angelscript/add_on/scriptstdstring/scriptstdstring.h index 0960beba645..fc0d8c89a17 100644 --- a/src/angelscript/add_on/scriptstdstring/scriptstdstring.h +++ b/src/angelscript/add_on/scriptstdstring/scriptstdstring.h @@ -3,7 +3,7 @@ // // This function registers the std::string type with AngelScript to be used as the default string type. // -// The string type is registered as a value type, thus may have performance issues if a lot of +// The string type is registered as a value type, thus may have performance issues if a lot of // string operations are performed in the script. However, for relatively few operations, this should // not cause any problem for most applications. // @@ -11,7 +11,7 @@ #ifndef SCRIPTSTDSTRING_H #define SCRIPTSTDSTRING_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif diff --git a/src/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp b/src/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp index 930681f39ca..708499ec02a 100644 --- a/src/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp +++ b/src/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp @@ -22,45 +22,45 @@ BEGIN_AS_NAMESPACE // array@ string::split(const string &in delim) const static CScriptArray *StringSplit(const string &delim, const string &str) { - // Obtain a pointer to the engine - asIScriptContext *ctx = asGetActiveContext(); - asIScriptEngine *engine = ctx->GetEngine(); - - // TODO: This should only be done once - // TODO: This assumes that CScriptArray was already registered - asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); - - // Create the array object - CScriptArray *array = CScriptArray::Create(arrayType); - - // Find the existence of the delimiter in the input string - int pos = 0, prev = 0, count = 0; - while( (pos = (int)str.find(delim, prev)) != (int)string::npos ) - { - // Add the part to the array - array->Resize(array->GetSize()+1); - ((string*)array->At(count))->assign(&str[prev], pos-prev); - - // Find the next part - count++; - prev = pos + (int)delim.length(); - } - - // Add the remaining part - array->Resize(array->GetSize()+1); - ((string*)array->At(count))->assign(&str[prev]); - - return array; + // Obtain a pointer to the engine + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); + + // TODO: This should only be done once + // TODO: This assumes that CScriptArray was already registered + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); + + // Create the array object + CScriptArray *array = CScriptArray::Create(arrayType); + + // Find the existence of the delimiter in the input string + int pos = 0, prev = 0, count = 0; + while( (pos = (int)str.find(delim, prev)) != (int)string::npos ) + { + // Add the part to the array + array->Resize(array->GetSize()+1); + ((string*)array->At(count))->assign(&str[prev], pos-prev); + + // Find the next part + count++; + prev = pos + (int)delim.length(); + } + + // Add the remaining part + array->Resize(array->GetSize()+1); + ((string*)array->At(count))->assign(&str[prev]); + + return array; } static void StringSplit_Generic(asIScriptGeneric *gen) { - // Get the arguments - string *str = (string*)gen->GetObject(); - string *delim = *(string**)gen->GetAddressOfArg(0); + // Get the arguments + string *str = (string*)gen->GetObject(); + string *delim = *(string**)gen->GetAddressOfArg(0); - // Return the array by handle - *(CScriptArray**)gen->GetAddressOfReturnLocation() = StringSplit(*delim, *str); + // Return the array by handle + *(CScriptArray**)gen->GetAddressOfReturnLocation() = StringSplit(*delim, *str); } @@ -80,32 +80,32 @@ static void StringSplit_Generic(asIScriptGeneric *gen) // string join(const array &in array, const string &in delim) static string StringJoin(const CScriptArray &array, const string &delim) { - // Create the new string - string str = ""; - if( array.GetSize() ) - { - int n; - for( n = 0; n < (int)array.GetSize() - 1; n++ ) - { - str += *(string*)array.At(n); - str += delim; - } - - // Add the last part - str += *(string*)array.At(n); - } - - return str; + // Create the new string + string str = ""; + if( array.GetSize() ) + { + int n; + for( n = 0; n < (int)array.GetSize() - 1; n++ ) + { + str += *(string*)array.At(n); + str += delim; + } + + // Add the last part + str += *(string*)array.At(n); + } + + return str; } static void StringJoin_Generic(asIScriptGeneric *gen) { - // Get the arguments - CScriptArray *array = *(CScriptArray**)gen->GetAddressOfArg(0); - string *delim = *(string**)gen->GetAddressOfArg(1); + // Get the arguments + CScriptArray *array = *(CScriptArray**)gen->GetAddressOfArg(0); + string *delim = *(string**)gen->GetAddressOfArg(1); - // Return the string - new(gen->GetAddressOfReturnLocation()) string(StringJoin(*array, *delim)); + // Return the string + new(gen->GetAddressOfReturnLocation()) string(StringJoin(*array, *delim)); } // This is where the utility functions are registered. @@ -113,16 +113,16 @@ static void StringJoin_Generic(asIScriptGeneric *gen) void RegisterStdStringUtils(asIScriptEngine *engine) { - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - { - engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0); - engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0); - } - else - { - engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0); - engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0); - } + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + { + engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0); + engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0); + } + else + { + engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0); + engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0); + } } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/serializer/serializer.cpp b/src/angelscript/add_on/serializer/serializer.cpp index a359fcddc6c..6ab04e12440 100644 --- a/src/angelscript/add_on/serializer/serializer.cpp +++ b/src/angelscript/add_on/serializer/serializer.cpp @@ -18,146 +18,146 @@ BEGIN_AS_NAMESPACE CSerializer::CSerializer() { - m_engine = 0; + m_engine = 0; } CSerializer::~CSerializer() { - // Extra objects need to be released, since they are not stored in - // the module and we cannot rely on the application releasing them - for( size_t i = 0; i < m_extraObjects.size(); i++ ) - { - SExtraObject &o = m_extraObjects[i]; - for( size_t i2 = 0; i2 < m_root.m_children.size(); i2++ ) - { - if( m_root.m_children[i2]->m_originalPtr == o.originalObject && m_root.m_children[i2]->m_restorePtr ) - reinterpret_cast(m_root.m_children[i2]->m_restorePtr)->Release(); - } - } - - // 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(); + // Extra objects need to be released, since they are not stored in + // the module and we cannot rely on the application releasing them + for( size_t i = 0; i < m_extraObjects.size(); i++ ) + { + SExtraObject &o = m_extraObjects[i]; + for( size_t i2 = 0; i2 < m_root.m_children.size(); i2++ ) + { + if( m_root.m_children[i2]->m_originalPtr == o.originalObject && m_root.m_children[i2]->m_restorePtr ) + reinterpret_cast(m_root.m_children[i2]->m_restorePtr)->Release(); + } + } + + // 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; + 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; + 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]; - asITypeInfo *type = m_mod->GetTypeInfoByName( 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; + 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]; + asITypeInfo *type = m_mod->GetTypeInfoByName( 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 ); + return m_root.GetPointerToRestoredObject( ptr ); } void CSerializer::AddExtraObjectToStore( asIScriptObject *object ) { - if( !object ) - return; + 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; + // 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(); + SExtraObject o; + o.originalObject = object; + o.originalClassName = object->GetObjectType()->GetName(); + o.originalTypeId = object->GetTypeId(); - m_extraObjects.push_back( o ); + m_extraObjects.push_back( o ); } @@ -165,384 +165,384 @@ void CSerializer::AddExtraObjectToStore( asIScriptObject *object ) CSerializedValue::CSerializedValue() { - Init(); + Init(); } -CSerializedValue::CSerializedValue(CSerializedValue *parent, const std::string &name, const std::string &nameSpace, void *ref, int typeId) +CSerializedValue::CSerializedValue(CSerializedValue *parent, const std::string &name, const std::string &nameSpace, void *ref, int typeId) { - Init(); + Init(); - m_name = name; - m_nameSpace = nameSpace; - m_serializer = parent->m_serializer; - Store(ref, typeId); + 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; + 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; + m_isInit = false; - ClearChildren(); + ClearChildren(); - if( m_userData ) - { - CUserType *type = m_serializer->m_userTypes[m_typeName]; - if( type ) - type->CleanupUserData(this); - m_userData = 0; - } + 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->GetTypeInfoById(m_children[0]->m_typeId)); - } - - for( size_t n = 0; n < m_children.size(); n++ ) - delete m_children[n]; - m_children.clear(); + // 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->GetTypeInfoById(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(); + 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]; + 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; + return 0; } void CSerializedValue::GetAllPointersOfChildren(std::vector *ptrs) { - ptrs->push_back(m_originalPtr); + ptrs->push_back(m_originalPtr); - for( size_t i = 0; i < m_children.size(); ++i ) - m_children[i]->GetAllPointersOfChildren(ptrs); + 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; + 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; - } + for( size_t i = 0; i < m_children.size(); i++ ) + { + CSerializedValue *find = m_children[i]->FindByPtr(ptr); + if( find ) + return find; + } - return 0; + return 0; } void *CSerializedValue::GetPointerToRestoredObject(void *ptr) { - if( m_originalPtr == ptr ) - return m_restorePtr; + 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; - } + for( size_t i = 0; i < m_children.size(); ++i ) + { + void *ret = m_children[i]->GetPointerToRestoredObject(ptr); + if( ret ) + return ret; + } - return 0; + 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; + // 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; - asITypeInfo *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); - else - { - // POD-types can be stored without need for user type - asITypeInfo *type = GetType(); - if( type && (type->GetFlags() & asOBJ_POD) ) - size = GetType()->GetSize(); - - // It is not necessary to report an error here if it is not a POD-type as that will be done when restoring - } - } - - if( size ) - { - m_mem.resize(size); - memcpy(&m_mem[0], ref, size); - } - } + 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; + asITypeInfo *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); + else + { + // POD-types can be stored without need for user type + asITypeInfo *type = GetType(); + if( type && (type->GetFlags() & asOBJ_POD) ) + size = GetType()->GetSize(); + + // It is not necessary to report an error here if it is not a POD-type as that will be done when restoring + } + } + + 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; - asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(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 ) - { - asITypeInfo *ctype = m_children[0]->GetType(); - - if( ctype->GetFactoryCount() == 0 ) - { - // There are no factories, so assume the same pointer is going to be used - m_children[0]->m_restorePtr = m_handlePtr; - - // Increase the refCount for the object as it will be released upon clean-up - m_serializer->m_engine->AddRefScriptObject(m_handlePtr, ctype); - } - 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(ctype); - m_children[0]->Restore(newObject, ctype->GetTypeId()); - } - } - } - else if( m_typeId & asTYPEID_SCRIPTOBJECT ) - { - asIScriptObject *obj = (asIScriptObject *)ref; - - // Retrieve children - for( asUINT i = 0; i < type->GetPropertyCount() ; i++ ) - { - const char *nameProperty; - int ptypeId; - type->GetProperty(i, &nameProperty, &ptypeId); - - CSerializedValue *var = FindByName(nameProperty, ""); - if( var ) - var->Restore(obj->GetAddressOfProperty(i), ptypeId); - } - } - 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()); - } - } + 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; + asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(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 ) + { + asITypeInfo *ctype = m_children[0]->GetType(); + + if( ctype->GetFactoryCount() == 0 ) + { + // There are no factories, so assume the same pointer is going to be used + m_children[0]->m_restorePtr = m_handlePtr; + + // Increase the refCount for the object as it will be released upon clean-up + m_serializer->m_engine->AddRefScriptObject(m_handlePtr, ctype); + } + 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(ctype); + m_children[0]->Restore(newObject, ctype->GetTypeId()); + } + } + } + else if( m_typeId & asTYPEID_SCRIPTOBJECT ) + { + asIScriptObject *obj = (asIScriptObject *)ref; + + // Retrieve children + for( asUINT i = 0; i < type->GetPropertyCount() ; i++ ) + { + const char *nameProperty; + int ptypeId; + type->GetProperty(i, &nameProperty, &ptypeId); + + CSerializedValue *var = FindByName(nameProperty, ""); + if( var ) + var->Restore(obj->GetAddressOfProperty(i), ptypeId); + } + } + 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]); - } - } + 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 - asITypeInfo *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(); + 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 + asITypeInfo *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 ) - { - asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(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->GetTypeInfoById(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(); + 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 ) + { + asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(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->GetTypeInfoById(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; + m_typeId = typeId; - asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(typeId); + asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(typeId); - if( type ) - m_typeName = type->GetName(); + if( type ) + m_typeName = type->GetName(); } asITypeInfo *CSerializedValue::GetType() { - if( !m_typeName.empty() ) - { - int newTypeId = m_serializer->m_mod->GetTypeIdByDecl(m_typeName.c_str()); - return m_serializer->m_engine->GetTypeInfoById(newTypeId); - } + if( !m_typeName.empty() ) + { + int newTypeId = m_serializer->m_mod->GetTypeIdByDecl(m_typeName.c_str()); + return m_serializer->m_engine->GetTypeInfoById(newTypeId); + } - return 0; + return 0; } void CSerializedValue::SetUserData(void *data) { - m_userData = data; + m_userData = data; } void *CSerializedValue::GetUserData() { - return m_userData; + return m_userData; } END_AS_NAMESPACE diff --git a/src/angelscript/add_on/serializer/serializer.h b/src/angelscript/add_on/serializer/serializer.h index 2d91cbe8195..746d8c3802f 100644 --- a/src/angelscript/add_on/serializer/serializer.h +++ b/src/angelscript/add_on/serializer/serializer.h @@ -8,7 +8,7 @@ #ifndef SERIALIZER_H #define SERIALIZER_H -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -27,164 +27,164 @@ class CSerializedValue; // 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*/) {} + 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(); + 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); + // Save the object and its children + void Store(void *ref, int refTypeId); - // Restore the object and its children - void Restore(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); + // Set type of this var + void SetType(int typeId); - // Returns the object type for non-primitives - asITypeInfo *GetType(); + // Returns the object type for non-primitives + asITypeInfo *GetType(); - // Get child by name variable - CSerializedValue *FindByName(const std::string &name, const std::string &nameSpace); + // Get child by name variable + CSerializedValue *FindByName(const std::string &name, const std::string &nameSpace); - // Find variable by ptr - CSerializedValue *FindByPtr(void *ptr); + // Find variable by ptr + CSerializedValue *FindByPtr(void *ptr); - // User data - void *GetUserData(); - void SetUserData(void *data); + // 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; + // 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; + friend class CSerializer; - void Init(); - void Uninit(); + void Init(); + void Uninit(); - // you first need to save all the objects before you can save references to objects - void ReplaceHandles(); + // 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(); + // 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); + // 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); + // 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); + // 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); + // ptr - is a handle to class + void *GetPointerToRestoredObject(void *ptr); - // Cleanup children - void ClearChildren(); + // Cleanup children + void ClearChildren(); - // The serializer object - CSerializer *m_serializer; + // The serializer object + CSerializer *m_serializer; - // The user data can be used by CUserType to store extra information - void *m_userData; + // 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; + // 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; + // 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; - // Is initialized - bool m_isInit; + // Name of variable or property + std::string m_name; + std::string m_nameSpace; - // '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; + // Is initialized + bool m_isInit; - // where handle references - // While storing, this points to the actual object. - // While restoring, it is just a unique identifier. - void *m_handlePtr; + // '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; - // 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; + // where handle references + // While storing, this points to the actual object. + // While restoring, it is just a unique identifier. + void *m_handlePtr; - // Serialized data for primitives - std::vector m_mem; + // 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. +// 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 +// 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); + 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); + // Store all global variables in the module + int Store(asIScriptModule *mod); - // Restore all global variables after reloading script - int Restore(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); + // 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); + // Return new pointer to restored object + void *GetPointerToRestoredObject(void *originalObject); protected: - friend class CSerializedValue; + friend class CSerializedValue; - CSerializedValue m_root; - asIScriptEngine *m_engine; - asIScriptModule *m_mod; + CSerializedValue m_root; + asIScriptEngine *m_engine; + asIScriptModule *m_mod; - std::map m_userTypes; + std::map m_userTypes; - struct SExtraObject - { - asIScriptObject *originalObject; - std::string originalClassName; - int originalTypeId; - }; + struct SExtraObject + { + asIScriptObject *originalObject; + std::string originalClassName; + int originalTypeId; + }; - std::vector m_extraObjects; + std::vector m_extraObjects; }; diff --git a/src/angelscript/add_on/weakref/weakref.cpp b/src/angelscript/add_on/weakref/weakref.cpp index 385ff7155a0..9842320b686 100644 --- a/src/angelscript/add_on/weakref/weakref.cpp +++ b/src/angelscript/add_on/weakref/weakref.cpp @@ -10,367 +10,367 @@ BEGIN_AS_NAMESPACE static void ScriptWeakRefConstruct(asITypeInfo *type, void *mem) { - new(mem) CScriptWeakRef(type); + new(mem) CScriptWeakRef(type); } static void ScriptWeakRefConstruct2(asITypeInfo *type, void *ref, void *mem) { - new(mem) CScriptWeakRef(ref, type); + new(mem) CScriptWeakRef(ref, type); - // It's possible the constructor raised a script exception, in which case we - // need to call the destructor in order to cleanup the memory before returning - asIScriptContext *ctx = asGetActiveContext(); - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - reinterpret_cast(mem)->~CScriptWeakRef(); + // It's possible the constructor raised a script exception, in which case we + // need to call the destructor in order to cleanup the memory before returning + asIScriptContext *ctx = asGetActiveContext(); + if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) + reinterpret_cast(mem)->~CScriptWeakRef(); } static void ScriptWeakRefDestruct(CScriptWeakRef *obj) { - obj->~CScriptWeakRef(); + obj->~CScriptWeakRef(); } static bool ScriptWeakRefTemplateCallback(asITypeInfo *ti, bool &/*dontGarbageCollect*/) { - asITypeInfo *subType = ti->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( ti->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; - } - - ti->GetEngine()->WriteMessage("weakref", 0, 0, asMSGTYPE_ERROR, "The subtype doesn't support weak references"); - return false; + asITypeInfo *subType = ti->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( ti->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; + } + + ti->GetEngine()->WriteMessage("weakref", 0, 0, asMSGTYPE_ERROR, "The subtype doesn't support weak references"); + return false; } CScriptWeakRef::CScriptWeakRef(asITypeInfo *type) { - m_ref = 0; - m_type = type; - m_type->AddRef(); - m_weakRefFlag = 0; + m_ref = 0; + m_type = type; + m_type->AddRef(); + m_weakRefFlag = 0; } CScriptWeakRef::CScriptWeakRef(const CScriptWeakRef &other) { - m_ref = other.m_ref; - m_type = other.m_type; - m_type->AddRef(); - m_weakRefFlag = other.m_weakRefFlag; - if( m_weakRefFlag ) - m_weakRefFlag->AddRef(); + 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, asITypeInfo *type) { - 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(); + 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(); + if( m_type ) + m_type->Release(); + if( m_weakRefFlag ) + m_weakRefFlag->Release(); } CScriptWeakRef &CScriptWeakRef::operator =(const CScriptWeakRef &other) { - // Don't do anything if it is the same reference - // It is not enough to verify only the reference to the object, as the - // address may be reused by another instance after the first has been freed. - // By checking also the weakRefFlag we can be certain that it is the same - // instance. - if( m_ref == other.m_ref && - m_weakRefFlag == other.m_weakRefFlag ) - return *this; - - // Must not allow changing the type - if( m_type != other.m_type ) - { - // We can allow a weakref to be assigned to a const_weakref - if( !(strcmp(m_type->GetName(), "const_weakref") == 0 && - strcmp(other.m_type->GetName(), "weakref") == 0 && - m_type->GetSubType() == other.m_type->GetSubType()) ) - { - assert( false ); - return *this; - } - } - - m_ref = other.m_ref; - - if( m_weakRefFlag ) - m_weakRefFlag->Release(); - m_weakRefFlag = other.m_weakRefFlag; - if( m_weakRefFlag ) - m_weakRefFlag->AddRef(); - - return *this; + // Don't do anything if it is the same reference + // It is not enough to verify only the reference to the object, as the + // address may be reused by another instance after the first has been freed. + // By checking also the weakRefFlag we can be certain that it is the same + // instance. + if( m_ref == other.m_ref && + m_weakRefFlag == other.m_weakRefFlag ) + return *this; + + // Must not allow changing the type + if( m_type != other.m_type ) + { + // We can allow a weakref to be assigned to a const_weakref + if( !(strcmp(m_type->GetName(), "const_weakref") == 0 && + strcmp(other.m_type->GetName(), "weakref") == 0 && + m_type->GetSubType() == other.m_type->GetSubType()) ) + { + assert( false ); + return *this; + } + } + + m_ref = other.m_ref; + + if( m_weakRefFlag ) + m_weakRefFlag->Release(); + m_weakRefFlag = other.m_weakRefFlag; + if( m_weakRefFlag ) + m_weakRefFlag->AddRef(); + + return *this; } CScriptWeakRef &CScriptWeakRef::Set(void *newRef) { - // Release the previous weak ref - if( m_weakRefFlag ) - m_weakRefFlag->Release(); - - // Retrieve the new weak ref - m_ref = newRef; - if( newRef ) - { - m_weakRefFlag = m_type->GetEngine()->GetWeakRefFlagOfScriptObject(newRef, m_type->GetSubType()); - m_weakRefFlag->AddRef(); - } - else - m_weakRefFlag = 0; - - // Release the newRef since we're only supposed to hold a weakref - m_type->GetEngine()->ReleaseScriptObject(newRef, m_type->GetSubType()); - - return *this; + // Release the previous weak ref + if( m_weakRefFlag ) + m_weakRefFlag->Release(); + + // Retrieve the new weak ref + m_ref = newRef; + if( newRef ) + { + m_weakRefFlag = m_type->GetEngine()->GetWeakRefFlagOfScriptObject(newRef, m_type->GetSubType()); + m_weakRefFlag->AddRef(); + } + else + m_weakRefFlag = 0; + + // Release the newRef since we're only supposed to hold a weakref + m_type->GetEngine()->ReleaseScriptObject(newRef, m_type->GetSubType()); + + return *this; } asITypeInfo *CScriptWeakRef::GetRefType() const { - return m_type->GetSubType(); + return m_type->GetSubType(); } bool CScriptWeakRef::operator==(const CScriptWeakRef &o) const { - // It is not enough to compare just the address of the object, as it may - // be reused by another instance after the first has been freed. By verifying - // also the weakRefFlag we can guarantee that it is indeed the same instance. - if( m_ref == o.m_ref && - m_weakRefFlag == o.m_weakRefFlag && - 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; + // It is not enough to compare just the address of the object, as it may + // be reused by another instance after the first has been freed. By verifying + // also the weakRefFlag we can guarantee that it is indeed the same instance. + if( m_ref == o.m_ref && + m_weakRefFlag == o.m_weakRefFlag && + 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); + 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; + // 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; } bool CScriptWeakRef::Equals(void *ref) const { - if( m_ref != ref ) - return false; + if( m_ref != ref ) + return false; - // It is not enough to compare just the address, as another instance may - // get the same address after the first instance has been freed. Verify the - // weakref flag too to make sure it is the same instance - asILockableSharedBool *flag = m_type->GetEngine()->GetWeakRefFlagOfScriptObject(ref, m_type->GetSubType()); - if (m_weakRefFlag != flag) - return false; + // It is not enough to compare just the address, as another instance may + // get the same address after the first instance has been freed. Verify the + // weakref flag too to make sure it is the same instance + asILockableSharedBool *flag = m_type->GetEngine()->GetWeakRefFlagOfScriptObject(ref, m_type->GetSubType()); + if (m_weakRefFlag != flag) + return false; - return true; + return true; } void RegisterScriptWeakRef_Native(asIScriptEngine *engine) { - int r; - - // Register a type for non-const handles - r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); 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->RegisterObjectMethod("weakref", "T@ opImplCast()", asMETHOD(CScriptWeakRef, Get), 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 &opHndlAssign(const weakref &in)", asMETHOD(CScriptWeakRef, operator=), 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 ); - r = engine->RegisterObjectMethod("weakref", "weakref &opHndlAssign(T@)", asMETHOD(CScriptWeakRef, Set), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("weakref", "bool opEquals(const T@+) const", asMETHOD(CScriptWeakRef, Equals), asCALL_THISCALL); assert(r >= 0); - - // Register another type for const handles - r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); 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->RegisterObjectMethod("const_weakref", "const T@ opImplCast() const", asMETHOD(CScriptWeakRef, Get), 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 &opHndlAssign(const const_weakref &in)", asMETHOD(CScriptWeakRef, operator=), 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 ); - r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const T@)", asMETHOD(CScriptWeakRef, Set), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const T@+) const", asMETHOD(CScriptWeakRef, Equals), asCALL_THISCALL); assert(r >= 0); - - // Allow non-const weak references to be converted to const weak references - r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(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 ); + int r; + + // Register a type for non-const handles + r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); 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->RegisterObjectMethod("weakref", "T@ opImplCast()", asMETHOD(CScriptWeakRef, Get), 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 &opHndlAssign(const weakref &in)", asMETHOD(CScriptWeakRef, operator=), 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 ); + r = engine->RegisterObjectMethod("weakref", "weakref &opHndlAssign(T@)", asMETHOD(CScriptWeakRef, Set), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "bool opEquals(const T@+) const", asMETHOD(CScriptWeakRef, Equals), asCALL_THISCALL); assert(r >= 0); + + // Register another type for const handles + r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); 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->RegisterObjectMethod("const_weakref", "const T@ opImplCast() const", asMETHOD(CScriptWeakRef, Get), 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 &opHndlAssign(const const_weakref &in)", asMETHOD(CScriptWeakRef, operator=), 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 ); + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const T@)", asMETHOD(CScriptWeakRef, Set), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const T@+) const", asMETHOD(CScriptWeakRef, Equals), asCALL_THISCALL); assert(r >= 0); + + // Allow non-const weak references to be converted to const weak references + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(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 ScriptWeakRefConstruct_Generic(asIScriptGeneric *gen) { - asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); + asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); - ScriptWeakRefConstruct(ti, gen->GetObject()); + ScriptWeakRefConstruct(ti, gen->GetObject()); } static void ScriptWeakRefConstruct2_Generic(asIScriptGeneric *gen) { - asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); - void *ref = gen->GetArgAddress(1); + asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); + void *ref = gen->GetArgAddress(1); - ScriptWeakRefConstruct2(ti, ref, gen->GetObject()); + ScriptWeakRefConstruct2(ti, ref, gen->GetObject()); } static void ScriptWeakRefDestruct_Generic(asIScriptGeneric *gen) { - CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); - self->~CScriptWeakRef(); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + self->~CScriptWeakRef(); } void CScriptWeakRef_Get_Generic(asIScriptGeneric *gen) { - CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); - gen->SetReturnAddress(self->Get()); + 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); + CScriptWeakRef *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + *self = *other; + gen->SetReturnAddress(self); } void CScriptWeakRef_Assign2_Generic(asIScriptGeneric *gen) { - void *other = gen->GetArgAddress(0); - CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); - self->Set(other); - gen->SetReturnAddress(self); + void *other = gen->GetArgAddress(0); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + self->Set(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); + CScriptWeakRef *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + gen->SetReturnByte(*self == *other); } void CScriptWeakRef_Equals2_Generic(asIScriptGeneric *gen) { - void *other = gen->GetArgAddress(0); - CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + void *other = gen->GetArgAddress(0); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); - gen->SetReturnByte(self->Equals(other)); + gen->SetReturnByte(self->Equals(other)); } static void ScriptWeakRefTemplateCallback_Generic(asIScriptGeneric *gen) { - asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); - bool *dontGarbageCollect = *reinterpret_cast(gen->GetAddressOfArg(1)); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptWeakRefTemplateCallback(ti, *dontGarbageCollect); + asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); + bool *dontGarbageCollect = *reinterpret_cast(gen->GetAddressOfArg(1)); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptWeakRefTemplateCallback(ti, *dontGarbageCollect); } void RegisterScriptWeakRef_Generic(asIScriptEngine *engine) { - int r; - - // Register a type for non-const handles - r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2_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_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("weakref", "T@ opImplCast()", asFUNCTION(CScriptWeakRef_Get_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 &opHndlAssign(const weakref &in)", asFUNCTION(CScriptWeakRef_Assign_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 ); - r = engine->RegisterObjectMethod("weakref", "weakref &opHndlAssign(T@)", asFUNCTION(CScriptWeakRef_Assign2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("weakref", "bool opEquals(const T@+) const", asFUNCTION(CScriptWeakRef_Equals2_Generic), asCALL_GENERIC); assert(r >= 0); - - // Register another type for const handles - r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2_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_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("const_weakref", "const T@ opImplCast() const", asFUNCTION(CScriptWeakRef_Get_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 &opHndlAssign(const const_weakref &in)", asFUNCTION(CScriptWeakRef_Assign_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 ); - r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const T@)", asFUNCTION(CScriptWeakRef_Assign2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const T@+) const", asFUNCTION(CScriptWeakRef_Equals2_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 &opHndlAssign(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 ); + int r; + + // Register a type for non-const handles + r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2_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_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("weakref", "T@ opImplCast()", asFUNCTION(CScriptWeakRef_Get_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 &opHndlAssign(const weakref &in)", asFUNCTION(CScriptWeakRef_Assign_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 ); + r = engine->RegisterObjectMethod("weakref", "weakref &opHndlAssign(T@)", asFUNCTION(CScriptWeakRef_Assign2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "bool opEquals(const T@+) const", asFUNCTION(CScriptWeakRef_Equals2_Generic), asCALL_GENERIC); assert(r >= 0); + + // Register another type for const handles + r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2_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_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("const_weakref", "const T@ opImplCast() const", asFUNCTION(CScriptWeakRef_Get_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 &opHndlAssign(const const_weakref &in)", asFUNCTION(CScriptWeakRef_Assign_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 ); + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const T@)", asFUNCTION(CScriptWeakRef_Assign2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const T@+) const", asFUNCTION(CScriptWeakRef_Equals2_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 &opHndlAssign(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); + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptWeakRef_Generic(engine); + else + RegisterScriptWeakRef_Native(engine); } diff --git a/src/angelscript/add_on/weakref/weakref.h b/src/angelscript/add_on/weakref/weakref.h index ac24ea95716..e18e7dc452b 100644 --- a/src/angelscript/add_on/weakref/weakref.h +++ b/src/angelscript/add_on/weakref/weakref.h @@ -3,7 +3,7 @@ // The CScriptWeakRef class was originally implemented by vroad in March 2013 -#ifndef ANGELSCRIPT_H +#ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif @@ -11,44 +11,44 @@ BEGIN_AS_NAMESPACE -class CScriptWeakRef +class CScriptWeakRef { public: - // Constructors - CScriptWeakRef(asITypeInfo *type); - CScriptWeakRef(const CScriptWeakRef &other); - CScriptWeakRef(void *ref, asITypeInfo *type); + // Constructors + CScriptWeakRef(asITypeInfo *type); + CScriptWeakRef(const CScriptWeakRef &other); + CScriptWeakRef(void *ref, asITypeInfo *type); - ~CScriptWeakRef(); + ~CScriptWeakRef(); - // Copy the stored value from another weakref object - CScriptWeakRef &operator=(const CScriptWeakRef &other); + // 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; + // Compare equalness + bool operator==(const CScriptWeakRef &o) const; + bool operator!=(const CScriptWeakRef &o) const; - // Sets a new reference - CScriptWeakRef &Set(void *newRef); + // Sets a new reference + CScriptWeakRef &Set(void *newRef); - // Returns the object if it is still alive - // This will increment the refCount of the returned object - void *Get() const; + // Returns the object if it is still alive + // This will increment the refCount of the returned object + void *Get() const; - // Returns true if the contained reference is the same - bool Equals(void *ref) const; + // Returns true if the contained reference is the same + bool Equals(void *ref) const; - // Returns the type of the reference held - asITypeInfo *GetRefType() const; + // Returns the type of the reference held + asITypeInfo *GetRefType() const; protected: - // These functions need to have access to protected - // members in order to call them from the script engine - friend void RegisterScriptWeakRef_Native(asIScriptEngine *engine); + // These functions need to have access to protected + // members in order to call them from the script engine + friend void RegisterScriptWeakRef_Native(asIScriptEngine *engine); - void *m_ref; - asITypeInfo *m_type; - asILockableSharedBool *m_weakRefFlag; + void *m_ref; + asITypeInfo *m_type; + asILockableSharedBool *m_weakRefFlag; }; void RegisterScriptWeakRef(asIScriptEngine *engine); diff --git a/src/angelscript/include/angelscript.h b/src/angelscript/include/angelscript.h index 5c9900effcf..37ada2e4116 100644 --- a/src/angelscript/include/angelscript.h +++ b/src/angelscript/include/angelscript.h @@ -83,273 +83,273 @@ class asIStringFactory; // 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, - asMODULE_IS_IN_USE = -28 + 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, + asMODULE_IS_IN_USE = -28 }; // 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_DISALLOW_EMPTY_LIST_ELEMENTS = 23, - asEP_PRIVATE_PROP_AS_PROTECTED = 24, - asEP_ALLOW_UNICODE_IDENTIFIERS = 25, - asEP_HEREDOC_TRIM_MODE = 26, - asEP_MAX_NESTED_CALLS = 27, - asEP_GENERIC_CALL_MODE = 28, - asEP_INIT_STACK_SIZE = 29, - asEP_INIT_CALL_STACK_SIZE = 30, - asEP_MAX_CALL_STACK_SIZE = 31, - - asEP_LAST_PROPERTY + 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_DISALLOW_EMPTY_LIST_ELEMENTS = 23, + asEP_PRIVATE_PROP_AS_PROTECTED = 24, + asEP_ALLOW_UNICODE_IDENTIFIERS = 25, + asEP_HEREDOC_TRIM_MODE = 26, + asEP_MAX_NESTED_CALLS = 27, + asEP_GENERIC_CALL_MODE = 28, + asEP_INIT_STACK_SIZE = 29, + asEP_INIT_CALL_STACK_SIZE = 30, + asEP_MAX_CALL_STACK_SIZE = 31, + + 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 + 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_CLASS_MORE_CONSTRUCTORS = (1<<31), - 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_IMPLICIT_HANDLE = (1<<20), - asOBJ_MASK_VALID_FLAGS = 0x801FFFFF, - // Internal flags - asOBJ_SCRIPT_OBJECT = (1<<21), - asOBJ_SHARED = (1<<22), - asOBJ_NOINHERIT = (1<<23), - asOBJ_FUNCDEF = (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) + 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_CLASS_MORE_CONSTRUCTORS = (1<<31), + 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_IMPLICIT_HANDLE = (1<<20), + asOBJ_MASK_VALID_FLAGS = 0x801FFFFF, + // Internal flags + asOBJ_SCRIPT_OBJECT = (1<<21), + asOBJ_SHARED = (1<<22), + asOBJ_NOINHERIT = (1<<23), + asOBJ_FUNCDEF = (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_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 + // 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_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 + 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 + 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 + 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 + 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 + 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 + 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 + asGM_ONLY_IF_EXISTS = 0, + asGM_CREATE_IF_NOT_EXISTS = 1, + asGM_ALWAYS_CREATE = 2 }; // Compile flags enum asECompileFlags { - asCOMP_ADD_TO_MODULE = 1 + 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 + asFUNC_DUMMY =-1, + asFUNC_SYSTEM = 0, + asFUNC_SCRIPT = 1, + asFUNC_INTERFACE = 2, + asFUNC_VIRTUAL = 3, + asFUNC_FUNCDEF = 4, + asFUNC_IMPORTED = 5, + asFUNC_DELEGATE = 6 }; // @@ -365,33 +365,33 @@ typedef unsigned char asBYTE; typedef unsigned short asWORD; typedef unsigned int asUINT; #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__S3E__) || (defined(_MSC_VER) && defined(__clang__)) - // size_t is not really correct, since it only guaranteed to be large enough to hold the segment size. - // For example, on 16bit systems the size_t may be 16bits only even if pointers are 32bit. But nobody - // is likely to use MSVC6 to compile for 16bit systems anymore, so this should be ok. - typedef size_t asPWORD; + // 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; + typedef uintptr_t asPWORD; #endif #ifdef __LP64__ - typedef unsigned int asDWORD; - typedef unsigned long asQWORD; - typedef long asINT64; + typedef unsigned int asDWORD; + typedef unsigned long asQWORD; + typedef long asINT64; #else - typedef unsigned long asDWORD; + typedef unsigned long asDWORD; #if !defined(_MSC_VER) && (defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_CC) || defined(__psp2__)) - typedef uint64_t asQWORD; - typedef int64_t asINT64; + typedef uint64_t asQWORD; + typedef int64_t asINT64; #else - typedef unsigned __int64 asQWORD; - typedef __int64 asINT64; + typedef unsigned __int64 asQWORD; + typedef __int64 asINT64; #endif #endif // Is the target a 64bit system? #if defined(__LP64__) || defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) - #ifndef AS_64BIT_PTR - #define AS_64BIT_PTR - #endif + #ifndef AS_64BIT_PTR + #define AS_64BIT_PTR + #endif #endif typedef void (*asFUNCTION_t)(); @@ -441,29 +441,29 @@ 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 + 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__) @@ -492,30 +492,30 @@ template 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 + 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; + const char *section; + int row; + int col; + asEMsgType type; + const char *message; }; @@ -548,34 +548,34 @@ struct asSMessageInfo #ifndef ANGELSCRIPT_DLL_MANUAL_IMPORT extern "C" { - // Engine - AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version = ANGELSCRIPT_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(); + // Engine + AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version = ANGELSCRIPT_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 @@ -591,58 +591,58 @@ template asUINT asGetTypeTraits() { #if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5) || defined(__clang__) - // MSVC, XCode/Clang, and gnuc 5+ - // C++11 compliant code - bool hasConstructor = std::is_default_constructible::value && !std::is_trivially_default_constructible::value; - 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; + // MSVC, XCode/Clang, and 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 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; + // gnuc 4.8 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 - // All other compilers and versions are assumed to use non C++11 compliant code until proven otherwise - // 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; + // All other compilers and versions are assumed to use non C++11 compliant code until proven otherwise + // 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; + 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 @@ -652,545 +652,545 @@ asUINT asGetTypeTraits() class asIScriptEngine { public: - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; - virtual int ShutDownAndRelease() = 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 *auxiliary = 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, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; - virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; - virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; - virtual int RegisterInterface(const char *name) = 0; - virtual int RegisterInterfaceMethod(const char *intf, const char *declaration) = 0; - virtual asUINT GetObjectTypeCount() const = 0; - virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0; - - // String factory - virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory) = 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 asITypeInfo *GetEnumByIndex(asUINT index) const = 0; - - // Funcdefs - virtual int RegisterFuncdef(const char *decl) = 0; - virtual asUINT GetFuncdefCount() const = 0; - virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const = 0; - - // Typedefs - virtual int RegisterTypedef(const char *type, const char *decl) = 0; - virtual asUINT GetTypedefCount() const = 0; - virtual asITypeInfo *GetTypedefByIndex(asUINT index) 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; - - // Type identification - virtual int GetTypeIdByDecl(const char *decl) const = 0; - virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const = 0; - virtual int GetSizeOfPrimitiveType(int typeId) const = 0; - virtual asITypeInfo *GetTypeInfoById(int typeId) const = 0; - virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0; - virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0; - - // Script execution - virtual asIScriptContext *CreateContext() = 0; - virtual void *CreateScriptObject(const asITypeInfo *type) = 0; - virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type) = 0; - virtual void *CreateUninitializedScriptObject(const asITypeInfo *type) = 0; - virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj) = 0; - virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type) = 0; - virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type) = 0; - virtual void AddRefScriptObject(void *obj, const asITypeInfo *type) = 0; - virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false) = 0; - virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const = 0; - - // Context pooling - virtual asIScriptContext *RequestContext() = 0; - 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, asUINT *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, asITypeInfo *type) = 0; - virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr = 0, void **obj = 0, asITypeInfo **type = 0) = 0; - virtual void GCEnumCallback(void *reference) = 0; - virtual void ForwardGCEnumReferences(void *ref, asITypeInfo *type) = 0; - virtual void ForwardGCReleaseReferences(void *ref, asITypeInfo *type) = 0; - virtual void SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param = 0) = 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 SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type = 0) = 0; - virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type = 0) = 0; - - // Exception handling - virtual int SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv) = 0; + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; + virtual int ShutDownAndRelease() = 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 *auxiliary = 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, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; + virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; + virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; + virtual int RegisterInterface(const char *name) = 0; + virtual int RegisterInterfaceMethod(const char *intf, const char *declaration) = 0; + virtual asUINT GetObjectTypeCount() const = 0; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0; + + // String factory + virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory) = 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 asITypeInfo *GetEnumByIndex(asUINT index) const = 0; + + // Funcdefs + virtual int RegisterFuncdef(const char *decl) = 0; + virtual asUINT GetFuncdefCount() const = 0; + virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const = 0; + + // Typedefs + virtual int RegisterTypedef(const char *type, const char *decl) = 0; + virtual asUINT GetTypedefCount() const = 0; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) 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; + + // Type identification + virtual int GetTypeIdByDecl(const char *decl) const = 0; + virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const = 0; + virtual int GetSizeOfPrimitiveType(int typeId) const = 0; + virtual asITypeInfo *GetTypeInfoById(int typeId) const = 0; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0; + + // Script execution + virtual asIScriptContext *CreateContext() = 0; + virtual void *CreateScriptObject(const asITypeInfo *type) = 0; + virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type) = 0; + virtual void *CreateUninitializedScriptObject(const asITypeInfo *type) = 0; + virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj) = 0; + virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type) = 0; + virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type) = 0; + virtual void AddRefScriptObject(void *obj, const asITypeInfo *type) = 0; + virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false) = 0; + virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const = 0; + + // Context pooling + virtual asIScriptContext *RequestContext() = 0; + 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, asUINT *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, asITypeInfo *type) = 0; + virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr = 0, void **obj = 0, asITypeInfo **type = 0) = 0; + virtual void GCEnumCallback(void *reference) = 0; + virtual void ForwardGCEnumReferences(void *ref, asITypeInfo *type) = 0; + virtual void ForwardGCReleaseReferences(void *ref, asITypeInfo *type) = 0; + virtual void SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param = 0) = 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 SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type = 0) = 0; + virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type = 0) = 0; + + // Exception handling + virtual int SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv) = 0; protected: - virtual ~asIScriptEngine() {} + virtual ~asIScriptEngine() {} }; class asIStringFactory { public: - virtual const void *GetStringConstant(const char *data, asUINT length) = 0; - virtual int ReleaseStringConstant(const void *str) = 0; - virtual int GetRawStringData(const void *str, char *data, asUINT *length) const = 0; + virtual const void *GetStringConstant(const char *data, asUINT length) = 0; + virtual int ReleaseStringConstant(const void *str) = 0; + virtual int GetRawStringData(const void *str, char *data, asUINT *length) const = 0; protected: - virtual ~asIStringFactory() {} + virtual ~asIStringFactory() {} }; class asIThreadManager { protected: - virtual ~asIThreadManager() {} + 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 asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0; - virtual int GetTypeIdByDecl(const char *decl) const = 0; - virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0; - virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0; - - // Enums - virtual asUINT GetEnumCount() const = 0; - virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0; - - // Typedefs - virtual asUINT GetTypedefCount() const = 0; - virtual asITypeInfo *GetTypedefByIndex(asUINT index) 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; + 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 asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0; + virtual int GetTypeIdByDecl(const char *decl) const = 0; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0; + + // Enums + virtual asUINT GetEnumCount() const = 0; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0; + + // Typedefs + virtual asUINT GetTypedefCount() const = 0; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) 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() {} + 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 int SetArgVarType(asUINT arg, void *ptr, int typeId) = 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 *info, bool allowCatch = true) = 0; - virtual int GetExceptionLineNumber(int *column = 0, const char **sectionName = 0) = 0; - virtual asIScriptFunction *GetExceptionFunction() = 0; - virtual const char * GetExceptionString() = 0; - virtual bool WillExceptionBeCaught() = 0; - virtual int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv) = 0; - virtual void ClearExceptionCallback() = 0; - - // 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; + // 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 int SetArgVarType(asUINT arg, void *ptr, int typeId) = 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 *info, bool allowCatch = true) = 0; + virtual int GetExceptionLineNumber(int *column = 0, const char **sectionName = 0) = 0; + virtual asIScriptFunction *GetExceptionFunction() = 0; + virtual const char * GetExceptionString() = 0; + virtual bool WillExceptionBeCaught() = 0; + virtual int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv) = 0; + virtual void ClearExceptionCallback() = 0; + + // 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() {} + virtual ~asIScriptContext() {} }; class asIScriptGeneric { public: - // Miscellaneous - virtual asIScriptEngine *GetEngine() const = 0; - virtual asIScriptFunction *GetFunction() const = 0; - virtual void *GetAuxiliary() 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; + // Miscellaneous + virtual asIScriptEngine *GetEngine() const = 0; + virtual asIScriptFunction *GetFunction() const = 0; + virtual void *GetAuxiliary() 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() {} + virtual ~asIScriptGeneric() {} }; class asIScriptObject { public: - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; - virtual asILockableSharedBool *GetWeakRefFlag() const = 0; + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; + virtual asILockableSharedBool *GetWeakRefFlag() const = 0; - // Type info - virtual int GetTypeId() const = 0; - virtual asITypeInfo *GetObjectType() const = 0; + // Type info + virtual int GetTypeId() const = 0; + virtual asITypeInfo *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; + // 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; - // Miscellaneous - virtual asIScriptEngine *GetEngine() const = 0; - virtual int CopyFrom(const asIScriptObject *other) = 0; + // Miscellaneous + virtual asIScriptEngine *GetEngine() const = 0; + virtual int CopyFrom(const asIScriptObject *other) = 0; - // User data - virtual void *SetUserData(void *data, asPWORD type = 0) = 0; - virtual void *GetUserData(asPWORD type = 0) const = 0; + // User data + virtual void *SetUserData(void *data, asPWORD type = 0) = 0; + virtual void *GetUserData(asPWORD type = 0) const = 0; protected: - virtual ~asIScriptObject() {} + virtual ~asIScriptObject() {} }; class asITypeInfo { public: - // Miscellaneous - 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 asITypeInfo *GetBaseType() const = 0; - virtual bool DerivesFrom(const asITypeInfo *objType) const = 0; - virtual asDWORD GetFlags() const = 0; - virtual asUINT GetSize() const = 0; - virtual int GetTypeId() const = 0; - virtual int GetSubTypeId(asUINT subTypeIndex = 0) const = 0; - virtual asITypeInfo *GetSubType(asUINT subTypeIndex = 0) const = 0; - virtual asUINT GetSubTypeCount() const = 0; - - // Interfaces - virtual asUINT GetInterfaceCount() const = 0; - virtual asITypeInfo *GetInterface(asUINT index) const = 0; - virtual bool Implements(const asITypeInfo *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, bool *isProtected = 0, int *offset = 0, bool *isReference = 0, asDWORD *accessMask = 0, int *compositeOffset = 0, bool *isCompositeIndirect = 0) const = 0; - virtual const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const = 0; - - // Behaviours - virtual asUINT GetBehaviourCount() const = 0; - virtual asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const = 0; - - // Child types - virtual asUINT GetChildFuncdefCount() const = 0; - virtual asITypeInfo *GetChildFuncdef(asUINT index) const = 0; - virtual asITypeInfo *GetParentType() const = 0; - - // Enums - virtual asUINT GetEnumValueCount() const = 0; - virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const = 0; - - // Typedef - virtual int GetTypedefTypeId() const = 0; - - // Funcdef - virtual asIScriptFunction *GetFuncdefSignature() const = 0; - - // User data - virtual void *SetUserData(void *data, asPWORD type = 0) = 0; - virtual void *GetUserData(asPWORD type = 0) const = 0; + // Miscellaneous + 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 asITypeInfo *GetBaseType() const = 0; + virtual bool DerivesFrom(const asITypeInfo *objType) const = 0; + virtual asDWORD GetFlags() const = 0; + virtual asUINT GetSize() const = 0; + virtual int GetTypeId() const = 0; + virtual int GetSubTypeId(asUINT subTypeIndex = 0) const = 0; + virtual asITypeInfo *GetSubType(asUINT subTypeIndex = 0) const = 0; + virtual asUINT GetSubTypeCount() const = 0; + + // Interfaces + virtual asUINT GetInterfaceCount() const = 0; + virtual asITypeInfo *GetInterface(asUINT index) const = 0; + virtual bool Implements(const asITypeInfo *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, bool *isProtected = 0, int *offset = 0, bool *isReference = 0, asDWORD *accessMask = 0, int *compositeOffset = 0, bool *isCompositeIndirect = 0) const = 0; + virtual const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const = 0; + + // Behaviours + virtual asUINT GetBehaviourCount() const = 0; + virtual asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const = 0; + + // Child types + virtual asUINT GetChildFuncdefCount() const = 0; + virtual asITypeInfo *GetChildFuncdef(asUINT index) const = 0; + virtual asITypeInfo *GetParentType() const = 0; + + // Enums + virtual asUINT GetEnumValueCount() const = 0; + virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const = 0; + + // Typedef + virtual int GetTypedefTypeId() const = 0; + + // Funcdef + virtual asIScriptFunction *GetFuncdefSignature() const = 0; + + // User data + virtual void *SetUserData(void *data, asPWORD type = 0) = 0; + virtual void *GetUserData(asPWORD type = 0) const = 0; protected: - virtual ~asITypeInfo() {} + virtual ~asITypeInfo() {} }; 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; - virtual void *GetAuxiliary() const = 0; - - // Function signature - virtual asITypeInfo *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 IsProtected() const = 0; - virtual bool IsFinal() const = 0; - virtual bool IsOverride() const = 0; - virtual bool IsShared() const = 0; - virtual bool IsExplicit() const = 0; - virtual bool IsProperty() const = 0; - virtual asUINT GetParamCount() const = 0; - virtual int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const = 0; - virtual int GetReturnTypeId(asDWORD *flags = 0) const = 0; - - // Type id for function pointers - virtual int GetTypeId() const = 0; - virtual bool IsCompatibleWithTypeId(int typeId) const = 0; - - // Delegates - virtual void *GetDelegateObject() const = 0; - virtual asITypeInfo *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; + 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; + virtual void *GetAuxiliary() const = 0; + + // Function signature + virtual asITypeInfo *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 IsProtected() const = 0; + virtual bool IsFinal() const = 0; + virtual bool IsOverride() const = 0; + virtual bool IsShared() const = 0; + virtual bool IsExplicit() const = 0; + virtual bool IsProperty() const = 0; + virtual asUINT GetParamCount() const = 0; + virtual int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const = 0; + virtual int GetReturnTypeId(asDWORD *flags = 0) const = 0; + + // Type id for function pointers + virtual int GetTypeId() const = 0; + virtual bool IsCompatibleWithTypeId(int typeId) const = 0; + + // Delegates + virtual void *GetDelegateObject() const = 0; + virtual asITypeInfo *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() {}; + virtual ~asIScriptFunction() {}; }; class asIBinaryStream { public: - virtual int Read(void *ptr, asUINT size) = 0; - virtual int Write(const void *ptr, asUINT size) = 0; + virtual int Read(void *ptr, asUINT size) = 0; + virtual int Write(const void *ptr, asUINT size) = 0; public: - virtual ~asIBinaryStream() {} + virtual ~asIBinaryStream() {} }; class asILockableSharedBool { public: - // Memory management - virtual int AddRef() const = 0; - virtual int Release() const = 0; + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; - // Value - virtual bool Get() const = 0; - virtual void Set(bool val) = 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; + // Thread management + virtual void Lock() const = 0; + virtual void Unlock() const = 0; protected: - virtual ~asILockableSharedBool() {} + virtual ~asILockableSharedBool() {} }; //----------------------------------------------------------------- @@ -1201,30 +1201,30 @@ class asILockableSharedBool template inline asSFuncPtr asFunctionPtr(T func) { - // Mark this as a global function - asSFuncPtr p(2); + // 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)); + // 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); + // 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; + 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; + // Mark this as a generic function + asSFuncPtr p(1); + p.ptr.f.func = reinterpret_cast(func); + return p; } #ifndef AS_NO_CLASS_METHODS @@ -1240,31 +1240,31 @@ const int SINGLE_PTR_SIZE = sizeof(asSIMPLEMETHOD_t); 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. + 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]; + int ERROR_UnsupportedMethodPtr[N-100]; - asSFuncPtr p(0); - return p; - } + 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; - } + 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__) @@ -1273,84 +1273,84 @@ struct asSMethodPtr 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 + 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. + 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)); + // 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. + // 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. + // 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: + // 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::*()); + // 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 + // 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); + // 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; - } + 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 + 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; - } + 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 @@ -1362,14 +1362,14 @@ struct asSMethodPtr 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 - asITypeInfo *objectType; // type of object held in object register - bool doProcessSuspend; // whether or not the JIT should break out when it encounters a suspend instruction - asIScriptContext *ctx; // the active context + 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 + asITypeInfo *objectType; // type of object held in object register + bool doProcessSuspend; // whether or not the JIT should break out when it encounters a suspend instruction + asIScriptContext *ctx; // the active context }; typedef void (*asJITFunction)(asSVMRegisters *registers, asPWORD jitArg); @@ -1377,304 +1377,304 @@ typedef void (*asJITFunction)(asSVMRegisters *registers, asPWORD jitArg); class asIJITCompiler { public: - virtual int CompileFunction(asIScriptFunction *function, asJITFunction *output) = 0; - virtual void ReleaseJITFunction(asJITFunction func) = 0; + virtual int CompileFunction(asIScriptFunction *function, asJITFunction *output) = 0; + virtual void ReleaseJITFunction(asJITFunction func) = 0; public: - virtual ~asIJITCompiler() {} + 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_Thiscall1 = 200, - asBC_MAXBYTECODE = 201, - - // Temporary tokens. Can't be output to the final program - asBC_TryBlock = 250, - asBC_VarDecl = 251, - asBC_Block = 252, - asBC_ObjInfo = 253, - asBC_LINE = 254, - asBC_LABEL = 255 + 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_Thiscall1 = 200, + asBC_MAXBYTECODE = 201, + + // Temporary tokens. Can't be output to the final program + asBC_TryBlock = 250, + asBC_VarDecl = 251, + asBC_Block = 252, + asBC_ObjInfo = 253, + 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 + 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 + 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; + 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 + #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 + #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} @@ -1682,264 +1682,264 @@ struct asSBCInfo 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(Thiscall1, DW_ARG, -AS_PTR_SIZE-1), - - 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(TryBlock, DW_ARG, 0), - asBCINFO(VarDecl, W_ARG, 0), - asBCINFO(Block, INFO, 0), - asBCINFO(ObjInfo, rW_DW_ARG, 0), - asBCINFO(LINE, INFO, 0), - asBCINFO(LABEL, INFO, 0) + 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(Thiscall1, DW_ARG, -AS_PTR_SIZE-1), + + 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(TryBlock, DW_ARG, 0), + 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 diff --git a/src/angelscript/source/as_array.h b/src/angelscript/source/as_array.h index 6474951778d..0b37fa4cf8c 100644 --- a/src/angelscript/source/as_array.h +++ b/src/angelscript/source/as_array.h @@ -45,48 +45,48 @@ BEGIN_AS_NAMESPACE template class asCArray { public: - asCArray(); - asCArray(const asCArray &); - asCArray(asUINT reserve); - ~asCArray(); + asCArray(); + asCArray(const asCArray &); + asCArray(asUINT reserve); + ~asCArray(); - void Allocate(asUINT numElements, bool keepData); - void AllocateNoConstruct(asUINT numElements, bool keepData); - asUINT GetCapacity() const; + void Allocate(asUINT numElements, bool keepData); + void AllocateNoConstruct(asUINT numElements, bool keepData); + asUINT GetCapacity() const; - void PushLast(const T &element); - T PopLast(); + void PushLast(const T &element); + T PopLast(); - bool SetLength(asUINT numElements); - bool SetLengthNoConstruct(asUINT numElements); - asUINT GetLength() const; + bool SetLength(asUINT numElements); + bool SetLengthNoConstruct(asUINT numElements); + asUINT GetLength() const; - void Copy(const T*, asUINT count); - asCArray &operator =(const asCArray &); - void SwapWith(asCArray &other); + void Copy(const T*, asUINT count); + asCArray &operator =(const asCArray &); + void SwapWith(asCArray &other); - const T &operator [](asUINT index) const; - T &operator [](asUINT index); - T *AddressOf(); - const T *AddressOf() const; + const T &operator [](asUINT index) const; + T &operator [](asUINT index); + T *AddressOf(); + const T *AddressOf() const; - bool Concatenate(const asCArray &); - void Concatenate(T*, unsigned int count); + bool Concatenate(const asCArray &); + void Concatenate(T*, unsigned int count); - bool Exists(const T &element) const; - int IndexOf(const T &element) const; - void RemoveIndex(asUINT index); // Removes the entry without reordering the array - void RemoveValue(const T &element); // Removes the value without reordering the array - void RemoveIndexUnordered(asUINT index); // Removes the entry without keeping the order + bool Exists(const T &element) const; + int IndexOf(const T &element) const; + void RemoveIndex(asUINT index); // Removes the entry without reordering the array + void RemoveValue(const T &element); // Removes the value without reordering the array + void RemoveIndexUnordered(asUINT index); // Removes the entry without keeping the order - bool operator==(const asCArray &) const; - bool operator!=(const asCArray &) const; + bool operator==(const asCArray &) const; + bool operator!=(const asCArray &) const; protected: - T *array; - asUINT length; // 32bits is enough for all uses of this array - asUINT maxLength; - char buf[2*4*AS_PTR_SIZE]; // Avoid dynamically allocated memory for tiny arrays + T *array; + asUINT length; // 32bits is enough for all uses of this array + asUINT maxLength; + char buf[2*4*AS_PTR_SIZE]; // Avoid dynamically allocated memory for tiny arrays }; // Implementation @@ -94,353 +94,353 @@ template class asCArray template T *asCArray::AddressOf() { - return array; + return array; } template const T *asCArray::AddressOf() const { - return array; + return array; } template asCArray::asCArray(void) { - array = 0; - length = 0; - maxLength = 0; + array = 0; + length = 0; + maxLength = 0; } template asCArray::asCArray(const asCArray ©) { - array = 0; - length = 0; - maxLength = 0; + array = 0; + length = 0; + maxLength = 0; - *this = copy; + *this = copy; } template asCArray::asCArray(asUINT reserve) { - array = 0; - length = 0; - maxLength = 0; + array = 0; + length = 0; + maxLength = 0; - Allocate(reserve, false); + Allocate(reserve, false); } template asCArray::~asCArray(void) { - // Allocating a zero length array will free all memory - Allocate(0,0); + // Allocating a zero length array will free all memory + Allocate(0,0); } template asUINT asCArray::GetLength() const { - return length; + return length; } template const T &asCArray::operator [](asUINT index) const { - asASSERT(index < length); + asASSERT(index < length); - return array[index]; + return array[index]; } template T &asCArray::operator [](asUINT index) { - asASSERT(index < length); + asASSERT(index < length); - return array[index]; + 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; + 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); + asASSERT(length > 0); - return array[--length]; + return array[--length]; } template void asCArray::Allocate(asUINT 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 <= sizeof(buf) ) - // 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( asUINT n = length; n < numElements; n++ ) - new (&tmp[n]) T(); - } - else - { - // Construct all elements - for( asUINT n = 0; n < numElements; n++ ) - new (&tmp[n]) T(); - } - } - - if( array ) - { - asUINT 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( asUINT n = length; n < oldLength; n++ ) - array[n].~T(); - } - else - { - if( keepData ) - { - if( length > numElements ) - length = numElements; - - for( asUINT n = 0; n < length; n++ ) - tmp[n] = array[n]; - } - else - length = 0; - - // Call the destructor for all elements - for( asUINT n = 0; n < oldLength; n++ ) - array[n].~T(); - - if( array != reinterpret_cast(buf) ) - asDELETEARRAY(array); - } - } - - array = tmp; - maxLength = numElements; + // 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 <= sizeof(buf) ) + // 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( asUINT n = length; n < numElements; n++ ) + new (&tmp[n]) T(); + } + else + { + // Construct all elements + for( asUINT n = 0; n < numElements; n++ ) + new (&tmp[n]) T(); + } + } + + if( array ) + { + asUINT 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( asUINT n = length; n < oldLength; n++ ) + array[n].~T(); + } + else + { + if( keepData ) + { + if( length > numElements ) + length = numElements; + + for( asUINT n = 0; n < length; n++ ) + tmp[n] = array[n]; + } + else + length = 0; + + // Call the destructor for all elements + for( asUINT n = 0; n < oldLength; n++ ) + array[n].~T(); + + if( array != reinterpret_cast(buf) ) + asDELETEARRAY(array); + } + } + + array = tmp; + maxLength = numElements; } template void asCArray::AllocateNoConstruct(asUINT 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 <= sizeof(buf) ) - // 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; + // 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 <= sizeof(buf) ) + // 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 asUINT asCArray::GetCapacity() const { - return maxLength; + return maxLength; } template bool asCArray::SetLength(asUINT numElements) { - if( numElements > maxLength ) - { - Allocate(numElements, true); - if( numElements > maxLength ) - { - // Out of memory. Return without doing anything - return false; - } - } - - length = numElements; - return true; + 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(asUINT numElements) { - if( numElements > maxLength ) - { - AllocateNoConstruct(numElements, true); - if( numElements > maxLength ) - { - // Out of memory. Return without doing anything - return false; - } - } - - length = numElements; - return true; + 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, asUINT count) { - if( maxLength < count ) - { - Allocate(count, false); - if( maxLength < count ) - { - // Out of memory. Return without doing anything - return; - } - } - - for( asUINT n = 0; n < count; n++ ) - array[n] = data[n]; - - length = count; + if( maxLength < count ) + { + Allocate(count, false); + if( maxLength < count ) + { + // Out of memory. Return without doing anything + return; + } + } + + for( asUINT n = 0; n < count; n++ ) + array[n] = data[n]; + + length = count; } template asCArray &asCArray::operator =(const asCArray ©) { - Copy(copy.array, copy.length); + Copy(copy.array, copy.length); - return *this; + return *this; } template void asCArray::SwapWith(asCArray &other) { - T *tmpArray = array; - asUINT tmpLength = length; - asUINT 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); + T *tmpArray = array; + asUINT tmpLength = length; + asUINT 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; + if( length != other.length ) return false; - for( asUINT n = 0; n < length; n++ ) - if( array[n] != other.array[n] ) - return false; + for( asUINT n = 0; n < length; n++ ) + if( array[n] != other.array[n] ) + return false; - return true; + return true; } template bool asCArray::operator !=(const asCArray &other) const { - return !(*this == other); + return !(*this == other); } @@ -448,79 +448,79 @@ bool asCArray::operator !=(const asCArray &other) const 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( asUINT n = 0; n < other.length; n++ ) - array[length+n] = other.array[n]; - - length += other.length; - - // Success - return true; + if( maxLength < length + other.length ) + { + Allocate(length + other.length, true); + if( maxLength < length + other.length ) + { + // Out of memory + return false; + } + } + + for( asUINT n = 0; n < other.length; n++ ) + array[length+n] = other.array[n]; + + length += other.length; + + // Success + return true; } template void asCArray::Concatenate(T* other, unsigned int count) { - for( unsigned int c = 0; c < count; c++ ) - PushLast(other[c]); + for( unsigned int c = 0; c < count; c++ ) + PushLast(other[c]); } template bool asCArray::Exists(const T &e) const { - return IndexOf(e) == -1 ? false : true; + return IndexOf(e) == -1 ? false : true; } template int asCArray::IndexOf(const T &e) const { - for( asUINT n = 0; n < length; n++ ) - if( array[n] == e ) return static_cast(n); + for( asUINT n = 0; n < length; n++ ) + if( array[n] == e ) return static_cast(n); - return -1; + return -1; } template void asCArray::RemoveIndex(asUINT index) { - if( index < length ) - { - for( asUINT n = index; n < length-1; n++ ) - array[n] = array[n+1]; + if( index < length ) + { + for( asUINT n = index; n < length-1; n++ ) + array[n] = array[n+1]; - PopLast(); - } + PopLast(); + } } template void asCArray::RemoveValue(const T &e) { - for( asUINT n = 0; n < length; n++ ) - { - if( array[n] == e ) - { - RemoveIndex(n); - break; - } - } + for( asUINT n = 0; n < length; n++ ) + { + if( array[n] == e ) + { + RemoveIndex(n); + break; + } + } } template void asCArray::RemoveIndexUnordered(asUINT index) { - if( index == length - 1 ) - PopLast(); - else if( index < length ) - array[index] = PopLast(); + if( index == length - 1 ) + PopLast(); + else if( index < length ) + array[index] = PopLast(); } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_atomic.cpp b/src/angelscript/source/as_atomic.cpp index e110b3fc9dd..34f642ffb57 100644 --- a/src/angelscript/source/as_atomic.cpp +++ b/src/angelscript/source/as_atomic.cpp @@ -27,7 +27,7 @@ Andreas Jonsson andreas@angelcode.com */ - + // // as_atomic.cpp // @@ -40,43 +40,43 @@ BEGIN_AS_NAMESPACE asCAtomic::asCAtomic() { - value = 0; + 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); + // 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; + 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); + // 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; + 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); + // 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); + 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); + // 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); + return asAtomicDec((int&)value); } // @@ -86,12 +86,12 @@ asDWORD asCAtomic::atomicDec() int asAtomicInc(int &value) { - return ++value; + return ++value; } int asAtomicDec(int &value) { - return --value; + return --value; } #elif defined(AS_XENON) /// XBox360 @@ -102,12 +102,12 @@ BEGIN_AS_NAMESPACE int asAtomicInc(int &value) { - return InterlockedIncrement((LONG*)&value); + return InterlockedIncrement((LONG*)&value); } int asAtomicDec(int &value) { - return InterlockedDecrement((LONG*)&value); + return InterlockedDecrement((LONG*)&value); } #elif defined(AS_WIN) @@ -119,36 +119,36 @@ BEGIN_AS_NAMESPACE int asAtomicInc(int &value) { - return InterlockedIncrement((LONG*)&value); + return InterlockedIncrement((LONG*)&value); } int asAtomicDec(int &value) { - asASSERT(value > 0); - return InterlockedDecrement((LONG*)&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 +// 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 +// 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); + return __sync_add_and_fetch(&value, 1); } int asAtomicDec(int &value) { - return __sync_sub_and_fetch(&value, 1); + return __sync_sub_and_fetch(&value, 1); } #elif defined(AS_MAC) || defined(AS_IPHONE) @@ -159,18 +159,18 @@ BEGIN_AS_NAMESPACE int asAtomicInc(int &value) { - return OSAtomicIncrement32((int32_t*)&value); + return OSAtomicIncrement32((int32_t*)&value); } int asAtomicDec(int &value) { - return OSAtomicDecrement32((int32_t*)&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. +// is wrong for the compiler/platform combination. int ERROR_PleaseFixTheConfig[-1]; #endif diff --git a/src/angelscript/source/as_atomic.h b/src/angelscript/source/as_atomic.h index c6fea885dcc..1bede8616cb 100644 --- a/src/angelscript/source/as_atomic.h +++ b/src/angelscript/source/as_atomic.h @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -33,7 +33,7 @@ // as_atomic.h // // The asCAtomic class provides methods for performing threadsafe -// operations on a single dword, e.g. reference counting and +// operations on a single dword, e.g. reference counting and // bitfields. // @@ -49,19 +49,19 @@ BEGIN_AS_NAMESPACE class asCAtomic { public: - asCAtomic(); + asCAtomic(); - asDWORD get() const; - void set(asDWORD val); + asDWORD get() const; + void set(asDWORD val); - // Increase and return new value - asDWORD atomicInc(); + // Increase and return new value + asDWORD atomicInc(); - // Decrease and return new value - asDWORD atomicDec(); + // Decrease and return new value + asDWORD atomicDec(); protected: - asDWORD value; + asDWORD value; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_builder.cpp b/src/angelscript/source/as_builder.cpp index 73c66e60f58..ffeb6ed85cb 100644 --- a/src/angelscript/source/as_builder.cpp +++ b/src/angelscript/source/as_builder.cpp @@ -55,400 +55,400 @@ BEGIN_AS_NAMESPACE template<> void asCSymbolTable::GetKey(const sGlobalVariableDescription *entry, asSNameSpaceNamePair &key) const { - asSNameSpace *ns = entry->ns; - asCString name = entry->name; - key = asSNameSpaceNamePair(ns, name); + 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) {} + 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; - } + 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;} + // 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; + 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 - CleanupEnumValues(); - 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; - } - } + 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 + CleanupEnumValues(); + 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; + numErrors = 0; + numWarnings = 0; + engine->preMessage.isSet = false; #ifndef AS_NO_COMPILER - // Clear the cache of known types - hasCachedKnownTypes = false; - knownTypes.EraseAll(); + // 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; + 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; } asCScriptCode *asCBuilder::FindOrAddCode(const char *name, const char *code, size_t length) { - for (asUINT n = 0; n < scripts.GetLength(); n++) - if( scripts[n]->name == name && scripts[n]->codeLength == length && memcmp(scripts[n]->code, code, length) == 0 ) - return scripts[n]; - - asCScriptCode *script = asNEW(asCScriptCode); - if (script == 0) - return 0; - - int r = script->SetCode(name, code, length, true); - if (r < 0) - { - asDELETE(script, asCScriptCode); - return 0; - } - - script->idx = engine->GetScriptSectionNameIndex(name); - scripts.PushLast(script); - return script; + for (asUINT n = 0; n < scripts.GetLength(); n++) + if( scripts[n]->name == name && scripts[n]->codeLength == length && memcmp(scripts[n]->code, code, length) == 0 ) + return scripts[n]; + + asCScriptCode *script = asNEW(asCScriptCode); + if (script == 0) + return 0; + + int r = script->SetCode(name, code, length, true); + if (r < 0) + { + asDELETE(script, asCScriptCode); + return 0; + } + + script->idx = engine->GetScriptSectionNameIndex(name); + scripts.PushLast(script); + return script; } void asCBuilder::EvaluateTemplateInstances(asUINT startIdx, bool keepSilent) { - // Backup the original message stream - bool msgCallback = engine->msgCallback; - asSSystemFunctionInterface msgCallbackFunc = engine->msgCallbackFunc; - void *msgCallbackObj = engine->msgCallbackObj; - - // Set the new temporary message stream - asCOutputBuffer outBuffer; - if( keepSilent ) - engine->SetMessageCallback(asMETHOD(asCOutputBuffer, Callback), &outBuffer, asCALL_THISCALL); - - // Evaluate each of the template instances that have been created since the start of the build - // TODO: This is not exactly correct, since another thread may have created template instances in parallel - for( asUINT n = startIdx; n < engine->templateInstanceTypes.GetLength(); n++ ) - { - bool dontGarbageCollect = false; - asCObjectType *tmpl = engine->templateInstanceTypes[n]; - asCScriptFunction *callback = engine->scriptFunctions[tmpl->beh.templateCallback]; - if( callback && !engine->CallGlobalFunctionRetBool(tmpl, &dontGarbageCollect, callback->sysFuncIntf, callback) ) - { - asCString sub = tmpl->templateSubTypes[0].Format(engine->nameSpaces[0]); - for( asUINT m = 1; m < tmpl->templateSubTypes.GetLength(); m++ ) - { - sub += ","; - sub += tmpl->templateSubTypes[m].Format(engine->nameSpaces[0]); - } - asCString str; - str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, tmpl->name.AddressOf(), sub.AddressOf()); - WriteError(tmpl->scriptSectionIdx >= 0 ? engine->scriptSectionNames[tmpl->scriptSectionIdx]->AddressOf() : "", str, tmpl->declaredAt&0xFFFFF, (tmpl->declaredAt>>20)&0xFFF); - } - else - { - // If the callback said this template instance won't be garbage collected then remove the flag - if( dontGarbageCollect ) - tmpl->flags &= ~asOBJ_GC; - } - } - - // Restore message callback - if( keepSilent ) - { - engine->msgCallback = msgCallback; - engine->msgCallbackFunc = msgCallbackFunc; - engine->msgCallbackObj = msgCallbackObj; - } + // 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; + if( keepSilent ) + engine->SetMessageCallback(asMETHOD(asCOutputBuffer, Callback), &outBuffer, asCALL_THISCALL); + + // Evaluate each of the template instances that have been created since the start of the build + // TODO: This is not exactly correct, since another thread may have created template instances in parallel + for( asUINT n = startIdx; n < engine->templateInstanceTypes.GetLength(); n++ ) + { + bool dontGarbageCollect = false; + asCObjectType *tmpl = engine->templateInstanceTypes[n]; + asCScriptFunction *callback = engine->scriptFunctions[tmpl->beh.templateCallback]; + if( callback && !engine->CallGlobalFunctionRetBool(tmpl, &dontGarbageCollect, callback->sysFuncIntf, callback) ) + { + asCString sub = tmpl->templateSubTypes[0].Format(engine->nameSpaces[0]); + for( asUINT m = 1; m < tmpl->templateSubTypes.GetLength(); m++ ) + { + sub += ","; + sub += tmpl->templateSubTypes[m].Format(engine->nameSpaces[0]); + } + asCString str; + str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, tmpl->name.AddressOf(), sub.AddressOf()); + WriteError(tmpl->scriptSectionIdx >= 0 ? engine->scriptSectionNames[tmpl->scriptSectionIdx]->AddressOf() : "", str, tmpl->declaredAt&0xFFFFF, (tmpl->declaredAt>>20)&0xFFF); + } + else + { + // If the callback said this template instance won't be garbage collected then remove the flag + if( dontGarbageCollect ) + tmpl->flags &= ~asOBJ_GC; + } + } + + // Restore message callback + if( keepSilent ) + { + engine->msgCallback = msgCallback; + engine->msgCallbackFunc = msgCallbackFunc; + engine->msgCallbackObj = msgCallbackObj; + } } int asCBuilder::Build() { - Reset(); - - // The template callbacks must only be called after the subtypes have a known structure, - // otherwise the callback may think it is not possible to create the template instance, - // even though it is. - // TODO: This flag shouldn't be set globally in the engine, as it would mean that another - // thread requesting a template instance in parallel to the compilation wouldn't - // evaluate the template instance. - engine->deferValidationOfTemplateTypes = true; - asUINT numTempl = (asUINT)engine->templateInstanceTypes.GetLength(); - - ParseScripts(); - if (numErrors > 0) - return asERROR; - - // Compile the types first - CompileInterfaces(); - CompileClasses(numTempl); - - // Evaluate the template instances one last time, this time with error messages, as we know - // all classes have been fully built and it is known which ones will need garbage collection. - EvaluateTemplateInstances(numTempl, false); - engine->deferValidationOfTemplateTypes = false; - if (numErrors > 0) - return asERROR; - - // Then the global variables. Here the variables declared with auto - // will be resolved, so they can be accessed properly in the functions - 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; + Reset(); + + // The template callbacks must only be called after the subtypes have a known structure, + // otherwise the callback may think it is not possible to create the template instance, + // even though it is. + // TODO: This flag shouldn't be set globally in the engine, as it would mean that another + // thread requesting a template instance in parallel to the compilation wouldn't + // evaluate the template instance. + engine->deferValidationOfTemplateTypes = true; + asUINT numTempl = (asUINT)engine->templateInstanceTypes.GetLength(); + + ParseScripts(); + if (numErrors > 0) + return asERROR; + + // Compile the types first + CompileInterfaces(); + CompileClasses(numTempl); + + // Evaluate the template instances one last time, this time with error messages, as we know + // all classes have been fully built and it is known which ones will need garbage collection. + EvaluateTemplateInstances(numTempl, false); + engine->deferValidationOfTemplateTypes = false; + if (numErrors > 0) + return asERROR; + + // Then the global variables. Here the variables declared with auto + // will be resolved, so they can be accessed properly in the functions + 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->m_defaultNamespace); - - CompileGlobalVariables(); - - // It is possible that the global variable initialization included anonymous functions that must be compiled too - for( asUINT n = 0; n < functions.GetLength(); n++ ) - { - asCCompiler compiler(engine); - asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId]; - int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0); - if( r < 0 ) - break; - } - - if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) - WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); - - // None of the functions should be added to the module if any error occurred, - // or it was requested that the functions wouldn't be added to the scope - if( numErrors > 0 ) - { - for( asUINT n = 0; n < functions.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId]; - if( module->m_globalFunctions.GetIndex(func) >= 0 ) - { - module->m_globalFunctions.Erase(module->m_globalFunctions.GetIndex(func)); - module->m_scriptFunctions.RemoveValue(func); - func->ReleaseInternal(); - } - } - } - - 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; + 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->m_defaultNamespace); + + CompileGlobalVariables(); + + // It is possible that the global variable initialization included anonymous functions that must be compiled too + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + asCCompiler compiler(engine); + asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId]; + int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0); + if( r < 0 ) + break; + } + + if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) + WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); + + // None of the functions should be added to the module if any error occurred, + // or it was requested that the functions wouldn't be added to the scope + if( numErrors > 0 ) + { + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId]; + if( module->m_globalFunctions.GetIndex(func) >= 0 ) + { + module->m_globalFunctions.Erase(module->m_globalFunctions.GetIndex(func)); + module->m_scriptFunctions.RemoveValue(func); + func->ReleaseInternal(); + } + } + } + + 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; + 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 @@ -456,1290 +456,1290 @@ int asCBuilder::ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, // 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; + // 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 - asSFunctionTraits funcTraits; - asCScriptFunction *func = asNEW(asCScriptFunction)(engine, compileFlags & asCOMP_ADD_TO_MODULE ? module : 0, asFUNC_SCRIPT); - if( func == 0 ) - return asOUT_OF_MEMORY; - - GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, func->defaultArgs, funcTraits, module->m_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->m_defaultNamespace; - - // Make sure the default args are declared correctly - int r = ValidateDefaultArgs(script, node, func); - if( r < 0 ) - { - func->ReleaseInternal(); - return asERROR; - } - - // Tell the engine that the function exists already so the compiler can access it - if( compileFlags & asCOMP_ADD_TO_MODULE ) - { - r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->m_defaultNamespace, false, false); - if( r < 0 ) - { - func->ReleaseInternal(); - return asERROR; - } - - module->m_globalFunctions.Put(func); - - module->AddScriptFunction(func); - } - else - engine->AddScriptFunction(func); - - // Fill in the function info for the builder too - node->DisconnectParent(); - sFunctionDescription *funcDesc = asNEW(sFunctionDescription); - if( funcDesc == 0 ) - { - func->ReleaseInternal(); - 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; - - // This must be done in a loop, as it is possible that additional functions get declared as lambda's in the code - for( asUINT n = 0; n < functions.GetLength(); n++ ) - { - asCCompiler compiler(engine); - asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId]; - r = compiler.CompileFunction(this, functions[n]->script, f->parameterNames, functions[n]->node, f, 0); - if( r < 0 ) - break; - } - - if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) - WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); - - // None of the functions should be added to the module if any error occurred, - // or it was requested that the functions wouldn't be added to the scope - if( !(compileFlags & asCOMP_ADD_TO_MODULE) || numErrors > 0 ) - { - for( asUINT n = 0; n < functions.GetLength(); n++ ) - { - asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId]; - if( module->m_globalFunctions.GetIndex(f) >= 0 ) - { - module->m_globalFunctions.Erase(module->m_globalFunctions.GetIndex(f)); - module->m_scriptFunctions.RemoveValue(f); - f->ReleaseInternal(); - } - } - } - - if( numErrors > 0 ) - { - // Release the function pointer that would otherwise be returned if no errors occured - func->ReleaseInternal(); - - return asERROR; - } - - // Return the function - *outFunc = func; - - return asSUCCESS; + 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 + asSFunctionTraits funcTraits; + asCScriptFunction *func = asNEW(asCScriptFunction)(engine, compileFlags & asCOMP_ADD_TO_MODULE ? module : 0, asFUNC_SCRIPT); + if( func == 0 ) + return asOUT_OF_MEMORY; + + GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, func->defaultArgs, funcTraits, module->m_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->m_defaultNamespace; + + // Make sure the default args are declared correctly + int r = ValidateDefaultArgs(script, node, func); + if( r < 0 ) + { + func->ReleaseInternal(); + return asERROR; + } + + // Tell the engine that the function exists already so the compiler can access it + if( compileFlags & asCOMP_ADD_TO_MODULE ) + { + r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->m_defaultNamespace, false, false); + if( r < 0 ) + { + func->ReleaseInternal(); + return asERROR; + } + + module->m_globalFunctions.Put(func); + + module->AddScriptFunction(func); + } + else + engine->AddScriptFunction(func); + + // Fill in the function info for the builder too + node->DisconnectParent(); + sFunctionDescription *funcDesc = asNEW(sFunctionDescription); + if( funcDesc == 0 ) + { + func->ReleaseInternal(); + 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; + + // This must be done in a loop, as it is possible that additional functions get declared as lambda's in the code + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + asCCompiler compiler(engine); + asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId]; + r = compiler.CompileFunction(this, functions[n]->script, f->parameterNames, functions[n]->node, f, 0); + if( r < 0 ) + break; + } + + if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) + WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); + + // None of the functions should be added to the module if any error occurred, + // or it was requested that the functions wouldn't be added to the scope + if( !(compileFlags & asCOMP_ADD_TO_MODULE) || numErrors > 0 ) + { + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId]; + if( module->m_globalFunctions.GetIndex(f) >= 0 ) + { + module->m_globalFunctions.Erase(module->m_globalFunctions.GetIndex(f)); + module->m_scriptFunctions.RemoveValue(f); + f->ReleaseInternal(); + } + } + } + + if( numErrors > 0 ) + { + // Release the function pointer that would otherwise be returned if no errors occured + func->ReleaseInternal(); + + 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]); - } - - // Before moving forward the builder must establish the relationship between types - // so that a derived type can see the child types of the parent type. - DetermineTypeRelations(); - - // Complete function definitions (defining returntype and parameters) - for( n = 0; n < funcDefs.GetLength(); n++ ) - CompleteFuncDef(funcDefs[n]); - - // Find other global nodes - for (n = 0; n < scripts.GetLength(); n++) - { - // Find other global nodes - asCScriptNode *node = parsers[n]->GetScriptNode(); - RegisterNonTypesFromScript(node, scripts[n], engine->nameSpaces[0]); - } - - // Register script methods found in the interfaces - for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) - { - 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, CastToObjectType(decl->typeInfo), true, false, 0, decl->isExistingShared); - } - else if( node->nodeType == snVirtualProperty ) - { - node->DisconnectParent(); - RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), 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, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared); - } - else if( node->nodeType == snVirtualProperty ) - { - node->DisconnectParent(); - RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared); - } - - node = next; - } - - // Make sure the default factory & constructor exists for classes - asCObjectType *ot = CastToObjectType(decl->typeInfo); - if( ot->beh.construct == engine->scriptTypeBehaviours.beh.construct ) - { - if( ot->beh.constructors.GetLength() == 1 || engine->ep.alwaysImplDefaultConstruct ) - { - AddDefaultConstructor(ot, decl->script); - } - else - { - // As the class has another constructor we shouldn't provide the default constructor - if( ot->beh.construct ) - { - engine->scriptFunctions[ot->beh.construct]->ReleaseInternal(); - ot->beh.construct = 0; - ot->beh.constructors.RemoveIndex(0); - } - if( ot->beh.factory ) - { - engine->scriptFunctions[ot->beh.factory]->ReleaseInternal(); - ot->beh.factory = 0; - ot->beh.factories.RemoveIndex(0); - } - // Only remove the opAssign method if the script hasn't provided one - if( ot->beh.copy == engine->scriptTypeBehaviours.beh.copy ) - { - engine->scriptFunctions[ot->beh.copy]->ReleaseInternal(); - ot->beh.copy = 0; - } - } - } - } - } - - for( n = 0; n < parsers.GetLength(); n++ ) - { - asDELETE(parsers[n],asCParser); - } + 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]); + } + + // Before moving forward the builder must establish the relationship between types + // so that a derived type can see the child types of the parent type. + DetermineTypeRelations(); + + // Complete function definitions (defining returntype and parameters) + for( n = 0; n < funcDefs.GetLength(); n++ ) + CompleteFuncDef(funcDefs[n]); + + // Find other global nodes + for (n = 0; n < scripts.GetLength(); n++) + { + // Find other global nodes + asCScriptNode *node = parsers[n]->GetScriptNode(); + RegisterNonTypesFromScript(node, scripts[n], engine->nameSpaces[0]); + } + + // Register script methods found in the interfaces + for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) + { + 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, CastToObjectType(decl->typeInfo), true, false, 0, decl->isExistingShared); + } + else if( node->nodeType == snVirtualProperty ) + { + node->DisconnectParent(); + RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), 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, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared); + } + else if( node->nodeType == snVirtualProperty ) + { + node->DisconnectParent(); + RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared); + } + + node = next; + } + + // Make sure the default factory & constructor exists for classes + asCObjectType *ot = CastToObjectType(decl->typeInfo); + if( ot->beh.construct == engine->scriptTypeBehaviours.beh.construct ) + { + if( ot->beh.constructors.GetLength() == 1 || engine->ep.alwaysImplDefaultConstruct ) + { + AddDefaultConstructor(ot, decl->script); + } + else + { + // As the class has another constructor we shouldn't provide the default constructor + if( ot->beh.construct ) + { + engine->scriptFunctions[ot->beh.construct]->ReleaseInternal(); + ot->beh.construct = 0; + ot->beh.constructors.RemoveIndex(0); + } + if( ot->beh.factory ) + { + engine->scriptFunctions[ot->beh.factory]->ReleaseInternal(); + ot->beh.factory = 0; + ot->beh.factories.RemoveIndex(0); + } + // Only remove the opAssign method if the script hasn't provided one + if( ot->beh.copy == engine->scriptTypeBehaviours.beh.copy ) + { + engine->scriptFunctions[ot->beh.copy]->ReleaseInternal(); + ot->beh.copy = 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, 0); - } - else if( node->nodeType == snMixin ) - { - node->DisconnectParent(); - RegisterMixinClass(node, script, ns); - } - } - - node = next; - } + 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, 0); + } + 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; - } + 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; - - // Don't compile if there is no statement block - if (current->node && !(current->node->nodeType == snStatementBlock || current->node->lastChild->nodeType == snStatementBlock)) - continue; - - asCCompiler compiler(engine); - asCScriptFunction *func = engine->scriptFunctions[current->funcId]; - - // Find the class declaration for constructors - sClassDeclaration *classDecl = 0; - if( current->objType && current->name == current->objType->name ) - { - for( asUINT c = 0; c < classDeclarations.GetLength(); c++ ) - { - if( classDeclarations[c]->typeInfo == current->objType ) - { - classDecl = classDeclarations[c]; - 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 ); - } - } + // 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; + + // Don't compile if there is no statement block + if (current->node && !(current->node->nodeType == snStatementBlock || current->node->lastChild->nodeType == snStatementBlock)) + continue; + + asCCompiler compiler(engine); + asCScriptFunction *func = engine->scriptFunctions[current->funcId]; + + // Find the class declaration for constructors + sClassDeclaration *classDecl = 0; + if( current->objType && current->name == current->objType->name ) + { + for( asUINT c = 0; c < classDeclarations.GetLength(); c++ ) + { + if( classDeclarations[c]->typeInfo == current->objType ) + { + classDecl = classDeclarations[c]; + 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(); + Reset(); - asCScriptCode source; - source.SetCode("", datatype, true); + asCScriptCode source; + source.SetCode("", datatype, true); - asCParser parser(this); - int r = parser.ParseDataType(&source, isReturnType); - if( r < 0 ) - return asINVALID_TYPE; + 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; + // 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); + *result = CreateDataTypeFromNode(dataType, &source, implicitNamespace, true); + if( isReturnType ) + *result = ModifyDataTypeFromNode(*result, dataType->next, &source, 0, 0); - if( numErrors > 0 ) - return asINVALID_TYPE; + if( numErrors > 0 ) + return asINVALID_TYPE; - return asSUCCESS; + return asSUCCESS; } int asCBuilder::ParseTemplateDecl(const char *decl, asCString *name, asCArray &subtypeNames) { - Reset(); + Reset(); - asCScriptCode source; - source.SetCode("", decl, true); + asCScriptCode source; + source.SetCode("", decl, true); - asCParser parser(this); - int r = parser.ParseTemplateDecl(&source); - if( r < 0 ) - return asINVALID_TYPE; + 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; + // 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); - } + 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 + // TODO: template: check for name conflicts - if( numErrors > 0 ) - return asINVALID_DECLARATION; + if( numErrors > 0 ) + return asINVALID_DECLARATION; - return asSUCCESS; + 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( CastToObjectType(dt->GetTypeInfo()) == 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 - asCScriptNode *dataType = parser.GetScriptNode()->firstChild; - - // Check if the property is declared 'by reference' - bool isReference = (dataType->next->tokenType == ttAmp); - - // Get the name of the property - asCScriptNode *nameNode = isReference ? dataType->next->next : 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->GetTypeInfo()->nameSpace : ns); - name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength); - type.MakeReference(isReference); - - // Validate that the type really can be a registered property - // We cannot use CanBeInstantiated, as it is allowed to register - // properties of type that cannot otherwise be instantiated - if( type.IsFuncdef() && !type.IsObjectHandle() ) - { - // Function definitions must always be handles - return asINVALID_DECLARATION; - } - - // Verify property name - if( dt ) - { - if( CheckNameConflictMember(dt->GetTypeInfo(), name.AddressOf(), nameNode, &source, true, false) < 0 ) - return asNAME_TAKEN; - } - else - { - if( CheckNameConflict(name.AddressOf(), nameNode, &source, ns, true, false) < 0 ) - return asNAME_TAKEN; - } - - if( numErrors > 0 ) - return asINVALID_DECLARATION; - - return asSUCCESS; + // Either datatype or namespace must be informed + asASSERT( dt || ns ); + + Reset(); + + if( dt ) + { + // Verify that the object type exist + if( CastToObjectType(dt->GetTypeInfo()) == 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 + asCScriptNode *dataType = parser.GetScriptNode()->firstChild; + + // Check if the property is declared 'by reference' + bool isReference = (dataType->next->tokenType == ttAmp); + + // Get the name of the property + asCScriptNode *nameNode = isReference ? dataType->next->next : 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->GetTypeInfo()->nameSpace : ns); + name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength); + type.MakeReference(isReference); + + // Validate that the type really can be a registered property + // We cannot use CanBeInstantiated, as it is allowed to register + // properties of type that cannot otherwise be instantiated + if( type.IsFuncdef() && !type.IsObjectHandle() ) + { + // Function definitions must always be handles + return asINVALID_DECLARATION; + } + + // Verify property name + if( dt ) + { + if( CheckNameConflictMember(dt->GetTypeInfo(), name.AddressOf(), nameNode, &source, true, false) < 0 ) + return asNAME_TAKEN; + } + else + { + if( CheckNameConflict(name.AddressOf(), nameNode, &source, ns, true, false) < 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(CastToObjectType(obj.GetTypeInfo()) != 0); - - // TODO: optimize: Improve linear search - asCArray &props = CastToObjectType(obj.GetTypeInfo())->properties; - for( asUINT n = 0; n < props.GetLength(); n++ ) - { - if( props[n]->name == prop ) - { - if( module->m_accessMask & props[n]->accessMask ) - return props[n]; - else - return 0; - } - } - - return 0; + asASSERT(CastToObjectType(obj.GetTypeInfo()) != 0); + + // TODO: optimize: Improve linear search + asCArray &props = CastToObjectType(obj.GetTypeInfo())->properties; + for( asUINT n = 0; n < props.GetLength(); n++ ) + { + if( props[n]->name == prop ) + { + if( module->m_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; - } + 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; - } + // 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->m_scriptGlobals.GetFirst(ns, prop); - if( globProp ) - { - if( outProp ) *outProp = globProp; - return true; - } - } - - return false; + // Check previously compiled global variables + if( module ) + { + globProp = module->m_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) ) - { + 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 + 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->m_accessMask & globProp->accessMask) ) - globProp = 0; - } - return globProp; - } - - return 0; + if( isAppProp ) + { + // Don't return the property if the module doesn't have access to it + if( !(module->m_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, asCObjectType **outParentClass) { - asASSERT( objType || ns ); - - if (listPattern) - *listPattern = 0; - if (outParentClass) - *outParentClass = 0; - - // TODO: Can't we use GetParsedFunctionDetails to do most of what is done in this function? - - Reset(); - - 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; - asCObjectType *parentClass = 0; - func->nameSpace = GetNameSpaceFromNode(n, &source, ns, &n, &parentClass); - if( func->nameSpace == 0 && parentClass == 0 ) - return asINVALID_DECLARATION; - if (parentClass && func->funcType != asFUNC_FUNCDEF) - return asINVALID_DECLARATION; - - if (outParentClass) - *outParentClass = parentClass; - - // Find name - func->name.Assign(&source.code[n->tokenPos], n->tokenLength); - - // 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, parentClass ? parentClass : objType); - func->returnType = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle); - if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) ) - return asINVALID_DECLARATION; - if( returnAutoHandle ) *returnAutoHandle = autoHandle; - - // Reference types cannot be returned by value from system functions - if( isSystemFunction && - (func->returnType.GetTypeInfo() && - (func->returnType.GetTypeInfo()->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, parentClass ? parentClass : objType); - type = ModifyDataTypeFromNode(type, n->next, &source, &inOutFlags, &autoHandle); - - // Reference types cannot be passed by value to system functions - if( isSystemFunction && - (type.GetTypeInfo() && - (type.GetTypeInfo()->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->SetReadOnly(true); - - n = n->next; - } - else - func->SetReadOnly(false); - - // Check for additional function traits - while (n && n->nodeType == snIdentifier) - { - if (source.TokenEquals(n->tokenPos, n->tokenLength, EXPLICIT_TOKEN)) - func->SetExplicit(true); - else if( source.TokenEquals(n->tokenPos, n->tokenLength, PROPERTY_TOKEN)) - func->SetProperty(true); - else - return asINVALID_DECLARATION; - - n = n->next; - } - - // 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; + asASSERT( objType || ns ); + + if (listPattern) + *listPattern = 0; + if (outParentClass) + *outParentClass = 0; + + // TODO: Can't we use GetParsedFunctionDetails to do most of what is done in this function? + + Reset(); + + 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; + asCObjectType *parentClass = 0; + func->nameSpace = GetNameSpaceFromNode(n, &source, ns, &n, &parentClass); + if( func->nameSpace == 0 && parentClass == 0 ) + return asINVALID_DECLARATION; + if (parentClass && func->funcType != asFUNC_FUNCDEF) + return asINVALID_DECLARATION; + + if (outParentClass) + *outParentClass = parentClass; + + // Find name + func->name.Assign(&source.code[n->tokenPos], n->tokenLength); + + // 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, parentClass ? parentClass : objType); + func->returnType = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle); + if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) ) + return asINVALID_DECLARATION; + if( returnAutoHandle ) *returnAutoHandle = autoHandle; + + // Reference types cannot be returned by value from system functions + if( isSystemFunction && + (func->returnType.GetTypeInfo() && + (func->returnType.GetTypeInfo()->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, parentClass ? parentClass : objType); + type = ModifyDataTypeFromNode(type, n->next, &source, &inOutFlags, &autoHandle); + + // Reference types cannot be passed by value to system functions + if( isSystemFunction && + (type.GetTypeInfo() && + (type.GetTypeInfo()->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->SetReadOnly(true); + + n = n->next; + } + else + func->SetReadOnly(false); + + // Check for additional function traits + while (n && n->nodeType == snIdentifier) + { + if (source.TokenEquals(n->tokenPos, n->tokenLength, EXPLICIT_TOKEN)) + func->SetExplicit(true); + else if( source.TokenEquals(n->tokenPos, n->tokenLength, PROPERTY_TOKEN)) + func->SetProperty(true); + else + return asINVALID_DECLARATION; + + n = n->next; + } + + // 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(); + Reset(); - asCScriptCode source; - source.SetCode(TXT_VARIABLE_DECL, decl, true); + asCScriptCode source; + source.SetCode(TXT_VARIABLE_DECL, decl, true); - asCParser parser(this); + asCParser parser(this); - int r = parser.ParsePropertyDeclaration(&source); - if( r < 0 ) - return asINVALID_DECLARATION; + int r = parser.ParsePropertyDeclaration(&source); + if( r < 0 ) + return asINVALID_DECLARATION; - asCScriptNode *node = parser.GetScriptNode(); + asCScriptNode *node = parser.GetScriptNode(); - // Determine the scope from declaration - asCScriptNode *n = node->firstChild->next; - // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace - outNamespace = GetNameSpaceFromNode(n, &source, implicitNamespace, &n); - if( outNamespace == 0 ) - return asINVALID_DECLARATION; + // Determine the scope from declaration + asCScriptNode *n = node->firstChild->next; + // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace + outNamespace = GetNameSpaceFromNode(n, &source, implicitNamespace, &n); + if( outNamespace == 0 ) + return asINVALID_DECLARATION; - // Find name - outName.Assign(&source.code[n->tokenPos], n->tokenLength); + // Find name + outName.Assign(&source.code[n->tokenPos], n->tokenLength); - // Initialize a script variable object for registration - outDt = CreateDataTypeFromNode(node->firstChild, &source, implicitNamespace); + // Initialize a script variable object for registration + outDt = CreateDataTypeFromNode(node->firstChild, &source, implicitNamespace); - if( numErrors > 0 || numWarnings > 0 ) - return asINVALID_DECLARATION; + if( numErrors > 0 || numWarnings > 0 ) + return asINVALID_DECLARATION; - return 0; + return 0; } // TODO: This should use SymbolLookupMember, which should be available in the TypeInfo class int asCBuilder::CheckNameConflictMember(asCTypeInfo *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty, bool isVirtualProperty) { - // It's not necessary to check against object types - - asCObjectType *ot = CastToObjectType(t); - if (!ot) - return 0; - - // Check against properties - // TODO: optimize: Improve linear search - // Properties are allowed to have the same name as virtual properties - if( !isVirtualProperty ) - { - asCArray &props = ot->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; - } - } - } - - // Check against virtual properties - // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties - // Properties are allowed to have the same name as virtual properties - if( !isProperty && !isVirtualProperty ) - { - asCArray methods = ot->methods; - for( asUINT n = 0; n < methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[methods[n]]; - if( func->IsProperty() && func->name.SubString(4) == name ) - { - if( code ) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_OBJ_PROPERTY, name); - WriteError(str, code, node); - } - - return -1; - } - } - } - - // Check against child types - asCArray &funcdefs = ot->childFuncDefs; - for (asUINT n = 0; n < funcdefs.GetLength(); n++) - { - if (funcdefs[n]->name == name) - { - if (code) - { - asCString str; - str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name); - WriteError(str, code, node); - } - - return -1; - } - } - - // Property names must be checked against method names - if( isProperty ) - { - asCArray methods = ot->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; - } - } - } - - // If there is a namespace at the same level with the same name as the class, then need to check for conflicts with symbols in that namespace too - // TODO: When classes can have static members, the code should change so that class name cannot be the same as a namespace - asCString scope; - if (ot->nameSpace->name != "") - scope = ot->nameSpace->name + "::" + ot->name; - else - scope = ot->name; - asSNameSpace *ns = engine->FindNameSpace(scope.AddressOf()); - if (ns) - { - // Check as if not a function as it doesn't matter the function signature - return CheckNameConflict(name, node, code, ns, true, isVirtualProperty); - } - - return 0; + // It's not necessary to check against object types + + asCObjectType *ot = CastToObjectType(t); + if (!ot) + return 0; + + // Check against properties + // TODO: optimize: Improve linear search + // Properties are allowed to have the same name as virtual properties + if( !isVirtualProperty ) + { + asCArray &props = ot->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; + } + } + } + + // Check against virtual properties + // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties + // Properties are allowed to have the same name as virtual properties + if( !isProperty && !isVirtualProperty ) + { + asCArray methods = ot->methods; + for( asUINT n = 0; n < methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[methods[n]]; + if( func->IsProperty() && func->name.SubString(4) == name ) + { + if( code ) + { + asCString str; + str.Format(TXT_NAME_CONFLICT_s_OBJ_PROPERTY, name); + WriteError(str, code, node); + } + + return -1; + } + } + } + + // Check against child types + asCArray &funcdefs = ot->childFuncDefs; + for (asUINT n = 0; n < funcdefs.GetLength(); n++) + { + if (funcdefs[n]->name == name) + { + if (code) + { + asCString str; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name); + WriteError(str, code, node); + } + + return -1; + } + } + + // Property names must be checked against method names + if( isProperty ) + { + asCArray methods = ot->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; + } + } + } + + // If there is a namespace at the same level with the same name as the class, then need to check for conflicts with symbols in that namespace too + // TODO: When classes can have static members, the code should change so that class name cannot be the same as a namespace + asCString scope; + if (ot->nameSpace->name != "") + scope = ot->nameSpace->name + "::" + ot->name; + else + scope = ot->name; + asSNameSpace *ns = engine->FindNameSpace(scope.AddressOf()); + if (ns) + { + // Check as if not a function as it doesn't matter the function signature + return CheckNameConflict(name, node, code, ns, true, isVirtualProperty); + } + + return 0; } // TODO: This should use SymbolLookup int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns, bool isProperty, bool isVirtualProperty) { - // Check against registered object types - if( engine->GetRegisteredType(name, ns) != 0 ) - { - if( code ) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - - // Check against global properties - // Virtual properties are allowed to have the same name as a real property - if( !isVirtualProperty && DoesGlobalPropertyExist(name, ns) ) - { - if( code ) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - - // Check against registered global virtual properties - // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties - if( !isProperty || !isVirtualProperty ) - { - for (asUINT n = 0; n < engine->registeredGlobalFuncs.GetSize(); n++) - { - asCScriptFunction *func = engine->registeredGlobalFuncs.Get(n); - if (func->IsProperty() && - func->nameSpace == ns && - func->name.SubString(4) == name) - { - if (code) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_IS_VIRTPROP, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - } - } - - // Property names must be checked against function names - if (isProperty) - { - for (asUINT n = 0; n < engine->registeredGlobalFuncs.GetSize(); n++) - { - if (engine->registeredGlobalFuncs.Get(n)->name == name && - engine->registeredGlobalFuncs.Get(n)->nameSpace == ns) - { - if (code) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_IS_FUNCTION, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - } - } + // Check against registered object types + if( engine->GetRegisteredType(name, ns) != 0 ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + + // Check against global properties + // Virtual properties are allowed to have the same name as a real property + if( !isVirtualProperty && DoesGlobalPropertyExist(name, ns) ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + + // Check against registered global virtual properties + // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties + if( !isProperty || !isVirtualProperty ) + { + for (asUINT n = 0; n < engine->registeredGlobalFuncs.GetSize(); n++) + { + asCScriptFunction *func = engine->registeredGlobalFuncs.Get(n); + if (func->IsProperty() && + func->nameSpace == ns && + func->name.SubString(4) == name) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_VIRTPROP, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + } + + // Property names must be checked against function names + if (isProperty) + { + for (asUINT n = 0; n < engine->registeredGlobalFuncs.GetSize(); n++) + { + if (engine->registeredGlobalFuncs.Get(n)->name == name && + engine->registeredGlobalFuncs.Get(n)->nameSpace == ns) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCTION, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + } #ifndef AS_NO_COMPILER - // Check against class types - asUINT n; - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - if( classDeclarations[n]->name == name && - classDeclarations[n]->typeInfo->nameSpace == ns ) - { - if( code ) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_STRUCT, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - } - - // Check against named types - for( n = 0; n < namedTypeDeclarations.GetLength(); n++ ) - { - if( namedTypeDeclarations[n]->name == name && - namedTypeDeclarations[n]->typeInfo->nameSpace == ns ) - { - if( code ) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_IS_NAMED_TYPE, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - } - - // Must check for name conflicts with funcdefs - for( n = 0; n < funcDefs.GetLength(); n++ ) - { - if( funcDefs[n]->name == name && - module->m_funcDefs[funcDefs[n]->idx]->nameSpace == ns ) - { - if( code ) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - } - - // Check against mixin classes - if( GetMixinClass(name, ns) ) - { - if( code ) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_IS_MIXIN, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - - // Check against virtual properties - // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties - if( !isProperty && !isVirtualProperty ) - { - for (n = 0; n < functions.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[functions[n] ? functions[n]->funcId : 0]; - if (func && - func->IsProperty() && - func->objectType == 0 && - func->nameSpace == ns && - func->name.SubString(4) == name) - { - if (code) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_IS_VIRTPROP, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - } - } - - // Property names must be checked against function names - if (isProperty) - { - for (n = 0; n < functions.GetLength(); n++) - { - if (functions[n] && - functions[n]->objType == 0 && - functions[n]->name == name && - engine->scriptFunctions[functions[n]->funcId]->nameSpace == ns ) - { - if (code) - { - asCString str; - if (ns->name != "") - str = ns->name + "::" + name; - else - str = name; - str.Format(TXT_NAME_CONFLICT_s_IS_FUNCTION, str.AddressOf()); - WriteError(str, code, node); - } - - return -1; - } - } - } + // Check against class types + asUINT n; + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + if( classDeclarations[n]->name == name && + classDeclarations[n]->typeInfo->nameSpace == ns ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_STRUCT, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + + // Check against named types + for( n = 0; n < namedTypeDeclarations.GetLength(); n++ ) + { + if( namedTypeDeclarations[n]->name == name && + namedTypeDeclarations[n]->typeInfo->nameSpace == ns ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_NAMED_TYPE, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + + // Must check for name conflicts with funcdefs + for( n = 0; n < funcDefs.GetLength(); n++ ) + { + if( funcDefs[n]->name == name && + module->m_funcDefs[funcDefs[n]->idx]->nameSpace == ns ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + + // Check against mixin classes + if( GetMixinClass(name, ns) ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_MIXIN, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + + // Check against virtual properties + // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties + if( !isProperty && !isVirtualProperty ) + { + for (n = 0; n < functions.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[functions[n] ? functions[n]->funcId : 0]; + if (func && + func->IsProperty() && + func->objectType == 0 && + func->nameSpace == ns && + func->name.SubString(4) == name) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_VIRTPROP, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + } + + // Property names must be checked against function names + if (isProperty) + { + for (n = 0; n < functions.GetLength(); n++) + { + if (functions[n] && + functions[n]->objType == 0 && + functions[n]->name == name && + engine->scriptFunctions[functions[n]->funcId]->nameSpace == ns ) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCTION, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + } #endif - return 0; + return 0; } // Returns a negative value on invalid property @@ -1749,4493 +1749,4493 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri // -5 name conflict int asCBuilder::ValidateVirtualProperty(asCScriptFunction *func) { - asASSERT( func->IsProperty() ); - - // A virtual property must have the prefix "get_" or "set_" - asCString prefix = func->name.SubString(0, 4); - if( prefix != "get_" && prefix != "set_" ) - return -2; - - // A getter must return a non-void type and have at most 1 argument (indexed property) - if( prefix == "get_" && (func->returnType == asCDataType::CreatePrimitive(ttVoid, false) || func->parameterTypes.GetLength() > 1) ) - return -3; - - // A setter must return a void and have 1 or 2 arguments (indexed property) - if( prefix == "set_" && (func->returnType != asCDataType::CreatePrimitive(ttVoid, false) || func->parameterTypes.GetLength() < 1 || func->parameterTypes.GetLength() > 2) ) - return -3; - - // Check matching getter/setter - asCDataType getType, setType; - bool found = false; - if( prefix == "get_" ) - { - getType = func->returnType; - - // Find if there is a set accessor in the same scope, and then validate the type of it - // TODO: optimize search - asCString setName = "set_" + func->name.SubString(4); - for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) - { - asCScriptFunction *setFunc = engine->scriptFunctions[n]; - if( setFunc == 0 || setFunc->name != setName || !setFunc->IsProperty() ) - continue; - - // Is it the same scope? - if( func->module != setFunc->module || func->nameSpace != setFunc->nameSpace || func->objectType != setFunc->objectType ) - continue; - - setType = setFunc->parameterTypes[setFunc->parameterTypes.GetLength() - 1]; - found = true; - break; - } - } - else - { - setType = func->parameterTypes[func->parameterTypes.GetLength() - 1]; - - // Find if there is a get accessor in the same scope and then validate the type of it - // TODO: optimize search - asCString getName = "get_" + func->name.SubString(4); - for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) - { - asCScriptFunction *getFunc = engine->scriptFunctions[n]; - if( getFunc == 0 || getFunc->name != getName || !getFunc->IsProperty() ) - continue; - - // Is it the same scope? - if( func->module != getFunc->module || func->nameSpace != getFunc->nameSpace || func->objectType != getFunc->objectType ) - continue; - - getType = getFunc->returnType; - found = true; - break; - } - } - - if( found ) - { - // Check that the type matches - // It is permitted for a getter to return a handle and the setter to take a reference - if( !getType.IsEqualExceptRefAndConst(setType) && - !((getType.IsObjectHandle() && !setType.IsObjectHandle()) && - (getType.GetTypeInfo() == setType.GetTypeInfo())) ) - { - return -4; - } - } - - // Check name conflict with other entities in the same scope - // It is allowed to have a real property of the same name, in which case the virtual property hides the real one. - int r; - if( func->objectType ) - r = CheckNameConflictMember(func->objectType, func->name.SubString(4).AddressOf(), 0, 0, true, true); - else - r = CheckNameConflict(func->name.SubString(4).AddressOf(), 0, 0, func->nameSpace, true, true); - if( r < 0 ) - return -5; - - // Everything is OK - return 0; + asASSERT( func->IsProperty() ); + + // A virtual property must have the prefix "get_" or "set_" + asCString prefix = func->name.SubString(0, 4); + if( prefix != "get_" && prefix != "set_" ) + return -2; + + // A getter must return a non-void type and have at most 1 argument (indexed property) + if( prefix == "get_" && (func->returnType == asCDataType::CreatePrimitive(ttVoid, false) || func->parameterTypes.GetLength() > 1) ) + return -3; + + // A setter must return a void and have 1 or 2 arguments (indexed property) + if( prefix == "set_" && (func->returnType != asCDataType::CreatePrimitive(ttVoid, false) || func->parameterTypes.GetLength() < 1 || func->parameterTypes.GetLength() > 2) ) + return -3; + + // Check matching getter/setter + asCDataType getType, setType; + bool found = false; + if( prefix == "get_" ) + { + getType = func->returnType; + + // Find if there is a set accessor in the same scope, and then validate the type of it + // TODO: optimize search + asCString setName = "set_" + func->name.SubString(4); + for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) + { + asCScriptFunction *setFunc = engine->scriptFunctions[n]; + if( setFunc == 0 || setFunc->name != setName || !setFunc->IsProperty() ) + continue; + + // Is it the same scope? + if( func->module != setFunc->module || func->nameSpace != setFunc->nameSpace || func->objectType != setFunc->objectType ) + continue; + + setType = setFunc->parameterTypes[setFunc->parameterTypes.GetLength() - 1]; + found = true; + break; + } + } + else + { + setType = func->parameterTypes[func->parameterTypes.GetLength() - 1]; + + // Find if there is a get accessor in the same scope and then validate the type of it + // TODO: optimize search + asCString getName = "get_" + func->name.SubString(4); + for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) + { + asCScriptFunction *getFunc = engine->scriptFunctions[n]; + if( getFunc == 0 || getFunc->name != getName || !getFunc->IsProperty() ) + continue; + + // Is it the same scope? + if( func->module != getFunc->module || func->nameSpace != getFunc->nameSpace || func->objectType != getFunc->objectType ) + continue; + + getType = getFunc->returnType; + found = true; + break; + } + } + + if( found ) + { + // Check that the type matches + // It is permitted for a getter to return a handle and the setter to take a reference + if( !getType.IsEqualExceptRefAndConst(setType) && + !((getType.IsObjectHandle() && !setType.IsObjectHandle()) && + (getType.GetTypeInfo() == setType.GetTypeInfo())) ) + { + return -4; + } + } + + // Check name conflict with other entities in the same scope + // It is allowed to have a real property of the same name, in which case the virtual property hides the real one. + int r; + if( func->objectType ) + r = CheckNameConflictMember(func->objectType, func->name.SubString(4).AddressOf(), 0, 0, true, true); + else + r = CheckNameConflict(func->name.SubString(4).AddressOf(), 0, 0, func->nameSpace, true, true); + if( r < 0 ) + return -5; + + // Everything is OK + 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]; + for( asUINT n = 0; n < mixinClasses.GetLength(); n++ ) + if( mixinClasses[n]->name == name && + mixinClasses[n]->ns == ns ) + return mixinClasses[n]; - return 0; + return 0; } int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent) { - // namespace and parent are exclusively mutual - asASSERT((ns == 0 && parent) || (ns && parent == 0)); - - // Skip leading 'shared' and 'external' keywords - asCScriptNode *n = node->firstChild; - while (n->nodeType == snIdentifier) - n = n->next; - - // Find the name - asASSERT( n->nodeType == snDataType ); - n = n->next->next; - - asCString name; - name.Assign(&file->code[n->tokenPos], n->tokenLength); - - // Check for name conflict with other types - if (ns) - { - int r = CheckNameConflict(name.AddressOf(), node, file, ns, true, false); - if (asSUCCESS != r) - { - node->Destroy(engine); - return r; - } - } - else - { - int r = CheckNameConflictMember(parent, name.AddressOf(), node, file, false, false); - 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, parent); - - funcDefs.PushLast(fd); - - return 0; + // namespace and parent are exclusively mutual + asASSERT((ns == 0 && parent) || (ns && parent == 0)); + + // Skip leading 'shared' and 'external' keywords + asCScriptNode *n = node->firstChild; + while (n->nodeType == snIdentifier) + n = n->next; + + // Find the name + asASSERT( n->nodeType == snDataType ); + n = n->next->next; + + asCString name; + name.Assign(&file->code[n->tokenPos], n->tokenLength); + + // Check for name conflict with other types + if (ns) + { + int r = CheckNameConflict(name.AddressOf(), node, file, ns, true, false); + if (asSUCCESS != r) + { + node->Destroy(engine); + return r; + } + } + else + { + int r = CheckNameConflictMember(parent, name.AddressOf(), node, file, false, false); + 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, parent); + + funcDefs.PushLast(fd); + + return 0; } void asCBuilder::CompleteFuncDef(sFuncDef *funcDef) { - asCArray defaultArgs; - asSFunctionTraits funcTraits; - - asCFuncdefType *fdt = module->m_funcDefs[funcDef->idx]; - asASSERT( fdt ); - asCScriptFunction *func = fdt->funcdef; - - asSNameSpace *implicitNs = func->nameSpace ? func->nameSpace : fdt->parentClass->nameSpace; - GetParsedFunctionDetails(funcDef->node, funcDef->script, fdt->parentClass, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, funcTraits, implicitNs); - - // There should not be any defaultArgs, but if there are any we need to delete them to avoid leaks - for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) - if( defaultArgs[n] ) - asDELETE(defaultArgs[n], asCString); - - // All funcdefs are shared, unless one of the parameter types or return type is not shared - bool declaredShared = funcTraits.GetTrait(asTRAIT_SHARED); - funcTraits.SetTrait(asTRAIT_SHARED, true); - if (func->returnType.GetTypeInfo() && !func->returnType.GetTypeInfo()->IsShared()) - { - if (declaredShared) - { - asCString s; - s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->returnType.GetTypeInfo()->name.AddressOf()); - WriteError(s.AddressOf(), funcDef->script, funcDef->node); - } - funcTraits.SetTrait(asTRAIT_SHARED, false); - } - for( asUINT n = 0; funcTraits.GetTrait(asTRAIT_SHARED) && n < func->parameterTypes.GetLength(); n++ ) - if (func->parameterTypes[n].GetTypeInfo() && !func->parameterTypes[n].GetTypeInfo()->IsShared()) - { - if (declaredShared) - { - asCString s; - s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); - WriteError(s.AddressOf(), funcDef->script, funcDef->node); - } - funcTraits.SetTrait(asTRAIT_SHARED, false); - } - func->SetShared(funcTraits.GetTrait(asTRAIT_SHARED)); - - // Check if there is another identical funcdef from another module and if so reuse that instead - bool found = false; - if( func->IsShared() ) - { - for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) - { - asCFuncdefType *fdt2 = engine->funcDefs[n]; - if( fdt2 == 0 || fdt == fdt2 ) - continue; - - if( !fdt2->funcdef->IsShared() ) - continue; - - if( fdt2->name == fdt->name && - fdt2->nameSpace == fdt->nameSpace && - fdt2->funcdef->IsSignatureExceptNameEqual(func) ) - { - // Replace our funcdef for the existing one - funcDef->idx = fdt2->funcdef->id; - module->ReplaceFuncDef(fdt, fdt2); - fdt2->AddRefInternal(); - - engine->funcDefs.RemoveValue(fdt); - - fdt->ReleaseInternal(); - found = true; - break; - } - } - } - - // If the funcdef was declared as external then the existing shared declaration must have been found - if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !found) - { - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf()); - WriteError(str, funcDef->script, funcDef->node); - } - - // Remember if the type was declared as external so the saved bytecode can be flagged accordingly - if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && found) - module->m_externalTypes.PushLast(engine->scriptFunctions[funcDef->idx]->funcdefType); + asCArray defaultArgs; + asSFunctionTraits funcTraits; + + asCFuncdefType *fdt = module->m_funcDefs[funcDef->idx]; + asASSERT( fdt ); + asCScriptFunction *func = fdt->funcdef; + + asSNameSpace *implicitNs = func->nameSpace ? func->nameSpace : fdt->parentClass->nameSpace; + GetParsedFunctionDetails(funcDef->node, funcDef->script, fdt->parentClass, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, funcTraits, implicitNs); + + // There should not be any defaultArgs, but if there are any we need to delete them to avoid leaks + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + // All funcdefs are shared, unless one of the parameter types or return type is not shared + bool declaredShared = funcTraits.GetTrait(asTRAIT_SHARED); + funcTraits.SetTrait(asTRAIT_SHARED, true); + if (func->returnType.GetTypeInfo() && !func->returnType.GetTypeInfo()->IsShared()) + { + if (declaredShared) + { + asCString s; + s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->returnType.GetTypeInfo()->name.AddressOf()); + WriteError(s.AddressOf(), funcDef->script, funcDef->node); + } + funcTraits.SetTrait(asTRAIT_SHARED, false); + } + for( asUINT n = 0; funcTraits.GetTrait(asTRAIT_SHARED) && n < func->parameterTypes.GetLength(); n++ ) + if (func->parameterTypes[n].GetTypeInfo() && !func->parameterTypes[n].GetTypeInfo()->IsShared()) + { + if (declaredShared) + { + asCString s; + s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); + WriteError(s.AddressOf(), funcDef->script, funcDef->node); + } + funcTraits.SetTrait(asTRAIT_SHARED, false); + } + func->SetShared(funcTraits.GetTrait(asTRAIT_SHARED)); + + // Check if there is another identical funcdef from another module and if so reuse that instead + bool found = false; + if( func->IsShared() ) + { + for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) + { + asCFuncdefType *fdt2 = engine->funcDefs[n]; + if( fdt2 == 0 || fdt == fdt2 ) + continue; + + if( !fdt2->funcdef->IsShared() ) + continue; + + if( fdt2->name == fdt->name && + fdt2->nameSpace == fdt->nameSpace && + fdt2->funcdef->IsSignatureExceptNameEqual(func) ) + { + // Replace our funcdef for the existing one + funcDef->idx = fdt2->funcdef->id; + module->ReplaceFuncDef(fdt, fdt2); + fdt2->AddRefInternal(); + + engine->funcDefs.RemoveValue(fdt); + + fdt->ReleaseInternal(); + found = true; + break; + } + } + } + + // If the funcdef was declared as external then the existing shared declaration must have been found + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !found) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf()); + WriteError(str, funcDef->script, funcDef->node); + } + + // Remember if the type was declared as external so the saved bytecode can be flagged accordingly + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && found) + module->m_externalTypes.PushLast(engine->scriptFunctions[funcDef->idx]->funcdefType); } 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(ns).AddressOf()); - else if( type.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(ns).AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(ns).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, true, false); - - // 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; + // 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(ns).AddressOf()); + else if( type.IsInterface() ) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(ns).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(ns).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, true, false); + + // 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, true, false); - - 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); - - // Check that the mixin class doesn't contain any child types - // TODO: Add support for child types in mixin classes - n = cl->firstChild; - while (n) - { - if (n->nodeType == snFuncDef) - { - WriteError(TXT_MIXIN_CANNOT_HAVE_CHILD_TYPES, file, n); - break; - } - n = n->next; - } - - return 0; + 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, true, false); + + 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); + + // Check that the mixin class doesn't contain any child types + // TODO: Add support for child types in mixin classes + n = cl->firstChild; + while (n) + { + if (n->nodeType == snFuncDef) + { + WriteError(TXT_MIXIN_CANNOT_HAVE_CHILD_TYPES, file, n); + break; + } + n = n->next; + } + + return 0; } int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) { - asCScriptNode *n = node->firstChild; - bool isFinal = false; - bool isShared = false; - bool isAbstract = false; - bool isExternal = 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, EXTERNAL_TOKEN)) - { - if (isExternal) - { - asCString msg; - msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); - WriteWarning(msg, file, n); - } - isExternal = true; - } - else if( file->TokenEquals(n->tokenPos, n->tokenLength, ABSTRACT_TOKEN) ) - { - if( isFinal ) - 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, true, false); - - 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; - - // External shared interfaces must not try to redefine the interface - if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement)) - { - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); - WriteError(str, file, n); - } - else if (!isExternal && n->next && n->next->tokenType == ttEndStatement) - { - asCString str; - str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); - WriteError(str, file, n); - } - - // If this type is shared and there already exist another shared - // type of the same name, then that one should be used instead of - // creating a new one. - asCObjectType *st = 0; - if( isShared ) - { - for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ ) - { - st = CastToObjectType(engine->sharedScriptTypes[i]); - if( st && - st->IsShared() && - st->name == name && - st->nameSpace == ns && - !st->IsInterface() ) - { - // We'll use the existing type - decl->isExistingShared = true; - decl->typeInfo = st; - module->AddClassType(st); - st->AddRefInternal(); - break; - } - } - } - - // If the class was declared as external then it must have been compiled in a different module first - if (isExternal && decl->typeInfo == 0) - { - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); - WriteError(str, file, n); - } - - // Remember if the class was declared as external so the saved bytecode can be flagged accordingly - if (isExternal) - module->m_externalTypes.PushLast(st); - - if (!decl->isExistingShared) - { - // Create a new object type for this class - st = asNEW(asCObjectType)(engine); - if (st == 0) - return asOUT_OF_MEMORY; - - // By default all script classes are marked as garbage collected. - // Only after the complete structure and relationship between classes - // is known, can the flag be cleared for those objects that truly cannot - // form circular references. This is important because a template - // callback may be called with a script class before the compilation - // completes, and until it is known, the callback must assume the class - // is garbage collected. - st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_GC; - - if (isShared) - st->flags |= asOBJ_SHARED; - - if (isFinal) - st->flags |= asOBJ_NOINHERIT; - - if (isAbstract) - st->flags |= asOBJ_ABSTRACT; - - if (node->tokenType == ttHandle) - st->flags |= asOBJ_IMPLICIT_HANDLE; - - st->size = sizeof(asCScriptObject); - st->name = name; - st->nameSpace = ns; - st->module = module; - module->AddClassType(st); - if (isShared) - { - engine->sharedScriptTypes.PushLast(st); - st->AddRefInternal(); - } - decl->typeInfo = st; - - // Use the default script class behaviours - st->beh = engine->scriptTypeBehaviours.beh; - - // TODO: Move this to asCObjectType so that the asCRestore can reuse it - engine->scriptFunctions[st->beh.addref]->AddRefInternal(); - engine->scriptFunctions[st->beh.release]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcEnumReferences]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcGetFlag]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcGetRefCount]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRefInternal(); - engine->scriptFunctions[st->beh.gcSetFlag]->AddRefInternal(); - engine->scriptFunctions[st->beh.copy]->AddRefInternal(); - engine->scriptFunctions[st->beh.factory]->AddRefInternal(); - engine->scriptFunctions[st->beh.construct]->AddRefInternal(); - // TODO: weak: Should not do this if the class has been declared with noweak - engine->scriptFunctions[st->beh.getWeakRefFlag]->AddRefInternal(); - - // Skip to the content of the class - while (n && n->nodeType == snIdentifier) - n = n->next; - } - - // Register possible child types - while (n) - { - node = n->next; - if (n->nodeType == snFuncDef) - { - n->DisconnectParent(); - if (!decl->isExistingShared) - RegisterFuncDef(n, file, 0, st); - else - { - // Destroy the node, since it won't be used - // TODO: Should verify that the funcdef is identical to the one in the existing shared class - n->Destroy(engine); - } - } - n = node; - } - - return 0; + asCScriptNode *n = node->firstChild; + bool isFinal = false; + bool isShared = false; + bool isAbstract = false; + bool isExternal = 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, EXTERNAL_TOKEN)) + { + if (isExternal) + { + asCString msg; + msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); + WriteWarning(msg, file, n); + } + isExternal = true; + } + else if( file->TokenEquals(n->tokenPos, n->tokenLength, ABSTRACT_TOKEN) ) + { + if( isFinal ) + 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, true, false); + + 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; + + // External shared interfaces must not try to redefine the interface + if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement)) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, n); + } + else if (!isExternal && n->next && n->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, n); + } + + // If this type is shared and there already exist another shared + // type of the same name, then that one should be used instead of + // creating a new one. + asCObjectType *st = 0; + if( isShared ) + { + for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ ) + { + st = CastToObjectType(engine->sharedScriptTypes[i]); + if( st && + st->IsShared() && + st->name == name && + st->nameSpace == ns && + !st->IsInterface() ) + { + // We'll use the existing type + decl->isExistingShared = true; + decl->typeInfo = st; + module->AddClassType(st); + st->AddRefInternal(); + break; + } + } + } + + // If the class was declared as external then it must have been compiled in a different module first + if (isExternal && decl->typeInfo == 0) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, n); + } + + // Remember if the class was declared as external so the saved bytecode can be flagged accordingly + if (isExternal) + module->m_externalTypes.PushLast(st); + + if (!decl->isExistingShared) + { + // Create a new object type for this class + st = asNEW(asCObjectType)(engine); + if (st == 0) + return asOUT_OF_MEMORY; + + // By default all script classes are marked as garbage collected. + // Only after the complete structure and relationship between classes + // is known, can the flag be cleared for those objects that truly cannot + // form circular references. This is important because a template + // callback may be called with a script class before the compilation + // completes, and until it is known, the callback must assume the class + // is garbage collected. + st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_GC; + + if (isShared) + st->flags |= asOBJ_SHARED; + + if (isFinal) + st->flags |= asOBJ_NOINHERIT; + + if (isAbstract) + st->flags |= asOBJ_ABSTRACT; + + if (node->tokenType == ttHandle) + st->flags |= asOBJ_IMPLICIT_HANDLE; + + st->size = sizeof(asCScriptObject); + st->name = name; + st->nameSpace = ns; + st->module = module; + module->AddClassType(st); + if (isShared) + { + engine->sharedScriptTypes.PushLast(st); + st->AddRefInternal(); + } + decl->typeInfo = st; + + // Use the default script class behaviours + st->beh = engine->scriptTypeBehaviours.beh; + + // TODO: Move this to asCObjectType so that the asCRestore can reuse it + engine->scriptFunctions[st->beh.addref]->AddRefInternal(); + engine->scriptFunctions[st->beh.release]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcEnumReferences]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcGetFlag]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcGetRefCount]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcSetFlag]->AddRefInternal(); + engine->scriptFunctions[st->beh.copy]->AddRefInternal(); + engine->scriptFunctions[st->beh.factory]->AddRefInternal(); + engine->scriptFunctions[st->beh.construct]->AddRefInternal(); + // TODO: weak: Should not do this if the class has been declared with noweak + engine->scriptFunctions[st->beh.getWeakRefFlag]->AddRefInternal(); + + // Skip to the content of the class + while (n && n->nodeType == snIdentifier) + n = n->next; + } + + // Register possible child types + while (n) + { + node = n->next; + if (n->nodeType == snFuncDef) + { + n->DisconnectParent(); + if (!decl->isExistingShared) + RegisterFuncDef(n, file, 0, st); + else + { + // Destroy the node, since it won't be used + // TODO: Should verify that the funcdef is identical to the one in the existing shared class + n->Destroy(engine); + } + } + n = node; + } + + return 0; } int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) { - asCScriptNode *n = node->firstChild; - - bool isShared = false; - bool isExternal = false; - while( n->nodeType == snIdentifier ) - { - if (file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN)) - isShared = true; - else if (file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN)) - isExternal = true; - else - break; - n = n->next; - } - - int r, c; - file->ConvertPosToRowCol(n->tokenPos, &r, &c); - - asCString name; - name.Assign(&file->code[n->tokenPos], n->tokenLength); - CheckNameConflict(name.AddressOf(), n, file, ns, true, false); - - 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; - - // External shared interfaces must not try to redefine the interface - if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement) ) - { - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); - WriteError(str, file, n); - } - else if (!isExternal && n->next && n->next->tokenType == ttEndStatement) - { - asCString str; - str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); - WriteError(str, file, n); - } - - // If this type is shared and there already exist another shared - // type of the same name, then that one should be used instead of - // creating a new one. - if( isShared ) - { - for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ ) - { - asCObjectType *st = CastToObjectType(engine->sharedScriptTypes[i]); - if( st && - st->IsShared() && - st->name == name && - st->nameSpace == ns && - st->IsInterface() ) - { - // We'll use the existing type - decl->isExistingShared = true; - decl->typeInfo = st; - module->AddClassType(st); - st->AddRefInternal(); - - // Remember if the interface was declared as external so the saved bytecode can be flagged accordingly - if (isExternal) - module->m_externalTypes.PushLast(st); - - return 0; - } - } - } - - // If the interface was declared as external then it must have been compiled in a different module first - if (isExternal) - { - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); - WriteError(str, file, n); - } - - // Register the object type for the interface - asCObjectType *st = asNEW(asCObjectType)(engine); - if( st == 0 ) - 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->AddClassType(st); - if( isShared ) - { - engine->sharedScriptTypes.PushLast(st); - st->AddRefInternal(); - } - decl->typeInfo = st; - - // Use the default script class behaviours - st->beh.construct = 0; - st->beh.addref = engine->scriptTypeBehaviours.beh.addref; - engine->scriptFunctions[st->beh.addref]->AddRefInternal(); - st->beh.release = engine->scriptTypeBehaviours.beh.release; - engine->scriptFunctions[st->beh.release]->AddRefInternal(); - st->beh.copy = 0; - - return 0; + asCScriptNode *n = node->firstChild; + + bool isShared = false; + bool isExternal = false; + while( n->nodeType == snIdentifier ) + { + if (file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN)) + isShared = true; + else if (file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN)) + isExternal = true; + else + break; + n = n->next; + } + + int r, c; + file->ConvertPosToRowCol(n->tokenPos, &r, &c); + + asCString name; + name.Assign(&file->code[n->tokenPos], n->tokenLength); + CheckNameConflict(name.AddressOf(), n, file, ns, true, false); + + 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; + + // External shared interfaces must not try to redefine the interface + if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement) ) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, n); + } + else if (!isExternal && n->next && n->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, n); + } + + // If this type is shared and there already exist another shared + // type of the same name, then that one should be used instead of + // creating a new one. + if( isShared ) + { + for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ ) + { + asCObjectType *st = CastToObjectType(engine->sharedScriptTypes[i]); + if( st && + st->IsShared() && + st->name == name && + st->nameSpace == ns && + st->IsInterface() ) + { + // We'll use the existing type + decl->isExistingShared = true; + decl->typeInfo = st; + module->AddClassType(st); + st->AddRefInternal(); + + // Remember if the interface was declared as external so the saved bytecode can be flagged accordingly + if (isExternal) + module->m_externalTypes.PushLast(st); + + return 0; + } + } + } + + // If the interface was declared as external then it must have been compiled in a different module first + if (isExternal) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, n); + } + + // Register the object type for the interface + asCObjectType *st = asNEW(asCObjectType)(engine); + if( st == 0 ) + 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->AddClassType(st); + if( isShared ) + { + engine->sharedScriptTypes.PushLast(st); + st->AddRefInternal(); + } + decl->typeInfo = st; + + // Use the default script class behaviours + st->beh.construct = 0; + st->beh.addref = engine->scriptTypeBehaviours.beh.addref; + engine->scriptFunctions[st->beh.addref]->AddRefInternal(); + st->beh.release = engine->scriptTypeBehaviours.beh.release; + engine->scriptFunctions[st->beh.release]->AddRefInternal(); + 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(gvar->ns); - 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.GetTypeInfo()->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 ) - { - enumVal = int(gvar2->constantValue) + 1; - - if( !gvar2->isCompiled ) - { - int row, col; - gvar->script->ConvertPosToRowCol(gvar->declaredAtNode->tokenPos, &row, &col); - - asCString str = gvar->datatype.Format(gvar->ns); - 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; - } - } - } - - 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->AddScriptFunction(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->ReleaseInternal(); - 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 ) - { - asCEnumType *enumType = CastToEnumType(gvar->datatype.GetTypeInfo()); - asASSERT(NULL != enumType); - - asSEnumValue *e = asNEW(asSEnumValue); - if( e == 0 ) - { - // Out of memory - numErrors++; - return; - } - - e->name = gvar->name; - e->value = int(gvar->constantValue); - - enumType->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->m_scriptGlobals.GetSize() == initOrder.GetSize() ) - module->m_scriptGlobals.SwapWith(initOrder); - } - - CleanupEnumValues(); + 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(gvar->ns); + 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.GetTypeInfo()->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 ) + { + enumVal = int(gvar2->constantValue) + 1; + + if( !gvar2->isCompiled ) + { + int row, col; + gvar->script->ConvertPosToRowCol(gvar->declaredAtNode->tokenPos, &row, &col); + + asCString str = gvar->datatype.Format(gvar->ns); + 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; + } + } + } + + 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->AddScriptFunction(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->ReleaseInternal(); + 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 ) + { + asCEnumType *enumType = CastToEnumType(gvar->datatype.GetTypeInfo()); + asASSERT(NULL != enumType); + + asSEnumValue *e = asNEW(asSEnumValue); + if( e == 0 ) + { + // Out of memory + numErrors++; + return; + } + + e->name = gvar->name; + e->value = int(gvar->constantValue); + + enumType->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->m_scriptGlobals.GetSize() == initOrder.GetSize() ) + module->m_scriptGlobals.SwapWith(initOrder); + } + + CleanupEnumValues(); } void asCBuilder::CleanupEnumValues() { - // 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++; - } + // 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) { - // TODO: child funcdef: The node might be a snScope now - asASSERT( n->nodeType == snIdentifier ); + // TODO: child funcdef: The node might be a snScope now + asASSERT( n->nodeType == snIdentifier ); - // Get the optional scope from the node - // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace - asSNameSpace *ns = GetNameSpaceFromNode(n->firstChild, script, implicitNs, 0); - if( ns == 0 ) - return -1; + // Get the optional scope from the node + // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace + asSNameSpace *ns = GetNameSpaceFromNode(n->firstChild, script, implicitNs, 0); + if( ns == 0 ) + return -1; - // Get the name - asCString name(&script->code[n->lastChild->tokenPos], n->lastChild->tokenLength); + // Get the name + asCString name(&script->code[n->lastChild->tokenPos], n->lastChild->tokenLength); - outNs = ns; - outName = name; + outNs = ns; + outName = name; - return 0; + 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->typeInfo->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; - } + // 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->typeInfo->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->typeInfo->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->typeInfo->Implements(intfType) ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName()); - WriteError(str, decl->script, errNode); - return; - } - } - else - { - // If the interface is already in the class then don't add it again - if( decl->typeInfo->Implements(intfType) ) - return; - - // Add the interface to the class - CastToObjectType(decl->typeInfo)->interfaces.PushLast(intfType); - - // Add the inherited interfaces too - // For interfaces this will be done outside to handle out-of-order declarations - if( !CastToObjectType(decl->typeInfo)->IsInterface() ) - { - for( asUINT n = 0; n < intfType->interfaces.GetLength(); n++ ) - AddInterfaceToClass(decl, errNode, intfType->interfaces[n]); - } - } + // A shared type may only implement from shared interfaces + if( decl->typeInfo->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->typeInfo->Implements(intfType) ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName()); + WriteError(str, decl->script, errNode); + return; + } + } + else + { + // If the interface is already in the class then don't add it again + if( decl->typeInfo->Implements(intfType) ) + return; + + // Add the interface to the class + CastToObjectType(decl->typeInfo)->interfaces.PushLast(intfType); + + // Add the inherited interfaces too + // For interfaces this will be done outside to handle out-of-order declarations + if( !CastToObjectType(decl->typeInfo)->IsInterface() ) + { + for( asUINT n = 0; n < intfType->interfaces.GetLength(); n++ ) + AddInterfaceToClass(decl, errNode, intfType->interfaces[n]); + } + } } void asCBuilder::CompileInterfaces() { - asUINT n; - - // 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 = CastToObjectType(intfDecl->typeInfo); - - if( intfType->interfaces.GetLength() == 0 ) continue; - - // If any of the derived interfaces are found after this interface, then move this to the end of the list - for( asUINT m = n+1; m < interfaceDeclarations.GetLength(); m++ ) - { - if( intfType->Implements(interfaceDeclarations[m]->typeInfo) ) - { - 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]; - if( intfDecl->isExistingShared ) - { - // Set the declaration as validated already, so that other - // types that contain this will accept this type - intfDecl->validState = 1; - continue; - } - - asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); - - // TODO: Is this really at the correct place? Hasn't the vfTableIdx already been set here? - // 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 l = 0; l < base->methods.GetLength(); l++ ) - { - // If the derived interface implements the same method, then don't add the base interface' method - asCScriptFunction *baseFunc = GetFunctionDescription(base->methods[l]); - 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->AddRefInternal(); - } - } - } - } + asUINT n; + + // 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 = CastToObjectType(intfDecl->typeInfo); + + if( intfType->interfaces.GetLength() == 0 ) continue; + + // If any of the derived interfaces are found after this interface, then move this to the end of the list + for( asUINT m = n+1; m < interfaceDeclarations.GetLength(); m++ ) + { + if( intfType->Implements(interfaceDeclarations[m]->typeInfo) ) + { + 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]; + if( intfDecl->isExistingShared ) + { + // Set the declaration as validated already, so that other + // types that contain this will accept this type + intfDecl->validState = 1; + continue; + } + + asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); + + // TODO: Is this really at the correct place? Hasn't the vfTableIdx already been set here? + // 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 l = 0; l < base->methods.GetLength(); l++ ) + { + // If the derived interface implements the same method, then don't add the base interface' method + asCScriptFunction *baseFunc = GetFunctionDescription(base->methods[l]); + 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->AddRefInternal(); + } + } + } + } } void asCBuilder::DetermineTypeRelations() { - // Determine inheritance between interfaces - for (asUINT n = 0; n < interfaceDeclarations.GetLength(); n++) - { - sClassDeclaration *intfDecl = interfaceDeclarations[n]; - asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); - - asCScriptNode *node = intfDecl->node; - asASSERT(node && node->nodeType == snInterface); - node = node->firstChild; - - // Skip the 'shared' & 'external' keywords - while( node->nodeType == snIdentifier && - (intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) || - intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) ) - node = node->next; - - // Skip the name - node = node->next; - - // Verify the inherited interfaces - while (node && node->nodeType == snIdentifier) - { - asSNameSpace *ns; - asCString name; - if (GetNamespaceAndNameFromNode(node, intfDecl->script, intfType->nameSpace, ns, name) < 0) - { - node = node->next; - continue; - } - - // Find the object type for the interface - asCObjectType *objType = 0; - while (ns) - { - objType = GetObjectType(name.AddressOf(), ns); - if (objType) break; - - ns = engine->GetParentNameSpace(ns); - } - - // Check that the object type is an interface - bool ok = true; - if (objType && objType->IsInterface()) - { - // Check that the implemented interface is shared if the base interface is shared - if (intfType->IsShared() && !objType->IsShared()) - { - asCString str; - str.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, objType->GetName()); - WriteError(str, intfDecl->script, node); - ok = false; - } - } - else - { - WriteError(TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE, intfDecl->script, node); - ok = false; - } - - if (ok) - { - // Make sure none of the implemented interfaces implement from this one - asCObjectType *base = objType; - while (base != 0) - { - if (base == intfType) - { - WriteError(TXT_CANNOT_IMPLEMENT_SELF, intfDecl->script, node); - ok = false; - break; - } - - // At this point there is at most one implemented interface - if (base->interfaces.GetLength()) - base = base->interfaces[0]; - else - break; - } - } - - if (ok) - AddInterfaceToClass(intfDecl, node, objType); - - // Remove the nodes so they aren't parsed again - asCScriptNode *delNode = node; - node = node->next; - delNode->DisconnectParent(); - delNode->Destroy(engine); - } - } - - // Determine class inheritances and interfaces - for (asUINT 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) || - file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_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->typeInfo->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 = engine->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 && CastToObjectType(decl->typeInfo)->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->typeInfo) - { - 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->typeInfo->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 (CastToObjectType(decl->typeInfo)->derivedFrom != objType) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName()); - WriteError(str, file, node); - } - } - else - { - // Set the base class - CastToObjectType(decl->typeInfo)->derivedFrom = objType; - objType->AddRefInternal(); - } - } - } - } - else - { - // The class implements an interface - AddInterfaceToClass(decl, node, objType); - } - - node = node->next; - } - } + // Determine inheritance between interfaces + for (asUINT n = 0; n < interfaceDeclarations.GetLength(); n++) + { + sClassDeclaration *intfDecl = interfaceDeclarations[n]; + asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); + + asCScriptNode *node = intfDecl->node; + asASSERT(node && node->nodeType == snInterface); + node = node->firstChild; + + // Skip the 'shared' & 'external' keywords + while( node->nodeType == snIdentifier && + (intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) || + intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) ) + node = node->next; + + // Skip the name + node = node->next; + + // Verify the inherited interfaces + while (node && node->nodeType == snIdentifier) + { + asSNameSpace *ns; + asCString name; + if (GetNamespaceAndNameFromNode(node, intfDecl->script, intfType->nameSpace, ns, name) < 0) + { + node = node->next; + continue; + } + + // Find the object type for the interface + asCObjectType *objType = 0; + while (ns) + { + objType = GetObjectType(name.AddressOf(), ns); + if (objType) break; + + ns = engine->GetParentNameSpace(ns); + } + + // Check that the object type is an interface + bool ok = true; + if (objType && objType->IsInterface()) + { + // Check that the implemented interface is shared if the base interface is shared + if (intfType->IsShared() && !objType->IsShared()) + { + asCString str; + str.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, objType->GetName()); + WriteError(str, intfDecl->script, node); + ok = false; + } + } + else + { + WriteError(TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE, intfDecl->script, node); + ok = false; + } + + if (ok) + { + // Make sure none of the implemented interfaces implement from this one + asCObjectType *base = objType; + while (base != 0) + { + if (base == intfType) + { + WriteError(TXT_CANNOT_IMPLEMENT_SELF, intfDecl->script, node); + ok = false; + break; + } + + // At this point there is at most one implemented interface + if (base->interfaces.GetLength()) + base = base->interfaces[0]; + else + break; + } + } + + if (ok) + AddInterfaceToClass(intfDecl, node, objType); + + // Remove the nodes so they aren't parsed again + asCScriptNode *delNode = node; + node = node->next; + delNode->DisconnectParent(); + delNode->Destroy(engine); + } + } + + // Determine class inheritances and interfaces + for (asUINT 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) || + file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_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->typeInfo->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 = engine->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 && CastToObjectType(decl->typeInfo)->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->typeInfo) + { + 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->typeInfo->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 (CastToObjectType(decl->typeInfo)->derivedFrom != objType) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName()); + WriteError(str, file, node); + } + } + else + { + // Set the base class + CastToObjectType(decl->typeInfo)->derivedFrom = objType; + objType->AddRefInternal(); + } + } + } + } + else + { + // The class implements an interface + AddInterfaceToClass(decl, node, objType); + } + + node = node->next; + } + } } // numTempl is the number of template instances that existed in the engine before the build begun void asCBuilder::CompileClasses(asUINT numTempl) { - asUINT n; - asCArray toValidate((int)classDeclarations.GetLength()); - - // Order class declarations so that base classes are compiled before derived classes. - // This will allow the derived classes to copy properties and methods in the next step. - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - sClassDeclaration *decl = classDeclarations[n]; - asCObjectType *derived = CastToObjectType(decl->typeInfo); - 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->typeInfo ) - { - 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]; - asCObjectType *ot = CastToObjectType(decl->typeInfo); - 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( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() ); - } - - // Methods included from mixin classes should take precedence over inherited methods - IncludeMethodsFromMixins(decl); - - // Add all properties and methods from the base class - if( !decl->isExistingShared && ot->derivedFrom ) - { - asCObjectType *baseType = ot->derivedFrom; - - // The derived class inherits all interfaces from the base class - for( unsigned int m = 0; m < baseType->interfaces.GetLength(); m++ ) - { - if( !ot->Implements(baseType->interfaces[m]) ) - ot->interfaces.PushLast(baseType->interfaces[m]); - } - - // 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, baseType->properties[p]->isProtected, true); - - // 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 < ot->methods.GetLength(); d++ ) - { - derivedFunc = GetFunctionDescription(ot->methods[d]); - if( baseFunc->name == "opConv" || baseFunc->name == "opImplConv" || - baseFunc->name == "opCast" || baseFunc->name == "opImplCast" ) - { - // For the opConv and opCast 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 - ot->methods.RemoveIndex(d); - ot->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 - ot->methods.RemoveIndex(d); - ot->virtualFunctionTable.PushLast(derivedFunc); - found = true; - break; - } - } - } - - if( !found ) - { - // Push the base class function on the virtual function table - ot->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]); - baseType->virtualFunctionTable[m]->AddRefInternal(); - - CheckForConflictsDueToDefaultArgs(decl->script, decl->node, baseType->virtualFunctionTable[m], ot); - } - - ot->methods.PushLast(baseType->methods[m]); - engine->scriptFunctions[baseType->methods[m]]->AddRefInternal(); - } - } - - if( !decl->isExistingShared ) - { - // Move this class' methods into the virtual function table - for( asUINT m = 0; m < ot->methods.GetLength(); m++ ) - { - asCScriptFunction *func = GetFunctionDescription(ot->methods[m]); - if( func->funcType != asFUNC_VIRTUAL ) - { - // Move the reference from the method list to the virtual function list - ot->methods.RemoveIndex(m); - ot->virtualFunctionTable.PushLast(func); - - // Substitute the function description in the method list for a virtual method - // Make sure the methods are in the same order as the virtual function table - ot->methods.PushLast(CreateVirtualFunction(func, (int)ot->virtualFunctionTable.GetLength() - 1)); - m--; - } - } - - // Make virtual function table chunks for each implemented interface - for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ ) - { - asCObjectType *intf = ot->interfaces[m]; - - // Add all the interface's functions to the virtual function table - asUINT offset = asUINT(ot->virtualFunctionTable.GetLength()); - ot->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 < ot->methods.GetLength(); p++ ) - { - asCScriptFunction *func = GetFunctionDescription(ot->methods[p]); - - if( func->signatureId == intfFunc->signatureId ) - { - if( func->funcType == asFUNC_VIRTUAL ) - { - realFunc = ot->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. - ot->virtualFunctionTable.PushLast(realFunc); - if( realFunc ) - realFunc->AddRefInternal(); - } - } - } - - // 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 && node->nodeType == snDeclaration ) - { - asCScriptNode *nd = node->firstChild; - - // Is the property declared as private or protected? - bool isPrivate = false, isProtected = false; - if( nd && nd->tokenType == ttPrivate ) - { - isPrivate = true; - nd = nd->next; - } - else if( nd && nd->tokenType == ttProtected ) - { - isProtected = true; - nd = nd->next; - } - - // Determine the type of the property - asCScriptCode *file = decl->script; - asCDataType dt = CreateDataTypeFromNode(nd, file, ot->nameSpace, false, ot); - if( ot->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); - WriteError(msg, file, node); - } - - if( dt.IsReadOnly() ) - WriteError(TXT_PROPERTY_CANT_BE_CONST, file, node); - - // Multiple properties can be declared separated by , - nd = nd->next; - while( nd ) - { - asCString name(&file->code[nd->tokenPos], nd->tokenLength); - - if( !decl->isExistingShared ) - { - CheckNameConflictMember(ot, name.AddressOf(), nd, file, true, false); - AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, nd); - } - else - { - // Verify that the property exists in the original declaration - bool found = false; - for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) - { - asCObjectProperty *prop = ot->properties[p]; - if( prop->isPrivate == isPrivate && - prop->isProtected == isProtected && - prop->name == name && - prop->type.IsEqualExceptRef(dt) ) - { - found = true; - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); - WriteError(str, file, nd); - } - } - - // Skip the initialization node - if( nd->next && nd->next->nodeType != snIdentifier ) - nd = nd->next; - - nd = nd->next; - } - - 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( ot->interfaces.GetLength() == ot->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; - - asCObjectType *ot = CastToObjectType(decl->typeInfo); - asCArray overrideValidations(ot->GetMethodCount()); - for( asUINT k = 0; k < ot->methods.GetLength(); k++ ) - overrideValidations.PushLast( !static_cast(ot->GetMethodByIndex(k, false))->IsOverride() ); - - for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ ) - { - asCObjectType *objType = ot->interfaces[m]; - for( asUINT i = 0; i < objType->methods.GetLength(); i++ ) - { - // Only check the interface methods that was explicitly declared in this interface - // 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(ot, 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 = ot->derivedFrom != 0; - - for( asUINT j = 0; j < overrideValidations.GetLength(); j++ ) - { - if( !overrideValidations[j] && (!hasBaseClass || !DoesMethodExist(ot->derivedFrom, ot->methods[j])) ) - { - asCString msg; - msg.Format(TXT_METHOD_s_DOES_NOT_OVERRIDE, ot->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]; - asCObjectType *ot = CastToObjectType(decl->typeInfo); - int validState = 1; - for( n = 0; n < ot->properties.GetLength(); n++ ) - { - // A valid structure is one that uses only primitives or other valid objects - asCObjectProperty *prop = ot->properties[n]; - asCDataType dt = prop->type; - - // TODO: Add this check again, once solving the issues commented below - /* - if( dt.IsTemplate() ) - { - // TODO: This must verify all sub types, not just the first one - // TODO: Just because the subtype is not a handle doesn't mean the template will actually instance the object - // this it shouldn't automatically raise an error for this, e.g. weakref should be legal as member - // of the Object class - 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]->typeInfo == dt.GetTypeInfo() ) - { - pdecl = classDeclarations[p]; - break; - } - } - - if( pdecl ) - { - if( pdecl->typeInfo == decl->typeInfo ) - { - 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. - // This must be done in the correct order, so that a class that contains another class isn't needlessly marked - // as garbage collected, just because the contained class was evaluated afterwards. - - // 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. - - asCArray typesToValidate; - for( n = 0; n < classDeclarations.GetLength(); n++ ) - { - // Existing shared classes won't need evaluating, nor interfaces - sClassDeclaration *decl = classDeclarations[n]; - if( decl->isExistingShared ) continue; - - asCObjectType *ot = CastToObjectType(decl->typeInfo); - if( ot->IsInterface() ) continue; - - typesToValidate.PushLast(ot); - } - - asUINT numReevaluations = 0; - while( typesToValidate.GetLength() ) - { - if( numReevaluations > typesToValidate.GetLength() ) - { - // No types could be completely evaluated in the last iteration so - // we consider the remaining types in the array as garbage collected - break; - } - - asCObjectType *type = typesToValidate[0]; - typesToValidate.RemoveIndex(0); - - // If the type inherits from another type that is yet to be validated, then reinsert it at the end - if( type->derivedFrom && typesToValidate.Exists(type->derivedFrom) ) - { - typesToValidate.PushLast(type); - numReevaluations++; - continue; - } - - // If the type inherits from a known garbage collected type, then this type must also be garbage collected - if( type->derivedFrom && (type->derivedFrom->flags & asOBJ_GC) ) - { - type->flags |= asOBJ_GC; - continue; - } - - // Evaluate template instances (silently) before verifying each of the classes, since it is possible that - // a class will be marked as non-garbage collected, which in turn will mark the template instance that uses - // it as non-garbage collected, which in turn means the class that contains the array also do not have to be - // garbage collected - EvaluateTemplateInstances(numTempl, true); - - // Is there some path in which this structure is involved in circular references? - // If the type contains a member of a type that is yet to be validated, then reinsert it at the end - bool mustReevaluate = false; - bool gc = false; - for( asUINT p = 0; p < type->properties.GetLength(); p++ ) - { - asCDataType dt = type->properties[p]->type; - - if (dt.IsFuncdef()) - { - // If a class holds a function pointer as member then the class must be garbage collected as the - // function pointer can form circular references with the class through use of a delegate. Example: - // - // class A { B @b; void f(); } - // class B { F @f; } - // funcdef void F(); - // - // A a; - // @a.b = B(); // instance of A refers to instance of B - // @a.b.f = F(a.f); // instance of B refers to delegate that refers to instance of A - // - gc = true; - break; - } - - if( !dt.IsObject() ) - continue; - - if( typesToValidate.Exists(CastToObjectType(dt.GetTypeInfo())) ) - mustReevaluate = true; - else - { - if( dt.IsTemplate() ) - { - // Check if any of the subtypes are yet to be evaluated - bool skip = false; - for( asUINT s = 0; s < dt.GetTypeInfo()->GetSubTypeCount(); s++ ) - { - asCObjectType *t = reinterpret_cast(dt.GetTypeInfo()->GetSubType(s)); - if( typesToValidate.Exists(t) ) - { - mustReevaluate = true; - skip = true; - break; - } - } - if( skip ) - 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 = CastToObjectType(dt.GetTypeInfo()); - - 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 with this - // class. - 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.GetTypeInfo()->flags & (asOBJ_SCRIPT_OBJECT | asOBJ_GC) ) - { - gc = true; - break; - } - } - else if( sdt.GetTypeInfo()->flags & asOBJ_GC ) - { - // TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is. - // Only if the object is of a type that can reference this type, either directly or indirectly - 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 - // TODO: runtime optimize: Just because an application registered class is garbage collected, doesn't mean it - // can form a circular reference with this script class. Perhaps need a flag to tell - // if the script classes that contains the type should be garbage collected or not. - gc = true; - break; - } - } - else if( dt.GetTypeInfo()->flags & asOBJ_GC ) - { - // TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is. - // Only if the object is of a type that can reference this type, either directly or indirectly - gc = true; - break; - } - } - } - - // If the class wasn't found to require garbage collection, but it - // contains another type that has yet to be evaluated then it must be - // re-evaluated. - if( !gc && mustReevaluate ) - { - typesToValidate.PushLast(type); - numReevaluations++; - continue; - } - - // Update the flag in the object type - if( gc ) - type->flags |= asOBJ_GC; - else - type->flags &= ~asOBJ_GC; - - // Reset the counter - numReevaluations = 0; - } + asUINT n; + asCArray toValidate((int)classDeclarations.GetLength()); + + // Order class declarations so that base classes are compiled before derived classes. + // This will allow the derived classes to copy properties and methods in the next step. + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + sClassDeclaration *decl = classDeclarations[n]; + asCObjectType *derived = CastToObjectType(decl->typeInfo); + 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->typeInfo ) + { + 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]; + asCObjectType *ot = CastToObjectType(decl->typeInfo); + 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( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() ); + } + + // Methods included from mixin classes should take precedence over inherited methods + IncludeMethodsFromMixins(decl); + + // Add all properties and methods from the base class + if( !decl->isExistingShared && ot->derivedFrom ) + { + asCObjectType *baseType = ot->derivedFrom; + + // The derived class inherits all interfaces from the base class + for( unsigned int m = 0; m < baseType->interfaces.GetLength(); m++ ) + { + if( !ot->Implements(baseType->interfaces[m]) ) + ot->interfaces.PushLast(baseType->interfaces[m]); + } + + // 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, baseType->properties[p]->isProtected, true); + + // 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 < ot->methods.GetLength(); d++ ) + { + derivedFunc = GetFunctionDescription(ot->methods[d]); + if( baseFunc->name == "opConv" || baseFunc->name == "opImplConv" || + baseFunc->name == "opCast" || baseFunc->name == "opImplCast" ) + { + // For the opConv and opCast 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 + ot->methods.RemoveIndex(d); + ot->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 + ot->methods.RemoveIndex(d); + ot->virtualFunctionTable.PushLast(derivedFunc); + found = true; + break; + } + } + } + + if( !found ) + { + // Push the base class function on the virtual function table + ot->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]); + baseType->virtualFunctionTable[m]->AddRefInternal(); + + CheckForConflictsDueToDefaultArgs(decl->script, decl->node, baseType->virtualFunctionTable[m], ot); + } + + ot->methods.PushLast(baseType->methods[m]); + engine->scriptFunctions[baseType->methods[m]]->AddRefInternal(); + } + } + + if( !decl->isExistingShared ) + { + // Move this class' methods into the virtual function table + for( asUINT m = 0; m < ot->methods.GetLength(); m++ ) + { + asCScriptFunction *func = GetFunctionDescription(ot->methods[m]); + if( func->funcType != asFUNC_VIRTUAL ) + { + // Move the reference from the method list to the virtual function list + ot->methods.RemoveIndex(m); + ot->virtualFunctionTable.PushLast(func); + + // Substitute the function description in the method list for a virtual method + // Make sure the methods are in the same order as the virtual function table + ot->methods.PushLast(CreateVirtualFunction(func, (int)ot->virtualFunctionTable.GetLength() - 1)); + m--; + } + } + + // Make virtual function table chunks for each implemented interface + for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ ) + { + asCObjectType *intf = ot->interfaces[m]; + + // Add all the interface's functions to the virtual function table + asUINT offset = asUINT(ot->virtualFunctionTable.GetLength()); + ot->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 < ot->methods.GetLength(); p++ ) + { + asCScriptFunction *func = GetFunctionDescription(ot->methods[p]); + + if( func->signatureId == intfFunc->signatureId ) + { + if( func->funcType == asFUNC_VIRTUAL ) + { + realFunc = ot->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. + ot->virtualFunctionTable.PushLast(realFunc); + if( realFunc ) + realFunc->AddRefInternal(); + } + } + } + + // 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 && node->nodeType == snDeclaration ) + { + asCScriptNode *nd = node->firstChild; + + // Is the property declared as private or protected? + bool isPrivate = false, isProtected = false; + if( nd && nd->tokenType == ttPrivate ) + { + isPrivate = true; + nd = nd->next; + } + else if( nd && nd->tokenType == ttProtected ) + { + isProtected = true; + nd = nd->next; + } + + // Determine the type of the property + asCScriptCode *file = decl->script; + asCDataType dt = CreateDataTypeFromNode(nd, file, ot->nameSpace, false, ot); + if( ot->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + WriteError(msg, file, node); + } + + if( dt.IsReadOnly() ) + WriteError(TXT_PROPERTY_CANT_BE_CONST, file, node); + + // Multiple properties can be declared separated by , + nd = nd->next; + while( nd ) + { + asCString name(&file->code[nd->tokenPos], nd->tokenLength); + + if( !decl->isExistingShared ) + { + CheckNameConflictMember(ot, name.AddressOf(), nd, file, true, false); + AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, nd); + } + else + { + // Verify that the property exists in the original declaration + bool found = false; + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) + { + asCObjectProperty *prop = ot->properties[p]; + if( prop->isPrivate == isPrivate && + prop->isProtected == isProtected && + prop->name == name && + prop->type.IsEqualExceptRef(dt) ) + { + found = true; + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + WriteError(str, file, nd); + } + } + + // Skip the initialization node + if( nd->next && nd->next->nodeType != snIdentifier ) + nd = nd->next; + + nd = nd->next; + } + + 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( ot->interfaces.GetLength() == ot->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; + + asCObjectType *ot = CastToObjectType(decl->typeInfo); + asCArray overrideValidations(ot->GetMethodCount()); + for( asUINT k = 0; k < ot->methods.GetLength(); k++ ) + overrideValidations.PushLast( !static_cast(ot->GetMethodByIndex(k, false))->IsOverride() ); + + for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ ) + { + asCObjectType *objType = ot->interfaces[m]; + for( asUINT i = 0; i < objType->methods.GetLength(); i++ ) + { + // Only check the interface methods that was explicitly declared in this interface + // 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(ot, 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 = ot->derivedFrom != 0; + + for( asUINT j = 0; j < overrideValidations.GetLength(); j++ ) + { + if( !overrideValidations[j] && (!hasBaseClass || !DoesMethodExist(ot->derivedFrom, ot->methods[j])) ) + { + asCString msg; + msg.Format(TXT_METHOD_s_DOES_NOT_OVERRIDE, ot->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]; + asCObjectType *ot = CastToObjectType(decl->typeInfo); + int validState = 1; + for( n = 0; n < ot->properties.GetLength(); n++ ) + { + // A valid structure is one that uses only primitives or other valid objects + asCObjectProperty *prop = ot->properties[n]; + asCDataType dt = prop->type; + + // TODO: Add this check again, once solving the issues commented below + /* + if( dt.IsTemplate() ) + { + // TODO: This must verify all sub types, not just the first one + // TODO: Just because the subtype is not a handle doesn't mean the template will actually instance the object + // this it shouldn't automatically raise an error for this, e.g. weakref should be legal as member + // of the Object class + 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]->typeInfo == dt.GetTypeInfo() ) + { + pdecl = classDeclarations[p]; + break; + } + } + + if( pdecl ) + { + if( pdecl->typeInfo == decl->typeInfo ) + { + 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. + // This must be done in the correct order, so that a class that contains another class isn't needlessly marked + // as garbage collected, just because the contained class was evaluated afterwards. + + // 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. + + asCArray typesToValidate; + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + // Existing shared classes won't need evaluating, nor interfaces + sClassDeclaration *decl = classDeclarations[n]; + if( decl->isExistingShared ) continue; + + asCObjectType *ot = CastToObjectType(decl->typeInfo); + if( ot->IsInterface() ) continue; + + typesToValidate.PushLast(ot); + } + + asUINT numReevaluations = 0; + while( typesToValidate.GetLength() ) + { + if( numReevaluations > typesToValidate.GetLength() ) + { + // No types could be completely evaluated in the last iteration so + // we consider the remaining types in the array as garbage collected + break; + } + + asCObjectType *type = typesToValidate[0]; + typesToValidate.RemoveIndex(0); + + // If the type inherits from another type that is yet to be validated, then reinsert it at the end + if( type->derivedFrom && typesToValidate.Exists(type->derivedFrom) ) + { + typesToValidate.PushLast(type); + numReevaluations++; + continue; + } + + // If the type inherits from a known garbage collected type, then this type must also be garbage collected + if( type->derivedFrom && (type->derivedFrom->flags & asOBJ_GC) ) + { + type->flags |= asOBJ_GC; + continue; + } + + // Evaluate template instances (silently) before verifying each of the classes, since it is possible that + // a class will be marked as non-garbage collected, which in turn will mark the template instance that uses + // it as non-garbage collected, which in turn means the class that contains the array also do not have to be + // garbage collected + EvaluateTemplateInstances(numTempl, true); + + // Is there some path in which this structure is involved in circular references? + // If the type contains a member of a type that is yet to be validated, then reinsert it at the end + bool mustReevaluate = false; + bool gc = false; + for( asUINT p = 0; p < type->properties.GetLength(); p++ ) + { + asCDataType dt = type->properties[p]->type; + + if (dt.IsFuncdef()) + { + // If a class holds a function pointer as member then the class must be garbage collected as the + // function pointer can form circular references with the class through use of a delegate. Example: + // + // class A { B @b; void f(); } + // class B { F @f; } + // funcdef void F(); + // + // A a; + // @a.b = B(); // instance of A refers to instance of B + // @a.b.f = F(a.f); // instance of B refers to delegate that refers to instance of A + // + gc = true; + break; + } + + if( !dt.IsObject() ) + continue; + + if( typesToValidate.Exists(CastToObjectType(dt.GetTypeInfo())) ) + mustReevaluate = true; + else + { + if( dt.IsTemplate() ) + { + // Check if any of the subtypes are yet to be evaluated + bool skip = false; + for( asUINT s = 0; s < dt.GetTypeInfo()->GetSubTypeCount(); s++ ) + { + asCObjectType *t = reinterpret_cast(dt.GetTypeInfo()->GetSubType(s)); + if( typesToValidate.Exists(t) ) + { + mustReevaluate = true; + skip = true; + break; + } + } + if( skip ) + 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 = CastToObjectType(dt.GetTypeInfo()); + + 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 with this + // class. + 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.GetTypeInfo()->flags & (asOBJ_SCRIPT_OBJECT | asOBJ_GC) ) + { + gc = true; + break; + } + } + else if( sdt.GetTypeInfo()->flags & asOBJ_GC ) + { + // TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is. + // Only if the object is of a type that can reference this type, either directly or indirectly + 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 + // TODO: runtime optimize: Just because an application registered class is garbage collected, doesn't mean it + // can form a circular reference with this script class. Perhaps need a flag to tell + // if the script classes that contains the type should be garbage collected or not. + gc = true; + break; + } + } + else if( dt.GetTypeInfo()->flags & asOBJ_GC ) + { + // TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is. + // Only if the object is of a type that can reference this type, either directly or indirectly + gc = true; + break; + } + } + } + + // If the class wasn't found to require garbage collection, but it + // contains another type that has yet to be evaluated then it must be + // re-evaluated. + if( !gc && mustReevaluate ) + { + typesToValidate.PushLast(type); + numReevaluations++; + continue; + } + + // Update the flag in the object type + if( gc ) + type->flags |= asOBJ_GC; + else + type->flags &= ~asOBJ_GC; + + // Reset the counter + numReevaluations = 0; + } } 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->typeInfo->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 = engine->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, CastToObjectType(decl->typeInfo), false, false, mixin->ns, 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; - } + 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->typeInfo->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 = engine->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, CastToObjectType(decl->typeInfo), false, false, mixin->ns, 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->typeInfo->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 = engine->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, isProtected = false; - if( n2 && n2->tokenType == ttPrivate ) - { - isPrivate = true; - n2 = n2->next; - } - else if( n2 && n2->tokenType == ttProtected ) - { - isProtected = true; - n2 = n2->next; - } - - asCScriptCode *file = mixin->script; - asCDataType dt = CreateDataTypeFromNode(n2, file, mixin->ns); - - if( decl->typeInfo->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); - WriteError(msg, file, 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 ) - { - name.Assign(&file->code[n2->tokenPos], n2->tokenLength); - - // Add the property only if it doesn't already exist in the class - bool exists = false; - asCObjectType *ot = CastToObjectType(decl->typeInfo); - for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) - if( ot->properties[p]->name == name ) - { - exists = true; - break; - } - - if( !exists ) - { - if( !decl->isExistingShared ) - { - // It must not conflict with the name of methods - int r = CheckNameConflictMember(ot, name.AddressOf(), n2, file, true, false); - if( r < 0 ) - WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); - - AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, n2); - } - else - { - // Verify that the property exists in the original declaration - bool found = false; - for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) - { - asCObjectProperty *prop = ot->properties[p]; - if( prop->isPrivate == isPrivate && - prop->isProtected == isProtected && - prop->name == name && - prop->type == dt ) - { - found = true; - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->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; - } + 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->typeInfo->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 = engine->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, isProtected = false; + if( n2 && n2->tokenType == ttPrivate ) + { + isPrivate = true; + n2 = n2->next; + } + else if( n2 && n2->tokenType == ttProtected ) + { + isProtected = true; + n2 = n2->next; + } + + asCScriptCode *file = mixin->script; + asCDataType dt = CreateDataTypeFromNode(n2, file, mixin->ns); + + if( decl->typeInfo->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + WriteError(msg, file, 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 ) + { + name.Assign(&file->code[n2->tokenPos], n2->tokenLength); + + // Add the property only if it doesn't already exist in the class + bool exists = false; + asCObjectType *ot = CastToObjectType(decl->typeInfo); + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) + if( ot->properties[p]->name == name ) + { + exists = true; + break; + } + + if( !exists ) + { + if( !decl->isExistingShared ) + { + // It must not conflict with the name of methods + int r = CheckNameConflictMember(ot, name.AddressOf(), n2, file, true, false); + if( r < 0 ) + WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); + + AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, n2); + } + else + { + // Verify that the property exists in the original declaration + bool found = false; + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) + { + asCObjectProperty *prop = ot->properties[p]; + if( prop->isPrivate == isPrivate && + prop->isProtected == isProtected && + prop->name == name && + prop->type == dt ) + { + found = true; + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->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; + asCScriptFunction *vf = asNEW(asCScriptFunction)(engine, module, asFUNC_VIRTUAL); + if( vf == 0 ) + return asOUT_OF_MEMORY; - vf->name = func->name; - vf->nameSpace = func->nameSpace; - vf->returnType = func->returnType; - vf->parameterTypes = func->parameterTypes; - vf->inOutFlags = func->inOutFlags; - vf->id = engine->GetNextScriptFunctionId(); - vf->objectType = func->objectType; - vf->objectType->AddRefInternal(); - vf->signatureId = func->signatureId; - vf->vfTableIdx = idx; - vf->traits = func->traits; + vf->name = func->name; + vf->nameSpace = func->nameSpace; + vf->returnType = func->returnType; + vf->parameterTypes = func->parameterTypes; + vf->inOutFlags = func->inOutFlags; + vf->id = engine->GetNextScriptFunctionId(); + vf->objectType = func->objectType; + vf->objectType->AddRefInternal(); + vf->signatureId = func->signatureId; + vf->vfTableIdx = idx; + vf->traits = func->traits; - // Clear the shared trait since the virtual function should not have that - vf->SetShared(false); + // Clear the shared trait since the virtual function should not have that + vf->SetShared(false); - // It is not necessary to copy the default args, as they have no meaning in the virtual function + // It is not necessary to copy the default args, as they have no meaning in the virtual function - module->AddScriptFunction(vf); + module->AddScriptFunction(vf); - // Add a dummy to the builder so that it doesn't mix up function ids - functions.PushLast(0); + // Add a dummy to the builder so that it doesn't mix up function ids + functions.PushLast(0); - return vf->id; + return vf->id; } asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited, asCScriptCode *file, asCScriptNode *node) { - if( node ) - { - asASSERT(!isInherited); - - // 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(decl->typeInfo->nameSpace).AddressOf()); - else if( dt.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->typeInfo->nameSpace).AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(decl->typeInfo->nameSpace).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); - } - else - { - // If the declaration node is not given, then - // this property is inherited from a base class - asASSERT(isInherited); - } - - // Add the property to the object type - return CastToObjectType(decl->typeInfo)->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); + if( node ) + { + asASSERT(!isInherited); + + // 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(decl->typeInfo->nameSpace).AddressOf()); + else if( dt.IsInterface() ) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->typeInfo->nameSpace).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(decl->typeInfo->nameSpace).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); + } + else + { + // If the declaration node is not given, then + // this property is inherited from a base class + asASSERT(isInherited); + } + + // Add the property to the object type + return CastToObjectType(decl->typeInfo)->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); } bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex) { - asCScriptFunction *method = GetFunctionDescription(methodId); + asCScriptFunction *method = GetFunctionDescription(methodId); - for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) - { - asCScriptFunction *m = GetFunctionDescription(objType->methods[n]); + 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( 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; + if( methodIndex ) + *methodIndex = n; - return true; - } + return true; + } - return false; + 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, false, asSFunctionTraits(), objType->nameSpace); - - // Set it as default constructor - if( objType->beh.construct ) - engine->scriptFunctions[objType->beh.construct]->ReleaseInternal(); - objType->beh.construct = funcId; - objType->beh.constructors[0] = funcId; - engine->scriptFunctions[funcId]->AddRefInternal(); - - // 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]->ReleaseInternal(); - 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]->AddRefInternal(); - - // If the object is shared, then the factory must also be marked as shared - if( objType->flags & asOBJ_SHARED ) - engine->scriptFunctions[funcId]->SetShared(true); + 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, false, asSFunctionTraits(), objType->nameSpace); + + // Set it as default constructor + if( objType->beh.construct ) + engine->scriptFunctions[objType->beh.construct]->ReleaseInternal(); + objType->beh.construct = funcId; + objType->beh.constructors[0] = funcId; + engine->scriptFunctions[funcId]->AddRefInternal(); + + // 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]->ReleaseInternal(); + 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]->AddRefInternal(); + + // If the object is shared, then the factory must also be marked as shared + if( objType->flags & asOBJ_SHARED ) + engine->scriptFunctions[funcId]->SetShared(true); } int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) { - // Is it a shared enum? - bool isShared = false; - bool isExternal = false; - asCEnumType *existingSharedType = 0; - asCScriptNode *tmp = node->firstChild; - while( tmp->nodeType == snIdentifier ) - { - if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, SHARED_TOKEN)) - isShared = true; - else if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, EXTERNAL_TOKEN)) - isExternal = true; - else - break; - tmp = tmp->next; - } - - // 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->sharedScriptTypes.GetLength(); n++ ) - { - asCTypeInfo *o = engine->sharedScriptTypes[n]; - if( o && - o->IsShared() && - (o->flags & asOBJ_ENUM) && - o->name == name && - o->nameSpace == ns ) - { - existingSharedType = CastToEnumType(o); - break; - } - } - } - - // If the enum was declared as external then it must have been compiled in a different module first - if (isExternal && existingSharedType == 0) - { - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); - WriteError(str, file, tmp); - } - - // Remember if the type was declared as external so the saved bytecode can be flagged accordingly - if (isExternal && existingSharedType) - module->m_externalTypes.PushLast(existingSharedType); - - // Check the name and add the enum - int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file, ns, true, false); - if( asSUCCESS == r ) - { - asCEnumType *st; - - if( existingSharedType ) - { - st = existingSharedType; - st->AddRefInternal(); - } - else - { - st = asNEW(asCEnumType)(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->AddEnumType(st); - - if( !existingSharedType && isShared ) - { - engine->sharedScriptTypes.PushLast(st); - st->AddRefInternal(); - } - - // 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->typeInfo = st; - namedTypeDeclarations.PushLast(decl); - - asCDataType type = CreateDataTypeFromNode(tmp, file, ns); - asASSERT(!type.IsReference()); - - // External shared enums must not redeclare the enum values - if (isExternal && (tmp->next == 0 || tmp->next->tokenType != ttEndStatement) ) - { - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); - WriteError(str, file, tmp); - } - else if (!isExternal && tmp->next && tmp->next->tokenType == ttEndStatement) - { - asCString str; - str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); - WriteError(str, file, tmp); - } - - // Register the enum values - tmp = tmp->next; - while( tmp && tmp->nodeType == snIdentifier ) - { - name.Assign(&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( asUINT 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; + // Is it a shared enum? + bool isShared = false; + bool isExternal = false; + asCEnumType *existingSharedType = 0; + asCScriptNode *tmp = node->firstChild; + while( tmp->nodeType == snIdentifier ) + { + if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, SHARED_TOKEN)) + isShared = true; + else if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, EXTERNAL_TOKEN)) + isExternal = true; + else + break; + tmp = tmp->next; + } + + // 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->sharedScriptTypes.GetLength(); n++ ) + { + asCTypeInfo *o = engine->sharedScriptTypes[n]; + if( o && + o->IsShared() && + (o->flags & asOBJ_ENUM) && + o->name == name && + o->nameSpace == ns ) + { + existingSharedType = CastToEnumType(o); + break; + } + } + } + + // If the enum was declared as external then it must have been compiled in a different module first + if (isExternal && existingSharedType == 0) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, tmp); + } + + // Remember if the type was declared as external so the saved bytecode can be flagged accordingly + if (isExternal && existingSharedType) + module->m_externalTypes.PushLast(existingSharedType); + + // Check the name and add the enum + int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file, ns, true, false); + if( asSUCCESS == r ) + { + asCEnumType *st; + + if( existingSharedType ) + { + st = existingSharedType; + st->AddRefInternal(); + } + else + { + st = asNEW(asCEnumType)(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->AddEnumType(st); + + if( !existingSharedType && isShared ) + { + engine->sharedScriptTypes.PushLast(st); + st->AddRefInternal(); + } + + // 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->typeInfo = st; + namedTypeDeclarations.PushLast(decl); + + asCDataType type = CreateDataTypeFromNode(tmp, file, ns); + asASSERT(!type.IsReference()); + + // External shared enums must not redeclare the enum values + if (isExternal && (tmp->next == 0 || tmp->next->tokenType != ttEndStatement) ) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, tmp); + } + else if (!isExternal && tmp->next && tmp->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, tmp); + } + + // Register the enum values + tmp = tmp->next; + while( tmp && tmp->nodeType == snIdentifier ) + { + name.Assign(&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( asUINT 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, true, false); - - asCTypedefType *st = 0; - if( asSUCCESS == r ) - { - // Create the new type - st = asNEW(asCTypedefType)(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->aliasForType = dataType; - st->module = module; - - module->AddTypeDef(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->typeInfo = st; - namedTypeDeclarations.PushLast(decl); - } - } - - node->Destroy(engine); - - return r; + // 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, true, false); + + asCTypedefType *st = 0; + if( asSUCCESS == r ) + { + // Create the new type + st = asNEW(asCTypedefType)(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->aliasForType = dataType; + st->module = module; + + module->AddTypeDef(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->typeInfo = 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, asSFunctionTraits &funcTraits, asSNameSpace *implicitNamespace) { - node = node->firstChild; - - // Is the function shared? - funcTraits.SetTrait(asTRAIT_SHARED, false); - funcTraits.SetTrait(asTRAIT_EXTERNAL, false); - while (node->tokenType == ttIdentifier) - { - if (file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN)) - funcTraits.SetTrait(asTRAIT_SHARED, true); - else if (file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) - funcTraits.SetTrait(asTRAIT_EXTERNAL, true); - else - break; - node = node->next; - } - - // Is the function a private or protected class method? - funcTraits.SetTrait(asTRAIT_PRIVATE, false); - funcTraits.SetTrait(asTRAIT_PROTECTED, false); - if( node->tokenType == ttPrivate ) - { - funcTraits.SetTrait(asTRAIT_PRIVATE, true); - node = node->next; - } - else if( node->tokenType == ttProtected ) - { - funcTraits.SetTrait(asTRAIT_PROTECTED, true); - node = node->next; - } - - // Find the name - funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, false); - funcTraits.SetTrait(asTRAIT_DESTRUCTOR, 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; - funcTraits.SetTrait(asTRAIT_DESTRUCTOR, true); - } - else - { - n = node; - funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, true); - } - } - name.Assign(&file->code[n->tokenPos], n->tokenLength); - - if( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) - { - returnType = CreateDataTypeFromNode(node, file, implicitNamespace, false, objType); - returnType = ModifyDataTypeFromNode(returnType, node->next, file, 0, 0); - - if( engine->ep.disallowValueAssignForRefType && - returnType.GetTypeInfo() && - (returnType.GetTypeInfo()->flags & asOBJ_REF) && - !(returnType.GetTypeInfo()->flags & asOBJ_SCOPED) && - !returnType.IsReference() && - !returnType.IsObjectHandle() ) - { - WriteError(TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL, file, node); - } - } - else - returnType = asCDataType::CreatePrimitive(ttVoid, false); - - funcTraits.SetTrait(asTRAIT_CONST, false); - funcTraits.SetTrait(asTRAIT_FINAL, false); - funcTraits.SetTrait(asTRAIT_OVERRIDE, false); - funcTraits.SetTrait(asTRAIT_EXPLICIT, false); - funcTraits.SetTrait(asTRAIT_PROPERTY, false); - - if( n->next->next ) - { - asCScriptNode *decorator = n->next->next; - - // Is this a const method? - if( objType && decorator->tokenType == ttConst ) - { - funcTraits.SetTrait(asTRAIT_CONST, true); - decorator = decorator->next; - } - - while( decorator && decorator->tokenType == ttIdentifier ) - { - if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, FINAL_TOKEN)) - funcTraits.SetTrait(asTRAIT_FINAL, true); - else if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, OVERRIDE_TOKEN)) - funcTraits.SetTrait(asTRAIT_OVERRIDE, true); - else if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, EXPLICIT_TOKEN)) - funcTraits.SetTrait(asTRAIT_EXPLICIT, true); - else if (file->TokenEquals(decorator->tokenPos, decorator->tokenLength, PROPERTY_TOKEN)) - funcTraits.SetTrait(asTRAIT_PROPERTY, true); - else - { - asCString msg(&file->code[decorator->tokenPos], decorator->tokenLength); - msg.Format(TXT_UNEXPECTED_TOKEN_s, msg.AddressOf()); - WriteError(msg.AddressOf(), file, decorator); - } - - 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, false, objType); - type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0); - - if( engine->ep.disallowValueAssignForRefType && - type.GetTypeInfo() && - (type.GetTypeInfo()->flags & asOBJ_REF) && - !(type.GetTypeInfo()->flags & asOBJ_SCOPED) && - !type.IsReference() && - !type.IsObjectHandle() ) - { - WriteError(TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL, file, node); - } - - // Store the parameter type - parameterTypes.PushLast(type); - inOutFlags.PushLast(inOutFlag); - - // Move to next parameter - n = n->next->next; - if( n && n->nodeType == snIdentifier ) - { - asCString paramName(&file->code[n->tokenPos], n->tokenLength); - parameterNames.PushLast(paramName); - 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); - } + node = node->firstChild; + + // Is the function shared? + funcTraits.SetTrait(asTRAIT_SHARED, false); + funcTraits.SetTrait(asTRAIT_EXTERNAL, false); + while (node->tokenType == ttIdentifier) + { + if (file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN)) + funcTraits.SetTrait(asTRAIT_SHARED, true); + else if (file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) + funcTraits.SetTrait(asTRAIT_EXTERNAL, true); + else + break; + node = node->next; + } + + // Is the function a private or protected class method? + funcTraits.SetTrait(asTRAIT_PRIVATE, false); + funcTraits.SetTrait(asTRAIT_PROTECTED, false); + if( node->tokenType == ttPrivate ) + { + funcTraits.SetTrait(asTRAIT_PRIVATE, true); + node = node->next; + } + else if( node->tokenType == ttProtected ) + { + funcTraits.SetTrait(asTRAIT_PROTECTED, true); + node = node->next; + } + + // Find the name + funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, false); + funcTraits.SetTrait(asTRAIT_DESTRUCTOR, 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; + funcTraits.SetTrait(asTRAIT_DESTRUCTOR, true); + } + else + { + n = node; + funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, true); + } + } + name.Assign(&file->code[n->tokenPos], n->tokenLength); + + if( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) + { + returnType = CreateDataTypeFromNode(node, file, implicitNamespace, false, objType); + returnType = ModifyDataTypeFromNode(returnType, node->next, file, 0, 0); + + if( engine->ep.disallowValueAssignForRefType && + returnType.GetTypeInfo() && + (returnType.GetTypeInfo()->flags & asOBJ_REF) && + !(returnType.GetTypeInfo()->flags & asOBJ_SCOPED) && + !returnType.IsReference() && + !returnType.IsObjectHandle() ) + { + WriteError(TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL, file, node); + } + } + else + returnType = asCDataType::CreatePrimitive(ttVoid, false); + + funcTraits.SetTrait(asTRAIT_CONST, false); + funcTraits.SetTrait(asTRAIT_FINAL, false); + funcTraits.SetTrait(asTRAIT_OVERRIDE, false); + funcTraits.SetTrait(asTRAIT_EXPLICIT, false); + funcTraits.SetTrait(asTRAIT_PROPERTY, false); + + if( n->next->next ) + { + asCScriptNode *decorator = n->next->next; + + // Is this a const method? + if( objType && decorator->tokenType == ttConst ) + { + funcTraits.SetTrait(asTRAIT_CONST, true); + decorator = decorator->next; + } + + while( decorator && decorator->tokenType == ttIdentifier ) + { + if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, FINAL_TOKEN)) + funcTraits.SetTrait(asTRAIT_FINAL, true); + else if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, OVERRIDE_TOKEN)) + funcTraits.SetTrait(asTRAIT_OVERRIDE, true); + else if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, EXPLICIT_TOKEN)) + funcTraits.SetTrait(asTRAIT_EXPLICIT, true); + else if (file->TokenEquals(decorator->tokenPos, decorator->tokenLength, PROPERTY_TOKEN)) + funcTraits.SetTrait(asTRAIT_PROPERTY, true); + else + { + asCString msg(&file->code[decorator->tokenPos], decorator->tokenLength); + msg.Format(TXT_UNEXPECTED_TOKEN_s, msg.AddressOf()); + WriteError(msg.AddressOf(), file, decorator); + } + + 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, false, objType); + type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0); + + if( engine->ep.disallowValueAssignForRefType && + type.GetTypeInfo() && + (type.GetTypeInfo()->flags & asOBJ_REF) && + !(type.GetTypeInfo()->flags & asOBJ_SCOPED) && + !type.IsReference() && + !type.IsObjectHandle() ) + { + WriteError(TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL, file, node); + } + + // Store the parameter type + parameterTypes.PushLast(type); + inOutFlags.PushLast(inOutFlag); + + // Move to next parameter + n = n->next->next; + if( n && n->nodeType == snIdentifier ) + { + asCString paramName(&file->code[n->tokenPos], n->tokenLength); + parameterNames.PushLast(paramName); + 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(); ) - { - asUINT len = 0; - 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; + asASSERT(node && node->nodeType == snExpression); + + asCString str; + str.Assign(file->code + node->tokenPos, node->tokenLength); + + asCString cleanStr; + for( asUINT n = 0; n < str.GetLength(); ) + { + asUINT len = 0; + 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; - asSFunctionTraits funcTraits; - - asASSERT( (objType && ns == 0) || isGlobalFunction || isMixin ); - - // 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, funcTraits, ns); - - return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits); + asCString name; + asCDataType returnType; + asCArray parameterNames; + asCArray parameterTypes; + asCArray inOutFlags; + asCArray defaultArgs; + asSFunctionTraits funcTraits; + + asASSERT( (objType && ns == 0) || isGlobalFunction || isMixin ); + + // 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, funcTraits, ns); + + return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits); } asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns) { - // Get the parameter names from the node - asCArray parameterNames; - asCArray defaultArgs; - asCScriptNode *args = node->firstChild; - while( args && args->nodeType != snStatementBlock ) - { - if (args->nodeType == snIdentifier) - { - asCString argName; - argName.Assign(&file->code[args->tokenPos], args->tokenLength); - parameterNames.PushLast(argName); - defaultArgs.PushLast(0); - } - args = args->next; - } - - // The statement block for the function must be disconnected, as the builder is going to be the owner of it - args->DisconnectParent(); - - // Get the return and parameter types from the funcDef - asCString funcName = name; - int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, asSFunctionTraits()); - if( r < 0 ) - return 0; - - // Return the function that was just created (but that will be compiled later) - return engine->scriptFunctions[functions[functions.GetLength()-1]->funcId]; + // Get the parameter names from the node + asCArray parameterNames; + asCArray defaultArgs; + asCScriptNode *args = node->firstChild; + while( args && args->nodeType != snStatementBlock ) + { + if (args->nodeType == snIdentifier) + { + asCString argName; + argName.Assign(&file->code[args->tokenPos], args->tokenLength); + parameterNames.PushLast(argName); + defaultArgs.PushLast(0); + } + args = args->next; + } + + // The statement block for the function must be disconnected, as the builder is going to be the owner of it + args->DisconnectParent(); + + // Get the return and parameter types from the funcDef + asCString funcName = name; + int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, asSFunctionTraits()); + if( r < 0 ) + return 0; + + // Return the function that was just created (but that will be compiled later) + return engine->scriptFunctions[functions[functions.GetLength()-1]->funcId]; } int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits funcTraits) { - // 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(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) || funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) - { - // 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, funcTraits.GetTrait(asTRAIT_CONST)) ) - { - // Add the shared function in this module too - module->AddScriptFunction(func); - - 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( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) - { - if( objType ) - { - CheckNameConflictMember(objType, name.AddressOf(), node, file, false, false); - - if( name == objType->name ) - WriteError(TXT_METHOD_CANT_HAVE_NAME_OF_CLASS, file, node); - } - else - CheckNameConflict(name.AddressOf(), node, file, ns, false, false); - } - 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 ) - { - asCString str; - if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) - str.Format(TXT_DESTRUCTOR_s_s_NAME_ERROR, objType->name.AddressOf(), name.AddressOf()); - else - str.Format(TXT_METHOD_s_s_HAS_NO_RETURN_TYPE, objType->name.AddressOf(), name.AddressOf()); - WriteError(str, file, node); - } - - if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR)) - name = "~" + name; - } - - // Validate virtual properties signature - if( funcTraits.GetTrait(asTRAIT_PROPERTY) ) - { - asCScriptFunction func(engine, module, asFUNC_SCRIPT); - func.name = name; - func.nameSpace = ns; - func.objectType = objType; - if( objType ) - objType->AddRefInternal(); - func.traits = funcTraits; - func.returnType = returnType; - func.parameterTypes = parameterTypes; - - int r = ValidateVirtualProperty(&func); - if( r < 0 ) - { - asCString str; - if( r == -2 || r == -3 ) - str.Format(TXT_INVALID_SIG_FOR_VIRTPROP); - else if( r == -4 ) - str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.SubString(4).AddressOf()); - else if( r == -5 ) - str.Format(TXT_NAME_CONFLICT_s_ALREADY_USED, name.SubString(4).AddressOf()); - WriteError(str, file, node); - } - - func.funcType = asFUNC_DUMMY; - } - - 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(funcTraits.GetTrait(asTRAIT_SHARED)) - { - // Look for a pre-existing shared function with the same signature - for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) - { - asCScriptFunction *f = engine->scriptFunctions[n]; - if( f && - f->IsShared() && - f->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; - } - } - } - - // Remember if the function was declared as external so the saved bytecode can be flagged accordingly - if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && func->isExistingShared) - module->m_externalFunctions.PushLast(engine->scriptFunctions[func->funcId]); - - if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !func->isExistingShared) - { - // Mark it as existing shared to avoid compiling it - func->isExistingShared = true; - - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); - WriteError(str, file, node); - } - - // External shared function must not try to redefine the interface - if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->tokenType == ttEndStatement || node->lastChild->tokenType == ttEndStatement)) - { - asCString str; - str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); - WriteError(str, file, node); - } - else if (!funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->nodeType == snStatementBlock || node->lastChild->nodeType == snStatementBlock) ) - { - asCString str; - str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); - WriteError(str, file, node); - } - } - - // Destructors may not have any parameters - if (funcTraits.GetTrait(asTRAIT_DESTRUCTOR) && parameterTypes.GetLength() > 0) - WriteError(TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM, file, node); - - // If a function, class, or interface is shared then only shared types may be used in the signature - if( (objType && objType->IsShared()) || funcTraits.GetTrait(asTRAIT_SHARED)) - { - asCTypeInfo *ti = returnType.GetTypeInfo(); - if( ti && !ti->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->name.AddressOf()); - WriteError(msg, file, node); - } - - for( asUINT p = 0; p < parameterTypes.GetLength(); ++p ) - { - ti = parameterTypes[p].GetTypeInfo(); - if( ti && !ti->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->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" || name == "opCast" || name == "opImplCast") && parameterTypes.GetLength() == 0 ) - { - // opConv and opCast 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, funcTraits.GetTrait(asTRAIT_CONST)) ) - { - // 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 *funcDesc = functions.PopLast(); - asDELETE(funcDesc, sFunctionDescription); - - // Free the default args - for( 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, funcTraits.GetTrait(asTRAIT_CONST)) ) - { - if( isMixin ) - { - // Clean up the memory, as the function will not be registered - if( node ) - node->Destroy(engine); - sFunctionDescription *funcDesc = functions.PopLast(); - asDELETE(funcDesc, sFunctionDescription); - - // Free the default args - for( 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->m_globalFunctions.Put(f); - } - 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, isGlobalFunction, funcTraits, 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]->AddRefInternal(); - if(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR)) - { - int factoryId = engine->GetNextScriptFunctionId(); - if( parameterTypes.GetLength() == 0 ) - { - // Overload the default constructor - engine->scriptFunctions[objType->beh.construct]->ReleaseInternal(); - objType->beh.construct = funcId; - objType->beh.constructors[0] = funcId; - - // Register the default factory as well - engine->scriptFunctions[objType->beh.factory]->ReleaseInternal(); - objType->beh.factory = factoryId; - objType->beh.factories[0] = factoryId; - } - else - { - // The copy constructor needs to be marked for easy finding - if( parameterTypes.GetLength() == 1 && - parameterTypes[0].GetTypeInfo() == objType && - (parameterTypes[0].IsReference() || parameterTypes[0].IsObjectHandle()) ) - { - // Verify that there are not multiple options matching the copy constructor - // TODO: Need a better message, since the parameters can be slightly different, e.g. & vs @ - if( objType->beh.copyconstruct ) - WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); - - objType->beh.copyconstruct = funcId; - objType->beh.copyfactory = factoryId; - } - - // Register as a normal constructor - 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, 0, false, funcTraits); - - // If the object is shared, then the factory must also be marked as shared - if( objType->flags & asOBJ_SHARED ) - engine->scriptFunctions[factoryId]->SetShared(true); - - // Add a dummy function to the builder so that it doesn't mix up the fund Ids - functions.PushLast(0); - - // Compile the factory immediately - asCCompiler compiler(engine); - compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]); - engine->scriptFunctions[factoryId]->AddRefInternal(); - } - else if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR)) - objType->beh.destruct = funcId; - else - { - // If the method is the assignment operator we need to replace the default implementation - asCScriptFunction *f = engine->scriptFunctions[funcId]; - if( f->name == "opAssign" && f->parameterTypes.GetLength() == 1 && - f->parameterTypes[0].GetTypeInfo() == f->objectType && - (f->inOutFlags[0] & asTM_INREF) ) - { - engine->scriptFunctions[objType->beh.copy]->ReleaseInternal(); - objType->beh.copy = funcId; - f->AddRefInternal(); - } - - 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; + // 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(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) || funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) + { + // 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, funcTraits.GetTrait(asTRAIT_CONST)) ) + { + // Add the shared function in this module too + module->AddScriptFunction(func); + + 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( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) + { + if( objType ) + { + CheckNameConflictMember(objType, name.AddressOf(), node, file, false, false); + + if( name == objType->name ) + WriteError(TXT_METHOD_CANT_HAVE_NAME_OF_CLASS, file, node); + } + else + CheckNameConflict(name.AddressOf(), node, file, ns, false, false); + } + 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 ) + { + asCString str; + if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) + str.Format(TXT_DESTRUCTOR_s_s_NAME_ERROR, objType->name.AddressOf(), name.AddressOf()); + else + str.Format(TXT_METHOD_s_s_HAS_NO_RETURN_TYPE, objType->name.AddressOf(), name.AddressOf()); + WriteError(str, file, node); + } + + if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR)) + name = "~" + name; + } + + // Validate virtual properties signature + if( funcTraits.GetTrait(asTRAIT_PROPERTY) ) + { + asCScriptFunction func(engine, module, asFUNC_SCRIPT); + func.name = name; + func.nameSpace = ns; + func.objectType = objType; + if( objType ) + objType->AddRefInternal(); + func.traits = funcTraits; + func.returnType = returnType; + func.parameterTypes = parameterTypes; + + int r = ValidateVirtualProperty(&func); + if( r < 0 ) + { + asCString str; + if( r == -2 || r == -3 ) + str.Format(TXT_INVALID_SIG_FOR_VIRTPROP); + else if( r == -4 ) + str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.SubString(4).AddressOf()); + else if( r == -5 ) + str.Format(TXT_NAME_CONFLICT_s_ALREADY_USED, name.SubString(4).AddressOf()); + WriteError(str, file, node); + } + + func.funcType = asFUNC_DUMMY; + } + + 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(funcTraits.GetTrait(asTRAIT_SHARED)) + { + // Look for a pre-existing shared function with the same signature + for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) + { + asCScriptFunction *f = engine->scriptFunctions[n]; + if( f && + f->IsShared() && + f->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; + } + } + } + + // Remember if the function was declared as external so the saved bytecode can be flagged accordingly + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && func->isExistingShared) + module->m_externalFunctions.PushLast(engine->scriptFunctions[func->funcId]); + + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !func->isExistingShared) + { + // Mark it as existing shared to avoid compiling it + func->isExistingShared = true; + + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, node); + } + + // External shared function must not try to redefine the interface + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->tokenType == ttEndStatement || node->lastChild->tokenType == ttEndStatement)) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, node); + } + else if (!funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->nodeType == snStatementBlock || node->lastChild->nodeType == snStatementBlock) ) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, node); + } + } + + // Destructors may not have any parameters + if (funcTraits.GetTrait(asTRAIT_DESTRUCTOR) && parameterTypes.GetLength() > 0) + WriteError(TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM, file, node); + + // If a function, class, or interface is shared then only shared types may be used in the signature + if( (objType && objType->IsShared()) || funcTraits.GetTrait(asTRAIT_SHARED)) + { + asCTypeInfo *ti = returnType.GetTypeInfo(); + if( ti && !ti->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->name.AddressOf()); + WriteError(msg, file, node); + } + + for( asUINT p = 0; p < parameterTypes.GetLength(); ++p ) + { + ti = parameterTypes[p].GetTypeInfo(); + if( ti && !ti->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->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" || name == "opCast" || name == "opImplCast") && parameterTypes.GetLength() == 0 ) + { + // opConv and opCast 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, funcTraits.GetTrait(asTRAIT_CONST)) ) + { + // 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 *funcDesc = functions.PopLast(); + asDELETE(funcDesc, sFunctionDescription); + + // Free the default args + for( 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, funcTraits.GetTrait(asTRAIT_CONST)) ) + { + if( isMixin ) + { + // Clean up the memory, as the function will not be registered + if( node ) + node->Destroy(engine); + sFunctionDescription *funcDesc = functions.PopLast(); + asDELETE(funcDesc, sFunctionDescription); + + // Free the default args + for( 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->m_globalFunctions.Put(f); + } + 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, isGlobalFunction, funcTraits, 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]->AddRefInternal(); + if(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR)) + { + int factoryId = engine->GetNextScriptFunctionId(); + if( parameterTypes.GetLength() == 0 ) + { + // Overload the default constructor + engine->scriptFunctions[objType->beh.construct]->ReleaseInternal(); + objType->beh.construct = funcId; + objType->beh.constructors[0] = funcId; + + // Register the default factory as well + engine->scriptFunctions[objType->beh.factory]->ReleaseInternal(); + objType->beh.factory = factoryId; + objType->beh.factories[0] = factoryId; + } + else + { + // The copy constructor needs to be marked for easy finding + if( parameterTypes.GetLength() == 1 && + parameterTypes[0].GetTypeInfo() == objType && + (parameterTypes[0].IsReference() || parameterTypes[0].IsObjectHandle()) ) + { + // Verify that there are not multiple options matching the copy constructor + // TODO: Need a better message, since the parameters can be slightly different, e.g. & vs @ + if( objType->beh.copyconstruct ) + WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); + + objType->beh.copyconstruct = funcId; + objType->beh.copyfactory = factoryId; + } + + // Register as a normal constructor + 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, 0, false, funcTraits); + + // If the object is shared, then the factory must also be marked as shared + if( objType->flags & asOBJ_SHARED ) + engine->scriptFunctions[factoryId]->SetShared(true); + + // Add a dummy function to the builder so that it doesn't mix up the fund Ids + functions.PushLast(0); + + // Compile the factory immediately + asCCompiler compiler(engine); + compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]); + engine->scriptFunctions[factoryId]->AddRefInternal(); + } + else if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR)) + objType->beh.destruct = funcId; + else + { + // If the method is the assignment operator we need to replace the default implementation + asCScriptFunction *f = engine->scriptFunctions[funcId]; + if( f->name == "opAssign" && f->parameterTypes.GetLength() == 1 && + f->parameterTypes[0].GetTypeInfo() == f->objectType && + (f->inOutFlags[0] & asTM_INREF) ) + { + engine->scriptFunctions[objType->beh.copy]->ReleaseInternal(); + objType->beh.copy = funcId; + f->AddRefInternal(); + } + + 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, isProtected = false; - asCString emulatedName; - asCDataType emulatedType; - - asCScriptNode *mainNode = node; - node = node->firstChild; - - if( !isGlobalFunction && node->tokenType == ttPrivate ) - { - isPrivate = true; - node = node->next; - } - else if( !isGlobalFunction && node->tokenType == ttProtected ) - { - isProtected = 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; - asSFunctionTraits funcTraits; - asCDataType returnType; - asCArray paramNames; - asCArray paramTypes; - asCArray paramModifiers; - asCArray defaultArgs; - asCString name; - - funcTraits.SetTrait(asTRAIT_PRIVATE, isPrivate); - funcTraits.SetTrait(asTRAIT_PROTECTED, isProtected); - funcTraits.SetTrait(asTRAIT_PROPERTY, true); - - if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, GET_TOKEN)) - name = "get_"; - else if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, SET_TOKEN)) - name = "set_"; - else - WriteError(TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE, file, node); - - if (name != "") - { - success = true; - funcNode = node->firstChild->next; - - if (funcNode && funcNode->tokenType == ttConst) - { - funcTraits.SetTrait(asTRAIT_CONST, true); - funcNode = funcNode->next; - } - - while (funcNode && funcNode->nodeType != snStatementBlock) - { - if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN)) - funcTraits.SetTrait(asTRAIT_FINAL, true); - else if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN)) - funcTraits.SetTrait(asTRAIT_OVERRIDE, true); - else - { - asCString msg(&file->code[funcNode->tokenPos], funcNode->tokenLength);; - msg.Format(TXT_UNEXPECTED_TOKEN_s, msg.AddressOf()); - WriteError(msg.AddressOf(), file, node); - } - - 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); - } - - if (name == "get_") - { - // Setup the signature for the get accessor method - returnType = emulatedType; - name = "get_" + emulatedName; - } - else if (name == "set_") - { - // Setup the signature for the set accessor method - returnType = asCDataType::CreatePrimitive(ttVoid, false); - paramModifiers.PushLast(asTM_NONE); - paramNames.PushLast("value"); - paramTypes.PushLast(emulatedType); - defaultArgs.PushLast(0); - name = "set_" + emulatedName; - } - } - - if( success ) - { - if( !isExistingShared ) - RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, funcTraits); - else - { - // Free the funcNode as it won't be used - 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, funcTraits.GetTrait(asTRAIT_CONST)) ) - { - 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; + 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, isProtected = false; + asCString emulatedName; + asCDataType emulatedType; + + asCScriptNode *mainNode = node; + node = node->firstChild; + + if( !isGlobalFunction && node->tokenType == ttPrivate ) + { + isPrivate = true; + node = node->next; + } + else if( !isGlobalFunction && node->tokenType == ttProtected ) + { + isProtected = 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; + asSFunctionTraits funcTraits; + asCDataType returnType; + asCArray paramNames; + asCArray paramTypes; + asCArray paramModifiers; + asCArray defaultArgs; + asCString name; + + funcTraits.SetTrait(asTRAIT_PRIVATE, isPrivate); + funcTraits.SetTrait(asTRAIT_PROTECTED, isProtected); + funcTraits.SetTrait(asTRAIT_PROPERTY, true); + + if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, GET_TOKEN)) + name = "get_"; + else if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, SET_TOKEN)) + name = "set_"; + else + WriteError(TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE, file, node); + + if (name != "") + { + success = true; + funcNode = node->firstChild->next; + + if (funcNode && funcNode->tokenType == ttConst) + { + funcTraits.SetTrait(asTRAIT_CONST, true); + funcNode = funcNode->next; + } + + while (funcNode && funcNode->nodeType != snStatementBlock) + { + if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN)) + funcTraits.SetTrait(asTRAIT_FINAL, true); + else if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN)) + funcTraits.SetTrait(asTRAIT_OVERRIDE, true); + else + { + asCString msg(&file->code[funcNode->tokenPos], funcNode->tokenLength);; + msg.Format(TXT_UNEXPECTED_TOKEN_s, msg.AddressOf()); + WriteError(msg.AddressOf(), file, node); + } + + 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); + } + + if (name == "get_") + { + // Setup the signature for the get accessor method + returnType = emulatedType; + name = "get_" + emulatedName; + } + else if (name == "set_") + { + // Setup the signature for the set accessor method + returnType = asCDataType::CreatePrimitive(ttVoid, false); + paramModifiers.PushLast(asTM_NONE); + paramNames.PushLast("value"); + paramTypes.PushLast(emulatedType); + defaultArgs.PushLast(0); + name = "set_" + emulatedName; + } + } + + if( success ) + { + if( !isExistingShared ) + RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, funcTraits); + else + { + // Free the funcNode as it won't be used + 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, funcTraits.GetTrait(asTRAIT_CONST)) ) + { + 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; - asSFunctionTraits funcTraits; - - if( ns == 0 ) - ns = engine->nameSpaces[0]; - - GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns); - CheckNameConflict(name.AddressOf(), node, file, ns, false, false); - - // 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, funcTraits, ns, moduleName); - - return 0; + asCString name; + asCDataType returnType; + asCArray parameterNames; + asCArray parameterTypes; + asCArray inOutFlags; + asCArray defaultArgs; + asSFunctionTraits funcTraits; + + if( ns == 0 ) + ns = engine->nameSpaces[0]; + + GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns); + CheckNameConflict(name.AddressOf(), node, file, ns, false, false); + + // 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, funcTraits, 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; + // 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->m_globalFunctions.GetIndexes(ns, name); - for( n = 0; n < idxs.GetLength(); n++ ) - { - const asCScriptFunction *f = module->m_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->m_bindInformations.GetLength(); n++ ) - { - if( module->m_bindInformations[n]->importedFunctionSignature->name == name && - module->m_bindInformations[n]->importedFunctionSignature->nameSpace == ns ) - funcs.PushLast(module->m_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->m_accessMask & f->accessMask ) - { - funcs.PushLast(f->id); - } - } + asUINT n; + + // Get the script declared global functions + const asCArray &idxs = module->m_globalFunctions.GetIndexes(ns, name); + for( n = 0; n < idxs.GetLength(); n++ ) + { + const asCScriptFunction *f = module->m_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->m_bindInformations.GetLength(); n++ ) + { + if( module->m_bindInformations[n]->importedFunctionSignature->name == name && + module->m_bindInformations[n]->importedFunctionSignature->nameSpace == ns ) + funcs.PushLast(module->m_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->m_accessMask & f->accessMask ) + { + funcs.PushLast(f->id); + } + } } // scope is only informed when looking for a base class' method void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray &methods, bool objIsConst, const asCString &scope, asCScriptNode *errNode, asCScriptCode *script) { - asASSERT(objectType); - - if( scope != "" ) - { - // If searching with a scope informed, then the node and script must also be informed for potential error reporting - asASSERT( errNode && script ); - - // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace - // TODO: child funcdef: A scope can include a template type, e.g. array - int n = scope.FindLast("::"); - asCString className = n >= 0 ? scope.SubString(n+2) : scope; - asCString nsName = n >= 0 ? scope.SubString(0, n) : ""; - - // If a namespace was specifically defined, then this must be used - asSNameSpace *ns = 0; - if (n >= 0) - { - if (nsName == "") - ns = engine->nameSpaces[0]; - else - ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, 0, false); - - // If the namespace isn't found return silently and let the calling - // function report the error if it cannot resolve the symbol - if (ns == 0) - return; - } - - // Find the base class with the specified scope - while (objectType) - { - // If the name and namespace matches it is the correct class. If no - // specific namespace was given, then don't compare the namespace - if (objectType->name == className && (ns == 0 || objectType->nameSpace == ns)) - break; - - objectType = objectType->derivedFrom; - } - - // If the scope is not any of the base classes, then return no methods - if( objectType == 0 ) - return; - } - - // Find the methods in the object that match the name - // TODO: optimize: Improve linear search - for( asUINT n = 0; n < objectType->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]]; - if( func->name == name && - (!objIsConst || func->IsReadOnly()) && - (func->accessMask & module->m_accessMask) ) - { - // When the scope is defined the returned methods should be the true methods, not the virtual method stubs - if( scope == "" ) - methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id); - else - { - asCScriptFunction *f = engine->scriptFunctions[objectType->methods[n]]; - if( f && f->funcType == asFUNC_VIRTUAL ) - f = objectType->virtualFunctionTable[f->vfTableIdx]; - methods.PushLast(f->id); - } - } - } + asASSERT(objectType); + + if( scope != "" ) + { + // If searching with a scope informed, then the node and script must also be informed for potential error reporting + asASSERT( errNode && script ); + + // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace + // TODO: child funcdef: A scope can include a template type, e.g. array + int n = scope.FindLast("::"); + asCString className = n >= 0 ? scope.SubString(n+2) : scope; + asCString nsName = n >= 0 ? scope.SubString(0, n) : ""; + + // If a namespace was specifically defined, then this must be used + asSNameSpace *ns = 0; + if (n >= 0) + { + if (nsName == "") + ns = engine->nameSpaces[0]; + else + ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, 0, false); + + // If the namespace isn't found return silently and let the calling + // function report the error if it cannot resolve the symbol + if (ns == 0) + return; + } + + // Find the base class with the specified scope + while (objectType) + { + // If the name and namespace matches it is the correct class. If no + // specific namespace was given, then don't compare the namespace + if (objectType->name == className && (ns == 0 || objectType->nameSpace == ns)) + break; + + objectType = objectType->derivedFrom; + } + + // If the scope is not any of the base classes, then return no methods + if( objectType == 0 ) + return; + } + + // Find the methods in the object that match the name + // TODO: optimize: Improve linear search + for( asUINT n = 0; n < objectType->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]]; + if( func->name == name && + (!objIsConst || func->IsReadOnly()) && + (func->accessMask & module->m_accessMask) ) + { + // When the scope is defined the returned methods should be the true methods, not the virtual method stubs + if( scope == "" ) + methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id); + else + { + asCScriptFunction *f = engine->scriptFunctions[objectType->methods[n]]; + if( f && f->funcType == asFUNC_VIRTUAL ) + f = objectType->virtualFunctionTable[f->vfTableIdx]; + methods.PushLast(f->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()); - } + // 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); + int r = 0, c = 0; + if( node ) + file->ConvertPosToRowCol(node->tokenPos, &r, &c); - WriteInfo(file->name, message, r, c, false); + 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); + int r = 0, c = 0; + if( node && file ) + file->ConvertPosToRowCol(node->tokenPos, &r, &c); - WriteError(file ? file->name : asCString(""), message, r, c); + WriteError(file ? file->name : asCString(""), message, r, c); } void asCBuilder::WriteError(const asCString &scriptname, const asCString &message, int r, int c) { - numErrors++; + numErrors++; - if( !silent ) - engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_ERROR, message.AddressOf()); + 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( engine->ep.compilerWarnings ) + { + numWarnings++; - if( !silent ) - engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_WARNING, message.AddressOf()); - } + 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); + int r = 0, c = 0; + if( node && file ) + file->ConvertPosToRowCol(node->tokenPos, &r, &c); - WriteWarning(file ? file->name : asCString(""), message, r, c); + WriteWarning(file ? file->name : asCString(""), message, r, c); } // TODO: child funcdef: Should try to eliminate this function. GetNameSpaceFromNode is more complete asCString asCBuilder::GetScopeFromNode(asCScriptNode *node, asCScriptCode *script, asCScriptNode **next) { - if (node->nodeType != snScope) - { - if (next) - *next = node; - return ""; - } - - asCString scope; - asCScriptNode *sn = node->firstChild; - if( sn->tokenType == ttScope ) - { - scope = "::"; - sn = sn->next; - } - - // TODO: child funcdef: A scope can have a template type as the innermost - while( sn && sn->next && sn->next->tokenType == ttScope ) - { - asCString tmp; - tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength); - if( scope != "" && scope != "::" ) - scope += "::"; - scope += tmp; - sn = sn->next->next; - } - - if( next ) - *next = node->next; - - return scope; + if (node->nodeType != snScope) + { + if (next) + *next = node; + return ""; + } + + asCString scope; + asCScriptNode *sn = node->firstChild; + if( sn->tokenType == ttScope ) + { + scope = "::"; + sn = sn->next; + } + + // TODO: child funcdef: A scope can have a template type as the innermost + while( sn && sn->next && sn->next->tokenType == ttScope ) + { + asCString tmp; + tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength); + if( scope != "" && scope != "::" ) + scope += "::"; + scope += tmp; + sn = sn->next->next; + } + + if( next ) + *next = node->next; + + return scope; } asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next, asCObjectType **objType) { - if (objType) - *objType = 0; - - // If no scope has been informed, then return the implicit namespace - if (node->nodeType != snScope) - { - if (next) - *next = node; - return implicitNs ? implicitNs : engine->nameSpaces[0]; - } - - if (next) - *next = node->next; - - asCString scope; - asCScriptNode *sn = node->firstChild; - if (sn && sn->tokenType == ttScope) - { - scope = "::"; - sn = sn->next; - } - - while (sn) - { - if (sn->next->tokenType == ttScope) - { - asCString tmp; - tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength); - if (scope != "" && scope != "::") - scope += "::"; - scope += tmp; - sn = sn->next->next; - } - else - { - // This is a template type - asASSERT(sn->next->nodeType == snDataType); - - asSNameSpace *ns = implicitNs; - if (scope != "") - ns = engine->FindNameSpace(scope.AddressOf()); - - asCString templateName(&script->code[sn->tokenPos], sn->tokenLength); - asCObjectType *templateType = GetObjectType(templateName.AddressOf(), ns); - if (templateType == 0 || (templateType->flags & asOBJ_TEMPLATE) == 0) - { - // TODO: child funcdef: Report error - return ns; - } - - if (objType) - *objType = GetTemplateInstanceFromNode(sn, script, templateType, implicitNs, 0); - - // Return no namespace, since this is an object type - return 0; - } - } - - asCTypeInfo *ti = 0; - asSNameSpace *ns = GetNameSpaceByString(scope, implicitNs ? implicitNs : engine->nameSpaces[0], node, script, &ti); - if (ti && objType) - *objType = CastToObjectType(ti); - return ns; + if (objType) + *objType = 0; + + // If no scope has been informed, then return the implicit namespace + if (node->nodeType != snScope) + { + if (next) + *next = node; + return implicitNs ? implicitNs : engine->nameSpaces[0]; + } + + if (next) + *next = node->next; + + asCString scope; + asCScriptNode *sn = node->firstChild; + if (sn && sn->tokenType == ttScope) + { + scope = "::"; + sn = sn->next; + } + + while (sn) + { + if (sn->next->tokenType == ttScope) + { + asCString tmp; + tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength); + if (scope != "" && scope != "::") + scope += "::"; + scope += tmp; + sn = sn->next->next; + } + else + { + // This is a template type + asASSERT(sn->next->nodeType == snDataType); + + asSNameSpace *ns = implicitNs; + if (scope != "") + ns = engine->FindNameSpace(scope.AddressOf()); + + asCString templateName(&script->code[sn->tokenPos], sn->tokenLength); + asCObjectType *templateType = GetObjectType(templateName.AddressOf(), ns); + if (templateType == 0 || (templateType->flags & asOBJ_TEMPLATE) == 0) + { + // TODO: child funcdef: Report error + return ns; + } + + if (objType) + *objType = GetTemplateInstanceFromNode(sn, script, templateType, implicitNs, 0); + + // Return no namespace, since this is an object type + return 0; + } + } + + asCTypeInfo *ti = 0; + asSNameSpace *ns = GetNameSpaceByString(scope, implicitNs ? implicitNs : engine->nameSpaces[0], node, script, &ti); + if (ti && objType) + *objType = CastToObjectType(ti); + return ns; } asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType, bool isRequired) { - if( scopeType ) - *scopeType = 0; - - asSNameSpace *ns = implicitNs; - if( nsName == "::" ) - ns = engine->nameSpaces[0]; - else if( nsName != "" ) - { - ns = engine->FindNameSpace(nsName.AddressOf()); - if (ns == 0 && scopeType) - { - asCString typeName; - asCString searchNs; - - // Split the scope with at the inner most :: - int pos = nsName.FindLast("::"); - bool recursive = false; - if (pos >= 0) - { - // Fully qualified namespace - typeName = nsName.SubString(pos + 2); - searchNs = nsName.SubString(0, pos); - } - else - { - // Partially qualified, use the implicit namespace and then search recursively for the type - typeName = nsName; - searchNs = implicitNs->name; - recursive = true; - } - - asSNameSpace *nsTmp = searchNs == "::" ? engine->nameSpaces[0] : engine->FindNameSpace(searchNs.AddressOf()); - asCTypeInfo *ti = 0; - while( !ti && nsTmp ) - { - // Check if the typeName is an existing type in the namespace - ti = GetType(typeName.AddressOf(), nsTmp, 0); - if (ti) - { - // The informed scope is not a namespace, but it does match a type - *scopeType = ti; - return 0; - } - nsTmp = recursive ? engine->GetParentNameSpace(nsTmp) : 0; - } - } - - if (ns == 0 && isRequired) - { - asCString msg; - msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, nsName.AddressOf()); - WriteError(msg, script, errNode); - } - } - - return ns; + if( scopeType ) + *scopeType = 0; + + asSNameSpace *ns = implicitNs; + if( nsName == "::" ) + ns = engine->nameSpaces[0]; + else if( nsName != "" ) + { + ns = engine->FindNameSpace(nsName.AddressOf()); + if (ns == 0 && scopeType) + { + asCString typeName; + asCString searchNs; + + // Split the scope with at the inner most :: + int pos = nsName.FindLast("::"); + bool recursive = false; + if (pos >= 0) + { + // Fully qualified namespace + typeName = nsName.SubString(pos + 2); + searchNs = nsName.SubString(0, pos); + } + else + { + // Partially qualified, use the implicit namespace and then search recursively for the type + typeName = nsName; + searchNs = implicitNs->name; + recursive = true; + } + + asSNameSpace *nsTmp = searchNs == "::" ? engine->nameSpaces[0] : engine->FindNameSpace(searchNs.AddressOf()); + asCTypeInfo *ti = 0; + while( !ti && nsTmp ) + { + // Check if the typeName is an existing type in the namespace + ti = GetType(typeName.AddressOf(), nsTmp, 0); + if (ti) + { + // The informed scope is not a namespace, but it does match a type + *scopeType = ti; + return 0; + } + nsTmp = recursive ? engine->GetParentNameSpace(nsTmp) : 0; + } + } + + if (ns == 0 && isRequired) + { + asCString msg; + msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, nsName.AddressOf()); + WriteError(msg, script, errNode); + } + } + + return ns; } asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope, asCObjectType *currentType, bool reportError, bool *isValid) { - asASSERT(node->nodeType == snDataType || node->nodeType == snIdentifier || node->nodeType == snScope ); - - asCDataType dt; - - asCScriptNode *n = node->firstChild; - - if (isValid) - *isValid = true; - - // If the informed node is an identifier or scope, then the - // datatype should be identified directly from that - if (node->nodeType != snDataType) - n = node; - - bool isConst = false; - bool isImplicitHandle = false; - if( n->tokenType == ttConst ) - { - isConst = true; - n = n->next; - } - - // Determine namespace (or parent type) to search for the data type in - asCObjectType *parentType = 0; - asSNameSpace *ns = GetNameSpaceFromNode(n, file, implicitNamespace, &n, &parentType); - if( ns == 0 && parentType == 0 ) - { - // The namespace and parent type doesn't exist. Return a dummy type instead. - dt = asCDataType::CreatePrimitive(ttInt, false); - if (isValid) - *isValid = false; - return dt; - } - - if( n->tokenType == ttIdentifier ) - { - bool found = false; - - asCString str; - str.Assign(&file->code[n->tokenPos], n->tokenLength); - - // Recursively search parent namespaces for matching type - asSNameSpace *origNs = ns; - asCObjectType *origParentType = parentType; - while( (ns || parentType) && !found ) - { - asCTypeInfo *ti = 0; - - if (currentType) - { - // If this is for a template type, then we must first determine if the - // identifier matches any of the template subtypes - if (currentType->flags & asOBJ_TEMPLATE) - { - for (asUINT subtypeIndex = 0; subtypeIndex < currentType->templateSubTypes.GetLength(); subtypeIndex++) - { - asCTypeInfo *type = currentType->templateSubTypes[subtypeIndex].GetTypeInfo(); - if (type && str == type->name) - { - ti = type; - break; - } - } - } - - if (ti == 0) - { - // Check if the type is a child type of the current type - ti = GetFuncDef(str.AddressOf(), 0, currentType); - if (ti) - { - dt = asCDataType::CreateType(ti, false); - found = true; - } - } - } - - if( ti == 0 ) - ti = GetType(str.AddressOf(), ns, parentType); - if( ti == 0 && !module && currentType ) - ti = GetTypeFromTypesKnownByObject(str.AddressOf(), currentType); - - if( ti && !found ) - { - found = true; - - if( ti->flags & asOBJ_IMPLICIT_HANDLE ) - isImplicitHandle = true; - - // Make sure the module has access to the object type - if( !module || (module->m_accessMask & ti->accessMask) ) - { - if( asOBJ_TYPEDEF == (ti->flags & asOBJ_TYPEDEF) ) - { - // TODO: typedef: A typedef should be considered different from the original type (though with implicit conversions between the two) - // Create primitive data type based on object flags - dt = CastToTypedefType(ti)->aliasForType; - dt.MakeReadOnly(isConst); - } - else - { - if( ti->flags & asOBJ_TEMPLATE ) - { - ti = GetTemplateInstanceFromNode(n, file, CastToObjectType(ti), implicitNamespace, currentType, &n); - if (ti == 0) - { - if (isValid) - *isValid = false; - - // Return a dummy - return asCDataType::CreatePrimitive(ttInt, false); - } - } - else if( n && n->next && n->next->nodeType == snDataType ) - { - if (reportError) - { - asCString msg; - msg.Format(TXT_TYPE_s_NOT_TEMPLATE, ti->name.AddressOf()); - WriteError(msg, file, n); - } - if (isValid) - *isValid = false; - } - - // Create object data type - if( ti ) - dt = asCDataType::CreateType(ti, isConst); - else - dt = asCDataType::CreatePrimitive(ttInt, isConst); - } - } - else - { - if (reportError) - { - asCString msg; - msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf()); - WriteError(msg, file, n); - } - - dt.SetTokenType(ttInt); - if (isValid) - *isValid = false; - } - } - - if( !found ) - { - // Try to find it in the parent namespace - if( ns ) - ns = engine->GetParentNameSpace(ns); - if (parentType) - parentType = 0; - } - } - - if( !found ) - { - if (reportError) - { - asCString msg; - if (origNs && origNs->name == "") - msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, str.AddressOf()); - else if (origNs) - msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), origNs->name.AddressOf()); - else - { - // TODO: child funcdef: Message should explain that the identifier is not a type of the parent type - asCDataType pt = asCDataType::CreateType(origParentType, false); - msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), pt.Format(origParentType->nameSpace, false).AddressOf()); - } - WriteError(msg, file, n); - } - - dt = asCDataType::CreatePrimitive(ttInt, isConst); - if (isValid) - *isValid = false; - return dt; - } - } - 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() ) - { - if (reportError) - { - asCString str; - if (dt.IsAbstractClass()) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); - else if (dt.IsInterface()) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(ns).AddressOf()); - - WriteError(str, file, n); - } - if (isValid) - *isValid = false; - } - - // Make the type an array (or multidimensional array) - if( dt.MakeArray(engine, module) < 0 ) - { - if( reportError ) - WriteError(TXT_NO_DEFAULT_ARRAY_TYPE, file, n); - if (isValid) - *isValid = false; - break; - } - } - else - { - // Make the type a handle - if( dt.IsObjectHandle() ) - { - if( reportError ) - WriteError(TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED, file, n); - if (isValid) - *isValid = false; - break; - } - else - { - if( dt.MakeHandle(true, acceptHandleForScope) < 0 ) - { - if( reportError ) - WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); - if (isValid) - *isValid = false; - break; - } - - // Check if the handle should be read-only - if( n && n->next && n->next->tokenType == ttConst ) - dt.MakeReadOnly(true); - } - } - n = n->next; - } - - if( isImplicitHandle ) - { - // Make the type a handle - if (dt.MakeHandle(true, acceptHandleForScope) < 0) - { - if( reportError ) - WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); - if (isValid) - *isValid = false; - } - } - - return dt; + asASSERT(node->nodeType == snDataType || node->nodeType == snIdentifier || node->nodeType == snScope ); + + asCDataType dt; + + asCScriptNode *n = node->firstChild; + + if (isValid) + *isValid = true; + + // If the informed node is an identifier or scope, then the + // datatype should be identified directly from that + if (node->nodeType != snDataType) + n = node; + + bool isConst = false; + bool isImplicitHandle = false; + if( n->tokenType == ttConst ) + { + isConst = true; + n = n->next; + } + + // Determine namespace (or parent type) to search for the data type in + asCObjectType *parentType = 0; + asSNameSpace *ns = GetNameSpaceFromNode(n, file, implicitNamespace, &n, &parentType); + if( ns == 0 && parentType == 0 ) + { + // The namespace and parent type doesn't exist. Return a dummy type instead. + dt = asCDataType::CreatePrimitive(ttInt, false); + if (isValid) + *isValid = false; + return dt; + } + + if( n->tokenType == ttIdentifier ) + { + bool found = false; + + asCString str; + str.Assign(&file->code[n->tokenPos], n->tokenLength); + + // Recursively search parent namespaces for matching type + asSNameSpace *origNs = ns; + asCObjectType *origParentType = parentType; + while( (ns || parentType) && !found ) + { + asCTypeInfo *ti = 0; + + if (currentType) + { + // If this is for a template type, then we must first determine if the + // identifier matches any of the template subtypes + if (currentType->flags & asOBJ_TEMPLATE) + { + for (asUINT subtypeIndex = 0; subtypeIndex < currentType->templateSubTypes.GetLength(); subtypeIndex++) + { + asCTypeInfo *type = currentType->templateSubTypes[subtypeIndex].GetTypeInfo(); + if (type && str == type->name) + { + ti = type; + break; + } + } + } + + if (ti == 0) + { + // Check if the type is a child type of the current type + ti = GetFuncDef(str.AddressOf(), 0, currentType); + if (ti) + { + dt = asCDataType::CreateType(ti, false); + found = true; + } + } + } + + if( ti == 0 ) + ti = GetType(str.AddressOf(), ns, parentType); + if( ti == 0 && !module && currentType ) + ti = GetTypeFromTypesKnownByObject(str.AddressOf(), currentType); + + if( ti && !found ) + { + found = true; + + if( ti->flags & asOBJ_IMPLICIT_HANDLE ) + isImplicitHandle = true; + + // Make sure the module has access to the object type + if( !module || (module->m_accessMask & ti->accessMask) ) + { + if( asOBJ_TYPEDEF == (ti->flags & asOBJ_TYPEDEF) ) + { + // TODO: typedef: A typedef should be considered different from the original type (though with implicit conversions between the two) + // Create primitive data type based on object flags + dt = CastToTypedefType(ti)->aliasForType; + dt.MakeReadOnly(isConst); + } + else + { + if( ti->flags & asOBJ_TEMPLATE ) + { + ti = GetTemplateInstanceFromNode(n, file, CastToObjectType(ti), implicitNamespace, currentType, &n); + if (ti == 0) + { + if (isValid) + *isValid = false; + + // Return a dummy + return asCDataType::CreatePrimitive(ttInt, false); + } + } + else if( n && n->next && n->next->nodeType == snDataType ) + { + if (reportError) + { + asCString msg; + msg.Format(TXT_TYPE_s_NOT_TEMPLATE, ti->name.AddressOf()); + WriteError(msg, file, n); + } + if (isValid) + *isValid = false; + } + + // Create object data type + if( ti ) + dt = asCDataType::CreateType(ti, isConst); + else + dt = asCDataType::CreatePrimitive(ttInt, isConst); + } + } + else + { + if (reportError) + { + asCString msg; + msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf()); + WriteError(msg, file, n); + } + + dt.SetTokenType(ttInt); + if (isValid) + *isValid = false; + } + } + + if( !found ) + { + // Try to find it in the parent namespace + if( ns ) + ns = engine->GetParentNameSpace(ns); + if (parentType) + parentType = 0; + } + } + + if( !found ) + { + if (reportError) + { + asCString msg; + if (origNs && origNs->name == "") + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, str.AddressOf()); + else if (origNs) + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), origNs->name.AddressOf()); + else + { + // TODO: child funcdef: Message should explain that the identifier is not a type of the parent type + asCDataType pt = asCDataType::CreateType(origParentType, false); + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), pt.Format(origParentType->nameSpace, false).AddressOf()); + } + WriteError(msg, file, n); + } + + dt = asCDataType::CreatePrimitive(ttInt, isConst); + if (isValid) + *isValid = false; + return dt; + } + } + 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() ) + { + if (reportError) + { + asCString str; + if (dt.IsAbstractClass()) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); + else if (dt.IsInterface()) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(ns).AddressOf()); + + WriteError(str, file, n); + } + if (isValid) + *isValid = false; + } + + // Make the type an array (or multidimensional array) + if( dt.MakeArray(engine, module) < 0 ) + { + if( reportError ) + WriteError(TXT_NO_DEFAULT_ARRAY_TYPE, file, n); + if (isValid) + *isValid = false; + break; + } + } + else + { + // Make the type a handle + if( dt.IsObjectHandle() ) + { + if( reportError ) + WriteError(TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED, file, n); + if (isValid) + *isValid = false; + break; + } + else + { + if( dt.MakeHandle(true, acceptHandleForScope) < 0 ) + { + if( reportError ) + WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if (isValid) + *isValid = false; + break; + } + + // Check if the handle should be read-only + if( n && n->next && n->next->tokenType == ttConst ) + dt.MakeReadOnly(true); + } + } + n = n->next; + } + + if( isImplicitHandle ) + { + // Make the type a handle + if (dt.MakeHandle(true, acceptHandleForScope) < 0) + { + if( reportError ) + WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if (isValid) + *isValid = false; + } + } + + return dt; } asCObjectType *asCBuilder::GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next) { - // Check if the subtype is a type or the template's subtype - // if it is the template's subtype then this is the actual template type, - // orderwise it is a template instance. - // Only do this for application registered interface, as the - // scripts cannot implement templates. - asCArray subTypes; - asUINT subtypeIndex; - asCScriptNode *n = node; - while (n && n->next && n->next->nodeType == snDataType) - { - n = n->next; - - // When parsing function definitions for template registrations (currentType != 0) it is necessary - // to pass in the current template type to the recursive call since it is this ones sub-template types - // that should be allowed. - asCDataType subType = CreateDataTypeFromNode(n, file, implicitNamespace, false, module ? 0 : (currentType ? currentType : templateType)); - subTypes.PushLast(subType); - - if (subType.IsReadOnly()) - { - asCString msg; - msg.Format(TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY); - WriteError(msg, file, n); - - // Return a dummy - return 0; - } - } - - if (next) - *next = n; - - if (subTypes.GetLength() != templateType->templateSubTypes.GetLength()) - { - asCString msg; - msg.Format(TXT_TMPL_s_EXPECTS_d_SUBTYPES, templateType->name.AddressOf(), int(templateType->templateSubTypes.GetLength())); - WriteError(msg, file, node); - - // Return a dummy - return 0; - } - - // Check if any of the given subtypes are different from the template's declared subtypes - bool isDifferent = false; - for (subtypeIndex = 0; subtypeIndex < subTypes.GetLength(); subtypeIndex++) - { - if (subTypes[subtypeIndex].GetTypeInfo() != templateType->templateSubTypes[subtypeIndex].GetTypeInfo()) - { - isDifferent = true; - break; - } - } - - if (isDifferent) - { - // This is a template instance - // Need to find the correct object type - asCObjectType *otInstance = engine->GetTemplateInstanceType(templateType, subTypes, module); - - if (otInstance && otInstance->scriptSectionIdx < 0) - { - // If this is the first time the template instance is used, store where it was declared from - otInstance->scriptSectionIdx = engine->GetScriptSectionNameIndex(file->name.AddressOf()); - int row, column; - file->ConvertPosToRowCol(n->tokenPos, &row, &column); - otInstance->declaredAt = (row & 0xFFFFF) | (column << 20); - } - - if (!otInstance) - { - asCString sub = subTypes[0].Format(templateType->nameSpace); - for (asUINT s = 1; s < subTypes.GetLength(); s++) - { - sub += ","; - sub += subTypes[s].Format(templateType->nameSpace); - } - asCString msg; - msg.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, templateType->name.AddressOf(), sub.AddressOf()); - WriteError(msg, file, n); - } - - return otInstance; - } - - return templateType; + // Check if the subtype is a type or the template's subtype + // if it is the template's subtype then this is the actual template type, + // orderwise it is a template instance. + // Only do this for application registered interface, as the + // scripts cannot implement templates. + asCArray subTypes; + asUINT subtypeIndex; + asCScriptNode *n = node; + while (n && n->next && n->next->nodeType == snDataType) + { + n = n->next; + + // When parsing function definitions for template registrations (currentType != 0) it is necessary + // to pass in the current template type to the recursive call since it is this ones sub-template types + // that should be allowed. + asCDataType subType = CreateDataTypeFromNode(n, file, implicitNamespace, false, module ? 0 : (currentType ? currentType : templateType)); + subTypes.PushLast(subType); + + if (subType.IsReadOnly()) + { + asCString msg; + msg.Format(TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY); + WriteError(msg, file, n); + + // Return a dummy + return 0; + } + } + + if (next) + *next = n; + + if (subTypes.GetLength() != templateType->templateSubTypes.GetLength()) + { + asCString msg; + msg.Format(TXT_TMPL_s_EXPECTS_d_SUBTYPES, templateType->name.AddressOf(), int(templateType->templateSubTypes.GetLength())); + WriteError(msg, file, node); + + // Return a dummy + return 0; + } + + // Check if any of the given subtypes are different from the template's declared subtypes + bool isDifferent = false; + for (subtypeIndex = 0; subtypeIndex < subTypes.GetLength(); subtypeIndex++) + { + if (subTypes[subtypeIndex].GetTypeInfo() != templateType->templateSubTypes[subtypeIndex].GetTypeInfo()) + { + isDifferent = true; + break; + } + } + + if (isDifferent) + { + // This is a template instance + // Need to find the correct object type + asCObjectType *otInstance = engine->GetTemplateInstanceType(templateType, subTypes, module); + + if (otInstance && otInstance->scriptSectionIdx < 0) + { + // If this is the first time the template instance is used, store where it was declared from + otInstance->scriptSectionIdx = engine->GetScriptSectionNameIndex(file->name.AddressOf()); + int row, column; + file->ConvertPosToRowCol(n->tokenPos, &row, &column); + otInstance->declaredAt = (row & 0xFFFFF) | (column << 20); + } + + if (!otInstance) + { + asCString sub = subTypes[0].Format(templateType->nameSpace); + for (asUINT s = 1; s < subTypes.GetLength(); s++) + { + sub += ","; + sub += subTypes[s].Format(templateType->nameSpace); + } + asCString msg; + msg.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, templateType->name.AddressOf(), sub.AddressOf()); + WriteError(msg, file, n); + } + + return otInstance; + } + + return templateType; } asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlags, bool *autoHandle) { - asCDataType dt = type; - - if( inOutFlags ) *inOutFlags = asTM_NONE; - - // Is the argument sent by reference? - asCScriptNode *n = node->firstChild; - if( n && n->tokenType == ttAmp ) - { - if (dt.GetTokenType() == ttVoid) - { - asCString msg; - msg.Format(TXT_TYPE_s_CANNOT_BE_REFERENCE, type.Format(0).AddressOf()); - WriteError(msg, file, node->firstChild); - return dt; - } - - dt.MakeReference(true); - n = n->next; - - 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 && - !(dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) - { - // Verify that the base type support &inout parameter types - if( !dt.IsObject() || dt.IsObjectHandle() || - !((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || (CastToObjectType(dt.GetTypeInfo())->beh.addref && CastToObjectType(dt.GetTypeInfo())->beh.release)) ) - WriteError(TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, file, node->firstChild); - } - } - - 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.GetTypeInfo()->flags & asOBJ_NOCOUNT) ) - WriteError(TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT, file, node->firstChild); - - if( autoHandle ) *autoHandle = true; - } - - if (n && n->tokenType == ttIdentifier) - { - asCString str; - str.Assign(&file->code[n->tokenPos], n->tokenLength); - if (str == IF_HANDLE_TOKEN) - dt.SetIfHandleThenConst(true); - else - { - // TODO: Should give error if not currently parsing template registration - asCString msg; - msg.Format(TXT_UNEXPECTED_TOKEN_s, str.AddressOf()); - WriteError(msg, file, node->firstChild); - } - } - - return dt; + asCDataType dt = type; + + if( inOutFlags ) *inOutFlags = asTM_NONE; + + // Is the argument sent by reference? + asCScriptNode *n = node->firstChild; + if( n && n->tokenType == ttAmp ) + { + if (dt.GetTokenType() == ttVoid) + { + asCString msg; + msg.Format(TXT_TYPE_s_CANNOT_BE_REFERENCE, type.Format(0).AddressOf()); + WriteError(msg, file, node->firstChild); + return dt; + } + + dt.MakeReference(true); + n = n->next; + + 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 && + !(dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) + { + // Verify that the base type support &inout parameter types + if( !dt.IsObject() || dt.IsObjectHandle() || + !((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || (CastToObjectType(dt.GetTypeInfo())->beh.addref && CastToObjectType(dt.GetTypeInfo())->beh.release)) ) + WriteError(TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, file, node->firstChild); + } + } + + 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.GetTypeInfo()->flags & asOBJ_NOCOUNT) ) + WriteError(TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT, file, node->firstChild); + + if( autoHandle ) *autoHandle = true; + } + + if (n && n->tokenType == ttIdentifier) + { + asCString str; + str.Assign(&file->code[n->tokenPos], n->tokenLength); + if (str == IF_HANDLE_TOKEN) + dt.SetIfHandleThenConst(true); + else + { + // TODO: Should give error if not currently parsing template registration + asCString msg; + msg.Format(TXT_UNEXPECTED_TOKEN_s, str.AddressOf()); + WriteError(msg, file, node->firstChild); + } + } + + return dt; } asCTypeInfo *asCBuilder::GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType) { - asASSERT((ns == 0 && parentType) || (ns && parentType == 0)); - - if (ns) - { - asCTypeInfo *ti = engine->GetRegisteredType(type, ns); - if (!ti && module) - ti = module->GetType(type, ns); - return ti; - } - else - { - // Recursively check base classes - asCObjectType *currType = parentType; - while (currType) - { - for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++) - { - asCFuncdefType *funcDef = currType->childFuncDefs[n]; - if (funcDef && funcDef->name == type) - return funcDef; - } - currType = currType->derivedFrom; - } - } - - return 0; + asASSERT((ns == 0 && parentType) || (ns && parentType == 0)); + + if (ns) + { + asCTypeInfo *ti = engine->GetRegisteredType(type, ns); + if (!ti && module) + ti = module->GetType(type, ns); + return ti; + } + else + { + // Recursively check base classes + asCObjectType *currType = parentType; + while (currType) + { + for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = currType->childFuncDefs[n]; + if (funcDef && funcDef->name == type) + return funcDef; + } + currType = currType->derivedFrom; + } + } + + return 0; } asCObjectType *asCBuilder::GetObjectType(const char *type, asSNameSpace *ns) { - return CastToObjectType(GetType(type, ns, 0)); + return CastToObjectType(GetType(type, ns, 0)); } #ifndef AS_NO_COMPILER @@ -6243,207 +6243,207 @@ asCObjectType *asCBuilder::GetObjectType(const char *type, asSNameSpace *ns) // 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 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); - } - - if (module) - { - // Add script classes and interfaces - for (n = 0; n < module->m_classTypes.GetLength(); n++) - if (!knownTypes.MoveTo(0, module->m_classTypes[n]->name)) - knownTypes.Insert(module->m_classTypes[n]->name, true); - - // Add script enums - for (n = 0; n < module->m_enumTypes.GetLength(); n++) - if (!knownTypes.MoveTo(0, module->m_enumTypes[n]->name)) - knownTypes.Insert(module->m_enumTypes[n]->name, true); - - // Add script typedefs - for (n = 0; n < module->m_typeDefs.GetLength(); n++) - if (!knownTypes.MoveTo(0, module->m_typeDefs[n]->name)) - knownTypes.Insert(module->m_typeDefs[n]->name, true); - - // Add script funcdefs - for (n = 0; n < module->m_funcDefs.GetLength(); n++) - if (!knownTypes.MoveTo(0, module->m_funcDefs[n]->name)) - knownTypes.Insert(module->m_funcDefs[n]->name, true); - } - } - - // Check if the type is known - return knownTypes.MoveTo(0, 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 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); + } + + if (module) + { + // Add script classes and interfaces + for (n = 0; n < module->m_classTypes.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->m_classTypes[n]->name)) + knownTypes.Insert(module->m_classTypes[n]->name, true); + + // Add script enums + for (n = 0; n < module->m_enumTypes.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->m_enumTypes[n]->name)) + knownTypes.Insert(module->m_enumTypes[n]->name, true); + + // Add script typedefs + for (n = 0; n < module->m_typeDefs.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->m_typeDefs[n]->name)) + knownTypes.Insert(module->m_typeDefs[n]->name, true); + + // Add script funcdefs + for (n = 0; n < module->m_funcDefs.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->m_funcDefs[n]->name)) + knownTypes.Insert(module->m_funcDefs[n]->name, true); + } + } + + // Check if the type is known + return knownTypes.MoveTo(0, type); } #endif asCTypeInfo *asCBuilder::GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType) { - if (currentType->name == type) - return currentType; - - asUINT n; - - asCTypeInfo *found = 0; - - for (n = 0; found == 0 && n < currentType->properties.GetLength(); n++) - if (currentType->properties[n]->type.GetTypeInfo() && - currentType->properties[n]->type.GetTypeInfo()->name == type) - found = currentType->properties[n]->type.GetTypeInfo(); - - for (n = 0; found == 0 && n < currentType->methods.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[currentType->methods[n]]; - if (func->returnType.GetTypeInfo() && - func->returnType.GetTypeInfo()->name == type) - found = func->returnType.GetTypeInfo(); - - for (asUINT f = 0; found == 0 && f < func->parameterTypes.GetLength(); f++) - if (func->parameterTypes[f].GetTypeInfo() && - func->parameterTypes[f].GetTypeInfo()->name == type) - found = func->parameterTypes[f].GetTypeInfo(); - } - - if (found) - { - // 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; + if (currentType->name == type) + return currentType; + + asUINT n; + + asCTypeInfo *found = 0; + + for (n = 0; found == 0 && n < currentType->properties.GetLength(); n++) + if (currentType->properties[n]->type.GetTypeInfo() && + currentType->properties[n]->type.GetTypeInfo()->name == type) + found = currentType->properties[n]->type.GetTypeInfo(); + + for (n = 0; found == 0 && n < currentType->methods.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[currentType->methods[n]]; + if (func->returnType.GetTypeInfo() && + func->returnType.GetTypeInfo()->name == type) + found = func->returnType.GetTypeInfo(); + + for (asUINT f = 0; found == 0 && f < func->parameterTypes.GetLength(); f++) + if (func->parameterTypes[f].GetTypeInfo() && + func->parameterTypes[f].GetTypeInfo()->name == type) + found = func->parameterTypes[f].GetTypeInfo(); + } + + if (found) + { + // 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; } asCFuncdefType *asCBuilder::GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType) { - asASSERT((ns == 0 && parentType) || (ns && parentType == 0)); - - if (ns) - { - for (asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++) - { - asCFuncdefType *funcDef = engine->registeredFuncDefs[n]; - // TODO: access: Only return the definitions that the module has access to - if (funcDef && funcDef->nameSpace == ns && funcDef->name == type) - return funcDef; - } - - if (module) - { - for (asUINT n = 0; n < module->m_funcDefs.GetLength(); n++) - { - asCFuncdefType *funcDef = module->m_funcDefs[n]; - if (funcDef && funcDef->nameSpace == ns && funcDef->name == type) - return funcDef; - } - } - } - else - { - // Recursively check base classes - asCObjectType *currType = parentType; - while (currType) - { - for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++) - { - asCFuncdefType *funcDef = currType->childFuncDefs[n]; - if (funcDef && funcDef->name == type) - return funcDef; - } - currType = currType->derivedFrom; - } - } - - return 0; + asASSERT((ns == 0 && parentType) || (ns && parentType == 0)); + + if (ns) + { + for (asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = engine->registeredFuncDefs[n]; + // TODO: access: Only return the definitions that the module has access to + if (funcDef && funcDef->nameSpace == ns && funcDef->name == type) + return funcDef; + } + + if (module) + { + for (asUINT n = 0; n < module->m_funcDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = module->m_funcDefs[n]; + if (funcDef && funcDef->nameSpace == ns && funcDef->name == type) + return funcDef; + } + } + } + else + { + // Recursively check base classes + asCObjectType *currType = parentType; + while (currType) + { + for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = currType->childFuncDefs[n]; + if (funcDef && funcDef->name == type) + return funcDef; + } + currType = currType->derivedFrom; + } + } + + return 0; } #ifndef AS_NO_COMPILER int asCBuilder::GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue) { - if( !type || !(type->flags & asOBJ_ENUM) ) - return 0; - - for( asUINT n = 0; n < type->enumValues.GetLength(); ++n ) - { - if( type->enumValues[n]->name == name ) - { - outDt = asCDataType::CreateType(type, true); - outValue = type->enumValues[n]->value; - return 1; - } - } - - return 0; + if( !type || !(type->flags & asOBJ_ENUM) ) + return 0; + + for( asUINT n = 0; n < type->enumValues.GetLength(); ++n ) + { + if( type->enumValues[n]->name == name ) + { + outDt = asCDataType::CreateType(type, true); + outValue = type->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++ ) - { - asCEnumType *et = engine->registeredEnums[t]; - if( ns != et->nameSpace ) continue; - - // Don't bother with types the module doesn't have access to - if( (et->accessMask & module->m_accessMask) == 0 ) - continue; - - if( GetEnumValueFromType(et, name, outDt, outValue) ) - { - if( !found ) - found = true; - else - { - // Found more than one value in different enum types - return 2; - } - } - } - - for( t = 0; t < module->m_enumTypes.GetLength(); t++ ) - { - asCEnumType *et = module->m_enumTypes[t]; - if( ns != et->nameSpace ) continue; - - if( GetEnumValueFromType(et, 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; + bool found = false; + + // Search all available enum types + asUINT t; + for( t = 0; t < engine->registeredEnums.GetLength(); t++ ) + { + asCEnumType *et = engine->registeredEnums[t]; + if( ns != et->nameSpace ) continue; + + // Don't bother with types the module doesn't have access to + if( (et->accessMask & module->m_accessMask) == 0 ) + continue; + + if( GetEnumValueFromType(et, name, outDt, outValue) ) + { + if( !found ) + found = true; + else + { + // Found more than one value in different enum types + return 2; + } + } + } + + for( t = 0; t < module->m_enumTypes.GetLength(); t++ ) + { + asCEnumType *et = module->m_enumTypes[t]; + if( ns != et->nameSpace ) continue; + + if( GetEnumValueFromType(et, 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 diff --git a/src/angelscript/source/as_builder.h b/src/angelscript/source/as_builder.h index 3b2f5c71893..d3ac823776f 100644 --- a/src/angelscript/source/as_builder.h +++ b/src/angelscript/source/as_builder.h @@ -60,72 +60,72 @@ struct sGlobalVariableDescription; struct sFunctionDescription { - asCScriptCode *script; - asCScriptNode *node; - asCString name; - asCObjectType *objType; - asCArray paramNames; - int funcId; - bool isExistingShared; + 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; + 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; + 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; typeInfo = 0; isExistingShared = false; isFinal = false;} + sClassDeclaration() {script = 0; node = 0; validState = 0; typeInfo = 0; isExistingShared = false; isFinal = false;} - asCScriptCode *script; - asCScriptNode *node; - asCString name; - int validState; - asCTypeInfo *typeInfo; - bool isExistingShared; - bool isFinal; + asCScriptCode *script; + asCScriptNode *node; + asCString name; + int validState; + asCTypeInfo *typeInfo; + bool isExistingShared; + bool isFinal; - asCArray propInits; + asCArray propInits; }; struct sFuncDef { - asCScriptCode *script; - asCScriptNode *node; - asCString name; - int idx; + asCScriptCode *script; + asCScriptNode *node; + asCString name; + int idx; }; struct sMixinClass { - asCScriptCode *script; - asCScriptNode *node; - asCString name; - asSNameSpace *ns; + asCScriptCode *script; + asCScriptNode *node; + asCString name; + asSNameSpace *ns; }; #endif // AS_NO_COMPILER @@ -133,127 +133,127 @@ struct sMixinClass 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 **outListPattern = 0, asCObjectType **outParentClass = 0); - int ParseVariableDeclaration(const char *decl, asSNameSpace *implicitNamespace, asCString &outName, asSNameSpace *&outNamespace, asCDataType &outDt); - int CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns, bool isProperty, bool isVirtualProperty); - int CheckNameConflictMember(asCTypeInfo *type, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty, bool isVirtualProperty); - int ValidateVirtualProperty(asCScriptFunction *func); + 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 **outListPattern = 0, asCObjectType **outParentClass = 0); + int ParseVariableDeclaration(const char *decl, asSNameSpace *implicitNamespace, asCString &outName, asSNameSpace *&outNamespace, asCDataType &outDt); + int CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns, bool isProperty, bool isVirtualProperty); + int CheckNameConflictMember(asCTypeInfo *type, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty, bool isVirtualProperty); + int ValidateVirtualProperty(asCScriptFunction *func); #ifndef AS_NO_COMPILER - int AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy); - asCScriptCode *FindOrAddCode(const char *name, const char *code, size_t length); - int Build(); + int AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy); + asCScriptCode *FindOrAddCode(const char *name, const char *code, size_t length); + 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); + 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, asCObjectType **objType = 0); - asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType = 0, bool isRequired = true); - asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0); - - asCTypeInfo *GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType); - asCObjectType *GetObjectType(const char *type, asSNameSpace *ns); - asCFuncdefType *GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType); - asCTypeInfo *GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType); - asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0, bool reportError = true, bool *isValid = 0); - asCObjectType *GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next = 0); - asCDataType ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlag, bool *autoHandle); - - int numErrors; - int numWarnings; - bool silent; - - asCScriptEngine *engine; - asCModule *module; + 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, asCObjectType **objType = 0); + asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType = 0, bool isRequired = true); + asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0); + + asCTypeInfo *GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType); + asCObjectType *GetObjectType(const char *type, asSNameSpace *ns); + asCFuncdefType *GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType); + asCTypeInfo *GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType); + asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0, bool reportError = true, bool *isValid = 0); + asCObjectType *GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next = 0); + asCDataType ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlag, bool *autoHandle); + + int numErrors; + 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, asSFunctionTraits funcTraits); - int RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false); - int RegisterImportedFunction(int funcID, asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); - int RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); - 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, asCObjectType *parent); - asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns); - void CompleteFuncDef(sFuncDef *funcDef); - void CompileInterfaces(); - void CompileClasses(asUINT originalNumTempl); - void DetermineTypeRelations(); - void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits &traits, asSNameSpace *implicitNamespace); - bool DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex = 0); - void AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file); - asCObjectProperty *AddPropertyToClass(sClassDeclaration *c, const asCString &name, const asCDataType &type, bool isPrivate, bool isProtected, bool isInherited, asCScriptCode *file = 0, asCScriptNode *node = 0); - 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 GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue); - int GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue, asSNameSpace *ns); - bool DoesTypeExist(const asCString &type); - asCObjectProperty *GetObjectProperty(asCDataType &obj, const char *prop); - 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 = "", asCScriptNode *errNode = 0, asCScriptCode *script = 0); - void EvaluateTemplateInstances(asUINT startIdx, bool keepSilent); - void CleanupEnumValues(); - - 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; + 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, asSFunctionTraits funcTraits); + int RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false); + int RegisterImportedFunction(int funcID, asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + int RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + 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, asCObjectType *parent); + asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns); + void CompleteFuncDef(sFuncDef *funcDef); + void CompileInterfaces(); + void CompileClasses(asUINT originalNumTempl); + void DetermineTypeRelations(); + void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits &traits, asSNameSpace *implicitNamespace); + bool DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex = 0); + void AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file); + asCObjectProperty *AddPropertyToClass(sClassDeclaration *c, const asCString &name, const asCDataType &type, bool isPrivate, bool isProtected, bool isInherited, asCScriptCode *file = 0, asCScriptNode *node = 0); + 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 GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue); + int GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue, asSNameSpace *ns); + bool DoesTypeExist(const asCString &type); + asCObjectProperty *GetObjectProperty(asCDataType &obj, const char *prop); + 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 = "", asCScriptNode *errNode = 0, asCScriptCode *script = 0); + void EvaluateTemplateInstances(asUINT startIdx, bool keepSilent); + void CleanupEnumValues(); + + 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 }; diff --git a/src/angelscript/source/as_bytecode.cpp b/src/angelscript/source/as_bytecode.cpp index fbad9d9c1e0..29e567dccb5 100644 --- a/src/angelscript/source/as_bytecode.cpp +++ b/src/angelscript/source/as_bytecode.cpp @@ -52,1641 +52,1641 @@ BEGIN_AS_NAMESPACE asCByteCode::asCByteCode(asCScriptEngine *engine) { - first = 0; - last = 0; - largestStackUsed = -1; - temporaryVariables = 0; + first = 0; + last = 0; + largestStackUsed = -1; + temporaryVariables = 0; - this->engine = engine; + this->engine = engine; } asCByteCode::~asCByteCode() { - ClearAll(); + ClearAll(); } void asCByteCode::Finalize(const asCArray &tempVariableOffsets) { - temporaryVariables = &tempVariableOffsets; + temporaryVariables = &tempVariableOffsets; - // verify the bytecode - PostProcess(); + // verify the bytecode + PostProcess(); - // Optimize the code - Optimize(); + // Optimize the code + Optimize(); - // Resolve jumps - ResolveJumpAddresses(); + // Resolve jumps + ResolveJumpAddresses(); - // Build line numbers buffer - ExtractLineNumbers(); + // Build line numbers buffer + ExtractLineNumbers(); } void asCByteCode::ClearAll() { - asCByteInstruction *del = first; + asCByteInstruction *del = first; - while( del ) - { - first = del->next; - engine->memoryMgr.FreeByteInstruction(del); - del = first; - } + while( del ) + { + first = del->next; + engine->memoryMgr.FreeByteInstruction(del); + del = first; + } - first = 0; - last = 0; + first = 0; + last = 0; - lineNumbers.SetLength(0); + lineNumbers.SetLength(0); - largestStackUsed = -1; + largestStackUsed = -1; } void asCByteCode::InsertIfNotExists(asCArray &vars, int var) { - if( !vars.Exists(var) ) - vars.PushLast(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; - } + 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; + 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; - } + 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); - } + 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; + curr->op = bc; - if( curr->next ) DeleteInstruction(curr->next); + if( curr->next ) DeleteInstruction(curr->next); - // Continue optimization with the instruction before the altered one - if( curr->prev ) - return curr->prev; - else - return curr; + // 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 ); + asASSERT( curr->next ); - asCByteInstruction *instr = curr->next; - instr->op = bc; + asCByteInstruction *instr = curr->next; + instr->op = bc; - DeleteInstruction(curr); + DeleteInstruction(curr); - // Continue optimization with the instruction before the altered one - if( instr->prev ) - return instr->prev; - else - return instr; + // 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); + 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( before->prev ) before->prev->next = instr; + instr->prev = before->prev; + before->prev = instr; + instr->next = before; - if( first == before ) first = instr; + if( first == before ) first = instr; } void asCByteCode::RemoveInstruction(asCByteInstruction *instr) { - if( instr == first ) first = first->next; - if( instr == last ) last = last->prev; + 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; + if( instr->prev ) instr->prev->next = instr->next; + if( instr->next ) instr->next->prev = instr->prev; - instr->next = 0; - instr->prev = 0; + instr->next = 0; + instr->prev = 0; } bool asCByteCode::CanBeSwapped(asCByteInstruction *curr) { - asASSERT( curr->op == asBC_SwapPtr ); + asASSERT( curr->op == asBC_SwapPtr ); - if( !curr->prev || !curr->prev->prev ) return false; + if( !curr->prev || !curr->prev->prev ) return false; - asCByteInstruction *b = curr->prev; - asCByteInstruction *a = b->prev; + asCByteInstruction *b = curr->prev; + asCByteInstruction *a = b->prev; - if( a->op != asBC_PshNull && - a->op != asBC_PshVPtr && - a->op != asBC_PSF ) - return false; + 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; + if( b->op != asBC_PshNull && + b->op != asBC_PshVPtr && + b->op != asBC_PSF ) + return false; - return true; + 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; + // 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; + // 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"); + TimeIt("asCByteCode::PostponeInitOfTemp"); - // This is not done for pointers - if( (curr->op != asBC_SetV4 && curr->op != asBC_SetV8) || - !IsTemporary(curr->wArg[0]) ) return false; + // 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; + // 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( IsTempVarOverwrittenByInstr(use, curr->wArg[0]) ) + return false; - if( IsInstrJmpOrLabel(use) ) - return false; + if( IsInstrJmpOrLabel(use) ) + return false; - use = use->next; - } + use = use->next; + } - if( use && use->prev != curr ) - { - asCByteInstruction *orig = curr->next; + if( use && use->prev != curr ) + { + asCByteInstruction *orig = curr->next; - // Move the instruction - RemoveInstruction(curr); - InsertBefore(use, curr); + // 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; - } + // 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 the instructions to its original position as it wasn't useful + RemoveInstruction(curr); + InsertBefore(orig, curr); + } - return false; + 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; + 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"); + TimeIt("asCByteCode::IsTemporary"); - asASSERT(temporaryVariables); + asASSERT(temporaryVariables); - return temporaryVariables->Exists(offset); + 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); - } - // VAR a, GETOBJREF 0 -> PshVPtr a - else if( curr->next && curr->next->op == asBC_GETOBJREF && curr->next->wArg[0] == 0 ) - { - ChangeFirstDeleteNext(curr, asBC_PshVPtr); - instr = GoForward(curr); - } - // VAR, PSF, GETREF {PTR_SIZE} -> PSF, PSF - if( curr->next && curr->next->op == asBC_PSF && - curr->next->next && curr->next->next->op == asBC_GETREF && - curr->next->next->wArg[0] == AS_PTR_SIZE ) - { - curr->op = asBC_PSF; - DeleteInstruction(curr->next->next); - 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; - - 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; - } - } - } - } + // 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); + } + // VAR a, GETOBJREF 0 -> PshVPtr a + else if( curr->next && curr->next->op == asBC_GETOBJREF && curr->next->wArg[0] == 0 ) + { + ChangeFirstDeleteNext(curr, asBC_PshVPtr); + instr = GoForward(curr); + } + // VAR, PSF, GETREF {PTR_SIZE} -> PSF, PSF + if( curr->next && curr->next->op == asBC_PSF && + curr->next->next && curr->next->next->op == asBC_GETREF && + curr->next->next->wArg[0] == AS_PTR_SIZE ) + { + curr->op = asBC_PSF; + DeleteInstruction(curr->next->next); + 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; + + 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, VarDecl, LINE -> VarDecl, LINE - else if (instrOp == asBC_VarDecl && instr->next && instr->next->op == asBC_LINE ) - { - // Delete the first instruction - instr = GoBack(DeleteInstruction(curr)); - } - // LINE, LINE -> LINE - else if( instrOp == asBC_LINE ) - { - // 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)); - } - } + // 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, VarDecl, LINE -> VarDecl, LINE + else if (instrOp == asBC_VarDecl && instr->next && instr->next->op == asBC_LINE ) + { + // Delete the first instruction + instr = GoBack(DeleteInstruction(curr)); + } + // LINE, LINE -> LINE + else if( instrOp == asBC_LINE ) + { + // 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; + // 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; + 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; + 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; + // 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; + 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; + 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_Thiscall1 || - 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; + 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_Thiscall1 || + 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 || - instr->op == asBC_Thiscall1 ) - return false; - - instr = instr->next; - } - - return true; + // 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 || + instr->op == asBC_Thiscall1 ) + 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; - } + // 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 = (asEObjVarInfoOption)*(int*)ARG_DW(instr->arg); - outFunc->scriptData->objVariableInfo.PushLast(info); - } - else if( instr->op == asBC_VarDecl ) - { - // Record the position for debug info - outFunc->scriptData->variables[instr->wArg[0]]->declaredAtProgramPos = pos; - - // Record declaration of object variables for try/catch handling - // This is used for identifying if handles and objects on the heap should be cleared upon catching an exception - // Only extract this info if there is a try/catch block in the function, so we don't use up unnecessary space - if( outFunc->scriptData->tryCatchInfo.GetLength() && outFunc->scriptData->variables[instr->wArg[0]]->type.GetTypeInfo() ) - { - asSObjectVariableInfo info; - info.programPos = pos; - info.variableOffset = outFunc->scriptData->variables[instr->wArg[0]]->stackOffset; - info.option = asOBJ_VARDECL; - outFunc->scriptData->objVariableInfo.PushLast(info); - } - } - else - pos += instr->size; - - instr = instr->next; - } - asASSERT( blockLevel == 0 ); + 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 = (asEObjVarInfoOption)*(int*)ARG_DW(instr->arg); + outFunc->scriptData->objVariableInfo.PushLast(info); + } + else if( instr->op == asBC_VarDecl ) + { + // Record the position for debug info + outFunc->scriptData->variables[instr->wArg[0]]->declaredAtProgramPos = pos; + + // Record declaration of object variables for try/catch handling + // This is used for identifying if handles and objects on the heap should be cleared upon catching an exception + // Only extract this info if there is a try/catch block in the function, so we don't use up unnecessary space + if( outFunc->scriptData->tryCatchInfo.GetLength() && outFunc->scriptData->variables[instr->wArg[0]]->type.GetTypeInfo() ) + { + asSObjectVariableInfo info; + info.programPos = pos; + info.variableOffset = outFunc->scriptData->variables[instr->wArg[0]]->stackOffset; + info.option = asOBJ_VARDECL; + outFunc->scriptData->objVariableInfo.PushLast(info); + } + } + else + pos += instr->size; + + instr = instr->next; + } + asASSERT( blockLevel == 0 ); } void asCByteCode::ExtractTryCatchInfo(asCScriptFunction *outFunc) { - asASSERT(outFunc->scriptData); + asASSERT(outFunc->scriptData); - unsigned int pos = 0; - asCByteInstruction *instr = first; - while (instr) - { - if (instr->op == asBC_TryBlock) - { - asSTryCatchInfo info; - info.tryPos = pos; - info.catchPos = *ARG_DW(instr->arg); - outFunc->scriptData->tryCatchInfo.PushLast(info); - } + unsigned int pos = 0; + asCByteInstruction *instr = first; + while (instr) + { + if (instr->op == asBC_TryBlock) + { + asSTryCatchInfo info; + info.tryPos = pos; + info.catchPos = *ARG_DW(instr->arg); + outFunc->scriptData->tryCatchInfo.PushLast(info); + } - pos += instr->size; - instr = instr->next; - } + pos += instr->size; + instr = instr->next; + } } int asCByteCode::GetSize() { - int size = 0; - asCByteInstruction *instr = first; - while( instr ) - { - size += instr->GetSize(); + int size = 0; + asCByteInstruction *instr = first; + while( instr ) + { + size += instr->GetSize(); - instr = instr->next; - } + instr = instr->next; + } - return size; + 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; - } - } + 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; - } + 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; - } + asCByteInstruction *instr = new(ptr) asCByteInstruction(); + if( first == 0 ) + { + first = last = instr; + } + else + { + last->AddAfter(instr); + last = instr; + } - return 0; + return 0; } int asCByteCode::AddInstructionFirst() { - void *ptr = engine->memoryMgr.AllocByteInstruction(); - if( ptr == 0 ) - { - // Out of memory - return 0; - } + 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; - } + asCByteInstruction *instr = new(ptr) asCByteInstruction(); + if( first == 0 ) + { + first = last = instr; + } + else + { + first->AddBefore(instr); + first = instr; + } - return 0; + return 0; } void asCByteCode::Call(asEBCInstr instr, int funcID, int pop) { - if( AddInstruction() < 0 ) - return; + if( AddInstruction() < 0 ) + return; - asASSERT(asBCInfo[instr].type == asBCTYPE_DW_ARG); + 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; + 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); @@ -1694,15 +1694,15 @@ void asCByteCode::Call(asEBCInstr instr, int funcID, int pop) void asCByteCode::CallPtr(asEBCInstr instr, int funcPtrVar, int pop) { - if( AddInstruction() < 0 ) - return; + if( AddInstruction() < 0 ) + return; - asASSERT(asBCInfo[instr].type == asBCTYPE_rW_ARG); + asASSERT(asBCInfo[instr].type == asBCTYPE_rW_ARG); - last->op = instr; - last->size = asBCTypeSize[asBCInfo[instr].type]; - last->stackInc = -pop; - last->wArg[0] = (short)funcPtrVar; + 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); @@ -1710,16 +1710,16 @@ void asCByteCode::CallPtr(asEBCInstr instr, int funcPtrVar, int pop) void asCByteCode::Alloc(asEBCInstr instr, void *objID, int funcID, int pop) { - if( AddInstruction() < 0 ) - return; + if( AddInstruction() < 0 ) + return; - last->op = instr; - last->size = asBCTypeSize[asBCInfo[instr].type]; - last->stackInc = -pop; // BC_ALLOC + 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; + 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); @@ -1727,59 +1727,59 @@ void asCByteCode::Alloc(asEBCInstr instr, void *objID, int funcID, int pop) void asCByteCode::Ret(int pop) { - if( AddInstruction() < 0 ) - return; + if( AddInstruction() < 0 ) + return; - asASSERT(asBCInfo[asBC_RET].type == asBCTYPE_W_ARG); + 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; + 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; + if( AddInstruction() < 0 ) + return; - asASSERT(asBCInfo[asBC_JMPP].type == asBCTYPE_rW_ARG); + 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; + 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; + // Store the largest jump that is made for PostProcess() + *ARG_DW(last->arg) = max; } void asCByteCode::Label(short label) { - if( AddInstruction() < 0 ) - return; + if( AddInstruction() < 0 ) + return; - last->op = asBC_LABEL; - last->size = 0; - last->stackInc = 0; - last->wArg[0] = label; + 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; + 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; + 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); @@ -1787,746 +1787,746 @@ void asCByteCode::Line(int line, int column, int scriptIdx) void asCByteCode::ObjInfo(int offset, int info) { - if( AddInstruction() < 0 ) - return; + 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; + // 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; + if( AddInstruction() < 0 ) + return; - last->op = asBC_Block; - last->size = 0; - last->stackInc = 0; - last->wArg[0] = start ? 1 : 0; + last->op = asBC_Block; + last->size = 0; + last->stackInc = 0; + last->wArg[0] = start ? 1 : 0; } void asCByteCode::TryBlock(short catchLabel) { - if (AddInstruction() < 0) - return; + if (AddInstruction() < 0) + return; - last->op = asBC_TryBlock; - last->size = 0; - last->stackInc = 0; - *ARG_DW(last->arg) = catchLabel; + last->op = asBC_TryBlock; + last->size = 0; + last->stackInc = 0; + *ARG_DW(last->arg) = catchLabel; } void asCByteCode::VarDecl(int varDeclIdx) { - if( AddInstruction() < 0 ) - return; + if( AddInstruction() < 0 ) + return; - last->op = asBC_VarDecl; - last->size = 0; - last->stackInc = 0; - last->wArg[0] = asWORD(varDeclIdx); + 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; + 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"); - - asUINT currPos = 0; - - 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; - } - else if (instr->op == asBC_TryBlock) - { - int label = *((int*)ARG_DW(instr->arg)); - int labelPosOffset; - int r = FindLabel(label, instr, 0, &labelPosOffset); - if (r == 0) - { - // Should store the absolute address so the exception handler doesn't need to figure it out - *((int*)ARG_DW(instr->arg)) = currPos + labelPosOffset; - } - else - return -1; - } - - currPos += instr->GetSize(); - instr = instr->next; - } - - return 0; + TimeIt("asCByteCode::ResolveJumpAddresses"); + + asUINT currPos = 0; + + 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; + } + else if (instr->op == asBC_TryBlock) + { + int label = *((int*)ARG_DW(instr->arg)); + int labelPosOffset; + int r = FindLabel(label, instr, 0, &labelPosOffset); + if (r == 0) + { + // Should store the absolute address so the exception handler doesn't need to figure it out + *((int*)ARG_DW(instr->arg)) = currPos + labelPosOffset; + } + else + return -1; + } + + currPos += instr->GetSize(); + instr = instr->next; + } + + return 0; } asCByteInstruction *asCByteCode::DeleteInstruction(asCByteInstruction *instr) { - if( instr == 0 ) return 0; + if( instr == 0 ) return 0; - asCByteInstruction *ret = instr->prev ? instr->prev : instr->next; + asCByteInstruction *ret = instr->prev ? instr->prev : instr->next; - RemoveInstruction(instr); + RemoveInstruction(instr); - engine->memoryMgr.FreeByteInstruction(instr); + engine->memoryMgr.FreeByteInstruction(instr); - return ret; + 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; - } + 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 || - instr->op == asBC_TryBlock ) - { - // 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 - { + 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 || + instr->op == asBC_TryBlock ) + { + // 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 + { #ifndef AS_DEBUG - // If the stackSize is negative, then there is a problem with the bytecode. - // If AS_DEBUG is turned on, this same check is done in DebugOutput. - asASSERT( instr->stackSize >= 0 || asBCInfo[instr->op].type == asBCTYPE_INFO ); + // If the stackSize is negative, then there is a problem with the bytecode. + // If AS_DEBUG is turned on, this same check is done in DebugOutput. + asASSERT( instr->stackSize >= 0 || asBCInfo[instr->op].type == asBCTYPE_INFO ); #endif - instr = instr->next; - } - } + instr = instr->next; + } + } } #ifdef AS_DEBUG void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func) { #ifndef __MINGW32__ - // _mkdir is broken on mingw - _mkdir("AS_DEBUG"); + // _mkdir is broken on mingw + _mkdir("AS_DEBUG"); #endif - asCString path = "AS_DEBUG/"; - path += name; + asCString path = "AS_DEBUG/"; + path += name; - // Anonymous functions created from within class methods will contain :: as part of the name - // Replace :: with __ to avoid error when creating the file for debug output - for (asUINT n = 0; n < path.GetLength(); n++) - if (path[n] == ':') path[n] = '_'; + // Anonymous functions created from within class methods will contain :: as part of the name + // Replace :: with __ to avoid error when creating the file for debug output + for (asUINT n = 0; n < path.GetLength(); n++) + if (path[n] == ':') path[n] = '_'; #if _MSC_VER >= 1500 && !defined(AS_MARMALADE) - FILE *file; - fopen_s(&file, path.AddressOf(), "w"); + FILE *file; + fopen_s(&file, path.AddressOf(), "w"); #else - FILE *file = fopen(path.AddressOf(), "w"); + FILE *file = fopen(path.AddressOf(), "w"); #endif #if !defined(AS_XENON) && !defined(__MINGW32__) - // XBox 360: When running in DVD Emu, no write is allowed - // MinGW: As _mkdir is broken, don't assert on file not created if the AS_DEBUG directory doesn't exist - asASSERT( file ); + // XBox 360: When running in DVD Emu, no write is allowed + // MinGW: As _mkdir is broken, don't assert on file not created if the AS_DEBUG directory doesn't exist + asASSERT( file ); #endif - 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(func->nameSpace, true).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(func->nameSpace, true).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"); - - bool invalidStackSize = false; - 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; - } - - if( instr->GetSize() > 0 ) - { - fprintf(file, "%5d ", pos); - pos += instr->GetSize(); - - fprintf(file, "%3d %c ", int(instr->stackSize + func->scriptData->variableSpace), instr->marked ? '*' : ' '); - if( instr->stackSize < 0 ) - invalidStackSize = true; - } - else - { - fprintf(file, " "); - } - - switch( asBCInfo[instr->op].type ) - { - case asBCTYPE_W_ARG: - 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: - { - asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg); - fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), ot->GetName()); - } - break; - - case asBC_FuncPtr: - { - asCScriptFunction *f = *(asCScriptFunction**)ARG_DW(instr->arg); - fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), f->GetDeclaration()); - } - break; - - 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: - case asBC_Thiscall1: - { - 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: - switch( instr->op ) - { - case asBC_OBJTYPE: - { - asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); - fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), ot->GetName()); - } - break; - - case asBC_FuncPtr: - { - asCScriptFunction *f = *(asCScriptFunction**)ARG_QW(instr->arg); - fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), f->GetDeclaration()); - } - break; - - case asBC_PGA: - { - void *ptr = *(void**)ARG_QW(instr->arg); - asSMapNode *cursor = 0; - if( engine->varAddressMap.MoveTo(&cursor, ptr) ) - { - fprintf(file, " %-8s 0x%x (var:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), cursor->value->name.AddressOf()); - } - else - { - asUINT length; - engine->stringFactory->GetRawStringData(ptr, 0, &length); - asCString str; - str.SetLength(length); - engine->stringFactory->GetRawStringData(ptr, str.AddressOf(), &length); - if (str.GetLength() > 20) - { - // TODO: Replace non-visible characters with space or something like it - str.SetLength(20); - str += "..."; - } - fprintf(file, " %-8s 0x%x (str:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), str.AddressOf()); - } - } - break; - - default: + 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(func->nameSpace, true).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(func->nameSpace, true).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"); + + bool invalidStackSize = false; + 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; + } + + if( instr->GetSize() > 0 ) + { + fprintf(file, "%5d ", pos); + pos += instr->GetSize(); + + fprintf(file, "%3d %c ", int(instr->stackSize + func->scriptData->variableSpace), instr->marked ? '*' : ' '); + if( instr->stackSize < 0 ) + invalidStackSize = true; + } + else + { + fprintf(file, " "); + } + + switch( asBCInfo[instr->op].type ) + { + case asBCTYPE_W_ARG: + 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: + { + asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg); + fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), ot->GetName()); + } + break; + + case asBC_FuncPtr: + { + asCScriptFunction *f = *(asCScriptFunction**)ARG_DW(instr->arg); + fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), f->GetDeclaration()); + } + break; + + 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: + case asBC_Thiscall1: + { + 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: + switch( instr->op ) + { + case asBC_OBJTYPE: + { + asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); + fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), ot->GetName()); + } + break; + + case asBC_FuncPtr: + { + asCScriptFunction *f = *(asCScriptFunction**)ARG_QW(instr->arg); + fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), f->GetDeclaration()); + } + break; + + case asBC_PGA: + { + void *ptr = *(void**)ARG_QW(instr->arg); + asSMapNode *cursor = 0; + if( engine->varAddressMap.MoveTo(&cursor, ptr) ) + { + fprintf(file, " %-8s 0x%x (var:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), cursor->value->name.AddressOf()); + } + else + { + asUINT length; + engine->stringFactory->GetRawStringData(ptr, 0, &length); + asCString str; + str.SetLength(length); + engine->stringFactory->GetRawStringData(ptr, str.AddressOf(), &length); + if (str.GetLength() > 20) + { + // TODO: Replace non-visible characters with space or something like it + str.SetLength(20); + str += "..."; + } + fprintf(file, " %-8s 0x%x (str:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), str.AddressOf()); + } + } + break; + + default: #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))); + 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))); + 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))); + 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: - switch( instr->op ) - { - case asBC_RefCpyV: - case asBC_FREE: - { - asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); - fprintf(file, " %-8s v%d, 0x%x (type:%s)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_QW(instr->arg), ot->GetName()); - } - break; - - default: + } + break; + + case asBCTYPE_wW_QW_ARG: + case asBCTYPE_rW_QW_ARG: + switch( instr->op ) + { + case asBC_RefCpyV: + case asBC_FREE: + { + asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); + fprintf(file, " %-8s v%d, 0x%x (type:%s)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_QW(instr->arg), ot->GetName()); + } + break; + + default: #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))); + 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))); + 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))); + 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); - asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]]; - fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); - } - else - fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1)); - 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); - asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]]; + } + break; + + case asBCTYPE_DW_DW_ARG: + if( instr->op == asBC_ALLOC ) + { + asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg); + asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]]; + fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); + } + else + fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1)); + 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); + asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]]; #if defined(__GNUC__) && !defined(_MSC_VER) #ifdef AS_64BIT_PTR - fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); + fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); #else - fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); + fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); #endif #else - fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); + fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); #endif - } - else + } + else #if defined(__GNUC__) && !defined(_MSC_VER) #ifdef AS_64BIT_PTR - fprintf(file, " %-8s %lu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2)); + 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)); + 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)); + 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); - - // If the stackSize is negative then there is something wrong with the - // bytecode, i.e. there is a bug in the compiler or in the optimizer. We - // only check this here to have the bytecode available on file for verification - asASSERT( !invalidStackSize ); + 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); + + // If the stackSize is negative then there is something wrong with the + // bytecode, i.e. there is a bug in the compiler or in the optimizer. We + // only check this here to have the bytecode available on file for verification + asASSERT( !invalidStackSize ); } #endif @@ -2534,487 +2534,487 @@ void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func) int asCByteCode::InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param) { - asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstructionFirst() < 0 ) - return 0; + if( AddInstructionFirst() < 0 ) + return 0; - first->op = bc; - *ARG_DW(first->arg) = param; - first->size = asBCTypeSize[asBCInfo[bc].type]; - first->stackInc = asBCInfo[bc].stackInc; + first->op = bc; + *ARG_DW(first->arg) = param; + first->size = asBCTypeSize[asBCInfo[bc].type]; + first->stackInc = asBCInfo[bc].stackInc; - return first->stackInc; + return first->stackInc; } int asCByteCode::InsertFirstInstrQWORD(asEBCInstr bc, asQWORD param) { - asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstructionFirst() < 0 ) - return 0; + if( AddInstructionFirst() < 0 ) + return 0; - first->op = bc; - *ARG_QW(first->arg) = param; - first->size = asBCTypeSize[asBCInfo[bc].type]; - first->stackInc = asBCInfo[bc].stackInc; + first->op = bc; + *ARG_QW(first->arg) = param; + first->size = asBCTypeSize[asBCInfo[bc].type]; + first->stackInc = asBCInfo[bc].stackInc; - return first->stackInc; + return first->stackInc; } int asCByteCode::Instr(asEBCInstr bc) { - asASSERT(asBCInfo[bc].type == asBCTYPE_NO_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].type == asBCTYPE_NO_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstruction() < 0 ) - return 0; + if( AddInstruction() < 0 ) + return 0; - last->op = bc; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; + last->op = bc; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->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); + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_rW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); - if( AddInstruction() < 0 ) - return 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; + 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; + 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); + 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; + 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; + 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; + 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); + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_PTR_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstruction() < 0 ) - return 0; + 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; + 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; + return last->stackInc; } int asCByteCode::InstrW_DW(asEBCInstr bc, asWORD a, asDWORD b) { - asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || + 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); + asBCInfo[bc].type == asBCTYPE_W_DW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); - if( AddInstruction() < 0 ) - return 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; + 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; + 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); + asASSERT(asBCInfo[bc].type == asBCTYPE_rW_DW_DW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); - if( AddInstruction() < 0 ) - return 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; + 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; + 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); + 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; + if( AddInstruction() < 0 ) + return 0; - last->op = bc; - last->wArg[0] = a; + 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; + // 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; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->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); + 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; + if( AddInstruction() < 0 ) + return 0; - last->op = bc; - last->wArg[0] = a; + 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 + // 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; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->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); + 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; + 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; + 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; + 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); + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); - if( AddInstruction() < 0 ) - return 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; + 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; + 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); + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); - if( AddInstruction() < 0 ) - return 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; + 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; + 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); + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); - if( AddInstruction() < 0 ) - return 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; + 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; + 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); + 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; + if( AddInstruction() < 0 ) + return 0; - last->op = bc; - last->wArg[0] = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; + last->op = bc; + last->wArg[0] = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->stackInc; + return last->stackInc; } int asCByteCode::InstrINT(asEBCInstr bc, int param) { - asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstruction() < 0 ) - return 0; + 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; + last->op = bc; + *((int*) ARG_DW(last->arg)) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->stackInc; + return last->stackInc; } int asCByteCode::InstrDWORD(asEBCInstr bc, asDWORD param) { - asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstruction() < 0 ) - return 0; + if( AddInstruction() < 0 ) + return 0; - last->op = bc; - *ARG_DW(last->arg) = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; + last->op = bc; + *ARG_DW(last->arg) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->stackInc; + return last->stackInc; } int asCByteCode::InstrPTR(asEBCInstr bc, void *param) { - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstruction() < 0 ) - return 0; + 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; + 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; + return last->stackInc; } int asCByteCode::InstrQWORD(asEBCInstr bc, asQWORD param) { - asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstruction() < 0 ) - return 0; + if( AddInstruction() < 0 ) + return 0; - last->op = bc; - *ARG_QW(last->arg) = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; + last->op = bc; + *ARG_QW(last->arg) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->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); + 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; + if( AddInstruction() < 0 ) + return 0; - last->op = bc; - last->wArg[0] = param; - last->size = asBCTypeSize[asBCInfo[bc].type]; - last->stackInc = asBCInfo[bc].stackInc; + last->op = bc; + last->wArg[0] = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->stackInc; + return last->stackInc; } int asCByteCode::InstrFLOAT(asEBCInstr bc, float param) { - asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstruction() < 0 ) - return 0; + 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; + last->op = bc; + *((float*) ARG_DW(last->arg)) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->stackInc; + return last->stackInc; } int asCByteCode::InstrDOUBLE(asEBCInstr bc, double param) { - asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); - asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); - if( AddInstruction() < 0 ) - return 0; + 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; + last->op = bc; + *((double*) ARG_QW(last->arg)) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; - return last->stackInc; + return last->stackInc; } int asCByteCode::GetLastInstr() { - if( last == 0 ) return -1; + if( last == 0 ) return -1; - return last->op; + return last->op; } int asCByteCode::RemoveLastInstr() { - if( last == 0 ) return -1; + if( last == 0 ) return -1; - if( first == last ) - { - engine->memoryMgr.FreeByteInstruction(last); - first = 0; - last = 0; - } - else - { - asCByteInstruction *bc = last; - last = bc->prev; + if( first == last ) + { + engine->memoryMgr.FreeByteInstruction(last); + first = 0; + last = 0; + } + else + { + asCByteInstruction *bc = last; + last = bc->prev; - bc->Remove(); - engine->memoryMgr.FreeByteInstruction(bc); - } + bc->Remove(); + engine->memoryMgr.FreeByteInstruction(bc); + } - return 0; + return 0; } asDWORD asCByteCode::GetLastInstrValueDW() { - if( last == 0 ) return 0; + if( last == 0 ) return 0; - return *ARG_DW(last->arg); + return *ARG_DW(last->arg); } //=================================================================== asCByteInstruction::asCByteInstruction() { - next = 0; - prev = 0; + next = 0; + prev = 0; - op = asBC_LABEL; + op = asBC_LABEL; - arg = 0; - wArg[0] = 0; - wArg[1] = 0; - wArg[2] = 0; - size = 0; - stackInc = 0; - marked = false; - stackSize = 0; + 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; + if( next ) + next->prev = nextCode; - nextCode->next = next; - nextCode->prev = this; - next = nextCode; + nextCode->next = next; + nextCode->prev = this; + next = nextCode; } void asCByteInstruction::AddBefore(asCByteInstruction *prevCode) { - if( prev ) - prev->next = prevCode; + if( prev ) + prev->next = prevCode; - prevCode->prev = prev; - prevCode->next = this; - prev = prevCode; + prevCode->prev = prev; + prevCode->next = this; + prev = prevCode; } int asCByteInstruction::GetSize() { - return size; + return size; } int asCByteInstruction::GetStackIncrease() { - return stackInc; + return stackInc; } void asCByteInstruction::Remove() { - if( prev ) prev->next = next; - if( next ) next->prev = prev; - prev = 0; - next = 0; + if( prev ) prev->next = next; + if( next ) next->prev = prev; + prev = 0; + next = 0; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_bytecode.h b/src/angelscript/source/as_bytecode.h index f69f35bdeba..58f44d99b01 100644 --- a/src/angelscript/source/as_bytecode.h +++ b/src/angelscript/source/as_bytecode.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2018 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -59,143 +59,143 @@ class asCByteInstruction; class asCByteCode { public: - asCByteCode(asCScriptEngine *engine); - ~asCByteCode(); + asCByteCode(asCScriptEngine *engine); + ~asCByteCode(); - void ClearAll(); + void ClearAll(); - int GetSize(); + int GetSize(); - void Finalize(const asCArray &tempVariableOffsets); + void Finalize(const asCArray &tempVariableOffsets); - void Optimize(); - void OptimizeLocally(const asCArray &tempVariableOffsets); - void ExtractLineNumbers(); - void ExtractObjectVariableInfo(asCScriptFunction *outFunc); - void ExtractTryCatchInfo(asCScriptFunction *outFunc); - int ResolveJumpAddresses(); - int FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta); + void Optimize(); + void OptimizeLocally(const asCArray &tempVariableOffsets); + void ExtractLineNumbers(); + void ExtractObjectVariableInfo(asCScriptFunction *outFunc); + void ExtractTryCatchInfo(asCScriptFunction *outFunc); + int ResolveJumpAddresses(); + int FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta); - void AddPath(asCArray &paths, asCByteInstruction *instr, int stackSize); + void AddPath(asCArray &paths, asCByteInstruction *instr, int stackSize); - void Output(asDWORD *array); - void AddCode(asCByteCode *bc); + void Output(asDWORD *array); + void AddCode(asCByteCode *bc); - void PostProcess(); + void PostProcess(); #ifdef AS_DEBUG - void DebugOutput(const char *name, asCScriptFunction *func); + void DebugOutput(const char *name, 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 TryBlock(short catchLabel); - - 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); - - asCScriptEngine *GetEngine() const { return engine; }; - - asCArray lineNumbers; - asCArray sectionIdxs; - int largestStackUsed; + 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 TryBlock(short catchLabel); + + 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); + + asCScriptEngine *GetEngine() const { return engine; }; + + 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; + // 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(); + asCByteInstruction(); - void AddAfter(asCByteInstruction *nextCode); - void AddBefore(asCByteInstruction *nextCode); - void Remove(); + void AddAfter(asCByteInstruction *nextCode); + void AddBefore(asCByteInstruction *nextCode); + void Remove(); - int GetSize(); - int GetStackIncrease(); + int GetSize(); + int GetStackIncrease(); - asCByteInstruction *next; - asCByteInstruction *prev; + asCByteInstruction *next; + asCByteInstruction *prev; - asEBCInstr op; - asQWORD arg; - short wArg[3]; - int size; - int stackInc; + asEBCInstr op; + asQWORD arg; + short wArg[3]; + int size; + int stackInc; - // Testing - bool marked; - int stackSize; + // Testing + bool marked; + int stackSize; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_callfunc.cpp b/src/angelscript/source/as_callfunc.cpp index 58dfaaad999..2b6b3a32e9f 100644 --- a/src/angelscript/source/as_callfunc.cpp +++ b/src/angelscript/source/as_callfunc.cpp @@ -55,493 +55,493 @@ BEGIN_AS_NAMESPACE int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal) { - memset(internal, 0, sizeof(asSSystemFunctionInterface)); - - internal->func = ptr.ptr.f.func; - internal->auxiliary = 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(auxiliary == 0) - return asINVALID_ARG; - internal->auxiliary = auxiliary; - internal->callConv = ICC_THISCALL; - - // This is really a thiscall, so it is necessary to check for virtual method pointers - base = asCALL_THISCALL; - isMethod = true; - } - else if (base == asCALL_GENERIC) - { - internal->callConv = ICC_GENERIC_FUNC; - - // The auxiliary object is optional for generic calling convention - internal->auxiliary = auxiliary; - } - else - return asNOT_SUPPORTED; - } - - if( isMethod ) - { + memset(internal, 0, sizeof(asSSystemFunctionInterface)); + + internal->func = ptr.ptr.f.func; + internal->auxiliary = 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(auxiliary == 0) + return asINVALID_ARG; + internal->auxiliary = auxiliary; + internal->callConv = ICC_THISCALL; + + // This is really a thiscall, so it is necessary to check for virtual method pointers + base = asCALL_THISCALL; + isMethod = true; + } + else if (base == asCALL_GENERIC) + { + internal->callConv = ICC_GENERIC_FUNC; + + // The auxiliary object is optional for generic calling convention + internal->auxiliary = auxiliary; + } + else + return asNOT_SUPPORTED; + } + + if( isMethod ) + { #ifndef AS_NO_CLASS_METHODS - if( base == asCALL_THISCALL || base == asCALL_THISCALL_OBJFIRST || base == asCALL_THISCALL_OBJLAST ) - { - internalCallConv thisCallConv; - if( base == asCALL_THISCALL ) - { - if(callConv != asCALL_THISCALL_ASGLOBAL && auxiliary) - return asINVALID_ARG; - - thisCallConv = ICC_THISCALL; - } - else - { + if( base == asCALL_THISCALL || base == asCALL_THISCALL_OBJFIRST || base == asCALL_THISCALL_OBJLAST ) + { + internalCallConv thisCallConv; + if( base == asCALL_THISCALL ) + { + if(callConv != asCALL_THISCALL_ASGLOBAL && auxiliary) + return asINVALID_ARG; + + thisCallConv = ICC_THISCALL; + } + else + { #ifdef AS_NO_THISCALL_FUNCTOR_METHOD - return asNOT_SUPPORTED; + return asNOT_SUPPORTED; #else - if(auxiliary == 0) - return asINVALID_ARG; - - internal->auxiliary = auxiliary; - if( base == asCALL_THISCALL_OBJFIRST ) - thisCallConv = ICC_THISCALL_OBJFIRST; - else //if( base == asCALL_THISCALL_OBJLAST ) - thisCallConv = ICC_THISCALL_OBJLAST; + if(auxiliary == 0) + return asINVALID_ARG; + + internal->auxiliary = auxiliary; + if( base == asCALL_THISCALL_OBJFIRST ) + thisCallConv = ICC_THISCALL_OBJFIRST; + else //if( base == asCALL_THISCALL_OBJLAST ) + thisCallConv = ICC_THISCALL_OBJLAST; #endif - } + } - internal->callConv = thisCallConv; + internal->callConv = thisCallConv; #ifdef GNU_STYLE_VIRTUAL_METHOD - if( (size_t(ptr.ptr.f.func) & 1) ) - internal->callConv = (internalCallConv)(thisCallConv + 2); + if( (size_t(ptr.ptr.f.func) & 1) ) + internal->callConv = (internalCallConv)(thisCallConv + 2); #endif - internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr); + internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr); #if (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS)) && (defined(__GNUC__) || defined(AS_PSVITA)) - // 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. - // MIPS also appear to use the base offset to indicate virtual method. - if( (size_t(internal->baseOffset) & 1) ) - internal->callConv = (internalCallConv)(thisCallConv + 2); + // 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. + // MIPS also appear to use the base offset to indicate virtual method. + 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; + // We don't support virtual inheritance + if( VIRTUAL_BASE_OFFSET(ptr) != 0 ) + return asNOT_SUPPORTED; #endif - } - else + } + 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; - internal->auxiliary = auxiliary; - } - else - return asNOT_SUPPORTED; - } - - return 0; + 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; + internal->auxiliary = auxiliary; + } + 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(); - - // Prepare the clean up instructions for the function arguments - internal->cleanArgs.SetLength(0); - int offset = 0; - for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - asCDataType &dt = func->parameterTypes[n]; - - if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() ) - { - if (dt.IsFuncdef()) - { - // If the generic call mode is set to old behaviour then always release handles - // else only release the handle if the function is declared with auto handles - if (engine->ep.genericCallMode == 0 || (internal->paramAutoHandles.GetLength() > n && internal->paramAutoHandles[n])) - { - asSSystemFunctionInterface::SClean clean; - clean.op = 0; // call release - clean.ot = &engine->functionBehaviours; - clean.off = short(offset); - internal->cleanArgs.PushLast(clean); - } - } - else if( dt.GetTypeInfo()->flags & asOBJ_REF ) - { - // If the generic call mode is set to old behaviour then always release handles - // else only release the handle if the function is declared with auto handles - if (!dt.IsObjectHandle() || - engine->ep.genericCallMode == 0 || - (internal->paramAutoHandles.GetLength() > n && internal->paramAutoHandles[n]) ) - { - asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; - asASSERT((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release); - if (beh->release) - { - asSSystemFunctionInterface::SClean clean; - clean.op = 0; // call release - clean.ot = CastToObjectType(dt.GetTypeInfo()); - clean.off = short(offset); - internal->cleanArgs.PushLast(clean); - } - } - } - else - { - asSSystemFunctionInterface::SClean clean; - clean.op = 1; // call free - clean.ot = CastToObjectType(dt.GetTypeInfo()); - clean.off = short(offset); - - // Call the destructor then free the memory - asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; - if( beh->destruct ) - clean.op = 2; // call destruct, then free - - internal->cleanArgs.PushLast(clean); - } - } - - if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) - offset += AS_PTR_SIZE; - else - offset += dt.GetSizeOnStackDWords(); - } - - return 0; + asASSERT(internal->callConv == ICC_GENERIC_METHOD || internal->callConv == ICC_GENERIC_FUNC); + + // Calculate the size needed for the parameters + internal->paramSize = func->GetSpaceNeededForArguments(); + + // Prepare the clean up instructions for the function arguments + internal->cleanArgs.SetLength(0); + int offset = 0; + for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + asCDataType &dt = func->parameterTypes[n]; + + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() ) + { + if (dt.IsFuncdef()) + { + // If the generic call mode is set to old behaviour then always release handles + // else only release the handle if the function is declared with auto handles + if (engine->ep.genericCallMode == 0 || (internal->paramAutoHandles.GetLength() > n && internal->paramAutoHandles[n])) + { + asSSystemFunctionInterface::SClean clean; + clean.op = 0; // call release + clean.ot = &engine->functionBehaviours; + clean.off = short(offset); + internal->cleanArgs.PushLast(clean); + } + } + else if( dt.GetTypeInfo()->flags & asOBJ_REF ) + { + // If the generic call mode is set to old behaviour then always release handles + // else only release the handle if the function is declared with auto handles + if (!dt.IsObjectHandle() || + engine->ep.genericCallMode == 0 || + (internal->paramAutoHandles.GetLength() > n && internal->paramAutoHandles[n]) ) + { + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; + asASSERT((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release); + if (beh->release) + { + asSSystemFunctionInterface::SClean clean; + clean.op = 0; // call release + clean.ot = CastToObjectType(dt.GetTypeInfo()); + clean.off = short(offset); + internal->cleanArgs.PushLast(clean); + } + } + } + else + { + asSSystemFunctionInterface::SClean clean; + clean.op = 1; // call free + clean.ot = CastToObjectType(dt.GetTypeInfo()); + clean.off = short(offset); + + // Call the destructor then free the memory + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; + if( beh->destruct ) + clean.op = 2; // call destruct, then free + + internal->cleanArgs.PushLast(clean); + } + } + + if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) + offset += AS_PTR_SIZE; + else + offset += dt.GetSizeOnStackDWords(); + } + + 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); + 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); + // 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.GetTypeInfo()->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.GetTypeInfo()->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 - { + // 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.GetTypeInfo()->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.GetTypeInfo()->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 ) + if( func->returnType.GetSizeInMemoryDWords() > 4 ) #else - if( func->returnType.GetSizeInMemoryDWords() > 2 ) + if( func->returnType.GetSizeInMemoryDWords() > 2 ) #endif - { - internal->hostReturnInMemory = true; - internal->hostReturnSize = sizeof(void*)/4; - } - else - { - internal->hostReturnInMemory = false; - internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords(); + { + 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.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) - internal->hostReturnFloat = true; + if( func->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) + internal->hostReturnFloat = true; #endif - } + } #ifdef THISCALL_RETURN_SIMPLE_IN_MEMORY - if((internal->callConv == ICC_THISCALL || + if((internal->callConv == ICC_THISCALL || #ifdef AS_NO_THISCALL_FUNCTOR_METHOD - internal->callConv == ICC_VIRTUAL_THISCALL) && + internal->callConv == ICC_VIRTUAL_THISCALL) && #else - internal->callConv == ICC_VIRTUAL_THISCALL || - internal->callConv == ICC_THISCALL_OBJFIRST || - internal->callConv == ICC_THISCALL_OBJLAST) && + 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; - } + 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; - } + 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; - } + 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.GetTypeInfo()->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(func->nameSpace).AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); - } + // 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.GetTypeInfo()->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(func->nameSpace).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 + } + 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 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); - } + 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].GetTypeInfo()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) ) - { - engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); - - asCString str; - str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); - } + 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].GetTypeInfo()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) ) + { + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); + + asCString str; + str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->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( + // 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].GetTypeInfo()->flags & COMPLEX_MASK) && + !(func->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) && #endif #ifdef LARGE_OBJS_PASS_BY_REF - func->parameterTypes[n].GetSizeInMemoryDWords() < AS_LARGE_OBJ_MIN_SIZE && + func->parameterTypes[n].GetSizeInMemoryDWords() < AS_LARGE_OBJ_MIN_SIZE && #endif - !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) ) - { - engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); - - asCString str; - str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); - } + !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) ) + { + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); + + asCString str; + str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); + } #endif - break; - } - } + break; + } + } - // Prepare the clean up instructions for the function arguments - internal->cleanArgs.SetLength(0); - int offset = 0; - for( n = 0; n < func->parameterTypes.GetLength(); n++ ) - { - asCDataType &dt = func->parameterTypes[n]; + // Prepare the clean up instructions for the function arguments + internal->cleanArgs.SetLength(0); + int offset = 0; + for( n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + asCDataType &dt = func->parameterTypes[n]; #if defined(COMPLEX_OBJS_PASSED_BY_REF) || defined(AS_LARGE_OBJS_PASSED_BY_REF) - bool needFree = false; + bool needFree = false; #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & COMPLEX_MASK ) needFree = true; + if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & COMPLEX_MASK ) needFree = true; #endif #ifdef AS_LARGE_OBJS_PASSED_BY_REF - if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ) needFree = true; + if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ) needFree = true; #endif - if( needFree && - dt.IsObject() && - !dt.IsObjectHandle() && - !dt.IsReference() ) - { - asSSystemFunctionInterface::SClean clean; - clean.op = 1; // call free - clean.ot = CastToObjectType(dt.GetTypeInfo()); - clean.off = short(offset); + if( needFree && + dt.IsObject() && + !dt.IsObjectHandle() && + !dt.IsReference() ) + { + asSSystemFunctionInterface::SClean clean; + clean.op = 1; // call free + clean.ot = CastToObjectType(dt.GetTypeInfo()); + clean.off = short(offset); #ifndef AS_CALLEE_DESTROY_OBJ_BY_VAL - // If the called function doesn't destroy objects passed by value we must do so here - asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; - if( beh->destruct ) - clean.op = 2; // call destruct, then free + // If the called function doesn't destroy objects passed by value we must do so here + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; + if( beh->destruct ) + clean.op = 2; // call destruct, then free #endif - internal->cleanArgs.PushLast(clean); - } + internal->cleanArgs.PushLast(clean); + } #endif - if( n < internal->paramAutoHandles.GetLength() && internal->paramAutoHandles[n] ) - { - asSSystemFunctionInterface::SClean clean; - clean.op = 0; // call release - if (dt.IsFuncdef()) - clean.ot = &engine->functionBehaviours; - else - clean.ot = CastToObjectType(dt.GetTypeInfo()); - clean.off = short(offset); - internal->cleanArgs.PushLast(clean); - } - - if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) - offset += AS_PTR_SIZE; - else - offset += dt.GetSizeOnStackDWords(); - } + if( n < internal->paramAutoHandles.GetLength() && internal->paramAutoHandles[n] ) + { + asSSystemFunctionInterface::SClean clean; + clean.op = 0; // call release + if (dt.IsFuncdef()) + clean.ot = &engine->functionBehaviours; + else + clean.ot = CastToObjectType(dt.GetTypeInfo()); + clean.off = short(offset); + internal->cleanArgs.PushLast(clean); + } + + if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) + offset += AS_PTR_SIZE; + else + offset += dt.GetSizeOnStackDWords(); + } #endif // !defined(AS_MAX_PORTABILITY) - return 0; + return 0; } #ifdef AS_MAX_PORTABILITY int CallSystemFunction(int id, asCContext *context) { - asCScriptEngine *engine = context->m_engine; - asCScriptFunction *func = engine->scriptFunctions[id]; - asSSystemFunctionInterface *sysFunc = func->sysFuncIntf; - int callConv = sysFunc->callConv; - if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD ) - return context->CallGeneric(func); + asCScriptEngine *engine = context->m_engine; + asCScriptFunction *func = engine->scriptFunctions[id]; + asSSystemFunctionInterface *sysFunc = func->sysFuncIntf; + int callConv = sysFunc->callConv; + if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD ) + return context->CallGeneric(func); - context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); - return 0; + return 0; } #else @@ -571,348 +571,348 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, int CallSystemFunction(int id, asCContext *context) { - asCScriptEngine *engine = context->m_engine; - asCScriptFunction *descr = engine->scriptFunctions[id]; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + 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(descr); + int callConv = sysFunc->callConv; + if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD ) + return context->CallGeneric(descr); - asQWORD retQW = 0; - asQWORD retQW2 = 0; - asDWORD *args = context->m_regs.stackPointer; - void *retPointer = 0; - int popSize = sysFunc->paramSize; + asQWORD retQW = 0; + asQWORD retQW2 = 0; + asDWORD *args = context->m_regs.stackPointer; + void *retPointer = 0; + int popSize = sysFunc->paramSize; - // TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers - // objForThiscall is the object pointer that should be used for the thiscall - // objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST + // TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers + // objForThiscall is the object pointer that should be used for the thiscall + // objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST - // Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST - void *obj = 0; - void *secondObj = 0; + // Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST + void *obj = 0; + void *secondObj = 0; #ifdef AS_NO_THISCALL_FUNCTOR_METHOD - if( callConv >= ICC_THISCALL ) - { - if(sysFunc->auxiliary) - { - // This class method is being called as if it is a global function - obj = sysFunc->auxiliary; - } - 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; - } - - // Skip the object pointer - args += AS_PTR_SIZE; - } - - // Add the base offset for multiple inheritance + if( callConv >= ICC_THISCALL ) + { + if(sysFunc->auxiliary) + { + // This class method is being called as if it is a global function + obj = sysFunc->auxiliary; + } + 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; + } + + // Skip the object pointer + args += AS_PTR_SIZE; + } + + // Add the base offset for multiple inheritance #if (defined(__GNUC__) && (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA) - // 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 - // MIPS also work like ARM in this regard - obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1)); + // 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 + // MIPS also work like ARM in this regard + obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1)); #else - obj = (void*)(asPWORD(obj) + sysFunc->baseOffset); -#endif - } + obj = (void*)(asPWORD(obj) + sysFunc->baseOffset); +#endif + } #else // !defined(AS_NO_THISCALL_FUNCTOR_METHOD) - 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->auxiliary != 0 ); - // This class method is being called as object method (sysFunc->auxiliary must be set). - obj = sysFunc->auxiliary; - continueCheckIndex = 1; - } - else if(sysFunc->auxiliary) - { - // This class method is being called as if it is a global function - obj = sysFunc->auxiliary; - continueCheck = false; - } - - if( obj ) - { - // Add the base offset for multiple inheritance + 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->auxiliary != 0 ); + // This class method is being called as object method (sysFunc->auxiliary must be set). + obj = sysFunc->auxiliary; + continueCheckIndex = 1; + } + else if(sysFunc->auxiliary) + { + // This class method is being called as if it is a global function + obj = sysFunc->auxiliary; + continueCheck = false; + } + + if( obj ) + { + // Add the base offset for multiple inheritance #if (defined(__GNUC__) && (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA) - // 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 - // MIPS also work like ARM in this regard - obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1)); + // 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 + // MIPS also work like ARM in this regard + obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1)); #else - obj = (void*)(asPWORD(obj) + sysFunc->baseOffset); -#endif - } - - if( continueCheck ) - { - void *tempPtr = 0; - - // 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 + obj = (void*)(asPWORD(obj) + sysFunc->baseOffset); +#endif + } + + if( continueCheck ) + { + void *tempPtr = 0; + + // 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_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA) - // 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 - // MIPS also work like ARM in this regard - tempPtr = (void*)(asPWORD(tempPtr) + (sysFunc->baseOffset>>1)); + // 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 + // MIPS also work like ARM in this regard + tempPtr = (void*)(asPWORD(tempPtr) + (sysFunc->baseOffset>>1)); #else - tempPtr = (void*)(asPWORD(tempPtr) + sysFunc->baseOffset); + tempPtr = (void*)(asPWORD(tempPtr) + sysFunc->baseOffset); #endif - // Skip the object pointer - args += AS_PTR_SIZE; - - if( continueCheckIndex ) - secondObj = tempPtr; - else - { - asASSERT( obj == 0 ); - obj = tempPtr; - } - } - } + // Skip the object pointer + args += AS_PTR_SIZE; + + if( continueCheckIndex ) + secondObj = tempPtr; + else + { + asASSERT( obj == 0 ); + obj = tempPtr; + } + } + } #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.GetTypeInfo(); - } - - // For composition we need to add the offset and/or dereference the pointer - if(obj) - { - obj = (void*) ((char*) obj + sysFunc->compositeOffset); - if(sysFunc->isCompositeIndirect) obj = *((void**)obj); - } - - context->m_callingSystemFunction = descr; - bool cppException = false; + 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.GetTypeInfo(); + } + + // For composition we need to add the offset and/or dereference the pointer + if(obj) + { + obj = (void*) ((char*) obj + sysFunc->compositeOffset); + if(sysFunc->isCompositeIndirect) obj = *((void**)obj); + } + + context->m_callingSystemFunction = descr; + bool cppException = false; #ifdef AS_NO_EXCEPTIONS - retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj); + retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj); #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, secondObj); - } - 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->HandleAppException(); - } + // 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, secondObj); + } + 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->HandleAppException(); + } #endif - context->m_callingSystemFunction = 0; + context->m_callingSystemFunction = 0; - // Store the returned value in our stack - if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() ) - { - if( descr->returnType.IsObjectHandle() ) - { + // Store the returned value in our stack + if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !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; + // 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.GetTypeInfo()->flags & asOBJ_NOCOUNT) ); - engine->CallObjectMethod(context->m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref); - } - } - else - { - asASSERT( retPointer ); - - if( !sysFunc->hostReturnInMemory ) - { - // Copy the returned value to the pointer sent by the script engine - if( sysFunc->hostReturnSize == 1 ) - { + context->m_regs.objectRegister = (void*)(asPWORD)retQW; + + if( sysFunc->returnAutoHandle && context->m_regs.objectRegister ) + { + asASSERT( !(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ); + engine->CallObjectMethod(context->m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->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; + // 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(CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct ) - engine->CallObjectMethod(retPointer, CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct); - } - } - } - else - { - // Store value in value register - if( sysFunc->hostReturnSize == 1 ) - { + *(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(CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct ) + engine->CallObjectMethod(retPointer, CastToObjectType(descr->returnType.GetTypeInfo())->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; - } + // 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; + *(asDWORD*)&context->m_regs.valueRegister = (asDWORD)retQW; #endif - } - else - context->m_regs.valueRegister = retQW; - } - - // Clean up arguments - const asUINT cleanCount = sysFunc->cleanArgs.GetLength(); - if( cleanCount ) - { - args = context->m_regs.stackPointer; - - // Skip the hidden argument for the return pointer - // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction - if( descr->DoesReturnOnStack() ) - args += AS_PTR_SIZE; - - // Skip the object pointer on the stack - // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction - if( callConv >= ICC_THISCALL && sysFunc->auxiliary == 0 ) - args += AS_PTR_SIZE; - - asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf(); - for( asUINT n = 0; n < cleanCount; n++, clean++ ) - { - void **addr = (void**)&args[clean->off]; - if( clean->op == 0 ) - { - if( *addr != 0 ) - { - engine->CallObjectMethod(*addr, clean->ot->beh.release); - *addr = 0; - } - } - else - { - asASSERT( clean->op == 1 || clean->op == 2 ); - asASSERT( *addr ); - - if( clean->op == 2 ) - engine->CallObjectMethod(*addr, clean->ot->beh.destruct); - - engine->CallFree(*addr); - } - } - } - - return popSize; + } + else + context->m_regs.valueRegister = retQW; + } + + // Clean up arguments + const asUINT cleanCount = sysFunc->cleanArgs.GetLength(); + if( cleanCount ) + { + args = context->m_regs.stackPointer; + + // Skip the hidden argument for the return pointer + // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction + if( descr->DoesReturnOnStack() ) + args += AS_PTR_SIZE; + + // Skip the object pointer on the stack + // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction + if( callConv >= ICC_THISCALL && sysFunc->auxiliary == 0 ) + args += AS_PTR_SIZE; + + asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf(); + for( asUINT n = 0; n < cleanCount; n++, clean++ ) + { + void **addr = (void**)&args[clean->off]; + if( clean->op == 0 ) + { + if( *addr != 0 ) + { + engine->CallObjectMethod(*addr, clean->ot->beh.release); + *addr = 0; + } + } + else + { + asASSERT( clean->op == 1 || clean->op == 2 ); + asASSERT( *addr ); + + if( clean->op == 2 ) + engine->CallObjectMethod(*addr, clean->ot->beh.destruct); + + engine->CallFree(*addr); + } + } + } + + return popSize; } #endif // AS_MAX_PORTABILITY diff --git a/src/angelscript/source/as_callfunc.h b/src/angelscript/source/as_callfunc.h index c9bdfc69418..663fb66bada 100644 --- a/src/angelscript/source/as_callfunc.h +++ b/src/angelscript/source/as_callfunc.h @@ -59,91 +59,91 @@ int CallSystemFunction(int id, asCContext *context); 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; + // 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; + 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 + 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; - bool hostReturnInMemory; - bool hostReturnFloat; - int hostReturnSize; - int paramSize; - bool takesObjByVal; - asCArray paramAutoHandles; // TODO: Should be able to remove this array. Perhaps the flags can be stored together with the inOutFlags in asCScriptFunction? - bool returnAutoHandle; - int compositeOffset; - bool isCompositeIndirect; - void *auxiliary; // can be used for functors, e.g. by asCALL_THISCALL_ASGLOBAL or asCALL_THISCALL_OBJFIRST - - struct SClean - { - asCObjectType *ot; // argument type for clean up - short op; // clean up operation: 0 = release, 1 = free, 2 = destruct then free - short off; // argument offset on the stack - }; - asCArray cleanArgs; - - asSSystemFunctionInterface() : func(0), baseOffset(0), callConv(ICC_GENERIC_FUNC), hostReturnInMemory(false), hostReturnFloat(false), hostReturnSize(0), paramSize(0), takesObjByVal(false), returnAutoHandle(false), compositeOffset(0), isCompositeIndirect(false), auxiliary(0) {} - - asSSystemFunctionInterface(const asSSystemFunctionInterface &in) - { - *this = in; - } - - asSSystemFunctionInterface &operator=(const asSSystemFunctionInterface &in) - { - func = in.func; - baseOffset = in.baseOffset; - callConv = in.callConv; - hostReturnInMemory = in.hostReturnInMemory; - hostReturnFloat = in.hostReturnFloat; - hostReturnSize = in.hostReturnSize; - paramSize = in.paramSize; - takesObjByVal = in.takesObjByVal; - paramAutoHandles = in.paramAutoHandles; - returnAutoHandle = in.returnAutoHandle; - compositeOffset = in.compositeOffset; - isCompositeIndirect = in.isCompositeIndirect; - auxiliary = in.auxiliary; - cleanArgs = in.cleanArgs; - return *this; - } + asFUNCTION_t func; + int baseOffset; + internalCallConv callConv; + bool hostReturnInMemory; + bool hostReturnFloat; + int hostReturnSize; + int paramSize; + bool takesObjByVal; + asCArray paramAutoHandles; // TODO: Should be able to remove this array. Perhaps the flags can be stored together with the inOutFlags in asCScriptFunction? + bool returnAutoHandle; + int compositeOffset; + bool isCompositeIndirect; + void *auxiliary; // can be used for functors, e.g. by asCALL_THISCALL_ASGLOBAL or asCALL_THISCALL_OBJFIRST + + struct SClean + { + asCObjectType *ot; // argument type for clean up + short op; // clean up operation: 0 = release, 1 = free, 2 = destruct then free + short off; // argument offset on the stack + }; + asCArray cleanArgs; + + asSSystemFunctionInterface() : func(0), baseOffset(0), callConv(ICC_GENERIC_FUNC), hostReturnInMemory(false), hostReturnFloat(false), hostReturnSize(0), paramSize(0), takesObjByVal(false), returnAutoHandle(false), compositeOffset(0), isCompositeIndirect(false), auxiliary(0) {} + + asSSystemFunctionInterface(const asSSystemFunctionInterface &in) + { + *this = in; + } + + asSSystemFunctionInterface &operator=(const asSSystemFunctionInterface &in) + { + func = in.func; + baseOffset = in.baseOffset; + callConv = in.callConv; + hostReturnInMemory = in.hostReturnInMemory; + hostReturnFloat = in.hostReturnFloat; + hostReturnSize = in.hostReturnSize; + paramSize = in.paramSize; + takesObjByVal = in.takesObjByVal; + paramAutoHandles = in.paramAutoHandles; + returnAutoHandle = in.returnAutoHandle; + compositeOffset = in.compositeOffset; + isCompositeIndirect = in.isCompositeIndirect; + auxiliary = in.auxiliary; + cleanArgs = in.cleanArgs; + return *this; + } }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_callfunc_arm.cpp b/src/angelscript/source/as_callfunc_arm.cpp index 6d820702f24..bd4c73db2f8 100644 --- a/src/angelscript/source/as_callfunc_arm.cpp +++ b/src/angelscript/source/as_callfunc_arm.cpp @@ -75,204 +75,204 @@ extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) { - 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++; - } - bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; - - - 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 + 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++; + } + bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; + + + 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) - // 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 ) + // 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 - { + { #if defined(AS_ANDROID) || defined(AS_LINUX) - // mask is used as a toggler to skip uneven registers. - int mask = 1; - - if( isThisCallMethod ) - { - mask = 0; - } - else - { - // 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; + // mask is used as a toggler to skip uneven registers. + int mask = 1; + + if( isThisCallMethod ) + { + mask = 0; + } + else + { + // 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; - - 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++; - } - - 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() ) - { + paramSize = 0; + int spos = 0; + int dpos = 2; + + 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++; + } + + 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].GetTypeInfo()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else #endif - { + { #if defined(AS_ANDROID) || defined(AS_LINUX) - if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && - ((dpos & 1) == mask) ) - { - // 64 bit value align - dpos++; - paramSize++; - } + if( (descr->parameterTypes[n].GetTypeInfo()->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 - { + // 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++; - } + // 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(); - } - } - - 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++; - } - - // 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: - case ICC_THISCALL_OBJFIRST: - case ICC_THISCALL_OBJLAST: - retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj); - break; - case ICC_THISCALL_RETURNINMEM: - case ICC_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_THISCALL_OBJLAST_RETURNINMEM: + // Copy the value directly + paramBuffer[dpos++] = args[spos++]; + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + paramBuffer[dpos++] = args[spos++]; + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + } + + 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++; + } + + // 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: + case ICC_THISCALL_OBJFIRST: + case ICC_THISCALL_OBJLAST: + retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj); + break; + case ICC_THISCALL_RETURNINMEM: + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL_OBJLAST_RETURNINMEM: #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); + // 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); + // 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: - case ICC_VIRTUAL_THISCALL_OBJFIRST: - case ICC_VIRTUAL_THISCALL_OBJLAST: - // 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: - case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: - // Get virtual function table from the object pointer - vftable = *(asFUNCTION_t**)obj; + break; + case ICC_CDECL_OBJFIRST_RETURNINMEM: + retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); + break; + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJLAST: + // 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: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + // 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); + // 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); + // 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; + 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 @@ -296,361 +296,361 @@ extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) { - 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.GetTypeInfo()->flags & COMPLEX_RETURN_MASK ) && - ( descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) && - descr->returnType.GetSizeInMemoryBytes() <= 8 ) - callConv--; - - // The return is made in memory - callConv++; - } - - bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; - - // 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; - - if( isThisCallMethod ) - { - mask = 0; - } - else - { - // 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; - - 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++; - } - - 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() && - !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) ) - { + 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.GetTypeInfo()->flags & COMPLEX_RETURN_MASK ) && + ( descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) && + descr->returnType.GetSizeInMemoryBytes() <= 8 ) + callConv--; + + // The return is made in memory + callConv++; + } + + bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; + + // 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; + + if( isThisCallMethod ) + { + mask = 0; + } + else + { + // 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; + + 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++; + } + + 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() && + !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) ) + { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else #endif - { - if( (descr->parameterTypes[n].GetTypeInfo()->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].GetTypeInfo()->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 - - 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++; - } - } - - // 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: - case ICC_THISCALL_OBJFIRST: - case ICC_THISCALL_OBJLAST: - retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj); - break; - case ICC_THISCALL_RETURNINMEM: - case ICC_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_THISCALL_OBJLAST_RETURNINMEM: - // 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: - case ICC_VIRTUAL_THISCALL_OBJFIRST: - case ICC_VIRTUAL_THISCALL_OBJLAST: - // 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: - case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: - // 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.GetTypeInfo()->flags & COMPLEX_RETURN_MASK) && - (descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) ) - memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() ); - } - - return retQW; + { + if( (descr->parameterTypes[n].GetTypeInfo()->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].GetTypeInfo()->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 + + 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++; + } + } + + // 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: + case ICC_THISCALL_OBJFIRST: + case ICC_THISCALL_OBJLAST: + retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj); + break; + case ICC_THISCALL_RETURNINMEM: + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL_OBJLAST_RETURNINMEM: + // 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: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJLAST: + // 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: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + // 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.GetTypeInfo()->flags & COMPLEX_RETURN_MASK) && + (descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) ) + memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() ); + } + + return retQW; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_callfunc_arm64.cpp b/src/angelscript/source/as_callfunc_arm64.cpp index 3e0944d05ad..962cb69ebdf 100644 --- a/src/angelscript/source/as_callfunc_arm64.cpp +++ b/src/angelscript/source/as_callfunc_arm64.cpp @@ -70,34 +70,34 @@ extern "C" void GetHFAReturnDouble(asQWORD *out1, asQWORD *out2, asQWORD returnS extern "C" void GetHFAReturnFloat(asQWORD *out1, asQWORD *out2, asQWORD returnSize); extern "C" asQWORD CallARM64RetInMemory( - const asQWORD *gpRegArgs, asQWORD numGPRegArgs, - const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, - const asQWORD *stackArgs, asQWORD numStackArgs, - void *retPointer, asFUNCTION_t func + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + void *retPointer, asFUNCTION_t func ); extern "C" double CallARM64Double( - const asQWORD *gpRegArgs, asQWORD numGPRegArgs, - const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, - const asQWORD *stackArgs, asQWORD numStackArgs, - asFUNCTION_t func + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + asFUNCTION_t func ); extern "C" float CallARM64Float( - const asQWORD *gpRegArgs, asQWORD numGPRegArgs, - const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, - const asQWORD *stackArgs, asQWORD numStackArgs, - asFUNCTION_t func + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + asFUNCTION_t func ); extern "C" asQWORD CallARM64( - const asQWORD *gpRegArgs, asQWORD numGPRegArgs, - const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, - const asQWORD *stackArgs, asQWORD numStackArgs, - asFUNCTION_t func + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + asFUNCTION_t func ); extern "C" asQWORD CallARM64Ret128( - const asQWORD *gpRegArgs, asQWORD numGPRegArgs, - const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, - const asQWORD *stackArgs, asQWORD numStackArgs, - asQWORD *higherQWORD, asFUNCTION_t func + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + asQWORD *higherQWORD, asFUNCTION_t func ); // @@ -106,17 +106,17 @@ extern "C" asQWORD CallARM64Ret128( // static inline bool IsRegisterHFA(const asCDataType &type) { - const asCTypeInfo *const typeInfo = type.GetTypeInfo(); + const asCTypeInfo *const typeInfo = type.GetTypeInfo(); - if( typeInfo == nullptr || - (typeInfo->flags & asOBJ_APP_CLASS_ALLFLOATS) == 0 || - type.IsObjectHandle() && type.IsReference() ) - return false; + if( typeInfo == nullptr || + (typeInfo->flags & asOBJ_APP_CLASS_ALLFLOATS) == 0 || + type.IsObjectHandle() && type.IsReference() ) + return false; - const bool doubles = (typeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0; - const int maxAllowedSize = doubles ? sizeof(double) * HFA_RET_REGISTERS : sizeof(float) * HFA_RET_REGISTERS; + const bool doubles = (typeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0; + const int maxAllowedSize = doubles ? sizeof(double) * HFA_RET_REGISTERS : sizeof(float) * HFA_RET_REGISTERS; - return type.GetSizeInMemoryBytes() <= maxAllowedSize; + return type.GetSizeInMemoryBytes() <= maxAllowedSize; } // @@ -125,198 +125,198 @@ static inline bool IsRegisterHFA(const asCDataType &type) // static inline bool IsRegisterHFAParameter(const asCDataType &type, const asQWORD numFloatRegArgs) { - if( !IsRegisterHFA(type) ) - return false; + if( !IsRegisterHFA(type) ) + return false; - const bool doubles = (type.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) != 0; - const int registersUsed = type.GetSizeInMemoryDWords() / (doubles ? sizeof(double) : sizeof(float)); + const bool doubles = (type.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) != 0; + const int registersUsed = type.GetSizeInMemoryDWords() / (doubles ? sizeof(double) : sizeof(float)); - return numFloatRegArgs + registersUsed <= FLOAT_ARG_REGISTERS; + return numFloatRegArgs + registersUsed <= FLOAT_ARG_REGISTERS; } asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObject) { - asCScriptEngine *engine = context->m_engine; - const asSSystemFunctionInterface *const sysFunc = descr->sysFuncIntf; - const asCDataType &retType = descr->returnType; - const asCTypeInfo *const retTypeInfo = retType.GetTypeInfo(); - asFUNCTION_t func = sysFunc->func; - int callConv = sysFunc->callConv; - asQWORD retQW = 0; - - asQWORD gpRegArgs[GP_ARG_REGISTERS]; - asQWORD floatRegArgs[FLOAT_ARG_REGISTERS]; - asQWORD stackArgs[64]; // It's how many x64 users can have - asQWORD numGPRegArgs = 0; - asQWORD numFloatRegArgs = 0; - asQWORD numStackArgs = 0; - - asFUNCTION_t *vftable; - - // 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) ) - { - // Add the object pointer as the first parameter - gpRegArgs[numGPRegArgs++] = (asQWORD)obj; - } - - if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ) - { - // Add the object pointer as the first parameter - gpRegArgs[numGPRegArgs++] = (asQWORD)obj; - } - 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 - gpRegArgs[numGPRegArgs++] = (asQWORD)secondObject; - } - - 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 ) - { - // Get virtual function table from the object pointer - vftable = *(asFUNCTION_t**)obj; - func = vftable[FuncPtrToUInt(func)/sizeof(void*)]; - } - - asUINT argsPos = 0; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - const asCDataType &parmType = descr->parameterTypes[n]; - const asCTypeInfo *const parmTypeInfo = parmType.GetTypeInfo(); - - if( parmType.IsObject() && !parmType.IsObjectHandle() && !parmType.IsReference() ) - { - const asUINT parmDWords = parmType.GetSizeInMemoryDWords(); - const asUINT parmQWords = (parmDWords >> 1) + (parmDWords & 1); - - const bool passedAsPointer = parmQWords <= 2; - const bool fitsInRegisters = passedAsPointer ? (numGPRegArgs < GP_ARG_REGISTERS) : (numGPRegArgs + parmQWords <= GP_ARG_REGISTERS); - asQWORD *const argsArray = fitsInRegisters ? gpRegArgs : stackArgs; - asQWORD &numArgs = fitsInRegisters ? numGPRegArgs : numStackArgs; - - if( (parmTypeInfo->flags & COMPLEX_MASK) ) - { - argsArray[numArgs++] = *(asQWORD*)&args[argsPos]; - argsPos += AS_PTR_SIZE; - } - else if( IsRegisterHFAParameter(parmType, numFloatRegArgs) ) - { - if( (parmTypeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0 ) - { - const asQWORD *const contents = *(asQWORD**)&args[argsPos]; - for( asUINT i = 0; i < parmQWords; i++ ) - floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&contents[i]; - } - else - { - const asDWORD *const contents = *(asDWORD**)&args[argsPos]; - for( asUINT i = 0; i < parmDWords; i++ ) - floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&contents[i]; - } - engine->CallFree(*(char**)(args+argsPos)); - argsPos += AS_PTR_SIZE; - } - else - { - // Copy the object's memory to the buffer - memcpy(&argsArray[numArgs], *(void**)(args+argsPos), parmType.GetSizeInMemoryBytes()); - - // Delete the original memory - engine->CallFree(*(char**)(args+argsPos)); - argsPos += AS_PTR_SIZE; - numArgs += parmQWords; - } - } - else if( parmType.IsFloatType() && !parmType.IsReference() ) - { - if( numFloatRegArgs >= FLOAT_ARG_REGISTERS ) - stackArgs[numStackArgs++] = args[argsPos]; - else - floatRegArgs[numFloatRegArgs++] = args[argsPos]; - argsPos++; - } - else if( parmType.IsDoubleType() && !parmType.IsReference() ) - { - if( numFloatRegArgs >= FLOAT_ARG_REGISTERS ) - stackArgs[numStackArgs++] = *(asQWORD*)&args[argsPos]; - else - floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&args[argsPos]; - argsPos += 2; - } - else - { - // Copy the value directly - const asUINT parmDWords = parmType.GetSizeOnStackDWords(); - const asUINT parmQWords = (parmDWords >> 1) + (parmDWords & 1); - - const bool fitsInRegisters = numGPRegArgs + parmQWords <= GP_ARG_REGISTERS; - asQWORD *const argsArray = fitsInRegisters ? gpRegArgs : stackArgs; - asQWORD &numArgs = fitsInRegisters ? numGPRegArgs : numStackArgs; - - memcpy(&argsArray[numArgs], (void*)(args+argsPos), parmDWords * 4); - argsPos += parmDWords; - numArgs += parmQWords; - } - } - - if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) - { - // Add the object pointer as the last parameter - if( numGPRegArgs < GP_ARG_REGISTERS ) - gpRegArgs[numGPRegArgs++] = (asQWORD)obj; - else - stackArgs[numStackArgs++] = (asQWORD)obj; - } - 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 - if( numGPRegArgs < GP_ARG_REGISTERS ) - gpRegArgs[numGPRegArgs++] = (asQWORD)secondObject; - else - stackArgs[numStackArgs++] = (asQWORD)secondObject; - } - - if( IsRegisterHFA(retType) && !(retTypeInfo->flags & COMPLEX_MASK) ) - { - // This is to deal with HFAs (Homogeneous Floating-point Aggregates): - // ARM64 will place all-float composite types (of equal precision) - // with <= 4 members in the float return registers - - const int structSize = retType.GetSizeInMemoryBytes(); - - CallARM64(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); - if( (retTypeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0 ) - { - if( structSize <= sizeof(double) * 2 ) - GetHFAReturnDouble(&retQW, &retQW2, structSize); - else - GetHFAReturnDouble((asQWORD*)retPointer, ((asQWORD*)retPointer) + 1, structSize); - } - else - GetHFAReturnFloat(&retQW, &retQW2, structSize); - } - else if( sysFunc->hostReturnFloat ) - { - if( sysFunc->hostReturnSize == 1 ) - *(float*)&retQW = CallARM64Float(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); - else - *(double*)&retQW = CallARM64Double(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); - } - else if( sysFunc->hostReturnInMemory ) - retQW = CallARM64RetInMemory(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, retPointer, func); - else - { - if( retType.GetSizeInMemoryBytes() > sizeof(asQWORD) ) - retQW = CallARM64Ret128(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, &retQW2, func); - else - retQW = CallARM64(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); - } - - return retQW; + asCScriptEngine *engine = context->m_engine; + const asSSystemFunctionInterface *const sysFunc = descr->sysFuncIntf; + const asCDataType &retType = descr->returnType; + const asCTypeInfo *const retTypeInfo = retType.GetTypeInfo(); + asFUNCTION_t func = sysFunc->func; + int callConv = sysFunc->callConv; + asQWORD retQW = 0; + + asQWORD gpRegArgs[GP_ARG_REGISTERS]; + asQWORD floatRegArgs[FLOAT_ARG_REGISTERS]; + asQWORD stackArgs[64]; // It's how many x64 users can have + asQWORD numGPRegArgs = 0; + asQWORD numFloatRegArgs = 0; + asQWORD numStackArgs = 0; + + asFUNCTION_t *vftable; + + // 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) ) + { + // Add the object pointer as the first parameter + gpRegArgs[numGPRegArgs++] = (asQWORD)obj; + } + + if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ) + { + // Add the object pointer as the first parameter + gpRegArgs[numGPRegArgs++] = (asQWORD)obj; + } + 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 + gpRegArgs[numGPRegArgs++] = (asQWORD)secondObject; + } + + 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 ) + { + // Get virtual function table from the object pointer + vftable = *(asFUNCTION_t**)obj; + func = vftable[FuncPtrToUInt(func)/sizeof(void*)]; + } + + asUINT argsPos = 0; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + const asCDataType &parmType = descr->parameterTypes[n]; + const asCTypeInfo *const parmTypeInfo = parmType.GetTypeInfo(); + + if( parmType.IsObject() && !parmType.IsObjectHandle() && !parmType.IsReference() ) + { + const asUINT parmDWords = parmType.GetSizeInMemoryDWords(); + const asUINT parmQWords = (parmDWords >> 1) + (parmDWords & 1); + + const bool passedAsPointer = parmQWords <= 2; + const bool fitsInRegisters = passedAsPointer ? (numGPRegArgs < GP_ARG_REGISTERS) : (numGPRegArgs + parmQWords <= GP_ARG_REGISTERS); + asQWORD *const argsArray = fitsInRegisters ? gpRegArgs : stackArgs; + asQWORD &numArgs = fitsInRegisters ? numGPRegArgs : numStackArgs; + + if( (parmTypeInfo->flags & COMPLEX_MASK) ) + { + argsArray[numArgs++] = *(asQWORD*)&args[argsPos]; + argsPos += AS_PTR_SIZE; + } + else if( IsRegisterHFAParameter(parmType, numFloatRegArgs) ) + { + if( (parmTypeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0 ) + { + const asQWORD *const contents = *(asQWORD**)&args[argsPos]; + for( asUINT i = 0; i < parmQWords; i++ ) + floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&contents[i]; + } + else + { + const asDWORD *const contents = *(asDWORD**)&args[argsPos]; + for( asUINT i = 0; i < parmDWords; i++ ) + floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&contents[i]; + } + engine->CallFree(*(char**)(args+argsPos)); + argsPos += AS_PTR_SIZE; + } + else + { + // Copy the object's memory to the buffer + memcpy(&argsArray[numArgs], *(void**)(args+argsPos), parmType.GetSizeInMemoryBytes()); + + // Delete the original memory + engine->CallFree(*(char**)(args+argsPos)); + argsPos += AS_PTR_SIZE; + numArgs += parmQWords; + } + } + else if( parmType.IsFloatType() && !parmType.IsReference() ) + { + if( numFloatRegArgs >= FLOAT_ARG_REGISTERS ) + stackArgs[numStackArgs++] = args[argsPos]; + else + floatRegArgs[numFloatRegArgs++] = args[argsPos]; + argsPos++; + } + else if( parmType.IsDoubleType() && !parmType.IsReference() ) + { + if( numFloatRegArgs >= FLOAT_ARG_REGISTERS ) + stackArgs[numStackArgs++] = *(asQWORD*)&args[argsPos]; + else + floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&args[argsPos]; + argsPos += 2; + } + else + { + // Copy the value directly + const asUINT parmDWords = parmType.GetSizeOnStackDWords(); + const asUINT parmQWords = (parmDWords >> 1) + (parmDWords & 1); + + const bool fitsInRegisters = numGPRegArgs + parmQWords <= GP_ARG_REGISTERS; + asQWORD *const argsArray = fitsInRegisters ? gpRegArgs : stackArgs; + asQWORD &numArgs = fitsInRegisters ? numGPRegArgs : numStackArgs; + + memcpy(&argsArray[numArgs], (void*)(args+argsPos), parmDWords * 4); + argsPos += parmDWords; + numArgs += parmQWords; + } + } + + if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last parameter + if( numGPRegArgs < GP_ARG_REGISTERS ) + gpRegArgs[numGPRegArgs++] = (asQWORD)obj; + else + stackArgs[numStackArgs++] = (asQWORD)obj; + } + 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 + if( numGPRegArgs < GP_ARG_REGISTERS ) + gpRegArgs[numGPRegArgs++] = (asQWORD)secondObject; + else + stackArgs[numStackArgs++] = (asQWORD)secondObject; + } + + if( IsRegisterHFA(retType) && !(retTypeInfo->flags & COMPLEX_MASK) ) + { + // This is to deal with HFAs (Homogeneous Floating-point Aggregates): + // ARM64 will place all-float composite types (of equal precision) + // with <= 4 members in the float return registers + + const int structSize = retType.GetSizeInMemoryBytes(); + + CallARM64(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); + if( (retTypeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0 ) + { + if( structSize <= sizeof(double) * 2 ) + GetHFAReturnDouble(&retQW, &retQW2, structSize); + else + GetHFAReturnDouble((asQWORD*)retPointer, ((asQWORD*)retPointer) + 1, structSize); + } + else + GetHFAReturnFloat(&retQW, &retQW2, structSize); + } + else if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(float*)&retQW = CallARM64Float(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); + else + *(double*)&retQW = CallARM64Double(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); + } + else if( sysFunc->hostReturnInMemory ) + retQW = CallARM64RetInMemory(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, retPointer, func); + else + { + if( retType.GetSizeInMemoryBytes() > sizeof(asQWORD) ) + retQW = CallARM64Ret128(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, &retQW2, func); + else + retQW = CallARM64(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); + } + + return retQW; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_callfunc_arm64_gcc.S b/src/angelscript/source/as_callfunc_arm64_gcc.S index b5d5a5df40a..f58bd1ec369 100644 --- a/src/angelscript/source/as_callfunc_arm64_gcc.S +++ b/src/angelscript/source/as_callfunc_arm64_gcc.S @@ -160,9 +160,9 @@ populateGPRegisterArgsEnd: ldp fp, lr, [sp],#0x20 .cfi_restore lr - .cfi_restore fp + .cfi_restore fp .cfi_restore 20 - .cfi_def_cfa_offset 0 + .cfi_def_cfa_offset 0 ret .cfi_endproc @@ -188,9 +188,9 @@ CallARM64Ret128: ldp fp, lr, [sp],#0x20 .cfi_restore lr - .cfi_restore fp + .cfi_restore fp .cfi_restore 20 - .cfi_def_cfa_offset 0 + .cfi_def_cfa_offset 0 ret .cfi_endproc @@ -213,7 +213,7 @@ CallARM64RetInMemory: ldp fp, lr, [sp],#0x10 .cfi_restore lr - .cfi_restore fp - .cfi_def_cfa_offset 0 + .cfi_restore fp + .cfi_def_cfa_offset 0 ret .cfi_endproc diff --git a/src/angelscript/source/as_callfunc_arm_gcc.S b/src/angelscript/source/as_callfunc_arm_gcc.S index 994fcb0df3c..a9047dab6b0 100644 --- a/src/angelscript/source/as_callfunc_arm_gcc.S +++ b/src/angelscript/source/as_callfunc_arm_gcc.S @@ -720,7 +720,7 @@ nomoreargsarmFuncR0R1: #endif /* arm */ #if defined(__linux__) && defined(__ELF__) -/* ref: http://hardened.gentoo.org/gnu-stack.xml +/* ref: http://hardened.gentoo.org/gnu-stack.xml ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */ .section .note.GNU-stack,"",%progbits #endif diff --git a/src/angelscript/source/as_callfunc_arm_msvc.asm b/src/angelscript/source/as_callfunc_arm_msvc.asm index 7ddf99758ec..a718ca23c81 100644 --- a/src/angelscript/source/as_callfunc_arm_msvc.asm +++ b/src/angelscript/source/as_callfunc_arm_msvc.asm @@ -39,14 +39,14 @@ ; http://msdn.microsoft.com/en-us/library/hh873190.aspx - AREA |.rdata|, DATA, READONLY + AREA |.rdata|, DATA, READONLY EXPORT armFunc EXPORT armFuncR0 EXPORT armFuncR0R1 EXPORT armFuncObjLast EXPORT armFuncR0ObjLast - AREA |.text|, CODE, ARM, ALIGN=3 + AREA |.text|, CODE, ARM, ALIGN=3 ALIGN 8 armFunc PROC @@ -103,7 +103,7 @@ armFuncObjLast PROC ldrge r0, [r6],#4 cmp r7, #2*4 ldrge r1, [r6],#4 - ldrlt r1, [sp] + ldrlt r1, [sp] cmp r7, #3*4 ldrge r2, [r6],#4 ldrlt r2, [sp] diff --git a/src/angelscript/source/as_callfunc_arm_xcode.S b/src/angelscript/source/as_callfunc_arm_xcode.S index 235e242f3d0..41542a693e0 100644 --- a/src/angelscript/source/as_callfunc_arm_xcode.S +++ b/src/angelscript/source/as_callfunc_arm_xcode.S @@ -45,7 +45,7 @@ .globl _armFuncR0R1 .globl _armFuncObjLast .globl _armFuncR0ObjLast - + _armFunc: stmdb sp!, {r4-r8, lr} mov r6, r0 // arg table @@ -98,7 +98,7 @@ _armFuncObjLast: ldrge r0, [r6],#4 cmp r7, #2*4 ldrge r1, [r6],#4 - ldrlt r1, [sp] + ldrlt r1, [sp] cmp r7, #3*4 ldrge r2, [r6],#4 ldrlt r2, [sp] diff --git a/src/angelscript/source/as_callfunc_mips.cpp b/src/angelscript/source/as_callfunc_mips.cpp index be7d1895271..ca2a3aef689 100644 --- a/src/angelscript/source/as_callfunc_mips.cpp +++ b/src/angelscript/source/as_callfunc_mips.cpp @@ -65,7 +65,7 @@ BEGIN_AS_NAMESPACE // The MIPS ABI used by Linux is implemented here // (Tested on CI20 MIPS Creator with Debian Linux) // -// ref: SYSTEM V +// ref: SYSTEM V // APPLICATION BINARY INTERFACE // MIPS RISC Processor // http://math-atlas.sourceforge.net/devel/assembly/mipsabi32.pdf @@ -75,8 +75,8 @@ BEGIN_AS_NAMESPACE union SFloatRegs { - union { double d0; struct { float f0; asDWORD dummy0; };}; - union { double d1; struct { float f1; asDWORD dummy1; };}; + union { double d0; struct { float f0; asDWORD dummy0; };}; + union { double d1; struct { float f1; asDWORD dummy1; };}; } ; extern "C" asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs); @@ -85,283 +85,283 @@ asQWORD GetReturnedDouble(); asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) { - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - int callConv = sysFunc->callConv; - - asQWORD retQW = 0; - - void *func = (void*)sysFunc->func; - void **vftable; - - asDWORD argBuffer[128]; // Ought to be big enough - asASSERT( sysFunc->paramSize < 128 ); - - asDWORD argOffset = 0; - - SFloatRegs floatRegs; - asDWORD floatOffset = 0; - - // If the application function returns the value in memory then - // the first argument must be the pointer to that memory - if( sysFunc->hostReturnInMemory ) - { - asASSERT( retPointer ); - argBuffer[argOffset++] = (asPWORD)retPointer; - } - - if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM || - callConv == ICC_THISCALL || callConv == ICC_THISCALL_RETURNINMEM || - callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || - callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || - callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || - callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST || - callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) - { - // Add the object pointer as the first argument - argBuffer[argOffset++] = (asPWORD)obj; - } - - if( callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || - callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ) - { - // Add the second object pointer - argBuffer[argOffset++] = (asPWORD)secondObject; - } - - int spos = 0; - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - asCDataType ¶mType = descr->parameterTypes[n]; - if( paramType.IsObject() && !paramType.IsObjectHandle() && !paramType.IsReference() ) - { - if( paramType.GetTypeInfo()->flags & COMPLEX_MASK ) - { - // The object is passed by reference - argBuffer[argOffset++] = args[spos++]; - } - else - { - // Ensure 8byte alignment for classes that need it - if( (paramType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) ) - argOffset++; - - // Copy the object's memory to the buffer - memcpy(&argBuffer[argOffset], *(void**)(args+spos), paramType.GetSizeInMemoryBytes()); - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos++; - argOffset += paramType.GetSizeInMemoryDWords(); - } - } - else if( paramType.GetTokenType() == ttQuestion ) - { - // Copy both pointer and type id - argBuffer[argOffset++] = args[spos++]; - argBuffer[argOffset++] = args[spos++]; - } - else - { - // The first 2 floats or doubles are loaded into the float registers. - // Actually this is only done if they are the first arguments to the function, - // but it doesn't cause any harm to load them into the registers even if they - // won't be used so we don't need to check if they really are the first args. - if( floatOffset == 0 ) - { - if( paramType.GetTokenType() == ttFloat ) - floatRegs.f0 = *reinterpret_cast(&args[spos]); - else if( paramType.GetTokenType() == ttDouble ) - floatRegs.d0 = *reinterpret_cast(&args[spos]); - floatOffset++; - } - else if( floatOffset == 1 ) - { - if( paramType.GetTokenType() == ttFloat ) - floatRegs.f1 = *reinterpret_cast(&args[spos]); - else if( paramType.GetTokenType() == ttDouble ) - floatRegs.d1 = *reinterpret_cast(&args[spos]); - floatOffset++; - } - - // Copy the value directly - if( paramType.GetSizeOnStackDWords() > 1 ) - { - // Make sure the argument is 8byte aligned - if( argOffset & 1 ) - argOffset++; - *reinterpret_cast(&argBuffer[argOffset]) = *reinterpret_cast(&args[spos]); - argOffset += 2; - spos += 2; - } - else - argBuffer[argOffset++] = args[spos++]; - } - } - - if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) - { - // Add the object pointer as the last argument - argBuffer[argOffset++] = (asPWORD)obj; - } - - if( callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST || - callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) - { - // Add the second object pointer - argBuffer[argOffset++] = (asPWORD)secondObject; - } - - switch( callConv ) - { - case ICC_CDECL: - case ICC_CDECL_RETURNINMEM: - case ICC_STDCALL: - case ICC_STDCALL_RETURNINMEM: - case ICC_CDECL_OBJLAST: - case ICC_CDECL_OBJLAST_RETURNINMEM: - case ICC_CDECL_OBJFIRST: - case ICC_CDECL_OBJFIRST_RETURNINMEM: - case ICC_THISCALL: - case ICC_THISCALL_RETURNINMEM: - case ICC_THISCALL_OBJFIRST: - case ICC_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_THISCALL_OBJLAST: - case ICC_THISCALL_OBJLAST_RETURNINMEM: - retQW = mipsFunc(argOffset*4, argBuffer, func, floatRegs); - break; - - case ICC_VIRTUAL_THISCALL: - case ICC_VIRTUAL_THISCALL_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJFIRST: - case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: - // Get virtual function table from the object pointer - vftable = *(void***)obj; - retQW = mipsFunc(argOffset*4, argBuffer, vftable[asPWORD(func)>>2], floatRegs); - 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; + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + + asQWORD retQW = 0; + + void *func = (void*)sysFunc->func; + void **vftable; + + asDWORD argBuffer[128]; // Ought to be big enough + asASSERT( sysFunc->paramSize < 128 ); + + asDWORD argOffset = 0; + + SFloatRegs floatRegs; + asDWORD floatOffset = 0; + + // If the application function returns the value in memory then + // the first argument must be the pointer to that memory + if( sysFunc->hostReturnInMemory ) + { + asASSERT( retPointer ); + argBuffer[argOffset++] = (asPWORD)retPointer; + } + + if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM || + callConv == ICC_THISCALL || callConv == ICC_THISCALL_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || + callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || + callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the first argument + argBuffer[argOffset++] = (asPWORD)obj; + } + + if( callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ) + { + // Add the second object pointer + argBuffer[argOffset++] = (asPWORD)secondObject; + } + + int spos = 0; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + asCDataType ¶mType = descr->parameterTypes[n]; + if( paramType.IsObject() && !paramType.IsObjectHandle() && !paramType.IsReference() ) + { + if( paramType.GetTypeInfo()->flags & COMPLEX_MASK ) + { + // The object is passed by reference + argBuffer[argOffset++] = args[spos++]; + } + else + { + // Ensure 8byte alignment for classes that need it + if( (paramType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) ) + argOffset++; + + // Copy the object's memory to the buffer + memcpy(&argBuffer[argOffset], *(void**)(args+spos), paramType.GetSizeInMemoryBytes()); + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos++; + argOffset += paramType.GetSizeInMemoryDWords(); + } + } + else if( paramType.GetTokenType() == ttQuestion ) + { + // Copy both pointer and type id + argBuffer[argOffset++] = args[spos++]; + argBuffer[argOffset++] = args[spos++]; + } + else + { + // The first 2 floats or doubles are loaded into the float registers. + // Actually this is only done if they are the first arguments to the function, + // but it doesn't cause any harm to load them into the registers even if they + // won't be used so we don't need to check if they really are the first args. + if( floatOffset == 0 ) + { + if( paramType.GetTokenType() == ttFloat ) + floatRegs.f0 = *reinterpret_cast(&args[spos]); + else if( paramType.GetTokenType() == ttDouble ) + floatRegs.d0 = *reinterpret_cast(&args[spos]); + floatOffset++; + } + else if( floatOffset == 1 ) + { + if( paramType.GetTokenType() == ttFloat ) + floatRegs.f1 = *reinterpret_cast(&args[spos]); + else if( paramType.GetTokenType() == ttDouble ) + floatRegs.d1 = *reinterpret_cast(&args[spos]); + floatOffset++; + } + + // Copy the value directly + if( paramType.GetSizeOnStackDWords() > 1 ) + { + // Make sure the argument is 8byte aligned + if( argOffset & 1 ) + argOffset++; + *reinterpret_cast(&argBuffer[argOffset]) = *reinterpret_cast(&args[spos]); + argOffset += 2; + spos += 2; + } + else + argBuffer[argOffset++] = args[spos++]; + } + } + + if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last argument + argBuffer[argOffset++] = (asPWORD)obj; + } + + if( callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Add the second object pointer + argBuffer[argOffset++] = (asPWORD)secondObject; + } + + switch( callConv ) + { + case ICC_CDECL: + case ICC_CDECL_RETURNINMEM: + case ICC_STDCALL: + case ICC_STDCALL_RETURNINMEM: + case ICC_CDECL_OBJLAST: + case ICC_CDECL_OBJLAST_RETURNINMEM: + case ICC_CDECL_OBJFIRST: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL: + case ICC_THISCALL_RETURNINMEM: + case ICC_THISCALL_OBJFIRST: + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL_OBJLAST: + case ICC_THISCALL_OBJLAST_RETURNINMEM: + retQW = mipsFunc(argOffset*4, argBuffer, func, floatRegs); + break; + + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + // Get virtual function table from the object pointer + vftable = *(void***)obj; + retQW = mipsFunc(argOffset*4, argBuffer, vftable[asPWORD(func)>>2], floatRegs); + 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; } asDWORD GetReturnedFloat() { - asDWORD f; + asDWORD f; - asm("swc1 $f0, %0\n" : "=m"(f)); + asm("swc1 $f0, %0\n" : "=m"(f)); - return f; + return f; } asQWORD GetReturnedDouble() { - asQWORD d = 0; + asQWORD d = 0; - asm("sdc1 $f0, %0\n" : "=m"(d)); + asm("sdc1 $f0, %0\n" : "=m"(d)); - return d; + return d; } // asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs); // $2,$3 $4 $5 $6 $7 asm( -" .text\n" -//" .align 2\n" -" .cfi_startproc\n" -" .global mipsFunc\n" -" .ent mipsFunc\n" +" .text\n" +//" .align 2\n" +" .cfi_startproc\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" +//" .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, $4, 7\n" // t4 ($12) = argSize ($4) + 7 -" li $13, -8\n" // t5 ($13) = 0xfffffffffffffff8 -" and $12, $12, $13\n" // t4 ($12) &= t5 ($13). t4 holds the size of the argument block +" addiu $12, $4, 7\n" // t4 ($12) = argSize ($4) + 7 +" li $13, -8\n" // t5 ($13) = 0xfffffffffffffff8 +" and $12, $12, $13\n" // t4 ($12) &= t5 ($13). t4 holds the size of the argument block // It is required that the caller reserves space for at least 16 bytes even if there are less than 4 arguments // and add 8 bytes for the return pointer and s0 ($16) backup -" addiu $13, $12, 24\n" // t5 = t4 + 24. t5 ($13) holds the total size of the stack frame (including return pointer) +" addiu $13, $12, 24\n" // t5 = t4 + 24. t5 ($13) 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) -" .cfi_offset 16, -4\n" +" sw $16, -4($sp)\n" // store the s0 register (so we can use it to remember how big our stack frame is) +" .cfi_offset 16, -4\n" // store the return pointer -" sw $31, -8($sp)\n" -" .cfi_offset 31, -8\n" +" sw $31, -8($sp)\n" +" .cfi_offset 31, -8\n" // keep original stack pointer -" move $16, $sp\n" -" .cfi_def_cfa_register 16\n" +" move $16, $sp\n" +" .cfi_def_cfa_register 16\n" // push the stack -" subu $sp, $sp, $13\n" +" subu $sp, $sp, $13\n" // store the argument in temporary registers -" addiu $25, $6, 0\n" // t9 ($25) holds the function pointer (must be t9 for position independent code) -" addiu $3, $4, 0\n" // v1 ($3) holds the size of the argument buffer -" move $15, $5\n" // t7 ($15) holds the pointer to the argBuffer -" move $14, $7\n" // t6 ($14) holds the values for the float registers +" addiu $25, $6, 0\n" // t9 ($25) holds the function pointer (must be t9 for position independent code) +" addiu $3, $4, 0\n" // v1 ($3) holds the size of the argument buffer +" move $15, $5\n" // t7 ($15) holds the pointer to the argBuffer +" move $14, $7\n" // t6 ($14) holds the values for the float registers // load integer registers -" lw $4, 0($15)\n" // a0 ($4) -" lw $5, 4($15)\n" // a1 ($5) -" lw $6, 8($15)\n" // a2 ($6) -" lw $7, 12($15)\n" // a3 ($7) +" lw $4, 0($15)\n" // a0 ($4) +" lw $5, 4($15)\n" // a1 ($5) +" lw $6, 8($15)\n" // a2 ($6) +" lw $7, 12($15)\n" // a3 ($7) // load float registers -" ldc1 $f12, 8($14)\n" -" ldc1 $f14, 0($14)\n" +" ldc1 $f12, 8($14)\n" +" ldc1 $f14, 0($14)\n" // skip stack parameters if there are 4 or less as they are moved into the registers -" addi $14, $3, -16\n" // The first 4 args were already loaded into registers -" blez $14, andCall\n" -" nop\n" +" addi $14, $3, -16\n" // The first 4 args were already loaded into registers +" blez $14, andCall\n" +" nop\n" // push stack parameters "pushArgs:\n" -" addi $3, -4\n" +" addi $3, -4\n" // load from $15 + stack bytes ($3) -" addu $14, $15, $3\n" -" lw $14, 0($14)\n" +" 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" +" addu $13, $sp, $3\n" +" sw $14, 0($13)\n" // if there are more, loop... -" bne $3, $0, pushArgs\n" -" nop\n" +" bne $3, $0, pushArgs\n" +" nop\n" // and call the function "andCall:\n" -" jalr $25\n" -" nop\n" +" jalr $25\n" +" nop\n" // restore original stack pointer -" move $sp, $16\n" +" move $sp, $16\n" // restore the return pointer -" lw $31, -8($sp)\n" +" lw $31, -8($sp)\n" // restore the original value of $16 -" lw $16, -4($sp)\n" +" lw $16, -4($sp)\n" // and return from the function -" jr $31\n" -" nop\n" - -" .set macro\n" -" .set reorder\n" -" .end mipsFunc\n" -" .cfi_endproc\n" -" .size mipsFunc, .-mipsFunc\n" +" jr $31\n" +" nop\n" + +" .set macro\n" +" .set reorder\n" +" .end mipsFunc\n" +" .cfi_endproc\n" +" .size mipsFunc, .-mipsFunc\n" ); #else // !(defined(__linux__) && defined(_ABIO32)) @@ -393,338 +393,338 @@ extern "C" asQWORD mipsFunc(int intArgSize, int floatArgSize, int stackArgSize, // 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; - } + 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 argNum = argSize >> 2; - int intArgs = 0; - int floatArgs = 0; - int restArgs = 0; + 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); + // 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); + 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 argNum = argSize >> 2; - int intArgs = 1; - int floatArgs = 0; - int restArgs = 0; + int intArgs = 1; + int floatArgs = 0; + int restArgs = 0; - mipsArgs[0] = (asDWORD) obj; + 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); + // 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); + 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); + 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; + asDWORD f; - asm("swc1 $f0, %0\n" : "=m"(f)); + asm("swc1 $f0, %0\n" : "=m"(f)); - return f; + return f; } asQWORD GetReturnedDouble() { - asQWORD d = 0; + asQWORD d = 0; - asm("sdc1 $f0, %0\n" : "=m"(d)); + asm("sdc1 $f0, %0\n" : "=m"(d)); - return d; + return d; } asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) { - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - int callConv = sysFunc->callConv; - - // TODO: Mips does not yet support THISCALL_OBJFIRST/LAST - - 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() ) - { + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + + // TODO: Mips does not yet support THISCALL_OBJFIRST/LAST + + 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].GetTypeInfo()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else + if( descr->parameterTypes[n].GetTypeInfo()->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; + { + // 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" +" .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" +//" .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" // 0xfffffffffffffff8 -" and $12, $12, $13\n" // t4 holds the size of the argument block +" addiu $12, $6, 7\n" +" li $13, -8\n" // 0xfffffffffffffff8 +" 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) +" 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) +" 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" +" subu $sp, $sp, $13\n" // find the return address, place in s0 -" addu $16, $sp, $12\n" +" addu $16, $sp, $12\n" // store the return pointer -" sw $31, 0($16)\n" +" sw $31, 0($16)\n" // backup our function params -" addiu $2, $7, 0\n" -" addiu $3, $6, 0\n" +" 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" +//" 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" +" 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" +" 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" +" beq $3, $0, andCall\n" // push stack paramaters -" addiu $15, $15, 64\n" +" addiu $15, $15, 64\n" "pushArgs:\n" -" addiu $3, -4\n" +" addiu $3, -4\n" // load from $15 + stack bytes ($3) -" addu $14, $15, $3\n" -" lw $14, 0($14)\n" +" 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" +" addu $13, $sp, $3\n" +" sw $14, 0($13)\n" // if there are more, loop... -" bne $3, $0, pushArgs\n" -" nop\n" +" bne $3, $0, pushArgs\n" +" nop\n" // and call the function "andCall:\n" -" jal $2\n" -" nop\n" +" jal $2\n" +" nop\n" // restore the return pointer -" lw $31, 0($16)\n" +" lw $31, 0($16)\n" // pop the stack pointer (remembering the return pointer was 8 bytes below the top) -" addiu $sp, $16, 8\n" +" addiu $sp, $16, 8\n" // and return from the function -" jr $31\n" +" 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" +" lw $16, -4($sp)\n" +" .set macro\n" +" .set reorder\n" +" .end mipsFunc\n" +" .size mipsFunc, .-mipsFunc\n" ); #endif // PSP and PS2 MIPS ABI - + END_AS_NAMESPACE #endif // AS_MIPS diff --git a/src/angelscript/source/as_callfunc_ppc.cpp b/src/angelscript/source/as_callfunc_ppc.cpp index 053221fe943..04a403d8f88 100644 --- a/src/angelscript/source/as_callfunc_ppc.cpp +++ b/src/angelscript/source/as_callfunc_ppc.cpp @@ -75,10 +75,10 @@ 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]; + static asBYTE ppcArgsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1]; } -// NOTE: these values are for PowerPC 32 bit. +// 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 @@ -91,580 +91,580 @@ extern "C" 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" + " .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; + asDWORD f; + asm(" stfs f1, %0\n" : "=m"(f)); + return f; } asQWORD GetReturnedDouble() { - asQWORD f; - asm(" stfd f1, %0\n" : "=m"(f)); - return f; + 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; + 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 ); + 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); + 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 +// 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 ); + 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*/, void */*secondObject*/) { - // TODO: PPC does not yet support THISCALL_OBJFIRST/LAST - - // 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; + // TODO: PPC does not yet support THISCALL_OBJFIRST/LAST + + // 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() ) - { + 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].GetTypeInfo()->flags & COMPLEX_MASK ) - { - argsType[a++] = ppcINTARG; - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else + if( descr->parameterTypes[n].GetTypeInfo()->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; + { + // 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 diff --git a/src/angelscript/source/as_callfunc_ppc_64.cpp b/src/angelscript/source/as_callfunc_ppc_64.cpp index 275f6152b41..e44df54e329 100644 --- a/src/angelscript/source/as_callfunc_ppc_64.cpp +++ b/src/angelscript/source/as_callfunc_ppc_64.cpp @@ -62,8 +62,8 @@ BEGIN_AS_NAMESPACE -// This part was written and tested by Jeff Slutter -// from Reactor Zero, Abril, 2007, for PlayStation 3, which +// 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. @@ -83,9 +83,9 @@ BEGIN_AS_NAMESPACE 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]; + 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. @@ -102,667 +102,667 @@ extern "C" // 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 + ".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; + asDWORD f; #ifdef __SNC__ - __stfs( __freg(1), 0, (void*)&f); + __stfs( __freg(1), 0, (void*)&f); #else - asm(" stfs 1, %0\n" : "=m"(f)); + asm(" stfs 1, %0\n" : "=m"(f)); #endif - return f; + return f; } static asQWORD GetReturnedDouble(void) { - asQWORD f; + asQWORD f; #ifdef __SNC__ - __stfd( __freg(1), 0, (void*)&f); + __stfd( __freg(1), 0, (void*)&f); #else - asm(" stfd 1, %0\n" : "=m"(f)); + asm(" stfd 1, %0\n" : "=m"(f)); #endif - return f; + 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; + // 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 ); + 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); + 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 +// 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 ); + 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; + return (type.GetTokenType() == ttQuestion) ? true : false; } asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) { - // TODO: PPC 64 does not yet support THISCALL_OBJFIRST/LAST - - // 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() && - !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) ) - { + // TODO: PPC 64 does not yet support THISCALL_OBJFIRST/LAST + + // 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() && + !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) ) + { #ifdef COMPLEX_OBJS_PASSED_BY_REF - if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - ++paramSize; - } - else + if( descr->parameterTypes[n].GetTypeInfo()->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; + { + // 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 diff --git a/src/angelscript/source/as_callfunc_sh4.cpp b/src/angelscript/source/as_callfunc_sh4.cpp index b24be9a5454..e2f2ba84911 100644 --- a/src/angelscript/source/as_callfunc_sh4.cpp +++ b/src/angelscript/source/as_callfunc_sh4.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2015 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -77,312 +77,312 @@ static asDWORD sh4Args[AS_SH4_MAX_ARGS + 1 + 1]; extern "C" asQWORD sh4Func(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func); asm("" -" .align 4\n" -" .global _sh4Func\n" +" .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 +" 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" +" 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 +" 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" +" .align 4\n" "sh4Args:\n" -" .long _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; - } + 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 argNum = argSize >> 2; - int intArgs = 0; - int floatArgs = 0; - int restArgs = 0; + 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); + // 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); + 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 argNum = argSize >> 2; - int intArgs = 1; - int floatArgs = 0; - int restArgs = 0; + 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); + sh4Args[0] = (asDWORD) obj; - return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func); + // 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 argNum = argSize >> 2; + + int intArgs = 0; + int floatArgs = 0; + int restArgs = 0; - 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); - // 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++; + } - 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); + return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func); } asDWORD GetReturnedFloat() { - asDWORD f; + asDWORD f; - asm("fmov.s fr0, %0\n" : "=m"(f)); + asm("fmov.s fr0, %0\n" : "=m"(f)); - return f; + return f; } // sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4 // so this isn't really used... asQWORD GetReturnedDouble() { - asQWORD d; + asQWORD d; - asm("fmov dr0, %0\n" : "=m"(d)); + asm("fmov dr0, %0\n" : "=m"(d)); - return d; + return d; } asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) { - // TODO: SH4 does not yet support THISCALL_OBJFIRST/LAST - - 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() ) - { + // TODO: SH4 does not yet support THISCALL_OBJFIRST/LAST + + 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].GetTypeInfo()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else + if( descr->parameterTypes[n].GetTypeInfo()->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; + { + // 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 diff --git a/src/angelscript/source/as_callfunc_x64_gcc.cpp b/src/angelscript/source/as_callfunc_x64_gcc.cpp index ad6c27fb6d1..8bc14df121c 100644 --- a/src/angelscript/source/as_callfunc_x64_gcc.cpp +++ b/src/angelscript/source/as_callfunc_x64_gcc.cpp @@ -41,7 +41,7 @@ // 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 @@ -61,413 +61,413 @@ typedef asQWORD ( *funcptr_t )( void ); #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, +// 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) +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; + // 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 + // Reference: http://www.x86-64.org/documentation/abi.pdf - __asm__ __volatile__ ( + __asm__ __volatile__ ( - " movq %0, %%rcx \n" // rcx = cnt - " movq %1, %%r10 \n" // r10 = args - " movq %2, %%r11 \n" // r11 = func + " 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" + // Backup stack pointer in R15 that is guaranteed to maintain its value over function calls + " movq %%rsp, %%r15 \n" #ifdef __OPTIMIZE__ - // Make sure the stack unwind logic knows we've backed up the stack pointer in register r15 - // This should only be done if any optimization is done. If no optimization (-O0) is used, - // then the compiler already backups the rsp before entering the inline assembler code - " .cfi_def_cfa_register r15 \n" + // Make sure the stack unwind logic knows we've backed up the stack pointer in register r15 + // This should only be done if any optimization is done. If no optimization (-O0) is used, + // then the compiler already backups the rsp before entering the inline assembler code + " .cfi_def_cfa_register r15 \n" #endif - // 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" + // 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" #ifdef __OPTIMIZE__ - // Inform the stack unwind logic that the stack pointer has been restored - // This should only be done if any optimization is done. If no optimization (-O0) is used, - // then the compiler already backups the rsp before entering the inline assembler code - " .cfi_def_cfa_register rsp \n" + // Inform the stack unwind logic that the stack pointer has been restored + // This should only be done if any optimization is done. If no optimization (-O0) is used, + // then the compiler already backups the rsp before entering the inline assembler code + " .cfi_def_cfa_register rsp \n" #endif - // 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" - - : : "g" ((asQWORD)cnt), "g" (args), "g" (func), "m" (retQW1), "m" (retQW2), "m" (returnFloat) - : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", - "%rdi", "%rsi", "%rax", "%rdx", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r15"); - - return retQW1; + // 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" + + : : "g" ((asQWORD)cnt), "g" (args), "g" (func), "m" (retQW1), "m" (retQW2), "m" (returnFloat) + : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", + "%rdi", "%rsi", "%rax", "%rdx", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r15"); + + return retQW1; } // returns true if the given parameter is a 'variable argument' static inline bool IsVariableArgument( asCDataType type ) { - return ( type.GetTokenType() == ttQuestion ) ? true : false; + return ( type.GetTokenType() == ttQuestion ) ? true : false; } asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObject) { - 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++; - } + 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++; + } #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 ) ) + // 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) ) + 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; - } + { + 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; + 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; + case ICC_THISCALL: + case ICC_VIRTUAL_THISCALL: + case ICC_CDECL_OBJFIRST: + { + paramBuffer[0] = (asPWORD)obj; + argsType[0] = x64INTARG; - argIndex = 1; + argIndex = 1; - break; - } + break; + } #ifndef AS_NO_THISCALL_FUNCTOR_METHOD - case ICC_THISCALL_OBJLAST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: - param_post = 2; + 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; - } + 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; - } + 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.GetTypeInfo()->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.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLINTS) || - (parmType.GetTypeInfo()->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.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) || - (parmType.GetTypeInfo()->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 ) - { + 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.GetTypeInfo()->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.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLINTS) || + (parmType.GetTypeInfo()->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.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) || + (parmType.GetTypeInfo()->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; + paramBuffer[argIndex] = (asPWORD)obj; #else - paramBuffer[argIndex] = (asPWORD)(param_post > 1 ? secondObject : obj); + 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; + 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 diff --git a/src/angelscript/source/as_callfunc_x64_mingw.cpp b/src/angelscript/source/as_callfunc_x64_mingw.cpp index 1c5bdb55236..3276ec9de1a 100644 --- a/src/angelscript/source/as_callfunc_x64_mingw.cpp +++ b/src/angelscript/source/as_callfunc_x64_mingw.cpp @@ -50,294 +50,294 @@ BEGIN_AS_NAMESPACE static asQWORD __attribute__((noinline)) CallX64(const asQWORD *args, const asQWORD *floatArgs, const int paramSize, asQWORD func) { - volatile asQWORD ret = 0; + 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 + __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" + "# 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 + "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" - ); + : // no output + : "m" (ret), "r" (args), "r" (floatArgs), "r" (paramSize), "r" (func) + : "rdi", "rsi", "rsp", "rbx", "r10", "r11", "%r12", "r13", "r14", "r15" + ); - return ret; + return ret; } static asDWORD GetReturnedFloat() { - volatile asDWORD ret = 0; + volatile asDWORD ret = 0; - __asm__ __volatile__ ( - "lea %0, %%rax\n" - "movss %%xmm0, (%%rax)" - : /* no output */ - : "m" (ret) - : "%rax" - ); + __asm__ __volatile__ ( + "lea %0, %%rax\n" + "movss %%xmm0, (%%rax)" + : /* no output */ + : "m" (ret) + : "%rax" + ); - return ret; + return ret; } static asQWORD GetReturnedDouble() { - volatile asQWORD ret = 0; + volatile asQWORD ret = 0; - __asm__ __volatile__ ( - "lea %0, %%rax\n" - "movlpd %%xmm0, (%%rax)" - : /* no optput */ - : "m" (ret) - : "%rax" - ); + __asm__ __volatile__ ( + "lea %0, %%rax\n" + "movlpd %%xmm0, (%%rax)" + : /* no optput */ + : "m" (ret) + : "%rax" + ); - return ret; + return ret; } asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) { - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - asQWORD retQW = 0; - void *func = (void*)sysFunc->func; - asUINT paramSize = 0; // QWords - void **vftable; + asQWORD retQW = 0; + void *func = (void*)sysFunc->func; + asUINT paramSize = 0; // QWords + void **vftable; - asQWORD allArgBuffer[64]; - asQWORD floatArgBuffer[4]; + asQWORD allArgBuffer[64]; + asQWORD floatArgBuffer[4]; - int callConv = sysFunc->callConv; + int callConv = sysFunc->callConv; - if( sysFunc->hostReturnInMemory ) - { - // The return is made in memory - callConv++; + if( sysFunc->hostReturnInMemory ) + { + // The return is made in memory + callConv++; - // Set the return pointer as the first argument - allArgBuffer[paramSize++] = (asQWORD)retPointer; - } + // 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 ) + if( callConv == ICC_THISCALL || + callConv == ICC_THISCALL_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL || + callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) #else - // 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) ) + // 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; - } + { + // 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; - } + 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 ) + 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 ) + 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].GetTypeInfo()->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; - } + { + // 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].GetTypeInfo()->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; - } + 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); + 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(); - } + // 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; + return retQW; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_callfunc_x64_msvc.cpp b/src/angelscript/source/as_callfunc_x64_msvc.cpp index 8af5adc01b8..fd7884fdd48 100644 --- a/src/angelscript/source/as_callfunc_x64_msvc.cpp +++ b/src/angelscript/source/as_callfunc_x64_msvc.cpp @@ -53,160 +53,160 @@ extern "C" asQWORD GetReturnedDouble(); asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) { - 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; - - // 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) ) - { - // 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; - } - 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; - } - - 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 ) - { - // 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++ ) - { - asCDataType &dt = descr->parameterTypes[n]; - if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) - { - if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE || - (dt.GetTypeInfo()->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), dt.GetSizeInMemoryBytes()); - - // Delete the original memory - engine->CallFree(*(char**)(args+spos)); - spos += AS_PTR_SIZE; - asUINT dwords = dt.GetSizeInMemoryDWords(); - asUINT qwords = (dwords >> 1) + (dwords & 1); - dpos += qwords; - paramSize += qwords; - } - } - else if( dt.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 = dt.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 && dt.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 && dt.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; - } - 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; - } - - 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; + 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; + + // 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) ) + { + // 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; + } + 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; + } + + 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 ) + { + // 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++ ) + { + asCDataType &dt = descr->parameterTypes[n]; + if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) + { + if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE || + (dt.GetTypeInfo()->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), dt.GetSizeInMemoryBytes()); + + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos += AS_PTR_SIZE; + asUINT dwords = dt.GetSizeInMemoryDWords(); + asUINT qwords = (dwords >> 1) + (dwords & 1); + dpos += qwords; + paramSize += qwords; + } + } + else if( dt.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 = dt.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 && dt.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 && dt.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; + } + 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; + } + + 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 diff --git a/src/angelscript/source/as_callfunc_x64_msvc_asm.asm b/src/angelscript/source/as_callfunc_x64_msvc_asm.asm index f4cd1acc6fe..118297f9516 100644 --- a/src/angelscript/source/as_callfunc_x64_msvc_asm.asm +++ b/src/angelscript/source/as_callfunc_x64_msvc_asm.asm @@ -2,23 +2,23 @@ ; 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 +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any ; damages arising from the use of this software. ; -; Permission is granted to anyone to use this software for any -; purpose, including commercial applications, and to alter it and +; Permission is granted to anyone to use this software for any +; purpose, including commercial applications, and to alter it and ; redistribute it freely, subject to the following restrictions: ; -; 1. The origin of this software must not be misrepresented; you +; 1. The origin of this software must not be misrepresented; you ; must not claim that you wrote the original software. If you use -; this software in a product, an acknowledgment in the product +; this software in a product, an acknowledgment in the product ; documentation would be appreciated but is not required. ; -; 2. Altered source versions must be plainly marked as such, and +; 2. Altered source versions must be plainly marked as such, and ; must not be misrepresented as being the original software. ; -; 3. This notice may not be removed or altered from any source +; 3. This notice may not be removed or altered from any source ; distribution. ; ; The original version of this library can be located at: @@ -35,123 +35,123 @@ PUBLIC CallX64 CallX64 PROC FRAME - ; PROLOG + ; PROLOG - ; We must save preserved registers that are used - ; TODO: No need to save unused registers + ; We must save preserved registers that are used + ; TODO: No need to save unused registers - push rbp + push rbp .pushreg rbp - push rsi + push rsi .pushreg rsi - push r11 + push r11 .pushreg r11 - push rdi + push rdi .pushreg rdi - push r12 + push r12 .pushreg r12 - push r13 + push r13 .pushreg r13 - push r14 + push r14 .pushreg r14 - push r15 + push r15 .pushreg r15 - push rbx + push rbx .pushreg rbx - sub rsp, 050h + sub rsp, 050h .allocstack 050h - mov rbp, rsp + 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 + ; 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 + 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] - + ; 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 + + ; 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 @@ -162,21 +162,21 @@ PUBLIC 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) + ; 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 + ; Move the float value from the XMM0 register to RAX register + movss dword ptr [rsp], xmm0 + mov eax, dword ptr [rsp] - ret + ; EPILOG: Clean up + + add rsp, 8 + + ret GetReturnedFloat ENDP @@ -187,22 +187,22 @@ PUBLIC GetReturnedDouble GetReturnedDouble PROC FRAME - ; PROLOG: Store registers and allocate stack space - - sub rsp, 8 ; We'll need 8 bytes for temporary storage + ; 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 - + ; 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/src/angelscript/source/as_callfunc_x86.cpp b/src/angelscript/source/as_callfunc_x86.cpp index 551f41a12f9..aff76fc58ca 100644 --- a/src/angelscript/source/as_callfunc_x86.cpp +++ b/src/angelscript/source/as_callfunc_x86.cpp @@ -91,182 +91,182 @@ asQWORD GetReturnedDouble(); asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) { - asCScriptEngine *engine = context->m_engine; - asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; - - asQWORD retQW = 0; - - // Prepare the parameters - asDWORD paramBuffer[64]; - int callConv = sysFunc->callConv; - - // 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; - - for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) - { - if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) - { + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + + asQWORD retQW = 0; + + // Prepare the parameters + asDWORD paramBuffer[64]; + int callConv = sysFunc->callConv; + + // 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; + + 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].GetTypeInfo()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else + if( descr->parameterTypes[n].GetTypeInfo()->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]; - } - - 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++; - } - - // 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: - case ICC_THISCALL_OBJFIRST: - case ICC_THISCALL_OBJLAST: - retQW = CallThisCallFunction(obj, args, paramSize<<2, func); - break; - - case ICC_THISCALL_RETURNINMEM: - case ICC_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_THISCALL_OBJLAST_RETURNINMEM: - retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, func, retPointer); - break; - - case ICC_VIRTUAL_THISCALL: - case ICC_VIRTUAL_THISCALL_OBJFIRST: - case ICC_VIRTUAL_THISCALL_OBJLAST: - { - // 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: - case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: - case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: - { - // 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; + { + // 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]; + } + + 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++; + } + + // 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: + case ICC_THISCALL_OBJFIRST: + case ICC_THISCALL_OBJLAST: + retQW = CallThisCallFunction(obj, args, paramSize<<2, func); + break; + + case ICC_THISCALL_RETURNINMEM: + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL_OBJLAST_RETURNINMEM: + retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, func, retPointer); + break; + + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJLAST: + { + // 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: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + { + // 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 @@ -281,1227 +281,1227 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, asQWORD NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func) { - volatile asQWORD retQW = 0; + 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 + // 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 + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop endcopy: - // Call function - call [func] + // Call function + call [func] - // Pop arguments from stack - add esp, paramSize + // Pop arguments from stack + add esp, paramSize - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx - } + // 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 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. + // 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)}; + // 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__( + asm __volatile__( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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" + _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" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asQWORD NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) { - volatile asQWORD retQW = 0; + 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 + // 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 + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop endcopy: - // Call function - call [func] + // Call function + call [func] - // Pop arguments from stack - add esp, paramSize - add esp, 4 + // 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 + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx - } + // Restore registers + pop ecx + } #elif defined ASM_AT_N_T - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - asm __volatile__ ( + asm __volatile__ ( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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" + _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" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asQWORD NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) { - volatile asQWORD retQW = 0; + 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 + // 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 + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop endcopy: - // push object as first parameter - push obj + // push object as first parameter + push obj - // Call function - call [func] + // Call function + call [func] - // Pop arguments from stack - add esp, paramSize - add esp, 4 + // 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 + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx - } + // Restore registers + pop ecx + } #elif defined ASM_AT_N_T - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - asm __volatile__ ( + asm __volatile__ ( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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" + _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" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asQWORD NOINLINE CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) { - volatile asQWORD retQW = 0; + 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 + // 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 + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop endcopy: - // Push the object pointer - push obj + // Push the object pointer + push obj - // Push the return pointer - push retPtr; + // Push the return pointer + push retPtr; - // Call function - call [func] + // Call function + call [func] - // Pop arguments from stack - add esp, paramSize + // Pop arguments from stack + add esp, paramSize #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - // Pop the return pointer - add esp, 8 + // Pop the return pointer + add esp, 8 #else - add esp, 4 + add esp, 4 #endif - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx - } + // Restore registers + pop ecx + } #elif defined ASM_AT_N_T - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; - asm __volatile__ ( + asm __volatile__ ( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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 + _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 + "addl $8, %%esp \n" // Pop the return pointer and object pointer #else - "addl $4, %%esp \n" // Pop the object pointer + "addl $4, %%esp \n" // Pop the object pointer #endif - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asQWORD NOINLINE CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) { - volatile asQWORD retQW = 0; + 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 + // 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 + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop endcopy: - // Push the return pointer - push retPtr; + // Push the return pointer + push retPtr; - // Call function - call [func] + // Call function + call [func] - // Pop arguments from stack - add esp, paramSize + // Pop arguments from stack + add esp, paramSize #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - // Pop the return pointer - add esp, 4 + // Pop the return pointer + add esp, 4 #endif - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx + // Restore registers + pop ecx - // return value in EAX or EAX:EDX - } + // return value in EAX or EAX:EDX + } #elif defined ASM_AT_N_T - volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; + volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; - asm __volatile__ ( + asm __volatile__ ( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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 + _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 + "addl $4, %%esp \n" // Pop the return pointer #endif - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asQWORD NOINLINE CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) { - volatile asQWORD retQW = 0; + 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 + // 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 + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop endcopy: - // Push the return pointer - push retPtr; + // Push the return pointer + push retPtr; - // Call function - call [func] + // Call function + call [func] - // Pop arguments from stack - add esp, paramSize - add esp, 4 + // Pop arguments from stack + add esp, paramSize + add esp, 4 #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER - // Pop the return pointer - add esp, 4 + // Pop the return pointer + add esp, 4 #endif - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx - } + // Restore registers + pop ecx + } #elif defined ASM_AT_N_T - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; - asm __volatile__ ( + asm __volatile__ ( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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 + _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 + "addl $8, %%esp \n" // Pop the return pointer and object pointer #else - "addl $4, %%esp \n" // Pop the object pointer + "addl $4, %%esp \n" // Pop the object pointer #endif - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asQWORD NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func) { - volatile asQWORD retQW = 0; + 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 + // 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 + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop endcopy: - // Call function - call [func] + // Call function + call [func] - // The callee already removed parameters from the stack + // The callee already removed parameters from the stack - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx - } + // Restore registers + pop ecx + } #elif defined ASM_AT_N_T - volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - asm __volatile__ ( + asm __volatile__ ( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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" + _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" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asQWORD NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) { - volatile asQWORD retQW = 0; + 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 + // 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 + 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 + // Push the object pointer on the stack + push obj #else - // Move object pointer to ECX - mov ecx, obj + // Move object pointer to ECX + mov ecx, obj #endif - // Call function - call [func] + // Call function + call [func] #ifndef THISCALL_CALLEE_POPS_ARGUMENTS - // Pop arguments - add esp, paramSize + // Pop arguments + add esp, paramSize #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - // Pop object pointer - add esp, 4 + // Pop object pointer + add esp, 4 #endif #endif - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx - } + // Restore registers + pop ecx + } #elif defined ASM_AT_N_T - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; - asm __volatile__ ( + asm __volatile__ ( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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 + _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 + "pushl %%ecx \n" // push obj on the stack #endif - "call *12(%%ebx) \n" + "call *12(%%ebx) \n" #ifndef THISCALL_CALLEE_POPS_ARGUMENTS - "addl 8(%%ebx), %%esp \n" // pop arguments + "addl 8(%%ebx), %%esp \n" // pop arguments #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - "addl $4, %%esp \n" // pop obj + "addl $4, %%esp \n" // pop obj #endif #endif - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asQWORD NOINLINE CallThisCallFunctionRetByRef(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) { - volatile asQWORD retQW = 0; + 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 + // 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 + 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 + // Push the object pointer on the stack + push obj #else - // Move object pointer to ECX - mov ecx, obj + // Move object pointer to ECX + mov ecx, obj #endif - // Push the return pointer - push retPtr + // Push the return pointer + push retPtr - // Call function - call [func] + // Call function + call [func] #ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER - // Pop the return pointer - add esp, 4 + // Pop the return pointer + add esp, 4 #endif #ifndef THISCALL_CALLEE_POPS_ARGUMENTS - // Pop arguments - add esp, paramSize + // Pop arguments + add esp, paramSize #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - // Pop object pointer - add esp, 4 + // Pop object pointer + add esp, 4 #endif #endif - // Copy return value from EAX:EDX - lea ecx, retQW - mov [ecx], eax - mov 4[ecx], edx + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx - // Restore registers - pop ecx - } + // Restore registers + pop ecx + } #elif defined ASM_AT_N_T - volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; - asm __volatile__ ( + asm __volatile__ ( #ifdef __OPTIMIZE__ - // When compiled with optimizations the stack unwind doesn't work properly, - // causing exceptions to crash the application. By adding this prologue - // and the epilogue below, the stack unwind works as it should. - // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below - "pushl %%ebp \n" - ".cfi_adjust_cfa_offset 4 \n" - ".cfi_rel_offset ebp, 0 \n" - "movl %%esp, %%ebp \n" - ".cfi_def_cfa_register ebp \n" + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" #endif - _S(CLEAR_FPU_STACK) "\n" - "pushl %%ebx \n" - "movl %%edx, %%ebx \n" - - // 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" + _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" #ifdef AS_MINGW47 - // MinGW made some strange choices with 4.7 and the thiscall calling convention, - // 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 + // MinGW made some strange choices with 4.7 and the thiscall calling convention, + // 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 + "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 + "pushl %%ecx \n" // push obj on the stack #endif - "pushl 16(%%ebx) \n" // push retPtr on the stack - "call *12(%%ebx) \n" + "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 + "addl $4, %%esp \n" // pop return pointer #endif #ifndef THISCALL_CALLEE_POPS_ARGUMENTS - "addl 8(%%ebx), %%esp \n" // pop arguments + "addl 8(%%ebx), %%esp \n" // pop arguments #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK - "addl $4, %%esp \n" // pop the object pointer + "addl $4, %%esp \n" // pop the object pointer #endif #endif #endif // AS_MINGW47 - // Pop the alignment bytes - "popl %%esp \n" - "popl %%ebx \n" + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" #ifdef __OPTIMIZE__ - // Epilogue - "movl %%ebp, %%esp \n" - ".cfi_def_cfa_register esp \n" - "popl %%ebp \n" - ".cfi_adjust_cfa_offset -4 \n" - ".cfi_restore ebp \n" + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" #endif - // Copy EAX:EDX to retQW. As the stack pointer has been - // restored it is now safe to access the local variable - "leal %1, %%ecx \n" - "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 - ); + // 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; + return retQW; } asDWORD GetReturnedFloat() { - asDWORD f; + asDWORD f; #if defined ASM_INTEL - // Get the float value from ST0 - __asm fstp dword ptr [f] + // Get the float value from ST0 + __asm fstp dword ptr [f] #elif defined ASM_AT_N_T - asm("fstps %0 \n" : "=m" (f)); + asm("fstps %0 \n" : "=m" (f)); #endif - return f; + return f; } asQWORD GetReturnedDouble() { - asQWORD d; + asQWORD d; #if defined ASM_INTEL - // Get the double value from ST0 - __asm fstp qword ptr [d] + // Get the double value from ST0 + __asm fstp qword ptr [d] #elif defined ASM_AT_N_T - asm("fstpl %0 \n" : "=m" (d)); + asm("fstpl %0 \n" : "=m" (d)); #endif - return d; + return d; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_callfunc_xenon.cpp b/src/angelscript/source/as_callfunc_xenon.cpp index c52055e99df..65593bba9bd 100644 --- a/src/angelscript/source/as_callfunc_xenon.cpp +++ b/src/angelscript/source/as_callfunc_xenon.cpp @@ -50,27 +50,27 @@ // XBox 360 calling convention // =========================== -// I've yet to find an official document with the ABI for XBox 360, +// 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. -// +// 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 +// 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 +// 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. // @@ -119,10 +119,10 @@ BEGIN_AS_NAMESPACE // 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 + ppcENDARG = 0, + ppcINTARG = 1, + ppcFLOATARG = 2, + ppcDOUBLEARG = 3 }; // Loads all data into the correct places and calls the function. @@ -131,601 +131,601 @@ enum argTypes // dwFunc is the address of the function that will be called asQWORD __declspec( naked ) ppcFunc(const asQWORD* pArgs, asDWORD dwFunc, const asBYTE* pArgTypes) { - __asm - { + __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) + // 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 + // 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 + 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 + // 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 + // 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 + // 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 - ld 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: - std 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, 8 // Increment pArgs - b ppcNextArg // Call next arg + // Get the arg from the stack + ld 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: + std 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, 8 // 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 + // 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 + // 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 - } + // 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; + // 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; + // 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; + return (type.GetTokenType() == ttQuestion) ? true : false; } asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) { - // TODO: Xenon does not yet support THISCALL_OBJFIRST/LAST - - 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]; - asQWORD 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() ) - { + // TODO: Xenon does not yet support THISCALL_OBJFIRST/LAST + + 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]; + asQWORD 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].GetTypeInfo()->flags & COMPLEX_MASK ) - { - paramBuffer[dpos++] = args[spos++]; - paramSize++; - } - else + if( descr->parameterTypes[n].GetTypeInfo()->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: The code also ignore the fact that large objects - // passed by value has been copied to the stack - // in the above loop. - - *pCurArgType++ = ppcINTARG; - - *((asQWORD*) pCurFixedArgValue) = *((asUINT*) pCurStackArgValue); - - if( !descr->parameterTypes[n].IsReference() ) - { - // If the arg is not 4 bytes which we coppied, lets do it again the right way - asUINT numBytes = descr->parameterTypes[n].GetSizeInMemoryBytes(); - if( numBytes == 1 ) - { - *((asQWORD*) pCurFixedArgValue) = *((asBYTE*) pCurStackArgValue); - } - else if( numBytes == 2 ) - { - *((asQWORD*) pCurFixedArgValue) = *((asWORD*) pCurStackArgValue); - } - else if( numBytes == 8 ) - { - *((asQWORD*) pCurFixedArgValue) = *((asQWORD*) pCurStackArgValue); - pCurStackArgValue += 4; // Increase our cur stack arg value by 4 bytes to = 8 total later - } - } - - pCurFixedArgValue += 8; - 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; - *((asQWORD*)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; + { + // 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: The code also ignore the fact that large objects + // passed by value has been copied to the stack + // in the above loop. + + *pCurArgType++ = ppcINTARG; + + *((asQWORD*) pCurFixedArgValue) = *((asUINT*) pCurStackArgValue); + + if( !descr->parameterTypes[n].IsReference() ) + { + // If the arg is not 4 bytes which we coppied, lets do it again the right way + asUINT numBytes = descr->parameterTypes[n].GetSizeInMemoryBytes(); + if( numBytes == 1 ) + { + *((asQWORD*) pCurFixedArgValue) = *((asBYTE*) pCurStackArgValue); + } + else if( numBytes == 2 ) + { + *((asQWORD*) pCurFixedArgValue) = *((asWORD*) pCurStackArgValue); + } + else if( numBytes == 8 ) + { + *((asQWORD*) pCurFixedArgValue) = *((asQWORD*) pCurStackArgValue); + pCurStackArgValue += 4; // Increase our cur stack arg value by 4 bytes to = 8 total later + } + } + + pCurFixedArgValue += 8; + 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; + *((asQWORD*)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 diff --git a/src/angelscript/source/as_compiler.cpp b/src/angelscript/source/as_compiler.cpp index 12700c6d8d5..787b02dbe84 100644 --- a/src/angelscript/source/as_compiler.cpp +++ b/src/angelscript/source/as_compiler.cpp @@ -78,9122 +78,9122 @@ BEGIN_AS_NAMESPACE asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine) { - builder = 0; - script = 0; + builder = 0; + script = 0; - variables = 0; - isProcessingDeferredParams = false; - isCompilingDefaultArg = false; - noCodeOutput = 0; + variables = 0; + isProcessingDeferredParams = false; + isCompilingDefaultArg = false; + noCodeOutput = 0; } asCCompiler::~asCCompiler() { - while( variables ) - { - asCVariableScope *var = variables; - variables = variables->parent; - - asDELETE(var,asCVariableScope); - } - - // Clean up all the string constants that were allocated. By now the script - // functions that were compiled successfully already holds their own references - for (asUINT n = 0; n < usedStringConstants.GetLength(); n++) - engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]); - usedStringConstants.SetLength(0); - - // Clean up the temporary script nodes that were allocated during compilation - for (asUINT n = 0; n < nodesToFreeUponComplete.GetLength(); n++) - nodesToFreeUponComplete[n]->Destroy(engine); + while( variables ) + { + asCVariableScope *var = variables; + variables = variables->parent; + + asDELETE(var,asCVariableScope); + } + + // Clean up all the string constants that were allocated. By now the script + // functions that were compiled successfully already holds their own references + for (asUINT n = 0; n < usedStringConstants.GetLength(); n++) + engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]); + usedStringConstants.SetLength(0); + + // Clean up the temporary script nodes that were allocated during compilation + for (asUINT n = 0; n < nodesToFreeUponComplete.GetLength(); n++) + nodesToFreeUponComplete[n]->Destroy(engine); } void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc) { - this->builder = in_builder; - this->engine = in_builder->engine; - this->script = in_script; - this->outFunc = in_outFunc; + this->builder = in_builder; + this->engine = in_builder->engine; + this->script = in_script; + this->outFunc = in_outFunc; - hasCompileErrors = false; + hasCompileErrors = false; - m_isConstructor = false; - m_isConstructorCalled = false; - m_classDecl = 0; - m_globalVar = 0; + m_isConstructor = false; + m_isConstructorCalled = false; + m_classDecl = 0; + m_globalVar = 0; - nextLabel = 0; - breakLabels.SetLength(0); - continueLabels.SetLength(0); + nextLabel = 0; + breakLabels.SetLength(0); + continueLabels.SetLength(0); - numLambdas = 0; + numLambdas = 0; - byteCode.ClearAll(); + byteCode.ClearAll(); } int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl) { - Reset(in_builder, in_script, in_outFunc); + Reset(in_builder, in_script, in_outFunc); - m_classDecl = in_classDecl; + m_classDecl = in_classDecl; - // Insert a JitEntry at the start of the function for JIT compilers - byteCode.InstrPTR(asBC_JitEntry, 0); + // 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(); + // 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); + // 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, in_node); + // 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, in_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); - } + // 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); + // 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; + // 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); + // 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; + // Count total variable size + int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1; + outFunc->scriptData->variableSpace = varSize; - FinalizeFunction(); + FinalizeFunction(); #ifdef AS_DEBUG - // DEBUG: output byte code - byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc); + // DEBUG: output byte code + byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc); #endif - return 0; + return 0; } int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc) { - Reset(in_builder, in_script, in_outFunc); - - // Insert a JitEntry at the start of the function for JIT compilers - byteCode.InstrPTR(asBC_JitEntry, 0); - - // Find the corresponding constructor - asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), 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.GetTypeInfo(), 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; + Reset(in_builder, in_script, in_outFunc); + + // Insert a JitEntry at the start of the function for JIT compilers + byteCode.InstrPTR(asBC_JitEntry, 0); + + // Find the corresponding constructor + asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), 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.GetTypeInfo(), 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); + // DEBUG: output byte code + asCString args; + args.Format("%d", outFunc->parameterTypes.GetLength()); + byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine); #endif */ - return 0; + return 0; } void asCCompiler::FinalizeFunction() { - TimeIt("asCCompiler::FinalizeFunction"); - - asASSERT( outFunc->scriptData ); - asUINT n; - - // Finalize the bytecode - byteCode.Finalize(tempVariableOffsets); - - // extract the try/catch info before object variable info, as - // some variable info is not needed if there are no try/catch blocks - byteCode.ExtractTryCatchInfo(outFunc); - - byteCode.ExtractObjectVariableInfo(outFunc); - - // Compile the list of object variables for the exception handler - // 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].IsFuncdef()) && !variableAllocations[n].IsReference() ) - { - if( variableIsOnHeap[n] ) - { - outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo()); - 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].IsFuncdef()) && !variableAllocations[n].IsReference() ) - { - if( !variableIsOnHeap[n] ) - { - outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo()); - 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); - } - } + TimeIt("asCCompiler::FinalizeFunction"); + + asASSERT( outFunc->scriptData ); + asUINT n; + + // Finalize the bytecode + byteCode.Finalize(tempVariableOffsets); + + // extract the try/catch info before object variable info, as + // some variable info is not needed if there are no try/catch blocks + byteCode.ExtractTryCatchInfo(outFunc); + + byteCode.ExtractObjectVariableInfo(outFunc); + + // Compile the list of object variables for the exception handler + // 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].IsFuncdef()) && !variableAllocations[n].IsReference() ) + { + if( variableIsOnHeap[n] ) + { + outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo()); + 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].IsFuncdef()) && !variableAllocations[n].IsReference() ) + { + if( !variableIsOnHeap[n] ) + { + outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo()); + 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() && - !returnType.IsReference() && - !returnType.IsObjectHandle() ) - { - // TODO: Hasn't this been validated by the builder already? - asCString str; - str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).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(outFunc->nameSpace); - 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; + 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() && + !returnType.IsReference() && + !returnType.IsObjectHandle() ) + { + // TODO: Hasn't this been validated by the builder already? + asCString str; + str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).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(outFunc->nameSpace); + 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 *bc, 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 - asCParser parser(builder); - 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; + 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 + asCParser parser(builder); + 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; + // 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 - int r = parser.ParseVarInit(initScript, initNode); - if( r < 0 ) - continue; + // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier + int r = parser.ParseVarInit(initScript, initNode); + if( r < 0 ) + continue; - initNode = parser.GetScriptNode(); + initNode = parser.GetScriptNode(); #endif - } - else - { - if( !onlyDefaults ) - continue; - } + } + 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.GetTypeInfo()->flags & asOBJ_REF) && - prop->type.GetBehaviour()->factory == 0) || - ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && - prop->type.GetBehaviour()->construct == 0 && - !(prop->type.GetTypeInfo()->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.GetTypeInfo()->GetName()); - Error(str, declNode); - } + // 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.GetTypeInfo()->flags & asOBJ_REF) && + prop->type.GetBehaviour()->factory == 0) || + ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && + prop->type.GetBehaviour()->construct == 0 && + !(prop->type.GetTypeInfo()->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.GetTypeInfo()->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(bc, declNode->tokenPos); - - // Compile the initialization - asQWORD constantValue; - asCByteCode bcInit(engine); - CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2); - bcInit.OptimizeLocally(tempVariableOffsets); - bc->AddCode(&bcInit); - - script = origScript; + // 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(bc, declNode->tokenPos); + + // Compile the initialization + asQWORD constantValue; + asCByteCode bcInit(engine); + CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2); + bcInit.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&bcInit); + + script = origScript; #endif - } - } + } + } } // Entry int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl) { - TimeIt("asCCompiler::CompileFunction"); - - Reset(in_builder, in_script, in_outFunc); - int buildErrors = builder->numErrors; - - int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func); - - //-------------------------------------------- - // Compile the statement block - - if( m_isConstructor ) - m_classDecl = in_classDecl; - - // We need to parse the statement block now - asCScriptNode *blockBegin; - - // If the function signature was implicit, e.g. virtual property accessor or - // lambda function, then the received node already is the statement block - if( in_func->nodeType != snStatementBlock ) - blockBegin = in_func->lastChild; - else - blockBegin = in_func; - - // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory - // TODO: optimize: For large functions, the parsing of the statement block can take a long time. Presumably because a lot of memory needs to be allocated - 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, in_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(); + TimeIt("asCCompiler::CompileFunction"); + + Reset(in_builder, in_script, in_outFunc); + int buildErrors = builder->numErrors; + + int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func); + + //-------------------------------------------- + // Compile the statement block + + if( m_isConstructor ) + m_classDecl = in_classDecl; + + // We need to parse the statement block now + asCScriptNode *blockBegin; + + // If the function signature was implicit, e.g. virtual property accessor or + // lambda function, then the received node already is the statement block + if( in_func->nodeType != snStatementBlock ) + blockBegin = in_func->lastChild; + else + blockBegin = in_func; + + // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory + // TODO: optimize: For large functions, the parsing of the statement block can take a long time. Presumably because a lot of memory needs to be allocated + 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, in_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(), in_outFunc); - else - byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc); + // DEBUG: output byte code + if( outFunc->objectType ) + byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc); + else + byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc); #endif - return 0; + return 0; } int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *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.GetTypeInfo() == type.GetTypeInfo() ); - - // Since we're calling the copy constructor, we have to trust the function to not do - // anything stupid otherwise we will just enter a loop, as we try to make temporary - // copies of the argument in order to guarantee safety. - - - if( type.GetTypeInfo()->flags & asOBJ_REF ) - { - asCExprContext 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, CastToObjectType(type.GetTypeInfo()), true, offset); - - // Pop the reference left by the function call - ctx.bc.Instr(asBC_PopPtr); - } - else - { - // Call factory - PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo())); - - // Store the returned handle in the global variable - ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); - ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); - 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); - } - } - - asCExprContext ctx(engine); - PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo())); - - 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.GetTypeInfo()->GetName()); - Error(str, node); - - return -1; + 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.GetTypeInfo() == type.GetTypeInfo() ); + + // Since we're calling the copy constructor, we have to trust the function to not do + // anything stupid otherwise we will just enter a loop, as we try to make temporary + // copies of the argument in order to guarantee safety. + + + if( type.GetTypeInfo()->flags & asOBJ_REF ) + { + asCExprContext 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, CastToObjectType(type.GetTypeInfo()), true, offset); + + // Pop the reference left by the function call + ctx.bc.Instr(asBC_PopPtr); + } + else + { + // Call factory + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo())); + + // Store the returned handle in the global variable + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); + 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); + } + } + + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo())); + + 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.GetTypeInfo()->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.GetTypeInfo()->flags & asOBJ_REF ) - { - asCExprContext 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, CastToObjectType(type.GetTypeInfo())); - - 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, CastToObjectType(type.GetTypeInfo()), true, offset); - - // Pop the reference left by the function call - ctx.bc.Instr(asBC_PopPtr); - } - else - { - // Call factory - PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo())); - - // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination - // instead of first storing it in a local variable and then copying it to the - // destination. - - if( !(type.GetTypeInfo()->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::CreateType(outFunc->objectType, false))); - } - - if( type.GetTypeInfo()->flags & asOBJ_SCOPED ) - { - // For scoped typed we must move the reference from the local - // variable rather than copy it as there is no AddRef behaviour - 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 - { - if( type.IsFuncdef() ) - ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); - } - ctx.bc.Instr(asBC_PopPtr); - ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); - } - - bc->AddCode(&ctx.bc); - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n], asCExprContext); - } - - return 0; - } - } - else - { - asCExprContext 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.GetTypeInfo()->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, CastToObjectType(type.GetTypeInfo())); - - 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); - - asCExprContext ctxCall(engine); - PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo())); - bc->AddCode(&ctxCall.bc); - - // TODO: value on stack: This probably needs to be done in PerformFunctionCall - // Mark the object as initialized - bc->ObjInfo(offset, asOBJ_INIT); - } - } - else if( isVarGlobOrMem == 2 ) - { - // Only POD types can be allocated inline in script classes - asASSERT( type.GetTypeInfo()->flags & asOBJ_POD ); - - if( func ) - { - // Call the constructor as a normal function - bc->InstrSHORT(asBC_PSF, 0); - bc->Instr(asBC_RDSPtr); - bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); - - asCExprContext ctxCall(engine); - PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo())); - bc->AddCode(&ctxCall.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::CreateType(outFunc->objectType, false))); - } - - if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) - { - asCScriptFunction *descr = engine->scriptFunctions[func]; - asASSERT( descr->funcType == asFUNC_SCRIPT ); - - // Find the id of the real constructor and not the generated stub - asUINT id = 0; - asDWORD *funcBc = descr->scriptData->byteCode.AddressOf(); - while( funcBc ) - { - if( (*(asBYTE*)funcBc) == asBC_CALLSYS ) - { - id = asBC_INTARG(funcBc); - break; - } - funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type]; - } - - asASSERT( id ); - - bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo()); - bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE); - } - else - bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE); - } - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n], asCExprContext); - } - - return 0; - } - } - - // Class has no default factory/constructor. - asCString str; - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName()); - Error(str, node); - - return -1; + if( !type.IsObject() || type.IsObjectHandle() ) + return 0; + + if( type.GetTypeInfo()->flags & asOBJ_REF ) + { + asCExprContext 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, CastToObjectType(type.GetTypeInfo())); + + 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, CastToObjectType(type.GetTypeInfo()), true, offset); + + // Pop the reference left by the function call + ctx.bc.Instr(asBC_PopPtr); + } + else + { + // Call factory + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo())); + + // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination + // instead of first storing it in a local variable and then copying it to the + // destination. + + if( !(type.GetTypeInfo()->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::CreateType(outFunc->objectType, false))); + } + + if( type.GetTypeInfo()->flags & asOBJ_SCOPED ) + { + // For scoped typed we must move the reference from the local + // variable rather than copy it as there is no AddRef behaviour + 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 + { + if( type.IsFuncdef() ) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); + } + ctx.bc.Instr(asBC_PopPtr); + ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); + } + + bc->AddCode(&ctx.bc); + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + + return 0; + } + } + else + { + asCExprContext 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.GetTypeInfo()->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, CastToObjectType(type.GetTypeInfo())); + + 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); + + asCExprContext ctxCall(engine); + PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo())); + bc->AddCode(&ctxCall.bc); + + // TODO: value on stack: This probably needs to be done in PerformFunctionCall + // Mark the object as initialized + bc->ObjInfo(offset, asOBJ_INIT); + } + } + else if( isVarGlobOrMem == 2 ) + { + // Only POD types can be allocated inline in script classes + asASSERT( type.GetTypeInfo()->flags & asOBJ_POD ); + + if( func ) + { + // Call the constructor as a normal function + bc->InstrSHORT(asBC_PSF, 0); + bc->Instr(asBC_RDSPtr); + bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + + asCExprContext ctxCall(engine); + PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo())); + bc->AddCode(&ctxCall.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::CreateType(outFunc->objectType, false))); + } + + if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) + { + asCScriptFunction *descr = engine->scriptFunctions[func]; + asASSERT( descr->funcType == asFUNC_SCRIPT ); + + // Find the id of the real constructor and not the generated stub + asUINT id = 0; + asDWORD *funcBc = descr->scriptData->byteCode.AddressOf(); + while( funcBc ) + { + if( (*(asBYTE*)funcBc) == asBC_CALLSYS ) + { + id = asBC_INTARG(funcBc); + break; + } + funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type]; + } + + asASSERT( id ); + + bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo()); + bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE); + } + else + bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE); + } + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + + return 0; + } + } + + // Class has no default factory/constructor. + asCString str; + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->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() || type.IsFuncdef() ) - { - // The null pointer doesn't need to be destroyed - if( type.IsNullHandle() ) - return; - - // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method - if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN ) - return; - - if( isObjectOnHeap || type.IsObjectHandle() ) - { - // Free the memory - if (type.IsFuncdef()) - bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours); - else - bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo()); - } - else - { - asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE ); - - if( type.GetBehaviour()->destruct ) - { - // Call the destructor as a regular function - asCExprContext 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); - } - } - } + if( !type.IsReference() ) + { + // Call destructor for the data type + if( type.IsObject() || type.IsFuncdef() ) + { + // The null pointer doesn't need to be destroyed + if( type.IsNullHandle() ) + return; + + // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method + if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN ) + return; + + if( isObjectOnHeap || type.IsObjectHandle() ) + { + // Free the memory + if (type.IsFuncdef()) + bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours); + else + bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo()); + } + else + { + asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE ); + + if( type.GetBehaviour()->destruct ) + { + // Call the destructor as a regular function + asCExprContext 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); + 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 ) - { + *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); + // 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); - } + 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 *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc) { - Reset(in_builder, in_script, in_outFunc); - m_globalVar = in_gvar; - - // Add a variable scope (even though variables can't be declared) - AddVariableScope(); - - in_gvar->isPureConstant = false; - - // Parse the initialization nodes - asCParser parser(builder); - if (in_node) - { - int r = parser.ParseVarInit(in_script, in_node); - if (r < 0) - return r; - - in_node = parser.GetScriptNode(); - } - - asCExprContext compiledCtx(engine); - bool preCompiled = false; - if (in_gvar->datatype.IsAuto()) - { - preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode); - if (!preCompiled) - { - // If it wasn't possible to determine the type from the expression then there - // is no need to continue with the initialization. The error was already reported - // in CompileAutoType. - return -1; - } - } - if( in_gvar->property == 0 ) - { - in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns); - in_gvar->index = in_gvar->property->id; - } - - // Compile the expression - asCExprContext ctx(engine); - asQWORD constantValue = 0; - if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) ) - { - // Should the variable be marked as pure constant? - if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() ) - { - in_gvar->isPureConstant = true; - in_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( in_gvar->declaredAtNode ) - pos = in_gvar->declaredAtNode->tokenPos; - else if( in_gvar->initializationNode ) - pos = in_gvar->initializationNode->tokenPos; - LineInstr(&byteCode, pos); - - // Reserve space for all local variables - 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(); + Reset(in_builder, in_script, in_outFunc); + m_globalVar = in_gvar; + + // Add a variable scope (even though variables can't be declared) + AddVariableScope(); + + in_gvar->isPureConstant = false; + + // Parse the initialization nodes + asCParser parser(builder); + if (in_node) + { + int r = parser.ParseVarInit(in_script, in_node); + if (r < 0) + return r; + + in_node = parser.GetScriptNode(); + } + + asCExprContext compiledCtx(engine); + bool preCompiled = false; + if (in_gvar->datatype.IsAuto()) + { + preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode); + if (!preCompiled) + { + // If it wasn't possible to determine the type from the expression then there + // is no need to continue with the initialization. The error was already reported + // in CompileAutoType. + return -1; + } + } + if( in_gvar->property == 0 ) + { + in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns); + in_gvar->index = in_gvar->property->id; + } + + // Compile the expression + asCExprContext ctx(engine); + asQWORD constantValue = 0; + if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) ) + { + // Should the variable be marked as pure constant? + if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() ) + { + in_gvar->isPureConstant = true; + in_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( in_gvar->declaredAtNode ) + pos = in_gvar->declaredAtNode->tokenPos; + else if( in_gvar->initializationNode ) + pos = in_gvar->initializationNode->tokenPos; + LineInstr(&byteCode, pos); + + // Reserve space for all local variables + 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_" + in_gvar->name + ".txt").AddressOf(), outFunc); + // DEBUG: output byte code + byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc); #endif - return 0; + return 0; } void asCCompiler::DetermineSingleFunc(asCExprContext *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::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false)); - ctx->type.dataType.MakeHandle(true); - ctx->type.isExplicitHandle = true; - ctx->methodName = ""; + // 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::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false)); + ctx->type.dataType.MakeHandle(true); + ctx->type.isExplicitHandle = true; + ctx->methodName = ""; } void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination) { - bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset); - - // Use copy constructor if available. - asCObjectType *ot = CastToObjectType(dt.GetTypeInfo()); - if(!dt.IsObjectHandle() && ot && (ot->beh.copyconstruct || ot->beh.copyfactory)) - { - 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: 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); - asCExprValue 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() || type.dataType.IsFuncdef() ) - 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); - } + bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset); + + // Use copy constructor if available. + asCObjectType *ot = CastToObjectType(dt.GetTypeInfo()); + if(!dt.IsObjectHandle() && ot && (ot->beh.copyconstruct || ot->beh.copyfactory)) + { + 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: 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); + asCExprValue 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() || type.dataType.IsFuncdef() ) + 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, asCExprContext *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->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.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->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); - - int offset; - if( refType == asTM_INREF ) - { - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - // 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() ) - { - // Make sure the argument type can support handles (or is itself a handle) - if( !dt.SupportHandles() && !dt.IsObjectHandle() ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - - ctx->type.Set(param); - return -1; - } - - // 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); - dt.MakeReadOnly(false); - 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); - ctx->type.isExplicitHandle = true; - } - else - { - IsVariableInitialized(&ctx->type, node); - - if( !isMakingCopy ) - { - // For parameters expecting a reference to a handle we need to make sure the argument - // is really a handle, and not just a reference to the object. Do this check before the - // implicit conversion so it can be treated correctly. - if (dt.IsObjectHandle() && !ctx->type.dataType.IsObjectHandle()) - { - // Make a refCopy into a local handle variable - // Allocate a handle variable - dt.MakeHandle(true); - dt.MakeReadOnly(false); - offset = AllocateVariableNotIn(dt, true, false, ctx); - - // Copy the handle - Dereference(ctx, true); - ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - if (ctx->type.dataType.IsFuncdef()) - ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - - // Release the original temporary variable - if( ctx->type.isTemporary ) - ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc); - - ctx->type.SetVariable(dt, offset, true); - } - - // 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(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).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 therefore guaranteed not to be modified by the - // function, then it is enough that the variable is local to guarantee the lifetime. - if( !ctx->type.isTemporary && !(param.IsReadOnly() && (ctx->type.isVariable || ctx->type.isRefSafe)) ) - { - if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) ) - { - // Funcdefs only need an extra handle to guarantee the lifetime. - - // If the object is a reference type (except scoped reference types), and the - // parameter is a const reference, then it is not necessary to make a copy of the - // object. The compiler just needs to hold a handle to guarantee the lifetime. - - // Allocate a handle variable - dt.MakeHandle(true); - dt.MakeReadOnly(false); - offset = AllocateVariableNotIn(dt, true, false, ctx); - - // Copy the handle - Dereference(ctx, true); - ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - if (ctx->type.dataType.IsFuncdef()) - ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - - // The type should be set to the param type instead of dt to guarantee - // that the expression keeps the correct type for variable ? args. Otherwise - // MoveArgsToStack will use the wrong bytecode to move the arg to the stack - bool isExplicitHandle = ctx->type.isExplicitHandle; - ctx->type.SetVariable(param, offset, true); - ctx->type.dataType.MakeHandle(true); - ctx->type.isExplicitHandle = isExplicitHandle; - } - else - { - // Make a copy of the object to guarantee that the original isn't modified - asASSERT(!dt.IsFuncdef()); - - // Allocate and initialize a temporary local object - dt.MakeReadOnly(false); - 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); - } - } - - // When calling a function expecting a var arg with a parameter received as reference to handle - // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will - // not be able to do the correct double dereference to put the reference to the object on the stack. - if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable) - { - sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset); - if (var && var->type.IsReference() && var->type.IsObjectHandle()) - { - // Copy the handle to local variable - - // Allocate a handle variable - dt.MakeHandle(true); - dt.MakeReadOnly(false); - offset = AllocateVariableNotIn(dt, true, false, ctx); - - // Copy the handle - Dereference(ctx, true); - ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - if (ctx->type.dataType.IsFuncdef()) - ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - - // The type should be set to the param type instead of dt to guarantee - // that the expression keeps the correct type for variable ? args. Otherwise - // MoveArgsToStack will use the wrong bytecode to move the arg to the stack - ctx->type.SetVariable(param, offset, true); - } - } - } - else - { - // We must guarantee that the address to the value is on the stack - if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && - !ctx->type.dataType.IsObjectHandle() && - ctx->type.dataType.IsReference() ) - Dereference(ctx, true); - } - } - } - else if( refType == asTM_OUTREF ) - { - // 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 the expression is marked as clean, then it can be used directly - // without the need to allocate another temporary value as it is known - // that the argument has no other value than the default - if( ctx->isCleanArg ) - { - // Must be a local variable - asASSERT( ctx->type.isVariable ); - } - else - { - // Null handles and void expressions must be marked as explicit - // handles for correct treatement in MoveArgsToStack - if (dt.IsNullHandle()) - ctx->type.isExplicitHandle = true; - - // Make sure the variable is not used in the expression - dt.MakeReadOnly(false); - offset = AllocateVariableNotIn(dt, true, false, ctx); - - if( dt.IsPrimitive() ) - { - ctx->type.SetVariable(dt, offset, true); - PushVariableOnStack(ctx, true); - } - else - { - // 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.IsFuncdef()) || dt.IsObjectHandle()); - asCExprValue type; - type.Set(dt); - type.isTemporary = true; - type.stackOffset = (short)offset; - - type.isExplicitHandle = ctx->type.isExplicitHandle; - ctx->type = type; - - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - if( (dt.IsObject() || dt.IsFuncdef()) && !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 ) - { - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - // 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 && - !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) ) - { - // 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; - } - } - - // Allow anonymous init lists to be converted to the arg type - if( ctx->IsAnonymousInitList() ) - ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, true); - - if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() ) - ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false); - - // Only objects that support object handles - // 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.IsFuncdef()) && - !ctx->type.dataType.IsObjectHandle() && - ((ctx->type.dataType.GetBehaviour()->addref && - ctx->type.dataType.GetBehaviour()->release) || - (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) || - ctx->type.dataType.IsFuncdef()) ) - { - // Store a handle to the object as local variable - asCExprContext tmp(engine); - dt = ctx->type.dataType; - dt.MakeHandle(true); - dt.MakeReference(false); - dt.MakeReadOnly(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); - if( ctx->type.dataType.IsFuncdef() ) - ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); - - 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.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() ) - Dereference(ctx, true); - else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) ) - ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); - else if( ctx->type.dataType.IsPrimitive() ) - ctx->bc.Instr(asBC_PshRPtr); - else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() ) - ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false); - } - } - else - { - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - 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(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - - ctx->type.Set(dt); - return -1; - } - - if( dt.IsObjectHandle() ) - ctx->type.isExplicitHandle = true; - - if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !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 the called function. - - // Handles passed by value must also be placed in a temporary variable - // to guarantee that the object referred to isn't freed too early. - - // TODO: value on stack: How can we avoid this unnecessary allocation? - - // Don't make temporary copies of handles if it is going to be used - // for handle assignment anyway, i.e. REFCPY. - if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) ) - PrepareTemporaryVariable(node, ctx, true); - } - } - } - - // Don't put any pointer on the stack yet - if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) ) - { - // &inout parameter may leave the reference on the stack already - // references considered safe too, i.e. when the life time is known - if( refType != asTM_INOUTREF && !ctx->type.isRefSafe ) - { - asASSERT( ctx->type.isVariable || ctx->type.isRefSafe || 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; + 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->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.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->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); + + int offset; + if( refType == asTM_INREF ) + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // 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() ) + { + // Make sure the argument type can support handles (or is itself a handle) + if( !dt.SupportHandles() && !dt.IsObjectHandle() ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + ctx->type.Set(param); + return -1; + } + + // 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); + dt.MakeReadOnly(false); + 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); + ctx->type.isExplicitHandle = true; + } + else + { + IsVariableInitialized(&ctx->type, node); + + if( !isMakingCopy ) + { + // For parameters expecting a reference to a handle we need to make sure the argument + // is really a handle, and not just a reference to the object. Do this check before the + // implicit conversion so it can be treated correctly. + if (dt.IsObjectHandle() && !ctx->type.dataType.IsObjectHandle()) + { + // Make a refCopy into a local handle variable + // Allocate a handle variable + dt.MakeHandle(true); + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Copy the handle + Dereference(ctx, true); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + if (ctx->type.dataType.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + // Release the original temporary variable + if( ctx->type.isTemporary ) + ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc); + + ctx->type.SetVariable(dt, offset, true); + } + + // 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(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).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 therefore guaranteed not to be modified by the + // function, then it is enough that the variable is local to guarantee the lifetime. + if( !ctx->type.isTemporary && !(param.IsReadOnly() && (ctx->type.isVariable || ctx->type.isRefSafe)) ) + { + if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) ) + { + // Funcdefs only need an extra handle to guarantee the lifetime. + + // If the object is a reference type (except scoped reference types), and the + // parameter is a const reference, then it is not necessary to make a copy of the + // object. The compiler just needs to hold a handle to guarantee the lifetime. + + // Allocate a handle variable + dt.MakeHandle(true); + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Copy the handle + Dereference(ctx, true); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + if (ctx->type.dataType.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + // The type should be set to the param type instead of dt to guarantee + // that the expression keeps the correct type for variable ? args. Otherwise + // MoveArgsToStack will use the wrong bytecode to move the arg to the stack + bool isExplicitHandle = ctx->type.isExplicitHandle; + ctx->type.SetVariable(param, offset, true); + ctx->type.dataType.MakeHandle(true); + ctx->type.isExplicitHandle = isExplicitHandle; + } + else + { + // Make a copy of the object to guarantee that the original isn't modified + asASSERT(!dt.IsFuncdef()); + + // Allocate and initialize a temporary local object + dt.MakeReadOnly(false); + 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); + } + } + + // When calling a function expecting a var arg with a parameter received as reference to handle + // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will + // not be able to do the correct double dereference to put the reference to the object on the stack. + if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable) + { + sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset); + if (var && var->type.IsReference() && var->type.IsObjectHandle()) + { + // Copy the handle to local variable + + // Allocate a handle variable + dt.MakeHandle(true); + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Copy the handle + Dereference(ctx, true); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + if (ctx->type.dataType.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + // The type should be set to the param type instead of dt to guarantee + // that the expression keeps the correct type for variable ? args. Otherwise + // MoveArgsToStack will use the wrong bytecode to move the arg to the stack + ctx->type.SetVariable(param, offset, true); + } + } + } + else + { + // We must guarantee that the address to the value is on the stack + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && + !ctx->type.dataType.IsObjectHandle() && + ctx->type.dataType.IsReference() ) + Dereference(ctx, true); + } + } + } + else if( refType == asTM_OUTREF ) + { + // 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 the expression is marked as clean, then it can be used directly + // without the need to allocate another temporary value as it is known + // that the argument has no other value than the default + if( ctx->isCleanArg ) + { + // Must be a local variable + asASSERT( ctx->type.isVariable ); + } + else + { + // Null handles and void expressions must be marked as explicit + // handles for correct treatement in MoveArgsToStack + if (dt.IsNullHandle()) + ctx->type.isExplicitHandle = true; + + // Make sure the variable is not used in the expression + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + if( dt.IsPrimitive() ) + { + ctx->type.SetVariable(dt, offset, true); + PushVariableOnStack(ctx, true); + } + else + { + // 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.IsFuncdef()) || dt.IsObjectHandle()); + asCExprValue type; + type.Set(dt); + type.isTemporary = true; + type.stackOffset = (short)offset; + + type.isExplicitHandle = ctx->type.isExplicitHandle; + ctx->type = type; + + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + if( (dt.IsObject() || dt.IsFuncdef()) && !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 ) + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // 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 && + !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) ) + { + // 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; + } + } + + // Allow anonymous init lists to be converted to the arg type + if( ctx->IsAnonymousInitList() ) + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, true); + + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() ) + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false); + + // Only objects that support object handles + // 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.IsFuncdef()) && + !ctx->type.dataType.IsObjectHandle() && + ((ctx->type.dataType.GetBehaviour()->addref && + ctx->type.dataType.GetBehaviour()->release) || + (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) || + ctx->type.dataType.IsFuncdef()) ) + { + // Store a handle to the object as local variable + asCExprContext tmp(engine); + dt = ctx->type.dataType; + dt.MakeHandle(true); + dt.MakeReference(false); + dt.MakeReadOnly(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); + if( ctx->type.dataType.IsFuncdef() ) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + 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.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() ) + Dereference(ctx, true); + else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) ) + ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); + else if( ctx->type.dataType.IsPrimitive() ) + ctx->bc.Instr(asBC_PshRPtr); + else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() ) + ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false); + } + } + else + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + 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(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + ctx->type.Set(dt); + return -1; + } + + if( dt.IsObjectHandle() ) + ctx->type.isExplicitHandle = true; + + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !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 the called function. + + // Handles passed by value must also be placed in a temporary variable + // to guarantee that the object referred to isn't freed too early. + + // TODO: value on stack: How can we avoid this unnecessary allocation? + + // Don't make temporary copies of handles if it is going to be used + // for handle assignment anyway, i.e. REFCPY. + if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) ) + PrepareTemporaryVariable(node, ctx, true); + } + } + } + + // Don't put any pointer on the stack yet + if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) ) + { + // &inout parameter may leave the reference on the stack already + // references considered safe too, i.e. when the life time is known + if( refType != asTM_INOUTREF && !ctx->type.isRefSafe ) + { + asASSERT( ctx->type.isVariable || ctx->type.isRefSafe || 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; } int 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); - - asASSERT( descr->parameterTypes.GetLength() == args.GetLength() ); - - // 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->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) || - (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) ) - makingCopy = true; - - // Add code for arguments - asCExprContext e(engine); - for( int n = (int)args.GetLength()-1; n >= 0; n-- ) - { - // Make sure PrepareArgument doesn't use any variable that is already - // being used by the argument or any of the following argument expressions - int l = int(reservedVariables.GetLength()); - for( int m = n; m >= 0; m-- ) - args[m]->bc.GetVarsUsed(reservedVariables); - - int r = PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy); - reservedVariables.SetLength(l); - - if (r < 0) - return r; - } - - bc->AddCode(&e.bc); - - return 0; + // When a match has been found, compile the final byte code using correct parameter types + asCScriptFunction *descr = builder->GetFunctionDescription(funcId); + + asASSERT( descr->parameterTypes.GetLength() == args.GetLength() ); + + // 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->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) || + (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) ) + makingCopy = true; + + // Add code for arguments + asCExprContext e(engine); + for( int n = (int)args.GetLength()-1; n >= 0; n-- ) + { + // Make sure PrepareArgument doesn't use any variable that is already + // being used by the argument or any of the following argument expressions + int l = int(reservedVariables.GetLength()); + for( int m = n; m >= 0; m-- ) + args[m]->bc.GetVarsUsed(reservedVariables); + + int r = PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy); + reservedVariables.SetLength(l); + + if (r < 0) + return r; + } + + bc->AddCode(&e.bc); + + return 0; } void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset) { - asCScriptFunction *descr = builder->GetFunctionDescription(funcId); + asCScriptFunction *descr = builder->GetFunctionDescription(funcId); - int offset = 0; - if( addOneToOffset ) - offset += AS_PTR_SIZE; + 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; + // 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->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) || - (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) ) - makingCopy = true; + // 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->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) || + (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) ) + makingCopy = true; #endif - // 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].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() ) - { - if( descr->inOutFlags[n] != asTM_INOUTREF && !args[n]->type.isRefSafe ) - { + // 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].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() ) + { + if( descr->inOutFlags[n] != asTM_INOUTREF && !args[n]->type.isRefSafe ) + { #ifdef AS_DEBUG - // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode - asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy ); + // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode + asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy ); #endif - 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 the argument is already known to be safe, i.e. has a guaranteed lifetime, - // then the address on the stack is already pointing to the correct object so no - // need to do anything else - if (!args[n]->type.isRefSafe) - { - if (descr->parameterTypes[n].GetTokenType() == ttQuestion && - (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) && - !args[n]->type.dataType.IsObjectHandle()) - { - // Send the object as a reference to the object, - // and not to the variable holding the object - 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 if (descr->parameterTypes[n].GetTokenType() == ttQuestion && - args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle) - { - // The object handle is being passed as an object, so dereference it before - // the call so the reference will be to the object rather than to the handle - if (engine->ep.disallowValueAssignForRefType) - { - // With disallow value assign all ref type objects are always passed by handle - bc->InstrWORD(asBC_GETREF, (asWORD)offset); - } - else - bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); - } - else - { - // If the variable is really an argument of @& type, then it is necessary - // to use asBC_GETOBJREF so the pointer is correctly dereferenced. - sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset); - if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle()) - bc->InstrWORD(asBC_GETREF, (asWORD)offset); - else - bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); - } - } - } - } - else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() ) - { - asASSERT(!args[n]->type.isRefSafe); - - // TODO: value on stack: What can we do to avoid this unnecessary allocation? - // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx - asASSERT(IsVariableOnHeap(args[n]->type.stackOffset)); - - // The pointer in the variable will be moved to the stack - bc->InstrWORD(asBC_GETOBJ, (asWORD)offset); - - // Deallocate the variable slot so it can be reused, but do not attempt to - // free the content of the variable since it was moved to the stack for the call - DeallocateVariable(args[n]->type.stackOffset); - args[n]->type.isTemporary = false; - } - - offset += descr->parameterTypes[n].GetSizeOnStackDWords(); - } + 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 the argument is already known to be safe, i.e. has a guaranteed lifetime, + // then the address on the stack is already pointing to the correct object so no + // need to do anything else + if (!args[n]->type.isRefSafe) + { + if (descr->parameterTypes[n].GetTokenType() == ttQuestion && + (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) && + !args[n]->type.dataType.IsObjectHandle()) + { + // Send the object as a reference to the object, + // and not to the variable holding the object + 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 if (descr->parameterTypes[n].GetTokenType() == ttQuestion && + args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle) + { + // The object handle is being passed as an object, so dereference it before + // the call so the reference will be to the object rather than to the handle + if (engine->ep.disallowValueAssignForRefType) + { + // With disallow value assign all ref type objects are always passed by handle + bc->InstrWORD(asBC_GETREF, (asWORD)offset); + } + else + bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); + } + else + { + // If the variable is really an argument of @& type, then it is necessary + // to use asBC_GETOBJREF so the pointer is correctly dereferenced. + sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset); + if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle()) + bc->InstrWORD(asBC_GETREF, (asWORD)offset); + else + bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); + } + } + } + } + else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() ) + { + asASSERT(!args[n]->type.isRefSafe); + + // TODO: value on stack: What can we do to avoid this unnecessary allocation? + // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx + asASSERT(IsVariableOnHeap(args[n]->type.stackOffset)); + + // The pointer in the variable will be moved to the stack + bc->InstrWORD(asBC_GETOBJ, (asWORD)offset); + + // Deallocate the variable slot so it can be reused, but do not attempt to + // free the content of the variable since it was moved to the stack for the call + DeallocateVariable(args[n]->type.stackOffset); + args[n]->type.isTemporary = false; + } + + 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; - - asCExprContext expr(engine); - int r = CompileAssignment(asgNode, &expr); - if( r < 0 ) anyErrors = true; - - asCExprContext *ctx = asNEW(asCExprContext)(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 a = 0; a < namedArgs.GetLength(); ++a ) - { - if( namedArgs[a].name == namedArg.name ) - { - Error(TXT_DUPLICATE_NAMED_ARG, asgNode); - anyErrors = true; - break; - } - } - - namedArgs.PushLast(namedArg); - } - - arg = arg->prev; - } - - return anyErrors ? -1 : 0; + 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; + + asCExprContext expr(engine); + int r = CompileAssignment(asgNode, &expr); + if( r < 0 ) anyErrors = true; + + asCExprContext *ctx = asNEW(asCExprContext)(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 a = 0; a < namedArgs.GetLength(); ++a ) + { + if( namedArgs[a].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; - int prevReservedVars = reservedVariables.GetLength(); - - int explicitArgs = (int)args.GetLength(); - - for( int p = 0; p < explicitArgs; p++ ) - args[p]->bc.GetVarsUsed(reservedVariables); - - // 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(reservedVariables); - - // 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 = builder->FindOrAddCode("default arg", func->defaultArgs[n]->AddressOf(), func->defaultArgs[n]->GetLength()); - 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 - isCompilingDefaultArg = true; - - // Temporarily set the namespace in the output function to the namespace of the called - // function so that the default arguments are evaluated in the correct namespace - asSNameSpace *origNameSpace = outFunc->nameSpace; - outFunc->nameSpace = func->nameSpace; - - asCExprContext expr(engine); - r = CompileExpression(arg, &expr); - - // Restore the namespace - outFunc->nameSpace = origNameSpace; - - // Don't allow address of class method - if( expr.IsClassMethod() ) - { - // 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(asCExprContext)(engine); - if( args[n] == 0 ) - { - // Out of memory - reservedVariables.SetLength(prevReservedVars); - return -1; - } - - MergeExprBytecodeAndType(args[n], &expr); - if (args[n]->exprNode) - { - // Disconnect the node from the parser, and tell the compiler to free it when complete - args[n]->exprNode->DisconnectParent(); - nodesToFreeUponComplete.PushLast(args[n]->exprNode); - } - } - - reservedVariables.SetLength(prevReservedVars); - return anyErrors ? -1 : 0; + 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; + int prevReservedVars = reservedVariables.GetLength(); + + int explicitArgs = (int)args.GetLength(); + + for( int p = 0; p < explicitArgs; p++ ) + args[p]->bc.GetVarsUsed(reservedVariables); + + // 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(reservedVariables); + + // 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 = builder->FindOrAddCode("default arg", func->defaultArgs[n]->AddressOf(), func->defaultArgs[n]->GetLength()); + 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 + isCompilingDefaultArg = true; + + // Temporarily set the namespace in the output function to the namespace of the called + // function so that the default arguments are evaluated in the correct namespace + asSNameSpace *origNameSpace = outFunc->nameSpace; + outFunc->nameSpace = func->nameSpace; + + asCExprContext expr(engine); + r = CompileExpression(arg, &expr); + + // Restore the namespace + outFunc->nameSpace = origNameSpace; + + // Don't allow address of class method + if( expr.IsClassMethod() ) + { + // 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(asCExprContext)(engine); + if( args[n] == 0 ) + { + // Out of memory + reservedVariables.SetLength(prevReservedVars); + return -1; + } + + MergeExprBytecodeAndType(args[n], &expr); + if (args[n]->exprNode) + { + // Disconnect the node from the parser, and tell the compiler to free it when complete + args[n]->exprNode->DisconnectParent(); + nodesToFreeUponComplete.PushLast(args[n]->exprNode); + } + } + + reservedVariables.SetLength(prevReservedVars); + 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 - 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 != "" && scope != "::" ) - 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.GetTypeInfo()->GetName(); - str += "::"; - } - str += args[n]->methodName; - } - else if (args[n]->IsAnonymousInitList()) - { - str += "{...}"; - } - else - str += args[n]->type.dataType.Format(outFunc->nameSpace); - } - 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(outFunc->nameSpace); - } - } - 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; + 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 + 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 != "" && scope != "::" ) + 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.GetTypeInfo()->GetName(); + str += "::"; + } + str += args[n]->methodName; + } + else if (args[n]->IsAnonymousInitList()) + { + str += "{...}"; + } + else + str += args[n]->type.dataType.Format(outFunc->nameSpace); + } + 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(outFunc->nameSpace); + } + } + 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, asCExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode) { - if( node && node->nodeType == snAssignment ) - { - int r = CompileAssignment(node, &compiledCtx); - if( r >= 0 ) - { - // Must not have unused ambiguous names - if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc()) - { - // TODO: Should mention that the problem is the ambiguous name - Error(TXT_CANNOT_RESOLVE_AUTO, errNode); - return false; - } - - // Must not have unused anonymous functions - if (compiledCtx.IsLambda()) - { - // TODO: Should mention that the problem is the anonymous function - Error(TXT_CANNOT_RESOLVE_AUTO, errNode); - return false; - } - - // Must not be a null handle - if (compiledCtx.type.dataType.IsNullHandle()) - { - // TODO: Should mention that the problem is the null pointer - Error(TXT_CANNOT_RESOLVE_AUTO, errNode); - return false; - } - - asCDataType newType = compiledCtx.type.dataType; - - // Handle const qualifier on auto - if (type.IsReadOnly()) - newType.MakeReadOnly(true); - else if (type.IsHandleToConst()) - newType.MakeHandleToConst(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); - return false; - } - } - } - - // Implicit handle types should always be handles - if (newType.GetTypeInfo() && - (newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)) - newType.MakeHandle(true); - - // For types that support handles auto should prefer handle - // as it is more efficient than making a copy - // TODO: 'auto a = ...;' and 'auto @a = ...;' works the same in this case. Is this what we want? - if( newType.SupportHandles() ) - newType.MakeHandle(true); - - type = newType; - return true; - } - - return false; - } - else - { - Error(TXT_CANNOT_RESOLVE_AUTO, errNode); - type = asCDataType::CreatePrimitive(ttInt, false); - return false; - } + if( node && node->nodeType == snAssignment ) + { + int r = CompileAssignment(node, &compiledCtx); + if( r >= 0 ) + { + // Must not have unused ambiguous names + if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc()) + { + // TODO: Should mention that the problem is the ambiguous name + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + + // Must not have unused anonymous functions + if (compiledCtx.IsLambda()) + { + // TODO: Should mention that the problem is the anonymous function + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + + // Must not be a null handle + if (compiledCtx.type.dataType.IsNullHandle()) + { + // TODO: Should mention that the problem is the null pointer + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + + asCDataType newType = compiledCtx.type.dataType; + + // Handle const qualifier on auto + if (type.IsReadOnly()) + newType.MakeReadOnly(true); + else if (type.IsHandleToConst()) + newType.MakeHandleToConst(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); + return false; + } + } + } + + // Implicit handle types should always be handles + if (newType.GetTypeInfo() && + (newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)) + newType.MakeHandle(true); + + // For types that support handles auto should prefer handle + // as it is more efficient than making a copy + // TODO: 'auto a = ...;' and 'auto @a = ...;' works the same in this case. Is this what we want? + if( newType.SupportHandles() ) + newType.MakeHandle(true); + + type = newType; + return true; + } + + 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, false, outFunc->objectType); - - // Declare all variables in this declaration - asCScriptNode *node = decl->firstChild->next; - while( node ) - { - // If this is an auto type, we have to compile the assignment now to figure out the type - asCExprContext compiledCtx(engine); - bool preCompiled = false; - if (type.IsAuto()) - { - preCompiled = CompileAutoType(type, compiledCtx, node->next, node); - if (!preCompiled) - { - // If it wasn't possible to determine the type from the expression then there - // is no need to continue with the initialization. The error was already reported - // in CompileAutoType. - return; - } - } - - // Is the type allowed? - if( !type.CanBeInstantiated() ) - { - asCString str; - if( type.IsAbstractClass() ) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf()); - else if( type.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - - // Don't continue, as it will most likely lead to further - // errors that may just mislead the script writer - return; - } - - // A shared object may not declare variables of non-shared types - if( outFunc->IsShared() ) - { - asCTypeInfo *ot = type.GetTypeInfo(); - 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->GetRegisteredType(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); + // Get the data type + asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType); + + // Declare all variables in this declaration + asCScriptNode *node = decl->firstChild->next; + while( node ) + { + // If this is an auto type, we have to compile the assignment now to figure out the type + asCExprContext compiledCtx(engine); + bool preCompiled = false; + if (type.IsAuto()) + { + preCompiled = CompileAutoType(type, compiledCtx, node->next, node); + if (!preCompiled) + { + // If it wasn't possible to determine the type from the expression then there + // is no need to continue with the initialization. The error was already reported + // in CompileAutoType. + return; + } + } + + // Is the type allowed? + if( !type.CanBeInstantiated() ) + { + asCString str; + if( type.IsAbstractClass() ) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf()); + else if( type.IsInterface() ) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + // Don't continue, as it will most likely lead to further + // errors that may just mislead the script writer + return; + } + + // A shared object may not declare variables of non-shared types + if( outFunc->IsShared() ) + { + asCTypeInfo *ot = type.GetTypeInfo(); + 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->GetRegisteredType(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, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled) { - bool isConstantExpression = false; - if( node && node->nodeType == snArgList ) - { - // Make sure it is an object and not a handle - if( type.GetTypeInfo() == 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.GetTypeInfo()->flags & asOBJ_REF ) - funcs = beh->factories; - else - funcs = beh->constructors; - } - - asCString str = type.Format(outFunc->nameSpace); - 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], CastToObjectType(type.GetTypeInfo()), &namedArgs); - - if( r == asSUCCESS ) - { - asCExprContext ctx(engine); - if( type.GetTypeInfo() && (type.GetTypeInfo()->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::CreateType(outFunc->objectType, false))); - } - if( type.IsFuncdef()) - ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); - 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.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF); - if( onHeap ) - { - ctx.bc.InstrSHORT(asBC_PSF, 0); - ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(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::CreateType(outFunc->objectType, false))); - } - else - { - ctx.bc.InstrSHORT(asBC_PSF, (short)offset); - } - } - - PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo())); - - 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], asCExprContext); - } - for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) - if( namedArgs[n].ctx ) - { - asDELETE(namedArgs[n].ctx, asCExprContext); - } - } - } - else if( node && node->nodeType == snInitList ) - { - asCExprValue 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 ) - { - // Compile the expression - asCExprContext newExpr(engine); - asCExprContext* expr; - int r = 0; - - if( preCompiled ) - { - expr = preCompiled; - } - else - { - expr = &newExpr; - r = CompileAssignment(node, expr); - } - - // handles initialized with null doesn't need any bytecode - // since handles will be initialized to null by default anyway - if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() ) - return false; - - // Look for appropriate constructor - asCArray funcs; - asCArray args; - - // Handles must use the handle assignment operation. - // Types that are ASHANDLE must not allow the use of the constructor in this case, - // because it is ambiguous whether a value assignment or handle assignment will be done. - // Only do this if the expression is of the same type, as the expression is an assignment - // and an initialization constructor may not have the same meaning. - // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions. - if( !type.IsObjectHandle() && !expr->type.isExplicitHandle && - !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) && - type.IsEqualExceptRefAndConst(expr->type.dataType) ) - { - asSTypeBehaviour *beh = type.GetBehaviour(); - if( beh ) - { - if( type.GetTypeInfo()->flags & asOBJ_REF ) - funcs = beh->factories; - else - funcs = beh->constructors; - } - - asCString str = type.Format(outFunc->nameSpace); - args.PushLast(expr); - MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true); - - // Make sure the argument is of the right type (and not just compatible with the expression) - if (funcs.GetLength() == 1) - { - asCScriptFunction *f = engine->scriptFunctions[funcs[0]]; - if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType)) - funcs.PopLast(); - } - } - - if( funcs.GetLength() == 1 ) - { - // Use the constructor - - // TODO: clean-up: A large part of this is identical to the initalization with argList above - - // Add the default values for arguments not explicitly supplied - r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo())); - - if( r == asSUCCESS ) - { - asCExprContext ctx(engine); - if( type.GetTypeInfo() && (type.GetTypeInfo()->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::CreateType(outFunc->objectType, false))); - } - if( type.IsFuncdef() ) - ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); - 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.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF); - if( onHeap ) - { - ctx.bc.InstrSHORT(asBC_PSF, 0); - ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(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::CreateType(outFunc->objectType, false))); - } - else - { - ctx.bc.InstrSHORT(asBC_PSF, (short)offset); - } - } - - PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo())); - - if( isVarGlobOrMem == 0 ) - { - // Mark the object in the local variable as initialized - ctx.bc.ObjInfo(offset, asOBJ_INIT); - } - } - bc->AddCode(&ctx.bc); - } - } - else - { - // Call the default constructur, then call the assignment operator - asCExprContext ctx(engine); - - // 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.GetConstantData(); - } - - asCExprContext 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::CreateType(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. - - asCExprContext 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.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->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::CreateType(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.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) ) - { - bool useHndlAssign = false; - if (lexpr.type.dataType.IsHandleToAsHandleType()) - { - useHndlAssign = true; - - // Make sure the right hand expression is treated as a handle - if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant() ) - { - // TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function - // Convert the expression to a handle - if (!expr->type.dataType.IsObjectHandle() && expr->type.dataType.GetTypeInfo() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) - { - asCDataType to = expr->type.dataType; - to.MakeHandle(true); - to.MakeReference(true); - to.MakeHandleToConst(expr->type.dataType.IsReadOnly()); - ImplicitConversion(expr, to, node, asIC_IMPLICIT_CONV, true, false); - - asASSERT(expr->type.dataType.IsObjectHandle()); - } - else if (expr->type.dataType.GetTypeInfo() && expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) - { - // For the ASHANDLE type we'll simply set the expression as a handle - expr->type.dataType.MakeHandle(true); - } - - if( !expr->type.dataType.IsObjectHandle() && !expr->type.dataType.SupportHandles()) - { - Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); - } - expr->type.isExplicitHandle = true; - } - } - assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &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.GetConstantQW(); - } - - // 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.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) ) - CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem); - else - CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem); - } - } - - return isConstantExpression; + bool isConstantExpression = false; + if( node && node->nodeType == snArgList ) + { + // Make sure it is an object and not a handle + if( type.GetTypeInfo() == 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.GetTypeInfo()->flags & asOBJ_REF ) + funcs = beh->factories; + else + funcs = beh->constructors; + } + + asCString str = type.Format(outFunc->nameSpace); + 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], CastToObjectType(type.GetTypeInfo()), &namedArgs); + + if( r == asSUCCESS ) + { + asCExprContext ctx(engine); + if( type.GetTypeInfo() && (type.GetTypeInfo()->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::CreateType(outFunc->objectType, false))); + } + if( type.IsFuncdef()) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); + 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.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF); + if( onHeap ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(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::CreateType(outFunc->objectType, false))); + } + else + { + ctx.bc.InstrSHORT(asBC_PSF, (short)offset); + } + } + + PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo())); + + 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], asCExprContext); + } + for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) + if( namedArgs[n].ctx ) + { + asDELETE(namedArgs[n].ctx, asCExprContext); + } + } + } + else if( node && node->nodeType == snInitList ) + { + asCExprValue 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 ) + { + // Compile the expression + asCExprContext newExpr(engine); + asCExprContext* expr; + int r = 0; + + if( preCompiled ) + { + expr = preCompiled; + } + else + { + expr = &newExpr; + r = CompileAssignment(node, expr); + } + + // handles initialized with null doesn't need any bytecode + // since handles will be initialized to null by default anyway + if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() ) + return false; + + // Look for appropriate constructor + asCArray funcs; + asCArray args; + + // Handles must use the handle assignment operation. + // Types that are ASHANDLE must not allow the use of the constructor in this case, + // because it is ambiguous whether a value assignment or handle assignment will be done. + // Only do this if the expression is of the same type, as the expression is an assignment + // and an initialization constructor may not have the same meaning. + // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions. + if( !type.IsObjectHandle() && !expr->type.isExplicitHandle && + !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) && + type.IsEqualExceptRefAndConst(expr->type.dataType) ) + { + asSTypeBehaviour *beh = type.GetBehaviour(); + if( beh ) + { + if( type.GetTypeInfo()->flags & asOBJ_REF ) + funcs = beh->factories; + else + funcs = beh->constructors; + } + + asCString str = type.Format(outFunc->nameSpace); + args.PushLast(expr); + MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true); + + // Make sure the argument is of the right type (and not just compatible with the expression) + if (funcs.GetLength() == 1) + { + asCScriptFunction *f = engine->scriptFunctions[funcs[0]]; + if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType)) + funcs.PopLast(); + } + } + + if( funcs.GetLength() == 1 ) + { + // Use the constructor + + // TODO: clean-up: A large part of this is identical to the initalization with argList above + + // Add the default values for arguments not explicitly supplied + r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo())); + + if( r == asSUCCESS ) + { + asCExprContext ctx(engine); + if( type.GetTypeInfo() && (type.GetTypeInfo()->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::CreateType(outFunc->objectType, false))); + } + if( type.IsFuncdef() ) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); + 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.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF); + if( onHeap ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(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::CreateType(outFunc->objectType, false))); + } + else + { + ctx.bc.InstrSHORT(asBC_PSF, (short)offset); + } + } + + PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo())); + + if( isVarGlobOrMem == 0 ) + { + // Mark the object in the local variable as initialized + ctx.bc.ObjInfo(offset, asOBJ_INIT); + } + } + bc->AddCode(&ctx.bc); + } + } + else + { + // Call the default constructur, then call the assignment operator + asCExprContext ctx(engine); + + // 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.GetConstantData(); + } + + asCExprContext 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::CreateType(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. + + asCExprContext 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.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->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::CreateType(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.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) ) + { + bool useHndlAssign = false; + if (lexpr.type.dataType.IsHandleToAsHandleType()) + { + useHndlAssign = true; + + // Make sure the right hand expression is treated as a handle + if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant() ) + { + // TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function + // Convert the expression to a handle + if (!expr->type.dataType.IsObjectHandle() && expr->type.dataType.GetTypeInfo() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) + { + asCDataType to = expr->type.dataType; + to.MakeHandle(true); + to.MakeReference(true); + to.MakeHandleToConst(expr->type.dataType.IsReadOnly()); + ImplicitConversion(expr, to, node, asIC_IMPLICIT_CONV, true, false); + + asASSERT(expr->type.dataType.IsObjectHandle()); + } + else if (expr->type.dataType.GetTypeInfo() && expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) + { + // For the ASHANDLE type we'll simply set the expression as a handle + expr->type.dataType.MakeHandle(true); + } + + if( !expr->type.dataType.IsObjectHandle() && !expr->type.dataType.SupportHandles()) + { + Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); + } + expr->type.isExplicitHandle = true; + } + } + assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &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.GetConstantQW(); + } + + // 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.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) ) + CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem); + else + CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem); + } + } + + return isConstantExpression; } void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem) { - // Check if the type supports initialization lists - if( var->dataType.GetTypeInfo() == 0 || - var->dataType.GetBehaviour()->listFactory == 0 ) - { - asCString str; - str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).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::CreateType(listPatternType, false), true); - asUINT bufferSize = 0; - - // Evaluate all elements of the list - asCExprContext valueExpr(engine); - asCScriptNode *el = node; - asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; - int elementsInSubList = -1; - int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList); - asASSERT( r || patternNode == 0 ); - if (r < 0) - { - asCString msg; - msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf()); - Error(msg, node); - } - - // After all values have been evaluated we know the final size of the buffer - asCExprContext 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; - asCExprContext arg1(engine); - arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false)); - arg1.type.dataType.MakeReference(true); - arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar)); - args.PushLast(&arg1); - - asCExprContext ctx(engine); - - if( var->isVariable ) - { - asASSERT( isVarGlobOrMem == 0 ); - - if( var->dataType.GetTypeInfo()->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, CastToObjectType(var->dataType.GetTypeInfo())); - - // Mark the object in the local variable as initialized - ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT); - } - } - else - { - if( var->dataType.GetTypeInfo()->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::CreateType(outFunc->objectType, false))); - } - if (var->dataType.IsFuncdef()) - ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo()); - ctx.bc.Instr(asBC_PopPtr); - ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); - } - 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.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF); - if( onHeap ) - { - ctx.bc.InstrSHORT(asBC_PSF, 0); - ctx.bc.Instr(asBC_RDSPtr); - ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(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::CreateType(outFunc->objectType, false))); - } - - // Call the ALLOC instruction to allocate memory and invoke constructor - PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo())); - } - } - - 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); + // Check if the type supports initialization lists + if( var->dataType.GetTypeInfo() == 0 || + var->dataType.GetBehaviour()->listFactory == 0 ) + { + asCString str; + str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).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::CreateType(listPatternType, false), true); + asUINT bufferSize = 0; + + // Evaluate all elements of the list + asCExprContext valueExpr(engine); + asCScriptNode *el = node; + asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; + int elementsInSubList = -1; + int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList); + asASSERT( r || patternNode == 0 ); + if (r < 0) + { + asCString msg; + msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf()); + Error(msg, node); + } + + // After all values have been evaluated we know the final size of the buffer + asCExprContext 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; + asCExprContext arg1(engine); + arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false)); + arg1.type.dataType.MakeReference(true); + arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar)); + args.PushLast(&arg1); + + asCExprContext ctx(engine); + + if( var->isVariable ) + { + asASSERT( isVarGlobOrMem == 0 ); + + if( var->dataType.GetTypeInfo()->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, CastToObjectType(var->dataType.GetTypeInfo())); + + // Mark the object in the local variable as initialized + ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT); + } + } + else + { + if( var->dataType.GetTypeInfo()->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::CreateType(outFunc->objectType, false))); + } + if (var->dataType.IsFuncdef()) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo()); + ctx.bc.Instr(asBC_PopPtr); + ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); + } + 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.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF); + if( onHeap ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(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::CreateType(outFunc->objectType, false))); + } + + // Call the ALLOC instruction to allocate memory and invoke constructor + PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo())); + } + } + + 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 &bcInit, 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; - } - - asCScriptNode *errNode = node; - int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList); - if( r < 0 ) return r; - - if( r == 1 ) - { - asASSERT( engine->ep.disallowEmptyListElements ); - // Empty elements in the middle are not allowed - Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode); - } - - 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; - - asCExprContext ctx(engine); - while( valueNode ) - { - patternNode = nextNode; - asCScriptNode *errNode = valueNode; - int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList); - if( r < 0 ) return r; - - if( r == 0 ) - countElements++; - else - { - asASSERT( r == 1 && engine->ep.disallowEmptyListElements ); - if( valueNode ) - { - // Empty elements in the middle are not allowed - Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode); - } - } - } - - 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 - bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements); - - // Add the values - bcInit.AddCode(&ctx.bc); - } - else if( patternNode->type == asLPT_TYPE ) - { - bool isEmpty = false; - - // Determine the size of the element - asUINT size = 0; - - asCDataType dt = reinterpret_cast(patternNode)->dataType; - - if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList ) - { - asCExprContext lctx(engine); - asCExprContext rctx(engine); - - if( valueNode->nodeType == snAssignment ) - { - // Compile the assignment expression - CompileAssignment(valueNode, &rctx); - - if( dt.GetTokenType() == ttQuestion ) - { - // Make sure the type is not ambiguous - DetermineSingleFunc(&rctx, valueNode); - - // We now know the type - dt = rctx.type.dataType; - dt.MakeReadOnly(false); - 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); - - // When value assignment for reference types us disabled, make sure all ref types are passed in as handles - if (engine->ep.disallowValueAssignForRefType && dt.SupportHandles()) - dt.MakeHandle(true); - - // Place the type id in the buffer - bcInit.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.GetTypeInfo()->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.GetTypeInfo()->flags & asOBJ_REF ) - { - lctx.type.isExplicitHandle = true; - lctx.type.dataType.MakeReference(true); - } - else - { - asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE ); - - // Make sure the object has been constructed before the assignment - // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects - asSTypeBehaviour *beh = dt.GetBehaviour(); - int func = 0; - if( beh ) func = beh->construct; - if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 ) - { - asCString str; - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); - Error(str, valueNode); - } - else if( func ) - { - // Call the constructor as a normal function - bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); - - asCExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo())); - bcInit.AddCode(&ctx.bc); - } - } - - if( lctx.type.dataType.IsNullHandle() ) - { - // Don't add any code to assign a null handle. RefCpy doesn't work without a known type. - // 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 - { - asCExprContext 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); - - bcInit.AddCode(&ctx.bc); - } - } - else - { - if( builder->engine->ep.disallowEmptyListElements ) - { - // Empty elements are not allowed, except if it is the last in the list - isEmpty = true; - } - 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 - bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0); - bufferSize += 4; - - dt = asCDataType::CreateNullHandle(); - - // No need to initialize the handle as the buffer is already initialized with zeroes - } - else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE ) - { - // For value types with default constructor we need to call the constructor - asSTypeBehaviour *beh = dt.GetBehaviour(); - int func = 0; - if( beh ) func = beh->construct; - if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 ) - { - asCString str; - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->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 - bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); - - asCExprContext ctx(engine); - PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo())); - bcInit.AddCode(&ctx.bc); - } - } - else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF ) - { - // For ref types (not handles) we need to call the default factory - asSTypeBehaviour *beh = dt.GetBehaviour(); - int func = 0; - if( beh ) func = beh->factory; - if( func == 0 ) - { - asCString str; - str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); - Error(str, valueNode); - } - else if( func ) - { - asCExprContext rctx(engine); - PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo())); - - // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. - if( bufferSize & 0x3 ) - bufferSize += 4 - (bufferSize & 0x3); - - asCExprContext lctx(engine); - lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); - lctx.type.Set(dt); - lctx.type.isLValue = true; - lctx.type.isExplicitHandle = true; - lctx.type.dataType.MakeReference(true); - - asCExprContext 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); - - bcInit.AddCode(&ctx.bc); - } - } - } - } - - if( !isEmpty ) - { - // Determine size of the element - if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) ) - size = dt.GetSizeInMemoryBytes(); - else - size = AS_PTR_SIZE*4; - asASSERT( size <= 4 || (size & 0x3) == 0 ); - - bufferSize += size; - } - - // Move to the next element - patternNode = patternNode->next; - valueNode = valueNode->next; - - if( isEmpty ) - { - // The caller will determine if the empty element should be ignored or not - return 1; - } - } - else - asASSERT( false ); - - return 0; + 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; + } + + asCScriptNode *errNode = node; + int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList); + if( r < 0 ) return r; + + if( r == 1 ) + { + asASSERT( engine->ep.disallowEmptyListElements ); + // Empty elements in the middle are not allowed + Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode); + } + + 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; + + asCExprContext ctx(engine); + while( valueNode ) + { + patternNode = nextNode; + asCScriptNode *errNode = valueNode; + int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList); + if( r < 0 ) return r; + + if( r == 0 ) + countElements++; + else + { + asASSERT( r == 1 && engine->ep.disallowEmptyListElements ); + if( valueNode ) + { + // Empty elements in the middle are not allowed + Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode); + } + } + } + + 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 + bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements); + + // Add the values + bcInit.AddCode(&ctx.bc); + } + else if( patternNode->type == asLPT_TYPE ) + { + bool isEmpty = false; + + // Determine the size of the element + asUINT size = 0; + + asCDataType dt = reinterpret_cast(patternNode)->dataType; + + if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList ) + { + asCExprContext lctx(engine); + asCExprContext rctx(engine); + + if( valueNode->nodeType == snAssignment ) + { + // Compile the assignment expression + CompileAssignment(valueNode, &rctx); + + if( dt.GetTokenType() == ttQuestion ) + { + // Make sure the type is not ambiguous + DetermineSingleFunc(&rctx, valueNode); + + // We now know the type + dt = rctx.type.dataType; + dt.MakeReadOnly(false); + 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); + + // When value assignment for reference types us disabled, make sure all ref types are passed in as handles + if (engine->ep.disallowValueAssignForRefType && dt.SupportHandles()) + dt.MakeHandle(true); + + // Place the type id in the buffer + bcInit.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.GetTypeInfo()->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.GetTypeInfo()->flags & asOBJ_REF ) + { + lctx.type.isExplicitHandle = true; + lctx.type.dataType.MakeReference(true); + } + else + { + asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE ); + + // Make sure the object has been constructed before the assignment + // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects + asSTypeBehaviour *beh = dt.GetBehaviour(); + int func = 0; + if( beh ) func = beh->construct; + if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 ) + { + asCString str; + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); + Error(str, valueNode); + } + else if( func ) + { + // Call the constructor as a normal function + bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo())); + bcInit.AddCode(&ctx.bc); + } + } + + if( lctx.type.dataType.IsNullHandle() ) + { + // Don't add any code to assign a null handle. RefCpy doesn't work without a known type. + // 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 + { + asCExprContext 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); + + bcInit.AddCode(&ctx.bc); + } + } + else + { + if( builder->engine->ep.disallowEmptyListElements ) + { + // Empty elements are not allowed, except if it is the last in the list + isEmpty = true; + } + 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 + bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0); + bufferSize += 4; + + dt = asCDataType::CreateNullHandle(); + + // No need to initialize the handle as the buffer is already initialized with zeroes + } + else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE ) + { + // For value types with default constructor we need to call the constructor + asSTypeBehaviour *beh = dt.GetBehaviour(); + int func = 0; + if( beh ) func = beh->construct; + if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 ) + { + asCString str; + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->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 + bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo())); + bcInit.AddCode(&ctx.bc); + } + } + else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF ) + { + // For ref types (not handles) we need to call the default factory + asSTypeBehaviour *beh = dt.GetBehaviour(); + int func = 0; + if( beh ) func = beh->factory; + if( func == 0 ) + { + asCString str; + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); + Error(str, valueNode); + } + else if( func ) + { + asCExprContext rctx(engine); + PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo())); + + // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. + if( bufferSize & 0x3 ) + bufferSize += 4 - (bufferSize & 0x3); + + asCExprContext lctx(engine); + lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + lctx.type.Set(dt); + lctx.type.isLValue = true; + lctx.type.isExplicitHandle = true; + lctx.type.dataType.MakeReference(true); + + asCExprContext 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); + + bcInit.AddCode(&ctx.bc); + } + } + } + } + + if( !isEmpty ) + { + // Determine size of the element + if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) ) + size = dt.GetSizeInMemoryBytes(); + else + size = AS_PTR_SIZE*4; + asASSERT( size <= 4 || (size & 0x3) == 0 ); + + bufferSize += size; + } + + // Move to the next element + patternNode = patternNode->next; + valueNode = valueNode->next; + + if( isEmpty ) + { + // The caller will determine if the empty element should be ignored or not + return 1; + } + } + 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 == snTryCatch) - CompileTryCatch(statement, hasReturn, bc); - else if (statement->nodeType == snReturn) - { - CompileReturnStatement(statement, bc); - *hasReturn = true; - } - else - asASSERT(false); + // 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 == snTryCatch) + CompileTryCatch(statement, hasReturn, bc); + else if (statement->nodeType == snReturn) + { + CompileReturnStatement(statement, bc); + *hasReturn = true; + } + else + asASSERT(false); } 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 - asCExprContext 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; - } - - if( ProcessPropertyGetAccessor(&expr, snode) < 0 ) - return; - - // 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 - asCExprContext 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); - else - { - ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true); - - // Has this case been declared already? - if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0) - Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild); - - // TODO: Optimize: We can insert the numbers sorted already - - // Store constant for later use - caseValues.PushLast(c.type.GetConstantDW()); - - // Reserve label for this case - caseLabels.PushLast(nextLabel++); - } - } - 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 i = caseValues[index]; i <= maxRange; i++ ) - { - if( caseValues[index] == i ) - 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 - for( int i = ranges[range]; i < index; ++i ) - { - tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); - expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]); - expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); - expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]); - 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); - - //---------------------------------- + // 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 + asCExprContext 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; + } + + if( ProcessPropertyGetAccessor(&expr, snode) < 0 ) + return; + + // 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 + asCExprContext 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); + else + { + ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true); + + // Has this case been declared already? + if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0) + Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild); + + // TODO: Optimize: We can insert the numbers sorted already + + // Store constant for later use + caseValues.PushLast(c.type.GetConstantDW()); + + // Reserve label for this case + caseLabels.PushLast(nextLabel++); + } + } + 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 i = caseValues[index]; i <= maxRange; i++ ) + { + if( caseValues[index] == i ) + 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 + for( int i = ranges[range]; i < index; ++i ) + { + tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); + expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]); + expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); + expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]); + 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++); + // 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); + 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; - } + // Is default the last case? + if( cnode->next ) + { + // We've already reported this error + break; + } - CompileCase(cnode->firstChild, &expr.bc); - } + CompileCase(cnode->firstChild, &expr.bc); + } - cnode = cnode->next; - } + cnode = cnode->next; + } - //-------------------------------- + //-------------------------------- - bc->AddCode(&expr.bc); + bc->AddCode(&expr.bc); - // Add break label - bc->Label((short)breakLabel); + // Add break label + bc->Label((short)breakLabel); - breakLabels.PopLast(); - RemoveVariableScope(); + 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; - } + 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::CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc) { - // We will use one label before and another after the catch statement - int beforeCatchLabel = nextLabel++; - int afterCatchLabel = nextLabel++; + // We will use one label before and another after the catch statement + int beforeCatchLabel = nextLabel++; + int afterCatchLabel = nextLabel++; - // Compile the try block - bool hasReturnTry; - asCByteCode tryBC(engine); - CompileStatement(node->firstChild, &hasReturnTry, &tryBC); + // Compile the try block + bool hasReturnTry; + asCByteCode tryBC(engine); + CompileStatement(node->firstChild, &hasReturnTry, &tryBC); - // Add marker to unwind exception until here, then jump to catch block - bc->TryBlock((short)beforeCatchLabel); + // Add marker to unwind exception until here, then jump to catch block + bc->TryBlock((short)beforeCatchLabel); - // Add the byte code - LineInstr(bc, node->firstChild->tokenPos); - bc->AddCode(&tryBC); + // Add the byte code + LineInstr(bc, node->firstChild->tokenPos); + bc->AddCode(&tryBC); - // Add jump to after catch - bc->InstrINT(asBC_JMP, afterCatchLabel); + // Add jump to after catch + bc->InstrINT(asBC_JMP, afterCatchLabel); - // Compile the catch block - bool hasReturnCatch; - asCByteCode catchBC(engine); - CompileStatement(node->firstChild->next, &hasReturnCatch, &catchBC); + // Compile the catch block + bool hasReturnCatch; + asCByteCode catchBC(engine); + CompileStatement(node->firstChild->next, &hasReturnCatch, &catchBC); - // Add marker to tell bytecode optimizer that this is a catch - // block so the code is not removed as unreachable code - bc->Label((short)beforeCatchLabel); + // Add marker to tell bytecode optimizer that this is a catch + // block so the code is not removed as unreachable code + bc->Label((short)beforeCatchLabel); - // Add the byte code - LineInstr(bc, node->firstChild->next->tokenPos); - bc->AddCode(&catchBC); + // Add the byte code + LineInstr(bc, node->firstChild->next->tokenPos); + bc->AddCode(&catchBC); - // Add the label after catch - bc->Label((short)afterCatchLabel); + // Add the label after catch + bc->Label((short)afterCatchLabel); - // The try/catch statement only has return (i.e. no code after - // the try/catch block will be executed) if both blocks have - *hasReturn = hasReturnTry && hasReturnCatch; + // The try/catch statement only has return (i.e. no code after + // the try/catch block will be executed) if both blocks have + *hasReturn = hasReturnTry && hasReturnCatch; } void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc) { - // We will use one label for the if statement - // and possibly another for the else statement - int afterLabel = nextLabel++; - - // Compile the expression - asCExprContext expr(engine); - int r = CompileAssignment(inode->firstChild, &expr); - if( r == 0 ) - { - // Allow value types to be converted to bool using 'bool opImplConv()' - if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) - ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV); - - if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild); - else - { - if( !expr.type.isConstant ) - { - if( ProcessPropertyGetAccessor(&expr, inode) < 0 ) - return; - ConvertToVariable(&expr); - ProcessDeferredParams(&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); - } + // We will use one label for the if statement + // and possibly another for the else statement + int afterLabel = nextLabel++; + + // Compile the expression + asCExprContext expr(engine); + int r = CompileAssignment(inode->firstChild, &expr); + if( r == 0 ) + { + // Allow value types to be converted to bool using 'bool opImplConv()' + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV); + + if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild); + else + { + if( !expr.type.isConstant ) + { + if( ProcessPropertyGetAccessor(&expr, inode) < 0 ) + return; + ConvertToVariable(&expr); + ProcessDeferredParams(&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); + } #if AS_SIZEOF_BOOL == 1 - else if( expr.type.GetConstantB() == 0 ) + else if( expr.type.GetConstantB() == 0 ) #else - else if (expr.type.GetConstantDW() == 0) + else if (expr.type.GetConstantDW() == 0) #endif - { - // 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; + { + // 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 - asCExprContext expr(engine); - asCScriptNode *second = fnode->firstChild->next; - if( second->firstChild ) - { - int r = CompileAssignment(second->firstChild, &expr); - if( r >= 0 ) - { - // Allow value types to be converted to bool using 'bool opImplConv()' - if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) - ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV); - - if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - Error(TXT_EXPR_MUST_BE_BOOL, second); - else - { - if( ProcessPropertyGetAccessor(&expr, second) < 0 ) - return; - ConvertToVariable(&expr); - ProcessDeferredParams(&expr); - - // If expression is false exit the loop - 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(s) - asCByteCode nextBC(engine); - asCScriptNode *cnode = second->next; - while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild ) - { - LineInstr(&nextBC, cnode->tokenPos); - CompileExpressionStatement(cnode, &nextBC); - cnode = cnode->next; - } - - //------------------------------ - // 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(); + // 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 + asCExprContext expr(engine); + asCScriptNode *second = fnode->firstChild->next; + if( second->firstChild ) + { + int r = CompileAssignment(second->firstChild, &expr); + if( r >= 0 ) + { + // Allow value types to be converted to bool using 'bool opImplConv()' + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV); + + if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + Error(TXT_EXPR_MUST_BE_BOOL, second); + else + { + if( ProcessPropertyGetAccessor(&expr, second) < 0 ) + return; + ConvertToVariable(&expr); + ProcessDeferredParams(&expr); + + // If expression is false exit the loop + 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(s) + asCByteCode nextBC(engine); + asCScriptNode *cnode = second->next; + while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild ) + { + LineInstr(&nextBC, cnode->tokenPos); + CompileExpressionStatement(cnode, &nextBC); + cnode = cnode->next; + } + + //------------------------------ + // 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 - asCExprContext expr(engine); - int r = CompileAssignment(wnode->firstChild, &expr); - if( r == 0 ) - { - // Allow value types to be converted to bool using 'bool opImplConv()' - if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) - ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV); - - if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild); - else - { - if( ProcessPropertyGetAccessor(&expr, wnode) < 0 ) - return; - ConvertToVariable(&expr); - ProcessDeferredParams(&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(); + // 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 + asCExprContext expr(engine); + int r = CompileAssignment(wnode->firstChild, &expr); + if( r == 0 ) + { + // Allow value types to be converted to bool using 'bool opImplConv()' + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV); + + if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild); + else + { + if( ProcessPropertyGetAccessor(&expr, wnode) < 0 ) + return; + ConvertToVariable(&expr); + ProcessDeferredParams(&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 - asCExprContext expr(engine); - CompileAssignment(wnode->lastChild, &expr); - - // Allow value types to be converted to bool using 'bool opImplConv()' - if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) - ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV); - - if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild); - else - { - if( ProcessPropertyGetAccessor(&expr, wnode) < 0 ) - return; - ConvertToVariable(&expr); - ProcessDeferredParams(&expr); - - // Jump to next iteration if expression is true - expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); - expr.bc.Instr(asBC_ClrHi); - 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(); + // 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 + asCExprContext expr(engine); + CompileAssignment(wnode->lastChild, &expr); + + // Allow value types to be converted to bool using 'bool opImplConv()' + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV); + + if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild); + else + { + if( ProcessPropertyGetAccessor(&expr, wnode) < 0 ) + return; + ConvertToVariable(&expr); + ProcessDeferredParams(&expr); + + // Jump to next iteration if expression is true + expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); + expr.bc.Instr(asBC_ClrHi); + 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]); + 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]); + 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 - asCExprContext expr(engine); - CompileAssignment(enode->firstChild, &expr); - - // Must not have unused ambiguous names - if( expr.IsClassMethod() || expr.IsGlobalFunc() ) - Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode); - - // Must not have unused anonymous functions - if( expr.IsLambda() ) - Error(TXT_INVALID_EXPRESSION_LAMBDA, 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 ) - if( ProcessPropertyGetAccessor(&expr, enode) < 0 ) - return; - - // 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); - } + if( enode->firstChild ) + { + // Compile the expression + asCExprContext expr(engine); + CompileAssignment(enode->firstChild, &expr); + + // Must not have unused ambiguous names + if( expr.IsClassMethod() || expr.IsGlobalFunc() ) + Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode); + + // Must not have unused anonymous functions + if( expr.IsLambda() ) + Error(TXT_INVALID_EXPRESSION_LAMBDA, 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 ) + if( ProcessPropertyGetAccessor(&expr, enode) < 0 ) + return; + + // 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::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap) { - // The input can be either an object or funcdef, either as handle or reference - asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()); - - // If the object already is stored in temporary variable then nothing needs to be done - // Note, a type can be temporary without being a variable, in which case it is holding off - // on releasing a previously used object. - 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)); - - asCExprValue lvalue; - lvalue.Set(dt); - lvalue.isExplicitHandle = ctx->type.isExplicitHandle; - bool isExplicitHandle = ctx->type.isExplicitHandle; - - bool prevIsTemp = ctx->type.isTemporary; - int prevStackOffset = ctx->type.stackOffset; - - CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false); - - // Release the previous temporary variable if it hasn't already been released - if( prevIsTemp && tempVariables.Exists(prevStackOffset) ) - ReleaseTemporaryVariable(prevStackOffset, &ctx->bc); - - // Push the reference to the temporary variable on the stack - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - - 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)); + // The input can be either an object or funcdef, either as handle or reference + asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()); + + // If the object already is stored in temporary variable then nothing needs to be done + // Note, a type can be temporary without being a variable, in which case it is holding off + // on releasing a previously used object. + 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)); + + asCExprValue lvalue; + lvalue.Set(dt); + lvalue.isExplicitHandle = ctx->type.isExplicitHandle; + bool isExplicitHandle = ctx->type.isExplicitHandle; + + bool prevIsTemp = ctx->type.isTemporary; + int prevStackOffset = ctx->type.stackOffset; + + CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false); + + // Release the previous temporary variable if it hasn't already been released + if( prevIsTemp && tempVariables.Exists(prevStackOffset) ) + ReleaseTemporaryVariable(prevStackOffset, &ctx->bc); + + // Push the reference to the temporary variable on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + + 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 - asCExprContext 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.IsFuncdef()) && - !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(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).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; - } - } - } - - // Can't return the reference if could point to a local variable - if( expr.type.isRefToLocal ) - { - ProcessDeferredParams(&expr); - Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, 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() ) - { - if( ProcessPropertyGetAccessor(&expr, rnode) < 0 ) - return; - - // 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(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).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() || v->type.IsFuncdef() ) - { - // 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(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).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.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() ); - - // Prepare the expression to be loaded into the object - // register. This will place the reference in local variable - 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); + // 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 + asCExprContext 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.IsFuncdef()) && + !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(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).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; + } + } + } + + // Can't return the reference if could point to a local variable + if( expr.type.isRefToLocal ) + { + ProcessDeferredParams(&expr); + Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, 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() ) + { + if( ProcessPropertyGetAccessor(&expr, rnode) < 0 ) + return; + + // 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(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).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() || v->type.IsFuncdef() ) + { + // 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(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).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.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() ); + + // Prepare the expression to be loaded into the object + // register. This will place the reference in local variable + 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); + // 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; + 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); - } + if( variables ) + { + asCVariableScope *var = variables; + variables = variables->parent; + asDELETE(var,asCVariableScope); + } } void asCCompiler::Error(const asCString &msg, asCScriptNode *node) { - asCString str; + asCString str; - int r = 0, c = 0; - asASSERT( node ); - if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); + int r = 0, c = 0; + asASSERT( node ); + if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); - builder->WriteError(script->name, msg, r, c); + builder->WriteError(script->name, msg, r, c); - hasCompileErrors = true; + hasCompileErrors = true; } void asCCompiler::Warning(const asCString &msg, asCScriptNode *node) { - asCString str; + asCString str; - int r = 0, c = 0; - asASSERT( node ); - if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); + int r = 0, c = 0; + asASSERT( node ); + if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); - builder->WriteWarning(script->name, msg, r, c); + builder->WriteWarning(script->name, msg, r, c); } void asCCompiler::Information(const asCString &msg, asCScriptNode *node) { - asCString str; + asCString str; - int r = 0, c = 0; - asASSERT( node ); - if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); + int r = 0, c = 0; + asASSERT( node ); + if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); - builder->WriteInfo(script->name, msg, r, c, false); + 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); - - if (func->objectType && (func->objectType->flags & asOBJ_TEMPLATE)) - { - // Check for funcdefs in the arguments that may have been generated by the template instance, so these can be shown to user - for (unsigned int p = 0; p < func->GetParamCount(); p++) - { - int typeId = 0; - func->GetParam(p, &typeId); - asITypeInfo *ti = engine->GetTypeInfoById(typeId); - if (ti && (ti->GetFlags() & asOBJ_FUNCDEF)) - { - asCString msg; - msg.Format(TXT_WHERE_s_IS_s, ti->GetName(), ti->GetFuncdefSignature()->GetDeclaration()); - builder->WriteInfo(script->name, msg.AddressOf(), r, c, false); - } - } - } - } + 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); + + if (func->objectType && (func->objectType->flags & asOBJ_TEMPLATE)) + { + // Check for funcdefs in the arguments that may have been generated by the template instance, so these can be shown to user + for (unsigned int p = 0; p < func->GetParamCount(); p++) + { + int typeId = 0; + func->GetParam(p, &typeId); + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if (ti && (ti->GetFlags() & asOBJ_FUNCDEF)) + { + asCString msg; + msg.Format(TXT_WHERE_s_IS_s, ti->GetName(), ti->GetFuncdefSignature()->GetDeclaration()); + builder->WriteInfo(script->name, msg.AddressOf(), r, c, false); + } + } + } + } } int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx) { - int l = int(reservedVariables.GetLength()); - ctx->bc.GetVarsUsed(reservedVariables); - int var = AllocateVariable(type, isTemporary, forceOnHeap); - reservedVariables.SetLength(l); - return var; + 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, bool asReference) { - asCDataType t(type); - t.MakeReference(asReference); - - 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.GetTypeInfo() && (t.GetTypeInfo()->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; + asCDataType t(type); + t.MakeReference(asReference); + + 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.GetTypeInfo() && (t.GetTypeInfo()->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; + // 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(); + 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; + if( varOffset == offset ) + return n; - varOffset++; - } + varOffset++; + } - return -1; + 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]; + 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; - } - } - - // Mark the variable slot available for new allocations - n = GetVariableSlot(offset); - if( n != -1 ) - { - freeVariables.PushLast(n); - return; - } - - // We might get here if the variable was implicitly declared - // because it was used before a formal declaration, in this case - // the offset is 0x7FFF - - asASSERT(offset == 0x7FFF); + // 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; + } + } + + // Mark the variable slot available for new allocations + n = GetVariableSlot(offset); + if( n != -1 ) + { + freeVariables.PushLast(n); + return; + } + + // We might get here if the variable was implicitly declared + // because it was used before a formal declaration, in this case + // the offset is 0x7FFF + + asASSERT(offset == 0x7FFF); } void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc) { - if( t.isTemporary ) - { - ReleaseTemporaryVariable(t.stackOffset, bc); - t.isTemporary = false; - } + 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); + 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(asCExprContext *ctx, bool generateCode) { - if( ctx->type.dataType.IsReference() ) - { - if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() ) - { - ctx->type.dataType.MakeReference(false); - if( generateCode ) - ctx->bc.Instr(asBC_RDSPtr); - } - else - { - // This should never happen as primitives are treated differently - asASSERT(false); - } - } + if( ctx->type.dataType.IsReference() ) + { + if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() ) + { + 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(asCExprValue *type, asCScriptNode *node) { - // No need to check if there is no variable scope - if( variables == 0 ) return true; + // 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; + // Temporary variables are assumed to be initialized + if( type->isTemporary ) return true; - // Verify that it is a variable - if( !type->isVariable ) return true; + // Verify that it is a variable + if( !type->isVariable ) return true; - // Find the variable - sVariable *v = variables->GetVariableByOffset(type->stackOffset); + // 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; + // 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; + if( v->isInitialized ) return true; - // Complex types don't need this test - if( v->type.IsObject() || v->type.IsFuncdef() ) return true; + // Complex types don't need this test + if( v->type.IsObject() || v->type.IsFuncdef() ) return true; - // Mark as initialized so that the user will not be bothered again - v->isInitialized = 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); + // Write warning + asCString str; + str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf()); + Warning(str, node); - return false; + return false; } void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node) { - // Check if the variable is initialized (if it indeed is a variable) - IsVariableInitialized(&ctx->type, 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); + asCDataType to = ctx->type.dataType; + to.MakeReference(false); - ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV); + ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV); - ProcessDeferredParams(ctx); + ProcessDeferredParams(ctx); } void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr) { - // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too - int l = int(reservedVariables.GetLength()); - if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables); - - if( ProcessPropertyGetAccessor(rctx, node) < 0 ) - return; - - // 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(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).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->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) - to.MakeHandle(true); - - // Don't allow the implicit conversion to create an object - ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary); - - if( !lvalue->IsObjectHandle() && - (lvalue->GetTypeInfo()->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(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - } - else - { - // If the assignment will be made with the copy behaviour then the rvalue must not be a reference - asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference()); - } - } - - // Unreserve variables - reservedVariables.SetLength(l); + // 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); + + if( ProcessPropertyGetAccessor(rctx, node) < 0 ) + return; + + // 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(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).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->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) + to.MakeHandle(true); + + // Don't allow the implicit conversion to create an object + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary); + + if( !lvalue->IsObjectHandle() && + (lvalue->GetTypeInfo()->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(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + else + { + // If the assignment will be made with the copy behaviour then the rvalue must not be a reference + asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference()); + } + } + + // Unreserve variables + reservedVariables.SetLength(l); } bool asCCompiler::IsLValue(asCExprValue &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; + 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(asCExprValue *lvalue, asCExprValue *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 ) - { - asCExprContext ctx(engine); - ctx.type = *lvalue; - Dereference(&ctx, true); - *lvalue = ctx.type; - bc->AddCode(&ctx.bc); - - asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour(); - if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy ) - { - asCExprContext res(engine); - PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo())); - - bc->AddCode(&res.bc); - *lvalue = res.type; - } - else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy ) - { - // Call the default copy operator for script classes - // This is done differently because the default copy operator - // 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.GetTypeInfo()->flags & asOBJ_POD) ) - { - asCString msg; - msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->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; - } - - if( lvalue->dataType.IsFuncdef() ) - bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo()); - - // Mark variable as initialized - if( variables ) - { - sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset); - if( v ) v->isInitialized = true; - } - } - - return 0; + 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 ) + { + asCExprContext ctx(engine); + ctx.type = *lvalue; + Dereference(&ctx, true); + *lvalue = ctx.type; + bc->AddCode(&ctx.bc); + + asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour(); + if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy ) + { + asCExprContext res(engine); + PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo())); + + bc->AddCode(&res.bc); + *lvalue = res.type; + } + else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy ) + { + // Call the default copy operator for script classes + // This is done differently because the default copy operator + // 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.GetTypeInfo()->flags & asOBJ_POD) ) + { + asCString msg; + msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->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; + } + + if( lvalue->dataType.IsFuncdef() ) + bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo()); + + // Mark variable as initialized + if( variables ) + { + sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset); + if( v ) v->isInitialized = true; + } + } + + return 0; } bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode) { - bool conversionDone = false; - - asCArray ops; - - // A ref cast must not remove the constness - bool isConst = ctx->type.dataType.IsObjectConst(); - - // Find a suitable opCast or opImplCast method - asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - if( (isExplicit && func->name == "opCast") || - func->name == "opImplCast" ) - { - // Is the operator for the output type? - if( func->returnType.GetTypeInfo() != to.GetTypeInfo() ) - continue; - - // Can't call a non-const function on a const object - if( isConst && !func->IsReadOnly() ) - continue; - - ops.PushLast(func->id); - } - } - - // Filter the list by constness to remove const methods if there are matching non-const methods - FilterConst(ops, !isConst); - - // If there is multiple matches, then pick the most appropriate one - if (ops.GetLength() > 1) - { - // This should only happen if an explicit cast is compiled - // and the type has both the opCast and opImplCast - asASSERT(isExplicit); - asASSERT(ops.GetLength() == 2); - - for (asUINT n = 0; n < ops.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[ops[n]]; - if (func->name == "opImplCast") - { - ops.RemoveIndex(n); - n--; - } - } - } - - // Should only have one behaviour for each output type - if( ops.GetLength() == 1 ) - { - conversionDone = true; - 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() - - if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE)) - { - // Add code to avoid calling the cast behaviour if the handle is already null, - // because that will raise a null pointer exception due to the cast behaviour - // being a class method, and the this pointer cannot be null. - - if (!ctx->type.isVariable) - { - 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], CastToObjectType(ctx->type.dataType.GetTypeInfo()), 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 - { - // Value types cannot be null, so there is no need to check for this. - - // Likewise for reference types that are registered with asOBJ_NOHANDLE - // as those are only expected as registered global properties that cannot - // be modified anyway. - - // Call the cast operator - asCArray args; - MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); - } - } - else - { - asCScriptFunction *func = engine->scriptFunctions[ops[0]]; - ctx->type.Set(func->returnType); - } - } - else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) && to.IsObjectHandle() ) - { - // Check for the generic ref cast method: void opCast(?&out) - // This option only works if the expected type is a handle - for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - if( (isExplicit && func->name == "opCast") || - func->name == "opImplCast" ) - { - // Does the operator take the ?&out parameter? - if( func->returnType.GetTokenType() != ttVoid || - func->parameterTypes.GetLength() != 1 || - func->parameterTypes[0].GetTokenType() != ttQuestion || - func->inOutFlags[0] != asTM_OUTREF ) - continue; - - ops.PushLast(func->id); - } - } - - // Filter the list by constness to remove const methods if there are matching non-const methods - FilterConst(ops, !isConst); - - // If there is multiple matches, then pick the most appropriate one - if (ops.GetLength() > 1) - { - // This should only happen if an explicit cast is compiled - // and the type has both the opCast and opImplCast - asASSERT(isExplicit); - asASSERT(ops.GetLength() == 2); - - for (asUINT n = 0; n < ops.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[ops[n]]; - if (func->name == "opImplCast") - { - ops.RemoveIndex(n); - n--; - } - } - } - - if( ops.GetLength() == 1 ) - { - conversionDone = true; - if( generateCode ) - { - int afterLabel = 0; - bool doNullCheck = false; - bool releaseTempVariable = false; - asCExprContext tmp(engine); - if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE)) - { - tmp.bc.AddCode(&ctx->bc); - tmp.Merge(ctx); - - // Add code to avoid calling the cast behaviour if the handle is already null, - // because that will raise a null pointer exception due to the cast behaviour - // being a class method, and the this pointer cannot be null. - doNullCheck = true; - if (!ctx->type.isVariable) - { - Dereference(&tmp, true); - ConvertToVariable(&tmp); - releaseTempVariable = true; - } - - // The reference on the stack will not be used - tmp.bc.Instr(asBC_PopPtr); - - // TODO: runtime optimize: should have immediate comparison for null pointer - int offset = AllocateVariable(asCDataType::CreateNullHandle(), true); - // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though) - tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset); - tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset); - DeallocateVariable(offset); - - afterLabel = nextLabel++; - tmp.bc.InstrDWORD(asBC_JZ, afterLabel); - - // Place the object pointer on the stack - ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset); - } - - // Allocate a temporary variable of the requested handle type - int stackOffset = AllocateVariableNotIn(to, true, false, ctx); - - // Pass the reference of that variable to the function as output parameter - asCDataType toRef(to); - toRef.MakeReference(true); - asCArray args; - asCExprContext arg(engine); - arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset); - // Don't mark the variable as temporary, so it won't be freed too early - arg.type.SetVariable(toRef, stackOffset, false); - arg.type.isLValue = true; - arg.type.isExplicitHandle = true; - args.PushLast(&arg); - - // Call the behaviour method - MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); - - if (doNullCheck) - { - // Add the call after the null check - tmp.bc.AddCode(&ctx->bc); - ctx->bc.AddCode(&tmp.bc); - - int endLabel = nextLabel++; - - ctx->bc.InstrINT(asBC_JMP, endLabel); - ctx->bc.Label((short)afterLabel); - - // Make a NULL pointer - ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset); - ctx->bc.Label((short)endLabel); - } - - // If a temporary variable was allocated in the tmp to convert - // the input expression to a variable, it must be released here - if (releaseTempVariable && tmp.type.isTemporary) - ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc); - - // 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); - } - } - } - - // If the script object didn't implement a matching opCast or opImplCast - // then check if the desired type is part of the hierarchy - if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) - { - // We need it to be a reference - if( !ctx->type.dataType.IsReference() ) - { - asCDataType toRef = ctx->type.dataType; - toRef.MakeReference(true); - ImplicitConversion(ctx, toRef, 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( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) ) - { - conversionDone = true; - ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); - } - } - - // A ref cast must not remove the constness - if( isConst ) - ctx->type.dataType.MakeHandleToConst(true); - } - - return conversionDone; + bool conversionDone = false; + + asCArray ops; + + // A ref cast must not remove the constness + bool isConst = ctx->type.dataType.IsObjectConst(); + + // Find a suitable opCast or opImplCast method + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( (isExplicit && func->name == "opCast") || + func->name == "opImplCast" ) + { + // Is the operator for the output type? + if( func->returnType.GetTypeInfo() != to.GetTypeInfo() ) + continue; + + // Can't call a non-const function on a const object + if( isConst && !func->IsReadOnly() ) + continue; + + ops.PushLast(func->id); + } + } + + // Filter the list by constness to remove const methods if there are matching non-const methods + FilterConst(ops, !isConst); + + // If there is multiple matches, then pick the most appropriate one + if (ops.GetLength() > 1) + { + // This should only happen if an explicit cast is compiled + // and the type has both the opCast and opImplCast + asASSERT(isExplicit); + asASSERT(ops.GetLength() == 2); + + for (asUINT n = 0; n < ops.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[ops[n]]; + if (func->name == "opImplCast") + { + ops.RemoveIndex(n); + n--; + } + } + } + + // Should only have one behaviour for each output type + if( ops.GetLength() == 1 ) + { + conversionDone = true; + 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() + + if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE)) + { + // Add code to avoid calling the cast behaviour if the handle is already null, + // because that will raise a null pointer exception due to the cast behaviour + // being a class method, and the this pointer cannot be null. + + if (!ctx->type.isVariable) + { + 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], CastToObjectType(ctx->type.dataType.GetTypeInfo()), 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 + { + // Value types cannot be null, so there is no need to check for this. + + // Likewise for reference types that are registered with asOBJ_NOHANDLE + // as those are only expected as registered global properties that cannot + // be modified anyway. + + // Call the cast operator + asCArray args; + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + } + } + else + { + asCScriptFunction *func = engine->scriptFunctions[ops[0]]; + ctx->type.Set(func->returnType); + } + } + else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) && to.IsObjectHandle() ) + { + // Check for the generic ref cast method: void opCast(?&out) + // This option only works if the expected type is a handle + for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( (isExplicit && func->name == "opCast") || + func->name == "opImplCast" ) + { + // Does the operator take the ?&out parameter? + if( func->returnType.GetTokenType() != ttVoid || + func->parameterTypes.GetLength() != 1 || + func->parameterTypes[0].GetTokenType() != ttQuestion || + func->inOutFlags[0] != asTM_OUTREF ) + continue; + + ops.PushLast(func->id); + } + } + + // Filter the list by constness to remove const methods if there are matching non-const methods + FilterConst(ops, !isConst); + + // If there is multiple matches, then pick the most appropriate one + if (ops.GetLength() > 1) + { + // This should only happen if an explicit cast is compiled + // and the type has both the opCast and opImplCast + asASSERT(isExplicit); + asASSERT(ops.GetLength() == 2); + + for (asUINT n = 0; n < ops.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[ops[n]]; + if (func->name == "opImplCast") + { + ops.RemoveIndex(n); + n--; + } + } + } + + if( ops.GetLength() == 1 ) + { + conversionDone = true; + if( generateCode ) + { + int afterLabel = 0; + bool doNullCheck = false; + bool releaseTempVariable = false; + asCExprContext tmp(engine); + if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE)) + { + tmp.bc.AddCode(&ctx->bc); + tmp.Merge(ctx); + + // Add code to avoid calling the cast behaviour if the handle is already null, + // because that will raise a null pointer exception due to the cast behaviour + // being a class method, and the this pointer cannot be null. + doNullCheck = true; + if (!ctx->type.isVariable) + { + Dereference(&tmp, true); + ConvertToVariable(&tmp); + releaseTempVariable = true; + } + + // The reference on the stack will not be used + tmp.bc.Instr(asBC_PopPtr); + + // TODO: runtime optimize: should have immediate comparison for null pointer + int offset = AllocateVariable(asCDataType::CreateNullHandle(), true); + // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though) + tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset); + tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset); + DeallocateVariable(offset); + + afterLabel = nextLabel++; + tmp.bc.InstrDWORD(asBC_JZ, afterLabel); + + // Place the object pointer on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset); + } + + // Allocate a temporary variable of the requested handle type + int stackOffset = AllocateVariableNotIn(to, true, false, ctx); + + // Pass the reference of that variable to the function as output parameter + asCDataType toRef(to); + toRef.MakeReference(true); + asCArray args; + asCExprContext arg(engine); + arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset); + // Don't mark the variable as temporary, so it won't be freed too early + arg.type.SetVariable(toRef, stackOffset, false); + arg.type.isLValue = true; + arg.type.isExplicitHandle = true; + args.PushLast(&arg); + + // Call the behaviour method + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + + if (doNullCheck) + { + // Add the call after the null check + tmp.bc.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmp.bc); + + int endLabel = nextLabel++; + + ctx->bc.InstrINT(asBC_JMP, endLabel); + ctx->bc.Label((short)afterLabel); + + // Make a NULL pointer + ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset); + ctx->bc.Label((short)endLabel); + } + + // If a temporary variable was allocated in the tmp to convert + // the input expression to a variable, it must be released here + if (releaseTempVariable && tmp.type.isTemporary) + ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc); + + // 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); + } + } + } + + // If the script object didn't implement a matching opCast or opImplCast + // then check if the desired type is part of the hierarchy + if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) + { + // We need it to be a reference + if( !ctx->type.dataType.IsReference() ) + { + asCDataType toRef = ctx->type.dataType; + toRef.MakeReference(true); + ImplicitConversion(ctx, toRef, 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( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) ) + { + conversionDone = true; + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + } + + // A ref cast must not remove the constness + if( isConst ) + ctx->type.dataType.MakeHandleToConst(true); + } + + return conversionDone; } asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *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->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), 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 (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() ) - cost = asCC_ENUM_SAME_SIZE_CONV; - else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes()) - cost = asCC_ENUM_DIFF_SIZE_CONV; - else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() ) - cost = asCC_SIGNED_CONV; - else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() ) - cost = asCC_SIGNED_CONV; - else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() ) - 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.SetTypeInfo(to.GetTypeInfo()); - } - 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.SetTypeInfo(to.GetTypeInfo()); - - 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 - 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.SetTypeInfo(to.GetTypeInfo()); - } - 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.SetTypeInfo(to.GetTypeInfo()); - - 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.SetTypeInfo(to.GetTypeInfo()); - } - 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.SetTypeInfo(to.GetTypeInfo()); - - 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 - 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.SetTypeInfo(to.GetTypeInfo()); - } - 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.SetTypeInfo(to.GetTypeInfo()); - - 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.SetTypeInfo(to.GetTypeInfo()); - } - 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.SetTypeInfo(to.GetTypeInfo()); - } - 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.SetTypeInfo(to.GetTypeInfo()); - } - 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.SetTypeInfo(to.GetTypeInfo()); - } - 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.SetTypeInfo(to.GetTypeInfo()); - } - } - - // Primitive types on the stack, can be const or non-const - ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); - return cost; + 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->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), 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 (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() ) + cost = asCC_ENUM_SAME_SIZE_CONV; + else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes()) + cost = asCC_ENUM_DIFF_SIZE_CONV; + else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() ) + cost = asCC_SIGNED_CONV; + else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() ) + cost = asCC_SIGNED_CONV; + else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() ) + 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.SetTypeInfo(to.GetTypeInfo()); + } + 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.SetTypeInfo(to.GetTypeInfo()); + + 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 + 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.SetTypeInfo(to.GetTypeInfo()); + } + 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.SetTypeInfo(to.GetTypeInfo()); + + 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.SetTypeInfo(to.GetTypeInfo()); + } + 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.SetTypeInfo(to.GetTypeInfo()); + + 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 + 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.SetTypeInfo(to.GetTypeInfo()); + } + 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.SetTypeInfo(to.GetTypeInfo()); + + 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.SetTypeInfo(to.GetTypeInfo()); + } + 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.SetTypeInfo(to.GetTypeInfo()); + } + 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.SetTypeInfo(to.GetTypeInfo()); + } + 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.SetTypeInfo(to.GetTypeInfo()); + } + 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.SetTypeInfo(to.GetTypeInfo()); + } + } + + // Primitive types on the stack, can be const or non-const + ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); + return cost; } asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode) { - asASSERT( to.IsFuncdef() && ctx->IsLambda() ); - - asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef; - - // Check that the lambda has the correct amount of arguments - asUINT count = 0; - asCScriptNode *argNode = ctx->exprNode->firstChild; - while( argNode->nodeType != snStatementBlock ) - { - // Check if the specified parameter types match the funcdef - if (argNode->nodeType == snDataType) - { - asCDataType dt = builder->CreateDataTypeFromNode(argNode, script, outFunc->nameSpace, false, outFunc->objectType); - asETypeModifiers inOutFlag; - dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0); - - if (count >= funcDef->parameterTypes.GetLength() || - funcDef->parameterTypes[count] != dt || - funcDef->inOutFlags[count] != inOutFlag) - return asCC_NO_CONV; - - argNode = argNode->next; - } - - if( argNode->nodeType == snIdentifier ) - count++; - argNode = argNode->next; - } - - if (funcDef->parameterTypes.GetLength() != count) - return asCC_NO_CONV; - - asASSERT(argNode->nodeType == snStatementBlock); - - // The Lambda can be used as this funcdef - ctx->type.dataType = to; - - if( generateCode ) - { - // Build a unique name for the anonymous function - asCString name; - if( m_globalVar ) - name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++); - else - name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++); - - // Register the lambda with the builder for later compilation - asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace); - asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) ); - ctx->bc.InstrPTR(asBC_FuncPtr, func); - - // Clear the expression node as it is no longer valid - ctx->exprNode = 0; - } - - return asCC_CONST_CONV; + asASSERT( to.IsFuncdef() && ctx->IsLambda() ); + + asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef; + + // Check that the lambda has the correct amount of arguments + asUINT count = 0; + asCScriptNode *argNode = ctx->exprNode->firstChild; + while( argNode->nodeType != snStatementBlock ) + { + // Check if the specified parameter types match the funcdef + if (argNode->nodeType == snDataType) + { + asCDataType dt = builder->CreateDataTypeFromNode(argNode, script, outFunc->nameSpace, false, outFunc->objectType); + asETypeModifiers inOutFlag; + dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0); + + if (count >= funcDef->parameterTypes.GetLength() || + funcDef->parameterTypes[count] != dt || + funcDef->inOutFlags[count] != inOutFlag) + return asCC_NO_CONV; + + argNode = argNode->next; + } + + if( argNode->nodeType == snIdentifier ) + count++; + argNode = argNode->next; + } + + if (funcDef->parameterTypes.GetLength() != count) + return asCC_NO_CONV; + + asASSERT(argNode->nodeType == snStatementBlock); + + // The Lambda can be used as this funcdef + ctx->type.dataType = to; + + if( generateCode ) + { + // Build a unique name for the anonymous function + asCString name; + if( m_globalVar ) + name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++); + else + name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++); + + // Register the lambda with the builder for later compilation + asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace); + asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) ); + ctx->bc.InstrPTR(asBC_FuncPtr, func); + + // Clear the expression node as it is no longer valid + ctx->exprNode = 0; + } + + return asCC_CONST_CONV; } asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) { - asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken || - ctx->type.dataType.IsNullHandle() || - ctx->IsAnonymousInitList() ); - - if( to.IsFuncdef() && ctx->IsLambda() ) - return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode); - - if (ctx->IsAnonymousInitList()) - { - if (to.GetBehaviour() && to.GetBehaviour()->listFactory) - { - if (generateCode) - CompileAnonymousInitList(ctx->exprNode, ctx, to); - else - ctx->type.dataType = to; - } - return asCC_NO_CONV; - } - - // No conversion from void to any other type - if( ctx->type.dataType.GetTokenType() == ttVoid ) - return asCC_NO_CONV; - - // No conversion from class method to any type (it requires delegate) - if( ctx->IsClassMethod() ) - 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.GetTypeInfo() ) - return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct); - } - - return asCC_NO_CONV; + asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken || + ctx->type.dataType.IsNullHandle() || + ctx->IsAnonymousInitList() ); + + if( to.IsFuncdef() && ctx->IsLambda() ) + return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode); + + if (ctx->IsAnonymousInitList()) + { + if (to.GetBehaviour() && to.GetBehaviour()->listFactory) + { + if (generateCode) + CompileAnonymousInitList(ctx->exprNode, ctx, to); + else + ctx->type.dataType = to; + } + return asCC_NO_CONV; + } + + // No conversion from void to any other type + if( ctx->type.dataType.GetTokenType() == ttVoid ) + return asCC_NO_CONV; + + // No conversion from class method to any type (it requires delegate) + if( ctx->IsClassMethod() ) + 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.GetTypeInfo() ) + return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct); + } + + return asCC_NO_CONV; } asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - } - return asCC_NO_CONV; - } - - // Find matching value cast behaviours - // Here we're only interested in those that convert the type to a primitive type - asCArray funcs; - asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - if( ot == 0 ) - { - if( convType != asIC_IMPLICIT_CONV && node ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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]); - } - } - - FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); - - int funcId = 0; - if( to.IsMathType() ) - { - // 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 - 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; - } - } - } - } - } - else - { - // Only accept the exact conversion for non-math types - - // Find the matching cast operator - for( unsigned int n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]); - if( descr->returnType.IsEqualExceptRefAndConst(to) ) - { - 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]); - } - } - - FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); - - // If there are multiple valid value casts, then we must choose the most appropriate one - if (funcs.GetLength() > 1) - { - // This should only happen in case of explicit value cast and - // the application has registered both opImplConv and opConv - asASSERT(convType == asIC_EXPLICIT_VAL_CAST); - asASSERT(funcs.GetLength() == 2); - - for (asUINT n = 0; n < funcs.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; - if (func->name == "opImplConv") - { - funcs.RemoveIndex(n); - n--; - } - } - } - - 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; - asCExprContext arg(engine); - // Don't mark the variable as temporary, so it won't be freed too early - arg.type.SetVariable(toRef, stackOffset, false); - arg.type.isLValue = true; - arg.exprNode = node; - args.PushLast(&arg); - - // Call the behaviour method - MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); - - // Use the reference to the variable as the result of the expression - // Now we can mark the variable as temporary - 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - } - - return asCC_NO_CONV; + 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + return asCC_NO_CONV; + } + + // Find matching value cast behaviours + // Here we're only interested in those that convert the type to a primitive type + asCArray funcs; + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + if( ot == 0 ) + { + if( convType != asIC_IMPLICIT_CONV && node ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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]); + } + } + + FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); + + int funcId = 0; + if( to.IsMathType() ) + { + // 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 + 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; + } + } + } + } + } + else + { + // Only accept the exact conversion for non-math types + + // Find the matching cast operator + for( unsigned int n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]); + if( descr->returnType.IsEqualExceptRefAndConst(to) ) + { + 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]); + } + } + + FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); + + // If there are multiple valid value casts, then we must choose the most appropriate one + if (funcs.GetLength() > 1) + { + // This should only happen in case of explicit value cast and + // the application has registered both opImplConv and opConv + asASSERT(convType == asIC_EXPLICIT_VAL_CAST); + asASSERT(funcs.GetLength() == 2); + + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; + if (func->name == "opImplConv") + { + funcs.RemoveIndex(n); + n--; + } + } + } + + 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; + asCExprContext arg(engine); + // Don't mark the variable as temporary, so it won't be freed too early + arg.type.SetVariable(toRef, stackOffset, false); + arg.type.isLValue = true; + arg.exprNode = node; + args.PushLast(&arg); + + // Call the behaviour method + MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + + // Use the reference to the variable as the result of the expression + // Now we can mark the variable as temporary + 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + + return asCC_NO_CONV; } asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) { - // Convert null to any object type handle, but not to a non-handle type - if( ctx->type.IsNullConstant() && ctx->methodName == "" ) - { - if( to.IsObjectHandle() ) - { - ctx->type.dataType = to; - return asCC_REF_CONV; - } - return asCC_NO_CONV; - } - - asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != ""); - - // First attempt to convert the base type without instantiating another instance - if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" ) - { - // If the to type is an interface and the from type implements it, then we can convert it immediately - if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) ) - { - ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); - return asCC_REF_CONV; - } - // If the to type is a class and the from type derives from it, then we can convert it immediately - else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) ) - { - ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); - return asCC_REF_CONV; - } - // If the types are not equal yet, then we may still be able to find a reference cast - else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() ) - { - // We may still be able to find an implicit ref cast behaviour - CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode); - - // Was the conversion done? - if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() ) - return asCC_REF_CONV; - } - } - - // Convert matching function types - if( to.IsFuncdef() ) - { - // If the input expression is already a funcdef, check if it can be converted - if( ctx->type.dataType.IsFuncdef() && - to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) - { - asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef; - asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef; - if( toFunc->IsSignatureExceptNameEqual(fromFunc) ) - { - ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); - 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 - asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef; - for( asUINT n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]); - if( toFunc->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::CreateType(to.GetTypeInfo(), false); - return asCC_REF_CONV; - } - } - } - } - - return asCC_NO_CONV; + // 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.GetTypeInfo() || ctx->methodName != ""); + + // First attempt to convert the base type without instantiating another instance + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" ) + { + // If the to type is an interface and the from type implements it, then we can convert it immediately + if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) ) + { + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + return asCC_REF_CONV; + } + // If the to type is a class and the from type derives from it, then we can convert it immediately + else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) ) + { + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + return asCC_REF_CONV; + } + // If the types are not equal yet, then we may still be able to find a reference cast + else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() ) + { + // We may still be able to find an implicit ref cast behaviour + CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode); + + // Was the conversion done? + if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() ) + return asCC_REF_CONV; + } + } + + // Convert matching function types + if( to.IsFuncdef() ) + { + // If the input expression is already a funcdef, check if it can be converted + if( ctx->type.dataType.IsFuncdef() && + to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) + { + asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef; + asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef; + if( toFunc->IsSignatureExceptNameEqual(fromFunc) ) + { + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + 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 + asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef; + for( asUINT n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]); + if( toFunc->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::CreateType(to.GetTypeInfo(), false); + return asCC_REF_CONV; + } + } + } + } + + return asCC_NO_CONV; } asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) { - asUINT cost = asCC_NO_CONV; - - // If the base type is still different, and we are allowed to instance - // another object then we can try an implicit value cast - if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) - { - // TODO: Implement support for implicit constructor/factory - asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - 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.GetTypeInfo() == to.GetTypeInfo() && - 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.GetTypeInfo() == to.GetTypeInfo() && - func->parameterTypes.GetLength() == 0 ) - funcs.PushLast(ot->methods[n]); - } - } - - FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); - - // If there are multiple valid value casts, then we must choose the most appropriate one - if (funcs.GetLength() > 1) - { - // This should only happen in case of explicit value cast and - // the application has registered both opImplConv and opConv - asASSERT(convType == asIC_EXPLICIT_VAL_CAST); - asASSERT(funcs.GetLength() == 2); - - for (asUINT n = 0; n < funcs.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; - if (func->name == "opImplConv") - { - funcs.RemoveIndex(n); - n--; - } - } - } - - 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]); - } - } - - FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); - - // If there are multiple valid value casts, then we must choose the most appropriate one - if (funcs.GetLength() > 1) - { - // This should only happen in case of explicit value cast and - // the application has registered both opImplConv and opConv - asASSERT(convType == asIC_EXPLICIT_VAL_CAST); - asASSERT(funcs.GetLength() == 2); - - for (asUINT n = 0; n < funcs.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; - if (func->name == "opImplConv") - { - funcs.RemoveIndex(n); - n--; - } - } - } - - 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); - asCExprContext arg(engine); - arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset); - - // If this an object on the heap, the pointer must be dereferenced - if( IsVariableOnHeap(stackOffset) ) - arg.bc.Instr(asBC_RDSPtr); - - // 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; - - // Mark the argument as clean, so that MakeFunctionCall knows it - // doesn't have to make a copy of it in order to protect the value - arg.isCleanArg = true; - - // Call the behaviour method - asCArray args; - args.PushLast(&arg); - MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); - - // Use the reference to the variable as the result of the expression - // Now we can mark the variable as temporary - ctx->type.SetVariable(toRef, stackOffset, true); - ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset); - } - else - { - // All casts are legal - ctx->type.Set(to); - } - } - else if( CastToObjectType(to.GetTypeInfo()) ) - { - // If no opConv/opImplConv methods were found on the object, then try to find a conversion constructor on the target type - if( to.GetTypeInfo()->flags & asOBJ_REF ) - funcs = CastToObjectType(to.GetTypeInfo())->beh.factories; - else - funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors; - - // If not explicit cast, remove any explicit conversion constructors - for (asUINT n = 0; n < funcs.GetLength(); n++) - { - asCScriptFunction *f = engine->scriptFunctions[funcs[n]]; - if( f == 0 || f->parameterTypes.GetLength() != 1 || (convType != asIC_EXPLICIT_VAL_CAST && f->IsExplicit()) ) - funcs.RemoveIndex(n--); - } - - asCArray args; - args.PushLast(ctx); - - cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false); - - // Did we find a matching constructor? - if (funcs.GetLength() == 1) - { - if (generateCode) - { - // TODO: This should really reuse the code from CompileConstructCall - - // Allocate the new object - asCExprValue tempObj; - asCExprContext e(engine); - bool onHeap = false; - if (to.GetTypeInfo()->flags & asOBJ_VALUE) - { - tempObj.dataType = to; - tempObj.dataType.MakeReference(false); - tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true); - tempObj.dataType.MakeReference(true); - tempObj.isTemporary = true; - tempObj.isVariable = true; - - onHeap = IsVariableOnHeap(tempObj.stackOffset); - - // Push the address of the object on the stack - if (onHeap) - e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); - } - - PrepareFunctionCall(funcs[0], &e.bc, args); - MoveArgsToStack(funcs[0], &e.bc, args, false); - - if (to.GetTypeInfo()->flags & asOBJ_VALUE) - { - // If the object is allocated on the stack, then call the constructor as a normal function - if (onHeap) - { - int offset = 0; - asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); - offset = descr->parameterTypes[0].GetSizeOnStackDWords(); - - e.bc.InstrWORD(asBC_GETREF, (asWORD)offset); - } - else - e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - } - - PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); - - if (to.GetTypeInfo()->flags & asOBJ_VALUE) - { - // Add tag that the object has been initialized - e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); - - // The constructor doesn't return anything, - // so we have to manually inform the type of - // the return value - e.type = tempObj; - if (!onHeap) - e.type.dataType.MakeReference(false); - - // Push the address of the object on the stack again - e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - } - - MergeExprBytecodeAndType(ctx, &e); - } - else - { - ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false)); - } - } - } - } - } - - return cost; + 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.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) + { + // TODO: Implement support for implicit constructor/factory + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + 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.GetTypeInfo() == to.GetTypeInfo() && + 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.GetTypeInfo() == to.GetTypeInfo() && + func->parameterTypes.GetLength() == 0 ) + funcs.PushLast(ot->methods[n]); + } + } + + FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); + + // If there are multiple valid value casts, then we must choose the most appropriate one + if (funcs.GetLength() > 1) + { + // This should only happen in case of explicit value cast and + // the application has registered both opImplConv and opConv + asASSERT(convType == asIC_EXPLICIT_VAL_CAST); + asASSERT(funcs.GetLength() == 2); + + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; + if (func->name == "opImplConv") + { + funcs.RemoveIndex(n); + n--; + } + } + } + + 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]); + } + } + + FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); + + // If there are multiple valid value casts, then we must choose the most appropriate one + if (funcs.GetLength() > 1) + { + // This should only happen in case of explicit value cast and + // the application has registered both opImplConv and opConv + asASSERT(convType == asIC_EXPLICIT_VAL_CAST); + asASSERT(funcs.GetLength() == 2); + + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; + if (func->name == "opImplConv") + { + funcs.RemoveIndex(n); + n--; + } + } + } + + 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); + asCExprContext arg(engine); + arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset); + + // If this an object on the heap, the pointer must be dereferenced + if( IsVariableOnHeap(stackOffset) ) + arg.bc.Instr(asBC_RDSPtr); + + // 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; + + // Mark the argument as clean, so that MakeFunctionCall knows it + // doesn't have to make a copy of it in order to protect the value + arg.isCleanArg = true; + + // Call the behaviour method + asCArray args; + args.PushLast(&arg); + MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + + // Use the reference to the variable as the result of the expression + // Now we can mark the variable as temporary + ctx->type.SetVariable(toRef, stackOffset, true); + ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset); + } + else + { + // All casts are legal + ctx->type.Set(to); + } + } + else if( CastToObjectType(to.GetTypeInfo()) ) + { + // If no opConv/opImplConv methods were found on the object, then try to find a conversion constructor on the target type + if( to.GetTypeInfo()->flags & asOBJ_REF ) + funcs = CastToObjectType(to.GetTypeInfo())->beh.factories; + else + funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors; + + // If not explicit cast, remove any explicit conversion constructors + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction *f = engine->scriptFunctions[funcs[n]]; + if( f == 0 || f->parameterTypes.GetLength() != 1 || (convType != asIC_EXPLICIT_VAL_CAST && f->IsExplicit()) ) + funcs.RemoveIndex(n--); + } + + asCArray args; + args.PushLast(ctx); + + cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false); + + // Did we find a matching constructor? + if (funcs.GetLength() == 1) + { + if (generateCode) + { + // TODO: This should really reuse the code from CompileConstructCall + + // Allocate the new object + asCExprValue tempObj; + asCExprContext e(engine); + bool onHeap = false; + if (to.GetTypeInfo()->flags & asOBJ_VALUE) + { + tempObj.dataType = to; + tempObj.dataType.MakeReference(false); + tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true); + tempObj.dataType.MakeReference(true); + tempObj.isTemporary = true; + tempObj.isVariable = true; + + onHeap = IsVariableOnHeap(tempObj.stackOffset); + + // Push the address of the object on the stack + if (onHeap) + e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); + } + + PrepareFunctionCall(funcs[0], &e.bc, args); + MoveArgsToStack(funcs[0], &e.bc, args, false); + + if (to.GetTypeInfo()->flags & asOBJ_VALUE) + { + // If the object is allocated on the stack, then call the constructor as a normal function + if (onHeap) + { + int offset = 0; + asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); + offset = descr->parameterTypes[0].GetSizeOnStackDWords(); + + e.bc.InstrWORD(asBC_GETREF, (asWORD)offset); + } + else + e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + } + + PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); + + if (to.GetTypeInfo()->flags & asOBJ_VALUE) + { + // Add tag that the object has been initialized + e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); + + // The constructor doesn't return anything, + // so we have to manually inform the type of + // the return value + e.type = tempObj; + if (!onHeap) + e.type.dataType.MakeReference(false); + + // Push the address of the object on the stack again + e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + } + + MergeExprBytecodeAndType(ctx, &e); + } + else + { + ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false)); + } + } + } + } + } + + return cost; } asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) { - // First try a ref cast - asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode); - - // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly - // construct the object through any of the available constructors - if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct ) - { - asCArray funcs; - funcs = CastToObjectType(to.GetTypeInfo())->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 - asCExprValue 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 - asCExprContext 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, CastToObjectType(tempObj.dataType.GetTypeInfo())); - - // Add tag that the object has been initialized - e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); - - // The constructor doesn't return anything, - // so we have to manually inform the type of - // the return value - e.type = tempObj; - if( !onHeap ) - e.type.dataType.MakeReference(false); - - // Push the address of the object on the stack again - e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); - - MergeExprBytecodeAndType(ctx, &e); - } - else - { - ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false)); - } - } - } - - // 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.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && 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.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) - 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 - - if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) || - (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) ) - { - // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const - // TODO: NEWSTRING: Should have an engine property to warn or error on this - if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType)) - { - if (generateCode) - PrepareTemporaryVariable(node, ctx); - else - { - ctx->type.dataType.MakeReadOnly(false); - ctx->type.isConstant = false; - } - - // Add the cost for the copy - cost += asCC_TO_OBJECT_CONV; - } - else if( convType != asIC_IMPLICIT_CONV ) - { - asASSERT(node); - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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); - if (dt.IsFuncdef()) - ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo()); - ctx->bc.Instr(asBC_PopPtr); - ctx->bc.InstrSHORT(asBC_PSF, (short)offset); - - 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 - PrepareTemporaryVariable(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 - PrepareTemporaryVariable(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.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->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() && allowObjectConstruct ) - { - // 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 - PrepareTemporaryVariable(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.GetTypeInfo()->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 - PrepareTemporaryVariable(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)); - } - - if (to.IsReadOnly()) - { - // This doesn't cost anything - ctx->type.dataType.MakeReadOnly(true); - } - - if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly()) - { - // A const object can be converted to a non-const object through a copy - if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST) - { - ctx->type.dataType.MakeReadOnly(false); - - if (generateCode) - { - // Make a temporary copy of the object in order to make it non-const - PrepareTemporaryVariable(node, ctx); - } - - // Add the cost for the copy - cost += asCC_TO_OBJECT_CONV; - } - - // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const - // TODO: NEWSTRING: Should have an engine property to warn or error on this - if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType)) - { - if (generateCode) - PrepareTemporaryVariable(node, ctx); - else - { - ctx->type.dataType.MakeReadOnly(false); - ctx->type.isConstant = false; - } - - // Add the cost for the copy - cost += asCC_TO_OBJECT_CONV; - } - } - } - } - } - - return cost; + // 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.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct ) + { + asCArray funcs; + funcs = CastToObjectType(to.GetTypeInfo())->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 + asCExprValue 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 + asCExprContext 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, CastToObjectType(tempObj.dataType.GetTypeInfo())); + + // Add tag that the object has been initialized + e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); + + // The constructor doesn't return anything, + // so we have to manually inform the type of + // the return value + e.type = tempObj; + if( !onHeap ) + e.type.dataType.MakeReference(false); + + // Push the address of the object on the stack again + e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + + MergeExprBytecodeAndType(ctx, &e); + } + else + { + ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false)); + } + } + } + + // 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.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && 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.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) + 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 + + if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) || + (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) ) + { + // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const + // TODO: NEWSTRING: Should have an engine property to warn or error on this + if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType)) + { + if (generateCode) + PrepareTemporaryVariable(node, ctx); + else + { + ctx->type.dataType.MakeReadOnly(false); + ctx->type.isConstant = false; + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + else if( convType != asIC_IMPLICIT_CONV ) + { + asASSERT(node); + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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); + if (dt.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + + 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 + PrepareTemporaryVariable(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 + PrepareTemporaryVariable(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.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->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() && allowObjectConstruct ) + { + // 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 + PrepareTemporaryVariable(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.GetTypeInfo()->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 + PrepareTemporaryVariable(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)); + } + + if (to.IsReadOnly()) + { + // This doesn't cost anything + ctx->type.dataType.MakeReadOnly(true); + } + + if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly()) + { + // A const object can be converted to a non-const object through a copy + if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST) + { + ctx->type.dataType.MakeReadOnly(false); + + if (generateCode) + { + // Make a temporary copy of the object in order to make it non-const + PrepareTemporaryVariable(node, ctx); + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + + // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const + // TODO: NEWSTRING: Should have an engine property to warn or error on this + if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType)) + { + if (generateCode) + PrepareTemporaryVariable(node, ctx); + else + { + ctx->type.dataType.MakeReadOnly(false); + ctx->type.isConstant = false; + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + } + } + } + } + + return cost; } asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv isExplicit, bool generateCode, bool allowObjectConstruct) { - asCObjectType *objType = CastToObjectType(to.GetTypeInfo()); - asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) ); - if( !objType ) - return asCC_NO_CONV; - - asCArray funcs; - if (objType->flags & asOBJ_VALUE) - { - // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference - for (asUINT n = 0; n < objType->beh.constructors.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]]; - if (func->parameterTypes.GetLength() == 1 && - func->parameterTypes[0].IsPrimitive() && - !(func->inOutFlags[0] & asTM_OUTREF) && - (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()) ) - { - funcs.PushLast(func->id); - } - } - } - else if (objType->flags & asOBJ_REF) - { - // For ref types the object must have a factory that takes a single primitive argument either by value or as input reference - for (asUINT n = 0; n < objType->beh.factories.GetLength(); n++) - { - asCScriptFunction *func = engine->scriptFunctions[objType->beh.factories[n]]; - if (func->parameterTypes.GetLength() == 1 && - func->parameterTypes[0].IsPrimitive() && - !(func->inOutFlags[0] & asTM_OUTREF) && - (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit())) - { - funcs.PushLast(func->id); - } - } - } - - if( funcs.GetLength() == 0 ) - return asCC_NO_CONV; - - // Check if it is possible to choose a best match - asCExprContext 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 - asCExprValue tempObj; - bool onHeap = false; - - if (!(objType->flags & asOBJ_REF)) - { - tempObj.dataType = to; - tempObj.stackOffset = (short)AllocateVariable(to, true); - tempObj.dataType.MakeReference(true); - tempObj.isTemporary = true; - tempObj.isVariable = true; - - onHeap = IsVariableOnHeap(tempObj.stackOffset); - - // Push the address of the object on the stack - if (onHeap) - ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); - } - - 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, CastToObjectType(tempObj.dataType.GetTypeInfo())); - - // 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); - - // Make another pass to make sure the result has the correct handle and reference settings - ImplicitConversion(ctx, to, node, isExplicit, generateCode, allowObjectConstruct); - } - - return cost; + asCObjectType *objType = CastToObjectType(to.GetTypeInfo()); + asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) ); + if( !objType ) + return asCC_NO_CONV; + + asCArray funcs; + if (objType->flags & asOBJ_VALUE) + { + // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference + for (asUINT n = 0; n < objType->beh.constructors.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]]; + if (func->parameterTypes.GetLength() == 1 && + func->parameterTypes[0].IsPrimitive() && + !(func->inOutFlags[0] & asTM_OUTREF) && + (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()) ) + { + funcs.PushLast(func->id); + } + } + } + else if (objType->flags & asOBJ_REF) + { + // For ref types the object must have a factory that takes a single primitive argument either by value or as input reference + for (asUINT n = 0; n < objType->beh.factories.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[objType->beh.factories[n]]; + if (func->parameterTypes.GetLength() == 1 && + func->parameterTypes[0].IsPrimitive() && + !(func->inOutFlags[0] & asTM_OUTREF) && + (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit())) + { + funcs.PushLast(func->id); + } + } + } + + if( funcs.GetLength() == 0 ) + return asCC_NO_CONV; + + // Check if it is possible to choose a best match + asCExprContext 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 + asCExprValue tempObj; + bool onHeap = false; + + if (!(objType->flags & asOBJ_REF)) + { + tempObj.dataType = to; + tempObj.stackOffset = (short)AllocateVariable(to, true); + tempObj.dataType.MakeReference(true); + tempObj.isTemporary = true; + tempObj.isVariable = true; + + onHeap = IsVariableOnHeap(tempObj.stackOffset); + + // Push the address of the object on the stack + if (onHeap) + ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); + } + + 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, CastToObjectType(tempObj.dataType.GetTypeInfo())); + + // 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); + + // Make another pass to make sure the result has the correct handle and reference settings + ImplicitConversion(ctx, to, node, isExplicit, generateCode, allowObjectConstruct); + } + + return cost; } void asCCompiler::ImplicitConversionConstant(asCExprContext *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() ) - { - asCDataType targetDt; - if (to.IsEnumType()) - targetDt = to; - else - targetDt = asCDataType::CreatePrimitive(ttInt, true); - - // Transform the value - // Float constants can be implicitly converted to int - if( from->type.dataType.IsFloatType() ) - { - float fc = from->type.GetConstantF(); - int ic = int(fc); - - if( float(ic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantDW(targetDt, ic); - } - // Double constants can be implicitly converted to int - else if( from->type.dataType.IsDoubleType() ) - { - double fc = from->type.GetConstantD(); - int ic = int(fc); - - if( double(ic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantDW(targetDt, ic); - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - // Verify that it is possible to convert to signed without getting negative - if( from->type.dataType.GetSizeInMemoryBytes() == 4 && - int(from->type.GetConstantDW()) < 0 && - convType != asIC_EXPLICIT_VAL_CAST && - node != 0 ) - Warning(TXT_CHANGE_SIGN, node); - - // Convert to 32bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.SetConstantDW(targetDt, from->type.GetConstantB()); - else if (from->type.dataType.GetSizeInMemoryBytes() == 2) - from->type.SetConstantDW(targetDt, from->type.GetConstantW()); - else - from->type.dataType = targetDt; - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - if (asQWORD(from->type.GetConstantQW()) >> 31) - if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - // Convert to 32bit - from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW())); - } - else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2) - { - if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW())) - if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - // Convert to 32bit - from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW())); - } - else if (from->type.dataType.IsIntegerType() && - from->type.dataType.GetSizeInMemoryBytes() < 4) - { - // Convert to 32bit - if (from->type.dataType.GetSizeInMemoryBytes() == 1) - from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB()); - else if (from->type.dataType.GetSizeInMemoryBytes() == 2) - from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW()); - } - else - { - // Only int32 and enums should come here and as these are 32bit - // already nothing needs to be done except set the target type - asASSERT((from->type.dataType.GetTokenType() == ttInt || - from->type.dataType.IsEnumType()) && - from->type.dataType.GetSizeInMemoryBytes() == 4); - - from->type.dataType = targetDt; - } - } - - // Check if a downsize is necessary - if( to.IsIntegerType() && - from->type.dataType.IsIntegerType() && - from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() ) - { - // Verify if it is possible - if( to.GetSizeInMemoryBytes() == 1 ) - { - if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) ) - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW())); - } - else if( to.GetSizeInMemoryBytes() == 2 ) - { - if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) ) - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW())); - } - } - } - else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 ) - { - // Float constants can be implicitly converted to int - if( from->type.dataType.IsFloatType() ) - { - float fc = from->type.GetConstantF(); - asINT64 ic = asINT64(fc); - - if( float(ic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic); - } - // Double constants can be implicitly converted to int - else if( from->type.dataType.IsDoubleType() ) - { - double fc = from->type.GetConstantD(); - asINT64 ic = asINT64(fc); - - if( double(ic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic); - } - else if( from->type.dataType.IsUnsignedType() ) - { - // Convert to 64bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 8 ) - { - if( asINT64(from->type.GetConstantQW()) < 0 ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); - } - from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); - } - } - else if( from->type.dataType.IsIntegerType() ) - { - // Convert to 64bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW()); - } - } - else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 ) - { - if( from->type.dataType.IsFloatType() ) - { - float fc = from->type.GetConstantF(); - // Some compilers set the value to 0 when converting a negative float to unsigned int. - // To maintain a consistent behaviour across compilers we convert to int first. - asUINT uic = asUINT(int(fc)); - - if( float(uic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic); - - // Try once more, in case of a smaller type - ImplicitConversionConstant(from, to, node, convType); - } - else if( from->type.dataType.IsDoubleType() ) - { - double fc = from->type.GetConstantD(); - // Some compilers set the value to 0 when converting a negative double to unsigned int. - // To maintain a consistent behaviour across compilers we convert to int first. - asUINT uic = asUINT(int(fc)); - - if( double(uic) != fc ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic); - - // Try once more, in case of a smaller type - ImplicitConversionConstant(from, to, node, convType); - } - else if( from->type.dataType.IsIntegerType() ) - { - // Verify that it is possible to convert to unsigned without loosing negative - if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) || - (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) || - (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) || - (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0)) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); - } - - // Check if any data is lost - if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - } - - // Convert to 32bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW()); - else if (from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW()); - else - from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW()); - - // Try once more, in case of a smaller type - ImplicitConversionConstant(from, to, node, convType); - } - else if( from->type.dataType.IsUnsignedType() && - from->type.dataType.GetSizeInMemoryBytes() < 4 ) - { - // Convert to 32bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW()); - - // 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.GetConstantDW()) != from->type.GetConstantDW() ) - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW())); - } - else if( to.GetSizeInMemoryBytes() == 2 ) - { - if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW())); - } - else if (to.GetSizeInMemoryBytes() == 4) - { - if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) - if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - - from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW())); - } - } - } - else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 ) - { - if( from->type.dataType.IsFloatType() ) - { - float fc = from->type.GetConstantF(); - // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers - asQWORD uic = asQWORD(asINT64(fc)); + 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() ) + { + asCDataType targetDt; + if (to.IsEnumType()) + targetDt = to; + else + targetDt = asCDataType::CreatePrimitive(ttInt, true); + + // Transform the value + // Float constants can be implicitly converted to int + if( from->type.dataType.IsFloatType() ) + { + float fc = from->type.GetConstantF(); + int ic = int(fc); + + if( float(ic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantDW(targetDt, ic); + } + // Double constants can be implicitly converted to int + else if( from->type.dataType.IsDoubleType() ) + { + double fc = from->type.GetConstantD(); + int ic = int(fc); + + if( double(ic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantDW(targetDt, ic); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Verify that it is possible to convert to signed without getting negative + if( from->type.dataType.GetSizeInMemoryBytes() == 4 && + int(from->type.GetConstantDW()) < 0 && + convType != asIC_EXPLICIT_VAL_CAST && + node != 0 ) + Warning(TXT_CHANGE_SIGN, node); + + // Convert to 32bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantDW(targetDt, from->type.GetConstantB()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 2) + from->type.SetConstantDW(targetDt, from->type.GetConstantW()); + else + from->type.dataType = targetDt; + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + if (asQWORD(from->type.GetConstantQW()) >> 31) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + // Convert to 32bit + from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW())); + } + else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2) + { + if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW())) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + // Convert to 32bit + from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW())); + } + else if (from->type.dataType.IsIntegerType() && + from->type.dataType.GetSizeInMemoryBytes() < 4) + { + // Convert to 32bit + if (from->type.dataType.GetSizeInMemoryBytes() == 1) + from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 2) + from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW()); + } + else + { + // Only int32 and enums should come here and as these are 32bit + // already nothing needs to be done except set the target type + asASSERT((from->type.dataType.GetTokenType() == ttInt || + from->type.dataType.IsEnumType()) && + from->type.dataType.GetSizeInMemoryBytes() == 4); + + from->type.dataType = targetDt; + } + } + + // Check if a downsize is necessary + if( to.IsIntegerType() && + from->type.dataType.IsIntegerType() && + from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() ) + { + // Verify if it is possible + if( to.GetSizeInMemoryBytes() == 1 ) + { + if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) ) + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW())); + } + else if( to.GetSizeInMemoryBytes() == 2 ) + { + if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) ) + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW())); + } + } + } + else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 ) + { + // Float constants can be implicitly converted to int + if( from->type.dataType.IsFloatType() ) + { + float fc = from->type.GetConstantF(); + asINT64 ic = asINT64(fc); + + if( float(ic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic); + } + // Double constants can be implicitly converted to int + else if( from->type.dataType.IsDoubleType() ) + { + double fc = from->type.GetConstantD(); + asINT64 ic = asINT64(fc); + + if( double(ic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic); + } + else if( from->type.dataType.IsUnsignedType() ) + { + // Convert to 64bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 8 ) + { + if( asINT64(from->type.GetConstantQW()) < 0 ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); + } + from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); + } + } + else if( from->type.dataType.IsIntegerType() ) + { + // Convert to 64bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW()); + } + } + else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 ) + { + if( from->type.dataType.IsFloatType() ) + { + float fc = from->type.GetConstantF(); + // Some compilers set the value to 0 when converting a negative float to unsigned int. + // To maintain a consistent behaviour across compilers we convert to int first. + asUINT uic = asUINT(int(fc)); + + if( float(uic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic); + + // Try once more, in case of a smaller type + ImplicitConversionConstant(from, to, node, convType); + } + else if( from->type.dataType.IsDoubleType() ) + { + double fc = from->type.GetConstantD(); + // Some compilers set the value to 0 when converting a negative double to unsigned int. + // To maintain a consistent behaviour across compilers we convert to int first. + asUINT uic = asUINT(int(fc)); + + if( double(uic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic); + + // Try once more, in case of a smaller type + ImplicitConversionConstant(from, to, node, convType); + } + else if( from->type.dataType.IsIntegerType() ) + { + // Verify that it is possible to convert to unsigned without loosing negative + if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0)) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); + } + + // Check if any data is lost + if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + } + + // Convert to 32bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW()); + else + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW()); + + // Try once more, in case of a smaller type + ImplicitConversionConstant(from, to, node, convType); + } + else if( from->type.dataType.IsUnsignedType() && + from->type.dataType.GetSizeInMemoryBytes() < 4 ) + { + // Convert to 32bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW()); + + // 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.GetConstantDW()) != from->type.GetConstantDW() ) + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW())); + } + else if( to.GetSizeInMemoryBytes() == 2 ) + { + if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW())); + } + else if (to.GetSizeInMemoryBytes() == 4) + { + if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW())); + } + } + } + else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 ) + { + if( from->type.dataType.IsFloatType() ) + { + float fc = from->type.GetConstantF(); + // 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); - } + // 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.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic); - } - else if( from->type.dataType.IsDoubleType() ) - { - double fc = from->type.GetConstantD(); - // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers - asQWORD uic = asQWORD(asINT64(fc)); + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic); + } + else if( from->type.dataType.IsDoubleType() ) + { + double fc = from->type.GetConstantD(); + // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers + asQWORD uic = asQWORD(asINT64(fc)); #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); - } + // 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.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic); - } - else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - // Convert to 64bit - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW()); - - // Verify that it is possible to convert to unsigned without loosing negative - if( asINT64(from->type.GetConstantQW()) < 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.GetConstantQW()) < 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.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW()); - else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) - from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW()); - } - } - else if( to.IsFloatType() ) - { - if( from->type.dataType.IsDoubleType() ) - { - double ic = from->type.GetConstantD(); - float fc = float(ic); - - from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - // Must properly convert value in case the from value is smaller - int ic; - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - ic = (asINT8)from->type.GetConstantB(); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - ic = (asINT16)from->type.GetConstantW(); - else - ic = (int)from->type.GetConstantDW(); - float fc = float(ic); - - if( int(fc) != ic ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - float fc = float(asINT64(from->type.GetConstantQW())); - if( asINT64(fc) != asINT64(from->type.GetConstantQW()) ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - // Must properly convert value in case the from value is smaller - unsigned int uic; - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - uic = from->type.GetConstantB(); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - uic = from->type.GetConstantW(); - else - uic = from->type.GetConstantDW(); - float fc = float(uic); - - if( (unsigned int)(fc) != uic ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - float fc = float((asINT64)from->type.GetConstantQW()); - - if( asQWORD(fc) != from->type.GetConstantQW()) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - } - else if( to.IsDoubleType() ) - { - if( from->type.dataType.IsFloatType() ) - { - float ic = from->type.GetConstantF(); - double fc = double(ic); - - from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - // Must properly convert value in case the from value is smaller - int ic; - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - ic = (asINT8)from->type.GetConstantB(); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - ic = (asINT16)from->type.GetConstantW(); - else - ic = (int)from->type.GetConstantDW(); - double fc = double(ic); - - if( int(fc) != ic ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - double fc = double(asINT64(from->type.GetConstantQW())); - - if( asINT64(fc) != asINT64(from->type.GetConstantQW()) ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - // Must properly convert value in case the from value is smaller - unsigned int uic; - if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) - uic = from->type.GetConstantB(); - else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) - uic = from->type.GetConstantW(); - else - uic = from->type.GetConstantDW(); - double fc = double(uic); - - if( (unsigned int)(fc) != uic ) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - double fc = double((asINT64)from->type.GetConstantQW()); - - if( asQWORD(fc) != from->type.GetConstantQW()) - { - if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); - } - - from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); - } - } + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Convert to 64bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW()); + + // Verify that it is possible to convert to unsigned without loosing negative + if( asINT64(from->type.GetConstantQW()) < 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.GetConstantQW()) < 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.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW()); + } + } + else if( to.IsFloatType() ) + { + if( from->type.dataType.IsDoubleType() ) + { + double ic = from->type.GetConstantD(); + float fc = float(ic); + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Must properly convert value in case the from value is smaller + int ic; + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + ic = (asINT8)from->type.GetConstantB(); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + ic = (asINT16)from->type.GetConstantW(); + else + ic = (int)from->type.GetConstantDW(); + float fc = float(ic); + + if( int(fc) != ic ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + float fc = float(asINT64(from->type.GetConstantQW())); + if( asINT64(fc) != asINT64(from->type.GetConstantQW()) ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Must properly convert value in case the from value is smaller + unsigned int uic; + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + uic = from->type.GetConstantB(); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + uic = from->type.GetConstantW(); + else + uic = from->type.GetConstantDW(); + float fc = float(uic); + + if( (unsigned int)(fc) != uic ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + float fc = float((asINT64)from->type.GetConstantQW()); + + if( asQWORD(fc) != from->type.GetConstantQW()) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + } + else if( to.IsDoubleType() ) + { + if( from->type.dataType.IsFloatType() ) + { + float ic = from->type.GetConstantF(); + double fc = double(ic); + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Must properly convert value in case the from value is smaller + int ic; + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + ic = (asINT8)from->type.GetConstantB(); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + ic = (asINT16)from->type.GetConstantW(); + else + ic = (int)from->type.GetConstantDW(); + double fc = double(ic); + + if( int(fc) != ic ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + double fc = double(asINT64(from->type.GetConstantQW())); + + if( asINT64(fc) != asINT64(from->type.GetConstantQW()) ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Must properly convert value in case the from value is smaller + unsigned int uic; + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + uic = from->type.GetConstantB(); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + uic = from->type.GetConstantW(); + else + uic = from->type.GetConstantDW(); + double fc = double(uic); + + if( (unsigned int)(fc) != uic ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + double fc = double((asINT64)from->type.GetConstantQW()); + + if( asQWORD(fc) != from->type.GetConstantQW()) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + } } int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode) { - // Don't allow any operators on expressions that take address of class method - // If methodName is set but the type is not an object, then it is a global function - 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.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->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 ) - { - // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value - return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode); - } - - // 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 - if( ProcessPropertyGetAccessor(lctx, opNode) < 0 ) - return -1; - } - - 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 - asCExprValue 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; - } - - asCExprContext 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(outFunc->nameSpace).AddressOf()); - Error(str, lexpr); - return -1; - } - - if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) - { - // The object is a value type but that should be treated as a handle - - // Make sure the right hand value is a handle - if( !rctx->type.isExplicitHandle && - !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->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(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); - Error(str, rexpr); - return -1; - } - } - - if (!rctx->type.dataType.IsObjectHandle() && !rctx->type.dataType.SupportHandles()) - { - Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, rexpr); - return -1; - } - - // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise - // the code for moving the argument to the stack may not know to correctly handle the argument type - // in case of variable parameter type. - rctx->type.isExplicitHandle = true; - } - - if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, 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(outFunc->nameSpace).AddressOf()); - Error(msg.AddressOf(), opNode); - return -1; - } - else - { - asCDataType dt = lctx->type.dataType; - dt.MakeReference(false); - - PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true); - if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); - Error(str, rexpr); - return -1; - } - - MergeExprBytecode(ctx, rctx); - MergeExprBytecode(ctx, lctx); - - if(!rctx->type.isRefSafe) - 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, false, 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(outFunc->nameSpace).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.GetTypeInfo()->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 ) - { - if( rctx->type.dataType.IsObjectHandle() && !rctx->type.isExplicitHandle && - !lctx->type.dataType.IsObjectHandle() && rctx->type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() ) - { - // Make the conversion from handle to non-handle without creating - // a copy of the object (otherwise done by PrepareArgument) - asCDataType dt = rctx->type.dataType; - dt.MakeHandle(false); - ImplicitConversion(rctx, dt, rexpr, asIC_IMPLICIT_CONV); - needConversion = false; - } - - asCDataType dt = lctx->type.dataType; - dt.MakeReference(true); - // A funcdef can be accessed by ref, but only as read-only - if( dt.IsFuncdef() && !dt.IsObjectHandle() ) - dt.MakeReadOnly(true); - int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion); - if( r < 0 ) - return -1; - if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) - { - asCString str; - str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); - Error(str, rexpr); - return -1; - } - } - else - { - // Process any property accessor first, before placing the final reference on the stack - if( ProcessPropertyGetAccessor(rctx, rexpr) < 0 ) - return -1; - - 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.isRefSafe && (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; + // 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.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->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 ) + { + // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value + return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode); + } + + // 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 + if( ProcessPropertyGetAccessor(lctx, opNode) < 0 ) + return -1; + } + + 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 + asCExprValue 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; + } + + asCExprContext 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(outFunc->nameSpace).AddressOf()); + Error(str, lexpr); + return -1; + } + + if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) + { + // The object is a value type but that should be treated as a handle + + // Make sure the right hand value is a handle + if( !rctx->type.isExplicitHandle && + !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->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(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, rexpr); + return -1; + } + } + + if (!rctx->type.dataType.IsObjectHandle() && !rctx->type.dataType.SupportHandles()) + { + Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, rexpr); + return -1; + } + + // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise + // the code for moving the argument to the stack may not know to correctly handle the argument type + // in case of variable parameter type. + rctx->type.isExplicitHandle = true; + } + + if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, 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(outFunc->nameSpace).AddressOf()); + Error(msg.AddressOf(), opNode); + return -1; + } + else + { + asCDataType dt = lctx->type.dataType; + dt.MakeReference(false); + + PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true); + if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, rexpr); + return -1; + } + + MergeExprBytecode(ctx, rctx); + MergeExprBytecode(ctx, lctx); + + if(!rctx->type.isRefSafe) + 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, false, 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(outFunc->nameSpace).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.GetTypeInfo()->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 ) + { + if( rctx->type.dataType.IsObjectHandle() && !rctx->type.isExplicitHandle && + !lctx->type.dataType.IsObjectHandle() && rctx->type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() ) + { + // Make the conversion from handle to non-handle without creating + // a copy of the object (otherwise done by PrepareArgument) + asCDataType dt = rctx->type.dataType; + dt.MakeHandle(false); + ImplicitConversion(rctx, dt, rexpr, asIC_IMPLICIT_CONV); + needConversion = false; + } + + asCDataType dt = lctx->type.dataType; + dt.MakeReference(true); + // A funcdef can be accessed by ref, but only as read-only + if( dt.IsFuncdef() && !dt.IsObjectHandle() ) + dt.MakeReadOnly(true); + int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion); + if( r < 0 ) + return -1; + if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, rexpr); + return -1; + } + } + else + { + // Process any property accessor first, before placing the final reference on the stack + if( ProcessPropertyGetAccessor(rctx, rexpr) < 0 ) + return -1; + + 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.isRefSafe && (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, asCExprContext *ctx) { - asASSERT(expr->nodeType == snAssignment); + asASSERT(expr->nodeType == snAssignment); - asCScriptNode *lexpr = expr->firstChild; - if( lexpr->next ) - { - // Compile the two expression terms - asCExprContext lctx(engine), rctx(engine); - int rr = CompileAssignment(lexpr->next->next, &rctx); - int lr = CompileCondition(lexpr, &lctx); + asCScriptNode *lexpr = expr->firstChild; + if( lexpr->next ) + { + // Compile the two expression terms + asCExprContext 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); + 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; - } + // Since the operands failed, the assignment was not computed + ctx->type.SetDummy(); + return -1; + } - return CompileCondition(lexpr, ctx); + return CompileCondition(lexpr, ctx); } int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) { - asCExprValue ctype; - - // Compile the conditional expression - asCScriptNode *cexpr = expr->firstChild; - if( cexpr->next ) - { - //------------------------------- - // Compile the condition - asCExprContext e(engine); - int r = CompileExpression(cexpr, &e); - if( r < 0 ) - e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); - - // Allow value types to be converted to bool using 'bool opImplConv()' - if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) - ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV); - - if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - { - Error(TXT_EXPR_MUST_BE_BOOL, cexpr); - e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); - } - ctype = e.type; - - if( ProcessPropertyGetAccessor(&e, cexpr) < 0) - return -1; - - if( e.type.dataType.IsReference() ) ConvertToVariable(&e); - ProcessDeferredParams(&e); - - //------------------------------- - // Compile the left expression - asCExprContext le(engine); - int lr = CompileAssignment(cexpr->next, &le); - - // Resolve any function names already - DetermineSingleFunc(&le, cexpr->next); - - //------------------------------- - // Compile the right expression - asCExprContext re(engine); - int rr = CompileAssignment(cexpr->next->next, &re); - DetermineSingleFunc(&re, cexpr->next->next); - - 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; - } - - if( ProcessPropertyGetAccessor(&le, cexpr->next) < 0 ) - return -1; - if( ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0 ) - return -1; - - bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle; - - // Allow a 0 or null in the first case to be implicitly converted to the second type - if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() ) - { - asCDataType to = re.type.dataType; - to.MakeReference(false); - to.MakeReadOnly(true); - ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV); - } - else if( le.type.IsNullConstant() ) - { - asCDataType to = re.type.dataType; - to.MakeHandle(true); - ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV); - } - - // Allow either case to be converted to const @ if the other is const @ - if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) ) - { - le.type.dataType.MakeHandleToConst(true); - re.type.dataType.MakeHandleToConst(true); - } - - // Allow an anonymous initialization list to be converted to the type in the other condition - if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory) - { - asCDataType to = re.type.dataType; - to.MakeReference(false); - to.MakeReadOnly(false); - ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV); - } - else if (re.IsAnonymousInitList() && le.type.dataType.GetBehaviour() && le.type.dataType.GetBehaviour()->listFactory) - { - asCDataType to = le.type.dataType; - to.MakeReference(false); - to.MakeReadOnly(false); - ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV); - } - - if (le.IsAnonymousInitList() ) - { - Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next); - return -1; - } - else if (re.IsAnonymousInitList()) - { - Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next->next); - return -1; - } - - //--------------------------------- - // 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 if (le.type.IsNullConstant() && re.type.IsNullConstant()) - { - // Special case for when both results are 'null' - // TODO: Other expressions where both results are identical literal constants can probably also be handled this way - - // Put the code for the condition expression on the output - MergeExprBytecode(ctx, &e); - - // Load the result into the register, but ignore the value since both paths give the same response - ctx->type = e.type; - ConvertToVariable(ctx); - ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); - ReleaseTemporaryVariable(ctx->type, &ctx->bc); - - // Return a null constant - ctx->bc.Instr(asBC_PshNull); - ctx->type.SetNullConstant(); - } - else - { - // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference) - // - // Restrictions for the condition to be used as lvalue: - // 1. both b and c must be of the same type and be lvalue references - // 2. neither of the expressions can have any deferred arguments - // that would have to be cleaned up after the reference - // 3. neither expression can be temporary - // - // If either expression is local, the resulting lvalue is not valid - // for return since it is not allowed to return references to local - // variables. - // - // The reference to the local variable must be loaded into the register, - // the resulting expression must not be considered as a local variable - // with a stack offset (i.e. it will not be allowed to use asBC_VAR) - - if( le.type.isLValue && re.type.isLValue && - le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 && - !le.type.isTemporary && !re.type.isTemporary && - le.type.dataType == re.type.dataType ) - { - // 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); - - // Start of the left expression - MergeExprBytecode(ctx, &le); - if( !le.type.dataType.IsReference() && le.type.isVariable ) - { - // Load the address of the variable into the register - ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset); - } - - ctx->bc.InstrINT(asBC_JMP, afterLabel); - - // Start of the right expression - ctx->bc.Label((short)elseLabel); - - MergeExprBytecode(ctx, &re); - if( !re.type.dataType.IsReference() && re.type.isVariable ) - { - // Load the address of the variable into the register - ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset); - } - - ctx->bc.Label((short)afterLabel); - - // In case the options were to objects, it is necessary to dereference the pointer on - // the stack so it will point to the actual object, instead of the variable - if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() ) - { - asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() ); - - ctx->bc.Instr(asBC_RDSPtr); - } - - // The result is an lvalue - ctx->type.isLValue = true; - ctx->type.dataType = le.type.dataType; - if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() ) - ctx->type.dataType.MakeReference(true); - else - ctx->type.dataType.MakeReference(false); - - // It can't be a treated as a variable, since we don't know which one was used - ctx->type.isVariable = false; - ctx->type.isTemporary = false; - - // Must remember if the reference was to a local variable, since it must not be allowed to be returned - ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal; - } - else - { - // Allocate temporary variable and copy the result to that one - asCExprValue 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 PrepareTemporaryVariable() - - 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 - asCExprValue 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)); - } - asCExprValue 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; + asCExprValue ctype; + + // Compile the conditional expression + asCScriptNode *cexpr = expr->firstChild; + if( cexpr->next ) + { + //------------------------------- + // Compile the condition + asCExprContext e(engine); + int r = CompileExpression(cexpr, &e); + if( r < 0 ) + e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + + // Allow value types to be converted to bool using 'bool opImplConv()' + if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV); + + if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + { + Error(TXT_EXPR_MUST_BE_BOOL, cexpr); + e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + } + ctype = e.type; + + if( ProcessPropertyGetAccessor(&e, cexpr) < 0) + return -1; + + if( e.type.dataType.IsReference() ) ConvertToVariable(&e); + ProcessDeferredParams(&e); + + //------------------------------- + // Compile the left expression + asCExprContext le(engine); + int lr = CompileAssignment(cexpr->next, &le); + + // Resolve any function names already + DetermineSingleFunc(&le, cexpr->next); + + //------------------------------- + // Compile the right expression + asCExprContext re(engine); + int rr = CompileAssignment(cexpr->next->next, &re); + DetermineSingleFunc(&re, cexpr->next->next); + + 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; + } + + if( ProcessPropertyGetAccessor(&le, cexpr->next) < 0 ) + return -1; + if( ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0 ) + return -1; + + bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle; + + // Allow a 0 or null in the first case to be implicitly converted to the second type + if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() ) + { + asCDataType to = re.type.dataType; + to.MakeReference(false); + to.MakeReadOnly(true); + ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV); + } + else if( le.type.IsNullConstant() ) + { + asCDataType to = re.type.dataType; + to.MakeHandle(true); + ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV); + } + + // Allow either case to be converted to const @ if the other is const @ + if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) ) + { + le.type.dataType.MakeHandleToConst(true); + re.type.dataType.MakeHandleToConst(true); + } + + // Allow an anonymous initialization list to be converted to the type in the other condition + if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory) + { + asCDataType to = re.type.dataType; + to.MakeReference(false); + to.MakeReadOnly(false); + ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV); + } + else if (re.IsAnonymousInitList() && le.type.dataType.GetBehaviour() && le.type.dataType.GetBehaviour()->listFactory) + { + asCDataType to = le.type.dataType; + to.MakeReference(false); + to.MakeReadOnly(false); + ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV); + } + + if (le.IsAnonymousInitList() ) + { + Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next); + return -1; + } + else if (re.IsAnonymousInitList()) + { + Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next->next); + return -1; + } + + //--------------------------------- + // 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 if (le.type.IsNullConstant() && re.type.IsNullConstant()) + { + // Special case for when both results are 'null' + // TODO: Other expressions where both results are identical literal constants can probably also be handled this way + + // Put the code for the condition expression on the output + MergeExprBytecode(ctx, &e); + + // Load the result into the register, but ignore the value since both paths give the same response + ctx->type = e.type; + ConvertToVariable(ctx); + ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + // Return a null constant + ctx->bc.Instr(asBC_PshNull); + ctx->type.SetNullConstant(); + } + else + { + // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference) + // + // Restrictions for the condition to be used as lvalue: + // 1. both b and c must be of the same type and be lvalue references + // 2. neither of the expressions can have any deferred arguments + // that would have to be cleaned up after the reference + // 3. neither expression can be temporary + // + // If either expression is local, the resulting lvalue is not valid + // for return since it is not allowed to return references to local + // variables. + // + // The reference to the local variable must be loaded into the register, + // the resulting expression must not be considered as a local variable + // with a stack offset (i.e. it will not be allowed to use asBC_VAR) + + if( le.type.isLValue && re.type.isLValue && + le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 && + !le.type.isTemporary && !re.type.isTemporary && + le.type.dataType == re.type.dataType ) + { + // 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); + + // Start of the left expression + MergeExprBytecode(ctx, &le); + if( !le.type.dataType.IsReference() && le.type.isVariable ) + { + // Load the address of the variable into the register + ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset); + } + + ctx->bc.InstrINT(asBC_JMP, afterLabel); + + // Start of the right expression + ctx->bc.Label((short)elseLabel); + + MergeExprBytecode(ctx, &re); + if( !re.type.dataType.IsReference() && re.type.isVariable ) + { + // Load the address of the variable into the register + ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset); + } + + ctx->bc.Label((short)afterLabel); + + // In case the options were to objects, it is necessary to dereference the pointer on + // the stack so it will point to the actual object, instead of the variable + if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() ) + { + asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() ); + + ctx->bc.Instr(asBC_RDSPtr); + } + + // The result is an lvalue + ctx->type.isLValue = true; + ctx->type.dataType = le.type.dataType; + if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() ) + ctx->type.dataType.MakeReference(true); + else + ctx->type.dataType.MakeReference(false); + + // It can't be a treated as a variable, since we don't know which one was used + ctx->type.isVariable = false; + ctx->type.isTemporary = false; + + // Must remember if the reference was to a local variable, since it must not be allowed to be returned + ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal; + } + else + { + // Allocate temporary variable and copy the result to that one + asCExprValue 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 PrepareTemporaryVariable() + + 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 + asCExprValue 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)); + } + asCExprValue 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, asCExprContext *ctx) { - asASSERT(expr->nodeType == snExpression); + asASSERT(expr->nodeType == snExpression); - // Convert to polish post fix, i.e: a+b => ab+ - asCArray postfix; - ConvertToPostFix(expr, postfix); + // Convert to polish post fix, i.e: a+b => ab+ + asCArray postfix; + ConvertToPostFix(expr, postfix); - // Compile the postfix formatted expression - return CompilePostFixExpression(&postfix, ctx); + // Compile the postfix formatted expression + return CompilePostFixExpression(&postfix, ctx); } void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray &postfix) { - // 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 stackA(count); - asCArray &stackB = postfix; - stackB.Allocate(count, false); - - node = expr->firstChild; - while( node ) - { - int precedence = GetPrecedence(node); - - while( stackA.GetLength() > 0 && - precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) ) - stackB.PushLast(stackA.PopLast()); - - stackA.PushLast(node); - - node = node->next; - } - - while( stackA.GetLength() > 0 ) - stackB.PushLast(stackA.PopLast()); + // 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 stackA(count); + asCArray &stackB = postfix; + stackB.Allocate(count, false); + + node = expr->firstChild; + while( node ) + { + int precedence = GetPrecedence(node); + + while( stackA.GetLength() > 0 && + precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) ) + stackB.PushLast(stackA.PopLast()); + + stackA.PushLast(node); + + node = node->next; + } + + while( stackA.GetLength() > 0 ) + stackB.PushLast(stackA.PopLast()); } int asCCompiler::CompilePostFixExpression(asCArray *postfix, asCExprContext *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 ) - { - asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine); - expr.PushLast(e); - e->exprNode = node; - ret = CompileExpressionTerm(node, e); - } - else - { - asCExprContext *r = expr.PopLast(); - asCExprContext *l = expr.PopLast(); - - // Now compile the operator - asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(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], asCExprContext); - for( asUINT f = 0; f < free.GetLength(); f++ ) - asDELETE(free[f], asCExprContext); - - return ret; + // 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 ) + { + asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine); + expr.PushLast(e); + e->exprNode = node; + ret = CompileExpressionTerm(node, e); + } + else + { + asCExprContext *r = expr.PopLast(); + asCExprContext *l = expr.PopLast(); + + // Now compile the operator + asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(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], asCExprContext); + for( asUINT f = 0; f < free.GetLength(); f++ ) + asDELETE(free[f], asCExprContext); + + return ret; } int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt) { - asASSERT(node->nodeType == snInitList); - - // Do not allow constructing non-shared types in shared functions - if (outFunc->IsShared() && - dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared()) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); - Error(msg, node); - } - - // If this is compiled from a default arg, then use the script code for the default arg - asCScriptCode *origCode = script; - if (ctx->origCode) - script = ctx->origCode; - - // Allocate and initialize the temporary object - int offset = AllocateVariable(dt, true); - CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0); - - // 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); - - // Clear the flag for anonymous initalization list as it is no - // longer true now that the object has been initialized. - ctx->isAnonymousInitList = false; - ctx->origCode = 0; - - script = origCode; - - return 0; + asASSERT(node->nodeType == snInitList); + + // Do not allow constructing non-shared types in shared functions + if (outFunc->IsShared() && + dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared()) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + Error(msg, node); + } + + // If this is compiled from a default arg, then use the script code for the default arg + asCScriptCode *origCode = script; + if (ctx->origCode) + script = ctx->origCode; + + // Allocate and initialize the temporary object + int offset = AllocateVariable(dt, true); + CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0); + + // 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); + + // Clear the flag for anonymous initalization list as it is no + // longer true now that the object has been initialized. + ctx->isAnonymousInitList = false; + ctx->origCode = 0; + + script = origCode; + + return 0; } int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx) { - // Shouldn't send any byte code - asASSERT(ctx->bc.GetLastInstr() == -1); - - // Check if this is an initialization of a temp object with an initialization list - if (node->firstChild ) - { - if (node->firstChild->nodeType == snDataType) - { - // Determine the type of the temporary object - asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); - - return CompileAnonymousInitList(node->lastChild, ctx, dt); - } - else if (node->firstChild->nodeType == snInitList) - { - // As the type is not yet known, the init list will be compiled at a - // later time when the type can be determined from the destination - ctx->SetAnonymousInitList(node->firstChild, script); - return 0; - } - } - - // 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; - - asCExprContext 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; + // Shouldn't send any byte code + asASSERT(ctx->bc.GetLastInstr() == -1); + + // Check if this is an initialization of a temp object with an initialization list + if (node->firstChild ) + { + if (node->firstChild->nodeType == snDataType) + { + // Determine the type of the temporary object + asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); + + return CompileAnonymousInitList(node->lastChild, ctx, dt); + } + else if (node->firstChild->nodeType == snInitList) + { + // As the type is not yet known, the init list will be compiled at a + // later time when the type can be determined from the destination + ctx->SetAnonymousInitList(node->firstChild, script); + return 0; + } + } + + // 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; + + asCExprContext 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; } // returns: @@ -9202,22 +9202,22 @@ int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx) // SL_NOMATCH = no match asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult) { - sVariable *v = 0; - if (variables) - v = variables->GetVariable(name.AddressOf()); - if (v) - { - if (v->isPureConstant) - { - outResult->type.SetConstantData(v->type, v->constantValue); - return SL_LOCALCONST; - } - - outResult->type.SetVariable(v->type, v->stackOffset, false); - return SL_LOCALVAR; - } - - return SL_NOMATCH; + sVariable *v = 0; + if (variables) + v = variables->GetVariable(name.AddressOf()); + if (v) + { + if (v->isPureConstant) + { + outResult->type.SetConstantData(v->type, v->constantValue); + return SL_LOCALCONST; + } + + outResult->type.SetVariable(v->type, v->stackOffset, false); + return SL_LOCALVAR; + } + + return SL_NOMATCH; } // returns: @@ -9229,62 +9229,62 @@ asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupLocalVar(const asCString &name, // SL_ERROR = error asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult) { - // See if there are any matching property accessors - asCExprContext access(engine); - access.type.Set(asCDataType::CreateType(objType, false)); - access.type.dataType.MakeReference(true); - int r = 0; - // Indexed property access - asCExprContext dummyArg(engine); - r = FindPropertyAccessor(name, &access, &dummyArg, 0, 0, true); - if (r == 0) - { - // Normal property access - r = FindPropertyAccessor(name, &access, 0, 0, true); - } - if (r <= -3) return SL_ERROR; - if (r != 0) - { - // The symbol matches getters/setters (though not necessarily a compilable match) - MergeExprBytecodeAndType(outResult, &access); - outResult->type.dataType.SetTypeInfo(objType); - return SL_CLASSPROPACCESS; - } - - // Look for matching properties - asCDataType dt; - dt = asCDataType::CreateType(objType, false); - asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf()); - if (prop) - { - outResult->type.dataType.SetTypeInfo(objType); - return SL_CLASSPROP; - } - - // If it is not a property, it may still be the name of a method - asCObjectType *ot = objType; - for (asUINT n = 0; n < ot->methods.GetLength(); n++) - { - asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; - if (f->name == name && - (builder->module->m_accessMask & f->accessMask)) - { - outResult->type.dataType.SetTypeInfo(objType); - return SL_CLASSMETHOD; - } - } - - // If it is not a method, then it can still be a child type - for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++) - { - if (ot->childFuncDefs[n]->name == name) - { - outResult->type.dataType.SetTypeInfo(objType); - return SL_CLASSTYPE; - } - } - - return SL_NOMATCH; + // See if there are any matching property accessors + asCExprContext access(engine); + access.type.Set(asCDataType::CreateType(objType, false)); + access.type.dataType.MakeReference(true); + int r = 0; + // Indexed property access + asCExprContext dummyArg(engine); + r = FindPropertyAccessor(name, &access, &dummyArg, 0, 0, true); + if (r == 0) + { + // Normal property access + r = FindPropertyAccessor(name, &access, 0, 0, true); + } + if (r <= -3) return SL_ERROR; + if (r != 0) + { + // The symbol matches getters/setters (though not necessarily a compilable match) + MergeExprBytecodeAndType(outResult, &access); + outResult->type.dataType.SetTypeInfo(objType); + return SL_CLASSPROPACCESS; + } + + // Look for matching properties + asCDataType dt; + dt = asCDataType::CreateType(objType, false); + asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf()); + if (prop) + { + outResult->type.dataType.SetTypeInfo(objType); + return SL_CLASSPROP; + } + + // If it is not a property, it may still be the name of a method + asCObjectType *ot = objType; + for (asUINT n = 0; n < ot->methods.GetLength(); n++) + { + asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; + if (f->name == name && + (builder->module->m_accessMask & f->accessMask)) + { + outResult->type.dataType.SetTypeInfo(objType); + return SL_CLASSMETHOD; + } + } + + // If it is not a method, then it can still be a child type + for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++) + { + if (ot->childFuncDefs[n]->name == name) + { + outResult->type.dataType.SetTypeInfo(objType); + return SL_CLASSTYPE; + } + } + + return SL_NOMATCH; } // The purpose of this function is to find the entity that matches the symbol name respecting the scope and visibility hierarchy @@ -9311,2712 +9311,2712 @@ asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupMember(const asCString &name, a // SL_ERROR = error asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult) { - asASSERT(outResult); - - // It is a local variable or parameter? - // This is not accessible by default arg expressions - if (!isCompilingDefaultArg && scope == "" && !objType ) - { - SYMBOLTYPE r = SymbolLookupLocalVar(name, outResult); - if (r != 0) - return r; - } - - // Is it a class member? - if (scope == "" && ((objType) || (outFunc && outFunc->objectType))) - { - // 'this' is not accessible by default arg expressions - if (name == THIS_TOKEN && !objType && !isCompilingDefaultArg) - { - asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()); - - // The object pointer is located at stack position 0 - outResult->type.SetVariable(dt, 0, false); - return SL_THISPTR; - } - - // 'super' is not accessible by default arg expressions - if (m_isConstructor && name == SUPER_TOKEN && !objType && !isCompilingDefaultArg) - { - // If the class is derived from another class, then super can be used to call the base' class constructor - if (outFunc && outFunc->objectType->derivedFrom) - { - outResult->type.dataType.SetTypeInfo(outFunc->objectType->derivedFrom); - return SL_CLASSMETHOD; - } - } - - // Look for members in the type - // class members are only accessible in default arg expressions as post op '.' - if( !isCompilingDefaultArg || (isCompilingDefaultArg && objType) ) - { - SYMBOLTYPE r = SymbolLookupMember(name, objType ? objType : outFunc->objectType, outResult); - if (r != 0) - return r; - } - } - - // Recursively search parent namespaces for global entities - asSNameSpace *currNamespace = DetermineNameSpace(""); - while( !objType && currNamespace ) - { - asCString currScope = scope; - - // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace - // TODO: child funcdef: A scope can include a template type, e.g. array - int n = currScope.FindLast("::"); - asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope; - asCString nsName = n >= 0 ? currScope.SubString(0, n) : ""; - - // If the scope represents a type that the current class inherits - // from then that should be used instead of going through the namespaces - if (nsName == "" && (outFunc && outFunc->objectType)) - { - asCObjectType *ot = outFunc->objectType; - while (ot) - { - if (ot->name == typeName) - { - SYMBOLTYPE r = SymbolLookupMember(name, ot, outResult); - if (r != 0) - return r; - } - - ot = ot->derivedFrom; - } - } - - // If the scope starts with :: then search from the global scope - if (currScope.GetLength() < 2 || currScope[0] != ':') - { - if (nsName != "") - { - if (currNamespace->name != "") - nsName = currNamespace->name + "::" + nsName; - } - else - nsName = currNamespace->name; - } - else - nsName = nsName.SubString(2); - - // Get the namespace for this scope - asSNameSpace *ns = engine->FindNameSpace(nsName.AddressOf()); - if (ns) - { - // Is there a type with typeName in the namespace? - asCTypeInfo *scopeType = builder->GetType(typeName.AddressOf(), ns, 0); - - // Check if the symbol is a member of that type - if (scopeType) - { - // Is it an object type? - if (CastToObjectType(scopeType)) - { - SYMBOLTYPE r = SymbolLookupMember(name, CastToObjectType(scopeType), outResult); - if (r != 0) - return r; - } - - // Is it an enum type? - if (CastToEnumType(scopeType)) - { - asDWORD value = 0; - asCDataType dt; - if (builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value)) - { - // an enum value was resolved - outResult->type.SetConstantDW(dt, value); - outResult->symbolNamespace = ns; - return SL_ENUMVAL; - } - } - } - } - - // Get the namespace for this scope. This may return null if the scope is an enum - nsName = currScope; - - // If the scope starts with :: then search from the global scope - if (currScope.GetLength() < 2 || currScope[0] != ':') - { - if (nsName != "") - { - if (currNamespace->name != "") - nsName = currNamespace->name + "::" + nsName; - } - else - nsName = currNamespace->name; - } - else - nsName = nsName.SubString(2); - - ns = engine->FindNameSpace(nsName.AddressOf()); - - // Is it a global property? - if (ns) - { - // See if there are any matching global property accessors - asCExprContext access(engine); - int r = 0; - // Indexed property access - asCExprContext dummyArg(engine); - r = FindPropertyAccessor(name, &access, &dummyArg, 0, ns); - if (r == 0) - { - // Normal property access - r = FindPropertyAccessor(name, &access, 0, ns); - } - if (r <= -3) return SL_ERROR; - if (r != 0) - { - // The symbol matches getters/setters (though not necessarily a compilable match) - MergeExprBytecodeAndType(outResult, &access); - outResult->symbolNamespace = ns; - return SL_GLOBALPROPACCESS; - } - - // See if there is any matching global property - 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) - { - // 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) - { - outResult->type.SetConstantData(prop->type, constantValue); - outResult->symbolNamespace = ns; - return SL_GLOBALCONST; - } - else - { - outResult->type.Set(prop->type); - outResult->symbolNamespace = ns; - return SL_GLOBALVAR; - } - } - } - - // Is it the name of a global function? - if (ns) - { - asCArray funcs; - - builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); - - if (funcs.GetLength() > 0) - { - // Defer the evaluation of which function until it is actually used - // Store the namespace and name of the function for later - outResult->type.SetUndefinedFuncHandle(engine); - outResult->methodName = ns ? ns->name + "::" + name : name; - outResult->symbolNamespace = ns; - return SL_GLOBALFUNC; - } - } - - // Check for type names - if (ns) - { - asCTypeInfo *type = builder->GetType(name.AddressOf(), ns, 0); - if (type) - { - outResult->type.dataType = asCDataType::CreateType(type, false); - return SL_GLOBALTYPE; - } - } - - // Is it an enum value? - if (ns && !engine->ep.requireEnumScope) - { - // Look for the enum value without explicitly informing the enum type - asDWORD value = 0; - asCDataType dt; - int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns); - if (e) - { - 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. - outResult->enumValue = name.AddressOf(); - - // We cannot set a dummy value because it will pass through - // cleanly as an integer. - outResult->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0); - outResult->symbolNamespace = ns; - return SL_ENUMVAL; - } - else - { - // an enum value was resolved - outResult->type.SetConstantDW(dt, value); - outResult->symbolNamespace = ns; - return SL_ENUMVAL; - } - } - } - - // If the given scope starts with '::' then the search starts from global scope - if (scope.GetLength() >= 2 && scope[0] == ':') - break; - - // Move up to parent namespace - currNamespace = engine->GetParentNameSpace(currNamespace); - } - - // The name doesn't match any symbol - return SL_NOMATCH; + asASSERT(outResult); + + // It is a local variable or parameter? + // This is not accessible by default arg expressions + if (!isCompilingDefaultArg && scope == "" && !objType ) + { + SYMBOLTYPE r = SymbolLookupLocalVar(name, outResult); + if (r != 0) + return r; + } + + // Is it a class member? + if (scope == "" && ((objType) || (outFunc && outFunc->objectType))) + { + // 'this' is not accessible by default arg expressions + if (name == THIS_TOKEN && !objType && !isCompilingDefaultArg) + { + asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()); + + // The object pointer is located at stack position 0 + outResult->type.SetVariable(dt, 0, false); + return SL_THISPTR; + } + + // 'super' is not accessible by default arg expressions + if (m_isConstructor && name == SUPER_TOKEN && !objType && !isCompilingDefaultArg) + { + // If the class is derived from another class, then super can be used to call the base' class constructor + if (outFunc && outFunc->objectType->derivedFrom) + { + outResult->type.dataType.SetTypeInfo(outFunc->objectType->derivedFrom); + return SL_CLASSMETHOD; + } + } + + // Look for members in the type + // class members are only accessible in default arg expressions as post op '.' + if( !isCompilingDefaultArg || (isCompilingDefaultArg && objType) ) + { + SYMBOLTYPE r = SymbolLookupMember(name, objType ? objType : outFunc->objectType, outResult); + if (r != 0) + return r; + } + } + + // Recursively search parent namespaces for global entities + asSNameSpace *currNamespace = DetermineNameSpace(""); + while( !objType && currNamespace ) + { + asCString currScope = scope; + + // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace + // TODO: child funcdef: A scope can include a template type, e.g. array + int n = currScope.FindLast("::"); + asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope; + asCString nsName = n >= 0 ? currScope.SubString(0, n) : ""; + + // If the scope represents a type that the current class inherits + // from then that should be used instead of going through the namespaces + if (nsName == "" && (outFunc && outFunc->objectType)) + { + asCObjectType *ot = outFunc->objectType; + while (ot) + { + if (ot->name == typeName) + { + SYMBOLTYPE r = SymbolLookupMember(name, ot, outResult); + if (r != 0) + return r; + } + + ot = ot->derivedFrom; + } + } + + // If the scope starts with :: then search from the global scope + if (currScope.GetLength() < 2 || currScope[0] != ':') + { + if (nsName != "") + { + if (currNamespace->name != "") + nsName = currNamespace->name + "::" + nsName; + } + else + nsName = currNamespace->name; + } + else + nsName = nsName.SubString(2); + + // Get the namespace for this scope + asSNameSpace *ns = engine->FindNameSpace(nsName.AddressOf()); + if (ns) + { + // Is there a type with typeName in the namespace? + asCTypeInfo *scopeType = builder->GetType(typeName.AddressOf(), ns, 0); + + // Check if the symbol is a member of that type + if (scopeType) + { + // Is it an object type? + if (CastToObjectType(scopeType)) + { + SYMBOLTYPE r = SymbolLookupMember(name, CastToObjectType(scopeType), outResult); + if (r != 0) + return r; + } + + // Is it an enum type? + if (CastToEnumType(scopeType)) + { + asDWORD value = 0; + asCDataType dt; + if (builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value)) + { + // an enum value was resolved + outResult->type.SetConstantDW(dt, value); + outResult->symbolNamespace = ns; + return SL_ENUMVAL; + } + } + } + } + + // Get the namespace for this scope. This may return null if the scope is an enum + nsName = currScope; + + // If the scope starts with :: then search from the global scope + if (currScope.GetLength() < 2 || currScope[0] != ':') + { + if (nsName != "") + { + if (currNamespace->name != "") + nsName = currNamespace->name + "::" + nsName; + } + else + nsName = currNamespace->name; + } + else + nsName = nsName.SubString(2); + + ns = engine->FindNameSpace(nsName.AddressOf()); + + // Is it a global property? + if (ns) + { + // See if there are any matching global property accessors + asCExprContext access(engine); + int r = 0; + // Indexed property access + asCExprContext dummyArg(engine); + r = FindPropertyAccessor(name, &access, &dummyArg, 0, ns); + if (r == 0) + { + // Normal property access + r = FindPropertyAccessor(name, &access, 0, ns); + } + if (r <= -3) return SL_ERROR; + if (r != 0) + { + // The symbol matches getters/setters (though not necessarily a compilable match) + MergeExprBytecodeAndType(outResult, &access); + outResult->symbolNamespace = ns; + return SL_GLOBALPROPACCESS; + } + + // See if there is any matching global property + 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) + { + // 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) + { + outResult->type.SetConstantData(prop->type, constantValue); + outResult->symbolNamespace = ns; + return SL_GLOBALCONST; + } + else + { + outResult->type.Set(prop->type); + outResult->symbolNamespace = ns; + return SL_GLOBALVAR; + } + } + } + + // Is it the name of a global function? + if (ns) + { + asCArray funcs; + + builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); + + if (funcs.GetLength() > 0) + { + // Defer the evaluation of which function until it is actually used + // Store the namespace and name of the function for later + outResult->type.SetUndefinedFuncHandle(engine); + outResult->methodName = ns ? ns->name + "::" + name : name; + outResult->symbolNamespace = ns; + return SL_GLOBALFUNC; + } + } + + // Check for type names + if (ns) + { + asCTypeInfo *type = builder->GetType(name.AddressOf(), ns, 0); + if (type) + { + outResult->type.dataType = asCDataType::CreateType(type, false); + return SL_GLOBALTYPE; + } + } + + // Is it an enum value? + if (ns && !engine->ep.requireEnumScope) + { + // Look for the enum value without explicitly informing the enum type + asDWORD value = 0; + asCDataType dt; + int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns); + if (e) + { + 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. + outResult->enumValue = name.AddressOf(); + + // We cannot set a dummy value because it will pass through + // cleanly as an integer. + outResult->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0); + outResult->symbolNamespace = ns; + return SL_ENUMVAL; + } + else + { + // an enum value was resolved + outResult->type.SetConstantDW(dt, value); + outResult->symbolNamespace = ns; + return SL_ENUMVAL; + } + } + } + + // If the given scope starts with '::' then the search starts from global scope + if (scope.GetLength() >= 2 && scope[0] == ':') + break; + + // Move up to parent namespace + currNamespace = engine->GetParentNameSpace(currNamespace); + } + + // The name doesn't match any symbol + return SL_NOMATCH; } int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, asCObjectType *objType) { - asCExprContext lookupResult(engine); - SYMBOLTYPE symbolType = SymbolLookup(name, scope, objType, &lookupResult); - if (symbolType < 0) - { - // Give dummy value - ctx->type.SetDummy(); - - return -1; - } - if (symbolType == SL_NOMATCH) - { - // Give dummy value - ctx->type.SetDummy(); - - if (!isOptional) - { - // No matching symbol - asCString msg; - asCString smbl; - if (scope == "::") - smbl = scope; - else if (scope != "") - smbl = scope + "::"; - smbl += name; - msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf()); - Error(msg, errNode); - } - return -1; - } - - // It is a local variable or parameter? - if( symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR ) - { - // This is not accessible by default arg expressions - asASSERT(!isCompilingDefaultArg && scope == "" && !objType && variables); - - sVariable *v = variables->GetVariable(name.AddressOf()); - asASSERT(v); - - if( v->isPureConstant ) - ctx->type.SetConstantData(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); - - // Set as lvalue unless it is a const variable - if( !v->type.IsReadOnly() ) - 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); - - // Mark the object as safe for access unless it is a handle, as the - // life time of the object is guaranteed throughout the scope. - if( !v->type.IsObjectHandle() ) - ctx->type.isRefSafe = true; - - // Set as lvalue unless it is a const variable - if (!v->type.IsReadOnly()) - ctx->type.isLValue = true; - } - - return 0; - } - - // Is it a class member? - if (symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || symbolType == SL_CLASSMETHOD || symbolType == SL_THISPTR) - { - // This is not accessible by default arg expressions - asASSERT(!isCompilingDefaultArg); - - if (symbolType == SL_THISPTR) - { - asASSERT(name == THIS_TOKEN && !objType && scope == ""); - asCDataType dt = asCDataType::CreateType(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; - - // The 'this' handle is always considered safe (i.e. life time guaranteed) - ctx->type.isRefSafe = true; - - return 0; - } - - if (symbolType == SL_CLASSPROPACCESS) - { - if (scope != "") - { - // Cannot access non-static members like this - asCString msg; - msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); - Error(msg, errNode); - return -1; - } - - // See if there are any matching property accessors - asCExprContext access(engine); - if (objType) - access.type.Set(asCDataType::CreateType(objType, false)); - else - access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly())); - access.type.dataType.MakeReference(true); - int r = 0; - if (errNode->next && errNode->next->tokenType == ttOpenBracket) - { - // This is an index access, check if there is a property accessor that takes an index arg - asCExprContext 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 == 0 && access.property_set == 0) - { - // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments - asCString msg; - if (errNode->next && errNode->next->tokenType == ttOpenBracket) - msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf()); - else - msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf()); - Error(msg, errNode); - return -1; - } - - 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); - - return 0; - } - - if (symbolType == SL_CLASSPROP) - { - if (scope != "") - { - // Cannot access non-static members like this - asCString msg; - msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); - Error(msg, errNode); - return -1; - } - - asCDataType dt; - if (objType) - dt = asCDataType::CreateType(objType, false); - else - dt = asCDataType::CreateType(outFunc->objectType, false); - asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf()); - asASSERT(prop); - - // Is the property access allowed? - if (prop->isPrivate && prop->isInherited) - { - if (engine->ep.privatePropAsProtected) - { - // The application is allowing inherited classes to access private properties of the parent - // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions - // as it was how the compiler behaved earlier. - asCString msg; - msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf()); - Warning(msg, errNode); - } - else - { - asCString msg; - msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf()); - Error(msg, errNode); - } - } - - 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); - - // Objects that are members but not handles are safe as long as the parent object is safe - if (!objType || ctx->type.isRefSafe) - ctx->type.isRefSafe = true; - } - else if (ctx->type.dataType.IsObjectHandle()) - { - // Objects accessed through handles cannot be considered safe - // as the handle can be cleared at any time - ctx->type.isRefSafe = false; - } - - // If the object reference is const, the property will also be const - ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly()); - - return 0; - } - - if (symbolType == SL_CLASSMETHOD) - { - if (scope != "") - { - // Cannot access non-static members like this - asCString msg; - msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); - Error(msg, errNode); - return -1; - } + asCExprContext lookupResult(engine); + SYMBOLTYPE symbolType = SymbolLookup(name, scope, objType, &lookupResult); + if (symbolType < 0) + { + // Give dummy value + ctx->type.SetDummy(); + + return -1; + } + if (symbolType == SL_NOMATCH) + { + // Give dummy value + ctx->type.SetDummy(); + + if (!isOptional) + { + // No matching symbol + asCString msg; + asCString smbl; + if (scope == "::") + smbl = scope; + else if (scope != "") + smbl = scope + "::"; + smbl += name; + msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf()); + Error(msg, errNode); + } + return -1; + } + + // It is a local variable or parameter? + if( symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR ) + { + // This is not accessible by default arg expressions + asASSERT(!isCompilingDefaultArg && scope == "" && !objType && variables); + + sVariable *v = variables->GetVariable(name.AddressOf()); + asASSERT(v); + + if( v->isPureConstant ) + ctx->type.SetConstantData(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); + + // Set as lvalue unless it is a const variable + if( !v->type.IsReadOnly() ) + 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); + + // Mark the object as safe for access unless it is a handle, as the + // life time of the object is guaranteed throughout the scope. + if( !v->type.IsObjectHandle() ) + ctx->type.isRefSafe = true; + + // Set as lvalue unless it is a const variable + if (!v->type.IsReadOnly()) + ctx->type.isLValue = true; + } + + return 0; + } + + // Is it a class member? + if (symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || symbolType == SL_CLASSMETHOD || symbolType == SL_THISPTR) + { + // This is not accessible by default arg expressions + asASSERT(!isCompilingDefaultArg); + + if (symbolType == SL_THISPTR) + { + asASSERT(name == THIS_TOKEN && !objType && scope == ""); + asCDataType dt = asCDataType::CreateType(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; + + // The 'this' handle is always considered safe (i.e. life time guaranteed) + ctx->type.isRefSafe = true; + + return 0; + } + + if (symbolType == SL_CLASSPROPACCESS) + { + if (scope != "") + { + // Cannot access non-static members like this + asCString msg; + msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); + Error(msg, errNode); + return -1; + } + + // See if there are any matching property accessors + asCExprContext access(engine); + if (objType) + access.type.Set(asCDataType::CreateType(objType, false)); + else + access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly())); + access.type.dataType.MakeReference(true); + int r = 0; + if (errNode->next && errNode->next->tokenType == ttOpenBracket) + { + // This is an index access, check if there is a property accessor that takes an index arg + asCExprContext 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 == 0 && access.property_set == 0) + { + // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments + asCString msg; + if (errNode->next && errNode->next->tokenType == ttOpenBracket) + msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf()); + else + msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf()); + Error(msg, errNode); + return -1; + } + + 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); + + return 0; + } + + if (symbolType == SL_CLASSPROP) + { + if (scope != "") + { + // Cannot access non-static members like this + asCString msg; + msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); + Error(msg, errNode); + return -1; + } + + asCDataType dt; + if (objType) + dt = asCDataType::CreateType(objType, false); + else + dt = asCDataType::CreateType(outFunc->objectType, false); + asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf()); + asASSERT(prop); + + // Is the property access allowed? + if (prop->isPrivate && prop->isInherited) + { + if (engine->ep.privatePropAsProtected) + { + // The application is allowing inherited classes to access private properties of the parent + // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions + // as it was how the compiler behaved earlier. + asCString msg; + msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf()); + Warning(msg, errNode); + } + else + { + asCString msg; + msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf()); + Error(msg, errNode); + } + } + + 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); + + // Objects that are members but not handles are safe as long as the parent object is safe + if (!objType || ctx->type.isRefSafe) + ctx->type.isRefSafe = true; + } + else if (ctx->type.dataType.IsObjectHandle()) + { + // Objects accessed through handles cannot be considered safe + // as the handle can be cleared at any time + ctx->type.isRefSafe = false; + } + + // If the object reference is const, the property will also be const + ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly()); + + return 0; + } + + if (symbolType == SL_CLASSMETHOD) + { + if (scope != "") + { + // Cannot access non-static members like this + asCString msg; + msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); + Error(msg, errNode); + return -1; + } #if AS_DEBUG - // If it is not a property, it may still be the name of a method which can be used to create delegates - asCObjectType *ot = outFunc->objectType; - asCScriptFunction *func = 0; - for (asUINT n = 0; n < ot->methods.GetLength(); n++) - { - asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; - if (f->name == name && - (builder->module->m_accessMask & f->accessMask)) - { - func = f; - break; - } - } - - asASSERT(func); + // 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++) + { + asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; + if (f->name == name && + (builder->module->m_accessMask & f->accessMask)) + { + func = f; + break; + } + } + + asASSERT(func); #endif - // An object method was found. Keep the name of the method in the expression, but - // don't actually modify the bytecode at this point since it is not yet known what - // the method will be used for, or even what overloaded method should be used. - 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::CreateType(outFunc->objectType, false), 0, false); - ctx->type.dataType.MakeReference(true); - Dereference(ctx, true); - } - - return 0; - } - } - - if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALVAR || symbolType == SL_GLOBALFUNC || symbolType == SL_ENUMVAL) - { - // Get the namespace from SymbolLookup - asSNameSpace *ns = lookupResult.symbolNamespace; - - if (symbolType == SL_GLOBALPROPACCESS) - { - // See if there are any matching global property accessors - asCExprContext access(engine); - int r = 0; - if (errNode->next && errNode->next->tokenType == ttOpenBracket) - { - // This is an index access, check if there is a property accessor that takes an index arg - asCExprContext 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 == 0 && access.property_set == 0) - { - // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments - asCString msg; - if (errNode->next && errNode->next->tokenType == ttOpenBracket) - msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf()); - else - msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf()); - Error(msg, errNode); - return -1; - } - - // Prepare the bytecode for the function call - MergeExprBytecodeAndType(ctx, &access); - - return 0; - } - - if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR) - { - bool isCompiled = true; - bool isPureConstant = false; - bool isAppProp = false; - asQWORD constantValue = 0; - asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp); - asASSERT(prop); - - // Verify that the global property has been compiled already - if (!isCompiled) - { - asCString str; - str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf()); - Error(str, errNode); - return -1; - } - - // 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.SetConstantData(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. - // This check is not needed for application registered properties, since they - // are guaranteed to be valid by the application itself. - if (!isAppProp && - ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) || - !ctx->type.dataType.IsObjectHandle())) - { - 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.GetTypeInfo()->flags & asOBJ_VALUE) || - ctx->type.dataType.IsObjectHandle()) - { - ctx->type.dataType.MakeReference(true); - } - else - { - asASSERT((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle()); - - // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object - ctx->bc.Instr(asBC_RDSPtr); - } - } - } - - return 0; - } - - if (symbolType == SL_GLOBALFUNC) - { - asCArray funcs; - - builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); - asASSERT(funcs.GetLength() > 0); - - if (funcs.GetLength() > 0) - { - // 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; - } - - return 0; - } - - if (symbolType == SL_ENUMVAL) - { - // The enum type and namespace must be returned from SymbolLookup - asCDataType dt = lookupResult.type.dataType; - if (!dt.IsEnumType()) - { - asASSERT(!engine->ep.requireEnumScope); - - // It is an ambigious enum value. The evaluation needs to be deferred for when the type is known - ctx->enumValue = name.AddressOf(); - ctx->symbolNamespace = lookupResult.symbolNamespace; - - // 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; - } - - asDWORD value = 0; - builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value); - - // Even if the enum type is not shared, and we're compiling a shared object, - // the use of the values are still allowed, since they are treated as constants. - - // an enum value was resolved - ctx->type.SetConstantDW(dt, value); - return 0; - } - } - - // The result must have been identified above - if (symbolType == SL_GLOBALTYPE || symbolType == SL_CLASSTYPE) - { - // Give dummy value - ctx->type.SetDummy(); - - // The symbol matches a type - asCString msg; - asCString smbl; - if (scope == "::") - smbl = scope; - else if (scope != "") - smbl = scope + "::"; - smbl += name; - msg.Format(TXT_EXPR_s_IS_DATA_TYPE, smbl.AddressOf()); - Error(msg, errNode); - return -1; - } - - // Should not come here - asASSERT(false); - return 0; + // 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::CreateType(outFunc->objectType, false), 0, false); + ctx->type.dataType.MakeReference(true); + Dereference(ctx, true); + } + + return 0; + } + } + + if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALVAR || symbolType == SL_GLOBALFUNC || symbolType == SL_ENUMVAL) + { + // Get the namespace from SymbolLookup + asSNameSpace *ns = lookupResult.symbolNamespace; + + if (symbolType == SL_GLOBALPROPACCESS) + { + // See if there are any matching global property accessors + asCExprContext access(engine); + int r = 0; + if (errNode->next && errNode->next->tokenType == ttOpenBracket) + { + // This is an index access, check if there is a property accessor that takes an index arg + asCExprContext 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 == 0 && access.property_set == 0) + { + // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments + asCString msg; + if (errNode->next && errNode->next->tokenType == ttOpenBracket) + msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf()); + else + msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf()); + Error(msg, errNode); + return -1; + } + + // Prepare the bytecode for the function call + MergeExprBytecodeAndType(ctx, &access); + + return 0; + } + + if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR) + { + bool isCompiled = true; + bool isPureConstant = false; + bool isAppProp = false; + asQWORD constantValue = 0; + asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp); + asASSERT(prop); + + // Verify that the global property has been compiled already + if (!isCompiled) + { + asCString str; + str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf()); + Error(str, errNode); + return -1; + } + + // 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.SetConstantData(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. + // This check is not needed for application registered properties, since they + // are guaranteed to be valid by the application itself. + if (!isAppProp && + ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) || + !ctx->type.dataType.IsObjectHandle())) + { + 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.GetTypeInfo()->flags & asOBJ_VALUE) || + ctx->type.dataType.IsObjectHandle()) + { + ctx->type.dataType.MakeReference(true); + } + else + { + asASSERT((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle()); + + // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object + ctx->bc.Instr(asBC_RDSPtr); + } + } + } + + return 0; + } + + if (symbolType == SL_GLOBALFUNC) + { + asCArray funcs; + + builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); + asASSERT(funcs.GetLength() > 0); + + if (funcs.GetLength() > 0) + { + // 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; + } + + return 0; + } + + if (symbolType == SL_ENUMVAL) + { + // The enum type and namespace must be returned from SymbolLookup + asCDataType dt = lookupResult.type.dataType; + if (!dt.IsEnumType()) + { + asASSERT(!engine->ep.requireEnumScope); + + // It is an ambigious enum value. The evaluation needs to be deferred for when the type is known + ctx->enumValue = name.AddressOf(); + ctx->symbolNamespace = lookupResult.symbolNamespace; + + // 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; + } + + asDWORD value = 0; + builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value); + + // Even if the enum type is not shared, and we're compiling a shared object, + // the use of the values are still allowed, since they are treated as constants. + + // an enum value was resolved + ctx->type.SetConstantDW(dt, value); + return 0; + } + } + + // The result must have been identified above + if (symbolType == SL_GLOBALTYPE || symbolType == SL_CLASSTYPE) + { + // Give dummy value + ctx->type.SetDummy(); + + // The symbol matches a type + asCString msg; + asCString smbl; + if (scope == "::") + smbl = scope; + else if (scope != "") + smbl = scope + "::"; + smbl += name; + msg.Format(TXT_EXPR_s_IS_DATA_TYPE, smbl.AddressOf()); + Error(msg, errNode); + return -1; + } + + // Should not come here + asASSERT(false); + return 0; } int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *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); - - bool overflow = false; - asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow); - - // Is the number bigger than a 64bit word? - if (overflow) - { - Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode); - - // Set the value to zero to avoid further warnings - val = 0; - } - - // Do we need 64 bits? - // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid - // 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 - bool overflow = false; - asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow); - - // Is the number bigger than a 64bit word? - if (overflow) - { - Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode); - - // Set the value to zero to avoid further warnings - val = 0; - } - - // Do we need 64 bits? - if( val>>32 ) - 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); + // 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); + + bool overflow = false; + asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow); + + // Is the number bigger than a 64bit word? + if (overflow) + { + Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode); + + // Set the value to zero to avoid further warnings + val = 0; + } + + // Do we need 64 bits? + // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid + // 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 + bool overflow = false; + asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow); + + // Is the number bigger than a 64bit word? + if (overflow) + { + Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode); + + // Set the value to zero to avoid further warnings + val = 0; + } + + // Do we need 64 bits? + if( val>>32 ) + 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); + // 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 ) - { + } + 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); + 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); + 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() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 ) - { - // This is the start of a UTF8 encoded character. We need to decode it - val = asStringDecodeUTF8(str.AddressOf(), 0); - 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 - if(engine->stringFactory == 0 ) - { - // Error - Error(TXT_STRINGS_NOT_RECOGNIZED, vnode); - - // Give dummy value - ctx->type.SetDummy(); - return -1; - } - else - { - void *strPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength())); - if (strPtr == 0) - { - // TODO: A better message is needed - Error(TXT_NULL_POINTER_ACCESS, vnode); - ctx->type.SetDummy(); - return -1; - } - - // Keep the pointer in the list for clean up at exit - usedStringConstants.PushLast(strPtr); - - // Push the pointer on the stack. The string factory already guarantees that the - // string object is valid throughout the lifetime of the script so no need to add - // reference count or make local copy. - ctx->bc.InstrPTR(asBC_PGA, strPtr); - ctx->type.Set(engine->stringType); - - // Mark the string as literal constant so the compiler knows it is allowed - // to treat it differently than an ordinary constant string variable - ctx->type.isConstant = true; - - // Mark the reference to the string constant as safe, so the compiler can - // avoid making unnecessary temporary copies when passing the reference to - // functions. - ctx->type.isRefSafe = true; - } - } - } - 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 ) - { - return CompileConstructCall(vnode, ctx); - } - else if( vnode->nodeType == snAssignment ) - { - asCExprContext 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 - return CompileConversion(vnode, ctx); - } - else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid ) - { - // This is a void expression - ctx->SetVoidExpression(); - } - else if( vnode->nodeType == snFunction ) - { - // This is an anonymous function - // Defer the evaluation of the function until it is known where it - // will be used, which is where the signature will be defined - ctx->SetLambda(vnode); - } - else - asASSERT(false); - - return 0; + } + 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() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 ) + { + // This is the start of a UTF8 encoded character. We need to decode it + val = asStringDecodeUTF8(str.AddressOf(), 0); + 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 + if(engine->stringFactory == 0 ) + { + // Error + Error(TXT_STRINGS_NOT_RECOGNIZED, vnode); + + // Give dummy value + ctx->type.SetDummy(); + return -1; + } + else + { + void *strPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength())); + if (strPtr == 0) + { + // TODO: A better message is needed + Error(TXT_NULL_POINTER_ACCESS, vnode); + ctx->type.SetDummy(); + return -1; + } + + // Keep the pointer in the list for clean up at exit + usedStringConstants.PushLast(strPtr); + + // Push the pointer on the stack. The string factory already guarantees that the + // string object is valid throughout the lifetime of the script so no need to add + // reference count or make local copy. + ctx->bc.InstrPTR(asBC_PGA, strPtr); + ctx->type.Set(engine->stringType); + + // Mark the string as literal constant so the compiler knows it is allowed + // to treat it differently than an ordinary constant string variable + ctx->type.isConstant = true; + + // Mark the reference to the string constant as safe, so the compiler can + // avoid making unnecessary temporary copies when passing the reference to + // functions. + ctx->type.isRefSafe = true; + } + } + } + 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 ) + { + return CompileConstructCall(vnode, ctx); + } + else if( vnode->nodeType == snAssignment ) + { + asCExprContext 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 + return CompileConversion(vnode, ctx); + } + else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid ) + { + // This is a void expression + ctx->SetVoidExpression(); + } + else if( vnode->nodeType == snFunction ) + { + // This is an anonymous function + // Defer the evaluation of the function until it is known where it + // will be used, which is where the signature will be defined + ctx->SetLambda(vnode); + } + else + asASSERT(false); + + return 0; } asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences) { - int charLiteral = -1; + int charLiteral = -1; - // Process escape sequences - asCArray str((int)cstr.GetLength()); + // Process escape sequences + asCArray str((int)cstr.GetLength()); - for( asUINT n = 0; n < cstr.GetLength(); n++ ) - { + 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; - } + // 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 - { + 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)); + str.PushLast((asBYTE)val); + str.PushLast((asBYTE)(val>>8)); #else - str.PushLast((asBYTE)(val>>8)); - str.PushLast((asBYTE)val); + 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; + } + 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 - bool isMultiline = false; - int start; - for( start = 0; start < (int)str.GetLength(); start++ ) - { - if( str[start] == '\n' ) - { - isMultiline = true; - - // Remove the linebreak as well - start++; - break; - } - - 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 || engine->ep.heredocTrimMode != 2 ) - { - // if heredocTrimMode == 0 the string shouldn't be trimmed - // if heredocTrimMode == 1 the string should only be trimmed if it is multiline - // if heredocTrimMode == 2 the string should always be trimmed - if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1)) - tmp.Assign(&str[start], end - start); - else - tmp = str; - } - - ProcessStringConstant(tmp, node, false); - - str = tmp; + // Remove first line if it only contains whitespace + bool isMultiline = false; + int start; + for( start = 0; start < (int)str.GetLength(); start++ ) + { + if( str[start] == '\n' ) + { + isMultiline = true; + + // Remove the linebreak as well + start++; + break; + } + + 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 || engine->ep.heredocTrimMode != 2 ) + { + // if heredocTrimMode == 0 the string shouldn't be trimmed + // if heredocTrimMode == 1 the string should only be trimmed if it is multiline + // if heredocTrimMode == 2 the string should always be trimmed + if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1)) + tmp.Assign(&str[start], end - start); + else + tmp = str; + } + + ProcessStringConstant(tmp, node, false); + + str = tmp; } int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx) { - asCExprContext expr(engine); - asCDataType to; - bool anyErrors = false; - EImplicitConv convType; - if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall ) - { - 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 if (node->lastChild->firstChild && - node->lastChild->firstChild->nodeType == snNamedArgument) - { - Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild); - expr.type.SetDummy(); - anyErrors = true; - } - else - { - // Compile the expression - 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); - - // If the type support object handles, then use it - if( to.SupportHandles() ) - { - to.MakeHandle(true); - if( expr.type.dataType.IsObjectConst() ) - to.MakeHandleToConst(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.GetTypeInfo() && !to.GetTypeInfo()->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf()); - Error(msg, node); - anyErrors = true; - } - - if( anyErrors ) - { - // Assume that the error can be fixed and allow the compilation to continue - ctx->type.Set(to); - return -1; - } - - if( ProcessPropertyGetAccessor(&expr, node) < 0 ) - return -1; - - // Don't allow any operators on expressions that take address of class method - if( expr.IsClassMethod() ) - { - Error(TXT_INVALID_OP_ON_METHOD, node); - return -1; - } - - // 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 0; - } - - if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() ) - { - MergeExprBytecode(ctx, &expr); - ctx->type = expr.type; - ctx->type.dataType.MakeReadOnly(true); - return 0; - } - - // 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 0; - - // Conversion not available - ctx->type.SetDummy(); - - asCString strTo, strFrom; - - strTo = to.Format(outFunc->nameSpace); - strFrom = expr.type.dataType.Format(outFunc->nameSpace); - - asCString msg; - msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf()); - - Error(msg, node); - return -1; + asCExprContext expr(engine); + asCDataType to; + bool anyErrors = false; + EImplicitConv convType; + if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall ) + { + 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 if (node->lastChild->firstChild && + node->lastChild->firstChild->nodeType == snNamedArgument) + { + Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild); + expr.type.SetDummy(); + anyErrors = true; + } + else + { + // Compile the expression + 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); + + // If the type support object handles, then use it + if( to.SupportHandles() ) + { + to.MakeHandle(true); + if( expr.type.dataType.IsObjectConst() ) + to.MakeHandleToConst(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.GetTypeInfo() && !to.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf()); + Error(msg, node); + anyErrors = true; + } + + if( anyErrors ) + { + // Assume that the error can be fixed and allow the compilation to continue + ctx->type.Set(to); + return -1; + } + + if( ProcessPropertyGetAccessor(&expr, node) < 0 ) + return -1; + + // Don't allow any operators on expressions that take address of class method + if( expr.IsClassMethod() ) + { + Error(TXT_INVALID_OP_ON_METHOD, node); + return -1; + } + + // 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 0; + } + + if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() ) + { + MergeExprBytecode(ctx, &expr); + ctx->type = expr.type; + ctx->type.dataType.MakeReadOnly(true); + return 0; + } + + // 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 0; + + // Conversion not available + ctx->type.SetDummy(); + + asCString strTo, strFrom; + + strTo = to.Format(outFunc->nameSpace); + strFrom = expr.type.dataType.Format(outFunc->nameSpace); + + asCString msg; + msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf()); + + Error(msg, node); + return -1; } void asCCompiler::AfterFunctionCall(int funcID, asCArray &args, asCExprContext *ctx, bool deferAll) { - // deferAll is set to true if for example the function returns a reference, since in - // 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, except if the argument is clean, in which case the actual reference was passed in to the function - // If deferAll is set all objects passed by reference or handle must be deferred - if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) || - (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]->isCleanArg) || 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); - } + // 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, except if the argument is clean, in which case the actual reference was passed in to the function + // If deferAll is set all objects passed by reference or handle must be deferred + if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) || + (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]->isCleanArg) || 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(asCExprContext *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 ) - { - asCExprContext *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 ) - { - asCExprContext 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; - } - - asCExprContext 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->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->IsVoidExpression() && !expr->type.IsNullConstant() && - !(expr->type.isConstant && expr->type.dataType.IsPrimitive() && expr->type.GetConstantData() == 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, asCExprContext); - } - 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.GetTypeInfo()->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; + 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 ) + { + asCExprContext *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 ) + { + asCExprContext 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; + } + + asCExprContext 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->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->IsVoidExpression() && !expr->type.IsNullConstant() && + !(expr->type.isConstant && expr->type.dataType.IsPrimitive() && expr->type.GetConstantData() == 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, asCExprContext); + } + 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.GetTypeInfo()->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; } int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx) { - // The first node is a datatype node - asCString name; - asCExprValue tempObj; - bool onHeap = true; - asCArray funcs; - bool error = false; - - // It is possible that the name is really a constructor - asCDataType dt; - dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType); - if( dt.IsPrimitive() ) - { - // This is a cast to a primitive type - return CompileConversion(node, ctx); - } - - if( dt.GetTypeInfo() && (dt.GetTypeInfo()->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(outFunc->nameSpace).AddressOf()); - Error(str, node); - ctx->type.SetDummy(); - return -1; - } - - // Make sure the desired type can actually be instantiated - // Delegates are allowed to be created through construct calls, - // even though they cannot be instantiated as variables - if( !dt.CanBeInstantiated() && !dt.IsFuncdef() ) - { - asCString str; - if( dt.IsAbstractClass() ) - str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf()); - else if( dt.IsInterface() ) - str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf()); - else - // TODO: Improve error message to explain why - str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - ctx->type.SetDummy(); - return -1; - } - - // Do not allow constructing non-shared types in shared functions - if( outFunc->IsShared() && - dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) - { - asCString msg; - msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); - Error(msg, node); - return -1; - } - - // 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 ) - { - asCExprContext conv(engine); - conv.Copy(args[0]); - asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false); - - // Clean the property_arg in the temporary copy so - // it isn't deleted when conv goes out of scope - conv.property_arg = 0; - - // Don't use this if the cost is 0 because it would mean that nothing - // is done and the script wants a new value to be constructed - if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 ) - { - // Make sure the result is a reference, just as if to a local variable - dt.MakeReference(true); - - // Make sure any property accessor is already evaluated - if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 ) - return -1; - - ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST); - - ctx->bc.AddCode(&args[0]->bc); - ctx->type = args[0]->type; - - asDELETE(args[0], asCExprContext); - - return 0; - } - } - - // Check for possible constructor/factory - name = dt.Format(outFunc->nameSpace); - - asSTypeBehaviour *beh = dt.GetBehaviour(); - - if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() ) - { - 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 if( beh ) - 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], asCExprContext); - 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 ) - { - beh = tempObj.dataType.GetBehaviour(); - if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->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 0; - } - } - - // Special case: If this is a construction of a delegate and the expression names an object method - if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" ) - { - // TODO: delegate: It is possible that the argument returns a function pointer already, in which - // case no object delegate will be created, but instead a delegate for a function pointer - // 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); - error = true; - } - else - { - // Filter the available object methods to find the one that matches the func def - asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo()); - 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(CastToFuncdefType(dt.GetTypeInfo())->funcdef) ) - { - 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 delegateFuncs; - builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]); - asASSERT(delegateFuncs.GetLength() == 1 ); - ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE); - - // Store the returned delegate in a temporary variable - int returnOffset = AllocateVariable(dt, true, false); - 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); - - // Clean up arguments - ReleaseTemporaryVariable(args[0]->type, &ctx->bc); - } - else - { - asCString msg; - msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration()); - Error(msg.AddressOf(), node); - error = true; - } - } - - // Clean-up arg - asDELETE(args[0], asCExprContext); - return error ? -1 : 0; - } - - MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false); - - if( funcs.GetLength() != 1 ) - { - // The error was reported by MatchFunctions() - error = true; - - // 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], CastToObjectType(dt.GetTypeInfo()), &namedArgs); - - if( r == asSUCCESS ) - { - asCByteCode objBC(engine); - - PrepareFunctionCall(funcs[0], &ctx->bc, args); - - MoveArgsToStack(funcs[0], &ctx->bc, args, false); - - if( !(dt.GetTypeInfo()->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, CastToObjectType(tempObj.dataType.GetTypeInfo())); - - // 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 - error = true; - } - } - else - { - // Failed to compile the argument list, set the result to the dummy type - ctx->type.SetDummy(); - error = true; - } - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n], asCExprContext); - } - for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) - if( namedArgs[n].ctx ) - { - asDELETE(namedArgs[n].ctx, asCExprContext); - } - - return error ? -1 : 0; + // The first node is a datatype node + asCString name; + asCExprValue tempObj; + bool onHeap = true; + asCArray funcs; + bool error = false; + + // It is possible that the name is really a constructor + asCDataType dt; + dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType); + if( dt.IsPrimitive() ) + { + // This is a cast to a primitive type + return CompileConversion(node, ctx); + } + + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->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(outFunc->nameSpace).AddressOf()); + Error(str, node); + ctx->type.SetDummy(); + return -1; + } + + // Make sure the desired type can actually be instantiated + // Delegates are allowed to be created through construct calls, + // even though they cannot be instantiated as variables + if( !dt.CanBeInstantiated() && !dt.IsFuncdef() ) + { + asCString str; + if( dt.IsAbstractClass() ) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf()); + else if( dt.IsInterface() ) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + ctx->type.SetDummy(); + return -1; + } + + // Do not allow constructing non-shared types in shared functions + if( outFunc->IsShared() && + dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + Error(msg, node); + return -1; + } + + // 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 ) + { + asCExprContext conv(engine); + conv.Copy(args[0]); + asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false); + + // Clean the property_arg in the temporary copy so + // it isn't deleted when conv goes out of scope + conv.property_arg = 0; + + // Don't use this if the cost is 0 because it would mean that nothing + // is done and the script wants a new value to be constructed + if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 ) + { + // Make sure the result is a reference, just as if to a local variable + dt.MakeReference(true); + + // Make sure any property accessor is already evaluated + if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 ) + return -1; + + ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST); + + ctx->bc.AddCode(&args[0]->bc); + ctx->type = args[0]->type; + + asDELETE(args[0], asCExprContext); + + return 0; + } + } + + // Check for possible constructor/factory + name = dt.Format(outFunc->nameSpace); + + asSTypeBehaviour *beh = dt.GetBehaviour(); + + if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() ) + { + 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 if( beh ) + 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], asCExprContext); + 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 ) + { + beh = tempObj.dataType.GetBehaviour(); + if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->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 0; + } + } + + // Special case: If this is a construction of a delegate and the expression names an object method + if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" ) + { + // TODO: delegate: It is possible that the argument returns a function pointer already, in which + // case no object delegate will be created, but instead a delegate for a function pointer + // 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); + error = true; + } + else + { + // Filter the available object methods to find the one that matches the func def + asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo()); + 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(CastToFuncdefType(dt.GetTypeInfo())->funcdef) ) + { + 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 delegateFuncs; + builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]); + asASSERT(delegateFuncs.GetLength() == 1 ); + ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE); + + // Store the returned delegate in a temporary variable + int returnOffset = AllocateVariable(dt, true, false); + 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); + + // Clean up arguments + ReleaseTemporaryVariable(args[0]->type, &ctx->bc); + } + else + { + asCString msg; + msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration()); + Error(msg.AddressOf(), node); + error = true; + } + } + + // Clean-up arg + asDELETE(args[0], asCExprContext); + return error ? -1 : 0; + } + + MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false); + + if( funcs.GetLength() != 1 ) + { + // The error was reported by MatchFunctions() + error = true; + + // 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], CastToObjectType(dt.GetTypeInfo()), &namedArgs); + + if( r == asSUCCESS ) + { + asCByteCode objBC(engine); + + PrepareFunctionCall(funcs[0], &ctx->bc, args); + + MoveArgsToStack(funcs[0], &ctx->bc, args, false); + + if( !(dt.GetTypeInfo()->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, CastToObjectType(tempObj.dataType.GetTypeInfo())); + + // 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 + error = true; + } + } + else + { + // Failed to compile the argument list, set the result to the dummy type + ctx->type.SetDummy(); + error = true; + } + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) + if( namedArgs[n].ctx ) + { + asDELETE(namedArgs[n].ctx, asCExprContext); + } + + return error ? -1 : 0; } int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope) { - asCExprValue tempObj; - asCArray funcs; - int localVar = -1; - bool initializeMembers = false; - asCExprContext funcExpr(engine); - - asCScriptNode *nm = node->lastChild->prev; - asCString name(&script->code[nm->tokenPos], nm->tokenLength); - - // Find the matching entities - // If objectType is set then this is a post op expression and we shouldn't look for local variables - asCExprContext lookupResult(engine); - SYMBOLTYPE symbolType = SymbolLookup(name, scope, objectType, &lookupResult); - if (symbolType < 0) - return -1; - if (symbolType == SL_NOMATCH) - { - // No matching symbol - asCString msg; - asCString smbl; - if (scope == "::") - smbl = scope; - else if (scope != "") - smbl = scope + "::"; - smbl += name; - msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf()); - Error(msg, node); - return -1; - } - - // Is the symbol matching a variable/property? - if (symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR || - symbolType == SL_THISPTR || symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || - symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR || symbolType == SL_ENUMVAL) - { - // Variables/properties can be used as functions if they have the opCall - - // Compile the variable - // TODO: Take advantage of the known symbol, so it doesn't have to be looked up again - localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType); - if( localVar < 0 ) - return -1; - - if (funcExpr.type.dataType.IsFuncdef()) - { - funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->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 - if (ctx->type.dataType.IsObject()) - { - // Make sure the ProcessPropertyGetAccess knows whether or not to - // dereference the original object before calling the get accessor - funcExpr.property_ref = ctx->type.dataType.IsReference(); - } - MergeExprBytecodeAndType(ctx, &funcExpr); - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - Dereference(ctx, true); - - objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo()); - - // 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", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst); - } - else - { - // The variable is not a function or object with opCall - asCString msg; - msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), lookupResult.type.dataType.Format(outFunc->nameSpace).AddressOf()); - Error(msg, node); - return -1; - } - } - - // Is the symbol matching a class method? - if (symbolType == SL_CLASSMETHOD) - { - // 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 can be used to specify the base class - builder->GetObjectMethodDescriptions(name.AddressOf(), CastToObjectType(lookupResult.type.dataType.GetTypeInfo()), funcs, objIsConst, scope, node, script); - } - - // If a class method is being called implicitly, then add the this pointer for the call - if (funcs.GetLength() && !objectType && outFunc->objectType) - { - // Verify that the identified function is actually part of the class hierarchy - if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo())) - { - asCString msg; - asCString mthd; - if (scope == "") - mthd = name; - else if (scope == "::") - mthd = scope + name; - else - mthd = scope + "::" + name; - - msg.Format(TXT_METHOD_s_NOT_PART_OF_OBJECT_s, mthd.AddressOf(), outFunc->objectType->name.AddressOf()); - Error(msg, node); - return -1; - } - - objectType = outFunc->objectType; - - asCDataType dt = asCDataType::CreateType(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); - } - else if (funcs.GetLength() && !objectType && !outFunc->objectType) - { - // Cannot call class methods directly without the object - asCString msg; - msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); - Error(msg, node); - return -1; - } - } - - // Is it a global function? - if (symbolType == SL_GLOBALFUNC) - { - // The symbol lookup identified the namespace to use - int n = lookupResult.methodName.FindLast("::"); - asSNameSpace *ns = engine->FindNameSpace(lookupResult.methodName.SubString(0, n).AddressOf()); - - builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); - } - - // Is it a type? - if (symbolType == SL_CLASSTYPE || symbolType == SL_GLOBALTYPE) - { - bool isValid = false; - asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType, false, &isValid); - if (isValid) - return CompileConstructCall(node, ctx); - } - - // 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.IsVoid() && !args[0]->IsVoidExpression() ) - { - // Evaluate the expression before the function call - MergeExprBytecode(ctx, args[0]); - asDELETE(args[0], asCExprContext); - 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 the object pointer to access the member - Dereference(ctx, true); - } - - if( funcExpr.property_get > 0 ) - { - if( ProcessPropertyGetAccessor(&funcExpr, node) < 0 ) - return -1; - Dereference(&funcExpr, true); - } - else - { - Dereference(&funcExpr, true); - ConvertToVariable(&funcExpr); - } - - // The actual function should be called as if a global function - objectType = 0; - - // 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); - - asCExprValue tmp = ctx->type; - MergeExprBytecodeAndType(ctx, &funcExpr); - ReleaseTemporaryVariable(tmp, &ctx->bc); - } - - r = MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset); - if( r < 0 ) - { - ctx->type.SetDummy(); - isOK = false; - } - } - 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], asCExprContext); - } - for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) - if( namedArgs[n].ctx ) - { - asDELETE(namedArgs[n].ctx, asCExprContext); - } - - 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; + asCExprValue tempObj; + asCArray funcs; + int localVar = -1; + bool initializeMembers = false; + asCExprContext funcExpr(engine); + + asCScriptNode *nm = node->lastChild->prev; + asCString name(&script->code[nm->tokenPos], nm->tokenLength); + + // Find the matching entities + // If objectType is set then this is a post op expression and we shouldn't look for local variables + asCExprContext lookupResult(engine); + SYMBOLTYPE symbolType = SymbolLookup(name, scope, objectType, &lookupResult); + if (symbolType < 0) + return -1; + if (symbolType == SL_NOMATCH) + { + // No matching symbol + asCString msg; + asCString smbl; + if (scope == "::") + smbl = scope; + else if (scope != "") + smbl = scope + "::"; + smbl += name; + msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf()); + Error(msg, node); + return -1; + } + + // Is the symbol matching a variable/property? + if (symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR || + symbolType == SL_THISPTR || symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || + symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR || symbolType == SL_ENUMVAL) + { + // Variables/properties can be used as functions if they have the opCall + + // Compile the variable + // TODO: Take advantage of the known symbol, so it doesn't have to be looked up again + localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType); + if( localVar < 0 ) + return -1; + + if (funcExpr.type.dataType.IsFuncdef()) + { + funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->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 + if (ctx->type.dataType.IsObject()) + { + // Make sure the ProcessPropertyGetAccess knows whether or not to + // dereference the original object before calling the get accessor + funcExpr.property_ref = ctx->type.dataType.IsReference(); + } + MergeExprBytecodeAndType(ctx, &funcExpr); + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + Dereference(ctx, true); + + objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo()); + + // 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", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst); + } + else + { + // The variable is not a function or object with opCall + asCString msg; + msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), lookupResult.type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(msg, node); + return -1; + } + } + + // Is the symbol matching a class method? + if (symbolType == SL_CLASSMETHOD) + { + // 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 can be used to specify the base class + builder->GetObjectMethodDescriptions(name.AddressOf(), CastToObjectType(lookupResult.type.dataType.GetTypeInfo()), funcs, objIsConst, scope, node, script); + } + + // If a class method is being called implicitly, then add the this pointer for the call + if (funcs.GetLength() && !objectType && outFunc->objectType) + { + // Verify that the identified function is actually part of the class hierarchy + if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo())) + { + asCString msg; + asCString mthd; + if (scope == "") + mthd = name; + else if (scope == "::") + mthd = scope + name; + else + mthd = scope + "::" + name; + + msg.Format(TXT_METHOD_s_NOT_PART_OF_OBJECT_s, mthd.AddressOf(), outFunc->objectType->name.AddressOf()); + Error(msg, node); + return -1; + } + + objectType = outFunc->objectType; + + asCDataType dt = asCDataType::CreateType(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); + } + else if (funcs.GetLength() && !objectType && !outFunc->objectType) + { + // Cannot call class methods directly without the object + asCString msg; + msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); + Error(msg, node); + return -1; + } + } + + // Is it a global function? + if (symbolType == SL_GLOBALFUNC) + { + // The symbol lookup identified the namespace to use + int n = lookupResult.methodName.FindLast("::"); + asSNameSpace *ns = engine->FindNameSpace(lookupResult.methodName.SubString(0, n).AddressOf()); + + builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); + } + + // Is it a type? + if (symbolType == SL_CLASSTYPE || symbolType == SL_GLOBALTYPE) + { + bool isValid = false; + asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType, false, &isValid); + if (isValid) + return CompileConstructCall(node, ctx); + } + + // 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.IsVoid() && !args[0]->IsVoidExpression() ) + { + // Evaluate the expression before the function call + MergeExprBytecode(ctx, args[0]); + asDELETE(args[0], asCExprContext); + 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 the object pointer to access the member + Dereference(ctx, true); + } + + if( funcExpr.property_get > 0 ) + { + if( ProcessPropertyGetAccessor(&funcExpr, node) < 0 ) + return -1; + Dereference(&funcExpr, true); + } + else + { + Dereference(&funcExpr, true); + ConvertToVariable(&funcExpr); + } + + // The actual function should be called as if a global function + objectType = 0; + + // 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); + + asCExprValue tmp = ctx->type; + MergeExprBytecodeAndType(ctx, &funcExpr); + ReleaseTemporaryVariable(tmp, &ctx->bc); + } + + r = MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset); + if( r < 0 ) + { + ctx->type.SetDummy(); + isOK = false; + } + } + 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], asCExprContext); + } + for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) + if( namedArgs[n].ctx ) + { + asDELETE(namedArgs[n].ctx, asCExprContext); + } + + 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 == "" ) - { - // When compiling default argument expression the correct namespace is stored in the outFunc even for objects - if( outFunc->nameSpace->name != "" || isCompilingDefaultArg ) - 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; + asSNameSpace *ns; + + if( scope == "" ) + { + // When compiling default argument expression the correct namespace is stored in the outFunc even for objects + if( outFunc->nameSpace->name != "" || isCompilingDefaultArg ) + 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, asCExprContext *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->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.SupportHandles() && !ctx->type.dataType.IsObjectHandle() ) - { - 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.dataType.IsFuncdef()) && !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.GetTypeInfo()->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.GetTypeInfo()->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 - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - // 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 = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - if( func->name == opName && - func->parameterTypes.GetLength() == 0 && - (!isConst || func->IsReadOnly()) ) - { - funcs.PushLast(func->id); - } - } - - // Did we find the method? - if( funcs.GetLength() == 1 ) - { - asCArray args; - return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); - } - 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; - } - - - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - 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()) - { - if (ctx->type.dataType.GetSizeInMemoryBytes() == 4) - ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW()); - else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2) - ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW()); - else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1) - ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB()); - else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8) - ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW()); - } - else if( ctx->type.dataType.IsFloatType() ) - ctx->type.SetConstantF(-ctx->type.GetConstantF()); - else if( ctx->type.dataType.IsDoubleType() ) - ctx->type.SetConstantD(-ctx->type.GetConstantD()); - else - { - Error(TXT_ILLEGAL_OPERATION, node); - return -1; - } - - return 0; - } - } - } - else if( op == ttNot ) - { - // Allow value types to be converted to bool using 'bool opImplConv()' - if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) - ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV); - - if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) - { - if( ctx->type.isConstant ) - { - #if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - #else - ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); - #endif - return 0; - } - - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - 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 ) - { - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - 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 ) - { - if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) - ctx->type.SetConstantB(~ctx->type.GetConstantB()); - else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2) - ctx->type.SetConstantW(~ctx->type.GetConstantW()); - else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4) - ctx->type.SetConstantDW(~ctx->type.GetConstantDW()); - else - ctx->type.SetConstantQW(~ctx->type.GetConstantQW()); - return 0; - } - - 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; + 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->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.SupportHandles() && !ctx->type.dataType.IsObjectHandle() ) + { + 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.dataType.IsFuncdef()) && !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.GetTypeInfo()->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.GetTypeInfo()->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 + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // 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 = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( func->name == opName && + func->parameterTypes.GetLength() == 0 && + (!isConst || func->IsReadOnly()) ) + { + funcs.PushLast(func->id); + } + } + + // Did we find the method? + if( funcs.GetLength() == 1 ) + { + asCArray args; + return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + } + 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; + } + + + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + 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()) + { + if (ctx->type.dataType.GetSizeInMemoryBytes() == 4) + ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2) + ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1) + ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8) + ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW()); + } + else if( ctx->type.dataType.IsFloatType() ) + ctx->type.SetConstantF(-ctx->type.GetConstantF()); + else if( ctx->type.dataType.IsDoubleType() ) + ctx->type.SetConstantD(-ctx->type.GetConstantD()); + else + { + Error(TXT_ILLEGAL_OPERATION, node); + return -1; + } + + return 0; + } + } + } + else if( op == ttNot ) + { + // Allow value types to be converted to bool using 'bool opImplConv()' + if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV); + + if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + { + if( ctx->type.isConstant ) + { + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + #else + ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + #endif + return 0; + } + + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + 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 ) + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + 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 ) + { + if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) + ctx->type.SetConstantB(~ctx->type.GetConstantB()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2) + ctx->type.SetConstantW(~ctx->type.GetConstantW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4) + ctx->type.SetConstantDW(~ctx->type.GetConstantDW()); + else + ctx->type.SetConstantQW(~ctx->type.GetConstantQW()); + return 0; + } + + 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(asCExprContext *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); - } + 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, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess) { - return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess); + return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess); } // Returns: @@ -12027,1567 +12027,1567 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx // -3 = processing error, e.g. out of memory int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess) { - // TODO: With asEP_PROPERTY_ACCESSOR_MODE == 3 this method doesn't need to validate the - // getter/setter as it is done at the time of declaration. Should deprecate the other options - - 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.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) || - engine->ep.propertyAccessorMode >= 2 ) - { - // Check if the object has any methods with the corresponding accessor name(s) - asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; - - if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) - continue; - - // 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]); - - if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) - continue; - - // Ignore script functions, if the application has disabled script defined property accessors - if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT ) - continue; - - // 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]); - - if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) - continue; - - // Ignore script functions, if the application has disabled script defined property accessors - if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT ) - continue; - - // 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(setId); - - 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 ) - { - if (node) - { - 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 ) - { - if (node) - { - 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.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) ) - { - if (node) - { - 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 -2; - } - } - - // 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; - } - - 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; - - bool isRefSafe = ctx->type.isRefSafe; - - 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; - - // Remember if the object is safe, so the invocation of the property - // accessor doesn't needlessly make a safe copy of the handle - ctx->type.isRefSafe = isRefSafe; - - // Store the argument for later use - if( arg ) - { - ctx->property_arg = asNEW(asCExprContext)(engine); - if( ctx->property_arg == 0 ) - { - // Out of memory - return -3; - } - - MergeExprBytecodeAndType(ctx->property_arg, arg); - } - - return 1; - } - - // No accessor was found - return 0; + // TODO: With asEP_PROPERTY_ACCESSOR_MODE == 3 this method doesn't need to validate the + // getter/setter as it is done at the time of declaration. Should deprecate the other options + + 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.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) || + engine->ep.propertyAccessorMode >= 2 ) + { + // Check if the object has any methods with the corresponding accessor name(s) + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; + + if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) + continue; + + // 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]); + + if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) + continue; + + // Ignore script functions, if the application has disabled script defined property accessors + if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT ) + continue; + + // 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]); + + if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) + continue; + + // Ignore script functions, if the application has disabled script defined property accessors + if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT ) + continue; + + // 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(setId); + + 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 ) + { + if (node) + { + 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 ) + { + if (node) + { + 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.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) ) + { + if (node) + { + 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 -2; + } + } + + // 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; + } + + 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; + + bool isRefSafe = ctx->type.isRefSafe; + + 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; + + // Remember if the object is safe, so the invocation of the property + // accessor doesn't needlessly make a safe copy of the handle + ctx->type.isRefSafe = isRefSafe; + + // Store the argument for later use + if( arg ) + { + ctx->property_arg = asNEW(asCExprContext)(engine); + if( ctx->property_arg == 0 ) + { + // Out of memory + return -3; + } + + MergeExprBytecodeAndType(ctx->property_arg, arg); + } + + return 1; + } + + // No accessor was found + return 0; } int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *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, asCExprContext); - 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::CreateType(func->objectType, ctx->property_const); - if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); - if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); - - // Don't allow the call if the object is read-only and the property accessor is not const - if( ctx->property_const && !func->IsReadOnly() ) - { - Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); - asCArray funcCandidates; - funcCandidates.PushLast(ctx->property_set); - PrintMatchingFuncs(funcCandidates, node); - } - } - - // Call the accessor - int r = 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, asCExprContext); - ctx->property_arg = 0; - } - - return r; + // 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, asCExprContext); + 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::CreateType(func->objectType, ctx->property_const); + if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); + if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); + + // Don't allow the call if the object is read-only and the property accessor is not const + if( ctx->property_const && !func->IsReadOnly() ) + { + Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); + asCArray funcCandidates; + funcCandidates.PushLast(ctx->property_set); + PrintMatchingFuncs(funcCandidates, node); + } + } + + // Call the accessor + int r = 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, asCExprContext); + ctx->property_arg = 0; + } + + return r; } int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode) { - // TODO: Perhaps it might be interesting to allow the definition of compound setters for better - // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible - // to support value types, since it would be a single call - - // Compound assignment for indexed property accessors is not supported yet - if( lctx->property_arg != 0 ) - { - // Process the property to free the memory - ProcessPropertySetAccessor(lctx, rctx, errNode); - Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode); - return -1; - } - - // Compound assignments require both get and set accessors - if( lctx->property_set == 0 || lctx->property_get == 0 ) - { - // Process the property to free the memory - ProcessPropertySetAccessor(lctx, rctx, errNode); - Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode); - return -1; - } - - // Property accessors on value types (or scoped references types) are not supported since - // it is not possible to guarantee that the object will stay alive between the two calls - asCScriptFunction *func = engine->scriptFunctions[lctx->property_set]; - if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) ) - { - // Process the property to free the memory - ProcessPropertySetAccessor(lctx, rctx, errNode); - Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode); - return -1; - } - - // Translate the compound assignment to the corresponding dual operator - switch( op ) - { - case ttAddAssign: op = ttPlus; break; - case ttSubAssign: op = ttMinus; break; - case ttMulAssign: op = ttStar; break; - case ttDivAssign: op = ttSlash; break; - case ttModAssign: op = ttPercent; break; - case ttPowAssign: op = ttStarStar; break; - - case ttAndAssign: op = ttAmp; break; - case ttOrAssign: op = ttBitOr; break; - case ttXorAssign: op = ttBitXor; break; - - case ttShiftLeftAssign: op = ttBitShiftLeft; break; - case ttShiftRightAAssign: op = ttBitShiftRightArith; break; - case ttShiftRightLAssign: op = ttBitShiftRight; break; - - default: op = ttUnrecognizedToken; break; - } - - if( op == ttUnrecognizedToken ) - { - // Shouldn't happen - asASSERT(false); - - // Process the property to free the memory - ProcessPropertySetAccessor(lctx, rctx, errNode); - return -1; - } - - asCExprContext before(engine); - if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF ) - { - // Keep a reference to the object in a local variable - before.bc.AddCode(&lctx->bc); - - asUINT len = reservedVariables.GetLength(); - rctx->bc.GetVarsUsed(reservedVariables); - before.bc.GetVarsUsed(reservedVariables); - - asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false); - int offset = AllocateVariable(dt, true); - - reservedVariables.SetLength(len); - - before.type.SetVariable(dt, offset, true); - - if( lctx->property_ref ) - before.bc.Instr(asBC_RDSPtr); - before.bc.InstrSHORT(asBC_PSF, (short)offset); - before.bc.InstrPTR(asBC_REFCPY, func->objectType); - before.bc.Instr(asBC_PopPtr); - - if( lctx->type.isTemporary ) - { - // Add the release of the temporary variable as a deferred expression - asSDeferredParam deferred; - deferred.origExpr = 0; - deferred.argInOutFlags = asTM_INREF; - deferred.argNode = 0; - deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true); - before.deferredParams.PushLast(deferred); - } - - // Update the left expression to use the local variable - lctx->bc.InstrSHORT(asBC_PSF, (short)offset); - lctx->type.stackOffset = (short)offset; - lctx->property_ref = true; - - // Don't release the temporary variable too early - lctx->type.isTemporary = false; - - ctx->bc.AddCode(&before.bc); - } - - // Keep the original information on the property - asCExprContext llctx(engine); - llctx.type = lctx->type; - llctx.property_arg = lctx->property_arg; - llctx.property_const = lctx->property_const; - llctx.property_get = lctx->property_get; - llctx.property_handle = lctx->property_handle; - llctx.property_ref = lctx->property_ref; - llctx.property_set = lctx->property_set; - - // Compile the dual operator using the get accessor - CompileOperator(errNode, lctx, rctx, ctx, op, false); - - // If we made a local variable to hold the reference it must be reused - if( before.type.stackOffset ) - llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset); - - // Compile the assignment using the set accessor - ProcessPropertySetAccessor(&llctx, ctx, errNode); - - MergeExprBytecodeAndType(ctx, &llctx); - - if( before.type.stackOffset ) - ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc); - - asASSERT( ctx->deferredParams.GetLength() == 0 ); - ctx->deferredParams = before.deferredParams; - ProcessDeferredParams(ctx); - - return 0; + // TODO: Perhaps it might be interesting to allow the definition of compound setters for better + // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible + // to support value types, since it would be a single call + + // Compound assignment for indexed property accessors is not supported yet + if( lctx->property_arg != 0 ) + { + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, errNode); + Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode); + return -1; + } + + // Compound assignments require both get and set accessors + if( lctx->property_set == 0 || lctx->property_get == 0 ) + { + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, errNode); + Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode); + return -1; + } + + // Property accessors on value types (or scoped references types) are not supported since + // it is not possible to guarantee that the object will stay alive between the two calls + asCScriptFunction *func = engine->scriptFunctions[lctx->property_set]; + if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) ) + { + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, errNode); + Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode); + return -1; + } + + // Translate the compound assignment to the corresponding dual operator + switch( op ) + { + case ttAddAssign: op = ttPlus; break; + case ttSubAssign: op = ttMinus; break; + case ttMulAssign: op = ttStar; break; + case ttDivAssign: op = ttSlash; break; + case ttModAssign: op = ttPercent; break; + case ttPowAssign: op = ttStarStar; break; + + case ttAndAssign: op = ttAmp; break; + case ttOrAssign: op = ttBitOr; break; + case ttXorAssign: op = ttBitXor; break; + + case ttShiftLeftAssign: op = ttBitShiftLeft; break; + case ttShiftRightAAssign: op = ttBitShiftRightArith; break; + case ttShiftRightLAssign: op = ttBitShiftRight; break; + + default: op = ttUnrecognizedToken; break; + } + + if( op == ttUnrecognizedToken ) + { + // Shouldn't happen + asASSERT(false); + + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, errNode); + return -1; + } + + asCExprContext before(engine); + if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF ) + { + // Keep a reference to the object in a local variable + before.bc.AddCode(&lctx->bc); + + asUINT len = reservedVariables.GetLength(); + rctx->bc.GetVarsUsed(reservedVariables); + before.bc.GetVarsUsed(reservedVariables); + + asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false); + int offset = AllocateVariable(dt, true); + + reservedVariables.SetLength(len); + + before.type.SetVariable(dt, offset, true); + + if( lctx->property_ref ) + before.bc.Instr(asBC_RDSPtr); + before.bc.InstrSHORT(asBC_PSF, (short)offset); + before.bc.InstrPTR(asBC_REFCPY, func->objectType); + before.bc.Instr(asBC_PopPtr); + + if( lctx->type.isTemporary ) + { + // Add the release of the temporary variable as a deferred expression + asSDeferredParam deferred; + deferred.origExpr = 0; + deferred.argInOutFlags = asTM_INREF; + deferred.argNode = 0; + deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true); + before.deferredParams.PushLast(deferred); + } + + // Update the left expression to use the local variable + lctx->bc.InstrSHORT(asBC_PSF, (short)offset); + lctx->type.stackOffset = (short)offset; + lctx->property_ref = true; + + // Don't release the temporary variable too early + lctx->type.isTemporary = false; + + ctx->bc.AddCode(&before.bc); + } + + // Keep the original information on the property + asCExprContext llctx(engine); + llctx.type = lctx->type; + llctx.property_arg = lctx->property_arg; + llctx.property_const = lctx->property_const; + llctx.property_get = lctx->property_get; + llctx.property_handle = lctx->property_handle; + llctx.property_ref = lctx->property_ref; + llctx.property_set = lctx->property_set; + + // Compile the dual operator using the get accessor + CompileOperator(errNode, lctx, rctx, ctx, op, false); + + // If we made a local variable to hold the reference it must be reused + if( before.type.stackOffset ) + llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset); + + // Compile the assignment using the set accessor + ProcessPropertySetAccessor(&llctx, ctx, errNode); + + MergeExprBytecodeAndType(ctx, &llctx); + + if( before.type.stackOffset ) + ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc); + + asASSERT( ctx->deferredParams.GetLength() == 0 ); + ctx->deferredParams = before.deferredParams; + ProcessDeferredParams(ctx); + + return 0; } int asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node) { - // If no property accessor has been prepared then don't do anything - if( !ctx->property_get && !ctx->property_set ) - return 0; - - if( !ctx->property_get ) - { - // Raise error on missing accessor - Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node); - return -1; - } - - asCExprValue objType = ctx->type; - asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get); - - // Make sure the arg match the property - asCArray funcs; - funcs.PushLast(ctx->property_get); - asCArray args; - 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, asCExprContext); - 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::CreateType(func->objectType, ctx->property_const); - if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); - if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); - - // Don't allow the call if the object is read-only and the property accessor is not const - if( ctx->property_const && !func->IsReadOnly() ) - { - Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); - asCArray funcCandidates; - funcCandidates.PushLast(ctx->property_get); - PrintMatchingFuncs(funcCandidates, node); - return -1; - } - } - - // The explicit handle flag must be remembered - bool isExplicitHandle = ctx->type.isExplicitHandle; - - // Call the accessor - int r = MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node); - if( isExplicitHandle ) - ctx->type.isExplicitHandle = true; - - // Clear the property get/set ids - ctx->property_get = 0; - ctx->property_set = 0; - if( ctx->property_arg ) - { - asDELETE(ctx->property_arg, asCExprContext); - ctx->property_arg = 0; - } - - return r; + // If no property accessor has been prepared then don't do anything + if( !ctx->property_get && !ctx->property_set ) + return 0; + + if( !ctx->property_get ) + { + // Raise error on missing accessor + Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node); + return -1; + } + + asCExprValue objType = ctx->type; + asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get); + + // Make sure the arg match the property + asCArray funcs; + funcs.PushLast(ctx->property_get); + asCArray args; + 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, asCExprContext); + 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::CreateType(func->objectType, ctx->property_const); + if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); + if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); + + // Don't allow the call if the object is read-only and the property accessor is not const + if( ctx->property_const && !func->IsReadOnly() ) + { + Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); + asCArray funcCandidates; + funcCandidates.PushLast(ctx->property_get); + PrintMatchingFuncs(funcCandidates, node); + return -1; + } + } + + // The explicit handle flag must be remembered + bool isExplicitHandle = ctx->type.isExplicitHandle; + + // Call the accessor + int r = MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node); + if( isExplicitHandle ) + ctx->type.isExplicitHandle = true; + + // Clear the property get/set ids + ctx->property_get = 0; + ctx->property_set = 0; + if( ctx->property_arg ) + { + asDELETE(ctx->property_arg, asCExprContext); + ctx->property_arg = 0; + } + + return r; } int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *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->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 - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - // 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 = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) - { - asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; - if( func->name == opName && - func->parameterTypes.GetLength() == 0 && - (!isConst || func->IsReadOnly()) ) - { - funcs.PushLast(func->id); - } - } - - // Did we find the method? - if( funcs.GetLength() == 1 ) - { - asCArray args; - return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); - } - 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 ) - { - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - // 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 - asCExprContext 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 || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) ) - { - asCString msg; - if( prop->isPrivate ) - msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf()); - else - msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf()); - Error(msg, node); - } - - // Adjust the pointer for composite member - // This must always be done even if the offset is 0 because the asCWriter needs the meta data in ADDSi to identify the composite property - if( prop->compositeOffset || prop->isCompositeIndirect ) - ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false))); - if (prop->isCompositeIndirect) - ctx->bc.Instr(asBC_RDSPtr); - - // Put the offset on the stack - // This must always be done even if the offset is 0 so the type info is stored - ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false))); - - if( prop->type.IsReference() ) - ctx->bc.Instr(asBC_RDSPtr); - - // 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.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() ) - { - // Objects that are members are not references - ctx->type.dataType.MakeReference(false); - - // The object is safe (life time guaranteed) if the parent object is also safe - } - else if (ctx->type.dataType.IsObjectHandle()) - { - // A object accessed through a handle cannot be considered safe, - // as it can be cleared at any time - ctx->type.isRefSafe = 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 = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - 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(outFunc->nameSpace).AddressOf()); - Error(str, node); - return -1; - } - } - } - else - { - asCString str; - str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).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(outFunc->nameSpace).AddressOf()); - Error(str, node); - return -1; - } - - // Process the get property accessor - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - - // Compile function call - int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), 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::CreateType(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, asCExprContext); - ctx->property_arg = 0; - } - } - else - { - if( !ctx->type.dataType.IsObject() ) - { - asCString str; - str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - return -1; - } - - if( ProcessPropertyGetAccessor(ctx, node) < 0 ) - return -1; - } - - // 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 = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - - 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 ) - isOK = false; - else if( MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset) < 0 ) - isOK = false; - } - } - } - if( lookForProperty && isOK ) - { - if( args.GetLength() != 1 ) - { - // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too - Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node); - isOK = false; - } - else - { - Dereference(ctx, true); - asCExprContext 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(outFunc->nameSpace).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], asCExprContext); - } - - 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.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) ) - { - Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node); - return -1; - } - - // Compile arguments - bool isOK = true; - asCArray args; - asCArray namedArgs; - if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) - { - // Match arguments with the funcdef - asCArray funcs; - if( ctx->type.dataType.IsFuncdef() ) - { - funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id); - MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs); - } - else - { - bool isConst = ctx->type.dataType.IsObjectConst(); - - builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst); - MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), 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], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs); - - // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or - // is it enough to make sure it is in a local variable? - - // 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.IsFuncdef() ) - { - 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); - } - - r = MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset); - if( r < 0 ) - isOK = false; - } - else - isOK = false; - } - } - else - ctx->type.SetDummy(); - - // Cleanup - for( asUINT n = 0; n < args.GetLength(); n++ ) - if( args[n] ) - { - asDELETE(args[n], asCExprContext); - } - for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) - if( namedArgs[n].ctx ) - { - asDELETE(namedArgs[n].ctx, asCExprContext); - } - - if( !isOK ) - return -1; - } - - return 0; + // 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->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 + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // 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 = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( func->name == opName && + func->parameterTypes.GetLength() == 0 && + (!isConst || func->IsReadOnly()) ) + { + funcs.PushLast(func->id); + } + } + + // Did we find the method? + if( funcs.GetLength() == 1 ) + { + asCArray args; + return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + } + 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 ) + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // 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 + asCExprContext 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 || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) ) + { + asCString msg; + if( prop->isPrivate ) + msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf()); + else + msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf()); + Error(msg, node); + } + + // Adjust the pointer for composite member + // This must always be done even if the offset is 0 because the asCWriter needs the meta data in ADDSi to identify the composite property + if( prop->compositeOffset || prop->isCompositeIndirect ) + ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false))); + if (prop->isCompositeIndirect) + ctx->bc.Instr(asBC_RDSPtr); + + // Put the offset on the stack + // This must always be done even if the offset is 0 so the type info is stored + ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false))); + + if( prop->type.IsReference() ) + ctx->bc.Instr(asBC_RDSPtr); + + // 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.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() ) + { + // Objects that are members are not references + ctx->type.dataType.MakeReference(false); + + // The object is safe (life time guaranteed) if the parent object is also safe + } + else if (ctx->type.dataType.IsObjectHandle()) + { + // A object accessed through a handle cannot be considered safe, + // as it can be cleared at any time + ctx->type.isRefSafe = 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 = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + 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(outFunc->nameSpace).AddressOf()); + Error(str, node); + return -1; + } + } + } + else + { + asCString str; + str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).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(outFunc->nameSpace).AddressOf()); + Error(str, node); + return -1; + } + + // Process the get property accessor + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // Compile function call + int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), 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::CreateType(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, asCExprContext); + ctx->property_arg = 0; + } + } + else + { + if( !ctx->type.dataType.IsObject() ) + { + asCString str; + str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + return -1; + } + + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + } + + // 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 = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + + 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 ) + isOK = false; + else if( MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset) < 0 ) + isOK = false; + } + } + } + if( lookForProperty && isOK ) + { + if( args.GetLength() != 1 ) + { + // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too + Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node); + isOK = false; + } + else + { + Dereference(ctx, true); + asCExprContext 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(outFunc->nameSpace).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], asCExprContext); + } + + 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.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) ) + { + Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node); + return -1; + } + + // Compile arguments + bool isOK = true; + asCArray args; + asCArray namedArgs; + if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) + { + // Match arguments with the funcdef + asCArray funcs; + if( ctx->type.dataType.IsFuncdef() ) + { + funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id); + MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs); + } + else + { + bool isConst = ctx->type.dataType.IsObjectConst(); + + builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst); + MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), 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], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs); + + // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or + // is it enough to make sure it is in a local variable? + + // 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.IsFuncdef() ) + { + 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); + } + + r = MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset); + if( r < 0 ) + isOK = false; + } + else + isOK = false; + } + } + else + ctx->type.SetDummy(); + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) + if( namedArgs[n].ctx ) + { + asDELETE(namedArgs[n].ctx, asCExprContext); + } + + if( !isOK ) + return -1; + } + + 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 + // 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 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; + // 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; + // Evaluate operators by token + int tokenType = op->tokenType; + if( tokenType == ttStarStar ) + return 0; - if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent ) - return -1; + if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent ) + return -1; - if( tokenType == ttPlus || tokenType == ttMinus ) - return -2; + if( tokenType == ttPlus || tokenType == ttMinus ) + return -2; - if( tokenType == ttBitShiftLeft || - tokenType == ttBitShiftRight || - tokenType == ttBitShiftRightArith ) - return -3; + if( tokenType == ttBitShiftLeft || + tokenType == ttBitShiftRight || + tokenType == ttBitShiftRightArith ) + return -3; - if( tokenType == ttAmp ) - return -4; + if( tokenType == ttAmp ) + return -4; - if( tokenType == ttBitXor ) - return -5; + if( tokenType == ttBitXor ) + return -5; - if( tokenType == ttBitOr ) - return -6; + if( tokenType == ttBitOr ) + return -6; - if( tokenType == ttLessThanOrEqual || - tokenType == ttLessThan || - tokenType == ttGreaterThanOrEqual || - tokenType == ttGreaterThan ) - return -7; + 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 == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs ) + return -8; - if( tokenType == ttAnd ) - return -9; + if( tokenType == ttAnd ) + return -9; - if( tokenType == ttOr ) - return -10; + if( tokenType == ttOr ) + return -10; - // Unknown operator - asASSERT(false); + // Unknown operator + asASSERT(false); - return 0; + return 0; } asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArray &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct) { - matches.SetLength(0); + matches.SetLength(0); - for( asUINT n = 0; n < funcs.GetLength(); n++ ) - { - asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]); + 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; + // 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))); - } + int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct); + if( cost != -1 ) + matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost))); + } - return (asUINT)matches.GetLength(); + return (asUINT)matches.GetLength(); } int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct) { - // void expressions can match any out parameter, but nothing else - if( argExpr->IsVoidExpression() ) - { - if( desc->inOutFlags[paramNum] == asTM_OUTREF ) - return 0; - return -1; - } - - // Anonymous init lists can only match parameters that can be initialized with a list - if (argExpr->IsAnonymousInitList()) - { - if( (desc->parameterTypes[paramNum].IsReference() && (desc->inOutFlags[paramNum] & asTM_INREF) == 0) || - desc->parameterTypes[paramNum].GetBehaviour() == 0 || - desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0 ) - { - return -1; - } - return 0; - } - - // Can we make the match by implicit conversion? - asCExprContext ti(engine); - ti.type = argExpr->type; - ti.methodName = argExpr->methodName; - ti.enumValue = argExpr->enumValue; - ti.exprNode = argExpr->exprNode; - if( argExpr->type.dataType.IsPrimitive() ) - ti.type.dataType.MakeReference(false); - - // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value - if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF) - allowObjectConstruct = false; - - int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct); - - // If the function parameter is an inout-reference then it must not be possible to call the - // 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].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() ) - { - 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].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) && - (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) ) - { - 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 expressions can match any out parameter, but nothing else + if( argExpr->IsVoidExpression() ) + { + if( desc->inOutFlags[paramNum] == asTM_OUTREF ) + return 0; + return -1; + } + + // Anonymous init lists can only match parameters that can be initialized with a list + if (argExpr->IsAnonymousInitList()) + { + if( (desc->parameterTypes[paramNum].IsReference() && (desc->inOutFlags[paramNum] & asTM_INREF) == 0) || + desc->parameterTypes[paramNum].GetBehaviour() == 0 || + desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0 ) + { + return -1; + } + return 0; + } + + // Can we make the match by implicit conversion? + asCExprContext ti(engine); + ti.type = argExpr->type; + ti.methodName = argExpr->methodName; + ti.enumValue = argExpr->enumValue; + ti.exprNode = argExpr->exprNode; + if( argExpr->type.dataType.IsPrimitive() ) + ti.type.dataType.MakeReference(false); + + // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value + if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF) + allowObjectConstruct = false; + + int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct); + + // If the function parameter is an inout-reference then it must not be possible to call the + // 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].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() ) + { + 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].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) && + (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) ) + { + 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; } int asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy) { - // Reference parameters whose value won't be used don't evaluate the expression - // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect - if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg ) - { - // Store the original bytecode so that it can be reused when processing the deferred output parameter - asCExprContext *orig = asNEW(asCExprContext)(engine); - if( orig == 0 ) - { - // Out of memory - return -1; - } - MergeExprBytecodeAndType(orig, arg); - arg->origExpr = orig; - } - - int r = PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy); - if (r < 0) - return r; - - // arg still holds the original expression for output parameters - ctx->bc.AddCode(&arg->bc); - - return 0; + // Reference parameters whose value won't be used don't evaluate the expression + // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect + if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg ) + { + // Store the original bytecode so that it can be reused when processing the deferred output parameter + asCExprContext *orig = asNEW(asCExprContext)(engine); + if( orig == 0 ) + { + // Out of memory + return -1; + } + MergeExprBytecodeAndType(orig, arg); + arg->origExpr = orig; + } + + int r = PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy); + if (r < 0) + return r; + + // arg still holds the original expression for output parameters + ctx->bc.AddCode(&arg->bc); + + return 0; } bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token) { - DetermineSingleFunc(lctx, node); - DetermineSingleFunc(rctx, node); - - ctx->exprNode = node; - - // What type of operator is it? - if( token == ttUnrecognizedToken ) - 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, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); - if( r == 0 ) - { - // Try again by switching the order of the operands - r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, 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, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false)); - if( r == 0 ) - { - // Try again by switching the order of the operands - swappedOrder = true; - r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, 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 - #if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); - #else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); - #endif - return true; - } - } - - // The rest of the operators are not commutative, and doesn't require specific return type - const char *op = 0, *op_r = 0; - switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested - { - 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, leftToRight, ctx); - if( r == 0 ) - { - // Try again by switching the order of the operands, and using the reversed operator - r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, 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.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ); - asASSERT( token == ttAssignment ); - - if( token == ttAssignment ) - op = "opHndlAssign"; - } - else - { - switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested - { - 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.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) ) - { - if( token == ttAssignment ) - Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node); - 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, false, 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; + DetermineSingleFunc(lctx, node); + DetermineSingleFunc(rctx, node); + + ctx->exprNode = node; + + // What type of operator is it? + if( token == ttUnrecognizedToken ) + 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, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + if( r == 0 ) + { + // Try again by switching the order of the operands + r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, 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, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false)); + if( r == 0 ) + { + // Try again by switching the order of the operands + swappedOrder = true; + r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, 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 + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); + #endif + return true; + } + } + + // The rest of the operators are not commutative, and doesn't require specific return type + const char *op = 0, *op_r = 0; + switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested + { + 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, leftToRight, ctx); + if( r == 0 ) + { + // Try again by switching the order of the operands, and using the reversed operator + r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, 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.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ); + asASSERT( token == ttAssignment ); + + if( token == ttAssignment ) + op = "opHndlAssign"; + } + else + { + switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested + { + 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.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) ) + { + if( token == ttAssignment ) + Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node); + 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, false, 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 @@ -13595,2842 +13595,2842 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprCont // one on matching operator int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType) { - // Find the matching method - if( lctx->type.dataType.IsObject() && - (!lctx->type.isExplicitHandle || - lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) && - !lctx->type.IsNullConstant() ) - { - asUINT n; - - // Is the left value a const? - bool isConst = lctx->type.dataType.IsObjectConst(); - - asCArray funcs; - asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo()); - asASSERT(ot); - for( n = 0; ot && 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->m_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 ) - { - // Reserve the variables used in the right expression so the new temporary - // variable allocated for the left operand isn't accidentally overwritten. - int l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - - // Process the lctx expression as get accessor - if( ProcessPropertyGetAccessor(lctx, node) < 0 ) - return -1; - - reservedVariables.SetLength(l); - - asCExprContext tmpCtx(engine); - if (leftToRight) - { - // Make sure lctx is in fact a variable. If it is a reference there is no - // guarantee that the reference will stay alive throughout the evaluation of rctx - if (!lctx->type.isVariable) - { - // Reserve the variables used in the right expression so the new temporary - // variable allocated for the left operand isn't accidentally overwritten. - l = int(reservedVariables.GetLength()); - rctx->bc.GetVarsUsed(reservedVariables); - - if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE)) - { - // If the application allows unsafe references, then it is not necessary to - // make a copy of the object, just store the reference as a local variable - - // Allocate a temporary variable as reference to the type - asCDataType dt = lctx->type.dataType; - dt.MakeReference(true); - int offset = AllocateVariable(dt, true, false, true); - - Dereference(lctx, true); - - // Copy the pointer to the temporary variable - lctx->bc.InstrSHORT(asBC_PSF, (short)offset); - if (lctx->type.dataType.IsFuncdef()) - lctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - lctx->bc.InstrPTR(asBC_REFCPY, lctx->type.dataType.GetTypeInfo()); - - lctx->type.SetVariable(dt, offset, true); - } - else - { - if (lctx->type.dataType.SupportHandles()) - lctx->type.dataType.MakeHandle(true); - PrepareTemporaryVariable(node, lctx); - } - - reservedVariables.SetLength(l); - } - - // Move the bytecode for the left operand to a temporary context - // so we can later make sure this is computed first - tmpCtx.bc.AddCode(&lctx->bc); - tmpCtx.bc.Instr(asBC_PopPtr); - - // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer - // This will be placed after rctx by MakeFunctionCall below - lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset); - - // Implicitly dereference handle parameters sent by reference - sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset); - if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle())) - lctx->bc.Instr(asBC_RDSPtr); - } - else - { - // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue, - // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue. - asCArray usedVars; - lctx->bc.GetVarsUsed(usedVars); - asUINT oldReservedVars = reservedVariables.GetLength(); - for (n = 0; n < rctx->deferredParams.GetLength(); n++) - { - if (rctx->deferredParams[n].argType.isTemporary && - usedVars.Exists(rctx->deferredParams[n].argType.stackOffset)) - { - if (reservedVariables.GetLength() == oldReservedVars) - reservedVariables.Concatenate(usedVars); - - // Allocate a new variable for the deferred argument - int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx); - int oldVar = rctx->deferredParams[n].argType.stackOffset; - rctx->deferredParams[n].argType.stackOffset = short(offset); - rctx->bc.ExchangeVar(oldVar, offset); - ReleaseTemporaryVariable(oldVar, 0); - } - } - reservedVariables.SetLength(oldReservedVars); - } - - // Merge the bytecode so that it forms lvalue.methodName(rvalue) - asCArray args; - args.PushLast(rctx); - MergeExprBytecode(ctx, lctx); - ctx->type = lctx->type; - if( MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node) < 0 ) - return -1; - - // Rearrange the bytecode so the left argument is computed first - if (leftToRight) - { - tmpCtx.bc.AddCode(&ctx->bc); - ctx->bc.AddCode(&tmpCtx.bc); - } - - // Found matching operator - return 1; - } - 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; + // Find the matching method + if( lctx->type.dataType.IsObject() && + (!lctx->type.isExplicitHandle || + lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) && + !lctx->type.IsNullConstant() ) + { + asUINT n; + + // Is the left value a const? + bool isConst = lctx->type.dataType.IsObjectConst(); + + asCArray funcs; + asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo()); + asASSERT(ot); + for( n = 0; ot && 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->m_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 ) + { + // Reserve the variables used in the right expression so the new temporary + // variable allocated for the left operand isn't accidentally overwritten. + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + + // Process the lctx expression as get accessor + if( ProcessPropertyGetAccessor(lctx, node) < 0 ) + return -1; + + reservedVariables.SetLength(l); + + asCExprContext tmpCtx(engine); + if (leftToRight) + { + // Make sure lctx is in fact a variable. If it is a reference there is no + // guarantee that the reference will stay alive throughout the evaluation of rctx + if (!lctx->type.isVariable) + { + // Reserve the variables used in the right expression so the new temporary + // variable allocated for the left operand isn't accidentally overwritten. + l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + + if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE)) + { + // If the application allows unsafe references, then it is not necessary to + // make a copy of the object, just store the reference as a local variable + + // Allocate a temporary variable as reference to the type + asCDataType dt = lctx->type.dataType; + dt.MakeReference(true); + int offset = AllocateVariable(dt, true, false, true); + + Dereference(lctx, true); + + // Copy the pointer to the temporary variable + lctx->bc.InstrSHORT(asBC_PSF, (short)offset); + if (lctx->type.dataType.IsFuncdef()) + lctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + lctx->bc.InstrPTR(asBC_REFCPY, lctx->type.dataType.GetTypeInfo()); + + lctx->type.SetVariable(dt, offset, true); + } + else + { + if (lctx->type.dataType.SupportHandles()) + lctx->type.dataType.MakeHandle(true); + PrepareTemporaryVariable(node, lctx); + } + + reservedVariables.SetLength(l); + } + + // Move the bytecode for the left operand to a temporary context + // so we can later make sure this is computed first + tmpCtx.bc.AddCode(&lctx->bc); + tmpCtx.bc.Instr(asBC_PopPtr); + + // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer + // This will be placed after rctx by MakeFunctionCall below + lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset); + + // Implicitly dereference handle parameters sent by reference + sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset); + if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle())) + lctx->bc.Instr(asBC_RDSPtr); + } + else + { + // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue, + // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue. + asCArray usedVars; + lctx->bc.GetVarsUsed(usedVars); + asUINT oldReservedVars = reservedVariables.GetLength(); + for (n = 0; n < rctx->deferredParams.GetLength(); n++) + { + if (rctx->deferredParams[n].argType.isTemporary && + usedVars.Exists(rctx->deferredParams[n].argType.stackOffset)) + { + if (reservedVariables.GetLength() == oldReservedVars) + reservedVariables.Concatenate(usedVars); + + // Allocate a new variable for the deferred argument + int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx); + int oldVar = rctx->deferredParams[n].argType.stackOffset; + rctx->deferredParams[n].argType.stackOffset = short(offset); + rctx->bc.ExchangeVar(oldVar, offset); + ReleaseTemporaryVariable(oldVar, 0); + } + } + reservedVariables.SetLength(oldReservedVars); + } + + // Merge the bytecode so that it forms lvalue.methodName(rvalue) + asCArray args; + args.PushLast(rctx); + MergeExprBytecode(ctx, lctx); + ctx->type = lctx->type; + if( MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node) < 0 ) + return -1; + + // Rearrange the bytecode so the left argument is computed first + if (leftToRight) + { + tmpCtx.bc.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmpCtx.bc); + } + + // Found matching operator + return 1; + } + 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; } int asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar) { - if( objectType ) - Dereference(ctx, true); - - // Store the expression node for error reporting - if( ctx->exprNode == 0 ) - ctx->exprNode = node; - - asCByteCode objBC(engine); - objBC.AddCode(&ctx->bc); - - int r = PrepareFunctionCall(funcId, &ctx->bc, args); - if (r < 0) - return r; - - // 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); - - return 0; + if( objectType ) + Dereference(ctx, true); + + // Store the expression node for error reporting + if( ctx->exprNode == 0 ) + ctx->exprNode = node; + + asCByteCode objBC(engine); + objBC.AddCode(&ctx->bc); + + int r = PrepareFunctionCall(funcId, &ctx->bc, args); + if (r < 0) + return r; + + // 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); + + return 0; } int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight) { - // Don't allow any operators on expressions that take address of class method, but allow it on global functions - if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) ) - { - Error(TXT_INVALID_OP_ON_METHOD, node); - return -1; - } - - // Don't allow any operators on void expressions - if( lctx->IsVoidExpression() || rctx->IsVoidExpression() ) - { - Error(TXT_VOID_CANT_BE_OPERAND, node); - return -1; - } - - if( op == ttUnrecognizedToken ) - op = node->tokenType; - - IsVariableInitialized(&lctx->type, node); - IsVariableInitialized(&rctx->type, node); - - if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle || - lctx->type.IsNullConstant() || rctx->type.IsNullConstant() || - op == ttIs || op == ttNotIs ) - { - CompileOperatorOnHandles(node, lctx, rctx, ctx, op); - return 0; - } - else - { - // Compile an overloaded operator for the two operands - if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) ) - 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(outFunc->nameSpace).AddressOf(), rctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - ctx->type.SetDummy(); - return -1; - } - - // Process the property get accessors (if any) - if( ProcessPropertyGetAccessor(lctx, node) < 0 ) - return -1; - if( ProcessPropertyGetAccessor(rctx, node) < 0 ) - return -1; - - // 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 - // + - * / % ** += -= *= /= %= **= - 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, op); - 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, op); - return 0; - } - - // Comparison operators - // == != < > <= >= - if( op == ttEqual || op == ttNotEqual || - op == ttLessThan || op == ttLessThanOrEqual || - op == ttGreaterThan || op == ttGreaterThanOrEqual ) - { - CompileComparisonOperator(node, lctx, rctx, ctx, op); - return 0; - } - - // Boolean operators - // && || ^^ - if( op == ttAnd || op == ttOr || op == ttXor ) - { - CompileBooleanOperator(node, lctx, rctx, ctx, op); - return 0; - } - } - - asASSERT(false); - return -1; + // 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->IsVoidExpression() || rctx->IsVoidExpression() ) + { + Error(TXT_VOID_CANT_BE_OPERAND, node); + return -1; + } + + if( op == ttUnrecognizedToken ) + op = node->tokenType; + + IsVariableInitialized(&lctx->type, node); + IsVariableInitialized(&rctx->type, node); + + if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle || + lctx->type.IsNullConstant() || rctx->type.IsNullConstant() || + op == ttIs || op == ttNotIs ) + { + CompileOperatorOnHandles(node, lctx, rctx, ctx, op); + return 0; + } + else + { + // Compile an overloaded operator for the two operands + if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) ) + 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(outFunc->nameSpace).AddressOf(), rctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + ctx->type.SetDummy(); + return -1; + } + + // Process the property get accessors (if any) + if( ProcessPropertyGetAccessor(lctx, node) < 0 ) + return -1; + if( ProcessPropertyGetAccessor(rctx, node) < 0 ) + return -1; + + // 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 + // + - * / % ** += -= *= /= %= **= + 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, op); + 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, op); + return 0; + } + + // Comparison operators + // == != < > <= >= + if( op == ttEqual || op == ttNotEqual || + op == ttLessThan || op == ttLessThanOrEqual || + op == ttGreaterThan || op == ttGreaterThanOrEqual ) + { + CompileComparisonOperator(node, lctx, rctx, ctx, op); + return 0; + } + + // Boolean operators + // && || ^^ + if( op == ttAnd || op == ttOr || op == ttXor ) + { + CompileBooleanOperator(node, lctx, rctx, ctx, op); + return 0; + } + } + + asASSERT(false); + return -1; } void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude) { - int l = int(reservedVariables.GetLength()); - if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); - ConvertToTempVariable(ctx); - reservedVariables.SetLength(l); + int l = int(reservedVariables.GetLength()); + if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); + ConvertToTempVariable(ctx); + reservedVariables.SetLength(l); } void asCCompiler::ConvertToTempVariable(asCExprContext *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); - } - } + // 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(asCExprContext *ctx) { - // We should never get here while the context is still an unprocessed property accessor - asASSERT(ctx->property_get == 0 && ctx->property_set == 0); - - 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); - if( ctx->type.dataType.IsFuncdef() ) - ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); - else - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); - ctx->bc.Instr(asBC_PopPtr); - } - - // 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.GetConstantB()); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) - ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW()); - else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) - ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW()); - else - ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW()); - - 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); - } + // 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); + if( ctx->type.dataType.IsFuncdef() ) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + } + + // 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.GetConstantB()); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) + ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW()); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) + ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW()); + else + ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW()); + + 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(asCExprContext *ctx, asCExprContext *exclude) { - int l = int(reservedVariables.GetLength()); - if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); - ConvertToVariable(ctx); - reservedVariables.SetLength(l); + int l = int(reservedVariables.GetLength()); + if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); + ConvertToVariable(ctx); + reservedVariables.SetLength(l); } void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node) { - asCArray funcs; - asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); - 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); - } + asCArray funcs; + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + 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, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) { - // 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( op == ttUnrecognizedToken ) - op = node->tokenType; - - // If integer division is disabled, convert to floating-point - 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(outFunc->nameSpace).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(outFunc->nameSpace).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 && - (op == ttSlash || op == ttDivAssign || - op == ttPercent || op == ttModAssign) && - ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) || - (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) || - (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) || - (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) ) - { - Error(TXT_DIVIDE_BY_ZERO, node); - } - - 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 = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW()); - else if( op == ttMinus ) - v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW()); - else if( op == ttStar ) - v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW()); - else if( op == ttSlash ) - { - // TODO: Should probably report an error, rather than silently convert the value to 0 - if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) ) - v = 0; - else - if( lctx->type.dataType.IsIntegerType() ) - v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW()); - else - v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW(); - } - else if( op == ttPercent ) - { - // TODO: Should probably report an error, rather than silently convert the value to 0 - if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) ) - v = 0; - else - if( lctx->type.dataType.IsIntegerType() ) - v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW()); - else - v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW(); - } - else if( op == ttStarStar ) - { - bool isOverflow; - if( lctx->type.dataType.IsIntegerType() ) - v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow); - else - v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow); - - if( isOverflow ) - Error(TXT_POW_OVERFLOW, node); - } - - 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.GetConstantDW() < rctx->type.GetConstantDW()) - ctx->type.dataType.SetTokenType(ttInt); - } - else - { - asQWORD v = 0; - if( op == ttPlus ) - v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW()); - else if( op == ttMinus ) - v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW()); - else if( op == ttStar ) - v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW()); - else if( op == ttSlash ) - { - // TODO: Should probably report an error, rather than silently convert the value to 0 - if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) ) - v = 0; - else - if( lctx->type.dataType.IsIntegerType() ) - v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW()); - else - v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW(); - } - else if( op == ttPercent ) - { - // TODO: Should probably report an error, rather than silently convert the value to 0 - if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) ) - v = 0; - else - if( lctx->type.dataType.IsIntegerType() ) - v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW()); - else - v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW(); - } - else if( op == ttStarStar ) - { - bool isOverflow; - if( lctx->type.dataType.IsIntegerType() ) - v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow); - else - v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow); - - if( isOverflow ) - Error(TXT_POW_OVERFLOW, node); - } - - 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.GetConstantQW() < rctx->type.GetConstantQW()) - ctx->type.dataType.SetTokenType(ttInt64); - } - } - else if( lctx->type.dataType.IsFloatType() ) - { - float v = 0.0f; - if( op == ttPlus ) - v = lctx->type.GetConstantF() + rctx->type.GetConstantF(); - else if( op == ttMinus ) - v = lctx->type.GetConstantF() - rctx->type.GetConstantF(); - else if( op == ttStar ) - v = lctx->type.GetConstantF() * rctx->type.GetConstantF(); - else if( op == ttSlash ) - { - if( rctx->type.GetConstantF() == 0 ) - v = 0; - else - v = lctx->type.GetConstantF() / rctx->type.GetConstantF(); - } - else if( op == ttPercent ) - { - if( rctx->type.GetConstantF() == 0 ) - v = 0; - else - v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF()); - } - else if( op == ttStarStar ) - { - v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF()); - - if( v == HUGE_VAL ) - Error(TXT_POW_OVERFLOW, node); - } - - 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.GetConstantD(), int(rctx->type.GetConstantDW())); - if( v == HUGE_VAL ) - Error(TXT_POW_OVERFLOW, node); - } - else - asASSERT(false); // Should not be possible - } - else - { - if( op == ttPlus ) - v = lctx->type.GetConstantD() + rctx->type.GetConstantD(); - else if( op == ttMinus ) - v = lctx->type.GetConstantD() - rctx->type.GetConstantD(); - else if( op == ttStar ) - v = lctx->type.GetConstantD() * rctx->type.GetConstantD(); - else if( op == ttSlash ) - { - if( rctx->type.GetConstantD() == 0 ) - v = 0; - else - v = lctx->type.GetConstantD() / rctx->type.GetConstantD(); - } - else if( op == ttPercent ) - { - if( rctx->type.GetConstantD() == 0 ) - v = 0; - else - v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD()); - } - else if( op == ttStarStar ) - { - v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD()); - if( v == HUGE_VAL ) - Error(TXT_POW_OVERFLOW, node); - } - } - - ctx->type.SetConstantD(lctx->type.dataType, v); - } - else - { - // Shouldn't be possible - asASSERT(false); - } - } + // 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( op == ttUnrecognizedToken ) + op = node->tokenType; + + // If integer division is disabled, convert to floating-point + 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(outFunc->nameSpace).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(outFunc->nameSpace).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 && + (op == ttSlash || op == ttDivAssign || + op == ttPercent || op == ttModAssign) && + ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) ) + { + Error(TXT_DIVIDE_BY_ZERO, node); + } + + 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 = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW()); + else if( op == ttMinus ) + v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW()); + else if( op == ttStar ) + v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW()); + else if( op == ttSlash ) + { + // TODO: Should probably report an error, rather than silently convert the value to 0 + if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) ) + v = 0; + else + if( lctx->type.dataType.IsIntegerType() ) + v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW()); + else + v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW(); + } + else if( op == ttPercent ) + { + // TODO: Should probably report an error, rather than silently convert the value to 0 + if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) ) + v = 0; + else + if( lctx->type.dataType.IsIntegerType() ) + v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW()); + else + v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW(); + } + else if( op == ttStarStar ) + { + bool isOverflow; + if( lctx->type.dataType.IsIntegerType() ) + v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow); + else + v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow); + + if( isOverflow ) + Error(TXT_POW_OVERFLOW, node); + } + + 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.GetConstantDW() < rctx->type.GetConstantDW()) + ctx->type.dataType.SetTokenType(ttInt); + } + else + { + asQWORD v = 0; + if( op == ttPlus ) + v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW()); + else if( op == ttMinus ) + v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW()); + else if( op == ttStar ) + v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW()); + else if( op == ttSlash ) + { + // TODO: Should probably report an error, rather than silently convert the value to 0 + if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) ) + v = 0; + else + if( lctx->type.dataType.IsIntegerType() ) + v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW()); + else + v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW(); + } + else if( op == ttPercent ) + { + // TODO: Should probably report an error, rather than silently convert the value to 0 + if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) ) + v = 0; + else + if( lctx->type.dataType.IsIntegerType() ) + v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW()); + else + v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW(); + } + else if( op == ttStarStar ) + { + bool isOverflow; + if( lctx->type.dataType.IsIntegerType() ) + v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow); + else + v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow); + + if( isOverflow ) + Error(TXT_POW_OVERFLOW, node); + } + + 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.GetConstantQW() < rctx->type.GetConstantQW()) + ctx->type.dataType.SetTokenType(ttInt64); + } + } + else if( lctx->type.dataType.IsFloatType() ) + { + float v = 0.0f; + if( op == ttPlus ) + v = lctx->type.GetConstantF() + rctx->type.GetConstantF(); + else if( op == ttMinus ) + v = lctx->type.GetConstantF() - rctx->type.GetConstantF(); + else if( op == ttStar ) + v = lctx->type.GetConstantF() * rctx->type.GetConstantF(); + else if( op == ttSlash ) + { + if( rctx->type.GetConstantF() == 0 ) + v = 0; + else + v = lctx->type.GetConstantF() / rctx->type.GetConstantF(); + } + else if( op == ttPercent ) + { + if( rctx->type.GetConstantF() == 0 ) + v = 0; + else + v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF()); + } + else if( op == ttStarStar ) + { + v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF()); + + if( v == HUGE_VAL ) + Error(TXT_POW_OVERFLOW, node); + } + + 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.GetConstantD(), int(rctx->type.GetConstantDW())); + if( v == HUGE_VAL ) + Error(TXT_POW_OVERFLOW, node); + } + else + asASSERT(false); // Should not be possible + } + else + { + if( op == ttPlus ) + v = lctx->type.GetConstantD() + rctx->type.GetConstantD(); + else if( op == ttMinus ) + v = lctx->type.GetConstantD() - rctx->type.GetConstantD(); + else if( op == ttStar ) + v = lctx->type.GetConstantD() * rctx->type.GetConstantD(); + else if( op == ttSlash ) + { + if( rctx->type.GetConstantD() == 0 ) + v = 0; + else + v = lctx->type.GetConstantD() / rctx->type.GetConstantD(); + } + else if( op == ttPercent ) + { + if( rctx->type.GetConstantD() == 0 ) + v = 0; + else + v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD()); + } + else if( op == ttStarStar ) + { + v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD()); + if( v == HUGE_VAL ) + Error(TXT_POW_OVERFLOW, node); + } + } + + ctx->type.SetConstantD(lctx->type.dataType, v); + } + else + { + // Shouldn't be possible + asASSERT(false); + } + } } void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) { - // TODO: If a constant is only using 32bits, then a 32bit operation is preferred - - if( op == ttUnrecognizedToken ) - op = node->tokenType; - if( op == ttAmp || op == ttAndAssign || - op == ttBitOr || op == ttOrAssign || - op == ttBitXor || op == ttXorAssign ) - { - // Also do not permit float/double to be implicitly converted to integer in this case - // as the user may think the result is a bitwise operation on the float value but it's not - if (lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType()) - { - asCString str; - str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - - // Set an integer value and allow the compiler to continue - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); - return; - } - if (rctx->type.dataType.IsFloatType() || rctx->type.dataType.IsDoubleType()) - { - asCString str; - str.Format(TXT_ILLEGAL_OPERATION_ON_s, rctx->type.dataType.Format(outFunc->nameSpace).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; - 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).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.GetConstantQW() & rctx->type.GetConstantQW(); - else if( op == ttBitOr ) - v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW(); - else if( op == ttBitXor ) - v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW(); - - // Remember the result - ctx->type.SetConstantQW(lctx->type.dataType, v); - } - else - { - asDWORD v = 0; - if( op == ttAmp ) - v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW(); - else if( op == ttBitOr ) - v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW(); - else if( op == ttBitXor ) - v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW(); - - // 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 - // Also do not permit float/double to be implicitly converted to integer in this case - if( lctx->type.dataType.IsObject() || lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType() ) - { - asCString str; - str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).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 ) - { - // Upgrade to 32bit - to = asCDataType::CreatePrimitive(ttUInt, false); - } - else if( !lctx->type.dataType.IsUnsignedType() ) - { - if (lctx->type.dataType.GetSizeInMemoryDWords() == 2) - to = asCDataType::CreatePrimitive(ttInt64, false); - else - to = asCDataType::CreatePrimitive(ttInt, false); - } - - // 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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(outFunc->nameSpace).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.GetConstantDW() << rctx->type.GetConstantDW(); - else if( op == ttBitShiftRight ) - v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW(); - else if( op == ttBitShiftRightArith ) - v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW(); - - ctx->type.SetConstantDW(lctx->type.dataType, v); - } - else - { - asQWORD v = 0; - if( op == ttBitShiftLeft ) - v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW(); - else if( op == ttBitShiftRight ) - v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW(); - else if( op == ttBitShiftRightArith ) - v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW(); - - ctx->type.SetConstantQW(lctx->type.dataType, v); - } - } - } + // TODO: If a constant is only using 32bits, then a 32bit operation is preferred + + if( op == ttUnrecognizedToken ) + op = node->tokenType; + if( op == ttAmp || op == ttAndAssign || + op == ttBitOr || op == ttOrAssign || + op == ttBitXor || op == ttXorAssign ) + { + // Also do not permit float/double to be implicitly converted to integer in this case + // as the user may think the result is a bitwise operation on the float value but it's not + if (lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType()) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + // Set an integer value and allow the compiler to continue + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); + return; + } + if (rctx->type.dataType.IsFloatType() || rctx->type.dataType.IsDoubleType()) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, rctx->type.dataType.Format(outFunc->nameSpace).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; + 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).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.GetConstantQW() & rctx->type.GetConstantQW(); + else if( op == ttBitOr ) + v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW(); + else if( op == ttBitXor ) + v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW(); + + // Remember the result + ctx->type.SetConstantQW(lctx->type.dataType, v); + } + else + { + asDWORD v = 0; + if( op == ttAmp ) + v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW(); + else if( op == ttBitOr ) + v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW(); + else if( op == ttBitXor ) + v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW(); + + // 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 + // Also do not permit float/double to be implicitly converted to integer in this case + if( lctx->type.dataType.IsObject() || lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType() ) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).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 ) + { + // Upgrade to 32bit + to = asCDataType::CreatePrimitive(ttUInt, false); + } + else if( !lctx->type.dataType.IsUnsignedType() ) + { + if (lctx->type.dataType.GetSizeInMemoryDWords() == 2) + to = asCDataType::CreatePrimitive(ttInt64, false); + else + to = asCDataType::CreatePrimitive(ttInt, false); + } + + // 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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(outFunc->nameSpace).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.GetConstantDW() << rctx->type.GetConstantDW(); + else if( op == ttBitShiftRight ) + v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW(); + else if( op == ttBitShiftRightArith ) + v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW(); + + ctx->type.SetConstantDW(lctx->type.dataType, v); + } + else + { + asQWORD v = 0; + if( op == ttBitShiftLeft ) + v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW(); + else if( op == ttBitShiftRight ) + v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW(); + else if( op == ttBitShiftRightArith ) + v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW(); + + ctx->type.SetConstantQW(lctx->type.dataType, v); + } + } + } } void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) { - // 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++ ) - { - asCExprContext *opCtx = n ? rctx : lctx; - - if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() ) - { - // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value - signMismatch = true; - if( opCtx->type.isConstant ) - { - if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 ) - { - if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) ) - signMismatch = false; - } - else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() ) - { - if( !(opCtx->type.GetConstantDW() & (1<<31)) ) - signMismatch = false; - } - else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16) - { - if (!(opCtx->type.GetConstantW() & (1 << 15))) - signMismatch = false; - } - else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8) - { - if (!(opCtx->type.GetConstantB() & (1 << 7))) - signMismatch = false; - } - - // 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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. + // 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++ ) + { + asCExprContext *opCtx = n ? rctx : lctx; + + if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() ) + { + // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value + signMismatch = true; + if( opCtx->type.isConstant ) + { + if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 ) + { + if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) ) + signMismatch = false; + } + else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() ) + { + if( !(opCtx->type.GetConstantDW() & (1<<31)) ) + signMismatch = false; + } + else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16) + { + if (!(opCtx->type.GetConstantW() & (1 << 15))) + signMismatch = false; + } + else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8) + { + if (!(opCtx->type.GetConstantB() & (1 << 7))) + signMismatch = false; + } + + // 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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. #if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); #else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); #endif - return; - } - - bool isConstant = lctx->type.isConstant && rctx->type.isConstant; - - if( op == ttUnrecognizedToken ) - op = node->tokenType; - - if( !isConstant ) - { - if( to.IsBooleanType() ) - { - 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); + return; + } + + bool isConstant = lctx->type.isConstant && rctx->type.isConstant; + + if( op == ttUnrecognizedToken ) + op = node->tokenType; + + if( !isConstant ) + { + if( to.IsBooleanType() ) + { + 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); #if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0); + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0); #else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0); + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0); #endif - } - } - 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() ) - { - if( op == ttEqual || op == ttNotEqual ) - { - asDWORD lv, rv; - #if AS_SIZEOF_BOOL == 1 - lv = lctx->type.GetConstantB(); - rv = rctx->type.GetConstantB(); - #else - lv = lctx->type.GetConstantDW(); - rv = rctx->type.GetConstantDW(); - #endif - - // Make sure they are equal if not false - if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE; - if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE; - - asDWORD v = 0; - if (op == ttEqual) - v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0; - else if (op == ttNotEqual) - v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0; - - #if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v); - #else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v); - #endif - } - else - { - // 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 = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW()); - if( v < 0 ) i = -1; - if( v > 0 ) i = 1; - } - else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) - { - asDWORD v1 = lctx->type.GetConstantDW(); - asDWORD v2 = rctx->type.GetConstantDW(); - if( v1 < v2 ) i = -1; - if( v1 > v2 ) i = 1; - } - else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW()); - if( v < 0 ) i = -1; - if( v > 0 ) i = 1; - } - else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) - { - asQWORD v1 = lctx->type.GetConstantQW(); - asQWORD v2 = rctx->type.GetConstantQW(); - if( v1 < v2 ) i = -1; - if( v1 > v2 ) i = 1; - } - else if( lctx->type.dataType.IsFloatType() ) - { - float v = lctx->type.GetConstantF() - rctx->type.GetConstantF(); - if( v < 0 ) i = -1; - if( v > 0 ) i = 1; - } - else if( lctx->type.dataType.IsDoubleType() ) - { - double v = lctx->type.GetConstantD() - rctx->type.GetConstantD(); - 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); - - #if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i); - #else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i); - #endif - } - } + } + } + 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() ) + { + if( op == ttEqual || op == ttNotEqual ) + { + asDWORD lv, rv; + #if AS_SIZEOF_BOOL == 1 + lv = lctx->type.GetConstantB(); + rv = rctx->type.GetConstantB(); + #else + lv = lctx->type.GetConstantDW(); + rv = rctx->type.GetConstantDW(); + #endif + + // Make sure they are equal if not false + if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE; + if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE; + + asDWORD v = 0; + if (op == ttEqual) + v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0; + else if (op == ttNotEqual) + v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0; + + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v); + #endif + } + else + { + // 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 = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW()); + if( v < 0 ) i = -1; + if( v > 0 ) i = 1; + } + else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + asDWORD v1 = lctx->type.GetConstantDW(); + asDWORD v2 = rctx->type.GetConstantDW(); + if( v1 < v2 ) i = -1; + if( v1 > v2 ) i = 1; + } + else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW()); + if( v < 0 ) i = -1; + if( v > 0 ) i = 1; + } + else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + asQWORD v1 = lctx->type.GetConstantQW(); + asQWORD v2 = rctx->type.GetConstantQW(); + if( v1 < v2 ) i = -1; + if( v1 > v2 ) i = 1; + } + else if( lctx->type.dataType.IsFloatType() ) + { + float v = lctx->type.GetConstantF() - rctx->type.GetConstantF(); + if( v < 0 ) i = -1; + if( v > 0 ) i = 1; + } + else if( lctx->type.dataType.IsDoubleType() ) + { + double v = lctx->type.GetConstantD() - rctx->type.GetConstantD(); + 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); + + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i); + #endif + } + } } void asCCompiler::PushVariableOnStack(asCExprContext *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); - } + // 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, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) { - // 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); - - // Allow value types to be converted to bool using 'bool opImplConv()' - if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) - ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); - if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) - 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(outFunc->nameSpace).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(outFunc->nameSpace).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? - if( op == ttUnrecognizedToken ) - 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 + // 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); + + // Allow value types to be converted to bool using 'bool opImplConv()' + if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); + if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + 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(outFunc->nameSpace).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(outFunc->nameSpace).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? + if( op == ttUnrecognizedToken ) + 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.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE); - if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE); + if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE); + if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE); - asBYTE v = 0; - v = lctx->type.GetConstantB() - rctx->type.GetConstantB(); - if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; + asBYTE v = 0; + v = lctx->type.GetConstantB() - rctx->type.GetConstantB(); + if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; - ctx->type.isConstant = true; - ctx->type.SetConstantB(v); + ctx->type.isConstant = true; + ctx->type.SetConstantB(v); #else - if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE); - if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE); + if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE); + if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE); - asDWORD v = 0; - v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW(); - if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; + asDWORD v = 0; + v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW(); + if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; - ctx->type.isConstant = true; - ctx->type.SetConstantDW(v); + ctx->type.isConstant = true; + ctx->type.SetConstantDW(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); + } + } + 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); + 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); + 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 - { + 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.GetConstantB() && rctx->type.GetConstantB(); - else if( op == ttOr ) - v = lctx->type.GetConstantB() || rctx->type.GetConstantB(); - - // Remember the result - ctx->type.isConstant = true; - ctx->type.SetConstantB(v); + asBYTE v = 0; + if( op == ttAnd ) + v = lctx->type.GetConstantB() && rctx->type.GetConstantB(); + else if( op == ttOr ) + v = lctx->type.GetConstantB() || rctx->type.GetConstantB(); + + // Remember the result + ctx->type.isConstant = true; + ctx->type.SetConstantB(v); #else - asDWORD v = 0; - if( op == ttAnd ) - v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW(); - else if( op == ttOr ) - v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW(); - - // Remember the result - ctx->type.isConstant = true; - ctx->type.SetConstantDW(v); + asDWORD v = 0; + if( op == ttAnd ) + v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW(); + else if( op == ttOr ) + v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW(); + + // Remember the result + ctx->type.isConstant = true; + ctx->type.SetConstantDW(v); #endif - } - } + } + } } void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken) { - // Process the property accessor as get - if( ProcessPropertyGetAccessor(lctx, node) < 0 ) - return; - if( ProcessPropertyGetAccessor(rctx, node) < 0 ) - return; - - 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); - } - - if( opToken == ttUnrecognizedToken ) - opToken = node->tokenType; - - // Warn if not both operands are explicit handles or null handles - if( (opToken == ttEqual || opToken == ttNotEqual) && - ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) || - (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) ) - { - Warning(TXT_HANDLE_COMPARISON, node); - } - - // If one of the operands is a value type used as handle, we should look for the opEquals method - if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) || - (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) && - (opToken == ttEqual || opToken == ttIs || - opToken == ttNotEqual || opToken == ttNotIs) ) - { - // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used - // Find the matching opEquals method - int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); - if( r == 0 ) - { - // Try again by switching the order of the operands - r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); - } - - if( r == 1 ) - { - if( opToken == ttNotEqual || opToken == 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 + // Process the property accessor as get + if( ProcessPropertyGetAccessor(lctx, node) < 0 ) + return; + if( ProcessPropertyGetAccessor(rctx, node) < 0 ) + return; + + 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); + } + + if( opToken == ttUnrecognizedToken ) + opToken = node->tokenType; + + // Warn if not both operands are explicit handles or null handles + if( (opToken == ttEqual || opToken == ttNotEqual) && + ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) || + (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) ) + { + Warning(TXT_HANDLE_COMPARISON, node); + } + + // If one of the operands is a value type used as handle, we should look for the opEquals method + if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) || + (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) && + (opToken == ttEqual || opToken == ttIs || + opToken == ttNotEqual || opToken == ttNotIs) ) + { + // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used + // Find the matching opEquals method + int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + if( r == 0 ) + { + // Try again by switching the order of the operands + r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + } + + if( r == 1 ) + { + if( opToken == ttNotEqual || opToken == 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 #if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); #else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); #endif - 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 - asCExprContext tmp(engine); - tmp.type = rctx->type; - ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false); - if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() ) - to = lctx->type.dataType; - else - to = rctx->type.dataType; - - // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const - to.MakeHandleToConst(true); - } - - // 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); + 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 + asCExprContext tmp(engine); + tmp.type = rctx->type; + ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false); + if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() ) + to = lctx->type.dataType; + else + to = rctx->type.dataType; + + // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const + to.MakeHandleToConst(true); + } + + // 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); #if AS_SIZEOF_BOOL == 1 - ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); #else - ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); #endif - 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); - Error(str, node); - } - - if( !rctx->type.dataType.IsEqualExceptConst(to) ) - { - asCString str; - str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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)); - - if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs ) - { - // Make sure handles received as parameters by reference are copied to a local variable before the - // 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( opToken == ttEqual || opToken == ttIs ) - ctx->bc.Instr(asBC_TZ); - else if( opToken == ttNotEqual || opToken == 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); - } + 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(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + + if( !rctx->type.dataType.IsEqualExceptConst(to) ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).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)); + + if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs ) + { + // Make sure handles received as parameters by reference are copied to a local variable before the + // 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( opToken == ttEqual || opToken == ttIs ) + ctx->bc.Instr(asBC_TZ); + else if( opToken == ttNotEqual || opToken == 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, asCExprContext *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 or protected - if (descr->IsPrivate()) - { - asCObjectType *type = descr->objectType; - if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR)) - type = CastToObjectType(descr->returnType.GetTypeInfo()); - - asASSERT(type); - - if( (type != outFunc->GetObjectType()) ) - { - asCString msg; - msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf()); - Error(msg, ctx->exprNode); - } - } - else if (descr->IsProtected()) - { - asCObjectType *type = descr->objectType; - if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR)) - type = CastToObjectType(descr->returnType.GetTypeInfo()); - - asASSERT(type); - - if (!(type == outFunc->objectType || (outFunc->objectType && outFunc->objectType->DerivesFrom(type)))) - { - asCString msg; - msg.Format(TXT_PROTECTED_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 reference. - if( !ctx->type.isRefSafe && - descr->objectType && - (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) && - (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) && - !(ctx->type.isVariable || ctx->type.isTemporary) && - !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) && - !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) ) - { - // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a - // 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. - - int tempRef = AllocateVariable(ctx->type.dataType, true); - ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef); - ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); - - // 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); - - if( (objType->flags & asOBJ_TEMPLATE) ) - { - asASSERT( descr->funcType == asFUNC_SCRIPT ); - - // Find the id of the real constructor and not the generated stub - asUINT id = 0; - asDWORD *bc = descr->scriptData->byteCode.AddressOf(); - while( bc ) - { - if( (*(asBYTE*)bc) == asBC_CALLSYS ) - { - id = asBC_INTARG(bc); - break; - } - bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type]; - } - - asASSERT( id ); - - ctx->bc.InstrPTR(asBC_OBJTYPE, objType); - ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE); - } - else - 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 ) - { - // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of - // type &obj::func(int) - // type &obj::func(uint) - if( descr->GetObjectType() && descr->returnType.IsReference() && - descr->parameterTypes.GetLength() == 1 && - (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) && - descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 && - !descr->parameterTypes[0].IsReference() ) - ctx->bc.Call(asBC_Thiscall1, descr->id, argSize); - else - 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.IsFuncdef()) && !descr->returnType.IsReference() ) - { - int returnOffset = 0; - - asCExprValue 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 - { - asCExprValue tmpExpr = ctx->type; - - if( descr->returnType.GetSizeInMemoryBytes() ) - { - int offset; - if (useVariable) - offset = varOffset; - else - { - // 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++) - { - asCExprContext *expr = (*args)[n]->origExpr; - if (expr) - expr->bc.GetVarsUsed(reservedVariables); - } - 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); - } + 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 or protected + if (descr->IsPrivate()) + { + asCObjectType *type = descr->objectType; + if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR)) + type = CastToObjectType(descr->returnType.GetTypeInfo()); + + asASSERT(type); + + if( (type != outFunc->GetObjectType()) ) + { + asCString msg; + msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf()); + Error(msg, ctx->exprNode); + } + } + else if (descr->IsProtected()) + { + asCObjectType *type = descr->objectType; + if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR)) + type = CastToObjectType(descr->returnType.GetTypeInfo()); + + asASSERT(type); + + if (!(type == outFunc->objectType || (outFunc->objectType && outFunc->objectType->DerivesFrom(type)))) + { + asCString msg; + msg.Format(TXT_PROTECTED_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 reference. + if( !ctx->type.isRefSafe && + descr->objectType && + (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) && + (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) && + !(ctx->type.isVariable || ctx->type.isTemporary) && + !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) && + !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) ) + { + // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a + // 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. + + int tempRef = AllocateVariable(ctx->type.dataType, true); + ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef); + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + + // 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); + + if( (objType->flags & asOBJ_TEMPLATE) ) + { + asASSERT( descr->funcType == asFUNC_SCRIPT ); + + // Find the id of the real constructor and not the generated stub + asUINT id = 0; + asDWORD *bc = descr->scriptData->byteCode.AddressOf(); + while( bc ) + { + if( (*(asBYTE*)bc) == asBC_CALLSYS ) + { + id = asBC_INTARG(bc); + break; + } + bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type]; + } + + asASSERT( id ); + + ctx->bc.InstrPTR(asBC_OBJTYPE, objType); + ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE); + } + else + 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 ) + { + // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of + // type &obj::func(int) + // type &obj::func(uint) + if( descr->GetObjectType() && descr->returnType.IsReference() && + descr->parameterTypes.GetLength() == 1 && + (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) && + descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 && + !descr->parameterTypes[0].IsReference() ) + ctx->bc.Call(asBC_Thiscall1, descr->id, argSize); + else + 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.IsFuncdef()) && !descr->returnType.IsReference() ) + { + int returnOffset = 0; + + asCExprValue 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 + { + asCExprValue tmpExpr = ctx->type; + + if( descr->returnType.GetSizeInMemoryBytes() ) + { + int offset; + if (useVariable) + offset = varOffset; + else + { + // 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++) + { + asCExprContext *expr = (*args)[n]->origExpr; + if (expr) + expr->bc.GetVarsUsed(reservedVariables); + } + 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(asCExprContext *before, asCExprContext *after) { - before->bc.AddCode(&after->bc); + 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; - } + for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ ) + { + before->deferredParams.PushLast(after->deferredParams[n]); + after->deferredParams[n].origExpr = 0; + } - after->deferredParams.SetLength(0); + after->deferredParams.SetLength(0); } // This merges both bytecode and the type of the final context void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after) { - MergeExprBytecode(before, after); + MergeExprBytecode(before, after); - before->Merge(after); + before->Merge(after); } 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 || 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 && 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 && desc->IsReadOnly() == removeConst ) - { - if( n == funcs.GetLength() - 1 ) - funcs.PopLast(); - else - funcs[n] = funcs.PopLast(); - - n--; - } - } - } + if( funcs.GetLength() == 0 ) return; + + // This is only done for object methods + asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]); + if( !desc || 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 && 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 && desc->IsReadOnly() == removeConst ) + { + if( n == funcs.GetLength() - 1 ) + funcs.PopLast(); + else + funcs[n] = funcs.PopLast(); + + n--; + } + } + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// asCExprValue::asCExprValue() { - isTemporary = false; - stackOffset = 0; - isConstant = false; - isVariable = false; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; - isRefToLocal = false; - isRefSafe = false; + isTemporary = false; + stackOffset = 0; + isConstant = false; + isVariable = false; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; + isRefToLocal = false; + isRefSafe = false; } void asCExprValue::Set(const asCDataType &dt) { - dataType = dt; - - isTemporary = false; - stackOffset = 0; - isConstant = false; - isVariable = false; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; - isRefToLocal = false; - isRefSafe = false; + dataType = dt; + + isTemporary = false; + stackOffset = 0; + isConstant = false; + isVariable = false; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; + isRefToLocal = false; + isRefSafe = false; } void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary) { - Set(in_dt); + Set(in_dt); - this->isVariable = true; - this->isTemporary = in_isTemporary; - this->stackOffset = (short)in_stackOffset; + this->isVariable = true; + this->isTemporary = in_isTemporary; + this->stackOffset = (short)in_stackOffset; } void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value) { - Set(dt); + Set(dt); - isConstant = true; - SetConstantQW(value); + isConstant = true; + SetConstantQW(value); } void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value) { - Set(dt); + Set(dt); - isConstant = true; - SetConstantDW(value); + isConstant = true; + SetConstantDW(value); } void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value) { - Set(dt); + Set(dt); - isConstant = true; - SetConstantB(value); + isConstant = true; + SetConstantB(value); } void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value) { - Set(dt); + Set(dt); - isConstant = true; - SetConstantW(value); + isConstant = true; + SetConstantW(value); } void asCExprValue::SetConstantF(const asCDataType &dt, float value) { - Set(dt); + Set(dt); - isConstant = true; - SetConstantF(value); + isConstant = true; + SetConstantF(value); } void asCExprValue::SetConstantD(const asCDataType &dt, double value) { - Set(dt); + Set(dt); - isConstant = true; - SetConstantD(value); + isConstant = true; + SetConstantD(value); } void asCExprValue::SetConstantQW(asQWORD value) { - asASSERT(dataType.GetSizeInMemoryBytes() == 8); - qwordValue = value; + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + qwordValue = value; } void asCExprValue::SetConstantDW(asDWORD value) { - asASSERT(dataType.GetSizeInMemoryBytes() == 4); - dwordValue = value; + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + dwordValue = value; } void asCExprValue::SetConstantW(asWORD value) { - asASSERT(dataType.GetSizeInMemoryBytes() == 2); - wordValue = value; + asASSERT(dataType.GetSizeInMemoryBytes() == 2); + wordValue = value; } void asCExprValue::SetConstantB(asBYTE value) { - asASSERT(dataType.GetSizeInMemoryBytes() == 1); - byteValue = value; + asASSERT(dataType.GetSizeInMemoryBytes() == 1); + byteValue = value; } void asCExprValue::SetConstantF(float value) { - asASSERT(dataType.GetSizeInMemoryBytes() == 4); - floatValue = value; + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + floatValue = value; } void asCExprValue::SetConstantD(double value) { - asASSERT(dataType.GetSizeInMemoryBytes() == 8); - doubleValue = value; + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + doubleValue = value; } asQWORD asCExprValue::GetConstantQW() { - asASSERT(dataType.GetSizeInMemoryBytes() == 8); - return qwordValue; + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + return qwordValue; } asDWORD asCExprValue::GetConstantDW() { - asASSERT(dataType.GetSizeInMemoryBytes() == 4); - return dwordValue; + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + return dwordValue; } asWORD asCExprValue::GetConstantW() { - asASSERT(dataType.GetSizeInMemoryBytes() == 2); - return wordValue; + asASSERT(dataType.GetSizeInMemoryBytes() == 2); + return wordValue; } asBYTE asCExprValue::GetConstantB() { - asASSERT(dataType.GetSizeInMemoryBytes() == 1); - return byteValue; + asASSERT(dataType.GetSizeInMemoryBytes() == 1); + return byteValue; } float asCExprValue::GetConstantF() { - asASSERT(dataType.GetSizeInMemoryBytes() == 4); - return floatValue; + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + return floatValue; } double asCExprValue::GetConstantD() { - asASSERT(dataType.GetSizeInMemoryBytes() == 8); - return doubleValue; + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + return doubleValue; } void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw) { - Set(dt); - - isConstant = true; - - // This code is necessary to guarantee that the code - // works on both big endian and little endian CPUs. - if (dataType.GetSizeInMemoryBytes() == 1) - byteValue = (asBYTE)qw; - if (dataType.GetSizeInMemoryBytes() == 2) - wordValue = (asWORD)qw; - if (dataType.GetSizeInMemoryBytes() == 4) - dwordValue = (asDWORD)qw; - else - qwordValue = qw; + Set(dt); + + isConstant = true; + + // This code is necessary to guarantee that the code + // works on both big endian and little endian CPUs. + if (dataType.GetSizeInMemoryBytes() == 1) + byteValue = (asBYTE)qw; + if (dataType.GetSizeInMemoryBytes() == 2) + wordValue = (asWORD)qw; + if (dataType.GetSizeInMemoryBytes() == 4) + dwordValue = (asDWORD)qw; + else + qwordValue = qw; } asQWORD asCExprValue::GetConstantData() { - asQWORD qw = 0; - // This code is necessary to guarantee that the code - // works on both big endian and little endian CPUs. - if (dataType.GetSizeInMemoryBytes() == 1) - qw = byteValue; - if (dataType.GetSizeInMemoryBytes() == 2) - qw = wordValue; - if (dataType.GetSizeInMemoryBytes() == 4) - qw = dwordValue; - else - qw = qwordValue; - return qw; + asQWORD qw = 0; + // This code is necessary to guarantee that the code + // works on both big endian and little endian CPUs. + if (dataType.GetSizeInMemoryBytes() == 1) + qw = byteValue; + if (dataType.GetSizeInMemoryBytes() == 2) + qw = wordValue; + if (dataType.GetSizeInMemoryBytes() == 4) + qw = dwordValue; + else + qw = qwordValue; + return qw; } void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine) { - // This is used for when the expression evaluates to a - // function, but it is not yet known exactly which. The - // owner expression will hold the name of the function - // to determine the exact function when the signature is - // known. - Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true)); - isConstant = true; - isExplicitHandle = false; - qwordValue = 1; // Set to a different value than 0 to differentiate from null constant - isLValue = false; + // This is used for when the expression evaluates to a + // function, but it is not yet known exactly which. The + // owner expression will hold the name of the function + // to determine the exact function when the signature is + // known. + Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true)); + isConstant = true; + isExplicitHandle = false; + qwordValue = 1; // Set to a different value than 0 to differentiate from null constant + isLValue = false; } bool asCExprValue::IsUndefinedFuncHandle() const { - if (isConstant == false) return false; - if (qwordValue == 0) return false; - if (isLValue) return false; - if (dataType.GetTypeInfo() == 0) return false; - if (dataType.GetTypeInfo()->name != "$func") return false; - if (dataType.IsFuncdef()) return false; - - return true; + if (isConstant == false) return false; + if (qwordValue == 0) return false; + if (isLValue) return false; + if (dataType.GetTypeInfo() == 0) return false; + if (dataType.GetTypeInfo()->name != "$func") return false; + if (dataType.IsFuncdef()) return false; + + return true; } void asCExprValue::SetNullConstant() { - Set(asCDataType::CreateNullHandle()); - isConstant = true; - isExplicitHandle = false; - qwordValue = 0; - isLValue = false; + Set(asCDataType::CreateNullHandle()); + isConstant = true; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; } bool asCExprValue::IsNullConstant() const { - // We can't check the actual object type, because the null constant may have been cast to another type - if (isConstant && dataType.IsObjectHandle() && qwordValue == 0) - return true; + // We can't check the actual object type, because the null constant may have been cast to another type + if (isConstant && dataType.IsObjectHandle() && qwordValue == 0) + return true; - return false; + return false; } void asCExprValue::SetVoid() { - Set(asCDataType::CreatePrimitive(ttVoid, false)); - isLValue = false; - isConstant = true; + Set(asCDataType::CreatePrimitive(ttVoid, false)); + isLValue = false; + isConstant = true; } bool asCExprValue::IsVoid() const { - if (dataType.GetTokenType() == ttVoid) - return true; + if (dataType.GetTokenType() == ttVoid) + return true; - return false; + return false; } void asCExprValue::SetDummy() { - SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); + SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); } //////////////////////////////////////////////////////////////////////////////////////////////// asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine) { - property_arg = 0; + property_arg = 0; - Clear(); + Clear(); } asCExprContext::~asCExprContext() { - if (property_arg) - asDELETE(property_arg, asCExprContext); + if (property_arg) + asDELETE(property_arg, asCExprContext); } void asCExprContext::Clear() { - bc.ClearAll(); - type.Set(asCDataType()); - deferredParams.SetLength(0); - if (property_arg) - asDELETE(property_arg, asCExprContext); - property_arg = 0; - exprNode = 0; - origExpr = 0; - property_get = 0; - property_set = 0; - property_const = false; - property_handle = false; - property_ref = false; - methodName = ""; - enumValue = ""; - symbolNamespace = 0; - isVoidExpression = false; - isCleanArg = false; - isAnonymousInitList = false; - origCode = 0; + bc.ClearAll(); + type.Set(asCDataType()); + deferredParams.SetLength(0); + if (property_arg) + asDELETE(property_arg, asCExprContext); + property_arg = 0; + exprNode = 0; + origExpr = 0; + property_get = 0; + property_set = 0; + property_const = false; + property_handle = false; + property_ref = false; + methodName = ""; + enumValue = ""; + symbolNamespace = 0; + isVoidExpression = false; + isCleanArg = false; + isAnonymousInitList = false; + origCode = 0; } bool asCExprContext::IsClassMethod() const { - if (type.dataType.GetTypeInfo() == 0) return false; - if (methodName == "") return false; - if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false; - if (isAnonymousInitList) return false; - return true; + if (type.dataType.GetTypeInfo() == 0) return false; + if (methodName == "") return false; + if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false; + if (isAnonymousInitList) return false; + return true; } bool asCExprContext::IsGlobalFunc() const { - if (type.dataType.GetTypeInfo() == 0) return false; - if (methodName == "") return false; - if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false; - if (isAnonymousInitList) return false; - return true; + if (type.dataType.GetTypeInfo() == 0) return false; + if (methodName == "") return false; + if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false; + if (isAnonymousInitList) return false; + return true; } void asCExprContext::SetLambda(asCScriptNode *funcDecl) { - asASSERT(funcDecl && funcDecl->nodeType == snFunction); - asASSERT(bc.GetLastInstr() == -1); + asASSERT(funcDecl && funcDecl->nodeType == snFunction); + asASSERT(bc.GetLastInstr() == -1); - Clear(); - type.SetUndefinedFuncHandle(bc.GetEngine()); - exprNode = funcDecl; + Clear(); + type.SetUndefinedFuncHandle(bc.GetEngine()); + exprNode = funcDecl; } bool asCExprContext::IsLambda() const { - if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction) - return true; + if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction) + return true; - return false; + return false; } void asCExprContext::SetVoidExpression() { - Clear(); - type.SetVoid(); - isVoidExpression = true; + Clear(); + type.SetVoid(); + isVoidExpression = true; } bool asCExprContext::IsVoidExpression() const { - if (isVoidExpression && type.IsVoid() && exprNode == 0) - return true; + if (isVoidExpression && type.IsVoid() && exprNode == 0) + return true; - return false; + return false; } void asCExprContext::SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script) { - Clear(); - exprNode = initList; - origCode = script; - isAnonymousInitList = true; + Clear(); + exprNode = initList; + origCode = script; + isAnonymousInitList = true; } bool asCExprContext::IsAnonymousInitList() const { - if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList) - return true; + if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList) + return true; - return false; + return false; } void asCExprContext::Copy(asCExprContext *other) { - type = other->type; - property_get = other->property_get; - property_set = other->property_set; - property_const = other->property_const; - property_handle = other->property_handle; - property_ref = other->property_ref; - property_arg = other->property_arg; - exprNode = other->exprNode; - methodName = other->methodName; - enumValue = other->enumValue; - isVoidExpression = other->isVoidExpression; - isCleanArg = other->isCleanArg; - isAnonymousInitList = other->isAnonymousInitList; - origCode = other->origCode; - - // Do not copy the origExpr member + type = other->type; + property_get = other->property_get; + property_set = other->property_set; + property_const = other->property_const; + property_handle = other->property_handle; + property_ref = other->property_ref; + property_arg = other->property_arg; + exprNode = other->exprNode; + methodName = other->methodName; + enumValue = other->enumValue; + isVoidExpression = other->isVoidExpression; + isCleanArg = other->isCleanArg; + isAnonymousInitList = other->isAnonymousInitList; + origCode = other->origCode; + + // Do not copy the origExpr member } void asCExprContext::Merge(asCExprContext *after) { - // Overwrite properties with the expression that comes after - Copy(after); + // Overwrite properties with the expression that comes after + Copy(after); - // Clean the properties in 'after' that have now moved into - // this structure so they are not cleaned up accidentally - after->property_arg = 0; + // Clean the properties in 'after' that have now moved into + // this structure so they are not cleaned up accidentally + after->property_arg = 0; } diff --git a/src/angelscript/source/as_compiler.h b/src/angelscript/source/as_compiler.h index ae4bff4e922..578c166fcdd 100644 --- a/src/angelscript/source/as_compiler.h +++ b/src/angelscript/source/as_compiler.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2020 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -54,382 +54,382 @@ BEGIN_AS_NAMESPACE // This class represents the value of an expression as evaluated by the compiler. -// It holds information such as the type of the value, stack offset for a local +// It holds information such as the type of the value, stack offset for a local // variable, value of constants, whether the value can be modified (i.e. lvalue), etc. struct asCExprValue { - asCExprValue(); - void Set(const asCDataType &dataType); - - void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary); - void SetConstantB(const asCDataType &dataType, asBYTE value); - void SetConstantQW(const asCDataType &dataType, asQWORD value); - void SetConstantDW(const asCDataType &dataType, asDWORD value); - void SetConstantW(const asCDataType &dataType, asWORD value); - void SetConstantF(const asCDataType &dataType, float value); - void SetConstantD(const asCDataType &dataType, double value); - void SetConstantB(asBYTE value); - void SetConstantW(asWORD value); - void SetConstantQW(asQWORD value); - void SetConstantDW(asDWORD value); - void SetConstantF(float value); - void SetConstantD(double value); - asBYTE GetConstantB(); - asWORD GetConstantW(); - asQWORD GetConstantQW(); - asDWORD GetConstantDW(); - float GetConstantF(); - double GetConstantD(); - - void SetConstantData(const asCDataType &dataType, asQWORD value); - asQWORD GetConstantData(); - - void SetNullConstant(); - void SetUndefinedFuncHandle(asCScriptEngine *engine); - void SetVoid(); - void SetDummy(); - - bool IsUndefinedFuncHandle() const; - bool IsNullConstant() const; - bool IsVoid() const; - - asCDataType dataType; - bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc - bool isTemporary : 1; - bool isConstant : 1; - bool isVariable : 1; - bool isExplicitHandle : 1; - bool isRefToLocal : 1; // The reference may be to a local variable - bool isRefSafe : 1; // the life-time of the ref is guaranteed for the duration of the access - short dummy : 9; - short stackOffset; + asCExprValue(); + void Set(const asCDataType &dataType); + + void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary); + void SetConstantB(const asCDataType &dataType, asBYTE value); + void SetConstantQW(const asCDataType &dataType, asQWORD value); + void SetConstantDW(const asCDataType &dataType, asDWORD value); + void SetConstantW(const asCDataType &dataType, asWORD value); + void SetConstantF(const asCDataType &dataType, float value); + void SetConstantD(const asCDataType &dataType, double value); + void SetConstantB(asBYTE value); + void SetConstantW(asWORD value); + void SetConstantQW(asQWORD value); + void SetConstantDW(asDWORD value); + void SetConstantF(float value); + void SetConstantD(double value); + asBYTE GetConstantB(); + asWORD GetConstantW(); + asQWORD GetConstantQW(); + asDWORD GetConstantDW(); + float GetConstantF(); + double GetConstantD(); + + void SetConstantData(const asCDataType &dataType, asQWORD value); + asQWORD GetConstantData(); + + void SetNullConstant(); + void SetUndefinedFuncHandle(asCScriptEngine *engine); + void SetVoid(); + void SetDummy(); + + bool IsUndefinedFuncHandle() const; + bool IsNullConstant() const; + bool IsVoid() const; + + asCDataType dataType; + bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc + bool isTemporary : 1; + bool isConstant : 1; + bool isVariable : 1; + bool isExplicitHandle : 1; + bool isRefToLocal : 1; // The reference may be to a local variable + bool isRefSafe : 1; // the life-time of the ref is guaranteed for the duration of the access + short dummy : 9; + short stackOffset; private: - // These values must not be accessed directly in order to avoid problems with endianess. - // Use the appropriate accessor methods instead - union - { - asQWORD qwordValue; - double doubleValue; - asDWORD dwordValue; - float floatValue; - asWORD wordValue; - asBYTE byteValue; - }; + // These values must not be accessed directly in order to avoid problems with endianess. + // Use the appropriate accessor methods instead + union + { + asQWORD qwordValue; + double doubleValue; + asDWORD dwordValue; + float floatValue; + asWORD wordValue; + asBYTE byteValue; + }; }; struct asCExprContext; -// This class holds information for arguments that needs to be +// This class holds information for arguments that needs to be // cleaned up after the result of a function has been evaluated. struct asSDeferredParam { - asSDeferredParam() {argNode = 0; origExpr = 0;} + asSDeferredParam() {argNode = 0; origExpr = 0;} - asCScriptNode *argNode; - asCExprValue argType; - int argInOutFlags; - asCExprContext *origExpr; + asCScriptNode *argNode; + asCExprValue argType; + int argInOutFlags; + asCExprContext *origExpr; }; -// TODO: refactor: asCExprContext should have indicators to inform where the value is, +// TODO: refactor: asCExprContext should have indicators to inform where the value is, // i.e. if the reference to an object is pushed on the stack or not, etc // This class holds information about an expression that is being evaluated, e.g. // the current bytecode, ambiguous symbol names, property accessors, etc. struct asCExprContext { - asCExprContext(asCScriptEngine *engine); - ~asCExprContext(); - void Clear(); - bool IsClassMethod() const; - bool IsGlobalFunc() const; - void SetLambda(asCScriptNode *funcDecl); - bool IsLambda() const; - void SetVoidExpression(); - bool IsVoidExpression() const; - void Merge(asCExprContext *after); - void Copy(asCExprContext *other); - void SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script); - bool IsAnonymousInitList() const; - - asCByteCode bc; - asCExprValue 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 - bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls - bool isCleanArg; // Set to true if the expression has only been initialized with default constructor - asCExprContext *property_arg; - asCArray deferredParams; - asCScriptNode *exprNode; - asCExprContext *origExpr; - asCScriptCode *origCode; - // TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value - asCString methodName; - asCString enumValue; - asSNameSpace *symbolNamespace; // The namespace in which the ambiguous symbol was found - bool isAnonymousInitList; // Set to true if the expression is an init list for which the type has not yet been determined + asCExprContext(asCScriptEngine *engine); + ~asCExprContext(); + void Clear(); + bool IsClassMethod() const; + bool IsGlobalFunc() const; + void SetLambda(asCScriptNode *funcDecl); + bool IsLambda() const; + void SetVoidExpression(); + bool IsVoidExpression() const; + void Merge(asCExprContext *after); + void Copy(asCExprContext *other); + void SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script); + bool IsAnonymousInitList() const; + + asCByteCode bc; + asCExprValue 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 + bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls + bool isCleanArg; // Set to true if the expression has only been initialized with default constructor + asCExprContext *property_arg; + asCArray deferredParams; + asCScriptNode *exprNode; + asCExprContext *origExpr; + asCScriptCode *origCode; + // TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value + asCString methodName; + asCString enumValue; + asSNameSpace *symbolNamespace; // The namespace in which the ambiguous symbol was found + bool isAnonymousInitList; // Set to true if the expression is an init list for which the type has not yet been determined }; struct asSOverloadCandidate { - asSOverloadCandidate() : funcId(0), cost(0) {} - asSOverloadCandidate(int _id, asUINT _cost) : funcId(_id), cost(_cost) {} - int funcId; - asUINT cost; + asSOverloadCandidate() : funcId(0), cost(0) {} + asSOverloadCandidate(int _id, asUINT _cost) : funcId(_id), cost(_cost) {} + int funcId; + asUINT cost; }; struct asSNamedArgument { - asCString name; - asCExprContext *ctx; - asUINT match; + asCString name; + asCExprContext *ctx; + asUINT match; }; enum EImplicitConv { - asIC_IMPLICIT_CONV, - asIC_EXPLICIT_REF_CAST, - asIC_EXPLICIT_VAL_CAST + asIC_IMPLICIT_CONV, + asIC_EXPLICIT_REF_CAST, + asIC_EXPLICIT_VAL_CAST }; enum EConvCost { - asCC_NO_CONV = 0, - asCC_CONST_CONV = 1, - asCC_ENUM_SAME_SIZE_CONV = 2, - asCC_ENUM_DIFF_SIZE_CONV = 3, - asCC_PRIMITIVE_SIZE_CONV = 4, - asCC_SIGNED_CONV = 5, - asCC_INT_FLOAT_CONV = 6, - asCC_REF_CONV = 7, - asCC_OBJ_TO_PRIMITIVE_CONV = 8, - asCC_TO_OBJECT_CONV = 9, - asCC_VARIABLE_CONV = 10 + asCC_NO_CONV = 0, + asCC_CONST_CONV = 1, + asCC_ENUM_SAME_SIZE_CONV = 2, + asCC_ENUM_DIFF_SIZE_CONV = 3, + asCC_PRIMITIVE_SIZE_CONV = 4, + asCC_SIGNED_CONV = 5, + asCC_INT_FLOAT_CONV = 6, + asCC_REF_CONV = 7, + asCC_OBJ_TO_PRIMITIVE_CONV = 8, + asCC_TO_OBJECT_CONV = 9, + asCC_VARIABLE_CONV = 10 }; class asCCompiler { public: - asCCompiler(asCScriptEngine *engine); - ~asCCompiler(); + 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); + 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); - void CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); - - // Expressions - int CompileAssignment(asCScriptNode *expr, asCExprContext *out); - int CompileCondition(asCScriptNode *expr, asCExprContext *out); - int CompileExpression(asCScriptNode *expr, asCExprContext *out); - int CompilePostFixExpression(asCArray *postfix, asCExprContext *out); - int CompileExpressionTerm(asCScriptNode *node, asCExprContext *out); - int CompileExpressionPreOp(asCScriptNode *node, asCExprContext *out); - int CompileExpressionPostOp(asCScriptNode *node, asCExprContext *out); - int CompileExpressionValue(asCScriptNode *node, asCExprContext *out); - int CompileFunctionCall(asCScriptNode *node, asCExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = ""); - int CompileConstructCall(asCScriptNode *node, asCExprContext *out); - int CompileConversion(asCScriptNode *node, asCExprContext *out); - int CompileOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken, bool leftToRight = true); - void CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileMathOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileBitwiseOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileComparisonOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); - void CompileBooleanOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); - bool CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken); - int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false)); - - void CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem); - int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList); - int CompileAnonymousInitList(asCScriptNode *listNode, asCExprContext *ctx, const asCDataType &dt); - - int CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false); - int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false); - void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc); - int CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs); - int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *type, asCArray *namedArgs = 0); - asUINT MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs = NULL, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = ""); - int CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, asCObjectType *objType = 0); - void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults); - bool CompileAutoType(asCDataType &autoType, asCExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode); - bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled = 0); - void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination); - - // Helper functions - void ConvertToPostFix(asCScriptNode *expr, asCArray &postfix); - int ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node); - int ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node); - int ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode); - int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); - int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); - void PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap = false); - void PrepareOperand(asCExprContext *ctx, asCScriptNode *node); - void PrepareForAssignment(asCDataType *lvalue, asCExprContext *rvalue, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr = 0); - int PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node); - bool IsVariableInitialized(asCExprValue *type, asCScriptNode *node); - void Dereference(asCExprContext *ctx, bool generateCode); - bool CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true); - asUINT MatchArgument(asCArray &funcs, asCArray &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); - int MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); - void PerformFunctionCall(int funcId, asCExprContext *out, bool isConstructor = false, asCArray *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0); - void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset); - int MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0); - int PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args); - void AfterFunctionCall(int funcId, asCArray &args, asCExprContext *ctx, bool deferAll); - void ProcessDeferredParams(asCExprContext *ctx); - int PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false); - int PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false); - bool IsLValue(asCExprValue &type); - int DoAssignment(asCExprContext *out, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode); - void MergeExprBytecode(asCExprContext *before, asCExprContext *after); - void MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after); - void FilterConst(asCArray &funcs, bool removeConst = true); - void ConvertToVariable(asCExprContext *ctx); - void ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); - void ConvertToTempVariable(asCExprContext *ctx); - void ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); - void ConvertToReference(asCExprContext *ctx); - void PushVariableOnStack(asCExprContext *ctx, bool asReference); - void DestroyVariables(asCByteCode *bc); - asSNameSpace *DetermineNameSpace(const asCString &scope); - int SetupParametersAndReturnVariable(asCArray ¶meterNames, asCScriptNode *func); - - enum SYMBOLTYPE - { - SL_NOMATCH, - SL_LOCALCONST, - SL_LOCALVAR, - SL_THISPTR, - SL_CLASSPROPACCESS, - SL_CLASSPROP, - SL_CLASSMETHOD, - SL_CLASSTYPE, - SL_GLOBALPROPACCESS, - SL_GLOBALCONST, - SL_GLOBALVAR, - SL_GLOBALFUNC, - SL_GLOBALTYPE, - SL_ENUMVAL, - SL_ERROR = -1 - }; - - SYMBOLTYPE SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult); - SYMBOLTYPE SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult); - SYMBOLTYPE SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult); - - void DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node); - - // Returns the cost of the conversion (the sum of the EConvCost performed) - asUINT ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); - asUINT ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); - asUINT ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); - asUINT ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); - asUINT ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); - void ImplicitConversionConstant(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType); - void ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node); - asUINT ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); - - void LineInstr(asCByteCode *bc, size_t pos); - - 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; - int numLambdas; - - asCVariableScope *variables; - asCBuilder *builder; - asCScriptEngine *engine; - asCScriptCode *script; - asCScriptFunction *outFunc; - - bool m_isConstructor; - bool m_isConstructorCalled; - sClassDeclaration *m_classDecl; - sGlobalVariableDescription *m_globalVar; - - asCArray breakLabels; - asCArray continueLabels; - - int AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap = false, bool asReference = false); - int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx); - int GetVariableOffset(int varIndex); - int GetVariableSlot(int varOffset); - void DeallocateVariable(int pos); - void ReleaseTemporaryVariable(asCExprValue &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; - - // This array holds the string constants that were allocated during the compilation, - // so they can be released upon completion, whether the compilation was successful or not. - asCArray usedStringConstants; - - // This array holds the nodes that have been allocated temporarily - asCArray nodesToFreeUponComplete; - - bool isCompilingDefaultArg; - bool isProcessingDeferredParams; - int noCodeOutput; + 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); + void CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); + + // Expressions + int CompileAssignment(asCScriptNode *expr, asCExprContext *out); + int CompileCondition(asCScriptNode *expr, asCExprContext *out); + int CompileExpression(asCScriptNode *expr, asCExprContext *out); + int CompilePostFixExpression(asCArray *postfix, asCExprContext *out); + int CompileExpressionTerm(asCScriptNode *node, asCExprContext *out); + int CompileExpressionPreOp(asCScriptNode *node, asCExprContext *out); + int CompileExpressionPostOp(asCScriptNode *node, asCExprContext *out); + int CompileExpressionValue(asCScriptNode *node, asCExprContext *out); + int CompileFunctionCall(asCScriptNode *node, asCExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = ""); + int CompileConstructCall(asCScriptNode *node, asCExprContext *out); + int CompileConversion(asCScriptNode *node, asCExprContext *out); + int CompileOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken, bool leftToRight = true); + void CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileMathOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileBitwiseOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileComparisonOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileBooleanOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + bool CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken); + int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false)); + + void CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem); + int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList); + int CompileAnonymousInitList(asCScriptNode *listNode, asCExprContext *ctx, const asCDataType &dt); + + int CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false); + int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false); + void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc); + int CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs); + int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *type, asCArray *namedArgs = 0); + asUINT MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs = NULL, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = ""); + int CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, asCObjectType *objType = 0); + void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults); + bool CompileAutoType(asCDataType &autoType, asCExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode); + bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled = 0); + void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination); + + // Helper functions + void ConvertToPostFix(asCScriptNode *expr, asCArray &postfix); + int ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node); + int ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node); + int ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode); + int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); + int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); + void PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap = false); + void PrepareOperand(asCExprContext *ctx, asCScriptNode *node); + void PrepareForAssignment(asCDataType *lvalue, asCExprContext *rvalue, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr = 0); + int PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node); + bool IsVariableInitialized(asCExprValue *type, asCScriptNode *node); + void Dereference(asCExprContext *ctx, bool generateCode); + bool CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true); + asUINT MatchArgument(asCArray &funcs, asCArray &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); + int MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); + void PerformFunctionCall(int funcId, asCExprContext *out, bool isConstructor = false, asCArray *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0); + void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset); + int MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0); + int PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args); + void AfterFunctionCall(int funcId, asCArray &args, asCExprContext *ctx, bool deferAll); + void ProcessDeferredParams(asCExprContext *ctx); + int PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false); + int PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false); + bool IsLValue(asCExprValue &type); + int DoAssignment(asCExprContext *out, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode); + void MergeExprBytecode(asCExprContext *before, asCExprContext *after); + void MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after); + void FilterConst(asCArray &funcs, bool removeConst = true); + void ConvertToVariable(asCExprContext *ctx); + void ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); + void ConvertToTempVariable(asCExprContext *ctx); + void ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); + void ConvertToReference(asCExprContext *ctx); + void PushVariableOnStack(asCExprContext *ctx, bool asReference); + void DestroyVariables(asCByteCode *bc); + asSNameSpace *DetermineNameSpace(const asCString &scope); + int SetupParametersAndReturnVariable(asCArray ¶meterNames, asCScriptNode *func); + + enum SYMBOLTYPE + { + SL_NOMATCH, + SL_LOCALCONST, + SL_LOCALVAR, + SL_THISPTR, + SL_CLASSPROPACCESS, + SL_CLASSPROP, + SL_CLASSMETHOD, + SL_CLASSTYPE, + SL_GLOBALPROPACCESS, + SL_GLOBALCONST, + SL_GLOBALVAR, + SL_GLOBALFUNC, + SL_GLOBALTYPE, + SL_ENUMVAL, + SL_ERROR = -1 + }; + + SYMBOLTYPE SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult); + SYMBOLTYPE SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult); + SYMBOLTYPE SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult); + + void DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node); + + // Returns the cost of the conversion (the sum of the EConvCost performed) + asUINT ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + asUINT ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + asUINT ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); + asUINT ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); + void ImplicitConversionConstant(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType); + void ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node); + asUINT ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + + void LineInstr(asCByteCode *bc, size_t pos); + + 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; + int numLambdas; + + asCVariableScope *variables; + asCBuilder *builder; + asCScriptEngine *engine; + asCScriptCode *script; + asCScriptFunction *outFunc; + + bool m_isConstructor; + bool m_isConstructorCalled; + sClassDeclaration *m_classDecl; + sGlobalVariableDescription *m_globalVar; + + asCArray breakLabels; + asCArray continueLabels; + + int AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap = false, bool asReference = false); + int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx); + int GetVariableOffset(int varIndex); + int GetVariableSlot(int varOffset); + void DeallocateVariable(int pos); + void ReleaseTemporaryVariable(asCExprValue &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; + + // This array holds the string constants that were allocated during the compilation, + // so they can be released upon completion, whether the compilation was successful or not. + asCArray usedStringConstants; + + // This array holds the nodes that have been allocated temporarily + asCArray nodesToFreeUponComplete; + + bool isCompilingDefaultArg; + bool isProcessingDeferredParams; + int noCodeOutput; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_config.h b/src/angelscript/source/as_config.h index 8af33a2112f..3515625dfc5 100644 --- a/src/angelscript/source/as_config.h +++ b/src/angelscript/source/as_config.h @@ -168,7 +168,7 @@ // GNU C based compilers // __GNUC__ is defined -// CLang/LLVM +// CLang/LLVM // __clang__ is defined // Embarcadero C++Builder @@ -391,847 +391,847 @@ #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 + #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 | asOBJ_APP_CLASS_MORE_CONSTRUCTORS) - #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) - - // Windows CE uses softfp calling convention, while Windows RT uses hardfp calling convention - // ref: http://stackoverflow.com/questions/16375355/what-is-the-windows-rt-on-arm-native-code-calling-convention - #if defined(_WIN32_WCE) - #define AS_SOFTFP - #endif - #endif - - #if defined(_M_ARM64) - #define AS_ARM64 - - // TODO: MORE HERE - #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 | asOBJ_APP_CLASS_MORE_CONSTRUCTORS) - #endif - - #define UNREACHABLE_RETURN + #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 | asOBJ_APP_CLASS_MORE_CONSTRUCTORS) + #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) + + // Windows CE uses softfp calling convention, while Windows RT uses hardfp calling convention + // ref: http://stackoverflow.com/questions/16375355/what-is-the-windows-rt-on-arm-native-code-calling-convention + #if defined(_WIN32_WCE) + #define AS_SOFTFP + #endif + #endif + + #if defined(_M_ARM64) + #define AS_ARM64 + + // TODO: MORE HERE + #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 | asOBJ_APP_CLASS_MORE_CONSTRUCTORS) + #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 + #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 MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) - #define CALLEE_POPS_HIDDEN_RETURN_POINTER - #define COMPLEX_OBJS_PASSED_BY_REF - - #ifdef __psp2__ - #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR) - #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR) - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #else - #define GNU_STYLE_VIRTUAL_METHOD - #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) - #endif - - #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 - #define AS_NO_MEMORY_H - #define AS_NO_EXCEPTIONS - #include - // PSP - #elif defined(__psp__) - #define AS_NO_MEMORY_H - #define AS_MIPS - #define AS_PSP - #define AS_USE_DOUBLE_AS_FLOAT - // PSVita - #elif defined(__psp2__) - #define AS_PSVITA - #define AS_ARM - #define AS_NO_MEMORY_H - #define AS_NO_EXCEPTIONS - #define AS_CALLEE_DESTROY_OBJ_BY_VAL - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #endif - - #define UNREACHABLE_RETURN + #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) + #define CALLEE_POPS_HIDDEN_RETURN_POINTER + #define COMPLEX_OBJS_PASSED_BY_REF + + #ifdef __psp2__ + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR) + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR) + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #else + #define GNU_STYLE_VIRTUAL_METHOD + #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) + #endif + + #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 + #define AS_NO_MEMORY_H + #define AS_NO_EXCEPTIONS + #include + // PSP + #elif defined(__psp__) + #define AS_NO_MEMORY_H + #define AS_MIPS + #define AS_PSP + #define AS_USE_DOUBLE_AS_FLOAT + // PSVita + #elif defined(__psp2__) + #define AS_PSVITA + #define AS_ARM + #define AS_NO_MEMORY_H + #define AS_NO_EXCEPTIONS + #define AS_CALLEE_DESTROY_OBJ_BY_VAL + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #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 - // MSVC2015 can now use CLang too, but it shouldn't go in here #if (defined(__GNUC__) && !defined(__SNC__) && !defined(_MSC_VER)) || defined(EPPC) || defined(__CYGWIN__) // JWC -- use this instead for Wii - #define GNU_STYLE_VIRTUAL_METHOD - #define MULTI_BASE_OFFSET(x) (*((asPWORD*)(&x)+1)) - #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) - #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 - #define AS_MINGW47 - #endif - - #if (__clang_major__ == 3 && __clang_minor__ > 4) || __clang_major > 3 - #define AS_MINGW47 - #endif - - #ifdef AS_MINGW47 - #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__) - // x86 32bit - #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(__x86_64__) - // x86 64bit - #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__) || defined(__aarch64__) || defined(__AARCH64EL__) - // arm - - // The assembler code currently doesn't support arm v4 - #if !defined(__ARM_ARCH_4__) && !defined(__ARM_ARCH_4T__) && !defined(__LP64__) - #define AS_ARM - - // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S - #define AS_NO_EXCEPTIONS - - #undef 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) || defined(__ARM_PCS) - // -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(__LP64__) || defined(__aarch64__) - #define AS_ARM64 - - #undef STDCALL - #define STDCALL - - #undef GNU_STYLE_VIRTUAL_METHOD - #undef AS_NO_THISCALL_FUNCTOR_METHOD - - #define HAS_128_BIT_PRIMITIVES - - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - - #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 - #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 - #endif - - #elif defined(__mips__) - // mips - #define AS_MIPS - #undef STDCALL - #define STDCALL - - #ifdef _ABIO32 - // 32bit O32 ABI - #define AS_MIPS - - // All structures are returned in memory regardless of size or complexity - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #else - // For other ABIs the native calling convention is not available (yet) - #define AS_MAX_PORTABILITY - #endif - #elif defined(__PPC64__) - // PPC 64bit - - // The code in as_callfunc_ppc_64.cpp was built for PS3 and XBox 360, that - // although use 64bit PPC only uses 32bit pointers. - // TODO: Add support for native calling conventions on Linux with PPC 64bit - #define AS_MAX_PORTABILITY - #elif defined(__e2k__) - // 64bit MCST Elbrus 2000 - // ref: https://en.wikipedia.org/wiki/Elbrus_2000 - #define AS_E2K - // AngelScript currently doesn't support native calling - // for MCST Elbrus 2000 processor so it's necessary to turn on - // portability mode - #define AS_MAX_PORTABILITY - // STDCALL is not available on 64bit Linux - #undef STDCALL - #define STDCALL - #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(__x86_64__) - #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 - #define AS_USE_DOUBLE_AS_FLOAT - #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 - - // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S - #define AS_NO_EXCEPTIONS - - #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #undef 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 - #elif defined(__mips__) - #define AS_MIPS - #undef STDCALL - #define STDCALL - - #ifdef _ABIO32 - #define AS_MIPS - - // All structures are returned in memory regardless of size or complexity - #define THISCALL_RETURN_SIMPLE_IN_MEMORY - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 - #define CDECL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 - #define STDCALL_RETURN_SIMPLE_IN_MEMORY - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 - #undef AS_NO_THISCALL_FUNCTOR_METHOD - #else - // For other ABIs the native calling convention is not available (yet) - #define AS_MAX_PORTABILITY - #endif - #endif - - // Haiku OS - #elif __HAIKU__ - #define AS_HAIKU - #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 - #elif defined(__x86_64__) - #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 - - // 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(__x86_64__) - #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 + #define GNU_STYLE_VIRTUAL_METHOD + #define MULTI_BASE_OFFSET(x) (*((asPWORD*)(&x)+1)) + #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 + #define AS_MINGW47 + #endif + + #if (__clang_major__ == 3 && __clang_minor__ > 4) || __clang_major > 3 + #define AS_MINGW47 + #endif + + #ifdef AS_MINGW47 + #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__) + // x86 32bit + #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(__x86_64__) + // x86 64bit + #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__) || defined(__aarch64__) || defined(__AARCH64EL__) + // arm + + // The assembler code currently doesn't support arm v4 + #if !defined(__ARM_ARCH_4__) && !defined(__ARM_ARCH_4T__) && !defined(__LP64__) + #define AS_ARM + + // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S + #define AS_NO_EXCEPTIONS + + #undef 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) || defined(__ARM_PCS) + // -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(__LP64__) || defined(__aarch64__) + #define AS_ARM64 + + #undef STDCALL + #define STDCALL + + #undef GNU_STYLE_VIRTUAL_METHOD + #undef AS_NO_THISCALL_FUNCTOR_METHOD + + #define HAS_128_BIT_PRIMITIVES + + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #endif + + #elif defined(__mips__) + // mips + #define AS_MIPS + #undef STDCALL + #define STDCALL + + #ifdef _ABIO32 + // 32bit O32 ABI + #define AS_MIPS + + // All structures are returned in memory regardless of size or complexity + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #else + // For other ABIs the native calling convention is not available (yet) + #define AS_MAX_PORTABILITY + #endif + #elif defined(__PPC64__) + // PPC 64bit + + // The code in as_callfunc_ppc_64.cpp was built for PS3 and XBox 360, that + // although use 64bit PPC only uses 32bit pointers. + // TODO: Add support for native calling conventions on Linux with PPC 64bit + #define AS_MAX_PORTABILITY + #elif defined(__e2k__) + // 64bit MCST Elbrus 2000 + // ref: https://en.wikipedia.org/wiki/Elbrus_2000 + #define AS_E2K + // AngelScript currently doesn't support native calling + // for MCST Elbrus 2000 processor so it's necessary to turn on + // portability mode + #define AS_MAX_PORTABILITY + // STDCALL is not available on 64bit Linux + #undef STDCALL + #define STDCALL + #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(__x86_64__) + #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 + #define AS_USE_DOUBLE_AS_FLOAT + #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 + + // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S + #define AS_NO_EXCEPTIONS + + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef 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 + #elif defined(__mips__) + #define AS_MIPS + #undef STDCALL + #define STDCALL + + #ifdef _ABIO32 + #define AS_MIPS + + // All structures are returned in memory regardless of size or complexity + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #else + // For other ABIs the native calling convention is not available (yet) + #define AS_MAX_PORTABILITY + #endif + #endif + + // Haiku OS + #elif __HAIKU__ + #define AS_HAIKU + #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 + #elif defined(__x86_64__) + #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 + + // 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(__x86_64__) + #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 + #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 @@ -1242,60 +1242,60 @@ // Big endian CPU target? // see: http://sourceforge.net/p/predef/wiki/Endianness/ #if !defined(AS_BIG_ENDIAN) && \ - defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ - defined(__BIG_ENDIAN__) || \ - defined(__ARMEB__) || \ - defined(__THUMBEB__) || \ - defined(__AARCH64EB__) || \ - defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) - #define AS_BIG_ENDIAN + defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ + defined(__BIG_ENDIAN__) || \ + defined(__ARMEB__) || \ + defined(__THUMBEB__) || \ + defined(__AARCH64EB__) || \ + defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) + #define AS_BIG_ENDIAN #endif // Dreamcast and Gamecube use only 32bit floats, so treat doubles as floats #if defined(__SH4_SINGLE_ONLY__) || defined(_GC) - #define AS_USE_DOUBLE_AS_FLOAT // use 32bit floats instead of doubles + #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_ARM64) && !defined(AS_X64_MINGW)) - #ifndef AS_MAX_PORTABILITY - #define AS_MAX_PORTABILITY - #endif + #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 + #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 + #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 + #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) + #include + #define asASSERT(x) assert(x) #endif diff --git a/src/angelscript/source/as_configgroup.cpp b/src/angelscript/source/as_configgroup.cpp index a29bc933676..014bc2b822e 100644 --- a/src/angelscript/source/as_configgroup.cpp +++ b/src/angelscript/source/as_configgroup.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2020 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -46,7 +46,7 @@ BEGIN_AS_NAMESPACE asCConfigGroup::asCConfigGroup() { - refCount = 0; + refCount = 0; } asCConfigGroup::~asCConfigGroup() @@ -55,155 +55,155 @@ asCConfigGroup::~asCConfigGroup() int asCConfigGroup::AddRef() { - refCount++; - return refCount; + refCount++; + return refCount; } int asCConfigGroup::Release() { - // Don't delete the object here, the engine will delete the object when ready - refCount--; - return refCount; + // Don't delete the object here, the engine will delete the object when ready + refCount--; + return refCount; } asCTypeInfo *asCConfigGroup::FindType(const char *obj) { - for( asUINT n = 0; n < types.GetLength(); n++ ) - if( types[n]->name == obj ) - return types[n]; + for( asUINT n = 0; n < types.GetLength(); n++ ) + if( types[n]->name == obj ) + return types[n]; - return 0; + return 0; } void asCConfigGroup::RefConfigGroup(asCConfigGroup *group) { - if( group == this || group == 0 ) return; + 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; + // 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(); + referencedConfigGroups.PushLast(group); + group->AddRef(); } void asCConfigGroup::AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func) { - AddReferencesForType(engine, func->returnType.GetTypeInfo()); - for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) - AddReferencesForType(engine, func->parameterTypes[n].GetTypeInfo()); + AddReferencesForType(engine, func->returnType.GetTypeInfo()); + for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) + AddReferencesForType(engine, func->parameterTypes[n].GetTypeInfo()); } void asCConfigGroup::AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type) { - if( type == 0 ) return; + if( type == 0 ) return; - // Keep reference to other groups - RefConfigGroup(engine->FindConfigGroupForTypeInfo(type)); + // Keep reference to other groups + RefConfigGroup(engine->FindConfigGroupForTypeInfo(type)); - // Keep track of which generated template instances the config group uses - if( type->flags & asOBJ_TEMPLATE && engine->generatedTemplateTypes.Exists(CastToObjectType(type)) && !generatedTemplateInstances.Exists(CastToObjectType(type)) ) - generatedTemplateInstances.PushLast(CastToObjectType(type)); + // Keep track of which generated template instances the config group uses + if( type->flags & asOBJ_TEMPLATE && engine->generatedTemplateTypes.Exists(CastToObjectType(type)) && !generatedTemplateInstances.Exists(CastToObjectType(type)) ) + generatedTemplateInstances.PushLast(CastToObjectType(type)); } bool asCConfigGroup::HasLiveObjects() { - for( asUINT n = 0; n < types.GetLength(); n++ ) - if( types[n]->externalRefCount.get() != 0 ) - return true; + for( asUINT n = 0; n < types.GetLength(); n++ ) + if( types[n]->externalRefCount.get() != 0 ) + return true; - return false; + 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(); - - 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]->ReleaseInternal(); - } - scriptFunctions.SetLength(0); - - // Remove behaviours and members of object types - for( n = 0; n < types.GetLength(); n++ ) - { - asCObjectType *obj = CastToObjectType(types[n]); - if( obj ) - obj->ReleaseAllFunctions(); - } - - // Remove object types (skip this if it is possible other groups are still using the types) - if( !notUsed ) - { - for( n = asUINT(types.GetLength()); n-- > 0; ) - { - asCTypeInfo *t = types[n]; - asSMapNode *cursor; - if( engine->allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(t->nameSpace, t->name)) && - cursor->value == t ) - { - engine->allRegisteredTypes.Erase(cursor); - - if( engine->defaultArrayObjectType == t ) - engine->defaultArrayObjectType = 0; - - if( t->flags & asOBJ_TYPEDEF ) - engine->registeredTypeDefs.RemoveValue(CastToTypedefType(t)); - else if( t->flags & asOBJ_ENUM ) - engine->registeredEnums.RemoveValue(CastToEnumType(t)); - else if (t->flags & asOBJ_TEMPLATE) - engine->registeredTemplateTypes.RemoveValue(CastToObjectType(t)); - else if (t->flags & asOBJ_FUNCDEF) - { - engine->registeredFuncDefs.RemoveValue(CastToFuncdefType(t)); - engine->RemoveFuncdef(CastToFuncdefType(t)); - } - else - engine->registeredObjTypes.RemoveValue(CastToObjectType(t)); - - t->DestroyInternal(); - t->ReleaseInternal(); - } - else - { - int idx = engine->templateInstanceTypes.IndexOf(CastToObjectType(t)); - if( idx >= 0 ) - { - engine->templateInstanceTypes.RemoveIndexUnordered(idx); - asCObjectType *ot = CastToObjectType(t); - ot->DestroyInternal(); - ot->ReleaseInternal(); - } - } - } - types.SetLength(0); - } - - // Release other config groups - for( n = 0; n < referencedConfigGroups.GetLength(); n++ ) - referencedConfigGroups[n]->refCount--; - referencedConfigGroups.SetLength(0); + 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(); + + 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]->ReleaseInternal(); + } + scriptFunctions.SetLength(0); + + // Remove behaviours and members of object types + for( n = 0; n < types.GetLength(); n++ ) + { + asCObjectType *obj = CastToObjectType(types[n]); + if( obj ) + obj->ReleaseAllFunctions(); + } + + // Remove object types (skip this if it is possible other groups are still using the types) + if( !notUsed ) + { + for( n = asUINT(types.GetLength()); n-- > 0; ) + { + asCTypeInfo *t = types[n]; + asSMapNode *cursor; + if( engine->allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(t->nameSpace, t->name)) && + cursor->value == t ) + { + engine->allRegisteredTypes.Erase(cursor); + + if( engine->defaultArrayObjectType == t ) + engine->defaultArrayObjectType = 0; + + if( t->flags & asOBJ_TYPEDEF ) + engine->registeredTypeDefs.RemoveValue(CastToTypedefType(t)); + else if( t->flags & asOBJ_ENUM ) + engine->registeredEnums.RemoveValue(CastToEnumType(t)); + else if (t->flags & asOBJ_TEMPLATE) + engine->registeredTemplateTypes.RemoveValue(CastToObjectType(t)); + else if (t->flags & asOBJ_FUNCDEF) + { + engine->registeredFuncDefs.RemoveValue(CastToFuncdefType(t)); + engine->RemoveFuncdef(CastToFuncdefType(t)); + } + else + engine->registeredObjTypes.RemoveValue(CastToObjectType(t)); + + t->DestroyInternal(); + t->ReleaseInternal(); + } + else + { + int idx = engine->templateInstanceTypes.IndexOf(CastToObjectType(t)); + if( idx >= 0 ) + { + engine->templateInstanceTypes.RemoveIndexUnordered(idx); + asCObjectType *ot = CastToObjectType(t); + ot->DestroyInternal(); + ot->ReleaseInternal(); + } + } + } + types.SetLength(0); + } + + // Release other config groups + for( n = 0; n < referencedConfigGroups.GetLength(); n++ ) + referencedConfigGroups[n]->refCount--; + referencedConfigGroups.SetLength(0); } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_configgroup.h b/src/angelscript/source/as_configgroup.h index 48720301e8a..619a0689489 100644 --- a/src/angelscript/source/as_configgroup.h +++ b/src/angelscript/source/as_configgroup.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2015 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -50,33 +50,33 @@ BEGIN_AS_NAMESPACE class asCConfigGroup { public: - asCConfigGroup(); - ~asCConfigGroup(); + asCConfigGroup(); + ~asCConfigGroup(); - // Memory management - int AddRef(); - int Release(); + // Memory management + int AddRef(); + int Release(); - asCTypeInfo *FindType(const char *name); - void RefConfigGroup(asCConfigGroup *group); + asCTypeInfo *FindType(const char *name); + void RefConfigGroup(asCConfigGroup *group); - bool HasLiveObjects(); - void RemoveConfiguration(asCScriptEngine *engine, bool notUsed = false); + bool HasLiveObjects(); + void RemoveConfiguration(asCScriptEngine *engine, bool notUsed = false); - void AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func); - void AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type); + void AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func); + void AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type); - asCString groupName; - int refCount; + asCString groupName; + int refCount; - asCArray types; - asCArray scriptFunctions; - asCArray globalProps; - asCArray referencedConfigGroups; + asCArray types; + asCArray scriptFunctions; + asCArray globalProps; + asCArray referencedConfigGroups; - // This array holds the generated template instances that are used - // by the config group as part of function signature or property - asCArray generatedTemplateInstances; + // This array holds the generated template instances that are used + // by the config group as part of function signature or property + asCArray generatedTemplateInstances; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_context.cpp b/src/angelscript/source/as_context.cpp index d578c3f8998..c52f9b4cc07 100644 --- a/src/angelscript/source/as_context.cpp +++ b/src/angelscript/source/as_context.cpp @@ -66,73 +66,73 @@ const int CALLSTACK_FRAME_SIZE = 9; 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. + 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. #ifndef __MINGW32__ - // _mkdir is broken on mingw - _mkdir("AS_DEBUG"); + // _mkdir is broken on mingw + _mkdir("AS_DEBUG"); #endif - #if _MSC_VER >= 1500 && !defined(AS_MARMALADE) - FILE *f; - fopen_s(&f, "AS_DEBUG/stats.txt", "wt"); - #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; + #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 @@ -140,1000 +140,1000 @@ class asCDebugStats // interface AS_API asIScriptContext *asGetActiveContext() { - asCThreadLocalData *tld = asCThreadManager::GetLocalData(); + asCThreadLocalData *tld = asCThreadManager::GetLocalData(); - // tld can be 0 if asGetActiveContext is called before any engine has been created. + // tld can be 0 if asGetActiveContext is called before any engine has been created. - // Observe! I've seen a case where an application linked with the library twice - // and thus ended up with two separate instances of the code and global variables. - // The application somehow mixed the two instances so that a function called from - // a script ended up calling asGetActiveContext from the other instance that had - // never been initialized. + // Observe! I've seen a case where an application linked with the library twice + // and thus ended up with two separate instances of the code and global variables. + // The application somehow mixed the two instances so that a function called from + // a script ended up calling asGetActiveContext from the other instance that had + // never been initialized. - if( tld == 0 || tld->activeContexts.GetLength() == 0 ) - return 0; - return tld->activeContexts[tld->activeContexts.GetLength()-1]; + if( tld == 0 || tld->activeContexts.GetLength() == 0 ) + return 0; + return tld->activeContexts[tld->activeContexts.GetLength()-1]; } // internal asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx) { - asCThreadLocalData *tld = asCThreadManager::GetLocalData(); - asASSERT( tld ); - if( tld == 0 ) - return 0; - tld->activeContexts.PushLast(ctx); - return tld; + asCThreadLocalData *tld = asCThreadManager::GetLocalData(); + asASSERT( tld ); + if( tld == 0 ) + return 0; + tld->activeContexts.PushLast(ctx); + return tld; } // internal void asPopActiveContext(asCThreadLocalData *tld, asIScriptContext *ctx) { - UNUSED_VAR(ctx); - asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength() - 1] == ctx); - if (tld) - tld->activeContexts.PopLast(); + UNUSED_VAR(ctx); + asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength() - 1] == ctx); + if (tld) + tld->activeContexts.PopLast(); } asCContext::asCContext(asCScriptEngine *engine, bool holdRef) { - m_refCount.set(1); - - 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; - m_exceptionWillBeCaught = false; + 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; + m_exceptionWillBeCaught = false; } asCContext::~asCContext() { - DetachEngine(); + 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; + 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(); + return m_refCount.atomicInc(); } // interface int asCContext::Release() const { - int r = m_refCount.atomicDec(); + int r = m_refCount.atomicDec(); - if( r == 0 ) - { - asDELETE(const_cast(this),asCContext); - return 0; - } + if( r == 0 ) + { + asDELETE(const_cast(this),asCContext); + return 0; + } - return r; + 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] ) - { + 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]); + asDELETEARRAY(m_stackBlocks[n]); #else - asDELETEARRAYALIGNED(m_stackBlocks[n]); + 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; + } + } + 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; + 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); + // 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); + // 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); + RELEASEEXCLUSIVE(m_engine->engineRWLock); - return oldData; - } - } + return oldData; + } + } - m_userData.PushLast(type); - m_userData.PushLast(reinterpret_cast(data)); + m_userData.PushLast(type); + m_userData.PushLast(reinterpret_cast(data)); - RELEASEEXCLUSIVE(m_engine->engineRWLock); + RELEASEEXCLUSIVE(m_engine->engineRWLock); - return 0; + 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; + // 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; + return m_callingSystemFunction; } // interface int asCContext::Prepare(asIScriptFunction *func) { - if( func == 0 ) - { - asCString str; - str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, "Prepare", "null", errorNames[-asNO_FUNCTION], 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_s_d, "Prepare", func->GetDeclaration(true, true), errorNames[-asCONTEXT_ACTIVE], 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_s_d, "Prepare", func->GetDeclaration(true, true), errorNames[-asINVALID_ARG], 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; - - // Set up the call stack too - if (m_callStack.GetCapacity() < m_engine->ep.initCallStackSize) - m_callStack.AllocateNoConstruct(m_engine->ep.initCallStackSize * CALLSTACK_FRAME_SIZE, true); - } - - // Reset state - // 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; + if( func == 0 ) + { + asCString str; + str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, "Prepare", "null", errorNames[-asNO_FUNCTION], 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_s_d, "Prepare", func->GetDeclaration(true, true), errorNames[-asCONTEXT_ACTIVE], 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_s_d, "Prepare", func->GetDeclaration(true, true), errorNames[-asINVALID_ARG], 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; + + // Set up the call stack too + if (m_callStack.GetCapacity() < m_engine->ep.initCallStackSize) + m_callStack.AllocateNoConstruct(m_engine->ep.initCallStackSize * CALLSTACK_FRAME_SIZE, true); + } + + // Reset state + // 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; - - // Set the context as active so that any clean up code can use access it if desired - asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this); - asDWORD count = m_refCount.get(); - UNUSED_VAR(count); - - // Only clean the stack if the context was prepared but not executed until the end - if( m_status != asEXECUTION_UNINITIALIZED && - m_status != asEXECUTION_FINISHED ) - CleanStack(); - - asASSERT( m_needToCleanupArgs == false ); - - // Release the returned object (if any) - CleanReturnObject(); - - // TODO: Unprepare is called during destruction, so nobody - // must be allowed to keep an extra reference - asASSERT(m_refCount.get() == count); - asPopActiveContext(tld, this); - - // Release the object if it is a script object - if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) - { - 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; + if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED ) + return asCONTEXT_ACTIVE; + + // Set the context as active so that any clean up code can use access it if desired + asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this); + asDWORD count = m_refCount.get(); + UNUSED_VAR(count); + + // Only clean the stack if the context was prepared but not executed until the end + if( m_status != asEXECUTION_UNINITIALIZED && + m_status != asEXECUTION_FINISHED ) + CleanStack(); + + asASSERT( m_needToCleanupArgs == false ); + + // Release the returned object (if any) + CleanReturnObject(); + + // TODO: Unprepare is called during destruction, so nobody + // must be allowed to keep an extra reference + asASSERT(m_refCount.get() == count); + asPopActiveContext(tld, this); + + // Release the object if it is a script object + if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) + { + 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; + if( m_status != asEXECUTION_FINISHED ) return 0; - asCDataType *dt = &m_initialFunction->returnType; + asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; - return *(asBYTE*)&m_regs.valueRegister; + return *(asBYTE*)&m_regs.valueRegister; } asWORD asCContext::GetReturnWord() { - if( m_status != asEXECUTION_FINISHED ) return 0; + if( m_status != asEXECUTION_FINISHED ) return 0; - asCDataType *dt = &m_initialFunction->returnType; + asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; - return *(asWORD*)&m_regs.valueRegister; + return *(asWORD*)&m_regs.valueRegister; } asDWORD asCContext::GetReturnDWord() { - if( m_status != asEXECUTION_FINISHED ) return 0; + if( m_status != asEXECUTION_FINISHED ) return 0; - asCDataType *dt = &m_initialFunction->returnType; + asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; - return *(asDWORD*)&m_regs.valueRegister; + return *(asDWORD*)&m_regs.valueRegister; } asQWORD asCContext::GetReturnQWord() { - if( m_status != asEXECUTION_FINISHED ) return 0; + if( m_status != asEXECUTION_FINISHED ) return 0; - asCDataType *dt = &m_initialFunction->returnType; + asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; - return m_regs.valueRegister; + return m_regs.valueRegister; } float asCContext::GetReturnFloat() { - if( m_status != asEXECUTION_FINISHED ) return 0; + if( m_status != asEXECUTION_FINISHED ) return 0; - asCDataType *dt = &m_initialFunction->returnType; + asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; - return *(float*)&m_regs.valueRegister; + return *(float*)&m_regs.valueRegister; } double asCContext::GetReturnDouble() { - if( m_status != asEXECUTION_FINISHED ) return 0; + if( m_status != asEXECUTION_FINISHED ) return 0; - asCDataType *dt = &m_initialFunction->returnType; + asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; - return *(double*)&m_regs.valueRegister; + return *(double*)&m_regs.valueRegister; } void *asCContext::GetReturnAddress() { - if( m_status != asEXECUTION_FINISHED ) return 0; + if( m_status != asEXECUTION_FINISHED ) return 0; - asCDataType *dt = &m_initialFunction->returnType; + asCDataType *dt = &m_initialFunction->returnType; - if( dt->IsReference() ) - return *(void**)&m_regs.valueRegister; - else if( dt->IsObject() || dt->IsFuncdef() ) - { - 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; + if( dt->IsReference() ) + return *(void**)&m_regs.valueRegister; + else if( dt->IsObject() || dt->IsFuncdef() ) + { + 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.stackFramePointer[offset]); + } - return m_regs.objectRegister; - } + return m_regs.objectRegister; + } - return 0; + return 0; } void *asCContext::GetReturnObject() { - if( m_status != asEXECUTION_FINISHED ) return 0; + if( m_status != asEXECUTION_FINISHED ) return 0; - asCDataType *dt = &m_initialFunction->returnType; + asCDataType *dt = &m_initialFunction->returnType; - if( !dt->IsObject() && !dt->IsFuncdef() ) return 0; + if( !dt->IsObject() && !dt->IsFuncdef() ) 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; + 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 *(void**)(&m_regs.stackFramePointer[offset]); + } - return m_regs.objectRegister; - } + 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() || dt->IsFuncdef()) ) - { - // 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; + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + // An object is stored in the objectRegister + if( !dt->IsReference() && (dt->IsObject() || dt->IsFuncdef()) ) + { + // 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_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; - if( !m_initialFunction->objectType ) - { - m_status = asEXECUTION_ERROR; - return asERROR; - } + if( !m_initialFunction->objectType ) + { + m_status = asEXECUTION_ERROR; + return asERROR; + } - asASSERT( *(asPWORD*)&m_regs.stackFramePointer[0] == 0 ); + asASSERT( *(asPWORD*)&m_regs.stackFramePointer[0] == 0 ); - *(asPWORD*)&m_regs.stackFramePointer[0] = (asPWORD)obj; + *(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(); + // 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; + 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->IsFuncdef() || 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; + 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->IsFuncdef() || 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->IsFuncdef() || 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; + 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->IsFuncdef() || 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->IsFuncdef() || 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; + 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->IsFuncdef() || 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->IsFuncdef() || 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; + 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->IsFuncdef() || 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->IsFuncdef() || 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; + 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->IsFuncdef() || 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->IsFuncdef() || 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; + 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->IsFuncdef() || 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; + 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() && !dt->IsFuncdef() ) - { - 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 - if (obj && dt->IsFuncdef()) - ((asIScriptFunction*)obj)->AddRef(); - else - { - asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh; - if (obj && beh->addref) - m_engine->CallObjectMethod(obj, beh->addref); - } - } - else - { - obj = m_engine->CreateScriptObjectCopy(obj, dt->GetTypeInfo()); - } - } - - // 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; + 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->IsFuncdef() ) + { + 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 + if (obj && dt->IsFuncdef()) + ((asIScriptFunction*)obj)->AddRef(); + else + { + asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh; + if (obj && beh->addref) + m_engine->CallObjectMethod(obj, beh->addref); + } + } + else + { + obj = m_engine->CreateScriptObjectCopy(obj, dt->GetTypeInfo()); + } + } + + // 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; } int asCContext::SetArgVarType(asUINT arg, void *ptr, int typeId) { - 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->GetTokenType() != ttQuestion ) - { - 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 typeId and pointer - *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)ptr; - offset += AS_PTR_SIZE; - *(int*)(&m_regs.stackFramePointer[offset]) = typeId; - - return 0; + 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->GetTokenType() != ttQuestion ) + { + 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 typeId and pointer + *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)ptr; + offset += AS_PTR_SIZE; + *(int*)(&m_regs.stackFramePointer[offset]) = typeId; + + return 0; } // TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead. @@ -1141,372 +1141,372 @@ int asCContext::SetArgVarType(asUINT arg, void *ptr, int typeId) // interface void *asCContext::GetAddressOfArg(asUINT arg) { - if( m_status != asEXECUTION_PREPARED ) - return 0; + if( m_status != asEXECUTION_PREPARED ) + return 0; - if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) - 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; + // 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; + // 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(); + 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 + // 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]; + // 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; + 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; + // 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; + m_doSuspend = true; + m_regs.doProcessSuspend = true; + m_externalSuspendRequest = true; + m_doAbort = true; - return 0; + 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. + // 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; + if( m_engine == 0 ) return asERROR; - m_doSuspend = true; - m_externalSuspendRequest = true; - m_regs.doProcessSuspend = true; + m_doSuspend = true; + m_externalSuspendRequest = true; + m_regs.doProcessSuspend = true; - return 0; + 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_s_d, "Execute", errorNames[-asCONTEXT_NOT_PREPARED], 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); - - // Make sure there are not too many nested calls, as it could crash the application - // by filling up the thread call stack - if (tld->activeContexts.GetLength() > m_engine->ep.maxNestedCalls) - SetInternalException(TXT_TOO_MANY_NESTED_CALLS); - else if( m_regs.programPointer == 0 ) - { - if( m_currentFunction->funcType == asFUNC_DELEGATE ) - { - // 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); - - // 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 an exception was raised that will be caught, then unwind the stack - // and move the program pointer to the catch block before proceeding - if (m_status == asEXECUTION_EXCEPTION && m_exceptionWillBeCaught) - CleanStack(true); - } - - if( m_lineCallback ) - { - // Call the line callback one last time before leaving - // 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 - asPopActiveContext(tld, this); - - if( m_status == asEXECUTION_FINISHED ) - { - m_regs.objectType = m_initialFunction->returnType.GetTypeInfo(); - 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; + asASSERT( m_engine != 0 ); + + if( m_status != asEXECUTION_SUSPENDED && m_status != asEXECUTION_PREPARED ) + { + asCString str; + str.Format(TXT_FAILED_IN_FUNC_s_s_d, "Execute", errorNames[-asCONTEXT_NOT_PREPARED], 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); + + // Make sure there are not too many nested calls, as it could crash the application + // by filling up the thread call stack + if (tld->activeContexts.GetLength() > m_engine->ep.maxNestedCalls) + SetInternalException(TXT_TOO_MANY_NESTED_CALLS); + else if( m_regs.programPointer == 0 ) + { + if( m_currentFunction->funcType == asFUNC_DELEGATE ) + { + // 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); + + // 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 an exception was raised that will be caught, then unwind the stack + // and move the program pointer to the catch block before proceeding + if (m_status == asEXECUTION_EXCEPTION && m_exceptionWillBeCaught) + CleanStack(true); + } + + if( m_lineCallback ) + { + // Call the line callback one last time before leaving + // 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 + asPopActiveContext(tld, this); + + if( m_status == asEXECUTION_FINISHED ) + { + m_regs.objectType = m_initialFunction->returnType.GetTypeInfo(); + 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; - } - - // Allocate space on the callstack for at least two states - if (m_callStack.GetLength() >= m_callStack.GetCapacity() - 2*CALLSTACK_FRAME_SIZE) - { - if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE) - { - // The call stack is too big to grow further - // If an error occurs, no change to the context should be done - return asOUT_OF_MEMORY; - } - - // Allocate space for 10 call states at a time to save time - m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10 * CALLSTACK_FRAME_SIZE, true); - } - - // Push the current script function that is calling the system function - // This cannot fail, since the memory was already allocated above - PushCallState(); - - // Push the system function too, which will serve both as a marker and - // informing which system function that created the nested call - 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; + // 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; + } + + // Allocate space on the callstack for at least two states + if (m_callStack.GetLength() >= m_callStack.GetCapacity() - 2*CALLSTACK_FRAME_SIZE) + { + if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE) + { + // The call stack is too big to grow further + // If an error occurs, no change to the context should be done + return asOUT_OF_MEMORY; + } + + // Allocate space for 10 call states at a time to save time + m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10 * CALLSTACK_FRAME_SIZE, true); + } + + // Push the current script function that is calling the system function + // This cannot fail, since the memory was already allocated above + PushCallState(); + + // Push the system function too, which will serve both as a marker and + // informing which system function that created the nested call + 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; + if( !IsNested() ) + return asERROR; - // Clean up the current execution - Unprepare(); + // 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 ); + // 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 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]; + // 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 = (asITypeInfo*)tmp[8]; + m_regs.valueRegister = asQWORD(asDWORD(tmp[5])); + m_regs.valueRegister |= asQWORD(tmp[6])<<32; + m_regs.objectRegister = (void*)tmp[7]; + m_regs.objectType = (asITypeInfo*)tmp[8]; - // Calculate the returnValueSize - if( m_initialFunction->DoesReturnOnStack() ) - m_returnValueSize = m_initialFunction->returnType.GetSizeInMemoryDWords(); - else - m_returnValueSize = 0; + // 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(); + // Pop the current script function. This will also restore the previous stack pointer + PopCallState(); - m_status = asEXECUTION_ACTIVE; + m_status = asEXECUTION_ACTIVE; - return asSUCCESS; + return asSUCCESS; } int asCContext::PushCallState() { - if( m_callStack.GetLength() == m_callStack.GetCapacity() ) - { - if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE) - { - // The call stack is too big to grow further - SetInternalException(TXT_STACK_OVERFLOW); - return asERROR; - } - - // Allocate space for 10 call states at a time to save time - m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true); - } - m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE); + if( m_callStack.GetLength() == m_callStack.GetCapacity() ) + { + if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE) + { + // The call stack is too big to grow further + SetInternalException(TXT_STACK_OVERFLOW); + return asERROR; + } + + // Allocate space for 10 call states at a time to save time + m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true); + } + 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. @@ -1515,4054 +1515,4054 @@ int asCContext::PushCallState() // 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]; - - return asSUCCESS; + 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]; + + return asSUCCESS; } 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); + // 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; + if( m_currentFunction == 0 ) return 0; - // The current function is accessed at stackLevel 0 - return asUINT(1 + m_callStack.GetLength() / CALLSTACK_FRAME_SIZE); + // 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 >= GetCallstackSize() ) return 0; - if( stackLevel == 0 ) return m_currentFunction; + if( stackLevel == 0 ) return m_currentFunction; - asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize() - stackLevel - 1)*CALLSTACK_FRAME_SIZE; - asCScriptFunction *func = (asCScriptFunction*)s[1]; + asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize() - stackLevel - 1)*CALLSTACK_FRAME_SIZE; + asCScriptFunction *func = (asCScriptFunction*)s[1]; - return func; + 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); + 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)); - } + // 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->ep.initContextStackSize; - asASSERT( m_stackBlockSize > 0 ); + // Make sure the first stack block is allocated + if( m_stackBlocks.GetLength() == 0 ) + { + m_stackBlockSize = m_engine->ep.initContextStackSize; + asASSERT( m_stackBlockSize > 0 ); #ifndef WIP_16BYTE_ALIGN - asDWORD *stack = asNEWARRAY(asDWORD,m_stackBlockSize); + asDWORD *stack = asNEWARRAY(asDWORD,m_stackBlockSize); #else - asDWORD *stack = asNEWARRAYALIGNED(asDWORD, m_stackBlockSize, MAX_TYPE_ALIGNMENT); + asDWORD *stack = asNEWARRAYALIGNED(asDWORD, m_stackBlockSize, MAX_TYPE_ALIGNMENT); #endif - if( stack == 0 ) - { - // Out of memory - return false; - } + if( stack == 0 ) + { + // Out of memory + return false; + } #ifdef WIP_16BYTE_ALIGN - asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) ); + asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) ); #endif - m_stackBlocks.PushLast(stack); - m_stackIndex = 0; - m_regs.stackPointer = m_stackBlocks[0] + m_stackBlockSize; + 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); + // 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) ); + 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 is on or 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 + } + + // 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 is on or 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)); + asDWORD *stack = asNEWARRAY(asDWORD, (m_stackBlockSize << m_stackIndex)); #else - asDWORD *stack = asNEWARRAYALIGNED(asDWORD, (m_stackBlockSize << m_stackIndex), MAX_TYPE_ALIGNMENT); + asDWORD *stack = asNEWARRAYALIGNED(asDWORD, (m_stackBlockSize << m_stackIndex), MAX_TYPE_ALIGNMENT); #endif - if( stack == 0 ) - { - // Out of memory - m_isStackMemoryNotAllocated = true; + 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; + // Set the stackFramePointer, even though the stackPointer wasn't updated + m_regs.stackFramePointer = m_regs.stackPointer; - SetInternalException(TXT_STACK_OVERFLOW); - return false; - } + SetInternalException(TXT_STACK_OVERFLOW); + return false; + } #ifdef WIP_16BYTE_ALIGN - asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) ); + asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) ); #endif - m_stackBlocks.PushLast(stack); - } + 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); + // 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); + // Align the stack pointer + (asPWORD&)m_regs.stackPointer &= ~(MAX_TYPE_ALIGNMENT-1); - asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) ); + asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) ); #endif - } + } - return true; + return true; } // internal void asCContext::CallScriptFunction(asCScriptFunction *func) { - asASSERT( func->scriptData ); + asASSERT( func->scriptData ); - // Push the framepointer, function id and programCounter on the stack - if (PushCallState() < 0) - return; + // Push the framepointer, function id and programCounter on the stack + if (PushCallState() < 0) + return; - // Update the current function and program position before increasing the stack - // so the exception handler will know what to do if there is a stack overflow - m_currentFunction = func; - m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf(); + // 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(); + 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; - } + 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); + // 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; + asDWORD *l_bc = m_regs.programPointer; + asDWORD *l_sp = m_regs.stackPointer; + asDWORD *l_fp = m_regs.stackFramePointer; - for(;;) - { + for(;;) + { #ifdef AS_DEBUG - // Gather statistics on executed bytecode - stats.Instr(*(asBYTE*)l_bc); + // 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; + // 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 ) - { + // 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: + 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; - } + { + // 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); + *(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; + 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; + // 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; + // 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 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; - } + { + // 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); + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); #endif - l_bc++; - break; + 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 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; - } + { + // 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); + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); #endif - l_bc++; - break; + l_bc++; + break; - // If the value in the register is negative, then set the register to 1, else to 0 - case asBC_TS: + // 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; - } + { + // 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); + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? VALUE_OF_BOOLEAN_TRUE : 0); #endif - l_bc++; - break; + 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 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; - } + { + // 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); + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); #endif - l_bc++; - break; + 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 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; - } + { + // 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); + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? VALUE_OF_BOOLEAN_TRUE : 0); #endif - l_bc++; - break; + 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 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; - } + { + // 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); + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); #endif - l_bc++; - break; + 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 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 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; + // 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; + // 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: - // TODO: NEWSTRING: Deprecate this instruction - asASSERT(false); - 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); - - // 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); - - // 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); - - // 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 ) - { - // Push the object pointer on the stack (it will be popped by the function) - l_sp -= AS_PTR_SIZE; - *(asPWORD*)l_sp = (asPWORD)mem; - - // 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); - } - - // 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)); - asPWORD offset = *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 && beh->release ) - m_engine->CallObjectMethod(*d, beh->release); - // Increase ref counter of wanted object - if( s != 0 && beh->addref ) - 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: + // 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: + // TODO: NEWSTRING: Deprecate this instruction + asASSERT(false); + 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); + + // 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); + + // 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); + + // 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 ) + { + // Push the object pointer on the stack (it will be popped by the function) + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = (asPWORD)mem; + + // 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); + } + + // 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)); + asPWORD offset = *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 && beh->release ) + m_engine->CallObjectMethod(*d, beh->release); + // Increase ref counter of wanted object + if( s != 0 && beh->addref ) + 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 defined(_MSC_VER) && _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); - } + { + // 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))); + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc))); #endif - l_bc += 2; - break; + 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_i64TOd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc))); + l_bc++; + break; - case asBC_u64TOd: + case asBC_u64TOd: #if defined(_MSC_VER) && _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); - } + { + // 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))); + *(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: + 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 + { + // 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. + // 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; - } + 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 + // 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); - - // 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); - - // 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 && beh->release ) - m_engine->CallObjectMethod(*d, beh->release); - // Increase ref counter of wanted object - if( s != 0 && beh->addref ) - 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)); + 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); + + // 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); + + // 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 && beh->release ) + m_engine->CallObjectMethod(*d, beh->release); + // Increase ref counter of wanted object + if( s != 0 && beh->addref ) + 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); + *var = asNEWARRAY(asBYTE, size); #else - *var = asNEWARRAYALIGNED(asBYTE, size, MAX_TYPE_ALIGNMENT); + *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; - case asBC_Thiscall1: - // This instruction is a faster version of asBC_CALLSYS. It is faster because - // it has much less runtime overhead with determining the calling convention - // and no dynamic code for loading the parameters. The instruction can only - // be used to call functions with the following signatures: - // - // type &obj::func(int) - // type &obj::func(uint) - // void obj::func(int) - // void obj::func(uint) - { - // 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; - - // Pop the thispointer from the stack - void *obj = *(void**)l_sp; - if (obj == 0) - SetInternalException(TXT_NULL_POINTER_ACCESS); - else - { - // Only update the stack pointer if all is OK so the - // exception handler can properly clean up the stack - l_sp += AS_PTR_SIZE; - - // Pop the int arg from the stack - int arg = *(int*)l_sp; - l_sp++; - - // Call the method - m_callingSystemFunction = m_engine->scriptFunctions[i]; - void *ptr = 0; + // 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; + case asBC_Thiscall1: + // This instruction is a faster version of asBC_CALLSYS. It is faster because + // it has much less runtime overhead with determining the calling convention + // and no dynamic code for loading the parameters. The instruction can only + // be used to call functions with the following signatures: + // + // type &obj::func(int) + // type &obj::func(uint) + // void obj::func(int) + // void obj::func(uint) + { + // 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; + + // Pop the thispointer from the stack + void *obj = *(void**)l_sp; + if (obj == 0) + SetInternalException(TXT_NULL_POINTER_ACCESS); + else + { + // Only update the stack pointer if all is OK so the + // exception handler can properly clean up the stack + l_sp += AS_PTR_SIZE; + + // Pop the int arg from the stack + int arg = *(int*)l_sp; + l_sp++; + + // Call the method + m_callingSystemFunction = m_engine->scriptFunctions[i]; + void *ptr = 0; #ifdef AS_NO_EXCEPTIONS - ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction); + ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction); #else - // This try/catch block is to catch potential exception that may - // be thrown by the registered function. - try - { - ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction); - } - catch (...) - { - // Convert the exception to a script exception so the VM can - // properly report the error to the application and then clean up - HandleAppException(); - } + // This try/catch block is to catch potential exception that may + // be thrown by the registered function. + try + { + ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction); + } + catch (...) + { + // Convert the exception to a script exception so the VM can + // properly report the error to the application and then clean up + HandleAppException(); + } #endif - m_callingSystemFunction = 0; - *(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr; - } - - // Update the program position after the call so that line number is correct - l_bc += 2; - - 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; - - // 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; + m_callingSystemFunction = 0; + *(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr; + } + + // Update the program position after the call so that line number is correct + l_bc += 2; + + 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; + + // 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); + 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); + 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] ); - } + 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 - } + } } // interface int asCContext::SetException(const char *descr, bool allowCatch) { - // Only allow this if we're executing a CALL byte code - if( m_callingSystemFunction == 0 ) return asERROR; + // Only allow this if we're executing a CALL byte code + if( m_callingSystemFunction == 0 ) return asERROR; - SetInternalException(descr, allowCatch); + SetInternalException(descr, allowCatch); - return 0; + return 0; } void asCContext::SetInternalException(const char *descr, bool allowCatch) { - 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; - } - - // Recursively search the callstack for try/catch blocks - m_exceptionWillBeCaught = allowCatch && FindExceptionTryCatch(); - - if( m_exceptionCallback ) - CallExceptionCallback(); + 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; + } + + // Recursively search the callstack for try/catch blocks + m_exceptionWillBeCaught = allowCatch && FindExceptionTryCatch(); + + if( m_exceptionCallback ) + CallExceptionCallback(); } // interface bool asCContext::WillExceptionBeCaught() { - return m_exceptionWillBeCaught; + return m_exceptionWillBeCaught; } 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(CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct ) - m_engine->CallObjectMethod(GetReturnObject(), CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct); - - return; - } - - if( m_regs.objectRegister == 0 ) return; - - asASSERT( m_regs.objectType != 0 ); - - if( m_regs.objectType ) - { - if (m_regs.objectType->GetFlags() & asOBJ_FUNCDEF) - { - // Release the function pointer - reinterpret_cast(m_regs.objectRegister)->Release(); - m_regs.objectRegister = 0; - } - else - { - // Call the destructor on the object - asSTypeBehaviour *beh = &(CastToObjectType(reinterpret_cast(m_regs.objectType))->beh); - if (m_regs.objectType->GetFlags() & asOBJ_REF) - { - asASSERT(beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT)); - - 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; - } - } - } + 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(CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct ) + m_engine->CallObjectMethod(GetReturnObject(), CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct); + + return; + } + + if( m_regs.objectRegister == 0 ) return; + + asASSERT( m_regs.objectType != 0 ); + + if( m_regs.objectType ) + { + if (m_regs.objectType->GetFlags() & asOBJ_FUNCDEF) + { + // Release the function pointer + reinterpret_cast(m_regs.objectRegister)->Release(); + m_regs.objectRegister = 0; + } + else + { + // Call the destructor on the object + asSTypeBehaviour *beh = &(CastToObjectType(reinterpret_cast(m_regs.objectType))->beh); + if (m_regs.objectType->GetFlags() & asOBJ_REF) + { + asASSERT(beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT)); + + 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(bool catchException) { - m_inExceptionHandler = true; - - // Run the clean up code and move to catch block - bool caught = CleanStackFrame(catchException); - if( !caught ) - { - // 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 (!caught && m_callStack.GetLength() > 0) - { - // Only clean up until the top most marker for a nested call - asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; - if (s[0] == 0) - break; - - PopCallState(); - - caught = CleanStackFrame(catchException); - } - } - - // If the exception was caught, then move the status to - // active as is now possible to resume the execution - if (caught) - m_status = asEXECUTION_ACTIVE; - - m_inExceptionHandler = false; + m_inExceptionHandler = true; + + // Run the clean up code and move to catch block + bool caught = CleanStackFrame(catchException); + if( !caught ) + { + // 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 (!caught && m_callStack.GetLength() > 0) + { + // Only clean up until the top most marker for a nested call + asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; + if (s[0] == 0) + break; + + PopCallState(); + + caught = CleanStackFrame(catchException); + } + } + + // If the exception was caught, then move the status to + // active as is now possible to resume the execution + if (caught) + m_status = asEXECUTION_ACTIVE; + + m_inExceptionHandler = false; } // 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; + // 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 occurred - 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; - case asOBJ_VARDECL: // A variable was declared - // We don't really care about the variable declarations at this moment - break; - } - } - - // We're done with the investigation - break; - } - } + 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 occurred + 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; + case asOBJ_VARDECL: // A variable was declared + // We don't really care about the variable declarations at this moment + 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 = CastToFuncdefType(m_currentFunction->scriptData->objVariableTypes[v])->funcdef; - 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 ) - { - if (m_currentFunction->parameterTypes[v].IsFuncdef()) - func = CastToFuncdefType(m_currentFunction->parameterTypes[v].GetTypeInfo())->funcdef; - 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].IsFuncdef()) && !func->parameterTypes[n].IsReference() ) - { - // TODO: cleanup: This logic is repeated twice in CleanStackFrame too. Should create a common function to share the code - if( *(asPWORD*)&m_regs.stackPointer[offset] ) - { - // Call the object's destructor - asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour(); - if (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF) - { - (*(asCScriptFunction**)&m_regs.stackPointer[offset])->Release(); - } - else if( func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF ) - { - asASSERT( (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); - - if( beh->release ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release); - } - 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; + 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 = CastToFuncdefType(m_currentFunction->scriptData->objVariableTypes[v])->funcdef; + 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 ) + { + if (m_currentFunction->parameterTypes[v].IsFuncdef()) + func = CastToFuncdefType(m_currentFunction->parameterTypes[v].GetTypeInfo())->funcdef; + 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].IsFuncdef()) && !func->parameterTypes[n].IsReference() ) + { + // TODO: cleanup: This logic is repeated twice in CleanStackFrame too. Should create a common function to share the code + if( *(asPWORD*)&m_regs.stackPointer[offset] ) + { + // Call the object's destructor + asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour(); + if (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF) + { + (*(asCScriptFunction**)&m_regs.stackPointer[offset])->Release(); + } + else if( func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF ) + { + asASSERT( (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); + + if( beh->release ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release); + } + 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; } bool asCContext::FindExceptionTryCatch() { - // Check each of the script functions on the callstack to see if - // the current program position is within a try/catch block - if (m_currentFunction && m_currentFunction->scriptData) - { - asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()); - for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++) - { - if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos && - currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos) - return true; - } - } - - int stackSize = GetCallstackSize(); - for (int level = 1; level < stackSize; level++) - { - asPWORD *s = m_callStack.AddressOf() + (stackSize - level - 1)*CALLSTACK_FRAME_SIZE; - asCScriptFunction *func = (asCScriptFunction*)s[1]; - if (func && func->scriptData) - { - asUINT currPos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf()); - for (asUINT n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++) - { - if (currPos >= func->scriptData->tryCatchInfo[n].tryPos && - currPos < func->scriptData->tryCatchInfo[n].catchPos) - return true; - } - } - } - - return false; + // Check each of the script functions on the callstack to see if + // the current program position is within a try/catch block + if (m_currentFunction && m_currentFunction->scriptData) + { + asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()); + for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++) + { + if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos && + currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos) + return true; + } + } + + int stackSize = GetCallstackSize(); + for (int level = 1; level < stackSize; level++) + { + asPWORD *s = m_callStack.AddressOf() + (stackSize - level - 1)*CALLSTACK_FRAME_SIZE; + asCScriptFunction *func = (asCScriptFunction*)s[1]; + if (func && func->scriptData) + { + asUINT currPos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf()); + for (asUINT n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++) + { + if (currPos >= func->scriptData->tryCatchInfo[n].tryPos && + currPos < func->scriptData->tryCatchInfo[n].catchPos) + return true; + } + } + } + + return false; } bool asCContext::CleanStackFrame(bool catchException) { - bool exceptionCaught = false; - asSTryCatchInfo *tryCatchInfo = 0; - - // Clean object variables on the stack - // If the stack memory is not allocated or the program pointer - // is not set, then there is nothing to clean up on the stack frame - 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(); - - // Check if this function will catch the exception - // Try blocks can be nested, so use the innermost block - asASSERT(m_currentFunction->scriptData); - if (catchException && m_currentFunction->scriptData) - { - asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()); - - for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++) - { - if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos && - currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos) - { - tryCatchInfo = &m_currentFunction->scriptData->tryCatchInfo[n]; - exceptionCaught = true; - } - if (currPos < m_currentFunction->scriptData->tryCatchInfo[n].tryPos) - break; - } - } - - // Restore the stack pointer - if( !exceptionCaught ) - 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 the exception was caught, then only clean up objects within the try block - if (exceptionCaught) - { - // Find out where the variable was declared, and skip cleaning of those that were declared before the try catch - // Multiple variables in different scopes may occupy the same slot on the stack so it is necessary to search - // the entire list to determine which variable occupies the slot now. - int skipClean = 0; - for( asUINT p = 0; p < m_currentFunction->scriptData->objVariableInfo.GetLength(); p++ ) - { - asSObjectVariableInfo &info = m_currentFunction->scriptData->objVariableInfo[p]; - if (info.variableOffset == pos && - info.option == asOBJ_VARDECL ) - { - asUINT progPos = info.programPos; - if (progPos < tryCatchInfo->tryPos ) - { - if( skipClean >= 0 ) - skipClean = 1; - break; - } - else if( progPos < tryCatchInfo->catchPos ) - { - skipClean = -1; - break; - } - } - } - - // Skip only variables that have been declared before the try block. Variables declared - // within the try block and variables whose declaration was not identified (temporary objects) - // will not be skipped. - // TODO: What if a temporary variable reuses a slot from a declared variable that is no longer in scope? - if (skipClean > 0) - continue; - } - - if( n < m_currentFunction->scriptData->objVariablesOnHeap ) - { - // Check if the pointer is initialized - if( *(asPWORD*)&m_regs.stackFramePointer[-pos] ) - { - // Call the object's destructor - if (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_FUNCDEF) - { - (*(asCScriptFunction**)&m_regs.stackFramePointer[-pos])->Release(); - } - else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_REF ) - { - asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; - asASSERT( (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_NOCOUNT) || beh->release ); - if( beh->release ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->release); - } - else - { - asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; - if( beh->destruct ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); - else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_LIST_PATTERN ) - m_engine->DestroyList((asBYTE*)*(asPWORD*)&m_regs.stackFramePointer[-pos], CastToObjectType(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 = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; - if( beh->destruct ) - m_engine->CallObjectMethod((void*)(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); - } - } - } - } - else - m_isStackMemoryNotAllocated = false; - - // If the exception was caught then move the program position to the catch block then stop the unwinding - if (exceptionCaught) - { - m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf() + tryCatchInfo->catchPos; - return exceptionCaught; - } - - // Functions that do not own the object and parameters shouldn't do any clean up - if( m_currentFunction->dontCleanUpOnException ) - return exceptionCaught; - - // 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].IsFuncdef()) && !m_currentFunction->parameterTypes[n].IsReference() ) - { - if( *(asPWORD*)&m_regs.stackFramePointer[offset] ) - { - // Call the object's destructor - asSTypeBehaviour *beh = m_currentFunction->parameterTypes[n].GetBehaviour(); - if (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF) - { - (*(asCScriptFunction**)&m_regs.stackFramePointer[offset])->Release(); - } - else if( m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF ) - { - asASSERT( (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); - - if( beh->release ) - m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->release); - } - 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(); - } - - return exceptionCaught; + bool exceptionCaught = false; + asSTryCatchInfo *tryCatchInfo = 0; + + // Clean object variables on the stack + // If the stack memory is not allocated or the program pointer + // is not set, then there is nothing to clean up on the stack frame + 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(); + + // Check if this function will catch the exception + // Try blocks can be nested, so use the innermost block + asASSERT(m_currentFunction->scriptData); + if (catchException && m_currentFunction->scriptData) + { + asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()); + + for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++) + { + if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos && + currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos) + { + tryCatchInfo = &m_currentFunction->scriptData->tryCatchInfo[n]; + exceptionCaught = true; + } + if (currPos < m_currentFunction->scriptData->tryCatchInfo[n].tryPos) + break; + } + } + + // Restore the stack pointer + if( !exceptionCaught ) + 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 the exception was caught, then only clean up objects within the try block + if (exceptionCaught) + { + // Find out where the variable was declared, and skip cleaning of those that were declared before the try catch + // Multiple variables in different scopes may occupy the same slot on the stack so it is necessary to search + // the entire list to determine which variable occupies the slot now. + int skipClean = 0; + for( asUINT p = 0; p < m_currentFunction->scriptData->objVariableInfo.GetLength(); p++ ) + { + asSObjectVariableInfo &info = m_currentFunction->scriptData->objVariableInfo[p]; + if (info.variableOffset == pos && + info.option == asOBJ_VARDECL ) + { + asUINT progPos = info.programPos; + if (progPos < tryCatchInfo->tryPos ) + { + if( skipClean >= 0 ) + skipClean = 1; + break; + } + else if( progPos < tryCatchInfo->catchPos ) + { + skipClean = -1; + break; + } + } + } + + // Skip only variables that have been declared before the try block. Variables declared + // within the try block and variables whose declaration was not identified (temporary objects) + // will not be skipped. + // TODO: What if a temporary variable reuses a slot from a declared variable that is no longer in scope? + if (skipClean > 0) + continue; + } + + if( n < m_currentFunction->scriptData->objVariablesOnHeap ) + { + // Check if the pointer is initialized + if( *(asPWORD*)&m_regs.stackFramePointer[-pos] ) + { + // Call the object's destructor + if (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_FUNCDEF) + { + (*(asCScriptFunction**)&m_regs.stackFramePointer[-pos])->Release(); + } + else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_REF ) + { + asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; + asASSERT( (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_NOCOUNT) || beh->release ); + if( beh->release ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->release); + } + else + { + asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; + if( beh->destruct ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); + else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_LIST_PATTERN ) + m_engine->DestroyList((asBYTE*)*(asPWORD*)&m_regs.stackFramePointer[-pos], CastToObjectType(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 = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; + if( beh->destruct ) + m_engine->CallObjectMethod((void*)(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); + } + } + } + } + else + m_isStackMemoryNotAllocated = false; + + // If the exception was caught then move the program position to the catch block then stop the unwinding + if (exceptionCaught) + { + m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf() + tryCatchInfo->catchPos; + return exceptionCaught; + } + + // Functions that do not own the object and parameters shouldn't do any clean up + if( m_currentFunction->dontCleanUpOnException ) + return exceptionCaught; + + // 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].IsFuncdef()) && !m_currentFunction->parameterTypes[n].IsReference() ) + { + if( *(asPWORD*)&m_regs.stackFramePointer[offset] ) + { + // Call the object's destructor + asSTypeBehaviour *beh = m_currentFunction->parameterTypes[n].GetBehaviour(); + if (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF) + { + (*(asCScriptFunction**)&m_regs.stackFramePointer[offset])->Release(); + } + else if( m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF ) + { + asASSERT( (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); + + if( beh->release ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->release); + } + 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(); + } + + return exceptionCaught; } // interface int asCContext::GetExceptionLineNumber(int *column, const char **sectionName) { - // Return the last exception even if the context is no longer in the exception state - // if( GetState() != asEXECUTION_EXCEPTION ) return asERROR; + // Return the last exception even if the context is no longer in the exception state + // if( GetState() != asEXECUTION_EXCEPTION ) return asERROR; - if( column ) *column = m_exceptionColumn; + if( column ) *column = m_exceptionColumn; - if( sectionName ) - { - // The section index can be -1 if the exception was raised in a generated function, e.g. $fact for templates - if( m_exceptionSectionIdx >= 0 ) - *sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf(); - else - *sectionName = 0; - } + if( sectionName ) + { + // The section index can be -1 if the exception was raised in a generated function, e.g. $fact for templates + if( m_exceptionSectionIdx >= 0 ) + *sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf(); + else + *sectionName = 0; + } - return m_exceptionLine; + return m_exceptionLine; } // interface asIScriptFunction *asCContext::GetExceptionFunction() { - // Return the last exception even if the context is no longer in the exception state - // if( GetState() != asEXECUTION_EXCEPTION ) return 0; + // Return the last exception even if the context is no longer in the exception state + // if( GetState() != asEXECUTION_EXCEPTION ) return 0; - return m_engine->scriptFunctions[m_exceptionFunction]; + return m_engine->scriptFunctions[m_exceptionFunction]; } // interface const char *asCContext::GetExceptionString() { - // Return the last exception even if the context is no longer in the exception state - // if( GetState() != asEXECUTION_EXCEPTION ) return 0; + // Return the last exception even if the context is no longer in the exception state + // if( GetState() != asEXECUTION_EXCEPTION ) return 0; - return m_exceptionString.AddressOf(); + return m_exceptionString.AddressOf(); } // interface asEContextState asCContext::GetState() const { - return m_status; + return m_status; } // interface int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv) { - // First turn off the line callback to avoid a second thread - // attempting to call it while the new one is still being set - m_lineCallback = false; - - m_lineCallbackObj = obj; - bool isObj = false; - if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST ) - { - m_regs.doProcessSuspend = m_doSuspend; - return asNOT_SUPPORTED; - } - if( (unsigned)callConv >= asCALL_THISCALL ) - { - isObj = true; - if( obj == 0 ) - { - m_regs.doProcessSuspend = m_doSuspend; - return asINVALID_ARG; - } - } - - int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_lineCallbackFunc); - - // Turn on the line callback after setting both the function pointer and object pointer - if( r >= 0 ) m_lineCallback = true; - - // The BC_SUSPEND instruction should be processed if either line - // callback is set or if the application has requested a suspension - m_regs.doProcessSuspend = m_doSuspend || m_lineCallback; - - return r; + // First turn off the line callback to avoid a second thread + // attempting to call it while the new one is still being set + m_lineCallback = false; + + m_lineCallbackObj = obj; + bool isObj = false; + if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST ) + { + m_regs.doProcessSuspend = m_doSuspend; + return asNOT_SUPPORTED; + } + if( (unsigned)callConv >= asCALL_THISCALL ) + { + isObj = true; + if( obj == 0 ) + { + m_regs.doProcessSuspend = m_doSuspend; + return asINVALID_ARG; + } + } + + int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_lineCallbackFunc); + + // Turn on the line callback after setting both the function pointer and object pointer + if( r >= 0 ) m_lineCallback = true; + + // The BC_SUSPEND instruction should be processed if either line + // callback is set or if the application has requested a suspension + 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); + 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; + 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); + 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); } #ifndef AS_NO_EXCEPTIONS // internal void asCContext::HandleAppException() { - // This method is called from within a catch(...) block - if (m_engine->translateExceptionCallback) - { - // Allow the application to translate the application exception to a proper exception string - if (m_engine->translateExceptionCallbackFunc.callConv < ICC_THISCALL) - m_engine->CallGlobalFunction(this, m_engine->translateExceptionCallbackObj, &m_engine->translateExceptionCallbackFunc, 0); - else - m_engine->CallObjectMethod(m_engine->translateExceptionCallbackObj, this, &m_engine->translateExceptionCallbackFunc, 0); - } - - // Make sure an exception is set even if the application decides not to do any specific translation - if( m_status != asEXECUTION_EXCEPTION ) - SetException(TXT_EXCEPTION_CAUGHT); + // This method is called from within a catch(...) block + if (m_engine->translateExceptionCallback) + { + // Allow the application to translate the application exception to a proper exception string + if (m_engine->translateExceptionCallbackFunc.callConv < ICC_THISCALL) + m_engine->CallGlobalFunction(this, m_engine->translateExceptionCallbackObj, &m_engine->translateExceptionCallbackFunc, 0); + else + m_engine->CallObjectMethod(m_engine->translateExceptionCallbackObj, this, &m_engine->translateExceptionCallbackFunc, 0); + } + + // Make sure an exception is set even if the application decides not to do any specific translation + if( m_status != asEXECUTION_EXCEPTION ) + SetException(TXT_EXCEPTION_CAUGHT); } #endif // interface void asCContext::ClearLineCallback() { - m_lineCallback = false; - m_regs.doProcessSuspend = m_doSuspend; + m_lineCallback = false; + m_regs.doProcessSuspend = m_doSuspend; } // interface void asCContext::ClearExceptionCallback() { - m_exceptionCallback = false; + m_exceptionCallback = false; } int asCContext::CallGeneric(asCScriptFunction *descr) { - asSSystemFunctionInterface *sysFunc = descr->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; - asASSERT( sysFunc->callConv == ICC_GENERIC_FUNC || sysFunc->callConv == ICC_GENERIC_METHOD ); - if( sysFunc->callConv == ICC_GENERIC_METHOD ) - { - // 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; - } - - asASSERT( sysFunc->baseOffset == 0 ); - - // Skip object pointer - args += AS_PTR_SIZE; - } - - if( descr->DoesReturnOnStack() ) - { - // Skip the address where the return value will be stored - args += AS_PTR_SIZE; - popSize += AS_PTR_SIZE; - } - - asCGeneric gen(m_engine, descr, currentObject, args); - - m_callingSystemFunction = descr; + asSSystemFunctionInterface *sysFunc = descr->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; + asASSERT( sysFunc->callConv == ICC_GENERIC_FUNC || sysFunc->callConv == ICC_GENERIC_METHOD ); + if( sysFunc->callConv == ICC_GENERIC_METHOD ) + { + // 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; + } + + asASSERT( sysFunc->baseOffset == 0 ); + + // Skip object pointer + args += AS_PTR_SIZE; + } + + if( descr->DoesReturnOnStack() ) + { + // Skip the address where the return value will be stored + args += AS_PTR_SIZE; + popSize += AS_PTR_SIZE; + } + + asCGeneric gen(m_engine, descr, currentObject, args); + + m_callingSystemFunction = descr; #ifdef AS_NO_EXCEPTIONS - func(&gen); + func(&gen); #else - // This try/catch block is to catch potential exception that may - // be thrown by the registered function. - try - { - func(&gen); - } - catch (...) - { - // Convert the exception to a script exception so the VM can - // properly report the error to the application and then clean up - HandleAppException(); - } + // This try/catch block is to catch potential exception that may + // be thrown by the registered function. + try + { + func(&gen); + } + catch (...) + { + // Convert the exception to a script exception so the VM can + // properly report the error to the application and then clean up + HandleAppException(); + } #endif - m_callingSystemFunction = 0; - - m_regs.valueRegister = gen.returnVal; - m_regs.objectRegister = gen.objectRegister; - m_regs.objectType = descr->returnType.GetTypeInfo(); - - // Increase the returned handle if the function has been declared with autohandles - // and the engine is not set to use the old mode for the generic calling convention - if (sysFunc->returnAutoHandle && m_engine->ep.genericCallMode == 1 && m_regs.objectRegister) - { - asASSERT(!(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT)); - m_engine->CallObjectMethod(m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref); - } - - // Clean up arguments - const asUINT cleanCount = sysFunc->cleanArgs.GetLength(); - if( cleanCount ) - { - asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf(); - for( asUINT n = 0; n < cleanCount; n++, clean++ ) - { - void **addr = (void**)&args[clean->off]; - if( clean->op == 0 ) - { - if( *addr != 0 ) - { - m_engine->CallObjectMethod(*addr, clean->ot->beh.release); - *addr = 0; - } - } - else - { - asASSERT( clean->op == 1 || clean->op == 2 ); - asASSERT( *addr ); - - if( clean->op == 2 ) - m_engine->CallObjectMethod(*addr, clean->ot->beh.destruct); - - m_engine->CallFree(*addr); - } - } - } - - // Return how much should be popped from the stack - return popSize; + m_callingSystemFunction = 0; + + m_regs.valueRegister = gen.returnVal; + m_regs.objectRegister = gen.objectRegister; + m_regs.objectType = descr->returnType.GetTypeInfo(); + + // Increase the returned handle if the function has been declared with autohandles + // and the engine is not set to use the old mode for the generic calling convention + if (sysFunc->returnAutoHandle && m_engine->ep.genericCallMode == 1 && m_regs.objectRegister) + { + asASSERT(!(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT)); + m_engine->CallObjectMethod(m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref); + } + + // Clean up arguments + const asUINT cleanCount = sysFunc->cleanArgs.GetLength(); + if( cleanCount ) + { + asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf(); + for( asUINT n = 0; n < cleanCount; n++, clean++ ) + { + void **addr = (void**)&args[clean->off]; + if( clean->op == 0 ) + { + if( *addr != 0 ) + { + m_engine->CallObjectMethod(*addr, clean->ot->beh.release); + *addr = 0; + } + } + else + { + asASSERT( clean->op == 1 || clean->op == 2 ); + asASSERT( *addr ); + + if( clean->op == 2 ) + m_engine->CallObjectMethod(*addr, clean->ot->beh.destruct); + + m_engine->CallFree(*addr); + } + } + } + + // 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; + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return asINVALID_ARG; - return func->GetVarCount(); + return func->GetVarCount(); } // interface const char *asCContext::GetVarName(asUINT varIndex, asUINT stackLevel) { - asIScriptFunction *func = GetFunction(stackLevel); - if( func == 0 ) return 0; + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return 0; - const char *name = 0; - int r = func->GetVar(varIndex, &name); - return r >= 0 ? name : 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; + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return 0; - return func->GetVarDecl(varIndex, includeNamespace); + return func->GetVarDecl(varIndex, includeNamespace); } // interface int asCContext::GetVarTypeId(asUINT varIndex, asUINT stackLevel) { - asIScriptFunction *func = GetFunction(stackLevel); - if( func == 0 ) return asINVALID_ARG; + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return asINVALID_ARG; - int typeId; - int r = func->GetVar(varIndex, 0, &typeId); - return r < 0 ? r : typeId; + 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.GetTypeInfo()->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; + // 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.GetTypeInfo()->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 @@ -5570,17 +5570,17 @@ void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel) // 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; + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return asINVALID_ARG; - if( func->GetObjectType() == 0 ) - return 0; // not in a method + if( func->GetObjectType() == 0 ) + return 0; // not in a method - // create a datatype - asCDataType dt = asCDataType::CreateType((asCObjectType*)func->GetObjectType(), false); + // create a datatype + asCDataType dt = asCDataType::CreateType((asCObjectType*)func->GetObjectType(), false); - // return a typeId from the data type - return m_engine->GetTypeIdFromDataType(dt); + // return a typeId from the data type + return m_engine->GetTypeIdFromDataType(dt); } // interface @@ -5588,38 +5588,38 @@ int asCContext::GetThisTypeId(asUINT stackLevel) // 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; + 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; } @@ -5632,363 +5632,363 @@ void *asCContext::GetThisPointer(asUINT stackLevel) struct POW_INFO { - asQWORD MaxBaseu64; - asDWORD MaxBasei64; - asWORD MaxBaseu32; - asWORD MaxBasei32; - char HighBit; + 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 + { 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; - } - } + 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; - } - } + 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; - } - } + 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; - } - } + 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/src/angelscript/source/as_context.h b/src/angelscript/source/as_context.h index e56454059b9..a63efa1d7b1 100644 --- a/src/angelscript/source/as_context.h +++ b/src/angelscript/source/as_context.h @@ -54,166 +54,166 @@ 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); - int SetArgVarType(asUINT arg, void *ptr, int typeId); - 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, bool allowCatch = true); - int GetExceptionLineNumber(int *column, const char **sectionName); - asIScriptFunction *GetExceptionFunction(); - const char * GetExceptionString(); - bool WillExceptionBeCaught(); - int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv); - void ClearExceptionCallback(); - - // 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); + // 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); + int SetArgVarType(asUINT arg, void *ptr, int typeId); + 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, bool allowCatch = true); + int GetExceptionLineNumber(int *column, const char **sectionName); + asIScriptFunction *GetExceptionFunction(); + const char * GetExceptionString(); + bool WillExceptionBeCaught(); + int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv); + void ClearExceptionCallback(); + + // 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(); + asIScriptFunction *GetSystemFunction(); - // User data - void *SetUserData(void *data, asPWORD type); - void *GetUserData(asPWORD type) const; + // User data + void *SetUserData(void *data, asPWORD type); + void *GetUserData(asPWORD type) const; public: - // Internal public functions - asCContext(asCScriptEngine *engine, bool holdRef); - virtual ~asCContext(); + // Internal public functions + asCContext(asCScriptEngine *engine, bool holdRef); + virtual ~asCContext(); //protected: - friend class asCScriptEngine; + friend class asCScriptEngine; - void CallLineCallback(); - void CallExceptionCallback(); + void CallLineCallback(); + void CallExceptionCallback(); - int CallGeneric(asCScriptFunction *func); + int CallGeneric(asCScriptFunction *func); #ifndef AS_NO_EXCEPTIONS - void HandleAppException(); + void HandleAppException(); #endif - void DetachEngine(); - - void ExecuteNext(); - void CleanStack(bool catchException = false); - bool CleanStackFrame(bool catchException = false); - void CleanArgsOnStack(); - void CleanReturnObject(); - void DetermineLiveObjects(asCArray &liveObjects, asUINT stackLevel); - - int PushCallState(); - void PopCallState(); - void CallScriptFunction(asCScriptFunction *func); - void CallInterfaceMethod(asCScriptFunction *func); - void PrepareScriptFunction(); - - bool ReserveStackSpace(asUINT size); - - void SetInternalException(const char *descr, bool allowCatch = true); - bool FindExceptionTryCatch(); - - // 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; - bool m_exceptionWillBeCaught; - - // 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; + void DetachEngine(); + + void ExecuteNext(); + void CleanStack(bool catchException = false); + bool CleanStackFrame(bool catchException = false); + void CleanArgsOnStack(); + void CleanReturnObject(); + void DetermineLiveObjects(asCArray &liveObjects, asUINT stackLevel); + + int PushCallState(); + void PopCallState(); + void CallScriptFunction(asCScriptFunction *func); + void CallInterfaceMethod(asCScriptFunction *func); + void PrepareScriptFunction(); + + bool ReserveStackSpace(asUINT size); + + void SetInternalException(const char *descr, bool allowCatch = true); + bool FindExceptionTryCatch(); + + // 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; + bool m_exceptionWillBeCaught; + + // 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 @@ -227,21 +227,21 @@ asQWORD as_powu64(asQWORD base, asQWORD exponent, bool& isOverflow); 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; - } + // 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 diff --git a/src/angelscript/source/as_criticalsection.h b/src/angelscript/source/as_criticalsection.h index 2e15288a576..9b1681422a4 100644 --- a/src/angelscript/source/as_criticalsection.h +++ b/src/angelscript/source/as_criticalsection.h @@ -80,33 +80,33 @@ BEGIN_AS_NAMESPACE class asCThreadCriticalSection { public: - asCThreadCriticalSection(); - ~asCThreadCriticalSection(); + asCThreadCriticalSection(); + ~asCThreadCriticalSection(); - void Enter(); - void Leave(); - bool TryEnter(); + void Enter(); + void Leave(); + bool TryEnter(); protected: - pthread_mutex_t cs; + pthread_mutex_t cs; }; class asCThreadReadWriteLock { public: - asCThreadReadWriteLock(); - ~asCThreadReadWriteLock(); + asCThreadReadWriteLock(); + ~asCThreadReadWriteLock(); - void AcquireExclusive(); - void ReleaseExclusive(); - bool TryAcquireExclusive(); + void AcquireExclusive(); + void ReleaseExclusive(); + bool TryAcquireExclusive(); - void AcquireShared(); - void ReleaseShared(); - bool TryAcquireShared(); + void AcquireShared(); + void ReleaseShared(); + bool TryAcquireShared(); protected: - pthread_rwlock_t lock; + pthread_rwlock_t lock; }; #elif defined(AS_WINDOWS_THREADS) @@ -132,47 +132,47 @@ BEGIN_AS_NAMESPACE class asCThreadCriticalSection { public: - asCThreadCriticalSection(); - ~asCThreadCriticalSection(); + asCThreadCriticalSection(); + ~asCThreadCriticalSection(); - void Enter(); - void Leave(); - bool TryEnter(); + void Enter(); + void Leave(); + bool TryEnter(); protected: - CRITICAL_SECTION cs; + CRITICAL_SECTION cs; }; class asCThreadReadWriteLock { public: - asCThreadReadWriteLock(); - ~asCThreadReadWriteLock(); + asCThreadReadWriteLock(); + ~asCThreadReadWriteLock(); - void AcquireExclusive(); - void ReleaseExclusive(); + void AcquireExclusive(); + void ReleaseExclusive(); - void AcquireShared(); - void ReleaseShared(); + 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. + // 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: + // Critical sections and semaphores are available on Windows XP and onwards. + // Windows XP is oldest version we support with multithreading. - // http://doc.qt.nokia.com/qq/qq11-mutex.html + // 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: - // TODO: Allow use of SRWLOCK through configuration in as_config.h + // http://doc.qt.nokia.com/qq/qq11-mutex.html - CRITICAL_SECTION writeLock; - HANDLE readLocks; + // 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, diff --git a/src/angelscript/source/as_datatype.cpp b/src/angelscript/source/as_datatype.cpp index 0fcd75ca649..72a719b3fd9 100644 --- a/src/angelscript/source/as_datatype.cpp +++ b/src/angelscript/source/as_datatype.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -47,28 +47,28 @@ BEGIN_AS_NAMESPACE asCDataType::asCDataType() { - tokenType = ttUnrecognizedToken; - typeInfo = 0; - isReference = false; - isReadOnly = false; - isAuto = false; - isObjectHandle = false; - isConstHandle = false; - isHandleToAsHandleType = false; - ifHandleThenConst = false; + tokenType = ttUnrecognizedToken; + typeInfo = 0; + isReference = false; + isReadOnly = false; + isAuto = false; + isObjectHandle = false; + isConstHandle = false; + isHandleToAsHandleType = false; + ifHandleThenConst = false; } asCDataType::asCDataType(const asCDataType &dt) { - tokenType = dt.tokenType; - typeInfo = dt.typeInfo; - isReference = dt.isReference; - isReadOnly = dt.isReadOnly; - isAuto = dt.isAuto; - isObjectHandle = dt.isObjectHandle; - isConstHandle = dt.isConstHandle; - isHandleToAsHandleType = dt.isHandleToAsHandleType; - ifHandleThenConst = dt.ifHandleThenConst; + tokenType = dt.tokenType; + typeInfo = dt.typeInfo; + isReference = dt.isReference; + isReadOnly = dt.isReadOnly; + isAuto = dt.isAuto; + isObjectHandle = dt.isObjectHandle; + isConstHandle = dt.isConstHandle; + isHandleToAsHandleType = dt.isHandleToAsHandleType; + ifHandleThenConst = dt.ifHandleThenConst; } asCDataType::~asCDataType() @@ -77,613 +77,613 @@ asCDataType::~asCDataType() bool asCDataType::IsValid() const { - if( tokenType == ttUnrecognizedToken && - !isObjectHandle ) - return false; + if( tokenType == ttUnrecognizedToken && + !isObjectHandle ) + return false; - return true; + return true; } asCDataType asCDataType::CreateType(asCTypeInfo *ti, bool isConst) { - asCDataType dt; + asCDataType dt; - dt.tokenType = ttIdentifier; - dt.typeInfo = ti; - dt.isReadOnly = isConst; + dt.tokenType = ttIdentifier; + dt.typeInfo = ti; + dt.isReadOnly = isConst; - return dt; + return dt; } asCDataType asCDataType::CreateAuto(bool isConst) { - asCDataType dt; + asCDataType dt; - dt.tokenType = ttIdentifier; - dt.isReadOnly = isConst; - dt.isAuto = true; + dt.tokenType = ttIdentifier; + dt.isReadOnly = isConst; + dt.isAuto = true; - return dt; + return dt; } asCDataType asCDataType::CreateObjectHandle(asCTypeInfo *ot, bool isConst) { - asCDataType dt; + asCDataType dt; - asASSERT(CastToObjectType(ot)); + asASSERT(CastToObjectType(ot)); - dt.tokenType = ttIdentifier; - dt.typeInfo = ot; - dt.isObjectHandle = true; - dt.isConstHandle = isConst; + dt.tokenType = ttIdentifier; + dt.typeInfo = ot; + dt.isObjectHandle = true; + dt.isConstHandle = isConst; - return dt; + return dt; } asCDataType asCDataType::CreatePrimitive(eTokenType tt, bool isConst) { - asCDataType dt; + asCDataType dt; - dt.tokenType = tt; - dt.isReadOnly = isConst; + dt.tokenType = tt; + dt.isReadOnly = isConst; - return dt; + return dt; } asCDataType asCDataType::CreateNullHandle() { - asCDataType dt; + asCDataType dt; - dt.tokenType = ttUnrecognizedToken; - dt.isReadOnly = true; - dt.isObjectHandle = true; - dt.isConstHandle = true; + dt.tokenType = ttUnrecognizedToken; + dt.isReadOnly = true; + dt.isObjectHandle = true; + dt.isConstHandle = true; - return dt; + return dt; } bool asCDataType::IsNullHandle() const { - if( tokenType == ttUnrecognizedToken && - typeInfo == 0 && - isObjectHandle ) - return true; + if( tokenType == ttUnrecognizedToken && + typeInfo == 0 && + isObjectHandle ) + return true; - return false; + return false; } asCString asCDataType::Format(asSNameSpace *currNs, bool includeNamespace) const { - if( IsNullHandle() ) - return ""; - - asCString str; - - if( isReadOnly ) - str = "const "; - - // If the type is not declared in the current namespace, then the namespace - // must always be informed to guarantee that the correct type is informed - if (includeNamespace || (typeInfo && typeInfo->nameSpace != currNs)) - { - if (typeInfo && typeInfo->nameSpace && typeInfo->nameSpace->name != "") - str += typeInfo->nameSpace->name + "::"; - } - if (typeInfo && typeInfo->nameSpace == 0) - { - // If funcDef->nameSpace is null it means the funcDef was declared as member of - // another type, in which case the scope should be built with the name of that type - str += CastToFuncdefType(typeInfo)->parentClass->name + "::"; - } - - if( tokenType != ttIdentifier ) - { - str += asCTokenizer::GetDefinition(tokenType); - } - else if( IsArrayType() && typeInfo && !typeInfo->engine->ep.expandDefaultArrayToTemplate ) - { - asCObjectType *ot = CastToObjectType(typeInfo); - asASSERT( ot && ot->templateSubTypes.GetLength() == 1 ); - str += ot->templateSubTypes[0].Format(currNs, includeNamespace); - str += "[]"; - } - else if(typeInfo) - { - str += typeInfo->name; - asCObjectType *ot = CastToObjectType(typeInfo); - if( ot && ot->templateSubTypes.GetLength() > 0 ) - { - str += "<"; - for( asUINT subtypeIndex = 0; subtypeIndex < ot->templateSubTypes.GetLength(); subtypeIndex++ ) - { - str += ot->templateSubTypes[subtypeIndex].Format(currNs, includeNamespace); - if( subtypeIndex != ot->templateSubTypes.GetLength()-1 ) - str += ","; - } - str += ">"; - } - } - else if( isAuto ) - { - str += ""; - } - else - { - str = ""; - } - - if( isObjectHandle ) - { - str += "@"; - if( isConstHandle ) - str += "const"; - } - - if( isReference ) - str += "&"; - - return str; + if( IsNullHandle() ) + return ""; + + asCString str; + + if( isReadOnly ) + str = "const "; + + // If the type is not declared in the current namespace, then the namespace + // must always be informed to guarantee that the correct type is informed + if (includeNamespace || (typeInfo && typeInfo->nameSpace != currNs)) + { + if (typeInfo && typeInfo->nameSpace && typeInfo->nameSpace->name != "") + str += typeInfo->nameSpace->name + "::"; + } + if (typeInfo && typeInfo->nameSpace == 0) + { + // If funcDef->nameSpace is null it means the funcDef was declared as member of + // another type, in which case the scope should be built with the name of that type + str += CastToFuncdefType(typeInfo)->parentClass->name + "::"; + } + + if( tokenType != ttIdentifier ) + { + str += asCTokenizer::GetDefinition(tokenType); + } + else if( IsArrayType() && typeInfo && !typeInfo->engine->ep.expandDefaultArrayToTemplate ) + { + asCObjectType *ot = CastToObjectType(typeInfo); + asASSERT( ot && ot->templateSubTypes.GetLength() == 1 ); + str += ot->templateSubTypes[0].Format(currNs, includeNamespace); + str += "[]"; + } + else if(typeInfo) + { + str += typeInfo->name; + asCObjectType *ot = CastToObjectType(typeInfo); + if( ot && ot->templateSubTypes.GetLength() > 0 ) + { + str += "<"; + for( asUINT subtypeIndex = 0; subtypeIndex < ot->templateSubTypes.GetLength(); subtypeIndex++ ) + { + str += ot->templateSubTypes[subtypeIndex].Format(currNs, includeNamespace); + if( subtypeIndex != ot->templateSubTypes.GetLength()-1 ) + str += ","; + } + str += ">"; + } + } + else if( isAuto ) + { + 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; - typeInfo = dt.typeInfo; - isReadOnly = dt.isReadOnly; - isObjectHandle = dt.isObjectHandle; - isConstHandle = dt.isConstHandle; - isAuto = dt.isAuto; - isHandleToAsHandleType = dt.isHandleToAsHandleType; - ifHandleThenConst = dt.ifHandleThenConst; + tokenType = dt.tokenType; + isReference = dt.isReference; + typeInfo = dt.typeInfo; + isReadOnly = dt.isReadOnly; + isObjectHandle = dt.isObjectHandle; + isConstHandle = dt.isConstHandle; + isAuto = dt.isAuto; + isHandleToAsHandleType = dt.isHandleToAsHandleType; + ifHandleThenConst = dt.ifHandleThenConst; - return (asCDataType &)*this; + 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( (!typeInfo || - !((typeInfo->flags & asOBJ_REF) || (typeInfo->flags & asOBJ_TEMPLATE_SUBTYPE) || (typeInfo->flags & asOBJ_ASHANDLE) || (typeInfo->flags & asOBJ_FUNCDEF)) || - (typeInfo->flags & asOBJ_NOHANDLE) || - ((typeInfo->flags & asOBJ_SCOPED) && !acceptHandleForScope)) ) - return -1; - - isObjectHandle = b; - isConstHandle = false; - - // ASHANDLE supports being handle, but as it really is a value type it will not be marked as a handle - if( (typeInfo->flags & asOBJ_ASHANDLE) ) - { - isObjectHandle = false; - isHandleToAsHandleType = true; - } - } - } - - return 0; + 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( (!typeInfo || + !((typeInfo->flags & asOBJ_REF) || (typeInfo->flags & asOBJ_TEMPLATE_SUBTYPE) || (typeInfo->flags & asOBJ_ASHANDLE) || (typeInfo->flags & asOBJ_FUNCDEF)) || + (typeInfo->flags & asOBJ_NOHANDLE) || + ((typeInfo->flags & asOBJ_SCOPED) && !acceptHandleForScope)) ) + return -1; + + isObjectHandle = b; + isConstHandle = false; + + // ASHANDLE supports being handle, but as it really is a value type it will not be marked as a handle + if( (typeInfo->flags & asOBJ_ASHANDLE) ) + { + isObjectHandle = false; + isHandleToAsHandleType = true; + } + } + } + + return 0; } int asCDataType::MakeArray(asCScriptEngine *engine, asCModule *module) { - if( engine->defaultArrayObjectType == 0 ) - return asINVALID_TYPE; + if( engine->defaultArrayObjectType == 0 ) + return asINVALID_TYPE; - bool tmpIsReadOnly = isReadOnly; - isReadOnly = false; - asCArray subTypes; - subTypes.PushLast(*this); - asCObjectType *at = engine->GetTemplateInstanceType(engine->defaultArrayObjectType, subTypes, module); - isReadOnly = tmpIsReadOnly; + bool tmpIsReadOnly = isReadOnly; + isReadOnly = false; + asCArray subTypes; + subTypes.PushLast(*this); + asCObjectType *at = engine->GetTemplateInstanceType(engine->defaultArrayObjectType, subTypes, module); + isReadOnly = tmpIsReadOnly; - isObjectHandle = false; - isConstHandle = false; - - typeInfo = at; - tokenType = ttIdentifier; + isObjectHandle = false; + isConstHandle = false; - return 0; + typeInfo = at; + tokenType = ttIdentifier; + + return 0; } int asCDataType::MakeReference(bool b) { - isReference = b; + isReference = b; - return 0; + return 0; } int asCDataType::MakeReadOnly(bool b) { - if( isObjectHandle ) - { - isConstHandle = b; - return 0; - } + if( isObjectHandle ) + { + isConstHandle = b; + return 0; + } - isReadOnly = b; - return 0; + isReadOnly = b; + return 0; } int asCDataType::MakeHandleToConst(bool b) { - if( !isObjectHandle ) return -1; + if( !isObjectHandle ) return -1; - isReadOnly = b; - return 0; + isReadOnly = b; + return 0; } bool asCDataType::SupportHandles() const { - if( typeInfo && - (typeInfo->flags & (asOBJ_REF | asOBJ_ASHANDLE | asOBJ_FUNCDEF)) && - !(typeInfo->flags & asOBJ_NOHANDLE) && - !isObjectHandle ) - return true; + if( typeInfo && + (typeInfo->flags & (asOBJ_REF | asOBJ_ASHANDLE | asOBJ_FUNCDEF)) && + !(typeInfo->flags & asOBJ_NOHANDLE) && + !isObjectHandle ) + return true; - return false; + return false; } bool asCDataType::CanBeInstantiated() const { - if( GetSizeOnStackDWords() == 0 ) // Void - return false; + if( GetSizeOnStackDWords() == 0 ) // Void + return false; - if( !IsObject() && !IsFuncdef() ) // Primitives - return true; + if( !IsObject() && !IsFuncdef() ) // Primitives + return true; - if (IsNullHandle()) // null - return false; + if (IsNullHandle()) // null + return false; - if( IsObjectHandle() && !(typeInfo->flags & asOBJ_NOHANDLE) ) // Handles - return true; + if( IsObjectHandle() && !(typeInfo->flags & asOBJ_NOHANDLE) ) // Handles + return true; - // Funcdefs cannot be instantiated without being handles - // The exception being delegates, but these can only be created as temporary objects - if (IsFuncdef()) - return false; + // Funcdefs cannot be instantiated without being handles + // The exception being delegates, but these can only be created as temporary objects + if (IsFuncdef()) + return false; - asCObjectType *ot = CastToObjectType(typeInfo); - if( ot && (ot->flags & asOBJ_REF) && ot->beh.factories.GetLength() == 0 ) // ref types without factories - return false; + asCObjectType *ot = CastToObjectType(typeInfo); + if( ot && (ot->flags & asOBJ_REF) && ot->beh.factories.GetLength() == 0 ) // ref types without factories + return false; - if( ot && (ot->flags & asOBJ_ABSTRACT) && !IsObjectHandle() ) // Can't instantiate abstract classes - return false; + if( ot && (ot->flags & asOBJ_ABSTRACT) && !IsObjectHandle() ) // Can't instantiate abstract classes + return false; - return true; + return true; } bool asCDataType::IsAbstractClass() const { - return typeInfo && (typeInfo->flags & asOBJ_ABSTRACT) ? true : false; + return typeInfo && (typeInfo->flags & asOBJ_ABSTRACT) ? true : false; } bool asCDataType::IsInterface() const { - if (typeInfo == 0) - return false; + if (typeInfo == 0) + return false; - asCObjectType *ot = CastToObjectType(typeInfo); - return ot && ot->IsInterface(); + asCObjectType *ot = CastToObjectType(typeInfo); + return ot && ot->IsInterface(); } bool asCDataType::CanBeCopied() const { - // All primitives can be copied - if( IsPrimitive() ) return true; + // All primitives can be copied + if( IsPrimitive() ) return true; - // Plain-old-data structures can always be copied - if( typeInfo->flags & asOBJ_POD ) return true; + // Plain-old-data structures can always be copied + if( typeInfo->flags & asOBJ_POD ) return true; - // It must be possible to instantiate the type - if( !CanBeInstantiated() ) return false; + // It must be possible to instantiate the type + if( !CanBeInstantiated() ) return false; - // It must have a default constructor or factory and the opAssign - // Alternatively it must have the copy constructor - asCObjectType *ot = CastToObjectType(typeInfo); - if (ot && (((ot->beh.construct != 0 || ot->beh.factory != 0) && ot->beh.copy != 0) || - (ot->beh.copyconstruct != 0 || ot->beh.copyfactory != 0)) ) - return true; + // It must have a default constructor or factory and the opAssign + // Alternatively it must have the copy constructor + asCObjectType *ot = CastToObjectType(typeInfo); + if (ot && (((ot->beh.construct != 0 || ot->beh.factory != 0) && ot->beh.copy != 0) || + (ot->beh.copyconstruct != 0 || ot->beh.copyfactory != 0)) ) + return true; - return false; + return false; } bool asCDataType::IsReadOnly() const { - if( isObjectHandle ) - return isConstHandle; + if( isObjectHandle ) + return isConstHandle; - return isReadOnly; + return isReadOnly; } bool asCDataType::IsHandleToConst() const { - if( !isObjectHandle ) return false; - return isReadOnly; + if( !isObjectHandle ) return false; + return isReadOnly; } bool asCDataType::IsObjectConst() const { - if( IsObjectHandle() ) - return IsHandleToConst(); + if( IsObjectHandle() ) + return IsHandleToConst(); - return IsReadOnly(); + 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( typeInfo && typeInfo->engine->defaultArrayObjectType ) - return typeInfo->name == typeInfo->engine->defaultArrayObjectType->name; - - return false; + // This is only true if the type used is the default array type, i.e. the one used for the [] syntax form + if( typeInfo && typeInfo->engine->defaultArrayObjectType ) + return typeInfo->name == typeInfo->engine->defaultArrayObjectType->name; + + return false; } bool asCDataType::IsTemplate() const { - if( typeInfo && (typeInfo->flags & asOBJ_TEMPLATE) ) - return true; + if( typeInfo && (typeInfo->flags & asOBJ_TEMPLATE) ) + return true; - return false; + return false; } bool asCDataType::IsScriptObject() const { - if( typeInfo && (typeInfo->flags & asOBJ_SCRIPT_OBJECT) ) - return true; + if( typeInfo && (typeInfo->flags & asOBJ_SCRIPT_OBJECT) ) + return true; - return false; + return false; } asCDataType asCDataType::GetSubType(asUINT subtypeIndex) const { - asASSERT(typeInfo); - asCObjectType *ot = CastToObjectType(typeInfo); - return ot->templateSubTypes[subtypeIndex]; + asASSERT(typeInfo); + asCObjectType *ot = CastToObjectType(typeInfo); + return ot->templateSubTypes[subtypeIndex]; } bool asCDataType::operator !=(const asCDataType &dt) const { - return !(*this == dt); + 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; + 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; + 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; + if( !IsEqualExceptRefAndConst(dt) ) return false; + if( isReadOnly != dt.isReadOnly ) return false; + if( isConstHandle != dt.isConstHandle ) return false; - return true; + return true; } bool asCDataType::IsEqualExceptRefAndConst(const asCDataType &dt) const { - // Check base type - if( tokenType != dt.tokenType ) return false; - if( typeInfo != dt.typeInfo ) return false; - if( isObjectHandle != dt.isObjectHandle ) return false; - if( isObjectHandle ) - if( isReadOnly != dt.isReadOnly ) return false; + // Check base type + if( tokenType != dt.tokenType ) return false; + if( typeInfo != dt.typeInfo ) return false; + if( isObjectHandle != dt.isObjectHandle ) return false; + if( isObjectHandle ) + if( isReadOnly != dt.isReadOnly ) return false; - return true; + return true; } bool asCDataType::IsEqualExceptConst(const asCDataType &dt) const { - if( !IsEqualExceptRefAndConst(dt) ) return false; - if( isReference != dt.isReference ) return false; + if( !IsEqualExceptRefAndConst(dt) ) return false; + if( isReference != dt.isReference ) return false; - return true; + return true; } bool asCDataType::IsPrimitive() const { - // Enumerations are primitives - if( IsEnumType() ) - return true; + // Enumerations are primitives + if( IsEnumType() ) + return true; - // A registered object is never a primitive neither is a pointer nor an array - if( typeInfo ) - return false; + // A registered object is never a primitive neither is a pointer nor an array + if( typeInfo ) + return false; - // Null handle doesn't have a typeInfo, but it is not a primitive - if( tokenType == ttUnrecognizedToken ) - return false; + // Null handle doesn't have a typeInfo, but it is not a primitive + if( tokenType == ttUnrecognizedToken ) + return false; - return true; + return true; } bool asCDataType::IsMathType() const { - if( tokenType == ttInt || tokenType == ttInt8 || tokenType == ttInt16 || tokenType == ttInt64 || - tokenType == ttUInt || tokenType == ttUInt8 || tokenType == ttUInt16 || tokenType == ttUInt64 || - tokenType == ttFloat || tokenType == ttDouble ) - return true; + if( tokenType == ttInt || tokenType == ttInt8 || tokenType == ttInt16 || tokenType == ttInt64 || + tokenType == ttUInt || tokenType == ttUInt8 || tokenType == ttUInt16 || tokenType == ttUInt64 || + tokenType == ttFloat || tokenType == ttDouble ) + return true; - return false; + return false; } bool asCDataType::IsIntegerType() const { - if( tokenType == ttInt || - tokenType == ttInt8 || - tokenType == ttInt16 || - tokenType == ttInt64 ) - return true; + if( tokenType == ttInt || + tokenType == ttInt8 || + tokenType == ttInt16 || + tokenType == ttInt64 ) + return true; - // Enums are also integer types - return IsEnumType(); + // Enums are also integer types + return IsEnumType(); } bool asCDataType::IsUnsignedType() const { - if( tokenType == ttUInt || - tokenType == ttUInt8 || - tokenType == ttUInt16 || - tokenType == ttUInt64 ) - return true; + if( tokenType == ttUInt || + tokenType == ttUInt8 || + tokenType == ttUInt16 || + tokenType == ttUInt64 ) + return true; - return false; + return false; } bool asCDataType::IsFloatType() const { - if( tokenType == ttFloat ) - return true; + if( tokenType == ttFloat ) + return true; - return false; + return false; } bool asCDataType::IsDoubleType() const { - if( tokenType == ttDouble ) - return true; + if( tokenType == ttDouble ) + return true; - return false; + return false; } bool asCDataType::IsBooleanType() const { - if( tokenType == ttBool ) - return true; + if( tokenType == ttBool ) + return true; - return false; + return false; } bool asCDataType::IsObject() const { - if( IsPrimitive() ) - return false; + if( IsPrimitive() ) + return false; - // Null handle doesn't have an object type but should still be considered an object - if( typeInfo == 0 ) - return IsNullHandle(); + // Null handle doesn't have an object type but should still be considered an object + if( typeInfo == 0 ) + return IsNullHandle(); - // Template subtypes shouldn't be considered objects - return CastToObjectType(typeInfo) ? true : false; + // Template subtypes shouldn't be considered objects + return CastToObjectType(typeInfo) ? true : false; } bool asCDataType::IsFuncdef() const { - if (typeInfo && (typeInfo->flags & asOBJ_FUNCDEF)) - return true; + if (typeInfo && (typeInfo->flags & asOBJ_FUNCDEF)) + return true; - return false; + return false; } int asCDataType::GetSizeInMemoryBytes() const { - if( typeInfo != 0 ) - return typeInfo->size; + if( typeInfo != 0 ) + return typeInfo->size; - if( tokenType == ttVoid ) - return 0; + if( tokenType == ttVoid ) + return 0; - if( tokenType == ttInt8 || - tokenType == ttUInt8 ) - return 1; + if( tokenType == ttInt8 || + tokenType == ttUInt8 ) + return 1; - if( tokenType == ttInt16 || - tokenType == ttUInt16 ) - return 2; + if( tokenType == ttInt16 || + tokenType == ttUInt16 ) + return 2; - if( tokenType == ttDouble || - tokenType == ttInt64 || - tokenType == ttUInt64 ) - return 8; + if( tokenType == ttDouble || + tokenType == ttInt64 || + tokenType == ttUInt64 ) + return 8; - if( tokenType == ttBool ) - return AS_SIZEOF_BOOL; + if( tokenType == ttBool ) + return AS_SIZEOF_BOOL; - // null handle - if( tokenType == ttUnrecognizedToken ) - return 4*AS_PTR_SIZE; + // null handle + if( tokenType == ttUnrecognizedToken ) + return 4*AS_PTR_SIZE; - return 4; + 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); + 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; + 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 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( typeInfo && !IsEnumType() ) return AS_PTR_SIZE + size; + if( isReference ) return AS_PTR_SIZE + size; + if( typeInfo && !IsEnumType() ) return AS_PTR_SIZE + size; - return GetSizeInMemoryDWords() + size; + return GetSizeInMemoryDWords() + size; } #ifdef WIP_16BYTE_ALIGN int asCDataType::GetAlignment() const { - if( typeInfo == NULL ) - { - // TODO: Small primitives should not be aligned to 4 byte boundaries - return 4; //Default alignment - } + if( typeInfo == NULL ) + { + // TODO: Small primitives should not be aligned to 4 byte boundaries + return 4; //Default alignment + } - return typeInfo->alignment; + return typeInfo->alignment; } #endif asSTypeBehaviour *asCDataType::GetBehaviour() const { - if (!typeInfo) return 0; - asCObjectType *ot = CastToObjectType(typeInfo); - return ot ? &ot->beh : 0; + if (!typeInfo) return 0; + asCObjectType *ot = CastToObjectType(typeInfo); + return ot ? &ot->beh : 0; } bool asCDataType::IsEnumType() const { - // Do a sanity check on the objectType, to verify that we aren't trying to access memory after it has been released - asASSERT(typeInfo == 0 || typeInfo->name.GetLength() < 100); + // Do a sanity check on the objectType, to verify that we aren't trying to access memory after it has been released + asASSERT(typeInfo == 0 || typeInfo->name.GetLength() < 100); - if (typeInfo && (typeInfo->flags & asOBJ_ENUM)) - return true; + if (typeInfo && (typeInfo->flags & asOBJ_ENUM)) + return true; - return false; + return false; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_datatype.h b/src/angelscript/source/as_datatype.h index 665f83a42ae..78c45992e77 100644 --- a/src/angelscript/source/as_datatype.h +++ b/src/angelscript/source/as_datatype.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2016 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -60,100 +60,100 @@ struct asSNameSpace; class asCDataType { public: - asCDataType(); - asCDataType(const asCDataType &); - ~asCDataType(); - - bool IsValid() const; - - asCString Format(asSNameSpace *currNs, bool includeNamespace = false) const; - - static asCDataType CreatePrimitive(eTokenType tt, bool isConst); - static asCDataType CreateType(asCTypeInfo *ti, bool isConst); - static asCDataType CreateAuto(bool isConst); - static asCDataType CreateObjectHandle(asCTypeInfo *ot, bool isConst); - static asCDataType CreateNullHandle(); - - int MakeHandle(bool b, bool acceptHandleForScope = false); - int MakeArray(asCScriptEngine *engine, asCModule *requestingModule); - int MakeReference(bool b); - int MakeReadOnly(bool b); - int MakeHandleToConst(bool b); - void SetIfHandleThenConst(bool b) { ifHandleThenConst = b; } - bool HasIfHandleThenConst() const { return ifHandleThenConst; } - - bool IsTemplate() const; - bool IsScriptObject() const; - bool IsPrimitive() const; - bool IsMathType() 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 IsFuncdef() 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;} - asCTypeInfo *GetTypeInfo() const { return typeInfo; } - - int GetSizeOnStackDWords() const; - int GetSizeInMemoryBytes() const; - int GetSizeInMemoryDWords() const; + asCDataType(); + asCDataType(const asCDataType &); + ~asCDataType(); + + bool IsValid() const; + + asCString Format(asSNameSpace *currNs, bool includeNamespace = false) const; + + static asCDataType CreatePrimitive(eTokenType tt, bool isConst); + static asCDataType CreateType(asCTypeInfo *ti, bool isConst); + static asCDataType CreateAuto(bool isConst); + static asCDataType CreateObjectHandle(asCTypeInfo *ot, bool isConst); + static asCDataType CreateNullHandle(); + + int MakeHandle(bool b, bool acceptHandleForScope = false); + int MakeArray(asCScriptEngine *engine, asCModule *requestingModule); + int MakeReference(bool b); + int MakeReadOnly(bool b); + int MakeHandleToConst(bool b); + void SetIfHandleThenConst(bool b) { ifHandleThenConst = b; } + bool HasIfHandleThenConst() const { return ifHandleThenConst; } + + bool IsTemplate() const; + bool IsScriptObject() const; + bool IsPrimitive() const; + bool IsMathType() 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 IsFuncdef() 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;} + asCTypeInfo *GetTypeInfo() const { return typeInfo; } + + int GetSizeOnStackDWords() const; + int GetSizeInMemoryBytes() const; + int GetSizeInMemoryDWords() const; #ifdef WIP_16BYTE_ALIGN - int GetAlignment() const; + int GetAlignment() const; #endif - void SetTokenType(eTokenType tt) {tokenType = tt;} - void SetTypeInfo(asCTypeInfo *ti) {typeInfo = ti;} + void SetTokenType(eTokenType tt) {tokenType = tt;} + void SetTypeInfo(asCTypeInfo *ti) {typeInfo = ti;} - asCDataType &operator =(const asCDataType &); + asCDataType &operator =(const asCDataType &); - asSTypeBehaviour *GetBehaviour() const; + asSTypeBehaviour *GetBehaviour() const; protected: - // Base object type - eTokenType tokenType; - - // Behaviour type - asCTypeInfo *typeInfo; - - // 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 - bool ifHandleThenConst:1; // Used when creating template instances to determine if a handle should be const or not - char dummy:1; + // Base object type + eTokenType tokenType; + + // Behaviour type + asCTypeInfo *typeInfo; + + // 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 + bool ifHandleThenConst:1; // Used when creating template instances to determine if a handle should be const or not + char dummy:1; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_debug.h b/src/angelscript/source/as_debug.h index e67d8b3aeb0..f936612a507 100644 --- a/src/angelscript/source/as_debug.h +++ b/src/angelscript/source/as_debug.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2016 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -51,8 +51,8 @@ #if !defined(_MSC_VER) && (defined(__GNUC__) || defined(AS_MARMALADE)) -#ifdef __ghs__ -// WIIU defines __GNUC__ but types are not defined here in 'conventional' way +#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; @@ -95,139 +95,139 @@ BEGIN_AS_NAMESPACE struct TimeCount { - double time; - int count; - double max; - double min; + 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; - } - + 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; + 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; @@ -235,20 +235,20 @@ extern CProfiler g_profiler; class CProfilerScope { public: - CProfilerScope(const char *name) - { - this->name = name; - beginTime = g_profiler.Begin(name); - } + CProfilerScope(const char *name) + { + this->name = name; + beginTime = g_profiler.Begin(name); + } - ~CProfilerScope() - { - g_profiler.End(name, beginTime); - } + ~CProfilerScope() + { + g_profiler.End(name, beginTime); + } protected: - const char *name; - double beginTime; + const char *name; + double beginTime; }; #define TimeIt(x) CProfilerScope profilescope(x) @@ -258,7 +258,7 @@ END_AS_NAMESPACE #else // !(_MSC_VER && AS_PROFILE) // Define it so nothing is done -#define TimeIt(x) +#define TimeIt(x) #endif // !(_MSC_VER && AS_PROFILE) diff --git a/src/angelscript/source/as_gc.cpp b/src/angelscript/source/as_gc.cpp index d6004e384ef..dd45d54d1f9 100644 --- a/src/angelscript/source/as_gc.cpp +++ b/src/angelscript/source/as_gc.cpp @@ -47,209 +47,209 @@ 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; - - circularRefDetectCallbackFunc = 0; - circularRefDetectCallbackParam = 0; + 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; + + circularRefDetectCallbackFunc = 0; + circularRefDetectCallbackParam = 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); + // 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; + 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, asITypeInfo **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; + 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 +// 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 - 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; + // 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 + 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 @@ -268,729 +268,729 @@ int asCGarbageCollector::GarbageCollect(asDWORD flags, asUINT iterations) // 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. + // 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( currentSize ) + *currentSize = (asUINT)(gcNewObjects.GetLength() + gcOldObjects.GetLength()); - if( totalDestroyed ) - *totalDestroyed = numDestroyed; + if( totalDestroyed ) + *totalDestroyed = numDestroyed; - if( totalDetected ) - *totalDetected = numDetected; + if( totalDetected ) + *totalDetected = numDetected; - if( newObjects ) - *newObjects = (asUINT)gcNewObjects.GetLength(); + if( newObjects ) + *newObjects = (asUINT)gcNewObjects.GetLength(); - if( totalNewDestroyed ) - *totalNewDestroyed = numNewDestroyed; + 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); + // 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; + 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); + // 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; + 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); + // 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); + // 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); + // 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); + // 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; + // 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 == "$func" ) - { - // 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 == "$obj" ) - { - msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast(gcObj.obj)->GetName()); - 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; + // 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 == "$func" ) + { + // 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 == "$obj" ) + { + msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast(gcObj.obj)->GetName()); + 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; + // 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; - - // If the application has requested a callback for detected circular references, - // then make that callback now for all the objects in the list. This step is not - // done in incremental steps as it is only meant for debugging purposes and thus - // doesn't require interactivity - if (gcMapCursor && circularRefDetectCallbackFunc) - { - while (gcMapCursor) - { - void *gcObj = gcMap.GetKey(gcMapCursor); - asCObjectType *type = gcMap.GetValue(gcMapCursor).type; - circularRefDetectCallbackFunc(type, gcObj, circularRefDetectCallbackParam); - - gcMap.MoveNext(&gcMapCursor, gcMapCursor); - } - - // Reset iterator - gcMap.MoveFirst(&gcMapCursor); - } - } - 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; + // 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; + + // If the application has requested a callback for detected circular references, + // then make that callback now for all the objects in the list. This step is not + // done in incremental steps as it is only meant for debugging purposes and thus + // doesn't require interactivity + if (gcMapCursor && circularRefDetectCallbackFunc) + { + while (gcMapCursor) + { + void *gcObj = gcMap.GetKey(gcMapCursor); + asCObjectType *type = gcMap.GetValue(gcMapCursor).type; + circularRefDetectCallbackFunc(type, gcObj, circularRefDetectCallbackParam); + + gcMap.MoveNext(&gcMapCursor, gcMapCursor); + } + + // Reset iterator + gcMap.MoveFirst(&gcMapCursor); + } + } + 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; + // 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); + // This function will only be called within the critical section gcCollecting + asASSERT(isProcessing); - if( node ) - freeNodes.PushLast(node); + 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); - } - } + // 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/src/angelscript/source/as_gc.h b/src/angelscript/source/as_gc.h index 76f27357a00..05aec010e90 100644 --- a/src/angelscript/source/as_gc.h +++ b/src/angelscript/source/as_gc.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2018 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -53,97 +53,97 @@ class asCObjectType; class asCGarbageCollector { public: - asCGarbageCollector(); - ~asCGarbageCollector(); + 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, asITypeInfo **type); + 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, asITypeInfo **type); - int ReportAndReleaseUndestroyedObjects(); + int ReportAndReleaseUndestroyedObjects(); - asCScriptEngine *engine; + asCScriptEngine *engine; - // Callback for when circular reference are detected - asCIRCULARREFFUNC_t circularRefDetectCallbackFunc; - void * circularRefDetectCallbackParam; + // Callback for when circular reference are detected + asCIRCULARREFFUNC_t circularRefDetectCallbackFunc; + void * circularRefDetectCallbackParam; 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 + 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 diff --git a/src/angelscript/source/as_generic.cpp b/src/angelscript/source/as_generic.cpp index 14dd9cb6f62..a57bda50090 100644 --- a/src/angelscript/source/as_generic.cpp +++ b/src/angelscript/source/as_generic.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2016 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -42,19 +42,19 @@ BEGIN_AS_NAMESPACE -// TODO: runtime optimize: The access to the arguments should be optimized so that code +// 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; + this->engine = engine; + this->sysFunction = sysFunction; + this->currentObject = currentObject; + this->stackPointer = stackPointer; + + objectRegister = 0; + returnVal = 0; } // internal @@ -65,470 +65,470 @@ asCGeneric::~asCGeneric() // interface void *asCGeneric::GetAuxiliary() const { - return sysFunction->GetAuxiliary(); + return sysFunction->GetAuxiliary(); } // interface asIScriptEngine *asCGeneric::GetEngine() const { - return (asIScriptEngine*)engine; + return (asIScriptEngine*)engine; } // interface asIScriptFunction *asCGeneric::GetFunction() const { - return sysFunction; + return sysFunction; } // interface void *asCGeneric::GetObject() { - return currentObject; + return currentObject; } // interface int asCGeneric::GetObjectTypeId() const { - asCDataType dt = asCDataType::CreateType(sysFunction->objectType, false); - return engine->GetTypeIdFromDataType(dt); + asCDataType dt = asCDataType::CreateType(sysFunction->objectType, false); + return engine->GetTypeIdFromDataType(dt); } // interface int asCGeneric::GetArgCount() const { - return (int)sysFunction->parameterTypes.GetLength(); + return (int)sysFunction->parameterTypes.GetLength(); } // interface asBYTE asCGeneric::GetArgByte(asUINT arg) { - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) - return 0; + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; - if( dt->GetSizeInMemoryBytes() != 1 ) - 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(); + // 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]; + // Get the value + return *(asBYTE*)&stackPointer[offset]; } // interface asWORD asCGeneric::GetArgWord(asUINT arg) { - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) - return 0; + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; - if( dt->GetSizeInMemoryBytes() != 2 ) - 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(); + // 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]; + // Get the value + return *(asWORD*)&stackPointer[offset]; } // interface asDWORD asCGeneric::GetArgDWord(asUINT arg) { - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) - return 0; + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; - if( dt->GetSizeInMemoryBytes() != 4 ) - 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(); + // 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]; + // Get the value + return *(asDWORD*)&stackPointer[offset]; } // interface asQWORD asCGeneric::GetArgQWord(asUINT arg) { - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) - return 0; + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; - if( dt->GetSizeInMemoryBytes() != 8 ) - 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(); + // 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]); + // Get the value + return *(asQWORD*)(&stackPointer[offset]); } // interface float asCGeneric::GetArgFloat(asUINT arg) { - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) - return 0; + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; - if( dt->GetSizeInMemoryBytes() != 4 ) - 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(); + // 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]); + // Get the value + return *(float*)(&stackPointer[offset]); } // interface double asCGeneric::GetArgDouble(asUINT arg) { - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) - return 0; + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; - if( dt->GetSizeInMemoryBytes() != 8 ) - 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(); + // 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]); + // Get the value + return *(double*)(&stackPointer[offset]); } // interface void *asCGeneric::GetArgAddress(asUINT arg) { - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; + 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; + // 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(); + // 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]); + // Get the value + return (void*)*(asPWORD*)(&stackPointer[offset]); } // interface void *asCGeneric::GetArgObject(asUINT arg) { - if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) - return 0; + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; - // Verify that the type is correct - asCDataType *dt = &sysFunction->parameterTypes[arg]; - if( !dt->IsObject() && !dt->IsFuncdef() ) - return 0; + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( !dt->IsObject() && !dt->IsFuncdef() ) + return 0; - // Determine the position of the argument - int offset = 0; - for( asUINT n = 0; n < arg; n++ ) - offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + // 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]); + // 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]; + 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]; - } + 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.IsFuncdef()) || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; - if( sysFunction->returnType.GetSizeInMemoryBytes() != 1 ) - return asINVALID_TYPE; + if( sysFunction->returnType.GetSizeInMemoryBytes() != 1 ) + return asINVALID_TYPE; - // Store the value - *(asBYTE*)&returnVal = val; + // Store the value + *(asBYTE*)&returnVal = val; - return 0; + return 0; } // interface int asCGeneric::SetReturnWord(asWORD val) { - // Verify the type of the return value - if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; - if( sysFunction->returnType.GetSizeInMemoryBytes() != 2 ) - return asINVALID_TYPE; + if( sysFunction->returnType.GetSizeInMemoryBytes() != 2 ) + return asINVALID_TYPE; - // Store the value - *(asWORD*)&returnVal = val; + // Store the value + *(asWORD*)&returnVal = val; - return 0; + return 0; } // interface int asCGeneric::SetReturnDWord(asDWORD val) { - // Verify the type of the return value - if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; - if( sysFunction->returnType.GetSizeInMemoryBytes() != 4 ) - return asINVALID_TYPE; + if( sysFunction->returnType.GetSizeInMemoryBytes() != 4 ) + return asINVALID_TYPE; - // Store the value - *(asDWORD*)&returnVal = val; + // Store the value + *(asDWORD*)&returnVal = val; - return 0; + return 0; } // interface int asCGeneric::SetReturnQWord(asQWORD val) { - // Verify the type of the return value - if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; - if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) - return asINVALID_TYPE; + if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) + return asINVALID_TYPE; - // Store the value - returnVal = val; + // Store the value + returnVal = val; - return 0; + return 0; } // interface int asCGeneric::SetReturnFloat(float val) { - // Verify the type of the return value - if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; - if( sysFunction->returnType.GetSizeOnStackDWords() != 1 ) - return asINVALID_TYPE; + if( sysFunction->returnType.GetSizeOnStackDWords() != 1 ) + return asINVALID_TYPE; - // Store the value - *(float*)&returnVal = val; + // Store the value + *(float*)&returnVal = val; - return 0; + return 0; } // interface int asCGeneric::SetReturnDouble(double val) { - // Verify the type of the return value - if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) - return asINVALID_TYPE; + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; - if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) - return asINVALID_TYPE; + if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) + return asINVALID_TYPE; - // Store the value - *(double*)&returnVal = val; + // Store the value + *(double*)&returnVal = val; - return 0; + 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; + // 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() && !dt->IsFuncdef() ) - return asINVALID_TYPE; - - if( dt->IsReference() ) - { - *(void**)&returnVal = obj; - return 0; - } - - if( dt->IsObjectHandle() ) - { - // Increase the reference counter - if (dt->IsFuncdef()) - { - if (obj) - reinterpret_cast(obj)->AddRef(); - } - else - { - asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh; - if (obj && beh && beh->addref) - engine->CallObjectMethod(obj, beh->addref); - } - } - else - { - // 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, CastToObjectType(dt->GetTypeInfo())); - return 0; - } - - objectRegister = obj; - - return 0; + asCDataType *dt = &sysFunction->returnType; + if( !dt->IsObject() && !dt->IsFuncdef() ) + return asINVALID_TYPE; + + if( dt->IsReference() ) + { + *(void**)&returnVal = obj; + return 0; + } + + if( dt->IsObjectHandle() ) + { + // Increase the reference counter + if (dt->IsFuncdef()) + { + if (obj) + reinterpret_cast(obj)->AddRef(); + } + else + { + asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh; + if (obj && beh && beh->addref) + engine->CallObjectMethod(obj, beh->addref); + } + } + else + { + // 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, CastToObjectType(dt->GetTypeInfo())); + return 0; + } + + objectRegister = obj; + + return 0; } // internal void *asCGeneric::GetReturnPointer() { - asCDataType &dt = sysFunction->returnType; + asCDataType &dt = sysFunction->returnType; - if( (dt.IsObject() ||dt.IsFuncdef()) && !dt.IsReference() ) - { - // This function doesn't support returning on the stack but the use of - // the function doesn't require it so we don't need to implement it here. - asASSERT( !sysFunction->DoesReturnOnStack() ); + if( (dt.IsObject() ||dt.IsFuncdef()) && !dt.IsReference() ) + { + // This function doesn't support returning on the stack but the use of + // the function doesn't require it so we don't need to implement it here. + asASSERT( !sysFunction->DoesReturnOnStack() ); - return &objectRegister; - } + return &objectRegister; + } - return &returnVal; + return &returnVal; } // interface void *asCGeneric::GetAddressOfReturnLocation() { - asCDataType &dt = sysFunction->returnType; - - if( (dt.IsObject() || dt.IsFuncdef()) && !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; + asCDataType &dt = sysFunction->returnType; + + if( (dt.IsObject() || dt.IsFuncdef()) && !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); + return sysFunction->GetReturnTypeId(flags); } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_generic.h b/src/angelscript/source/as_generic.h index 158d8f9c779..f9e03c17fd6 100644 --- a/src/angelscript/source/as_generic.h +++ b/src/angelscript/source/as_generic.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2015 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -52,55 +52,55 @@ class asCGeneric : public asIScriptGeneric //------------------------------ // asIScriptGeneric //------------------------------ - // Miscellaneous - asIScriptEngine *GetEngine() const; - asIScriptFunction *GetFunction() const; - void *GetAuxiliary() 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(); + // Miscellaneous + asIScriptEngine *GetEngine() const; + asIScriptFunction *GetFunction() const; + void *GetAuxiliary() 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(); + asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer); + virtual ~asCGeneric(); - void *GetReturnPointer(); + void *GetReturnPointer(); - asCScriptEngine *engine; - asCScriptFunction *sysFunction; - void *currentObject; - asDWORD *stackPointer; - void *objectRegister; + asCScriptEngine *engine; + asCScriptFunction *sysFunction; + void *currentObject; + asDWORD *stackPointer; + void *objectRegister; - asQWORD returnVal; + asQWORD returnVal; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_globalproperty.cpp b/src/angelscript/source/as_globalproperty.cpp index 3fe4627fbf0..10cdc49e589 100644 --- a/src/angelscript/source/as_globalproperty.cpp +++ b/src/angelscript/source/as_globalproperty.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2015 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -37,101 +37,101 @@ BEGIN_AS_NAMESPACE -asCGlobalProperty::asCGlobalProperty() -{ - memory = &storage; - memoryAllocated = false; - realAddress = 0; - initFunc = 0; - accessMask = 0xFFFFFFFF; +asCGlobalProperty::asCGlobalProperty() +{ + memory = &storage; + memoryAllocated = false; + realAddress = 0; + initFunc = 0; + accessMask = 0xFFFFFFFF; - refCount.set(1); + refCount.set(1); } asCGlobalProperty::~asCGlobalProperty() -{ +{ #ifndef WIP_16BYTE_ALIGNED - if( memoryAllocated ) { asDELETEARRAY(memory); } + if( memoryAllocated ) { asDELETEARRAY(memory); } #else - if( memoryAllocated ) { asDELETEARRAYALIGNED(memory); } + if( memoryAllocated ) { asDELETEARRAYALIGNED(memory); } #endif - if( initFunc ) - initFunc->ReleaseInternal(); + if( initFunc ) + initFunc->ReleaseInternal(); } void asCGlobalProperty::AddRef() { - refCount.atomicInc(); + refCount.atomicInc(); } void asCGlobalProperty::Release() { - if( refCount.atomicDec() == 0 ) - asDELETE(this, asCGlobalProperty); + if( refCount.atomicDec() == 0 ) + asDELETE(this, asCGlobalProperty); } void asCGlobalProperty::DestroyInternal() { - if( initFunc ) - { - initFunc->ReleaseInternal(); - initFunc = 0; - } + if( initFunc ) + { + initFunc->ReleaseInternal(); + initFunc = 0; + } } void *asCGlobalProperty::GetAddressOfValue() -{ - return memory; +{ + 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 ) - { +void asCGlobalProperty::AllocateMemory() +{ + if( type.GetSizeOnStackDWords() > 2 ) + { #ifndef WIP_16BYTE_ALIGNED - memory = asNEWARRAY(asDWORD, type.GetSizeOnStackDWords()); + 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()); + // 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; - } + 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::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; + return realAddress; } void asCGlobalProperty::SetInitFunc(asCScriptFunction *in_initFunc) { - // This should only be done once - asASSERT( initFunc == 0 ); + // This should only be done once + asASSERT( initFunc == 0 ); - initFunc = in_initFunc; - initFunc->AddRefInternal(); + initFunc = in_initFunc; + initFunc->AddRefInternal(); } asCScriptFunction *asCGlobalProperty::GetInitFunc() { - return initFunc; + return initFunc; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_map.h b/src/angelscript/source/as_map.h index c21037bd13f..c1218b035de 100644 --- a/src/angelscript/source/as_map.h +++ b/src/angelscript/source/as_map.h @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -44,50 +44,50 @@ template struct asSMapNode; template class asCMap { public: - asCMap(); - ~asCMap(); + 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); + int Insert(const KEY &key, const VAL &value); + int Insert(asSMapNode *node); + int GetCount() const; - void Erase(asSMapNode *cursor); - asSMapNode *Remove(asSMapNode *cursor); - void EraseAll(); + const KEY &GetKey(const asSMapNode *cursor) const; + const VAL &GetValue(const asSMapNode *cursor) const; + VAL &GetValue(asSMapNode *cursor); - void SwapWith(asCMap &other); + void Erase(asSMapNode *cursor); + asSMapNode *Remove(asSMapNode *cursor); + void EraseAll(); - // Returns true as long as cursor is valid + void SwapWith(asCMap &other); - 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; + // Returns true as long as cursor is valid - // For debugging only + 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; - int CheckIntegrity(asSMapNode *node) const; + // For debugging only + + int CheckIntegrity(asSMapNode *node) const; protected: - // Don't allow value assignment - asCMap &operator=(const asCMap &) { return *this; } + // Don't allow value assignment + asCMap &operator=(const asCMap &) { return *this; } - void BalanceInsert(asSMapNode *node); - void BalanceErase(asSMapNode *child, asSMapNode *parent); + void BalanceInsert(asSMapNode *node); + void BalanceErase(asSMapNode *child, asSMapNode *parent); - int EraseAll(asSMapNode *node); - int RotateLeft(asSMapNode *node); - int RotateRight(asSMapNode *node); + int EraseAll(asSMapNode *node); + int RotateLeft(asSMapNode *node); + int RotateRight(asSMapNode *node); - asSMapNode *root; - asSMapNode dummy; + asSMapNode *root; + asSMapNode dummy; - int count; + int count; }; //--------------------------------------------------------------------------- @@ -105,346 +105,346 @@ template class asCMap 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 = 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; + asSMapNode *parent; + asSMapNode *left; + asSMapNode *right; + bool isRed; - KEY key; - VAL value; + KEY key; + VAL value; }; template asCMap::asCMap() { - root = 0; - count = 0; + root = 0; + count = 0; } template asCMap::~asCMap() { - EraseAll(); + EraseAll(); } template void asCMap::SwapWith(asCMap &other) { - asSMapNode *tmpRoot = root; - int tmpCount = count; + asSMapNode *tmpRoot = root; + int tmpCount = count; - root = other.root; - count = other.count; + root = other.root; + count = other.count; - other.root = tmpRoot; - other.count = tmpCount; + other.root = tmpRoot; + other.count = tmpCount; } template void asCMap::EraseAll() { - EraseAll(root); - root = 0; + EraseAll(root); + root = 0; } template int asCMap::EraseAll(asSMapNode *p) { - if( p == 0 ) return -1; + if( p == 0 ) return -1; - EraseAll( p->left ); - EraseAll( p->right ); + EraseAll( p->left ); + EraseAll( p->right ); - typedef asSMapNode node_t; - asDELETE(p,node_t); + typedef asSMapNode node_t; + asDELETE(p,node_t); - count--; + count--; - return 0; + return 0; } template int asCMap::GetCount() const { - return count; + 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); + 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; + // 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; + // 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; + 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; + 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 ); + asSMapNode *node = Remove(cursor); + asASSERT( node == cursor ); - typedef asSMapNode node_t; - asDELETE(node,node_t); + 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; + 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 @@ -452,331 +452,331 @@ asSMapNode *asCMap::Remove(asSMapNode *cursor) template void asCMap::BalanceErase(asSMapNode *child, asSMapNode *parent) { - // If child is red - // Color child black - // Terminate + // If child is red + // Color child black + // Terminate - // These tests assume brother is to the right. + // These tests assume brother is to the right. - // 1. Brother is red - // Color parent red and brother black + // 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 - // 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; + // 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; + // 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; + // 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 +const VAL &asCMap::GetValue(const asSMapNode *cursor) const { - if( cursor == 0 ) - return dummy.value; + if( cursor == 0 ) + return dummy.value; - return cursor->value; + return cursor->value; } template -VAL &asCMap::GetValue(asSMapNode *cursor) +VAL &asCMap::GetValue(asSMapNode *cursor) { - if( cursor == 0 ) - return dummy.value; + if( cursor == 0 ) + return dummy.value; - return cursor->value; + return cursor->value; } template const KEY &asCMap::GetKey(const asSMapNode *cursor) const { - if( cursor == 0 ) - return dummy.key; + if( cursor == 0 ) + return dummy.key; - return cursor->key; + return cursor->key; } template bool asCMap::MoveFirst(asSMapNode **out) const { - *out = root; - if( root == 0 ) return false; + *out = root; + if( root == 0 ) return false; - while( (*out)->left ) - *out = (*out)->left; + while( (*out)->left ) + *out = (*out)->left; - return true; + return true; } template bool asCMap::MoveLast(asSMapNode **out) const { - *out = root; - if( root == 0 ) return false; + *out = root; + if( root == 0 ) return false; - while( (*out)->right ) - *out = (*out)->right; + while( (*out)->right ) + *out = (*out)->right; - return true; + 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; + 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 == 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; + 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; + cursor = cursor->parent; - *out = cursor; - if( cursor == 0 ) - return false; + *out = cursor; + if( cursor == 0 ) + return false; - return true; - } + return true; + } - cursor = cursor->left; - while( cursor->right ) - cursor = cursor->right; + cursor = cursor->left; + while( cursor->right ) + cursor = cursor->right; - *out = cursor; - return true; + *out = cursor; + return true; } diff --git a/src/angelscript/source/as_memory.cpp b/src/angelscript/source/as_memory.cpp index 5914658ba23..e53ea62398a 100644 --- a/src/angelscript/source/as_memory.cpp +++ b/src/angelscript/source/as_memory.cpp @@ -60,7 +60,7 @@ BEGIN_AS_NAMESPACE // 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 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) @@ -73,36 +73,36 @@ BEGIN_AS_NAMESPACE // 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); + 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)); + 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**)amem)[-1] = mem; + return amem; } void *alignedMalloc(size_t size, size_t align) { - void *mem = userAlloc(size + (align-1) + sizeof(void*)); + 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)); + 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**)amem)[-1] = mem; + return amem; } void alignedFree(void *mem) { - userFree( ((void**)mem)[-1] ); + userFree( ((void**)mem)[-1] ); } bool isAligned(const void* const pointer, asUINT alignment) { - return (uintptr_t(pointer) % alignment) == 0; + return (uintptr_t(pointer) % alignment) == 0; } #endif @@ -142,41 +142,41 @@ extern "C" // interface int asSetGlobalMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) { - // Clean-up thread local memory before changing the allocation routines to avoid - // potential problem with trying to free memory using a different allocation - // routine than used when allocating it. - asThreadCleanup(); + // Clean-up thread local memory before changing the allocation routines to avoid + // potential problem with trying to free memory using a different allocation + // routine than used when allocating it. + asThreadCleanup(); - userAlloc = allocFunc; - userFree = freeFunc; + userAlloc = allocFunc; + userFree = freeFunc; - return 0; + return 0; } // interface int asResetGlobalMemoryFunctions() { - // Clean-up thread local memory before changing the allocation routines to avoid - // potential problem with trying to free memory using a different allocation - // routine than used when allocating it. - asThreadCleanup(); + // Clean-up thread local memory before changing the allocation routines to avoid + // potential problem with trying to free memory using a different allocation + // routine than used when allocating it. + asThreadCleanup(); - userAlloc = malloc; - userFree = free; + userAlloc = malloc; + userFree = free; - return 0; + return 0; } // interface void *asAllocMem(size_t size) { - return asNEWARRAY(asBYTE, size); + return asNEWARRAY(asBYTE, size); } // interface void asFreeMem(void *mem) { - asDELETEARRAY(mem); + asDELETEARRAY(mem); } } // extern "C" @@ -187,96 +187,96 @@ asCMemoryMgr::asCMemoryMgr() asCMemoryMgr::~asCMemoryMgr() { - FreeUnusedMemory(); + 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); + // 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); + ENTERCRITICALSECTION(cs); - if( scriptNodePool.GetLength() ) - { - void *tRet = scriptNodePool.PopLast(); - LEAVECRITICALSECTION(cs); - return tRet; - } + if( scriptNodePool.GetLength() ) + { + void *tRet = scriptNodePool.PopLast(); + LEAVECRITICALSECTION(cs); + return tRet; + } - LEAVECRITICALSECTION(cs); + LEAVECRITICALSECTION(cs); -#if defined(AS_DEBUG) - return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCScriptNode), __FILE__, __LINE__); +#if defined(AS_DEBUG) + return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCScriptNode), __FILE__, __LINE__); #else - return userAlloc(sizeof(asCScriptNode)); + return userAlloc(sizeof(asCScriptNode)); #endif } void asCMemoryMgr::FreeScriptNode(void *ptr) { - ENTERCRITICALSECTION(cs); + ENTERCRITICALSECTION(cs); - // Pre allocate memory for the array to avoid slow growth - if( scriptNodePool.GetLength() == 0 ) - scriptNodePool.Allocate(100, 0); + // Pre allocate memory for the array to avoid slow growth + if( scriptNodePool.GetLength() == 0 ) + scriptNodePool.Allocate(100, 0); + + scriptNodePool.PushLast(ptr); - scriptNodePool.PushLast(ptr); - #ifdef AS_DEBUG - // clear the memory to facilitate identification of use after free - memset(ptr, 0xCDCDCDCD, sizeof(asCScriptNode)); + // clear the memory to facilitate identification of use after free + memset(ptr, 0xCDCDCDCD, sizeof(asCScriptNode)); #endif - LEAVECRITICALSECTION(cs); + LEAVECRITICALSECTION(cs); } #ifndef AS_NO_COMPILER void *asCMemoryMgr::AllocByteInstruction() { - // This doesn't need a critical section because, only one compilation is allowed at a time - - if( byteInstructionPool.GetLength() ) - return byteInstructionPool.PopLast(); + // This doesn't need a critical section because, only one compilation is allowed at a time + + if( byteInstructionPool.GetLength() ) + return byteInstructionPool.PopLast(); -#if defined(AS_DEBUG) - return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCByteInstruction), __FILE__, __LINE__); +#if defined(AS_DEBUG) + return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCByteInstruction), __FILE__, __LINE__); #else - return userAlloc(sizeof(asCByteInstruction)); + 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); + // Pre allocate memory for the array to avoid slow growth + if( byteInstructionPool.GetLength() == 0 ) + byteInstructionPool.Allocate(100, 0); + + byteInstructionPool.PushLast(ptr); - byteInstructionPool.PushLast(ptr); - #ifdef AS_DEBUG - // clear the memory to facilitate identification of use after free - memset(ptr, 0xCDCDCDCD, sizeof(asCByteInstruction)); + // clear the memory to facilitate identification of use after free + memset(ptr, 0xCDCDCDCD, sizeof(asCByteInstruction)); #endif } diff --git a/src/angelscript/source/as_memory.h b/src/angelscript/source/as_memory.h index 369af642b5e..ff44ae728f1 100644 --- a/src/angelscript/source/as_memory.h +++ b/src/angelscript/source/as_memory.h @@ -71,31 +71,31 @@ bool isAligned(const void* const pointer, asUINT alignment); #ifndef AS_DEBUG - #define asNEW(x) new(userAlloc(sizeof(x))) x - #define asDELETE(ptr,x) {void *tmp = ptr; (ptr)->~x(); userFree(tmp);} + #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) + #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) + #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); + 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 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) + #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) + //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 @@ -111,23 +111,23 @@ BEGIN_AS_NAMESPACE class asCMemoryMgr { public: - asCMemoryMgr(); - ~asCMemoryMgr(); + asCMemoryMgr(); + ~asCMemoryMgr(); - void FreeUnusedMemory(); + void FreeUnusedMemory(); - void *AllocScriptNode(); - void FreeScriptNode(void *ptr); + void *AllocScriptNode(); + void FreeScriptNode(void *ptr); #ifndef AS_NO_COMPILER - void *AllocByteInstruction(); - void FreeByteInstruction(void *ptr); + void *AllocByteInstruction(); + void FreeByteInstruction(void *ptr); #endif protected: - DECLARECRITICALSECTION(cs) - asCArray scriptNodePool; - asCArray byteInstructionPool; + DECLARECRITICALSECTION(cs) + asCArray scriptNodePool; + asCArray byteInstructionPool; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_module.cpp b/src/angelscript/source/as_module.cpp index 5ec55423c21..3cfe9c3d939 100644 --- a/src/angelscript/source/as_module.cpp +++ b/src/angelscript/source/as_module.cpp @@ -50,1827 +50,1827 @@ BEGIN_AS_NAMESPACE // internal asCModule::asCModule(const char *name, asCScriptEngine *engine) { - m_name = name; - m_engine = engine; + m_name = name; + m_engine = engine; - m_userData = 0; - m_builder = 0; - m_isGlobalVarInitialized = false; + m_userData = 0; + m_builder = 0; + m_isGlobalVarInitialized = false; - m_accessMask = 1; + m_accessMask = 1; - m_defaultNamespace = engine->nameSpaces[0]; + m_defaultNamespace = engine->nameSpaces[0]; } // internal asCModule::~asCModule() { - InternalReset(); - - // The builder is not removed by InternalReset because it holds the script - // sections that will be built, so we need to explictly remove it now if it exists - if( m_builder ) - { - asDELETE(m_builder,asCBuilder); - m_builder = 0; - } - - if( m_engine ) - { - // 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->cleanModuleFuncs.GetLength(); c++ ) - if( m_engine->cleanModuleFuncs[c].type == m_userData[n] ) - m_engine->cleanModuleFuncs[c].cleanFunc(this); - } - } - - // Remove the module from the engine - ACQUIREEXCLUSIVE(m_engine->engineRWLock); - // The module must have been discarded before it is deleted - asASSERT( !m_engine->scriptModules.Exists(this) ); - m_engine->discardedModules.RemoveValue(this); - RELEASEEXCLUSIVE(m_engine->engineRWLock); - } + InternalReset(); + + // The builder is not removed by InternalReset because it holds the script + // sections that will be built, so we need to explictly remove it now if it exists + if( m_builder ) + { + asDELETE(m_builder,asCBuilder); + m_builder = 0; + } + + if( m_engine ) + { + // 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->cleanModuleFuncs.GetLength(); c++ ) + if( m_engine->cleanModuleFuncs[c].type == m_userData[n] ) + m_engine->cleanModuleFuncs[c].cleanFunc(this); + } + } + + // Remove the module from the engine + ACQUIREEXCLUSIVE(m_engine->engineRWLock); + // The module must have been discarded before it is deleted + asASSERT( !m_engine->scriptModules.Exists(this) ); + m_engine->discardedModules.RemoveValue(this); + RELEASEEXCLUSIVE(m_engine->engineRWLock); + } } // interface void asCModule::Discard() { - // Reset the global variables already so that no object in the global variables keep the module alive forever. - // If any live object tries to access the global variables during clean up they will fail with a script exception, - // so the application must keep that in mind before discarding a module. - CallExit(); - - // Keep a local copy of the engine pointer, because once the module is moved do the discarded - // pile, it is possible that another thread might discard it while we are still in here. So no - // further access to members may be done after that - asCScriptEngine *engine = m_engine; - - // Instead of deleting the module immediately, move it to the discarded pile - // This will turn it invisible to the application, yet keep it alive until all - // external references to its entities have been released. - ACQUIREEXCLUSIVE(engine->engineRWLock); - if( engine->lastModule == this ) - engine->lastModule = 0; - engine->scriptModules.RemoveValue(this); - engine->discardedModules.PushLast(this); - RELEASEEXCLUSIVE(engine->engineRWLock); - - // Allow the engine to go over the list of discarded modules to see what can be cleaned up at this moment. - // Don't do this if the engine is already shutting down, as it will be done explicitly by the engine itself with error reporting - if( !engine->shuttingDown ) - { - if( engine->ep.autoGarbageCollect ) - engine->GarbageCollect(); - else - { - // GarbageCollect calls DeleteDiscardedModules, so no need - // to call it again if we already called GarbageCollect - engine->DeleteDiscardedModules(); - } - } + // Reset the global variables already so that no object in the global variables keep the module alive forever. + // If any live object tries to access the global variables during clean up they will fail with a script exception, + // so the application must keep that in mind before discarding a module. + CallExit(); + + // Keep a local copy of the engine pointer, because once the module is moved do the discarded + // pile, it is possible that another thread might discard it while we are still in here. So no + // further access to members may be done after that + asCScriptEngine *engine = m_engine; + + // Instead of deleting the module immediately, move it to the discarded pile + // This will turn it invisible to the application, yet keep it alive until all + // external references to its entities have been released. + ACQUIREEXCLUSIVE(engine->engineRWLock); + if( engine->lastModule == this ) + engine->lastModule = 0; + engine->scriptModules.RemoveValue(this); + engine->discardedModules.PushLast(this); + RELEASEEXCLUSIVE(engine->engineRWLock); + + // Allow the engine to go over the list of discarded modules to see what can be cleaned up at this moment. + // Don't do this if the engine is already shutting down, as it will be done explicitly by the engine itself with error reporting + if( !engine->shuttingDown ) + { + if( engine->ep.autoGarbageCollect ) + engine->GarbageCollect(); + else + { + // GarbageCollect calls DeleteDiscardedModules, so no need + // to call it again if we already called GarbageCollect + engine->DeleteDiscardedModules(); + } + } } // 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(m_engine->engineRWLock); + // 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); + // 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); + RELEASEEXCLUSIVE(m_engine->engineRWLock); - return oldData; - } - } + return oldData; + } + } - m_userData.PushLast(type); - m_userData.PushLast(reinterpret_cast(data)); + m_userData.PushLast(type); + m_userData.PushLast(reinterpret_cast(data)); - RELEASEEXCLUSIVE(m_engine->engineRWLock); + RELEASEEXCLUSIVE(m_engine->engineRWLock); - return 0; + 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(m_engine->engineRWLock); + // 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 ) - { - void *ud = reinterpret_cast(m_userData[n+1]); - RELEASESHARED(m_engine->engineRWLock); - return ud; - } - } + for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) + { + if( m_userData[n] == type ) + { + void *ud = reinterpret_cast(m_userData[n+1]); + RELEASESHARED(m_engine->engineRWLock); + return ud; + } + } - RELEASESHARED(m_engine->engineRWLock); + RELEASESHARED(m_engine->engineRWLock); - return 0; + return 0; } // interface asIScriptEngine *asCModule::GetEngine() const { - return m_engine; + return m_engine; } // interface void asCModule::SetName(const char *in_name) { - m_name = in_name; + m_name = in_name; } // interface const char *asCModule::GetName() const { - return m_name.AddressOf(); + return m_name.AddressOf(); } // interface const char *asCModule::GetDefaultNamespace() const { - return m_defaultNamespace->name.AddressOf(); + return m_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; + // 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; + 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 = m_engine->tok.GetToken(ns.AddressOf() + pos, ns.GetLength() - pos, &len); - if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) ) - return asINVALID_DECLARATION; + for( ; pos < ns.GetLength(); pos += len ) + { + t = m_engine->tok.GetToken(ns.AddressOf() + pos, ns.GetLength() - pos, &len); + if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) ) + return asINVALID_DECLARATION; - expectIdentifier = !expectIdentifier; - } + expectIdentifier = !expectIdentifier; + } - // If the namespace ends with :: then strip it off - if( t == ttScope ) - ns.SetLength(ns.GetLength()-2); - } + // If the namespace ends with :: then strip it off + if( t == ttScope ) + ns.SetLength(ns.GetLength()-2); + } - m_defaultNamespace = m_engine->AddNameSpace(ns.AddressOf()); + m_defaultNamespace = m_engine->AddNameSpace(ns.AddressOf()); - return 0; + return 0; } // interface int asCModule::AddScriptSection(const char *in_name, const char *in_code, size_t in_codeLength, int in_lineOffset) { #ifdef AS_NO_COMPILER - UNUSED_VAR(in_name); - UNUSED_VAR(in_code); - UNUSED_VAR(in_codeLength); - UNUSED_VAR(in_lineOffset); - return asNOT_SUPPORTED; + UNUSED_VAR(in_name); + UNUSED_VAR(in_code); + UNUSED_VAR(in_codeLength); + UNUSED_VAR(in_lineOffset); + return asNOT_SUPPORTED; #else - if( !m_builder ) - { - m_builder = asNEW(asCBuilder)(m_engine, this); - if( m_builder == 0 ) - return asOUT_OF_MEMORY; - } - - return m_builder->AddCode(in_name, in_code, (int)in_codeLength, in_lineOffset, (int)m_engine->GetScriptSectionNameIndex(in_name ? in_name : ""), m_engine->ep.copyScriptSections); + if( !m_builder ) + { + m_builder = asNEW(asCBuilder)(m_engine, this); + if( m_builder == 0 ) + return asOUT_OF_MEMORY; + } + + return m_builder->AddCode(in_name, in_code, (int)in_codeLength, in_lineOffset, (int)m_engine->GetScriptSectionNameIndex(in_name ? in_name : ""), m_engine->ep.copyScriptSections); #endif } // internal void asCModule::JITCompile() { - asIJITCompiler *jit = m_engine->GetJITCompiler(); - if( !jit ) - return; + asIJITCompiler *jit = m_engine->GetJITCompiler(); + if( !jit ) + return; - for (unsigned int i = 0; i < m_scriptFunctions.GetLength(); i++) - m_scriptFunctions[i]->JITCompile(); + for (unsigned int i = 0; i < m_scriptFunctions.GetLength(); i++) + m_scriptFunctions[i]->JITCompile(); } // interface int asCModule::Build() { #ifdef AS_NO_COMPILER - return asNOT_SUPPORTED; + return asNOT_SUPPORTED; #else - TimeIt("asCModule::Build"); - - // Don't allow the module to be rebuilt if there are still - // external references that will need the previous code - // TODO: interface: The asIScriptModule must have a method for querying if the module is used - if( HasExternalReferences(false) ) - { - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE); - return asMODULE_IS_IN_USE; - } - - // Only one thread may build at one time - // TODO: It should be possible to have multiple threads perform compilations - int r = m_engine->RequestBuild(); - if( r < 0 ) - return r; - - m_engine->PrepareEngine(); - if( m_engine->configFailed ) - { - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); - m_engine->BuildCompleted(); - return asINVALID_CONFIGURATION; - } - - InternalReset(); - - if( !m_builder ) - { - m_engine->BuildCompleted(); - return asSUCCESS; - } - - // Compile the script - r = m_builder->Build(); - asDELETE(m_builder,asCBuilder); - m_builder = 0; - - if( r < 0 ) - { - // Reset module again - InternalReset(); - - m_engine->BuildCompleted(); - return r; - } - - JITCompile(); - - m_engine->PrepareEngine(); + TimeIt("asCModule::Build"); + + // Don't allow the module to be rebuilt if there are still + // external references that will need the previous code + // TODO: interface: The asIScriptModule must have a method for querying if the module is used + if( HasExternalReferences(false) ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE); + return asMODULE_IS_IN_USE; + } + + // Only one thread may build at one time + // TODO: It should be possible to have multiple threads perform compilations + int r = m_engine->RequestBuild(); + if( r < 0 ) + return r; + + m_engine->PrepareEngine(); + if( m_engine->configFailed ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); + m_engine->BuildCompleted(); + return asINVALID_CONFIGURATION; + } + + InternalReset(); + + if( !m_builder ) + { + m_engine->BuildCompleted(); + return asSUCCESS; + } + + // Compile the script + r = m_builder->Build(); + asDELETE(m_builder,asCBuilder); + m_builder = 0; + + if( r < 0 ) + { + // Reset module again + InternalReset(); + + m_engine->BuildCompleted(); + return r; + } + + JITCompile(); + + m_engine->PrepareEngine(); #ifdef AS_DEBUG - // Verify that there are no unwanted gaps in the scriptFunctions array. - for( asUINT n = 1; n < m_engine->scriptFunctions.GetLength(); n++ ) - { - int id = n; - if( m_engine->scriptFunctions[n] == 0 && !m_engine->freeScriptFunctionIds.Exists(id) ) - asASSERT( false ); - } + // Verify that there are no unwanted gaps in the scriptFunctions array. + for( asUINT n = 1; n < m_engine->scriptFunctions.GetLength(); n++ ) + { + int id = n; + if( m_engine->scriptFunctions[n] == 0 && !m_engine->freeScriptFunctionIds.Exists(id) ) + asASSERT( false ); + } #endif - m_engine->BuildCompleted(); + m_engine->BuildCompleted(); - // Initialize global variables - if( r >= 0 && m_engine->ep.initGlobalVarsAfterBuild ) - r = ResetGlobalVars(0); + // Initialize global variables + if( r >= 0 && m_engine->ep.initGlobalVarsAfterBuild ) + r = ResetGlobalVars(0); - return r; + return r; #endif } // interface int asCModule::ResetGlobalVars(asIScriptContext *ctx) { - if( m_isGlobalVarInitialized ) - CallExit(); + if( m_isGlobalVarInitialized ) + CallExit(); - return CallInit(ctx); + return CallInit(ctx); } // interface asIScriptFunction *asCModule::GetFunctionByIndex(asUINT index) const { - return const_cast(m_globalFunctions.Get(index)); + return const_cast(m_globalFunctions.Get(index)); } // internal int asCModule::CallInit(asIScriptContext *myCtx) { - if( m_isGlobalVarInitialized ) - return asERROR; - - // Each global variable needs to be cleared individually - asCSymbolTableIterator it = m_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 = m_scriptGlobals.List(); - while( it && r == asEXECUTION_FINISHED ) - { - asCGlobalProperty *desc = *it; - it++; - if( desc->GetInitFunc() ) - { - if( ctx == 0 ) - { - ctx = m_engine->RequestContext(); - if( ctx == 0 ) - break; - } - - r = InitGlobalProp(desc, ctx); - } - } - - if( ctx && !myCtx ) - { - m_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. - m_isGlobalVarInitialized = true; - - if( r != asEXECUTION_FINISHED ) - return asINIT_GLOBAL_VARS_FAILED; - - return asSUCCESS; + if( m_isGlobalVarInitialized ) + return asERROR; + + // Each global variable needs to be cleared individually + asCSymbolTableIterator it = m_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 = m_scriptGlobals.List(); + while( it && r == asEXECUTION_FINISHED ) + { + asCGlobalProperty *desc = *it; + it++; + if( desc->GetInitFunc() ) + { + if( ctx == 0 ) + { + ctx = m_engine->RequestContext(); + if( ctx == 0 ) + break; + } + + r = InitGlobalProp(desc, ctx); + } + } + + if( ctx && !myCtx ) + { + m_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. + m_isGlobalVarInitialized = true; + + if( r != asEXECUTION_FINISHED ) + return asINIT_GLOBAL_VARS_FAILED; + + return asSUCCESS; } // internal // This function assumes the memory for the global property is already cleared int asCModule::InitGlobalProp(asCGlobalProperty *prop, asIScriptContext *myCtx) { - // Call the init function for each of the global variables - asIScriptContext *ctx = myCtx; - int r = asEXECUTION_FINISHED; - if( prop->GetInitFunc() ) - { - if( ctx == 0 ) - { - ctx = m_engine->RequestContext(); - if( ctx == 0 ) - return asERROR; - } - - r = ctx->Prepare(prop->GetInitFunc()); - if( r >= 0 ) - { - r = ctx->Execute(); - if( r != asEXECUTION_FINISHED ) - { - asCString msg; - msg.Format(TXT_FAILED_TO_INITIALIZE_s, prop->name.AddressOf()); - asCScriptFunction *func = prop->GetInitFunc(); - - m_engine->WriteMessage(func->scriptData->scriptSectionIdx >= 0 ? m_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()); - - m_engine->WriteMessage(function->GetScriptSectionName(), - ctx->GetExceptionLineNumber(), - 0, - asMSGTYPE_INFORMATION, - msg.AddressOf()); - } - } - } - } - - if( ctx && !myCtx ) - { - m_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. - m_isGlobalVarInitialized = true; - - if( r != asEXECUTION_FINISHED ) - return asINIT_GLOBAL_VARS_FAILED; - - return asSUCCESS; + // Call the init function for each of the global variables + asIScriptContext *ctx = myCtx; + int r = asEXECUTION_FINISHED; + if( prop->GetInitFunc() ) + { + if( ctx == 0 ) + { + ctx = m_engine->RequestContext(); + if( ctx == 0 ) + return asERROR; + } + + r = ctx->Prepare(prop->GetInitFunc()); + if( r >= 0 ) + { + r = ctx->Execute(); + if( r != asEXECUTION_FINISHED ) + { + asCString msg; + msg.Format(TXT_FAILED_TO_INITIALIZE_s, prop->name.AddressOf()); + asCScriptFunction *func = prop->GetInitFunc(); + + m_engine->WriteMessage(func->scriptData->scriptSectionIdx >= 0 ? m_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()); + + m_engine->WriteMessage(function->GetScriptSectionName(), + ctx->GetExceptionLineNumber(), + 0, + asMSGTYPE_INFORMATION, + msg.AddressOf()); + } + } + } + } + + if( ctx && !myCtx ) + { + m_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. + m_isGlobalVarInitialized = true; + + if( r != asEXECUTION_FINISHED ) + return asINIT_GLOBAL_VARS_FAILED; + + return asSUCCESS; } // internal void asCModule::UninitializeGlobalProp(asCGlobalProperty *prop) { - if (prop == 0) - return; - - if (prop->type.IsObject()) - { - void **obj = (void**)prop->GetAddressOfValue(); - if (*obj) - { - asCObjectType *ot = CastToObjectType(prop->type.GetTypeInfo()); - - if (ot->flags & asOBJ_REF) - { - asASSERT((ot->flags & asOBJ_NOCOUNT) || ot->beh.release); - if (ot->beh.release) - m_engine->CallObjectMethod(*obj, ot->beh.release); - } - else - { - if (ot->beh.destruct) - m_engine->CallObjectMethod(*obj, ot->beh.destruct); - - m_engine->CallFree(*obj); - } - - // Set the address to 0 as someone might try to access the variable afterwards - *obj = 0; - } - } - else if (prop->type.IsFuncdef()) - { - asCScriptFunction **func = (asCScriptFunction**)prop->GetAddressOfValue(); - if (*func) - { - (*func)->Release(); - *func = 0; - } - } + if (prop == 0) + return; + + if (prop->type.IsObject()) + { + void **obj = (void**)prop->GetAddressOfValue(); + if (*obj) + { + asCObjectType *ot = CastToObjectType(prop->type.GetTypeInfo()); + + if (ot->flags & asOBJ_REF) + { + asASSERT((ot->flags & asOBJ_NOCOUNT) || ot->beh.release); + if (ot->beh.release) + m_engine->CallObjectMethod(*obj, ot->beh.release); + } + else + { + if (ot->beh.destruct) + m_engine->CallObjectMethod(*obj, ot->beh.destruct); + + m_engine->CallFree(*obj); + } + + // Set the address to 0 as someone might try to access the variable afterwards + *obj = 0; + } + } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **func = (asCScriptFunction**)prop->GetAddressOfValue(); + if (*func) + { + (*func)->Release(); + *func = 0; + } + } } // internal void asCModule::CallExit() { - if( !m_isGlobalVarInitialized ) return; + if( !m_isGlobalVarInitialized ) return; - asCSymbolTableIterator it = m_scriptGlobals.List(); - while( it ) - { - UninitializeGlobalProp(*it); - it++; - } + asCSymbolTableIterator it = m_scriptGlobals.List(); + while( it ) + { + UninitializeGlobalProp(*it); + it++; + } - m_isGlobalVarInitialized = false; + m_isGlobalVarInitialized = false; } // internal bool asCModule::HasExternalReferences(bool shuttingDown) { - // Check all entities in the module for any external references. - // If there are any external references the module cannot be deleted yet. - - asCSymbolTableIterator it = m_scriptGlobals.List(); - while (it) - { - asCGlobalProperty *desc = *it; - if (desc->GetInitFunc() && desc->GetInitFunc()->externalRefCount.get()) - { - if( !shuttingDown ) - return true; - else - { - asCString msg; - msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); - - // TODO: Use a better error message - asCString tmpName = "init " + desc->name; - msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, tmpName.AddressOf(), desc->GetInitFunc()->GetFuncType()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); - } - } - it++; - } - - for (asUINT n = 0; n < m_scriptFunctions.GetLength(); n++) - { - asCScriptFunction *func = m_scriptFunctions[n]; - if (func && func->externalRefCount.get()) - { - // If the func is shared and can be moved to another module then this is not a reason to keep the module alive - if (func->IsShared() && m_engine->FindNewOwnerForSharedFunc(func, this) != this) - continue; - - if (!shuttingDown) - return true; - else - { - asCString msg; - msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); - - msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, m_scriptFunctions[n]->GetName(), m_scriptFunctions[n]->GetFuncType()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); - } - } - } - - for (asUINT n = 0; n < m_classTypes.GetLength(); n++) - { - asCObjectType *obj = m_classTypes[n]; - if (obj && obj->externalRefCount.get()) - { - // If the obj is shared and can be moved to another module then this is not a reason to keep the module alive - if (obj->IsShared() && m_engine->FindNewOwnerForSharedType(obj, this) != this) - continue; - - if (!shuttingDown) - return true; - else - { - asCString msg; - msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); - - msg.Format(TXT_PREV_TYPE_IS_NAMED_s, m_classTypes[n]->GetName()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); - } - } - } - - for (asUINT n = 0; n < m_funcDefs.GetLength(); n++) - { - asCFuncdefType *func = m_funcDefs[n]; - if (func && func->externalRefCount.get()) - { - // If the funcdef is shared and can be moved to another module then this is not a reason to keep the module alive - if (func->IsShared() && m_engine->FindNewOwnerForSharedType(func, this) != this) - continue; - - if (!shuttingDown) - return true; - else - { - asCString msg; - msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); - - msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, m_funcDefs[n]->GetName(), m_funcDefs[n]->funcdef->GetFuncType()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); - } - } - } - - for (asUINT n = 0; n < m_templateInstances.GetLength(); n++) - { - asCObjectType *obj = m_templateInstances[n]; - if (obj && obj->externalRefCount.get()) - { - // If the template can be moved to another module then this is not a reason to keep the module alive - if (obj->IsShared() && m_engine->FindNewOwnerForSharedType(obj, this) != this) - continue; - - if (!shuttingDown) - return true; - else - { - asCString msg; - msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); - - msg.Format(TXT_PREV_TYPE_IS_NAMED_s, m_templateInstances[n]->GetName()); - m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); - } - } - } - - return false; + // Check all entities in the module for any external references. + // If there are any external references the module cannot be deleted yet. + + asCSymbolTableIterator it = m_scriptGlobals.List(); + while (it) + { + asCGlobalProperty *desc = *it; + if (desc->GetInitFunc() && desc->GetInitFunc()->externalRefCount.get()) + { + if( !shuttingDown ) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + // TODO: Use a better error message + asCString tmpName = "init " + desc->name; + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, tmpName.AddressOf(), desc->GetInitFunc()->GetFuncType()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + it++; + } + + for (asUINT n = 0; n < m_scriptFunctions.GetLength(); n++) + { + asCScriptFunction *func = m_scriptFunctions[n]; + if (func && func->externalRefCount.get()) + { + // If the func is shared and can be moved to another module then this is not a reason to keep the module alive + if (func->IsShared() && m_engine->FindNewOwnerForSharedFunc(func, this) != this) + continue; + + if (!shuttingDown) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, m_scriptFunctions[n]->GetName(), m_scriptFunctions[n]->GetFuncType()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + } + + for (asUINT n = 0; n < m_classTypes.GetLength(); n++) + { + asCObjectType *obj = m_classTypes[n]; + if (obj && obj->externalRefCount.get()) + { + // If the obj is shared and can be moved to another module then this is not a reason to keep the module alive + if (obj->IsShared() && m_engine->FindNewOwnerForSharedType(obj, this) != this) + continue; + + if (!shuttingDown) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + msg.Format(TXT_PREV_TYPE_IS_NAMED_s, m_classTypes[n]->GetName()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + } + + for (asUINT n = 0; n < m_funcDefs.GetLength(); n++) + { + asCFuncdefType *func = m_funcDefs[n]; + if (func && func->externalRefCount.get()) + { + // If the funcdef is shared and can be moved to another module then this is not a reason to keep the module alive + if (func->IsShared() && m_engine->FindNewOwnerForSharedType(func, this) != this) + continue; + + if (!shuttingDown) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, m_funcDefs[n]->GetName(), m_funcDefs[n]->funcdef->GetFuncType()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + } + + for (asUINT n = 0; n < m_templateInstances.GetLength(); n++) + { + asCObjectType *obj = m_templateInstances[n]; + if (obj && obj->externalRefCount.get()) + { + // If the template can be moved to another module then this is not a reason to keep the module alive + if (obj->IsShared() && m_engine->FindNewOwnerForSharedType(obj, this) != this) + continue; + + if (!shuttingDown) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + msg.Format(TXT_PREV_TYPE_IS_NAMED_s, m_templateInstances[n]->GetName()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + } + + return false; } // internal void asCModule::InternalReset() { - CallExit(); - - asUINT n; - - // Remove all global functions - m_globalFunctions.Clear(); - - // Destroy the internals of the global properties here, but do not yet remove them from the - // engine, because functions need the engine's varAddressMap to get to the property. If the - // property is removed already, it may leak as the refCount doesn't reach 0. - asCSymbolTableIterator globIt = m_scriptGlobals.List(); - while( globIt ) - { - (*globIt)->DestroyInternal(); - globIt++; - } - - UnbindAllImportedFunctions(); - - // Free bind information - for( n = 0; n < m_bindInformations.GetLength(); n++ ) - { - if( m_bindInformations[n] ) - { - m_bindInformations[n]->importedFunctionSignature->ReleaseInternal(); - - asDELETE(m_bindInformations[n], sBindInfo); - } - } - m_bindInformations.SetLength(0); - - // Free declared types, including classes, typedefs, and enums - for( n = 0; n < m_templateInstances.GetLength(); n++ ) - { - asCObjectType *type = m_templateInstances[n]; - if( m_engine->FindNewOwnerForSharedType(type, this) != this ) - { - // The type is owned by another module, just release our reference - type->ReleaseInternal(); - continue; - } - - // Orphan the template instance - type->module = 0; - - // No other module is holding the template type - m_engine->RemoveTemplateInstanceType(type); - type->ReleaseInternal(); - } - m_templateInstances.SetLength(0); - for( n = 0; n < m_classTypes.GetLength(); n++ ) - { - asCObjectType *type = m_classTypes[n]; - if( type->IsShared() ) - { - // The type is shared, so transfer ownership to another module that also uses it - if( m_engine->FindNewOwnerForSharedType(type, this) != this ) - { - // The type is owned by another module, just release our reference - type->ReleaseInternal(); - continue; - } - } - - // The type should be destroyed now - type->DestroyInternal(); - - // Remove the type from the engine - if( type->IsShared() ) - { - m_engine->sharedScriptTypes.RemoveValue(type); - type->ReleaseInternal(); - } - - // Release it from the module - type->module = 0; - type->ReleaseInternal(); - } - m_classTypes.SetLength(0); - for( n = 0; n < m_enumTypes.GetLength(); n++ ) - { - asCEnumType *type = m_enumTypes[n]; - if( type->IsShared() ) - { - // The type is shared, so transfer ownership to another module that also uses it - if( m_engine->FindNewOwnerForSharedType(type, this) != this ) - { - // The type is owned by another module, just release our reference - type->ReleaseInternal(); - continue; - } - } - - // Remove the type from the engine - if( type->IsShared() ) - { - m_engine->sharedScriptTypes.RemoveValue(type); - type->ReleaseInternal(); - } - - // Release it from the module - type->module = 0; - type->ReleaseInternal(); - } - m_enumTypes.SetLength(0); - for( n = 0; n < m_typeDefs.GetLength(); n++ ) - { - asCTypedefType *type = m_typeDefs[n]; - - // The type should be destroyed now - type->DestroyInternal(); - - // Release it from the module - type->module = 0; - type->ReleaseInternal(); - } - m_typeDefs.SetLength(0); - - // Free funcdefs - for( n = 0; n < m_funcDefs.GetLength(); n++ ) - { - asCFuncdefType *func = m_funcDefs[n]; - asASSERT(func); - if( func->funcdef && func->funcdef->IsShared() ) - { - // The funcdef is shared, so transfer ownership to another module that also uses it - if( m_engine->FindNewOwnerForSharedType(func, this) != this ) - { - // The funcdef is owned by another module, just release our reference - func->ReleaseInternal(); - continue; - } - } - - func->DestroyInternal(); - m_engine->RemoveFuncdef(func); - func->module = 0; - func->ReleaseInternal(); - } - m_funcDefs.SetLength(0); - - // Then release the functions - for( n = 0; n < m_scriptFunctions.GetLength(); n++ ) - { - asCScriptFunction *func = m_scriptFunctions[n]; - if( func->IsShared() ) - { - // The func is shared, so transfer ownership to another module that also uses it - if( m_engine->FindNewOwnerForSharedFunc(func, this) != this ) - { - // The func is owned by another module, just release our reference - func->ReleaseInternal(); - continue; - } - } - - func->DestroyInternal(); - func->module = 0; - func->ReleaseInternal(); - } - m_scriptFunctions.SetLength(0); - - // Now remove and release the global properties as there are no more references to them - globIt = m_scriptGlobals.List(); - while( globIt ) - { - m_engine->RemoveGlobalProperty(*globIt); - asASSERT( (*globIt)->refCount.get() == 1 ); - (*globIt)->Release(); - globIt++; - } - m_scriptGlobals.Clear(); - - // Clear the type lookup - // The references were already released as the types were removed from the respective arrays - m_typeLookup.EraseAll(); - - asASSERT( IsEmpty() ); + CallExit(); + + asUINT n; + + // Remove all global functions + m_globalFunctions.Clear(); + + // Destroy the internals of the global properties here, but do not yet remove them from the + // engine, because functions need the engine's varAddressMap to get to the property. If the + // property is removed already, it may leak as the refCount doesn't reach 0. + asCSymbolTableIterator globIt = m_scriptGlobals.List(); + while( globIt ) + { + (*globIt)->DestroyInternal(); + globIt++; + } + + UnbindAllImportedFunctions(); + + // Free bind information + for( n = 0; n < m_bindInformations.GetLength(); n++ ) + { + if( m_bindInformations[n] ) + { + m_bindInformations[n]->importedFunctionSignature->ReleaseInternal(); + + asDELETE(m_bindInformations[n], sBindInfo); + } + } + m_bindInformations.SetLength(0); + + // Free declared types, including classes, typedefs, and enums + for( n = 0; n < m_templateInstances.GetLength(); n++ ) + { + asCObjectType *type = m_templateInstances[n]; + if( m_engine->FindNewOwnerForSharedType(type, this) != this ) + { + // The type is owned by another module, just release our reference + type->ReleaseInternal(); + continue; + } + + // Orphan the template instance + type->module = 0; + + // No other module is holding the template type + m_engine->RemoveTemplateInstanceType(type); + type->ReleaseInternal(); + } + m_templateInstances.SetLength(0); + for( n = 0; n < m_classTypes.GetLength(); n++ ) + { + asCObjectType *type = m_classTypes[n]; + if( type->IsShared() ) + { + // The type is shared, so transfer ownership to another module that also uses it + if( m_engine->FindNewOwnerForSharedType(type, this) != this ) + { + // The type is owned by another module, just release our reference + type->ReleaseInternal(); + continue; + } + } + + // The type should be destroyed now + type->DestroyInternal(); + + // Remove the type from the engine + if( type->IsShared() ) + { + m_engine->sharedScriptTypes.RemoveValue(type); + type->ReleaseInternal(); + } + + // Release it from the module + type->module = 0; + type->ReleaseInternal(); + } + m_classTypes.SetLength(0); + for( n = 0; n < m_enumTypes.GetLength(); n++ ) + { + asCEnumType *type = m_enumTypes[n]; + if( type->IsShared() ) + { + // The type is shared, so transfer ownership to another module that also uses it + if( m_engine->FindNewOwnerForSharedType(type, this) != this ) + { + // The type is owned by another module, just release our reference + type->ReleaseInternal(); + continue; + } + } + + // Remove the type from the engine + if( type->IsShared() ) + { + m_engine->sharedScriptTypes.RemoveValue(type); + type->ReleaseInternal(); + } + + // Release it from the module + type->module = 0; + type->ReleaseInternal(); + } + m_enumTypes.SetLength(0); + for( n = 0; n < m_typeDefs.GetLength(); n++ ) + { + asCTypedefType *type = m_typeDefs[n]; + + // The type should be destroyed now + type->DestroyInternal(); + + // Release it from the module + type->module = 0; + type->ReleaseInternal(); + } + m_typeDefs.SetLength(0); + + // Free funcdefs + for( n = 0; n < m_funcDefs.GetLength(); n++ ) + { + asCFuncdefType *func = m_funcDefs[n]; + asASSERT(func); + if( func->funcdef && func->funcdef->IsShared() ) + { + // The funcdef is shared, so transfer ownership to another module that also uses it + if( m_engine->FindNewOwnerForSharedType(func, this) != this ) + { + // The funcdef is owned by another module, just release our reference + func->ReleaseInternal(); + continue; + } + } + + func->DestroyInternal(); + m_engine->RemoveFuncdef(func); + func->module = 0; + func->ReleaseInternal(); + } + m_funcDefs.SetLength(0); + + // Then release the functions + for( n = 0; n < m_scriptFunctions.GetLength(); n++ ) + { + asCScriptFunction *func = m_scriptFunctions[n]; + if( func->IsShared() ) + { + // The func is shared, so transfer ownership to another module that also uses it + if( m_engine->FindNewOwnerForSharedFunc(func, this) != this ) + { + // The func is owned by another module, just release our reference + func->ReleaseInternal(); + continue; + } + } + + func->DestroyInternal(); + func->module = 0; + func->ReleaseInternal(); + } + m_scriptFunctions.SetLength(0); + + // Now remove and release the global properties as there are no more references to them + globIt = m_scriptGlobals.List(); + while( globIt ) + { + m_engine->RemoveGlobalProperty(*globIt); + asASSERT( (*globIt)->refCount.get() == 1 ); + (*globIt)->Release(); + globIt++; + } + m_scriptGlobals.Clear(); + + // Clear the type lookup + // The references were already released as the types were removed from the respective arrays + m_typeLookup.EraseAll(); + + asASSERT( IsEmpty() ); } // interface asIScriptFunction *asCModule::GetFunctionByName(const char *in_name) const { - asCString name; - asSNameSpace *ns = 0; - if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) - return 0; - - // Search recursively in the given namespace, moving up to parent namespace until the function is found - while( ns ) - { - const asCArray &idxs = m_globalFunctions.GetIndexes(ns, name); - if( idxs.GetLength() != 1 ) - return 0; + asCString name; + asSNameSpace *ns = 0; + if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) + return 0; - const asIScriptFunction *func = m_globalFunctions.Get(idxs[0]); - if( func ) - return const_cast(func); + // Search recursively in the given namespace, moving up to parent namespace until the function is found + while( ns ) + { + const asCArray &idxs = m_globalFunctions.GetIndexes(ns, name); + if( idxs.GetLength() != 1 ) + return 0; - // Recursively search parent namespaces - ns = m_engine->GetParentNameSpace(ns); - } + const asIScriptFunction *func = m_globalFunctions.Get(idxs[0]); + if( func ) + return const_cast(func); - return 0; + // Recursively search parent namespaces + ns = m_engine->GetParentNameSpace(ns); + } + + return 0; } // interface asUINT asCModule::GetImportedFunctionCount() const { - return (asUINT)m_bindInformations.GetLength(); + return (asUINT)m_bindInformations.GetLength(); } // interface int asCModule::GetImportedFunctionIndexByDecl(const char *decl) const { - asCBuilder bld(m_engine, const_cast(this)); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCScriptFunction func(m_engine, const_cast(this), asFUNC_DUMMY); - bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, m_defaultNamespace); - - // TODO: optimize: Improve linear search - // Search script functions for matching interface - int id = -1; - for( asUINT n = 0; n < m_bindInformations.GetLength(); ++n ) - { - if( func.name == m_bindInformations[n]->importedFunctionSignature->name && - func.returnType == m_bindInformations[n]->importedFunctionSignature->returnType && - func.parameterTypes.GetLength() == m_bindInformations[n]->importedFunctionSignature->parameterTypes.GetLength() ) - { - bool match = true; - for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p ) - { - if( func.parameterTypes[p] != m_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; + asCBuilder bld(m_engine, const_cast(this)); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCScriptFunction func(m_engine, const_cast(this), asFUNC_DUMMY); + bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, m_defaultNamespace); + + // TODO: optimize: Improve linear search + // Search script functions for matching interface + int id = -1; + for( asUINT n = 0; n < m_bindInformations.GetLength(); ++n ) + { + if( func.name == m_bindInformations[n]->importedFunctionSignature->name && + func.returnType == m_bindInformations[n]->importedFunctionSignature->returnType && + func.parameterTypes.GetLength() == m_bindInformations[n]->importedFunctionSignature->parameterTypes.GetLength() ) + { + bool match = true; + for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p ) + { + if( func.parameterTypes[p] != m_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)m_globalFunctions.GetSize(); + return (asUINT)m_globalFunctions.GetSize(); } // interface asIScriptFunction *asCModule::GetFunctionByDecl(const char *decl) const { - asCBuilder bld(m_engine, const_cast(this)); - - // Don't write parser errors to the message callback - bld.silent = true; - - asCScriptFunction func(m_engine, const_cast(this), asFUNC_DUMMY); - int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, m_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 == m_engine->nameSpaces[0] ? m_defaultNamespace : func.nameSpace; - - // Search script functions for matching interface - while( ns ) - { - asIScriptFunction *f = 0; - const asCArray &idxs = m_globalFunctions.GetIndexes(ns, func.name); - for( unsigned int n = 0; n < idxs.GetLength(); n++ ) - { - const asCScriptFunction *funcPtr = m_globalFunctions.Get(idxs[n]); - if( funcPtr->objectType == 0 && - func.returnType == funcPtr->returnType && - func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength() - ) - { - bool match = true; - for( asUINT 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; - } - } - } - - if( f ) - return f; - else - { - // Search for matching functions in the parent namespace - ns = m_engine->GetParentNameSpace(ns); - } - } - - return 0; + asCBuilder bld(m_engine, const_cast(this)); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCScriptFunction func(m_engine, const_cast(this), asFUNC_DUMMY); + int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, m_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 == m_engine->nameSpaces[0] ? m_defaultNamespace : func.nameSpace; + + // Search script functions for matching interface + while( ns ) + { + asIScriptFunction *f = 0; + const asCArray &idxs = m_globalFunctions.GetIndexes(ns, func.name); + for( unsigned int n = 0; n < idxs.GetLength(); n++ ) + { + const asCScriptFunction *funcPtr = m_globalFunctions.Get(idxs[n]); + if( funcPtr->objectType == 0 && + func.returnType == funcPtr->returnType && + func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength() + ) + { + bool match = true; + for( asUINT 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; + } + } + } + + if( f ) + return f; + else + { + // Search for matching functions in the parent namespace + ns = m_engine->GetParentNameSpace(ns); + } + } + + return 0; } // interface asUINT asCModule::GetGlobalVarCount() const { - return (asUINT)m_scriptGlobals.GetSize(); + return (asUINT)m_scriptGlobals.GetSize(); } // interface int asCModule::GetGlobalVarIndexByName(const char *in_name) const { - asCString name; - asSNameSpace *ns = 0; - if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) - return asINVALID_ARG; - - // Find the global var id - while( ns ) - { - int id = m_scriptGlobals.GetFirstIndex(ns, name); - if( id >= 0 ) return id; + asCString name; + asSNameSpace *ns = 0; + if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) + return asINVALID_ARG; + + // Find the global var id + while( ns ) + { + int id = m_scriptGlobals.GetFirstIndex(ns, name); + if( id >= 0 ) return id; - // Recursively search parent namespaces - ns = m_engine->GetParentNameSpace(ns); - } + // Recursively search parent namespaces + ns = m_engine->GetParentNameSpace(ns); + } - return asNO_GLOBAL_VAR; + return asNO_GLOBAL_VAR; } // interface int asCModule::RemoveGlobalVar(asUINT index) { - asCGlobalProperty *prop = m_scriptGlobals.Get(index); - if( !prop ) - return asINVALID_ARG; + asCGlobalProperty *prop = m_scriptGlobals.Get(index); + if( !prop ) + return asINVALID_ARG; - // If the global variables have already been initialized - // then uninitialize the variable before it is removed - if (m_isGlobalVarInitialized) - UninitializeGlobalProp(prop); + // If the global variables have already been initialized + // then uninitialize the variable before it is removed + if (m_isGlobalVarInitialized) + UninitializeGlobalProp(prop); - // Destroy the internal of the global variable (removes the initialization function) - prop->DestroyInternal(); + // Destroy the internal of the global variable (removes the initialization function) + prop->DestroyInternal(); - // Check if the module is the only one referring to the property, if so remove it from the engine too - // If the property is not removed now, it will be removed later when the module is discarded - if( prop->refCount.get() == 2 ) - m_engine->RemoveGlobalProperty(prop); + // Check if the module is the only one referring to the property, if so remove it from the engine too + // If the property is not removed now, it will be removed later when the module is discarded + if( prop->refCount.get() == 2 ) + m_engine->RemoveGlobalProperty(prop); - // Remove the global variable from the module - m_scriptGlobals.Erase(index); - prop->Release(); + // Remove the global variable from the module + m_scriptGlobals.Erase(index); + prop->Release(); - return 0; + return 0; } // interface int asCModule::GetGlobalVarIndexByDecl(const char *decl) const { - asCBuilder bld(m_engine, const_cast(this)); + asCBuilder bld(m_engine, const_cast(this)); - // Don't write parser errors to the message callback - bld.silent = true; + // Don't write parser errors to the message callback + bld.silent = true; - asCString declName; - asSNameSpace *nameSpace; - asCDataType dt; - int r = bld.ParseVariableDeclaration(decl, m_defaultNamespace, declName, nameSpace, dt); - if( r < 0 ) - return r; + asCString declName; + asSNameSpace *nameSpace; + asCDataType dt; + int r = bld.ParseVariableDeclaration(decl, m_defaultNamespace, declName, nameSpace, dt); + if( r < 0 ) + return r; - // Search global variables for a match - while( nameSpace ) - { - int id = m_scriptGlobals.GetFirstIndex(nameSpace, declName, asCCompGlobPropType(dt)); - if( id != -1 ) - return id; + // Search global variables for a match + while( nameSpace ) + { + int id = m_scriptGlobals.GetFirstIndex(nameSpace, declName, asCCompGlobPropType(dt)); + if( id != -1 ) + return id; - // Recursively search parent namespace - nameSpace = m_engine->GetParentNameSpace(nameSpace); - } + // Recursively search parent namespace + nameSpace = m_engine->GetParentNameSpace(nameSpace); + } - return asNO_GLOBAL_VAR; + return asNO_GLOBAL_VAR; } // interface void *asCModule::GetAddressOfGlobalVar(asUINT index) { - asCGlobalProperty *prop = m_scriptGlobals.Get(index); - if( !prop ) - return 0; + asCGlobalProperty *prop = m_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()); + // 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()); + return (void*)(prop->GetAddressOfValue()); } // interface const char *asCModule::GetGlobalVarDeclaration(asUINT index, bool includeNamespace) const { - const asCGlobalProperty *prop = m_scriptGlobals.Get(index); - if (!prop) return 0; + const asCGlobalProperty *prop = m_scriptGlobals.Get(index); + if (!prop) return 0; - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = prop->type.Format(m_defaultNamespace); - *tempString += " "; - if( includeNamespace && prop->nameSpace->name != "" ) - *tempString += prop->nameSpace->name + "::"; - *tempString += prop->name; + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = prop->type.Format(m_defaultNamespace); + *tempString += " "; + if( includeNamespace && prop->nameSpace->name != "" ) + *tempString += prop->nameSpace->name + "::"; + *tempString += prop->name; - return tempString->AddressOf(); + return tempString->AddressOf(); } // interface int asCModule::GetGlobalVar(asUINT index, const char **out_name, const char **out_nameSpace, int *out_typeId, bool *out_isConst) const { - const asCGlobalProperty *prop = m_scriptGlobals.Get(index); - if (!prop) return asINVALID_ARG; + const asCGlobalProperty *prop = m_scriptGlobals.Get(index); + if (!prop) return asINVALID_ARG; - if( out_name ) - *out_name = prop->name.AddressOf(); - if( out_nameSpace ) - *out_nameSpace = prop->nameSpace->name.AddressOf(); - if( out_typeId ) - *out_typeId = m_engine->GetTypeIdFromDataType(prop->type); - if( out_isConst ) - *out_isConst = prop->type.IsReadOnly(); + if( out_name ) + *out_name = prop->name.AddressOf(); + if( out_nameSpace ) + *out_nameSpace = prop->nameSpace->name.AddressOf(); + if( out_typeId ) + *out_typeId = m_engine->GetTypeIdFromDataType(prop->type); + if( out_isConst ) + *out_isConst = prop->type.IsReadOnly(); - return asSUCCESS; + return asSUCCESS; } // interface asUINT asCModule::GetObjectTypeCount() const { - return (asUINT)m_classTypes.GetLength(); + return (asUINT)m_classTypes.GetLength(); } // interface asITypeInfo *asCModule::GetObjectTypeByIndex(asUINT index) const { - if( index >= m_classTypes.GetLength() ) - return 0; + if( index >= m_classTypes.GetLength() ) + return 0; - return m_classTypes[index]; + return m_classTypes[index]; } // interface asITypeInfo *asCModule::GetTypeInfoByName(const char *in_name) const { - asCString name; - asSNameSpace *ns = 0; - if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) - return 0; - - while (ns) - { - asITypeInfo* info = GetType(name, ns); - if(info) - { - return info; - } + asCString name; + asSNameSpace *ns = 0; + if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) + return 0; + + while (ns) + { + asITypeInfo* info = GetType(name, ns); + if(info) + { + return info; + } - // Recursively search parent namespace - ns = m_engine->GetParentNameSpace(ns); - } + // Recursively search parent namespace + ns = m_engine->GetParentNameSpace(ns); + } - return 0; + return 0; } // interface int asCModule::GetTypeIdByDecl(const char *decl) const { - asCDataType dt; + asCDataType dt; - // This const cast is safe since we know the engine won't be modified - asCBuilder bld(m_engine, const_cast(this)); + // This const cast is safe since we know the engine won't be modified + asCBuilder bld(m_engine, const_cast(this)); - // Don't write parser errors to the message callback - bld.silent = true; + // Don't write parser errors to the message callback + bld.silent = true; - int r = bld.ParseDataType(decl, &dt, m_defaultNamespace); - if( r < 0 ) - return asINVALID_TYPE; + int r = bld.ParseDataType(decl, &dt, m_defaultNamespace); + if( r < 0 ) + return asINVALID_TYPE; - return m_engine->GetTypeIdFromDataType(dt); + return m_engine->GetTypeIdFromDataType(dt); } // interface asITypeInfo *asCModule::GetTypeInfoByDecl(const char *decl) const { - asCDataType dt; + asCDataType dt; - // This const cast is safe since we know the engine won't be modified - asCBuilder bld(m_engine, const_cast(this)); + // This const cast is safe since we know the engine won't be modified + asCBuilder bld(m_engine, const_cast(this)); - // Don't write parser errors to the message callback - bld.silent = true; + // Don't write parser errors to the message callback + bld.silent = true; - int r = bld.ParseDataType(decl, &dt, m_defaultNamespace); - if (r < 0) - return 0; + int r = bld.ParseDataType(decl, &dt, m_defaultNamespace); + if (r < 0) + return 0; - return dt.GetTypeInfo(); + return dt.GetTypeInfo(); } // interface asUINT asCModule::GetEnumCount() const { - return m_enumTypes.GetLength(); + return m_enumTypes.GetLength(); } // interface asITypeInfo *asCModule::GetEnumByIndex(asUINT index) const { - if( index >= m_enumTypes.GetLength() ) - return 0; + if( index >= m_enumTypes.GetLength() ) + return 0; - return m_enumTypes[index]; + return m_enumTypes[index]; } // interface asUINT asCModule::GetTypedefCount() const { - return (asUINT)m_typeDefs.GetLength(); + return (asUINT)m_typeDefs.GetLength(); } // interface asITypeInfo *asCModule::GetTypedefByIndex(asUINT index) const { - if( index >= m_typeDefs.GetLength() ) - return 0; + if( index >= m_typeDefs.GetLength() ) + return 0; - return m_typeDefs[index]; + return m_typeDefs[index]; } // internal int asCModule::GetNextImportedFunctionId() { - // TODO: multithread: This will break if one thread if freeing a module, while another is being compiled - if( m_engine->freeImportedFunctionIdxs.GetLength() ) - return FUNC_IMPORTED | (asUINT)m_engine->freeImportedFunctionIdxs[m_engine->freeImportedFunctionIdxs.GetLength()-1]; + // TODO: multithread: This will break if one thread if freeing a module, while another is being compiled + if( m_engine->freeImportedFunctionIdxs.GetLength() ) + return FUNC_IMPORTED | (asUINT)m_engine->freeImportedFunctionIdxs[m_engine->freeImportedFunctionIdxs.GetLength()-1]; - return FUNC_IMPORTED | (asUINT)m_engine->importedFunctions.GetLength(); + return FUNC_IMPORTED | (asUINT)m_engine->importedFunctions.GetLength(); } #ifndef AS_NO_COMPILER // internal int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &funcName, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType, bool isGlobalFunction, asSFunctionTraits funcTraits, asSNameSpace *ns) { - asASSERT(id >= 0); - - // Store the function information - asCScriptFunction *func = asNEW(asCScriptFunction)(m_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 = m_engine->nameSpaces[0]; - - // All methods of shared objects are also shared - if( objType && objType->IsShared() ) - funcTraits.SetTrait(asTRAIT_SHARED, true); - - func->name = funcName; - 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; - if( objType ) - objType->AddRefInternal(); - func->traits = funcTraits; - - asASSERT( params.GetLength() == inOutFlags.GetLength() && params.GetLength() == defaultArgs.GetLength() ); - - // Verify that we are not assigning either the final or override specifier(s) if we are registering a non-member function - asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_FINAL)) ); - asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_OVERRIDE)) ); - - // The internal ref count was already set by the constructor - m_scriptFunctions.PushLast(func); - m_engine->AddScriptFunction(func); - - // Compute the signature id - if( objType ) - func->ComputeSignatureId(); - - // Add reference - if( isGlobalFunction ) - m_globalFunctions.Put(func); - - return 0; + asASSERT(id >= 0); + + // Store the function information + asCScriptFunction *func = asNEW(asCScriptFunction)(m_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 = m_engine->nameSpaces[0]; + + // All methods of shared objects are also shared + if( objType && objType->IsShared() ) + funcTraits.SetTrait(asTRAIT_SHARED, true); + + func->name = funcName; + 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; + if( objType ) + objType->AddRefInternal(); + func->traits = funcTraits; + + asASSERT( params.GetLength() == inOutFlags.GetLength() && params.GetLength() == defaultArgs.GetLength() ); + + // Verify that we are not assigning either the final or override specifier(s) if we are registering a non-member function + asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_FINAL)) ); + asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_OVERRIDE)) ); + + // The internal ref count was already set by the constructor + m_scriptFunctions.PushLast(func); + m_engine->AddScriptFunction(func); + + // Compute the signature id + if( objType ) + func->ComputeSignatureId(); + + // Add reference + if( isGlobalFunction ) + m_globalFunctions.Put(func); + + return 0; } // internal int asCModule::AddScriptFunction(asCScriptFunction *func) { - m_scriptFunctions.PushLast(func); - func->AddRefInternal(); - m_engine->AddScriptFunction(func); - - // If the function that is being added is an already compiled shared function - // then it is necessary to look for anonymous functions that may be declared - // within it and add those as well - if( func->IsShared() && func->funcType == asFUNC_SCRIPT ) - { - // Loop through the byte code and check all the - // asBC_FuncPtr instructions for anonymous functions - asDWORD *bc = func->scriptData->byteCode.AddressOf(); - asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength(); - for( asUINT n = 0; n < bcLength; ) - { - int c = *(asBYTE*)&bc[n]; - if( c == asBC_FuncPtr ) - { - asCScriptFunction *f = reinterpret_cast(asBC_PTRARG(&bc[n])); - // Anonymous functions start with $ - // There are never two equal anonymous functions so it is not necessary to look for duplicates - if( f && f->name[0] == '$' ) - { - AddScriptFunction(f); - m_globalFunctions.Put(f); - } - } - n += asBCTypeSize[asBCInfo[c].type]; - } - } - - return 0; + m_scriptFunctions.PushLast(func); + func->AddRefInternal(); + m_engine->AddScriptFunction(func); + + // If the function that is being added is an already compiled shared function + // then it is necessary to look for anonymous functions that may be declared + // within it and add those as well + if( func->IsShared() && func->funcType == asFUNC_SCRIPT ) + { + // Loop through the byte code and check all the + // asBC_FuncPtr instructions for anonymous functions + asDWORD *bc = func->scriptData->byteCode.AddressOf(); + asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength(); + for( asUINT n = 0; n < bcLength; ) + { + int c = *(asBYTE*)&bc[n]; + if( c == asBC_FuncPtr ) + { + asCScriptFunction *f = reinterpret_cast(asBC_PTRARG(&bc[n])); + // Anonymous functions start with $ + // There are never two equal anonymous functions so it is not necessary to look for duplicates + if( f && f->name[0] == '$' ) + { + AddScriptFunction(f); + m_globalFunctions.Put(f); + } + } + n += asBCTypeSize[asBCInfo[c].type]; + } + } + + return 0; } // internal int asCModule::AddImportedFunction(int id, const asCString &funcName, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSFunctionTraits funcTraits, asSNameSpace *ns, const asCString &moduleName) { - asASSERT(id >= 0); - - // Store the function information - asCScriptFunction *func = asNEW(asCScriptFunction)(m_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 = funcName; - func->id = id; - func->returnType = returnType; - func->nameSpace = ns; - func->parameterTypes = params; - func->inOutFlags = inOutFlags; - func->defaultArgs = defaultArgs; - func->objectType = 0; - func->traits = funcTraits; - - sBindInfo *info = asNEW(sBindInfo); - if( info == 0 ) - { - asDELETE(func, asCScriptFunction); - return asOUT_OF_MEMORY; - } - - info->importedFunctionSignature = func; - info->boundFunctionId = -1; - info->importFromModule = moduleName; - m_bindInformations.PushLast(info); - - // Add the info to the array in the engine - if( m_engine->freeImportedFunctionIdxs.GetLength() ) - m_engine->importedFunctions[m_engine->freeImportedFunctionIdxs.PopLast()] = info; - else - m_engine->importedFunctions.PushLast(info); - - return 0; + asASSERT(id >= 0); + + // Store the function information + asCScriptFunction *func = asNEW(asCScriptFunction)(m_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 = funcName; + func->id = id; + func->returnType = returnType; + func->nameSpace = ns; + func->parameterTypes = params; + func->inOutFlags = inOutFlags; + func->defaultArgs = defaultArgs; + func->objectType = 0; + func->traits = funcTraits; + + sBindInfo *info = asNEW(sBindInfo); + if( info == 0 ) + { + asDELETE(func, asCScriptFunction); + return asOUT_OF_MEMORY; + } + + info->importedFunctionSignature = func; + info->boundFunctionId = -1; + info->importFromModule = moduleName; + m_bindInformations.PushLast(info); + + // Add the info to the array in the engine + if( m_engine->freeImportedFunctionIdxs.GetLength() ) + m_engine->importedFunctions[m_engine->freeImportedFunctionIdxs.PopLast()] = info; + else + m_engine->importedFunctions.PushLast(info); + + return 0; } #endif // internal asCScriptFunction *asCModule::GetImportedFunction(int index) const { - return m_bindInformations[index]->importedFunctionSignature; + return m_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; + // 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; + // Must verify that the interfaces are equal + asCScriptFunction *dst = GetImportedFunction(index); + if( dst == 0 ) return asNO_FUNCTION; - if( func == 0 ) - return asINVALID_ARG; + if( func == 0 ) + return asINVALID_ARG; - asCScriptFunction *src = m_engine->GetScriptFunction(func->GetId()); - if( src == 0 ) - return asNO_FUNCTION; + asCScriptFunction *src = m_engine->GetScriptFunction(func->GetId()); + if( src == 0 ) + return asNO_FUNCTION; - // Verify return type - if( dst->returnType != src->returnType ) - return asINVALID_INTERFACE; + // Verify return type + if( dst->returnType != src->returnType ) + return asINVALID_INTERFACE; - if( dst->parameterTypes.GetLength() != src->parameterTypes.GetLength() ) - return asINVALID_INTERFACE; + if( dst->parameterTypes.GetLength() != src->parameterTypes.GetLength() ) + return asINVALID_INTERFACE; - for( asUINT n = 0; n < dst->parameterTypes.GetLength(); ++n ) - { - if( dst->parameterTypes[n] != src->parameterTypes[n] ) - return asINVALID_INTERFACE; - } + for( asUINT n = 0; n < dst->parameterTypes.GetLength(); ++n ) + { + if( dst->parameterTypes[n] != src->parameterTypes[n] ) + return asINVALID_INTERFACE; + } - m_bindInformations[index]->boundFunctionId = src->GetId(); - src->AddRefInternal(); + m_bindInformations[index]->boundFunctionId = src->GetId(); + src->AddRefInternal(); - return asSUCCESS; + return asSUCCESS; } // interface int asCModule::UnbindImportedFunction(asUINT index) { - if( index >= m_bindInformations.GetLength() ) - return asINVALID_ARG; + if( index >= m_bindInformations.GetLength() ) + return asINVALID_ARG; - // Remove reference to old module - if( m_bindInformations[index] ) - { - int oldFuncID = m_bindInformations[index]->boundFunctionId; - if( oldFuncID != -1 ) - { - m_bindInformations[index]->boundFunctionId = -1; - m_engine->scriptFunctions[oldFuncID]->ReleaseInternal(); - } - } + // Remove reference to old module + if( m_bindInformations[index] ) + { + int oldFuncID = m_bindInformations[index]->boundFunctionId; + if( oldFuncID != -1 ) + { + m_bindInformations[index]->boundFunctionId = -1; + m_engine->scriptFunctions[oldFuncID]->ReleaseInternal(); + } + } - return asSUCCESS; + return asSUCCESS; } // interface const char *asCModule::GetImportedFunctionDeclaration(asUINT index) const { - asCScriptFunction *func = GetImportedFunction(index); - if( func == 0 ) return 0; + asCScriptFunction *func = GetImportedFunction(index); + if( func == 0 ) return 0; - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = func->GetDeclarationStr(); + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = func->GetDeclarationStr(); - return tempString->AddressOf(); + return tempString->AddressOf(); } // interface const char *asCModule::GetImportedFunctionSourceModule(asUINT index) const { - if( index >= m_bindInformations.GetLength() ) - return 0; + if( index >= m_bindInformations.GetLength() ) + return 0; - return m_bindInformations[index]->importFromModule.AddressOf(); + return m_bindInformations[index]->importFromModule.AddressOf(); } // inteface int asCModule::BindAllImportedFunctions() { - bool notAllFunctionsWereBound = false; + 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; + // 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(false, true); + asCString str = importFunc->GetDeclarationStr(false, true); - // Get module name from where the function should be imported - const char *moduleName = GetImportedFunctionSourceModule(n); - if( moduleName == 0 ) return asERROR; + // Get module name from where the function should be imported + const char *moduleName = GetImportedFunctionSourceModule(n); + if( moduleName == 0 ) return asERROR; - asCModule *srcMod = m_engine->GetModule(moduleName, false); - asIScriptFunction *func = 0; - if( srcMod ) - func = srcMod->GetFunctionByDecl(str.AddressOf()); + asCModule *srcMod = m_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( func == 0 ) + notAllFunctionsWereBound = true; + else + { + if( BindImportedFunction(n, func) < 0 ) + notAllFunctionsWereBound = true; + } + } - if( notAllFunctionsWereBound ) - return asCANT_BIND_ALL_FUNCTIONS; + if( notAllFunctionsWereBound ) + return asCANT_BIND_ALL_FUNCTIONS; - return asSUCCESS; + return asSUCCESS; } // interface int asCModule::UnbindAllImportedFunctions() { - asUINT c = GetImportedFunctionCount(); - for( asUINT n = 0; n < c; ++n ) - UnbindImportedFunction(n); + asUINT c = GetImportedFunctionCount(); + for( asUINT n = 0; n < c; ++n ) + UnbindImportedFunction(n); - return asSUCCESS; + return asSUCCESS; } // internal void asCModule::AddClassType(asCObjectType* type) { - m_classTypes.PushLast(type); - m_typeLookup.Insert({type->nameSpace, type->name}, type); + m_classTypes.PushLast(type); + m_typeLookup.Insert({type->nameSpace, type->name}, type); } // internal void asCModule::AddEnumType(asCEnumType* type) { - m_enumTypes.PushLast(type); - m_typeLookup.Insert({type->nameSpace, type->name}, type); + m_enumTypes.PushLast(type); + m_typeLookup.Insert({type->nameSpace, type->name}, type); } // internal void asCModule::AddTypeDef(asCTypedefType* type) { - m_typeDefs.PushLast(type); - m_typeLookup.Insert({type->nameSpace, type->name}, type); + m_typeDefs.PushLast(type); + m_typeLookup.Insert({type->nameSpace, type->name}, type); } // internal void asCModule::AddFuncDef(asCFuncdefType* type) { - m_funcDefs.PushLast(type); - m_typeLookup.Insert({type->nameSpace, type->name}, type); + m_funcDefs.PushLast(type); + m_typeLookup.Insert({type->nameSpace, type->name}, type); } // internal void asCModule::ReplaceFuncDef(asCFuncdefType* type, asCFuncdefType* newType) { - int i = m_funcDefs.IndexOf(type); - if( i >= 0 ) - { - m_funcDefs[i] = newType; - - // Replace it in the lookup map too - asSMapNode* result = nullptr; - if(m_typeLookup.MoveTo(&result, {type->nameSpace, type->name})) - { - asASSERT( result->value == type ); - result->value = newType; - } - } + int i = m_funcDefs.IndexOf(type); + if( i >= 0 ) + { + m_funcDefs[i] = newType; + + // Replace it in the lookup map too + asSMapNode* result = nullptr; + if(m_typeLookup.MoveTo(&result, {type->nameSpace, type->name})) + { + asASSERT( result->value == type ); + result->value = newType; + } + } } // internal asCTypeInfo *asCModule::GetType(const asCString &type, asSNameSpace *ns) const { - asSMapNode* result = nullptr; - if(m_typeLookup.MoveTo(&result, {ns, type})) - { - return result->value; - } - return 0; + asSMapNode* result = nullptr; + if(m_typeLookup.MoveTo(&result, {ns, type})) + { + return result->value; + } + return 0; } // internal asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) const { - asSMapNode* result = nullptr; - if(m_typeLookup.MoveTo(&result, {ns, type})) - { - return CastToObjectType(result->value); - } - - return 0; + asSMapNode* result = nullptr; + if(m_typeLookup.MoveTo(&result, {ns, type})) + { + return CastToObjectType(result->value); + } + + return 0; } // internal asCGlobalProperty *asCModule::AllocateGlobalProperty(const char *propName, const asCDataType &dt, asSNameSpace *ns) { - asCGlobalProperty *prop = m_engine->AllocateGlobalProperty(); - prop->name = propName; - prop->nameSpace = ns; + asCGlobalProperty *prop = m_engine->AllocateGlobalProperty(); + prop->name = propName; + prop->nameSpace = ns; - // Allocate the memory for this property based on its type - prop->type = dt; - prop->AllocateMemory(); + // Allocate the memory for this property based on its type + prop->type = dt; + prop->AllocateMemory(); - // Make an entry in the address to variable map - m_engine->varAddressMap.Insert(prop->GetAddressOfValue(), prop); + // Make an entry in the address to variable map + m_engine->varAddressMap.Insert(prop->GetAddressOfValue(), prop); - // Store the variable in the module scope - m_scriptGlobals.Put(prop); - prop->AddRef(); + // Store the variable in the module scope + m_scriptGlobals.Put(prop); + prop->AddRef(); - return prop; + return prop; } // internal bool asCModule::IsEmpty() const { - if( m_scriptFunctions.GetLength() ) return false; - if( m_globalFunctions.GetSize() ) return false; - if( m_bindInformations.GetLength() ) return false; - if( m_scriptGlobals.GetSize() ) return false; - if( m_classTypes.GetLength() ) return false; - if( m_enumTypes.GetLength() ) return false; - if( m_typeDefs.GetLength() ) return false; - if( m_funcDefs.GetLength() ) return false; + if( m_scriptFunctions.GetLength() ) return false; + if( m_globalFunctions.GetSize() ) return false; + if( m_bindInformations.GetLength() ) return false; + if( m_scriptGlobals.GetSize() ) return false; + if( m_classTypes.GetLength() ) return false; + if( m_enumTypes.GetLength() ) return false; + if( m_typeDefs.GetLength() ) return false; + if( m_funcDefs.GetLength() ) return false; - return true; + return true; } // interface int asCModule::SaveByteCode(asIBinaryStream *out, bool stripDebugInfo) const { #ifdef AS_NO_COMPILER - UNUSED_VAR(out); - UNUSED_VAR(stripDebugInfo); - return asNOT_SUPPORTED; + UNUSED_VAR(out); + UNUSED_VAR(stripDebugInfo); + return asNOT_SUPPORTED; #else - if( out == 0 ) return asINVALID_ARG; + if( out == 0 ) return asINVALID_ARG; - // Make sure there is actually something to save - if( IsEmpty() ) - return asERROR; + // Make sure there is actually something to save + if( IsEmpty() ) + return asERROR; - asCWriter write(const_cast(this), out, m_engine, stripDebugInfo); - return write.Write(); + asCWriter write(const_cast(this), out, m_engine, stripDebugInfo); + return write.Write(); #endif } // interface int asCModule::LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped) { - if( in == 0 ) return asINVALID_ARG; + if( in == 0 ) return asINVALID_ARG; - // Don't allow the module to be rebuilt if there are still - // external references that will need the previous code - if( HasExternalReferences(false) ) - { - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE); - return asMODULE_IS_IN_USE; - } + // Don't allow the module to be rebuilt if there are still + // external references that will need the previous code + if( HasExternalReferences(false) ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE); + return asMODULE_IS_IN_USE; + } - // Only permit loading bytecode if no other thread is currently compiling - // TODO: It should be possible to have multiple threads perform compilations - int r = m_engine->RequestBuild(); - if( r < 0 ) - return r; + // Only permit loading bytecode if no other thread is currently compiling + // TODO: It should be possible to have multiple threads perform compilations + int r = m_engine->RequestBuild(); + if( r < 0 ) + return r; - asCReader read(this, in, m_engine); - r = read.Read(wasDebugInfoStripped); - if (r < 0) - { - m_engine->BuildCompleted(); - return r; - } + asCReader read(this, in, m_engine); + r = read.Read(wasDebugInfoStripped); + if (r < 0) + { + m_engine->BuildCompleted(); + return r; + } - JITCompile(); + JITCompile(); #ifdef AS_DEBUG - // Verify that there are no unwanted gaps in the scriptFunctions array. - for( asUINT n = 1; n < m_engine->scriptFunctions.GetLength(); n++ ) - { - int id = n; - if( m_engine->scriptFunctions[n] == 0 && !m_engine->freeScriptFunctionIds.Exists(id) ) - asASSERT( false ); - } + // Verify that there are no unwanted gaps in the scriptFunctions array. + for( asUINT n = 1; n < m_engine->scriptFunctions.GetLength(); n++ ) + { + int id = n; + if( m_engine->scriptFunctions[n] == 0 && !m_engine->freeScriptFunctionIds.Exists(id) ) + asASSERT( false ); + } #endif - m_engine->BuildCompleted(); + m_engine->BuildCompleted(); - return r; + 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; + 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 = m_engine->RequestBuild(); - if( r < 0 ) - return r; - - // Prepare the engine - m_engine->PrepareEngine(); - if( m_engine->configFailed ) - { - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); - m_engine->BuildCompleted(); - return asINVALID_CONFIGURATION; - } - - // Compile the global variable and add it to the module scope - asCBuilder varBuilder(m_engine, this); - asCString str = code; - r = varBuilder.CompileGlobalVar(sectionName, str.AddressOf(), lineOffset); - - m_engine->BuildCompleted(); - - // Initialize the variable - if( r >= 0 ) - { - // Clear the memory - asCGlobalProperty *prop = m_scriptGlobals.GetLast(); - if( prop ) - { - memset(prop->GetAddressOfValue(), 0, sizeof(asDWORD)*prop->type.GetSizeOnStackDWords()); - } - - if( prop && m_engine->ep.initGlobalVarsAfterBuild ) - { - // Flag that there are initialized global variables - m_isGlobalVarInitialized = true; - - r = InitGlobalProp(prop, 0); - } - } - - return r; + // 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 = m_engine->RequestBuild(); + if( r < 0 ) + return r; + + // Prepare the engine + m_engine->PrepareEngine(); + if( m_engine->configFailed ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); + m_engine->BuildCompleted(); + return asINVALID_CONFIGURATION; + } + + // Compile the global variable and add it to the module scope + asCBuilder varBuilder(m_engine, this); + asCString str = code; + r = varBuilder.CompileGlobalVar(sectionName, str.AddressOf(), lineOffset); + + m_engine->BuildCompleted(); + + // Initialize the variable + if( r >= 0 ) + { + // Clear the memory + asCGlobalProperty *prop = m_scriptGlobals.GetLast(); + if( prop ) + { + memset(prop->GetAddressOfValue(), 0, sizeof(asDWORD)*prop->type.GetSizeOnStackDWords()); + } + + if( prop && m_engine->ep.initGlobalVarsAfterBuild ) + { + // Flag that there are initialized global variables + m_isGlobalVarInitialized = true; + + r = InitGlobalProp(prop, 0); + } + } + + 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; + // 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; + 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 = m_engine->RequestBuild(); - if( r < 0 ) - return r; - - // Prepare the engine - m_engine->PrepareEngine(); - if( m_engine->configFailed ) - { - m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); - m_engine->BuildCompleted(); - return asINVALID_CONFIGURATION; - } - - // Compile the single function - asCBuilder funcBuilder(m_engine, this); - asCString str = code; - asCScriptFunction *func = 0; - r = funcBuilder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func); - - m_engine->BuildCompleted(); - - if( r >= 0 && outFunc && func ) - { - // Return the function to the caller and add an external reference - *outFunc = func; - func->AddRef(); - } - - // Release our reference to the function - if( func ) - func->ReleaseInternal(); - - return r; + // 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 = m_engine->RequestBuild(); + if( r < 0 ) + return r; + + // Prepare the engine + m_engine->PrepareEngine(); + if( m_engine->configFailed ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); + m_engine->BuildCompleted(); + return asINVALID_CONFIGURATION; + } + + // Compile the single function + asCBuilder funcBuilder(m_engine, this); + asCString str = code; + asCScriptFunction *func = 0; + r = funcBuilder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func); + + m_engine->BuildCompleted(); + + if( r >= 0 && outFunc && func ) + { + // Return the function to the caller and add an external reference + *outFunc = func; + func->AddRef(); + } + + // Release our reference to the function + if( func ) + func->ReleaseInternal(); + + return r; #endif } // interface int asCModule::RemoveFunction(asIScriptFunction *func) { - // Find the global function - asCScriptFunction *f = static_cast(func); - int idx = m_globalFunctions.GetIndex(f); - if( idx >= 0 ) - { - m_globalFunctions.Erase(idx); - m_scriptFunctions.RemoveValue(f); - f->ReleaseInternal(); - return 0; - } + // Find the global function + asCScriptFunction *f = static_cast(func); + int idx = m_globalFunctions.GetIndex(f); + if( idx >= 0 ) + { + m_globalFunctions.Erase(idx); + m_scriptFunctions.RemoveValue(f); + f->ReleaseInternal(); + return 0; + } - return asNO_FUNCTION; + return asNO_FUNCTION; } #ifndef AS_NO_COMPILER // internal int asCModule::AddFuncDef(const asCString &funcName, asSNameSpace *ns, asCObjectType *parent) { - // namespace and parent are mutually exclusive - asASSERT((ns == 0 && parent) || (ns && parent == 0)); + // namespace and parent are mutually exclusive + asASSERT((ns == 0 && parent) || (ns && parent == 0)); - asCScriptFunction *func = asNEW(asCScriptFunction)(m_engine, 0, asFUNC_FUNCDEF); - if (func == 0) - return asOUT_OF_MEMORY; + asCScriptFunction *func = asNEW(asCScriptFunction)(m_engine, 0, asFUNC_FUNCDEF); + if (func == 0) + return asOUT_OF_MEMORY; - func->name = funcName; - func->nameSpace = ns; - func->module = this; + func->name = funcName; + func->nameSpace = ns; + func->module = this; - asCFuncdefType *fdt = asNEW(asCFuncdefType)(m_engine, func); - AddFuncDef(fdt); // The constructor set the refcount to 1 + asCFuncdefType *fdt = asNEW(asCFuncdefType)(m_engine, func); + AddFuncDef(fdt); // The constructor set the refcount to 1 - m_engine->funcDefs.PushLast(fdt); // doesn't increase refcount - func->id = m_engine->GetNextScriptFunctionId(); - m_engine->AddScriptFunction(func); + m_engine->funcDefs.PushLast(fdt); // doesn't increase refcount + func->id = m_engine->GetNextScriptFunctionId(); + m_engine->AddScriptFunction(func); - if (parent) - { - parent->childFuncDefs.PushLast(fdt); - fdt->parentClass = parent; - } + if (parent) + { + parent->childFuncDefs.PushLast(fdt); + fdt->parentClass = parent; + } - return (int)m_funcDefs.GetLength()-1; + return (int)m_funcDefs.GetLength()-1; } #endif // interface asDWORD asCModule::SetAccessMask(asDWORD mask) { - asDWORD old = m_accessMask; - m_accessMask = mask; - return old; + asDWORD old = m_accessMask; + m_accessMask = mask; + return old; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_module.h b/src/angelscript/source/as_module.h index 04a0af32e7f..5011b814fdb 100644 --- a/src/angelscript/source/as_module.h +++ b/src/angelscript/source/as_module.h @@ -64,15 +64,15 @@ struct asSNameSpace; struct sBindInfo { - asCScriptFunction *importedFunctionSignature; - asCString importFromModule; - int boundFunctionId; + asCScriptFunction *importedFunctionSignature; + asCString importFromModule; + int boundFunctionId; }; struct sObjectTypePair { - asCObjectType *a; - asCObjectType *b; + asCObjectType *a; + asCObjectType *b; }; @@ -98,158 +98,158 @@ 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 asITypeInfo *GetObjectTypeByIndex(asUINT index) const; - virtual int GetTypeIdByDecl(const char *decl) const; - virtual asITypeInfo *GetTypeInfoByName(const char *name) const; - virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const; - - // Enums - virtual asUINT GetEnumCount() const; - virtual asITypeInfo *GetEnumByIndex(asUINT index) const; - - // Typedefs - virtual asUINT GetTypedefCount() const; - virtual asITypeInfo *GetTypedefByIndex(asUINT index) 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; + 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 asITypeInfo *GetObjectTypeByIndex(asUINT index) const; + virtual int GetTypeIdByDecl(const char *decl) const; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const; + + // Enums + virtual asUINT GetEnumCount() const; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const; + + // Typedefs + virtual asUINT GetTypedefCount() const; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) 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(); + asCModule(const char *name, asCScriptEngine *engine); + ~asCModule(); //protected: - friend class asCScriptEngine; - friend class asCBuilder; - friend class asCCompiler; - friend class asCContext; - friend class asCRestore; + friend class asCScriptEngine; + friend class asCBuilder; + friend class asCCompiler; + friend class asCContext; + friend class asCRestore; - void InternalReset(); - bool IsEmpty() const; - bool HasExternalReferences(bool shuttingDown); + void InternalReset(); + bool IsEmpty() const; + bool HasExternalReferences(bool shuttingDown); - int CallInit(asIScriptContext *ctx); - void CallExit(); - int InitGlobalProp(asCGlobalProperty *prop, asIScriptContext *ctx); + int CallInit(asIScriptContext *ctx); + void CallExit(); + int InitGlobalProp(asCGlobalProperty *prop, asIScriptContext *ctx); - void JITCompile(); + 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 isGlobalFunction = false, asSFunctionTraits funcTraits = asSFunctionTraits(), asSNameSpace *ns = 0); - int AddScriptFunction(asCScriptFunction *func); - int AddImportedFunction(int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSFunctionTraits funcTraits, asSNameSpace *ns, const asCString &moduleName); - int AddFuncDef(const asCString &name, asSNameSpace *ns, asCObjectType *parent); + int AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType = 0, bool isGlobalFunction = false, asSFunctionTraits funcTraits = asSFunctionTraits(), asSNameSpace *ns = 0); + int AddScriptFunction(asCScriptFunction *func); + int AddImportedFunction(int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSFunctionTraits funcTraits, asSNameSpace *ns, const asCString &moduleName); + int AddFuncDef(const asCString &name, asSNameSpace *ns, asCObjectType *parent); #endif - int GetNextImportedFunctionId(); - asCScriptFunction *GetImportedFunction(int funcId) const; - asCTypeInfo *GetType(const asCString &type, asSNameSpace *ns) const; - asCObjectType *GetObjectType(const char *type, asSNameSpace *ns) const; - asCGlobalProperty *AllocateGlobalProperty(const char *name, const asCDataType &dt, asSNameSpace *ns); - void UninitializeGlobalProp(asCGlobalProperty *prop); - - // Adds the class type to the module. The module assumes ownership of the reference without increasing it - void AddClassType(asCObjectType*); - // Adds the enum type to the module. The module assumes ownership of the reference without increasing it - void AddEnumType(asCEnumType*); - // Adds the typedef to the module. The module assumes ownership of the reference without increasing it - void AddTypeDef(asCTypedefType*); - // Adds the funcdef to the module. The module assumes ownership of the reference without increasing it - void AddFuncDef(asCFuncdefType*); - // Replaces an existing funcdef with another (used for shared funcdefs). Doesn't add or release refCounts - void ReplaceFuncDef(asCFuncdefType *oldType, asCFuncdefType *newType); - - asCString m_name; - asCScriptEngine *m_engine; - asCBuilder *m_builder; - asCArray m_userData; - asDWORD m_accessMask; - asSNameSpace *m_defaultNamespace; - - // This array holds all functions, class members, factories, etc that were compiled with the module. - // These references hold an internal reference to the function object. - asCArray m_scriptFunctions; // increases ref count - // This array holds global functions declared in the module. These references are not counted, - // as the same pointer is always present in the scriptFunctions array too. - asCSymbolTable m_globalFunctions; // doesn't increase ref count - // This array holds imported functions in the module. - asCArray m_bindInformations; // increases ref count - // This array holds template instance types created for the module's object types - asCArray m_templateInstances; // increases ref count - - // This array holds the global variables declared in the script - asCSymbolTable m_scriptGlobals; // increases ref count - bool m_isGlobalVarInitialized; - - // This array holds class and interface types - asCArray m_classTypes; // increases ref count - // This array holds enum types - asCArray m_enumTypes; // increases ref count - // This array holds typedefs - asCArray m_typeDefs; // increases ref count - // This array holds the funcdefs declared in the module - asCArray m_funcDefs; // increases ref count - - // This map contains all the types (also contained in the arrays above) for quick lookup - // TODO: memory: Can we eliminate the arrays above? - asCMap m_typeLookup; // doesn't increase ref count - - // This array holds types that have been explicitly declared with 'external' - asCArray m_externalTypes; // doesn't increase ref count - // This array holds functions that have been explicitly declared with 'external' - asCArray m_externalFunctions; // doesn't increase ref count + int GetNextImportedFunctionId(); + asCScriptFunction *GetImportedFunction(int funcId) const; + asCTypeInfo *GetType(const asCString &type, asSNameSpace *ns) const; + asCObjectType *GetObjectType(const char *type, asSNameSpace *ns) const; + asCGlobalProperty *AllocateGlobalProperty(const char *name, const asCDataType &dt, asSNameSpace *ns); + void UninitializeGlobalProp(asCGlobalProperty *prop); + + // Adds the class type to the module. The module assumes ownership of the reference without increasing it + void AddClassType(asCObjectType*); + // Adds the enum type to the module. The module assumes ownership of the reference without increasing it + void AddEnumType(asCEnumType*); + // Adds the typedef to the module. The module assumes ownership of the reference without increasing it + void AddTypeDef(asCTypedefType*); + // Adds the funcdef to the module. The module assumes ownership of the reference without increasing it + void AddFuncDef(asCFuncdefType*); + // Replaces an existing funcdef with another (used for shared funcdefs). Doesn't add or release refCounts + void ReplaceFuncDef(asCFuncdefType *oldType, asCFuncdefType *newType); + + asCString m_name; + asCScriptEngine *m_engine; + asCBuilder *m_builder; + asCArray m_userData; + asDWORD m_accessMask; + asSNameSpace *m_defaultNamespace; + + // This array holds all functions, class members, factories, etc that were compiled with the module. + // These references hold an internal reference to the function object. + asCArray m_scriptFunctions; // increases ref count + // This array holds global functions declared in the module. These references are not counted, + // as the same pointer is always present in the scriptFunctions array too. + asCSymbolTable m_globalFunctions; // doesn't increase ref count + // This array holds imported functions in the module. + asCArray m_bindInformations; // increases ref count + // This array holds template instance types created for the module's object types + asCArray m_templateInstances; // increases ref count + + // This array holds the global variables declared in the script + asCSymbolTable m_scriptGlobals; // increases ref count + bool m_isGlobalVarInitialized; + + // This array holds class and interface types + asCArray m_classTypes; // increases ref count + // This array holds enum types + asCArray m_enumTypes; // increases ref count + // This array holds typedefs + asCArray m_typeDefs; // increases ref count + // This array holds the funcdefs declared in the module + asCArray m_funcDefs; // increases ref count + + // This map contains all the types (also contained in the arrays above) for quick lookup + // TODO: memory: Can we eliminate the arrays above? + asCMap m_typeLookup; // doesn't increase ref count + + // This array holds types that have been explicitly declared with 'external' + asCArray m_externalTypes; // doesn't increase ref count + // This array holds functions that have been explicitly declared with 'external' + asCArray m_externalFunctions; // doesn't increase ref count }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_namespace.h b/src/angelscript/source/as_namespace.h index ae384e7aab9..b7960e40f4f 100644 --- a/src/angelscript/source/as_namespace.h +++ b/src/angelscript/source/as_namespace.h @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -38,37 +38,37 @@ BEGIN_AS_NAMESPACE struct asSNameSpace { - asCString name; + asCString name; - // TODO: namespace: A namespace should have access masks. The application should be - // able to restrict specific namespaces from access to specific modules + // 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)); - } + 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 diff --git a/src/angelscript/source/as_objecttype.cpp b/src/angelscript/source/as_objecttype.cpp index 626cb11b108..df6d2584524 100644 --- a/src/angelscript/source/as_objecttype.cpp +++ b/src/angelscript/source/as_objecttype.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -47,658 +47,658 @@ BEGIN_AS_NAMESPACE asCObjectType::asCObjectType() : asCTypeInfo() { - derivedFrom = 0; + derivedFrom = 0; - acceptValueSubType = true; - acceptRefSubType = true; + acceptValueSubType = true; + acceptRefSubType = true; #ifdef WIP_16BYTE_ALIGN - alignment = 4; + alignment = 4; #endif } asCObjectType::asCObjectType(asCScriptEngine *in_engine) : asCTypeInfo(in_engine) { - derivedFrom = 0; + derivedFrom = 0; - acceptValueSubType = true; - acceptRefSubType = true; + acceptValueSubType = true; + acceptRefSubType = true; #ifdef WIP_16BYTE_ALIGN - alignment = 4; + alignment = 4; #endif } // interface asUINT asCObjectType::GetChildFuncdefCount() const { - return childFuncDefs.GetLength(); + return childFuncDefs.GetLength(); } // interface asITypeInfo *asCObjectType::GetChildFuncdef(asUINT index) const { - if (index >= childFuncDefs.GetLength()) - return 0; + if (index >= childFuncDefs.GetLength()) + return 0; - return childFuncDefs[index]; + return childFuncDefs[index]; } // internal 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 - bool isTemplateInstance = templateSubTypes.GetLength() > 0; - for( asUINT subtypeIndex = 0; subtypeIndex < templateSubTypes.GetLength(); subtypeIndex++ ) - { - if( templateSubTypes[subtypeIndex].GetTypeInfo() ) - templateSubTypes[subtypeIndex].GetTypeInfo()->ReleaseInternal(); - } - templateSubTypes.SetLength(0); - - // Clear the child types - for (asUINT n = 0; n < childFuncDefs.GetLength(); n++) - { - asCFuncdefType *func = childFuncDefs[n]; - if (func) - { - func->parentClass = 0; - if (isTemplateInstance) - { - // Any child funcdefs that have been created as part of the template - // instantiation must be destroyed too - // TODO: Before destroying the funcdef, make sure no external references to it is held - if (func->externalRefCount.get() == 0) - { - func->DestroyInternal(); - engine->RemoveFuncdef(func); - func->module = 0; - func->ReleaseInternal(); - } - } - } - } - childFuncDefs.SetLength(0); - - if( derivedFrom ) - derivedFrom->ReleaseInternal(); - derivedFrom = 0; - - ReleaseAllProperties(); - - ReleaseAllFunctions(); - - CleanUserData(); - - // Remove the type from the engine - if( typeId != -1 ) - engine->RemoveFromTypeIdMap(this); - - // Clear the engine pointer to mark the object type as invalid - engine = 0; + 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 + bool isTemplateInstance = templateSubTypes.GetLength() > 0; + for( asUINT subtypeIndex = 0; subtypeIndex < templateSubTypes.GetLength(); subtypeIndex++ ) + { + if( templateSubTypes[subtypeIndex].GetTypeInfo() ) + templateSubTypes[subtypeIndex].GetTypeInfo()->ReleaseInternal(); + } + templateSubTypes.SetLength(0); + + // Clear the child types + for (asUINT n = 0; n < childFuncDefs.GetLength(); n++) + { + asCFuncdefType *func = childFuncDefs[n]; + if (func) + { + func->parentClass = 0; + if (isTemplateInstance) + { + // Any child funcdefs that have been created as part of the template + // instantiation must be destroyed too + // TODO: Before destroying the funcdef, make sure no external references to it is held + if (func->externalRefCount.get() == 0) + { + func->DestroyInternal(); + engine->RemoveFuncdef(func); + func->module = 0; + func->ReleaseInternal(); + } + } + } + } + childFuncDefs.SetLength(0); + + if( derivedFrom ) + derivedFrom->ReleaseInternal(); + derivedFrom = 0; + + ReleaseAllProperties(); + + ReleaseAllFunctions(); + + CleanUserData(); + + // Remove the type from the engine + if( typeId != -1 ) + engine->RemoveFromTypeIdMap(this); + + // Clear the engine pointer to mark the object type as invalid + engine = 0; } asCObjectType::~asCObjectType() { - DestroyInternal(); + DestroyInternal(); } // interface bool asCObjectType::Implements(const asITypeInfo *objType) const { - if( this == objType ) - return true; + if( this == objType ) + return true; - for( asUINT n = 0; n < interfaces.GetLength(); n++ ) - if( interfaces[n] == objType ) return true; + for( asUINT n = 0; n < interfaces.GetLength(); n++ ) + if( interfaces[n] == objType ) return true; - return false; + return false; } // interface bool asCObjectType::DerivesFrom(const asITypeInfo *objType) const { - if( this == objType ) - return true; + if( this == objType ) + return true; - asCObjectType *base = derivedFrom; - while( base ) - { - if( base == objType ) - return true; + asCObjectType *base = derivedFrom; + while( base ) + { + if( base == objType ) + return true; - base = base->derivedFrom; - } + base = base->derivedFrom; + } - return false; + return false; } // interface int asCObjectType::GetSubTypeId(asUINT subtypeIndex) const { - // This method is only supported for templates and template specializations - if( templateSubTypes.GetLength() == 0 ) - return asERROR; + // This method is only supported for templates and template specializations + if( templateSubTypes.GetLength() == 0 ) + return asERROR; - if( subtypeIndex >= templateSubTypes.GetLength() ) - return asINVALID_ARG; + if( subtypeIndex >= templateSubTypes.GetLength() ) + return asINVALID_ARG; - return engine->GetTypeIdFromDataType(templateSubTypes[subtypeIndex]); + return engine->GetTypeIdFromDataType(templateSubTypes[subtypeIndex]); } // interface asITypeInfo *asCObjectType::GetSubType(asUINT subtypeIndex) const { - if( subtypeIndex >= templateSubTypes.GetLength() ) - return 0; + if( subtypeIndex >= templateSubTypes.GetLength() ) + return 0; - return templateSubTypes[subtypeIndex].GetTypeInfo(); + return templateSubTypes[subtypeIndex].GetTypeInfo(); } asUINT asCObjectType::GetSubTypeCount() const { - return asUINT(templateSubTypes.GetLength()); + return asUINT(templateSubTypes.GetLength()); } asUINT asCObjectType::GetInterfaceCount() const { - return asUINT(interfaces.GetLength()); + return asUINT(interfaces.GetLength()); } asITypeInfo *asCObjectType::GetInterface(asUINT index) const { - return interfaces[index]; + return interfaces[index]; } // internal bool asCObjectType::IsInterface() const { - if( (flags & asOBJ_SCRIPT_OBJECT) && size == 0 ) - return true; + if( (flags & asOBJ_SCRIPT_OBJECT) && size == 0 ) + return true; - return false; + return false; } // interface asUINT asCObjectType::GetFactoryCount() const { - return (asUINT)beh.factories.GetLength(); + return (asUINT)beh.factories.GetLength(); } // interface asIScriptFunction *asCObjectType::GetFactoryByIndex(asUINT index) const { - if( index >= beh.factories.GetLength() ) - return 0; + if( index >= beh.factories.GetLength() ) + return 0; - return engine->GetFunctionById(beh.factories[index]); + return engine->GetFunctionById(beh.factories[index]); } // interface asIScriptFunction *asCObjectType::GetFactoryByDecl(const char *decl) const { - if( beh.factories.GetLength() == 0 ) - return 0; + 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)); + // 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(); + return (asUINT)methods.GetLength(); } // interface asIScriptFunction *asCObjectType::GetMethodByIndex(asUINT index, bool getVirtual) const { - if( index >= methods.GetLength() ) - return 0; + if( index >= methods.GetLength() ) + return 0; - asCScriptFunction *func = engine->scriptFunctions[methods[index]]; - if( !getVirtual ) - { - if( func && func->funcType == asFUNC_VIRTUAL ) - return virtualFunctionTable[func->vfTableIdx]; - } + asCScriptFunction *func = engine->scriptFunctions[methods[index]]; + if( !getVirtual ) + { + if( func && func->funcType == asFUNC_VIRTUAL ) + return virtualFunctionTable[func->vfTableIdx]; + } - return func; + return func; } // interface asIScriptFunction *asCObjectType::GetMethodByName(const char *in_name, bool in_getVirtual) const { - int id = -1; - for( asUINT n = 0; n < methods.GetLength(); n++ ) - { - if( engine->scriptFunctions[methods[n]]->name == in_name ) - { - if( id == -1 ) - id = methods[n]; - else - return 0; - } - } - - if( id == -1 ) return 0; - - asCScriptFunction *func = engine->scriptFunctions[id]; - if( !in_getVirtual ) - { - if( func && func->funcType == asFUNC_VIRTUAL ) - return virtualFunctionTable[func->vfTableIdx]; - } - - return func; + int id = -1; + for( asUINT n = 0; n < methods.GetLength(); n++ ) + { + if( engine->scriptFunctions[methods[n]]->name == in_name ) + { + if( id == -1 ) + id = methods[n]; + else + return 0; + } + } + + if( id == -1 ) return 0; + + asCScriptFunction *func = engine->scriptFunctions[id]; + if( !in_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]; + 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(); + return (asUINT)properties.GetLength(); } // interface int asCObjectType::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const { - if( index >= properties.GetLength() ) - return asINVALID_ARG; - - asCObjectProperty *prop = properties[index]; - if( out_name ) - *out_name = prop->name.AddressOf(); - if( out_typeId ) - *out_typeId = engine->GetTypeIdFromDataType(prop->type); - if( out_isPrivate ) - *out_isPrivate = prop->isPrivate; - if( out_isProtected ) - *out_isProtected = prop->isProtected; - if( out_offset ) - *out_offset = prop->byteOffset; - if( out_isReference ) - *out_isReference = prop->type.IsReference(); - if( out_accessMask ) - *out_accessMask = prop->accessMask; - if (out_compositeOffset) - *out_compositeOffset = prop->compositeOffset; - if (out_isCompositeIndirect) - *out_isCompositeIndirect = prop->isCompositeIndirect; - - return 0; + if( index >= properties.GetLength() ) + return asINVALID_ARG; + + asCObjectProperty *prop = properties[index]; + if( out_name ) + *out_name = prop->name.AddressOf(); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(prop->type); + if( out_isPrivate ) + *out_isPrivate = prop->isPrivate; + if( out_isProtected ) + *out_isProtected = prop->isProtected; + if( out_offset ) + *out_offset = prop->byteOffset; + if( out_isReference ) + *out_isReference = prop->type.IsReference(); + if( out_accessMask ) + *out_accessMask = prop->accessMask; + if (out_compositeOffset) + *out_compositeOffset = prop->compositeOffset; + if (out_isCompositeIndirect) + *out_isCompositeIndirect = prop->isCompositeIndirect; + + return 0; } // 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 if( properties[index]->isProtected ) - *tempString = "protected "; - else - *tempString = ""; - *tempString += properties[index]->type.Format(nameSpace, includeNamespace); - *tempString += " "; - *tempString += properties[index]->name; - - return tempString->AddressOf(); + if( index >= properties.GetLength() ) + return 0; + + asCString *tempString = &asCThreadManager::GetLocalData()->string; + if( properties[index]->isPrivate ) + *tempString = "private "; + else if( properties[index]->isProtected ) + *tempString = "protected "; + else + *tempString = ""; + *tempString += properties[index]->type.Format(nameSpace, includeNamespace); + *tempString += " "; + *tempString += properties[index]->name; + + return tempString->AddressOf(); } asITypeInfo *asCObjectType::GetBaseType() const { - return derivedFrom; + 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(); - - return count; + // 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(); + + 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(); - - return 0; + // 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(); + + return 0; } // internal asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &propName, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited) { - 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 = propName; - prop->type = dt; - prop->isPrivate = isPrivate; - prop->isProtected = isProtected; - prop->isInherited = isInherited; - - 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.GetTypeInfo()->flags & asOBJ_POD ) - propSize = dt.GetSizeInMemoryBytes(); - else - { - propSize = dt.GetSizeOnStackDWords()*4; - if( !dt.IsObjectHandle() ) - prop->type.MakeReference(true); - } - } - else if (dt.IsFuncdef()) - { - // Funcdefs don't have a size, as they must always be stored as handles - asASSERT(dt.IsObjectHandle()); - propSize = AS_PTR_SIZE * 4; - } - else - propSize = dt.GetSizeInMemoryBytes(); - - // Add extra bytes so that the property will be properly aligned + 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 = propName; + prop->type = dt; + prop->isPrivate = isPrivate; + prop->isProtected = isProtected; + prop->isInherited = isInherited; + + 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.GetTypeInfo()->flags & asOBJ_POD ) + propSize = dt.GetSizeInMemoryBytes(); + else + { + propSize = dt.GetSizeOnStackDWords()*4; + if( !dt.IsObjectHandle() ) + prop->type.MakeReference(true); + } + } + else if (dt.IsFuncdef()) + { + // Funcdefs don't have a size, as they must always be stored as handles + asASSERT(dt.IsObjectHandle()); + propSize = AS_PTR_SIZE * 4; + } + else + propSize = dt.GetSizeInMemoryBytes(); + + // 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); + 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); + 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; + prop->byteOffset = size; + size += propSize; - properties.PushLast(prop); + properties.PushLast(prop); - // Make sure the struct holds a reference to the config group where the object is registered - asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(prop->type.GetTypeInfo()); - if( group != 0 ) group->AddRef(); + // Make sure the struct holds a reference to the config group where the object is registered + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(prop->type.GetTypeInfo()); + if( group != 0 ) group->AddRef(); - // Add reference to object types - asCTypeInfo *type = prop->type.GetTypeInfo(); - if( type ) - type->AddRefInternal(); + // Add reference to object types + asCTypeInfo *type = prop->type.GetTypeInfo(); + if( type ) + type->AddRefInternal(); - return prop; + 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->FindConfigGroupForTypeInfo(properties[n]->type.GetTypeInfo()); - if( group != 0 ) group->Release(); - - // Release references to objects types - asCTypeInfo *type = properties[n]->type.GetTypeInfo(); - if( type ) - type->ReleaseInternal(); - } - else - { - // Release template instance types (ref increased by RegisterObjectProperty) - asCTypeInfo *type = properties[n]->type.GetTypeInfo(); - if( type ) - type->ReleaseInternal(); - } - - asDELETE(properties[n],asCObjectProperty); - } - } - - properties.SetLength(0); + 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->FindConfigGroupForTypeInfo(properties[n]->type.GetTypeInfo()); + if( group != 0 ) group->Release(); + + // Release references to objects types + asCTypeInfo *type = properties[n]->type.GetTypeInfo(); + if( type ) + type->ReleaseInternal(); + } + else + { + // Release template instance types (ref increased by RegisterObjectProperty) + asCTypeInfo *type = properties[n]->type.GetTypeInfo(); + if( type ) + type->ReleaseInternal(); + } + + asDELETE(properties[n],asCObjectProperty); + } + } + + properties.SetLength(0); } // 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]]->ReleaseInternal(); - } - 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]]->ReleaseInternal(); - } - beh.constructors.SetLength(0); - - if( beh.templateCallback ) - engine->scriptFunctions[beh.templateCallback]->ReleaseInternal(); - beh.templateCallback = 0; - - if( beh.listFactory ) - engine->scriptFunctions[beh.listFactory]->ReleaseInternal(); - beh.listFactory = 0; - - if( beh.destruct ) - engine->scriptFunctions[beh.destruct]->ReleaseInternal(); - beh.destruct = 0; - - if( beh.copy ) - engine->scriptFunctions[beh.copy]->ReleaseInternal(); - beh.copy = 0; - - for( asUINT c = 0; c < methods.GetLength(); c++ ) - { - if( engine->scriptFunctions[methods[c]] ) - engine->scriptFunctions[methods[c]]->ReleaseInternal(); - } - methods.SetLength(0); - - for( asUINT d = 0; d < virtualFunctionTable.GetLength(); d++ ) - { - if( virtualFunctionTable[d] ) - virtualFunctionTable[d]->ReleaseInternal(); - } - virtualFunctionTable.SetLength(0); - - // GC behaviours - if( beh.addref ) - engine->scriptFunctions[beh.addref]->ReleaseInternal(); - beh.addref = 0; - - if( beh.release ) - engine->scriptFunctions[beh.release]->ReleaseInternal(); - beh.release = 0; - - if( beh.gcEnumReferences ) - engine->scriptFunctions[beh.gcEnumReferences]->ReleaseInternal(); - beh.gcEnumReferences = 0; - - if( beh.gcGetFlag ) - engine->scriptFunctions[beh.gcGetFlag]->ReleaseInternal(); - beh.gcGetFlag = 0; - - if( beh.gcGetRefCount ) - engine->scriptFunctions[beh.gcGetRefCount]->ReleaseInternal(); - beh.gcGetRefCount = 0; - - if( beh.gcReleaseAllReferences ) - engine->scriptFunctions[beh.gcReleaseAllReferences]->ReleaseInternal(); - beh.gcReleaseAllReferences = 0; - - if( beh.gcSetFlag ) - engine->scriptFunctions[beh.gcSetFlag]->ReleaseInternal(); - beh.gcSetFlag = 0; - - if ( beh.getWeakRefFlag ) - engine->scriptFunctions[beh.getWeakRefFlag]->ReleaseInternal(); - beh.getWeakRefFlag = 0; + 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]]->ReleaseInternal(); + } + 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]]->ReleaseInternal(); + } + beh.constructors.SetLength(0); + + if( beh.templateCallback ) + engine->scriptFunctions[beh.templateCallback]->ReleaseInternal(); + beh.templateCallback = 0; + + if( beh.listFactory ) + engine->scriptFunctions[beh.listFactory]->ReleaseInternal(); + beh.listFactory = 0; + + if( beh.destruct ) + engine->scriptFunctions[beh.destruct]->ReleaseInternal(); + beh.destruct = 0; + + if( beh.copy ) + engine->scriptFunctions[beh.copy]->ReleaseInternal(); + beh.copy = 0; + + for( asUINT c = 0; c < methods.GetLength(); c++ ) + { + if( engine->scriptFunctions[methods[c]] ) + engine->scriptFunctions[methods[c]]->ReleaseInternal(); + } + methods.SetLength(0); + + for( asUINT d = 0; d < virtualFunctionTable.GetLength(); d++ ) + { + if( virtualFunctionTable[d] ) + virtualFunctionTable[d]->ReleaseInternal(); + } + virtualFunctionTable.SetLength(0); + + // GC behaviours + if( beh.addref ) + engine->scriptFunctions[beh.addref]->ReleaseInternal(); + beh.addref = 0; + + if( beh.release ) + engine->scriptFunctions[beh.release]->ReleaseInternal(); + beh.release = 0; + + if( beh.gcEnumReferences ) + engine->scriptFunctions[beh.gcEnumReferences]->ReleaseInternal(); + beh.gcEnumReferences = 0; + + if( beh.gcGetFlag ) + engine->scriptFunctions[beh.gcGetFlag]->ReleaseInternal(); + beh.gcGetFlag = 0; + + if( beh.gcGetRefCount ) + engine->scriptFunctions[beh.gcGetRefCount]->ReleaseInternal(); + beh.gcGetRefCount = 0; + + if( beh.gcReleaseAllReferences ) + engine->scriptFunctions[beh.gcReleaseAllReferences]->ReleaseInternal(); + beh.gcReleaseAllReferences = 0; + + if( beh.gcSetFlag ) + engine->scriptFunctions[beh.gcSetFlag]->ReleaseInternal(); + beh.gcSetFlag = 0; + + if ( beh.getWeakRefFlag ) + engine->scriptFunctions[beh.getWeakRefFlag]->ReleaseInternal(); + beh.getWeakRefFlag = 0; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_objecttype.h b/src/angelscript/source/as_objecttype.h index 4b7bd5d0f8a..9b1398d5a4a 100644 --- a/src/angelscript/source/as_objecttype.h +++ b/src/angelscript/source/as_objecttype.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -50,49 +50,49 @@ BEGIN_AS_NAMESPACE 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; + 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; }; class asCScriptEngine; @@ -101,69 +101,69 @@ struct asSNameSpace; class asCObjectType : public asCTypeInfo { public: - asITypeInfo *GetBaseType() const; - bool DerivesFrom(const asITypeInfo *objType) const; - int GetSubTypeId(asUINT subtypeIndex = 0) const; - asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const; - asUINT GetSubTypeCount() const; - asUINT GetInterfaceCount() const; - asITypeInfo *GetInterface(asUINT index) const; - bool Implements(const asITypeInfo *objType) const; - asUINT GetFactoryCount() const; - asIScriptFunction *GetFactoryByIndex(asUINT index) const; - asIScriptFunction *GetFactoryByDecl(const char *decl) const; - 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; - asUINT GetPropertyCount() const; - int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const; - const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const; - asUINT GetBehaviourCount() const; - asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const; - asUINT GetChildFuncdefCount() const; - asITypeInfo *GetChildFuncdef(asUINT index) const; + asITypeInfo *GetBaseType() const; + bool DerivesFrom(const asITypeInfo *objType) const; + int GetSubTypeId(asUINT subtypeIndex = 0) const; + asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const; + asUINT GetSubTypeCount() const; + asUINT GetInterfaceCount() const; + asITypeInfo *GetInterface(asUINT index) const; + bool Implements(const asITypeInfo *objType) const; + asUINT GetFactoryCount() const; + asIScriptFunction *GetFactoryByIndex(asUINT index) const; + asIScriptFunction *GetFactoryByDecl(const char *decl) const; + 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; + asUINT GetPropertyCount() const; + int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const; + const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const; + asUINT GetBehaviourCount() const; + asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const; + asUINT GetChildFuncdefCount() const; + asITypeInfo *GetChildFuncdef(asUINT index) const; public: - asCObjectType(asCScriptEngine *engine); - ~asCObjectType(); - void DestroyInternal(); + asCObjectType(asCScriptEngine *engine); + ~asCObjectType(); + void DestroyInternal(); - void ReleaseAllFunctions(); + void ReleaseAllFunctions(); - bool IsInterface() const; + bool IsInterface() const; - asCObjectProperty *AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited); - void ReleaseAllProperties(); + asCObjectProperty *AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited); + void ReleaseAllProperties(); #ifdef WIP_16BYTE_ALIGN - int alignment; + int alignment; #endif - asCArray properties; - asCArray methods; + asCArray properties; + asCArray methods; - // TODO: These are not used by template types. Should perhaps create a derived class to save memory on ordinary object types - asCArray interfaces; - asCArray interfaceVFTOffsets; - asCObjectType * derivedFrom; - asCArray virtualFunctionTable; + // TODO: These are not used by template types. Should perhaps create a derived class to save memory on ordinary object types + asCArray interfaces; + asCArray interfaceVFTOffsets; + asCObjectType * derivedFrom; + asCArray virtualFunctionTable; - // Used for funcdefs declared as members of class. - // TODO: child funcdef: Should be possible to enumerate these from application - asCArray childFuncDefs; + // Used for funcdefs declared as members of class. + // TODO: child funcdef: Should be possible to enumerate these from application + asCArray childFuncDefs; - asSTypeBehaviour beh; + asSTypeBehaviour beh; - // Used for template types - asCArray templateSubTypes; // increases refCount for typeinfo held in datatype - bool acceptValueSubType; - bool acceptRefSubType; + // Used for template types + asCArray templateSubTypes; // increases refCount for typeinfo held in datatype + bool acceptValueSubType; + bool acceptRefSubType; protected: - friend class asCScriptEngine; - friend class asCConfigGroup; - friend class asCModule; - asCObjectType(); + friend class asCScriptEngine; + friend class asCConfigGroup; + friend class asCModule; + asCObjectType(); }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_outputbuffer.cpp b/src/angelscript/source/as_outputbuffer.cpp index 433f820f66b..e5c80299a0e 100644 --- a/src/angelscript/source/as_outputbuffer.cpp +++ b/src/angelscript/source/as_outputbuffer.cpp @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -47,60 +47,60 @@ BEGIN_AS_NAMESPACE asCOutputBuffer::~asCOutputBuffer() { - Clear(); + Clear(); } void asCOutputBuffer::Clear() { - for( asUINT n = 0; n < messages.GetLength(); n++ ) - { - if( messages[n] ) - { - asDELETE(messages[n],message_t); - } - } - messages.SetLength(0); + 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; + 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; + msgInfo->section = msg->section; + msgInfo->row = msg->row; + msgInfo->col = msg->col; + msgInfo->type = msg->type; + msgInfo->msg = msg->message; - messages.PushLast(msgInfo); + 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); + 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(); + 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 diff --git a/src/angelscript/source/as_outputbuffer.h b/src/angelscript/source/as_outputbuffer.h index 500b1625203..95137adce0c 100644 --- a/src/angelscript/source/as_outputbuffer.h +++ b/src/angelscript/source/as_outputbuffer.h @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -55,22 +55,22 @@ 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; + ~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 diff --git a/src/angelscript/source/as_parser.cpp b/src/angelscript/source/as_parser.cpp index 2de81aa0fd7..27bf5e34a31 100644 --- a/src/angelscript/source/as_parser.cpp +++ b/src/angelscript/source/as_parser.cpp @@ -63,461 +63,461 @@ BEGIN_AS_NAMESPACE asCParser::asCParser(asCBuilder *builder) { - this->builder = builder; - this->engine = builder->engine; + this->builder = builder; + this->engine = builder->engine; - script = 0; - scriptNode = 0; - checkValidTypes = false; - isParsingAppInterface = false; + script = 0; + scriptNode = 0; + checkValidTypes = false; + isParsingAppInterface = false; } asCParser::~asCParser() { - Reset(); + Reset(); } void asCParser::Reset() { - errorWhileParsing = false; - isSyntaxError = false; - checkValidTypes = false; - isParsingAppInterface = false; + errorWhileParsing = false; + isSyntaxError = false; + checkValidTypes = false; + isParsingAppInterface = false; - sourcePos = 0; + sourcePos = 0; - if( scriptNode ) - { - scriptNode->Destroy(engine); - } + if( scriptNode ) + { + scriptNode->Destroy(engine); + } - scriptNode = 0; + scriptNode = 0; - script = 0; + script = 0; - lastToken.pos = size_t(-1); + lastToken.pos = size_t(-1); } asCScriptNode *asCParser::GetScriptNode() { - return scriptNode; + return scriptNode; } int asCParser::ParseFunctionDefinition(asCScriptCode *in_script, bool in_expectListPattern) { - Reset(); + Reset(); - // Set flag that permits ? as datatype for parameters - isParsingAppInterface = true; + // Set flag that permits ? as datatype for parameters + isParsingAppInterface = true; - this->script = in_script; + this->script = in_script; - scriptNode = ParseFunctionDefinition(); + scriptNode = ParseFunctionDefinition(); - if( in_expectListPattern ) - scriptNode->AddChildLast(ParseListPattern()); + if( in_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; - } - } + // 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; + if( errorWhileParsing ) + return -1; - return 0; + 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); + void *ptr = engine->memoryMgr.AllocScriptNode(); + if( ptr == 0 ) + { + // Out of memory + errorWhileParsing = true; + return 0; + } + + return new(ptr) asCScriptNode(type); } int asCParser::ParseDataType(asCScriptCode *in_script, bool in_isReturnType) { - Reset(); + Reset(); - this->script = in_script; + this->script = in_script; - scriptNode = CreateNode(snDataType); - if( scriptNode == 0 ) return -1; + scriptNode = CreateNode(snDataType); + if( scriptNode == 0 ) return -1; - scriptNode->AddChildLast(ParseType(true)); - if( isSyntaxError ) return -1; + scriptNode->AddChildLast(ParseType(true)); + if( isSyntaxError ) return -1; - if( in_isReturnType ) - { - scriptNode->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return -1; - } + if( in_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; - } + // 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; + if( errorWhileParsing ) + return -1; - return 0; + return 0; } // Parse a template declaration: IDENTIFIER '<' 'class'? IDENTIFIER '>' int asCParser::ParseTemplateDecl(asCScriptCode *in_script) { - Reset(); - - this->script = in_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; + Reset(); + + this->script = in_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 *in_script) { - Reset(); + Reset(); - this->script = in_script; + this->script = in_script; - scriptNode = CreateNode(snDeclaration); - if( scriptNode == 0 ) return -1; + scriptNode = CreateNode(snDeclaration); + if( scriptNode == 0 ) return -1; - scriptNode->AddChildLast(ParseType(true)); - if( isSyntaxError ) return -1; + scriptNode->AddChildLast(ParseType(true)); + if( isSyntaxError ) return -1; - // Allow optional '&' to indicate that the property is indirect, i.e. stored as reference - sToken t; - GetToken(&t); - RewindTo(&t); - if( t.type == ttAmp ) - scriptNode->AddChildLast(ParseToken(ttAmp)); + // Allow optional '&' to indicate that the property is indirect, i.e. stored as reference + sToken t; + GetToken(&t); + RewindTo(&t); + if( t.type == ttAmp ) + scriptNode->AddChildLast(ParseToken(ttAmp)); - // 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); + // 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; + scriptNode->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return -1; - // The declaration should end after the identifier - GetToken(&t); - if( t.type != ttEnd ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); - Error(InsteadFound(t), &t); - return -1; - } + // The declaration should end after the identifier + GetToken(&t); + if( t.type != ttEnd ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); + Error(InsteadFound(t), &t); + return -1; + } - return 0; + return 0; } // BNF:5: SCOPE ::= ['::'] {IDENTIFIER '::'} [IDENTIFIER ['<' TYPE {',' TYPE} '>'] '::'] void asCParser::ParseOptionalScope(asCScriptNode *node) { - asCScriptNode *scope = CreateNode(snScope); - - sToken t1, t2; - GetToken(&t1); - GetToken(&t2); - if( t1.type == ttScope ) - { - RewindTo(&t1); - scope->AddChildLast(ParseToken(ttScope)); - GetToken(&t1); - GetToken(&t2); - } - while( t1.type == ttIdentifier && t2.type == ttScope ) - { - RewindTo(&t1); - scope->AddChildLast(ParseIdentifier()); - scope->AddChildLast(ParseToken(ttScope)); - GetToken(&t1); - GetToken(&t2); - } - - // The innermost scope may be a template type - if( t1.type == ttIdentifier && t2.type == ttLessThan ) - { - tempString.Assign(&script->code[t1.pos], t1.length); - if (engine->IsTemplateType(tempString.AddressOf())) - { - RewindTo(&t1); - asCScriptNode *restore = scope->lastChild; - scope->AddChildLast(ParseIdentifier()); - if (ParseTemplTypeList(scope, false)) - { - GetToken(&t2); - if (t2.type == ttScope) - { - // Template type is part of the scope - // Nothing more needs to be done - node->AddChildLast(scope); - return; - } - else - { - // The template type is not part of the scope - // Rewind to the template type and end the scope - RewindTo(&t1); - - // Restore the previously parsed node - while (scope->lastChild != restore) - { - asCScriptNode *last = scope->lastChild; - last->DisconnectParent(); - last->Destroy(engine); - } - if( scope->lastChild ) - node->AddChildLast(scope); - else - scope->Destroy(engine); - return; - } - } - } - } - - // The identifier is not part of the scope - RewindTo(&t1); - - if (scope->lastChild) - node->AddChildLast(scope); - else - scope->Destroy(engine); + asCScriptNode *scope = CreateNode(snScope); + + sToken t1, t2; + GetToken(&t1); + GetToken(&t2); + if( t1.type == ttScope ) + { + RewindTo(&t1); + scope->AddChildLast(ParseToken(ttScope)); + GetToken(&t1); + GetToken(&t2); + } + while( t1.type == ttIdentifier && t2.type == ttScope ) + { + RewindTo(&t1); + scope->AddChildLast(ParseIdentifier()); + scope->AddChildLast(ParseToken(ttScope)); + GetToken(&t1); + GetToken(&t2); + } + + // The innermost scope may be a template type + if( t1.type == ttIdentifier && t2.type == ttLessThan ) + { + tempString.Assign(&script->code[t1.pos], t1.length); + if (engine->IsTemplateType(tempString.AddressOf())) + { + RewindTo(&t1); + asCScriptNode *restore = scope->lastChild; + scope->AddChildLast(ParseIdentifier()); + if (ParseTemplTypeList(scope, false)) + { + GetToken(&t2); + if (t2.type == ttScope) + { + // Template type is part of the scope + // Nothing more needs to be done + node->AddChildLast(scope); + return; + } + else + { + // The template type is not part of the scope + // Rewind to the template type and end the scope + RewindTo(&t1); + + // Restore the previously parsed node + while (scope->lastChild != restore) + { + asCScriptNode *last = scope->lastChild; + last->DisconnectParent(); + last->Destroy(engine); + } + if( scope->lastChild ) + node->AddChildLast(scope); + else + scope->Destroy(engine); + return; + } + } + } + } + + // The identifier is not part of the scope + RewindTo(&t1); + + if (scope->lastChild) + node->AddChildLast(scope); + else + scope->Destroy(engine); } asCScriptNode *asCParser::ParseFunctionDefinition() { - asCScriptNode *node = CreateNode(snFunction); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snFunction); + if( node == 0 ) return 0; - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; + node->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return node; - ParseOptionalScope(node); + ParseOptionalScope(node); - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; - node->AddChildLast(ParseParameterList()); - 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)); + // Parse an optional 'const' after the function definition (used for object methods) + sToken t1; + GetToken(&t1); + RewindTo(&t1); + if( t1.type == ttConst ) + node->AddChildLast(ParseToken(ttConst)); - // Parse optional attributes - ParseMethodAttributes(node); + // Parse optional attributes + ParseMethodAttributes(node); - return node; + return node; } // BNF:4: TYPEMOD ::= ['&' ['in' | 'out' | 'inout']] 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; - } - - // Parse possible if_handle_then_const token - GetToken(&t); - RewindTo(&t); - if (IdentifierIs(t, IF_HANDLE_TOKEN)) - { - node->AddChildLast(ParseToken(ttIdentifier)); - if (isSyntaxError) return node; - } - - return node; + 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; + } + + // Parse possible if_handle_then_const token + GetToken(&t); + RewindTo(&t); + if (IdentifierIs(t, IF_HANDLE_TOKEN)) + { + node->AddChildLast(ParseToken(ttIdentifier)); + if (isSyntaxError) return node; + } + + return node; } // BNF:4: TYPE ::= ['const'] SCOPE DATATYPE ['<' TYPE {',' TYPE} '>'] { ('[' ']') | ('@' ['const']) } 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 < > - GetToken(&t); - RewindTo(&t); - asCScriptNode *type = node->lastChild; - tempString.Assign(&script->code[type->tokenPos], type->tokenLength); - if( engine->IsTemplateType(tempString.AddressOf()) && t.type == ttLessThan ) - { - ParseTemplTypeList(node); - if (isSyntaxError) return node; - } - - // 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); - if( t.type == ttConst ) - { - node->AddChildLast(ParseToken(ttConst)); - if( isSyntaxError ) return node; - } - } - - GetToken(&t); - RewindTo(&t); - } - - return node; + 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 < > + GetToken(&t); + RewindTo(&t); + asCScriptNode *type = node->lastChild; + tempString.Assign(&script->code[type->tokenPos], type->tokenLength); + if( engine->IsTemplateType(tempString.AddressOf()) && t.type == ttLessThan ) + { + ParseTemplTypeList(node); + if (isSyntaxError) return node; + } + + // 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); + if( t.type == ttConst ) + { + node->AddChildLast(ParseToken(ttConst)); + if( isSyntaxError ) return node; + } + } + + GetToken(&t); + RewindTo(&t); + } + + return node; } // This parses a template type list, e.g. @@ -526,716 +526,716 @@ asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType, boo // can be used as do an optional parsing bool asCParser::ParseTemplTypeList(asCScriptNode *node, bool required) { - sToken t; - bool isValid = true; - - // Remember the last child, so we can restore the state if needed - asCScriptNode *last = node->lastChild; - - // Starts with '<' - GetToken(&t); - if (t.type != ttLessThan) - { - if (required) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t); - Error(InsteadFound(t), &t); - } - return false; - } - - // At least one type - // TODO: child funcdef: Make this work with !required - node->AddChildLast(ParseType(true, false)); - if (isSyntaxError) return false; - - GetToken(&t); - - // Parse template types by list separator - while (t.type == ttListSeparator) - { - // TODO: child funcdef: Make this work with !required - node->AddChildLast(ParseType(true, false)); - if (isSyntaxError) return false; - GetToken(&t); - } - - // End with '>' - // Accept >> and >>> tokens too. But then force the tokenizer to move - // only 1 character ahead (thus splitting the token in two). - if (script->code[t.pos] != '>') - { - if (required) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t); - Error(InsteadFound(t), &t); - } - else - isValid = false; - } - else - { - // Break the token so that only the first > is parsed - SetPos(t.pos + 1); - } - - if (!required && !isValid) - { - // Restore the original state before returning - while (node->lastChild != last) - { - asCScriptNode *n = node->lastChild; - n->DisconnectParent(); - n->Destroy(engine); - } - - return false; - } - - // The template type list was parsed OK - return true; + sToken t; + bool isValid = true; + + // Remember the last child, so we can restore the state if needed + asCScriptNode *last = node->lastChild; + + // Starts with '<' + GetToken(&t); + if (t.type != ttLessThan) + { + if (required) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t); + Error(InsteadFound(t), &t); + } + return false; + } + + // At least one type + // TODO: child funcdef: Make this work with !required + node->AddChildLast(ParseType(true, false)); + if (isSyntaxError) return false; + + GetToken(&t); + + // Parse template types by list separator + while (t.type == ttListSeparator) + { + // TODO: child funcdef: Make this work with !required + node->AddChildLast(ParseType(true, false)); + if (isSyntaxError) return false; + GetToken(&t); + } + + // End with '>' + // Accept >> and >>> tokens too. But then force the tokenizer to move + // only 1 character ahead (thus splitting the token in two). + if (script->code[t.pos] != '>') + { + if (required) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t); + Error(InsteadFound(t), &t); + } + else + isValid = false; + } + else + { + // Break the token so that only the first > is parsed + SetPos(t.pos + 1); + } + + if (!required && !isValid) + { + // Restore the original state before returning + while (node->lastChild != last) + { + asCScriptNode *n = node->lastChild; + n->DisconnectParent(); + n->Destroy(engine); + } + + return false; + } + + // The template type list was parsed OK + return true; } asCScriptNode *asCParser::ParseToken(int token) { - asCScriptNode *node = CreateNode(snUndefined); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snUndefined); + if( node == 0 ) return 0; - sToken t1; + sToken t1; - GetToken(&t1); - if( t1.type != token ) - { - Error(ExpectedToken(asCTokenizer::GetDefinition(token)), &t1); - Error(InsteadFound(t1), &t1); - return node; - } + 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); + node->SetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); - return node; + 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 *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; } // BNF:5: DATATYPE ::= (IDENTIFIER | PRIMTYPE | '?' | 'auto') 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 *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; } // BNF:6: PRIMTYPE ::= 'void' | 'int' | 'int8' | 'int16' | 'int32' | 'int64' | 'uint' | 'uint8' | 'uint16' | 'uint32' | 'uint64' | 'float' | 'double' | 'bool' asCScriptNode *asCParser::ParseRealType() { - asCScriptNode *node = CreateNode(snDataType); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snDataType); + if( node == 0 ) return 0; - sToken t1; + sToken t1; - GetToken(&t1); - if( !IsRealType(t1.type) ) - { - Error(TXT_EXPECTED_DATA_TYPE, &t1); - Error(InsteadFound(t1), &t1); - return node; - } + 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); + node->SetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); - return node; + return node; } // BNF:17: IDENTIFIER ::= single token: starts with letter or _, can include any letter and digit, same as in C++ asCScriptNode *asCParser::ParseIdentifier() { - asCScriptNode *node = CreateNode(snIdentifier); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snIdentifier); + if( node == 0 ) return 0; - sToken t1; + sToken t1; - GetToken(&t1); - if( t1.type != ttIdentifier ) - { - Error(TXT_EXPECTED_IDENTIFIER, &t1); - Error(InsteadFound(t1), &t1); - return node; - } + 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); + node->SetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); - return node; + return node; } // BNF:3: PARAMLIST ::= '(' ['void' | (TYPE TYPEMOD [IDENTIFIER] ['=' EXPR] {',' TYPE TYPEMOD [IDENTIFIER] ['=' EXPR]})] ')' 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 *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; + 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 ); + // 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; + 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. + // 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; + // Store the token so it doesn't have to be tokenized again + lastToken = *token; - sourcePos = token->pos; + sourcePos = token->pos; } void asCParser::Error(const asCString &text, sToken *token) { - RewindTo(token); + RewindTo(token); - isSyntaxError = true; - errorWhileParsing = true; + isSyntaxError = true; + errorWhileParsing = true; - int row, col; - script->ConvertPosToRowCol(token->pos, &row, &col); + int row, col; + script->ConvertPosToRowCol(token->pos, &row, &col); - if( builder ) - builder->WriteError(script->name, text, 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); + int row, col; + script->ConvertPosToRowCol(token->pos, &row, &col); - if( builder ) - builder->WriteWarning(script->name, text, row, col); + if( builder ) + builder->WriteWarning(script->name, text, row, col); } void asCParser::Info(const asCString &text, sToken *token) { - RewindTo(token); + RewindTo(token); - isSyntaxError = true; - errorWhileParsing = true; + isSyntaxError = true; + errorWhileParsing = true; - int row, col; - script->ConvertPosToRowCol(token->pos, &row, &col); + int row, col; + script->ConvertPosToRowCol(token->pos, &row, &col); - if( builder ) - builder->WriteInfo(script->name, text, row, col, false); + 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; + 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 ) - { + 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; - } + 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; - } + return true; + } - if( IsRealType(token.type) ) - return true; + if( IsRealType(token.type) ) + return true; - return false; + return false; } asCString asCParser::ExpectedToken(const char *token) { - asCString str; + asCString str; - str.Format(TXT_EXPECTED_s, token); + str.Format(TXT_EXPECTED_s, token); - return str; + return str; } asCString asCParser::ExpectedTokens(const char *t1, const char *t2) { - asCString str; + asCString str; - str.Format(TXT_EXPECTED_s_OR_s, t1, t2); + str.Format(TXT_EXPECTED_s_OR_s, t1, t2); - return str; + return str; } asCString asCParser::ExpectedOneOf(int *tokens, int count) { - asCString str; + asCString str; - str = TXT_EXPECTED_ONE_OF; - for( int n = 0; n < count; n++ ) - { - str += asCTokenizer::GetDefinition(tokens[n]); - if( n < count-1 ) - 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; + return str; } asCString asCParser::ExpectedOneOf(const char **tokens, int count) { - asCString str; + asCString str; - str = TXT_EXPECTED_ONE_OF; - for( int n = 0; n < count; n++ ) - { - str += tokens[n]; - if( n < count-1 ) - str += ", "; - } + str = TXT_EXPECTED_ONE_OF; + for( int n = 0; n < count; n++ ) + { + str += tokens[n]; + if( n < count-1 ) + str += ", "; + } - return 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_IDENTIFIER_s, id.AddressOf()); - } - else if( t.type >= ttIf ) - str.Format(TXT_INSTEAD_FOUND_KEYWORD_s, asCTokenizer::GetDefinition(t.type)); - else - str.Format(TXT_INSTEAD_FOUND_s, asCTokenizer::GetDefinition(t.type)); - - return str; + asCString str; + if( t.type == ttIdentifier ) + { + asCString id(&script->code[t.pos], t.length); + str.Format(TXT_INSTEAD_FOUND_IDENTIFIER_s, id.AddressOf()); + } + else if( t.type >= ttIf ) + str.Format(TXT_INSTEAD_FOUND_KEYWORD_s, asCTokenizer::GetDefinition(t.type)); + else + str.Format(TXT_INSTEAD_FOUND_s, asCTokenizer::GetDefinition(t.type)); + + return str; } 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; + 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; + if( t.type != ttIdentifier ) + return false; - return script->TokenEquals(t.pos, t.length, str); + return script->TokenEquals(t.pos, t.length, str); } // BNF:6: FUNCATTR ::= {'override' | 'final' | 'explicit' | 'property'} void asCParser::ParseMethodAttributes(asCScriptNode *funcNode) { - sToken t1; - - for(;;) - { - GetToken(&t1); - RewindTo(&t1); - - if( IdentifierIs(t1, FINAL_TOKEN) || - IdentifierIs(t1, OVERRIDE_TOKEN) || - IdentifierIs(t1, EXPLICIT_TOKEN) || - IdentifierIs(t1, PROPERTY_TOKEN) ) - funcNode->AddChildLast(ParseIdentifier()); - else - break; - } + sToken t1; + + for(;;) + { + GetToken(&t1); + RewindTo(&t1); + + if( IdentifierIs(t1, FINAL_TOKEN) || + IdentifierIs(t1, OVERRIDE_TOKEN) || + IdentifierIs(t1, EXPLICIT_TOKEN) || + IdentifierIs(t1, PROPERTY_TOKEN) ) + funcNode->AddChildLast(ParseIdentifier()); + else + break; + } } #ifndef AS_NO_COMPILER @@ -1244,104 +1244,104 @@ void asCParser::ParseMethodAttributes(asCScriptNode *funcNode) // type, in this case it is set to the next token after the type tokens bool asCParser::IsType(sToken &nextToken) { - // Set a rewind point - sToken t, t1; - GetToken(&t); - - // A type can start with a const - t1 = t; - if (t1.type == ttConst) - GetToken(&t1); - - sToken t2; - if (t1.type != ttAuto) - { - // The type may be initiated with the scope operator - if (t1.type == ttScope) - GetToken(&t1); - - // The type may be preceded with a multilevel scope - GetToken(&t2); - while (t1.type == ttIdentifier) - { - if (t2.type == ttScope) - { - GetToken(&t1); - GetToken(&t2); - continue; - } - else if (t2.type == ttLessThan) - { - // Template types can also be used as scope identifiers - RewindTo(&t2); - if (CheckTemplateType(t1)) - { - sToken t3; - GetToken(&t3); - if (t3.type == ttScope) - { - GetToken(&t1); - GetToken(&t2); - continue; - } - } - } - - break; - } - RewindTo(&t2); - } - - // We don't validate if the identifier is an actual declared type at this moment - // as it may wrongly identify the statement as a non-declaration if the user typed - // the name incorrectly. The real type is validated in ParseDeclaration where a - // proper error message can be given. - if (!IsRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto) - { - RewindTo(&t); - return false; - } - - if (!CheckTemplateType(t1)) - { - RewindTo(&t); - return false; - } - - // Object handles can be interleaved with the array brackets - // Even though declaring variables with & is invalid we'll accept - // it here to give an appropriate error message later - GetToken(&t2); - while (t2.type == ttHandle || t2.type == ttAmp || t2.type == ttOpenBracket) - { - if( t2.type == ttHandle ) - { - // A handle can optionally be read-only - sToken t3; - GetToken(&t3); - if(t3.type != ttConst ) - RewindTo(&t3); - } - else if (t2.type == ttOpenBracket) - { - GetToken(&t2); - if (t2.type != ttCloseBracket) - { - RewindTo(&t); - return false; - } - } - - GetToken(&t2); - } - - // Return the next token so the caller can jump directly to it if desired - nextToken = t2; - - // Rewind to start point - RewindTo(&t); - - return true; + // Set a rewind point + sToken t, t1; + GetToken(&t); + + // A type can start with a const + t1 = t; + if (t1.type == ttConst) + GetToken(&t1); + + sToken t2; + if (t1.type != ttAuto) + { + // The type may be initiated with the scope operator + if (t1.type == ttScope) + GetToken(&t1); + + // The type may be preceded with a multilevel scope + GetToken(&t2); + while (t1.type == ttIdentifier) + { + if (t2.type == ttScope) + { + GetToken(&t1); + GetToken(&t2); + continue; + } + else if (t2.type == ttLessThan) + { + // Template types can also be used as scope identifiers + RewindTo(&t2); + if (CheckTemplateType(t1)) + { + sToken t3; + GetToken(&t3); + if (t3.type == ttScope) + { + GetToken(&t1); + GetToken(&t2); + continue; + } + } + } + + break; + } + RewindTo(&t2); + } + + // We don't validate if the identifier is an actual declared type at this moment + // as it may wrongly identify the statement as a non-declaration if the user typed + // the name incorrectly. The real type is validated in ParseDeclaration where a + // proper error message can be given. + if (!IsRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto) + { + RewindTo(&t); + return false; + } + + if (!CheckTemplateType(t1)) + { + RewindTo(&t); + return false; + } + + // Object handles can be interleaved with the array brackets + // Even though declaring variables with & is invalid we'll accept + // it here to give an appropriate error message later + GetToken(&t2); + while (t2.type == ttHandle || t2.type == ttAmp || t2.type == ttOpenBracket) + { + if( t2.type == ttHandle ) + { + // A handle can optionally be read-only + sToken t3; + GetToken(&t3); + if(t3.type != ttConst ) + RewindTo(&t3); + } + else if (t2.type == ttOpenBracket) + { + GetToken(&t2); + if (t2.type != ttCloseBracket) + { + RewindTo(&t); + return false; + } + } + + GetToken(&t2); + } + + // Return the next token so the caller can jump directly to it if desired + nextToken = t2; + + // Rewind to start point + RewindTo(&t); + + return true; } // This function will return true if the current token is not a template, or if it is and @@ -1349,238 +1349,238 @@ bool asCParser::IsType(sToken &nextToken) // at the first token after the type in case of success bool asCParser::CheckTemplateType(const sToken &t) { - // Is this a template type? - tempString.Assign(&script->code[t.pos], t.length); - if( engine->IsTemplateType(tempString.AddressOf()) ) - { - // If the next token is a < then parse the sub-type too - sToken t1; - GetToken(&t1); - if( t1.type != ttLessThan ) - { - RewindTo(&t1); - return true; - } - - for(;;) - { - // There might optionally be a 'const' - GetToken(&t1); - if( t1.type == ttConst ) - GetToken(&t1); - - // The type may be initiated with the scope operator - if( t1.type == ttScope ) - GetToken(&t1); - - // There may be multiple levels of scope operators - sToken t2; - GetToken(&t2); - while( t1.type == ttIdentifier && t2.type == ttScope ) - { - GetToken(&t1); - GetToken(&t2); - } - RewindTo(&t2); - - // Now there must be a data type - if( !IsDataType(t1) ) - return false; - - if( !CheckTemplateType(t1) ) - return false; - - GetToken(&t1); - - // Is it a handle or array? - while( t1.type == ttHandle || t1.type == ttOpenBracket ) - { - if( t1.type == ttOpenBracket ) - { - GetToken(&t1); - if( t1.type != ttCloseBracket ) - return false; - } - - GetToken(&t1); - } - - // Was this the last template subtype? - if( t1.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[t1.pos] != '>' ) - return false; - else if( t1.length != 1 ) - { - // We need to break the token, so that only the first character is parsed - SetPos(t1.pos + 1); - } - } - - return true; + // Is this a template type? + tempString.Assign(&script->code[t.pos], t.length); + if( engine->IsTemplateType(tempString.AddressOf()) ) + { + // If the next token is a < then parse the sub-type too + sToken t1; + GetToken(&t1); + if( t1.type != ttLessThan ) + { + RewindTo(&t1); + return true; + } + + for(;;) + { + // There might optionally be a 'const' + GetToken(&t1); + if( t1.type == ttConst ) + GetToken(&t1); + + // The type may be initiated with the scope operator + if( t1.type == ttScope ) + GetToken(&t1); + + // There may be multiple levels of scope operators + sToken t2; + GetToken(&t2); + while( t1.type == ttIdentifier && t2.type == ttScope ) + { + GetToken(&t1); + GetToken(&t2); + } + RewindTo(&t2); + + // Now there must be a data type + if( !IsDataType(t1) ) + return false; + + if( !CheckTemplateType(t1) ) + return false; + + GetToken(&t1); + + // Is it a handle or array? + while( t1.type == ttHandle || t1.type == ttOpenBracket ) + { + if( t1.type == ttOpenBracket ) + { + GetToken(&t1); + if( t1.type != ttCloseBracket ) + return false; + } + + GetToken(&t1); + } + + // Was this the last template subtype? + if( t1.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[t1.pos] != '>' ) + return false; + else if( t1.length != 1 ) + { + // We need to break the token, so that only the first character is parsed + SetPos(t1.pos + 1); + } + } + + return true; } // BNF:12: CAST ::= 'cast' '<' TYPE '>' '(' ASSIGN ')' 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; - - 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 *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; + + 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; } // BNF:11: EXPRVALUE ::= 'void' | CONSTRUCTCALL | FUNCCALL | VARACCESS | CAST | LITERAL | '(' ASSIGN ')' | LAMBDA 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 ) - { - // Check if the expression is an anonymous function - if( IsLambda() ) - { - node->AddChildLast(ParseLambda()); - } - else - { - // 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; - } - - GetToken(&t2); - - // Rewind so the real parsing can be done, after deciding what to parse - RewindTo(&t1); - - // Check if this is a construct call - // Just 'type()' isn't considered a construct call, because type may just be a function/method name. - // The compiler will have to sort this out, since the parser doesn't have enough information. - if( isDataType && (t.type == ttOpenBracket && t2.type == ttCloseBracket) ) // type[]() - node->AddChildLast(ParseConstructCall()); - else if( isTemplateType && t.type == ttLessThan ) // type() - node->AddChildLast(ParseConstructCall()); - 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 *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 ) + { + // Check if the expression is an anonymous function + if( IsLambda() ) + { + node->AddChildLast(ParseLambda()); + } + else + { + // 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; + } + + GetToken(&t2); + + // Rewind so the real parsing can be done, after deciding what to parse + RewindTo(&t1); + + // Check if this is a construct call + // Just 'type()' isn't considered a construct call, because type may just be a function/method name. + // The compiler will have to sort this out, since the parser doesn't have enough information. + if( isDataType && (t.type == ttOpenBracket && t2.type == ttCloseBracket) ) // type[]() + node->AddChildLast(ParseConstructCall()); + else if( isTemplateType && t.type == ttLessThan ) // type() + node->AddChildLast(ParseConstructCall()); + 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; } // BNF:12: LITERAL ::= NUMBER | STRING | BITS | 'true' | 'false' | 'null' @@ -1589,561 +1589,561 @@ asCScriptNode *asCParser::ParseExprValue() // BNF:17: BITS ::= single token: binary 0b or 0B, octal 0o or 0O, decimal 0d or 0D, hexadecimal 0x or 0X 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 *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; } bool asCParser::IsLambda() { - bool isLambda = false; - sToken t; - GetToken(&t); - if( t.type == ttIdentifier && IdentifierIs(t, FUNCTION_TOKEN) ) - { - sToken t2; - GetToken(&t2); - if( t2.type == ttOpenParanthesis ) - { - // Skip until ) - while( t2.type != ttCloseParanthesis && t2.type != ttEnd ) - GetToken(&t2); - - // The next token must be a { - GetToken(&t2); - if( t2.type == ttStartStatementBlock ) - isLambda = true; - } - } - - RewindTo(&t); - return isLambda; + bool isLambda = false; + sToken t; + GetToken(&t); + if( t.type == ttIdentifier && IdentifierIs(t, FUNCTION_TOKEN) ) + { + sToken t2; + GetToken(&t2); + if( t2.type == ttOpenParanthesis ) + { + // Skip until ) + while( t2.type != ttCloseParanthesis && t2.type != ttEnd ) + GetToken(&t2); + + // The next token must be a { + GetToken(&t2); + if( t2.type == ttStartStatementBlock ) + isLambda = true; + } + } + + RewindTo(&t); + return isLambda; } // BNF:12: LAMBDA ::= 'function' '(' [[TYPE TYPEMOD] IDENTIFIER {',' [TYPE TYPEMOD] IDENTIFIER}] ')' STATBLOCK asCScriptNode *asCParser::ParseLambda() { - asCScriptNode *node = CreateNode(snFunction); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - - if( t.type != ttIdentifier || !IdentifierIs(t, FUNCTION_TOKEN) ) - { - Error(ExpectedToken("function"), &t); - return node; - } - - GetToken(&t); - if( t.type != ttOpenParanthesis ) - { - Error(ExpectedToken("("), &t); - return node; - } - - // Parse optional type before parameter name - if( IsType(t) && (t.type == ttAmp || t.type == ttIdentifier) ) - { - node->AddChildLast(ParseType(true)); - if (isSyntaxError) return node; - node->AddChildLast(ParseTypeMod(true)); - if (isSyntaxError) return node; - } - - GetToken(&t); - if( t.type == ttIdentifier ) - { - RewindTo(&t); - node->AddChildLast(ParseIdentifier()); - if (isSyntaxError) return node; - - GetToken(&t); - while( t.type == ttListSeparator ) - { - // Parse optional type before parameter name - if (IsType(t) && (t.type == ttAmp || t.type == ttIdentifier)) - { - node->AddChildLast(ParseType(true)); - if (isSyntaxError) return node; - node->AddChildLast(ParseTypeMod(true)); - if (isSyntaxError) return node; - } - - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; - - GetToken(&t); - } - } - - if( t.type != ttCloseParanthesis ) - { - Error(ExpectedToken(")"), &t); - 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 *node = CreateNode(snFunction); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + + if( t.type != ttIdentifier || !IdentifierIs(t, FUNCTION_TOKEN) ) + { + Error(ExpectedToken("function"), &t); + return node; + } + + GetToken(&t); + if( t.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t); + return node; + } + + // Parse optional type before parameter name + if( IsType(t) && (t.type == ttAmp || t.type == ttIdentifier) ) + { + node->AddChildLast(ParseType(true)); + if (isSyntaxError) return node; + node->AddChildLast(ParseTypeMod(true)); + if (isSyntaxError) return node; + } + + GetToken(&t); + if( t.type == ttIdentifier ) + { + RewindTo(&t); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + + GetToken(&t); + while( t.type == ttListSeparator ) + { + // Parse optional type before parameter name + if (IsType(t) && (t.type == ttAmp || t.type == ttIdentifier)) + { + node->AddChildLast(ParseType(true)); + if (isSyntaxError) return node; + node->AddChildLast(ParseTypeMod(true)); + if (isSyntaxError) return node; + } + + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + GetToken(&t); + } + } + + if( t.type != ttCloseParanthesis ) + { + Error(ExpectedToken(")"), &t); + 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::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 *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; } // BNF:12: FUNCCALL ::= SCOPE IDENTIFIER ARGLIST asCScriptNode *asCParser::ParseFunctionCall() { - asCScriptNode *node = CreateNode(snFunctionCall); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snFunctionCall); + if( node == 0 ) return 0; - // Parse scope prefix - ParseOptionalScope(node); + // Parse scope prefix + ParseOptionalScope(node); - // Parse the function name followed by the argument list - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; + // Parse the function name followed by the argument list + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; - node->AddChildLast(ParseArgList()); + node->AddChildLast(ParseArgList()); - return node; + return node; } // BNF:12: VARACCESS ::= SCOPE IDENTIFIER asCScriptNode *asCParser::ParseVariableAccess() { - asCScriptNode *node = CreateNode(snVariableAccess); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snVariableAccess); + if( node == 0 ) return 0; - // Parse scope prefix - ParseOptionalScope(node); + // Parse scope prefix + ParseOptionalScope(node); - // Parse the variable name - node->AddChildLast(ParseIdentifier()); + // Parse the variable name + node->AddChildLast(ParseIdentifier()); - return node; + return node; } // BNF:11: CONSTRUCTCALL ::= TYPE ARGLIST asCScriptNode *asCParser::ParseConstructCall() { - asCScriptNode *node = CreateNode(snConstructCall); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snConstructCall); + if( node == 0 ) return 0; - node->AddChildLast(ParseType(false)); - if( isSyntaxError ) return node; + node->AddChildLast(ParseType(false)); + if( isSyntaxError ) return node; - node->AddChildLast(ParseArgList()); + node->AddChildLast(ParseArgList()); - return node; + return node; } // BNF:13: ARGLIST ::= '(' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':'] ASSIGN} ')' 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; - } - } - } + 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 - // The parser doesn't have enough information about scope to determine if the - // identifier is a datatype, so even if it happens to be the parser will - // identify the expression as a function call rather than a construct call. - // The compiler will sort this out later - if( t1.type != ttIdentifier ) - { - RewindTo(&s); - return false; - } - - if( t2.type == ttOpenParanthesis ) - { - RewindTo(&s); - return true; - } - - RewindTo(&s); - return false; + 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 + // The parser doesn't have enough information about scope to determine if the + // identifier is a datatype, so even if it happens to be the parser will + // identify the expression as a function call rather than a construct call. + // The compiler will sort this out later + if( t1.type != ttIdentifier ) + { + RewindTo(&s); + return false; + } + + if( t2.type == ttOpenParanthesis ) + { + RewindTo(&s); + return true; + } + + RewindTo(&s); + return false; } // BNF:13: ASSIGN ::= CONDITION [ ASSIGNOP ASSIGN ] asCScriptNode *asCParser::ParseAssignment() { - asCScriptNode *node = CreateNode(snAssignment); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snAssignment); + if( node == 0 ) return 0; - node->AddChildLast(ParseCondition()); - if( isSyntaxError ) return node; + node->AddChildLast(ParseCondition()); + if( isSyntaxError ) return node; - sToken t; - GetToken(&t); - RewindTo(&t); + sToken t; + GetToken(&t); + RewindTo(&t); - if( IsAssignOperator(t.type) ) - { - node->AddChildLast(ParseAssignOperator()); - if( isSyntaxError ) return node; + if( IsAssignOperator(t.type) ) + { + node->AddChildLast(ParseAssignOperator()); + if( isSyntaxError ) return node; - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - } + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + } - return node; + return node; } // BNF:14: CONDITION ::= EXPR ['?' ASSIGN ':' ASSIGN] 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 *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; } // BNF:9: EXPR ::= EXPRTERM {EXPROP EXPRTERM} asCScriptNode *asCParser::ParseExpression() { - asCScriptNode *node = CreateNode(snExpression); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snExpression); + if( node == 0 ) return 0; - node->AddChildLast(ParseExprTerm()); - if( isSyntaxError ) return node; + node->AddChildLast(ParseExprTerm()); + if( isSyntaxError ) return node; - for(;;) - { - sToken t; - GetToken(&t); - RewindTo(&t); + for(;;) + { + sToken t; + GetToken(&t); + RewindTo(&t); - if( !IsOperator(t.type) ) - return node; + if( !IsOperator(t.type) ) + return node; - node->AddChildLast(ParseExprOperator()); - if( isSyntaxError ) return node; + node->AddChildLast(ParseExprOperator()); + if( isSyntaxError ) return node; - node->AddChildLast(ParseExprTerm()); - if( isSyntaxError ) return node; - } - UNREACHABLE_RETURN; + node->AddChildLast(ParseExprTerm()); + if( isSyntaxError ) return node; + } + UNREACHABLE_RETURN; } // BNF:10: EXPRTERM ::= ([TYPE '='] INITLIST) | ({EXPRPREOP} EXPRVALUE {EXPRPOSTOP}) asCScriptNode *asCParser::ParseExprTerm() { - asCScriptNode *node = CreateNode(snExprTerm); - if( node == 0 ) return 0; - - // Check if the expression term is an initialization of a temp object with init list, i.e. type = {...} - sToken t; - GetToken(&t); - sToken t2 = t, t3; - if (IsDataType(t2) && CheckTemplateType(t2)) - { - // The next token must be a = followed by a { - GetToken(&t2); - GetToken(&t3); - if (t2.type == ttAssignment && t3.type == ttStartStatementBlock) - { - // It is an initialization, now parse it for real - RewindTo(&t); - node->AddChildLast(ParseType(false)); - GetToken(&t2); - node->AddChildLast(ParseInitList()); - return node; - } - } - // Or an anonymous init list, i.e. {...} - else if( t.type == ttStartStatementBlock ) - { - RewindTo(&t); - node->AddChildLast(ParseInitList()); - return node; - } - - // It wasn't an initialization, so it must be an ordinary expression term - RewindTo(&t); - - for(;;) - { - GetToken(&t); - RewindTo(&t); - if( !IsPreOperator(t.type) ) - break; - - node->AddChildLast(ParseExprPreOp()); - if( isSyntaxError ) return node; - } - - node->AddChildLast(ParseExprValue()); - if( isSyntaxError ) return node; - - - for(;;) - { - GetToken(&t); - RewindTo(&t); - if( !IsPostOperator(t.type) ) - return node; - - node->AddChildLast(ParseExprPostOp()); - if( isSyntaxError ) return node; - } - UNREACHABLE_RETURN; + asCScriptNode *node = CreateNode(snExprTerm); + if( node == 0 ) return 0; + + // Check if the expression term is an initialization of a temp object with init list, i.e. type = {...} + sToken t; + GetToken(&t); + sToken t2 = t, t3; + if (IsDataType(t2) && CheckTemplateType(t2)) + { + // The next token must be a = followed by a { + GetToken(&t2); + GetToken(&t3); + if (t2.type == ttAssignment && t3.type == ttStartStatementBlock) + { + // It is an initialization, now parse it for real + RewindTo(&t); + node->AddChildLast(ParseType(false)); + GetToken(&t2); + node->AddChildLast(ParseInitList()); + return node; + } + } + // Or an anonymous init list, i.e. {...} + else if( t.type == ttStartStatementBlock ) + { + RewindTo(&t); + node->AddChildLast(ParseInitList()); + return node; + } + + // It wasn't an initialization, so it must be an ordinary expression term + RewindTo(&t); + + for(;;) + { + GetToken(&t); + RewindTo(&t); + if( !IsPreOperator(t.type) ) + break; + + node->AddChildLast(ParseExprPreOp()); + if( isSyntaxError ) return node; + } + + node->AddChildLast(ParseExprValue()); + if( isSyntaxError ) return node; + + + for(;;) + { + GetToken(&t); + RewindTo(&t); + if( !IsPostOperator(t.type) ) + return node; + + node->AddChildLast(ParseExprPostOp()); + if( isSyntaxError ) return node; + } + UNREACHABLE_RETURN; } // BNF:11: EXPRPREOP ::= '-' | '+' | '!' | '++' | '--' | '~' | '@' 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 *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; } // BNF:11: EXPRPOSTOP ::= ('.' (FUNCCALL | IDENTIFIER)) | ('[' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':' ASSIGN} ']') | ARGLIST | '++' | '--' 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 *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; } // BNF:15: EXPROP ::= MATHOP | COMPOP | LOGICOP | BITOP @@ -2153,2383 +2153,2383 @@ asCScriptNode *asCParser::ParseExprPostOp() // BNF:16: BITOP ::= '&' | '|' | '^' | '<<' | '>>' | '>>>' 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 *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; } // BNF:16: ASSIGNOP ::= '=' | '+=' | '-=' | '*=' | '/=' | '|=' | '&=' | '^=' | '%=' | '**=' | '<<=' | '>>=' | '>>>=' 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; + 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; + 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; + 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; + 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; + 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; + 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 *in_script) { - Reset(); + Reset(); - this->script = in_script; + this->script = in_script; - scriptNode = ParseScript(false); + scriptNode = ParseScript(false); - if( errorWhileParsing ) - return -1; + if( errorWhileParsing ) + return -1; - // TODO: Should allow application to request this warning to be generated. - // It should be off by default, since pre-processor may remove all - // code from a section while still being meant as valid code + // TODO: Should allow application to request this warning to be generated. + // It should be off by default, since pre-processor may remove all + // code from a section while still being meant as valid code /* - // 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); - } + // 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; + return 0; } int asCParser::ParseExpression(asCScriptCode *in_script) { - Reset(); + Reset(); - this->script = in_script; + this->script = in_script; - checkValidTypes = true; + checkValidTypes = true; - scriptNode = ParseExpression(); - if( errorWhileParsing ) - return -1; + scriptNode = ParseExpression(); + if( errorWhileParsing ) + return -1; - return 0; + return 0; } // BNF:1: IMPORT ::= 'import' TYPE ['&'] IDENTIFIER PARAMLIST FUNCATTR 'from' STRING ';' 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 *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; } // BNF:0: SCRIPT ::= {IMPORT | ENUM | TYPEDEF | CLASS | MIXIN | INTERFACE | FUNCDEF | VIRTPROP | VAR | FUNC | NAMESPACE | ';'} asCScriptNode *asCParser::ParseScript(bool inBlock) { - asCScriptNode *node = CreateNode(snScript); - if( node == 0 ) return 0; - - // Determine type of node - for(;;) - { - while( !isSyntaxError ) - { - sToken tStart; - GetToken(&tStart); - - // Optimize by skipping tokens 'shared', 'external', 'final', 'abstract' so they don't have to be checked in every condition - sToken t1 = tStart; - while (IdentifierIs(t1, SHARED_TOKEN) || - IdentifierIs(t1, EXTERNAL_TOKEN) || - IdentifierIs(t1, FINAL_TOKEN) || - IdentifierIs(t1, ABSTRACT_TOKEN)) - GetToken(&t1); - RewindTo(&tStart); - - if( t1.type == ttImport ) - node->AddChildLast(ParseImport()); - else if( t1.type == ttEnum ) - node->AddChildLast(ParseEnumeration()); // Handle enumerations - else if( t1.type == ttTypedef ) - node->AddChildLast(ParseTypedef()); // Handle primitive typedefs - else if( t1.type == ttClass ) - node->AddChildLast(ParseClass()); - else if( t1.type == ttMixin ) - node->AddChildLast(ParseMixin()); - else if( t1.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 - sToken t1; - 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 *node = CreateNode(snScript); + if( node == 0 ) return 0; + + // Determine type of node + for(;;) + { + while( !isSyntaxError ) + { + sToken tStart; + GetToken(&tStart); + + // Optimize by skipping tokens 'shared', 'external', 'final', 'abstract' so they don't have to be checked in every condition + sToken t1 = tStart; + while (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN) || + IdentifierIs(t1, FINAL_TOKEN) || + IdentifierIs(t1, ABSTRACT_TOKEN)) + GetToken(&t1); + RewindTo(&tStart); + + if( t1.type == ttImport ) + node->AddChildLast(ParseImport()); + else if( t1.type == ttEnum ) + node->AddChildLast(ParseEnumeration()); // Handle enumerations + else if( t1.type == ttTypedef ) + node->AddChildLast(ParseTypedef()); // Handle primitive typedefs + else if( t1.type == ttClass ) + node->AddChildLast(ParseClass()); + else if( t1.type == ttMixin ) + node->AddChildLast(ParseMixin()); + else if( t1.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 + sToken t1; + 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; } // BNF:1: NAMESPACE ::= 'namespace' IDENTIFIER '{' SCRIPT '}' 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; + 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 *in_script, asCScriptNode *in_block) { - TimeIt("asCParser::ParseStatementBlock"); + TimeIt("asCParser::ParseStatementBlock"); - Reset(); + Reset(); - // Tell the parser to validate the identifiers as valid types - checkValidTypes = true; + // Tell the parser to validate the identifiers as valid types + checkValidTypes = true; - this->script = in_script; - sourcePos = in_block->tokenPos; + this->script = in_script; + sourcePos = in_block->tokenPos; - scriptNode = ParseStatementBlock(); + scriptNode = ParseStatementBlock(); - if( isSyntaxError || errorWhileParsing ) - return -1; + if( isSyntaxError || errorWhileParsing ) + return -1; - return 0; + return 0; } // BNF:1: ENUM ::= {'shared' | 'external'} 'enum' IDENTIFIER (';' | ('{' IDENTIFIER ['=' EXPR] {',' IDENTIFIER ['=' EXPR]} '}')) asCScriptNode *asCParser::ParseEnumeration() { - asCScriptNode *ident; - asCScriptNode *dataType; - - asCScriptNode *node = CreateNode(snEnum); - if( node == 0 ) return 0; - - sToken token; - - // Optional 'shared' and 'external' token - GetToken(&token); - while( IdentifierIs(token, SHARED_TOKEN) || - IdentifierIs(token, EXTERNAL_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 node; - - node->AddChildLast(dataType); - - ident = CreateNode(snIdentifier); - if( ident == 0 ) return node; - - ident->SetToken(&token); - ident->UpdateSourcePos(token.pos, token.length); - dataType->AddChildLast(ident); - - // External shared declarations are ended with ';' - GetToken(&token); - if (token.type == ttEndStatement) - { - RewindTo(&token); - node->AddChildLast(ParseToken(ttEndStatement)); - return node; - } - - // check for the start of the declaration block - if( token.type != ttStartStatementBlock ) - { - RewindTo(&token); - int tokens[] = { ttStartStatementBlock, ttEndStatement }; - Error(ExpectedOneOf(tokens, 2), &token); - Error(InsteadFound(token), &token); - return node; - } - - while(ttEnd != token.type) - { - 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 node; - - 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("}"), &token); - Error(InsteadFound(token), &token); - return node; - } - - return node; + asCScriptNode *ident; + asCScriptNode *dataType; + + asCScriptNode *node = CreateNode(snEnum); + if( node == 0 ) return 0; + + sToken token; + + // Optional 'shared' and 'external' token + GetToken(&token); + while( IdentifierIs(token, SHARED_TOKEN) || + IdentifierIs(token, EXTERNAL_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 node; + + node->AddChildLast(dataType); + + ident = CreateNode(snIdentifier); + if( ident == 0 ) return node; + + ident->SetToken(&token); + ident->UpdateSourcePos(token.pos, token.length); + dataType->AddChildLast(ident); + + // External shared declarations are ended with ';' + GetToken(&token); + if (token.type == ttEndStatement) + { + RewindTo(&token); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // check for the start of the declaration block + if( token.type != ttStartStatementBlock ) + { + RewindTo(&token); + int tokens[] = { ttStartStatementBlock, ttEndStatement }; + Error(ExpectedOneOf(tokens, 2), &token); + Error(InsteadFound(token), &token); + return node; + } + + while(ttEnd != token.type) + { + 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 node; + + 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("}"), &token); + Error(InsteadFound(token), &token); + return node; + } + + 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' or 'protected' - sToken t1; - GetToken(&t1); - if( t1.type != ttPrivate && t1.type != ttProtected ) - RewindTo(&t1); - - // A variable decl starts with the type - if (!IsType(t1)) - { - RewindTo(&t); - return false; - } - - // Jump to the token after the type - RewindTo(&t1); - GetToken(&t1); - - // The declaration needs to have a name - if( t1.type != ttIdentifier ) - { - RewindTo(&t); - return false; - } - - // It can be followed by an initialization - GetToken(&t1); - if( t1.type == ttEndStatement || t1.type == ttAssignment || t1.type == ttListSeparator ) - { - RewindTo(&t); - return true; - } - if( t1.type == ttOpenParanthesis ) - { - // If the closing parenthesis is followed by a statement block, - // function decorator, or end-of-file, then treat it as a function. - // A function decl may have nested parenthesis so we need to check - // for this too. - int nest = 0; - while( t1.type != ttEnd ) - { - if( t1.type == ttOpenParanthesis ) - nest++; - else if( t1.type == ttCloseParanthesis ) - { - nest--; - if( nest == 0 ) - break; - } - GetToken(&t1); - } - - if (t1.type == ttEnd) - { - RewindTo(&t); - return false; - } - else - { - GetToken(&t1); - RewindTo(&t); - if( t1.type == ttStartStatementBlock || - t1.type == ttIdentifier || // function decorator - t1.type == ttEnd ) - return false; - } - - RewindTo(&t); - return true; - } - - RewindTo(&t); - return false; + // Set start point so that we can rewind + sToken t; + GetToken(&t); + RewindTo(&t); + + // A class property decl can be preceded by 'private' or 'protected' + sToken t1; + GetToken(&t1); + if( t1.type != ttPrivate && t1.type != ttProtected ) + RewindTo(&t1); + + // A variable decl starts with the type + if (!IsType(t1)) + { + RewindTo(&t); + return false; + } + + // Jump to the token after the type + RewindTo(&t1); + GetToken(&t1); + + // The declaration needs to have a name + if( t1.type != ttIdentifier ) + { + RewindTo(&t); + return false; + } + + // It can be followed by an initialization + GetToken(&t1); + if( t1.type == ttEndStatement || t1.type == ttAssignment || t1.type == ttListSeparator ) + { + RewindTo(&t); + return true; + } + if( t1.type == ttOpenParanthesis ) + { + // If the closing parenthesis is followed by a statement block, + // function decorator, or end-of-file, then treat it as a function. + // A function decl may have nested parenthesis so we need to check + // for this too. + int nest = 0; + while( t1.type != ttEnd ) + { + if( t1.type == ttOpenParanthesis ) + nest++; + else if( t1.type == ttCloseParanthesis ) + { + nest--; + if( nest == 0 ) + break; + } + GetToken(&t1); + } + + if (t1.type == ttEnd) + { + RewindTo(&t); + return false; + } + else + { + GetToken(&t1); + RewindTo(&t); + if( t1.type == ttStartStatementBlock || + t1.type == ttIdentifier || // function decorator + 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' or 'protected' - sToken t1; - GetToken(&t1); - if( t1.type != ttPrivate && t1.type != ttProtected ) - RewindTo(&t1); - - // A variable decl starts with the type - if (!IsType(t1)) - { - RewindTo(&t); - return false; - } - - // Move to the token after the type - RewindTo(&t1); - GetToken(&t1); - - // The decl must have an identifier - if( t1.type != ttIdentifier ) - { - RewindTo(&t); - return false; - } - - // To be a virtual property it must also have a block for the get/set functions - GetToken(&t1); - if( t1.type == ttStartStatementBlock ) - { - RewindTo(&t); - return true; - } - - RewindTo(&t); - return false; + // Set start point so that we can rewind + sToken t; + GetToken(&t); + RewindTo(&t); + + // A class property decl can be preceded by 'private' or 'protected' + sToken t1; + GetToken(&t1); + if( t1.type != ttPrivate && t1.type != ttProtected ) + RewindTo(&t1); + + // A variable decl starts with the type + if (!IsType(t1)) + { + RewindTo(&t); + return false; + } + + // Move to the token after the type + RewindTo(&t1); + GetToken(&t1); + + // The decl must have an identifier + if( t1.type != ttIdentifier ) + { + RewindTo(&t); + return false; + } + + // To be a virtual property it must also have a block for the get/set functions + GetToken(&t1); + if( t1.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' or 'protected' - sToken t1, t2; - GetToken(&t1); - if( t1.type != ttPrivate && t1.type != ttProtected ) - 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 starts with a type - sToken t1; - if (!IsType(t1)) - { - RewindTo(&t); - return false; - } - - // Move to the token after the type - RewindTo(&t1); - GetToken(&t1); - - // There can be an ampersand if the function returns a reference - if( t1.type == ttAmp ) - { - RewindTo(&t); - return true; - } - - if( t1.type != ttIdentifier ) - { - RewindTo(&t); - return false; - } - - GetToken(&t1); - if( t1.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(&t1); - while( (nest || t1.type != ttCloseParanthesis) && t1.type != ttEnd ) - { - if( t1.type == ttOpenParanthesis ) - nest++; - if( t1.type == ttCloseParanthesis ) - nest--; - - GetToken(&t1); - } - - if( t1.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 function may also have any number of additional attributes - for( ; ; ) - { - GetToken(&t1); - if( !IdentifierIs(t1, FINAL_TOKEN) && - !IdentifierIs(t1, OVERRIDE_TOKEN) && - !IdentifierIs(t1, EXPLICIT_TOKEN) && - !IdentifierIs(t1, PROPERTY_TOKEN) ) - { - RewindTo(&t1); - break; - } - } - - GetToken(&t1); - RewindTo(&t); - if( t1.type == ttStartStatementBlock ) - return true; - } - - RewindTo(&t); - return false; - } - - RewindTo(&t); - return false; + // 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' or 'protected' + sToken t1, t2; + GetToken(&t1); + if( t1.type != ttPrivate && t1.type != ttProtected ) + 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 starts with a type + sToken t1; + if (!IsType(t1)) + { + RewindTo(&t); + return false; + } + + // Move to the token after the type + RewindTo(&t1); + GetToken(&t1); + + // There can be an ampersand if the function returns a reference + if( t1.type == ttAmp ) + { + RewindTo(&t); + return true; + } + + if( t1.type != ttIdentifier ) + { + RewindTo(&t); + return false; + } + + GetToken(&t1); + if( t1.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(&t1); + while( (nest || t1.type != ttCloseParanthesis) && t1.type != ttEnd ) + { + if( t1.type == ttOpenParanthesis ) + nest++; + if( t1.type == ttCloseParanthesis ) + nest--; + + GetToken(&t1); + } + + if( t1.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 function may also have any number of additional attributes + for( ; ; ) + { + GetToken(&t1); + if( !IdentifierIs(t1, FINAL_TOKEN) && + !IdentifierIs(t1, OVERRIDE_TOKEN) && + !IdentifierIs(t1, EXPLICIT_TOKEN) && + !IdentifierIs(t1, PROPERTY_TOKEN) ) + { + RewindTo(&t1); + break; + } + } + + GetToken(&t1); + RewindTo(&t); + if( t1.type == ttStartStatementBlock ) + return true; + } + + RewindTo(&t); + return false; + } + + RewindTo(&t); + return false; } // BNF:1: FUNCDEF ::= {'external' | 'shared'} 'funcdef' TYPE ['&'] IDENTIFIER PARAMLIST ';' asCScriptNode *asCParser::ParseFuncDef() { - asCScriptNode *node = CreateNode(snFuncDef); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snFuncDef); + if( node == 0 ) return 0; - // Allow keywords 'external' and 'shared' before 'interface' - sToken t1; - GetToken(&t1); - while (IdentifierIs(t1, SHARED_TOKEN) || - IdentifierIs(t1, EXTERNAL_TOKEN)) - { - RewindTo(&t1); - node->AddChildLast(ParseIdentifier()); - if (isSyntaxError) return node; + // Allow keywords 'external' and 'shared' before 'interface' + sToken t1; + GetToken(&t1); + while (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN)) + { + RewindTo(&t1); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; - GetToken(&t1); - } + GetToken(&t1); + } - if( t1.type != ttFuncDef ) - { - Error(asCTokenizer::GetDefinition(ttFuncDef), &t1); - return node; - } + if( t1.type != ttFuncDef ) + { + Error(asCTokenizer::GetDefinition(ttFuncDef), &t1); + return node; + } - node->SetToken(&t1); + node->SetToken(&t1); - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; + node->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return node; - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; - node->AddChildLast(ParseParameterList()); - 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; - } + GetToken(&t1); + if( t1.type != ttEndStatement ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatement)), &t1); + Error(InsteadFound(t1), &t1); + return node; + } - node->UpdateSourcePos(t1.pos, t1.length); + node->UpdateSourcePos(t1.pos, t1.length); - return node; + return node; } // BNF:1: FUNC ::= {'shared' | 'external'} ['private' | 'protected'] [((TYPE ['&']) | '~')] IDENTIFIER PARAMLIST ['const'] FUNCATTR (';' | STATBLOCK) asCScriptNode *asCParser::ParseFunction(bool isMethod) { - asCScriptNode *node = CreateNode(snFunction); - if( node == 0 ) return 0; - - sToken t1; - GetToken(&t1); - if (!isMethod) - { - // A global function can be marked as shared and external - while (t1.type == ttIdentifier) - { - if (IdentifierIs(t1, SHARED_TOKEN) || - IdentifierIs(t1, EXTERNAL_TOKEN)) - { - RewindTo(&t1); - node->AddChildLast(ParseIdentifier()); - if (isSyntaxError) return node; - } - else - break; - - GetToken(&t1); - } - } - - // A class method can start with 'private' or 'protected' - if (isMethod && t1.type == ttPrivate) - { - RewindTo(&t1); - node->AddChildLast(ParseToken(ttPrivate)); - GetToken(&t1); - } - else if (isMethod && t1.type == ttProtected) - { - RewindTo(&t1); - node->AddChildLast(ParseToken(ttProtected)); - GetToken(&t1); - } - if( isSyntaxError ) return node; - - // If it is a global function, or a method, except constructor and destructor, then the return type is parsed - sToken t2; - GetToken(&t2); - RewindTo(&t1); - if( !isMethod || (t1.type != ttBitNot && t2.type != ttOpenParanthesis) ) - { - node->AddChildLast(ParseType(true)); - 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 - ParseMethodAttributes(node); - if( isSyntaxError ) return node; - - // External shared functions must be ended with ';' - GetToken(&t1); - RewindTo(&t1); - if (t1.type == ttEndStatement) - { - node->AddChildLast(ParseToken(ttEndStatement)); - return node; - } - - // We should just find the end of the statement block here. The statements - // will be parsed on request by the compiler once it starts the compilation. - node->AddChildLast(SuperficiallyParseStatementBlock()); - - return node; + asCScriptNode *node = CreateNode(snFunction); + if( node == 0 ) return 0; + + sToken t1; + GetToken(&t1); + if (!isMethod) + { + // A global function can be marked as shared and external + while (t1.type == ttIdentifier) + { + if (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN)) + { + RewindTo(&t1); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + } + else + break; + + GetToken(&t1); + } + } + + // A class method can start with 'private' or 'protected' + if (isMethod && t1.type == ttPrivate) + { + RewindTo(&t1); + node->AddChildLast(ParseToken(ttPrivate)); + GetToken(&t1); + } + else if (isMethod && t1.type == ttProtected) + { + RewindTo(&t1); + node->AddChildLast(ParseToken(ttProtected)); + GetToken(&t1); + } + if( isSyntaxError ) return node; + + // If it is a global function, or a method, except constructor and destructor, then the return type is parsed + sToken t2; + GetToken(&t2); + RewindTo(&t1); + if( !isMethod || (t1.type != ttBitNot && t2.type != ttOpenParanthesis) ) + { + node->AddChildLast(ParseType(true)); + 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 + ParseMethodAttributes(node); + if( isSyntaxError ) return node; + + // External shared functions must be ended with ';' + GetToken(&t1); + RewindTo(&t1); + if (t1.type == ttEndStatement) + { + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // We should just find the end of the statement block here. The statements + // will be parsed on request by the compiler once it starts the compilation. + node->AddChildLast(SuperficiallyParseStatementBlock()); + + return node; } // BNF:2: INTFMTHD ::= TYPE ['&'] IDENTIFIER PARAMLIST ['const'] ';' asCScriptNode *asCParser::ParseInterfaceMethod() { - asCScriptNode *node = CreateNode(snFunction); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snFunction); + if( node == 0 ) return 0; - node->AddChildLast(ParseType(true)); - if( isSyntaxError ) return node; + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; - node->AddChildLast(ParseTypeMod(false)); - if( isSyntaxError ) return node; + node->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return node; - node->AddChildLast(ParseIdentifier()); - if( isSyntaxError ) return node; + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; - node->AddChildLast(ParseParameterList()); - 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)); + // 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; - } + GetToken(&t1); + if( t1.type != ttEndStatement ) + { + Error(ExpectedToken(";"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } - node->UpdateSourcePos(t1.pos, t1.length); + node->UpdateSourcePos(t1.pos, t1.length); - return node; + return node; } // BNF:1: VIRTPROP ::= ['private' | 'protected'] TYPE ['&'] IDENTIFIER '{' {('get' | 'set') ['const'] FUNCATTR (STATBLOCK | ';')} '}' 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' or 'protected' - if( isMethod && t1.type == ttPrivate ) - node->AddChildLast(ParseToken(ttPrivate)); - else if( isMethod && t1.type == ttProtected ) - node->AddChildLast(ParseToken(ttProtected)); - if( isSyntaxError ) return node; - - 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 ) - { - ParseMethodAttributes(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 *node = CreateNode(snVirtualProperty); + if( node == 0 ) return 0; + + sToken t1,t2; + GetToken(&t1); + GetToken(&t2); + RewindTo(&t1); + + // A class method can start with 'private' or 'protected' + if( isMethod && t1.type == ttPrivate ) + node->AddChildLast(ParseToken(ttPrivate)); + else if( isMethod && t1.type == ttProtected ) + node->AddChildLast(ParseToken(ttProtected)); + if( isSyntaxError ) return node; + + 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 ) + { + ParseMethodAttributes(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; } // BNF:1: INTERFACE ::= {'external' | 'shared'} 'interface' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | INTFMTHD} '}')) asCScriptNode *asCParser::ParseInterface() { - asCScriptNode *node = CreateNode(snInterface); - if( node == 0 ) return 0; - - sToken t; - - // Allow keywords 'external' and 'shared' before 'interface' - GetToken(&t); - while( IdentifierIs(t, SHARED_TOKEN) || - IdentifierIs(t, EXTERNAL_TOKEN) ) - { - RewindTo(&t); - node->AddChildLast(ParseIdentifier()); - if (isSyntaxError) return node; - - GetToken(&t); - } - - if( t.type != ttInterface ) - { - Error(ExpectedToken("interface"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->SetToken(&t); - node->AddChildLast(ParseIdentifier()); - - // External shared declarations are ended with ';' - GetToken(&t); - if (t.type == ttEndStatement) - { - RewindTo(&t); - node->AddChildLast(ParseToken(ttEndStatement)); - return node; - } - - // Can optionally have a list of interfaces that are inherited - if( t.type == ttColon ) - { - asCScriptNode *inherit = CreateNode(snIdentifier); - 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 *node = CreateNode(snInterface); + if( node == 0 ) return 0; + + sToken t; + + // Allow keywords 'external' and 'shared' before 'interface' + GetToken(&t); + while( IdentifierIs(t, SHARED_TOKEN) || + IdentifierIs(t, EXTERNAL_TOKEN) ) + { + RewindTo(&t); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + + GetToken(&t); + } + + if( t.type != ttInterface ) + { + Error(ExpectedToken("interface"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->AddChildLast(ParseIdentifier()); + + // External shared declarations are ended with ';' + GetToken(&t); + if (t.type == ttEndStatement) + { + RewindTo(&t); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // Can optionally have a list of interfaces that are inherited + if( t.type == ttColon ) + { + asCScriptNode *inherit = CreateNode(snIdentifier); + 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; } // BNF:1: MIXIN ::= 'mixin' CLASS asCScriptNode *asCParser::ParseMixin() { - asCScriptNode *node = CreateNode(snMixin); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snMixin); + if( node == 0 ) return 0; - sToken t; - GetToken(&t); + sToken t; + GetToken(&t); - if( t.type != ttMixin ) - { - Error(ExpectedToken("mixin"), &t); - Error(InsteadFound(t), &t); - return node; - } + if( t.type != ttMixin ) + { + Error(ExpectedToken("mixin"), &t); + Error(InsteadFound(t), &t); + return node; + } - node->SetToken(&t); + node->SetToken(&t); - // A mixin token must be followed by a class declaration - node->AddChildLast(ParseClass()); + // A mixin token must be followed by a class declaration + node->AddChildLast(ParseClass()); - return node; + return node; } // BNF:1: CLASS ::= {'shared' | 'abstract' | 'final' | 'external'} 'class' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | FUNC | VAR | FUNCDEF} '}')) asCScriptNode *asCParser::ParseClass() { - asCScriptNode *node = CreateNode(snClass); - if( node == 0 ) return 0; - - sToken t; - GetToken(&t); - - // Allow the keywords 'shared', 'abstract', 'final', and 'external' before 'class' - while( IdentifierIs(t, SHARED_TOKEN) || - IdentifierIs(t, ABSTRACT_TOKEN) || - IdentifierIs(t, FINAL_TOKEN) || - IdentifierIs(t, EXTERNAL_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()); - - // External shared declarations are ended with ';' - GetToken(&t); - if (t.type == ttEndStatement) - { - RewindTo(&t); - node->AddChildLast(ParseToken(ttEndStatement)); - return node; - } - - // Optional list of interfaces that are being implemented and classes that are being inherited - if( t.type == ttColon ) - { - 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 (t.type == ttFuncDef) - node->AddChildLast(ParseFuncDef()); - else 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; + asCScriptNode *node = CreateNode(snClass); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + + // Allow the keywords 'shared', 'abstract', 'final', and 'external' before 'class' + while( IdentifierIs(t, SHARED_TOKEN) || + IdentifierIs(t, ABSTRACT_TOKEN) || + IdentifierIs(t, FINAL_TOKEN) || + IdentifierIs(t, EXTERNAL_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()); + + // External shared declarations are ended with ';' + GetToken(&t); + if (t.type == ttEndStatement) + { + RewindTo(&t); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // Optional list of interfaces that are being implemented and classes that are being inherited + if( t.type == ttColon ) + { + 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 (t.type == ttFuncDef) + node->AddChildLast(ParseFuncDef()); + else 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 *in_script, asCScriptNode *in_init) { - Reset(); - - // Tell the parser to validate the identifiers as valid types - checkValidTypes = true; - - this->script = in_script; - sourcePos = in_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; + Reset(); + + // Tell the parser to validate the identifiers as valid types + checkValidTypes = true; + + this->script = in_script; + sourcePos = in_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); - sToken start = t; - - // Find the end of the expression - int indentParan = 0; - int indentBrace = 0; - while( indentParan || indentBrace || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) ) - { - if( t.type == ttOpenParanthesis ) - indentParan++; - else if( t.type == ttCloseParanthesis ) - indentParan--; - else if( t.type == ttStartStatementBlock ) - indentBrace++; - else if( t.type == ttEndStatementBlock ) - indentBrace--; - 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 *node = CreateNode(snAssignment); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + if( t.type == ttAssignment ) + { + GetToken(&t); + sToken start = t; + + // Find the end of the expression + int indentParan = 0; + int indentBrace = 0; + while( indentParan || indentBrace || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) ) + { + if( t.type == ttOpenParanthesis ) + indentParan++; + else if( t.type == ttCloseParanthesis ) + indentParan--; + else if( t.type == ttStartStatementBlock ) + indentBrace++; + else if( t.type == ttEndStatementBlock ) + indentBrace--; + 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 *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; } // BNF:2: STATBLOCK ::= '{' {VAR | STATEMENT} '}' 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 *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; } // BNF:4: INITLIST ::= '{' [ASSIGN | INITLIST] {',' [ASSIGN | INITLIST]} '}' 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)); - node->lastChild->UpdateSourcePos(t1.pos, 1); - - GetToken(&t1); - if( t1.type == ttEndStatementBlock ) - { - // No expression - node->AddChildLast(CreateNode(snUndefined)); - node->lastChild->UpdateSourcePos(t1.pos, 1); - node->UpdateSourcePos(t1.pos, t1.length); - return node; - } - RewindTo(&t1); - } - else if( t1.type == ttEndStatementBlock ) - { - // No expression - node->AddChildLast(CreateNode(snUndefined)); - node->lastChild->UpdateSourcePos(t1.pos, 1); - 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 *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)); + node->lastChild->UpdateSourcePos(t1.pos, 1); + + GetToken(&t1); + if( t1.type == ttEndStatementBlock ) + { + // No expression + node->AddChildLast(CreateNode(snUndefined)); + node->lastChild->UpdateSourcePos(t1.pos, 1); + node->UpdateSourcePos(t1.pos, t1.length); + return node; + } + RewindTo(&t1); + } + else if( t1.type == ttEndStatementBlock ) + { + // No expression + node->AddChildLast(CreateNode(snUndefined)); + node->lastChild->UpdateSourcePos(t1.pos, 1); + 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; } // BNF:1: VAR ::= ['private'|'protected'] TYPE IDENTIFIER [( '=' (INITLIST | EXPR)) | ARGLIST] {',' IDENTIFIER [( '=' (INITLIST | EXPR)) | ARGLIST]} ';' 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)); - else if( t.type == ttProtected && isClassProp ) - node->AddChildLast(ParseToken(ttProtected)); - - // 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 *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)); + else if( t.type == ttProtected && isClassProp ) + node->AddChildLast(ParseToken(ttProtected)); + + // 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; } // BNF:7: STATEMENT ::= (IF | FOR | WHILE | RETURN | STATBLOCK | BREAK | CONTINUE | DOWHILE | SWITCH | EXPRSTAT | TRY) 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 (t1.type == ttTry) - return ParseTryCatch(); - else - { - if( IsVarDecl() ) - { - Error(TXT_UNEXPECTED_VAR_DECL, &t1); - return 0; - } - return ParseExpressionStatement(); - } + 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 (t1.type == ttTry) + return ParseTryCatch(); + else + { + if( IsVarDecl() ) + { + Error(TXT_UNEXPECTED_VAR_DECL, &t1); + return 0; + } + return ParseExpressionStatement(); + } } // BNF:8: EXPRSTAT ::= [ASSIGN] ';' asCScriptNode *asCParser::ParseExpressionStatement() { - asCScriptNode *node = CreateNode(snExpressionStatement); - if( node == 0 ) return 0; + asCScriptNode *node = CreateNode(snExpressionStatement); + if( node == 0 ) return 0; - sToken t; - GetToken(&t); - if( t.type == ttEndStatement ) - { - node->UpdateSourcePos(t.pos, t.length); + sToken t; + GetToken(&t); + if( t.type == ttEndStatement ) + { + node->UpdateSourcePos(t.pos, t.length); - return node; - } + return node; + } - RewindTo(&t); + RewindTo(&t); - node->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; - GetToken(&t); - if( t.type != ttEndStatement ) - { - 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); + node->UpdateSourcePos(t.pos, t.length); - return node; + return node; } // BNF:8: SWITCH ::= 'switch' '(' ASSIGN ')' '{' {CASE} '}' 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 *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; } // BNF:9: CASE ::= (('case' EXPR) | 'default') ':' {STATEMENT} 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 *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; } // BNF:8: IF ::= 'if' '(' ASSIGN ')' STATEMENT ['else' STATEMENT] 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 *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; } // BNF:8: TRY ::= 'try' STATBLOCK 'catch' STATBLOCK asCScriptNode *asCParser::ParseTryCatch() { - asCScriptNode *node = CreateNode(snTryCatch); - if (node == 0) return 0; - - sToken t; - GetToken(&t); - if (t.type != ttTry) - { - Error(ExpectedToken("try"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->UpdateSourcePos(t.pos, t.length); - - node->AddChildLast(ParseStatementBlock()); - if (isSyntaxError) return node; - - GetToken(&t); - if (t.type != ttCatch) - { - Error(ExpectedToken("catch"), &t); - Error(InsteadFound(t), &t); - return node; - } - - node->AddChildLast(ParseStatementBlock()); - if (isSyntaxError) return node; - - return node; + asCScriptNode *node = CreateNode(snTryCatch); + if (node == 0) return 0; + + sToken t; + GetToken(&t); + if (t.type != ttTry) + { + Error(ExpectedToken("try"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + node->AddChildLast(ParseStatementBlock()); + if (isSyntaxError) return node; + + GetToken(&t); + if (t.type != ttCatch) + { + Error(ExpectedToken("catch"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseStatementBlock()); + if (isSyntaxError) return node; + + return node; } // BNF:8: FOR ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN {',' ASSIGN}] ')' STATEMENT asCScriptNode *asCParser::ParseFor() { - 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); - - // Parse N increment statements separated by , - for(;;) - { - asCScriptNode *n = CreateNode(snExpressionStatement); - if( n == 0 ) return 0; - node->AddChildLast(n); - n->AddChildLast(ParseAssignment()); - if( isSyntaxError ) return node; - - GetToken(&t); - if( t.type == ttListSeparator ) - continue; - else if( t.type == ttCloseParanthesis ) - break; - else - { - const char *tokens[] = {",", ")"}; - Error(ExpectedOneOf(tokens, 2), &t); - Error(InsteadFound(t), &t); - return node; - } - } - } - - node->AddChildLast(ParseStatement()); - - return node; + 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); + + // Parse N increment statements separated by , + for(;;) + { + asCScriptNode *n = CreateNode(snExpressionStatement); + if( n == 0 ) return 0; + node->AddChildLast(n); + n->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type == ttListSeparator ) + continue; + else if( t.type == ttCloseParanthesis ) + break; + else + { + const char *tokens[] = {",", ")"}; + Error(ExpectedOneOf(tokens, 2), &t); + Error(InsteadFound(t), &t); + return node; + } + } + } + + node->AddChildLast(ParseStatement()); + + return node; } // BNF:8: WHILE ::= 'while' '(' ASSIGN ')' STATEMENT 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 *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; } // BNF:8: DOWHILE ::= 'do' STATEMENT 'while' '(' ASSIGN ')' ';' 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 *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; } // BNF:8: RETURN ::= 'return' [ASSIGN] ';' 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 *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; } // BNF:8: BREAK ::= 'break' ';' 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 *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; } // BNF:8: CONTINUE ::= 'continue' ';' 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; + 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 // BNF:1: TYPEDEF ::= 'typedef' PRIMTYPE IDENTIFIER ';' 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(ttTypedef)), &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; + // 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(ttTypedef)), &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; } #endif diff --git a/src/angelscript/source/as_parser.h b/src/angelscript/source/as_parser.h index 4aec2646c1b..b642cb4d5d4 100644 --- a/src/angelscript/source/as_parser.h +++ b/src/angelscript/source/as_parser.h @@ -50,146 +50,146 @@ BEGIN_AS_NAMESPACE class asCParser { public: - asCParser(asCBuilder *builder); - ~asCParser(); + asCParser(asCBuilder *builder); + ~asCParser(); - int ParseFunctionDefinition(asCScriptCode *script, bool expectListPattern); - int ParsePropertyDeclaration(asCScriptCode *script); - int ParseDataType(asCScriptCode *script, bool isReturnType); - int ParseTemplateDecl(asCScriptCode *script); + 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); + int ParseScript(asCScriptCode *script); - // Called from compiler - int ParseStatementBlock(asCScriptCode *script, asCScriptNode *block); - int ParseVarInit(asCScriptCode *script, asCScriptNode *init); - int ParseExpression(asCScriptCode *script); + // Called from compiler + int ParseStatementBlock(asCScriptCode *script, asCScriptNode *block); + int ParseVarInit(asCScriptCode *script, asCScriptNode *init); + int ParseExpression(asCScriptCode *script); #endif - asCScriptNode *GetScriptNode(); + 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(); - bool ParseTemplTypeList(asCScriptNode *node, bool required = true); - void ParseMethodAttributes(asCScriptNode *funcNode); - - asCScriptNode *ParseListPattern(); - - bool IsRealType(int tokenType); - bool IsDataType(const sToken &token); - bool IdentifierIs(const sToken &t, const char *str); + 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(); + bool ParseTemplTypeList(asCScriptNode *node, bool required = true); + void ParseMethodAttributes(asCScriptNode *funcNode); + + 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(); - asCScriptNode *ParseTryCatch(); - - // 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(); - bool IsVarDecl(); - bool IsVirtualPropertyDecl(); - bool IsFuncDecl(bool isMethod); - bool IsLambda(); - bool IsFunctionCall(); - - // 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(); - asCScriptNode *ParseLambda(); - - bool IsType(sToken &nextToken); - bool IsConstant(int tokenType); - bool IsOperator(int tokenType); - bool IsPreOperator(int tokenType); - bool IsPostOperator(int tokenType); - bool IsAssignOperator(int tokenType); - - bool CheckTemplateType(const sToken &t); + // 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(); + asCScriptNode *ParseTryCatch(); + + // 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(); + bool IsVarDecl(); + bool IsVirtualPropertyDecl(); + bool IsFuncDecl(bool isMethod); + bool IsLambda(); + bool IsFunctionCall(); + + // 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(); + asCScriptNode *ParseLambda(); + + bool IsType(sToken &nextToken); + bool IsConstant(int tokenType); + bool IsOperator(int tokenType); + bool IsPreOperator(int tokenType); + bool IsPostOperator(int tokenType); + bool IsAssignOperator(int tokenType); + + bool CheckTemplateType(const sToken &t); #endif - asCScriptNode *ParseToken(int token); - asCScriptNode *ParseOneOf(int *tokens, int num); + 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); + 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; + bool errorWhileParsing; + bool isSyntaxError; + bool checkValidTypes; + bool isParsingAppInterface; - asCScriptEngine *engine; - asCBuilder *builder; - asCScriptCode *script; - asCScriptNode *scriptNode; + asCScriptEngine *engine; + asCBuilder *builder; + asCScriptCode *script; + asCScriptNode *scriptNode; - asCString tempString; // Used for reduzing amount of dynamic allocations + asCString tempString; // Used for reduzing amount of dynamic allocations - sToken lastToken; - size_t sourcePos; + sToken lastToken; + size_t sourcePos; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_property.h b/src/angelscript/source/as_property.h index c318ec4a3b4..8acd8f7c325 100644 --- a/src/angelscript/source/as_property.h +++ b/src/angelscript/source/as_property.h @@ -53,75 +53,75 @@ struct asSNameSpace; class asCObjectProperty { public: - asCObjectProperty() : byteOffset(0), accessMask(0xFFFFFFFF), compositeOffset(0), isCompositeIndirect(false), isPrivate(false), isProtected(false), isInherited(false) {} - asCObjectProperty(const asCObjectProperty &o) : name(o.name), type(o.type), byteOffset(o.byteOffset), accessMask(o.accessMask), compositeOffset(o.compositeOffset), isCompositeIndirect(o.isCompositeIndirect), isPrivate(o.isPrivate), isProtected(o.isProtected), isInherited(o.isInherited) {} - asCString name; - asCDataType type; - int byteOffset; - asDWORD accessMask; - int compositeOffset; - bool isCompositeIndirect; - bool isPrivate; - bool isProtected; - bool isInherited; + asCObjectProperty() : byteOffset(0), accessMask(0xFFFFFFFF), compositeOffset(0), isCompositeIndirect(false), isPrivate(false), isProtected(false), isInherited(false) {} + asCObjectProperty(const asCObjectProperty &o) : name(o.name), type(o.type), byteOffset(o.byteOffset), accessMask(o.accessMask), compositeOffset(o.compositeOffset), isCompositeIndirect(o.isCompositeIndirect), isPrivate(o.isPrivate), isProtected(o.isProtected), isInherited(o.isInherited) {} + asCString name; + asCDataType type; + int byteOffset; + asDWORD accessMask; + int compositeOffset; + bool isCompositeIndirect; + bool isPrivate; + bool isProtected; + bool isInherited; }; class asCGlobalProperty { public: - asCGlobalProperty(); - ~asCGlobalProperty(); + asCGlobalProperty(); + ~asCGlobalProperty(); - void AddRef(); - void Release(); - void DestroyInternal(); + void AddRef(); + void Release(); + void DestroyInternal(); - void *GetAddressOfValue(); - void AllocateMemory(); - void SetRegisteredAddress(void *p); - void *GetRegisteredAddress() const; + void *GetAddressOfValue(); + void AllocateMemory(); + void SetRegisteredAddress(void *p); + void *GetRegisteredAddress() const; - asCString name; - asCDataType type; - asUINT id; - asSNameSpace *nameSpace; + asCString name; + asCDataType type; + asUINT id; + asSNameSpace *nameSpace; - void SetInitFunc(asCScriptFunction *initFunc); - asCScriptFunction *GetInitFunc(); + void SetInitFunc(asCScriptFunction *initFunc); + asCScriptFunction *GetInitFunc(); //protected: - // This is only stored for registered properties, and keeps the pointer given by the application - void *realAddress; + // This is only stored for registered properties, and keeps the pointer given by the application + void *realAddress; - bool memoryAllocated; - void *memory; - asQWORD storage; + bool memoryAllocated; + void *memory; + asQWORD storage; - asCScriptFunction *initFunc; + asCScriptFunction *initFunc; - asDWORD accessMask; + 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; + // 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; }; class asCCompGlobPropType : public asIFilter { public: - const asCDataType &m_type; + const asCDataType &m_type; - asCCompGlobPropType(const asCDataType &type) : m_type(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; - } + 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;} + // 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 diff --git a/src/angelscript/source/as_restore.cpp b/src/angelscript/source/as_restore.cpp index a6b9abccfda..3ae3c33c301 100644 --- a/src/angelscript/source/as_restore.cpp +++ b/src/angelscript/source/as_restore.cpp @@ -51,5774 +51,5774 @@ BEGIN_AS_NAMESPACE asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine) : module(_module), stream(_stream), engine(_engine) { - error = false; - bytesRead = 0; + error = false; + bytesRead = 0; } int asCReader::ReadData(void *data, asUINT size) { - asASSERT(size == 1 || size == 2 || size == 4 || size == 8); - int ret = 0; + asASSERT(size == 1 || size == 2 || size == 4 || size == 8); + int ret = 0; #if defined(AS_BIG_ENDIAN) - for( asUINT n = 0; ret >= 0 && n < size; n++ ) - ret = stream->Read(((asBYTE*)data)+n, 1); + for( asUINT n = 0; ret >= 0 && n < size; n++ ) + ret = stream->Read(((asBYTE*)data)+n, 1); #else - for( int n = size-1; ret >= 0 && n >= 0; n-- ) - ret = stream->Read(((asBYTE*)data)+n, 1); + for( int n = size-1; ret >= 0 && n >= 0; n-- ) + ret = stream->Read(((asBYTE*)data)+n, 1); #endif - if (ret < 0) - Error(TXT_UNEXPECTED_END_OF_FILE); - bytesRead += size; - return ret; + if (ret < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); + bytesRead += size; + return ret; } int asCReader::Read(bool *wasDebugInfoStripped) { - TimeIt("asCReader::Read"); - - // Before starting the load, make sure that - // 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->m_scriptFunctions.GetLength(); i++ ) - if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) ) - if( module->m_scriptFunctions[i]->scriptData ) - module->m_scriptFunctions[i]->scriptData->byteCode.SetLength(0); - - asCSymbolTable::iterator it = module->m_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; - } - - // Clean up the loaded string constants - for (asUINT n = 0; n < usedStringConstants.GetLength(); n++) - engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]); - usedStringConstants.SetLength(0); - - return r; + TimeIt("asCReader::Read"); + + // 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->m_scriptFunctions.GetLength(); i++ ) + if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) ) + if( module->m_scriptFunctions[i]->scriptData ) + module->m_scriptFunctions[i]->scriptData->byteCode.SetLength(0); + + asCSymbolTable::iterator it = module->m_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; + } + + // Clean up the loaded string constants + for (asUINT n = 0; n < usedStringConstants.GetLength(); n++) + engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]); + usedStringConstants.SetLength(0); + + 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; + // 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() { - TimeIt("asCReader::ReadInner"); - - // This function will load each entity one by one from the stream. - // If any error occurs, it will return to the caller who is - // responsible for cleaning up the partially loaded entities. - - engine->deferValidationOfTemplateTypes = true; - - unsigned long i, count; - asCScriptFunction* func; - - // Read the flag as 1 byte even on platforms with 4byte booleans - noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0; - - // Read enums - count = ReadEncodedUInt(); - module->m_enumTypes.Allocate(count, false); - for( i = 0; i < count && !error; i++ ) - { - asCEnumType *et = asNEW(asCEnumType)(engine); - if( et == 0 ) - { - error = true; - return asOUT_OF_MEMORY; - } - - bool isExternal = false; - ReadTypeDeclaration(et, 1, &isExternal); - - // If the type is shared then we should use the original if it exists - bool sharedExists = false; - if( et->IsShared() ) - { - for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) - { - asCTypeInfo *t = engine->sharedScriptTypes[n]; - if( t && - t->IsShared() && - t->name == et->name && - t->nameSpace == et->nameSpace && - (t->flags & asOBJ_ENUM) ) - { - asDELETE(et, asCEnumType); - et = CastToEnumType(t); - sharedExists = true; - break; - } - } - } - - if (isExternal && !sharedExists) - { - asCString msg; - msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, et->name.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - asDELETE(et, asCEnumType); - error = true; - return asERROR; - } - - if( sharedExists ) - { - existingShared.Insert(et, true); - et->AddRefInternal(); - } - else - { - if( et->IsShared() ) - { - engine->sharedScriptTypes.PushLast(et); - et->AddRefInternal(); - } - - // Set this module as the owner - et->module = module; - } - module->AddEnumType(et); - - if (isExternal) - module->m_externalTypes.PushLast(et); - - ReadTypeDeclaration(et, 2); - } - - if( error ) return asERROR; - - // classTypes[] - // First restore the structure names, then the properties - count = ReadEncodedUInt(); - module->m_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; - } - - bool isExternal = false; - ReadTypeDeclaration(ot, 1, &isExternal); - - // 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->sharedScriptTypes.GetLength(); n++ ) - { - asCTypeInfo *ti = engine->sharedScriptTypes[n]; - asCObjectType *t = CastToObjectType(ti); - if( t && - t->IsShared() && - t->name == ot->name && - t->nameSpace == ot->nameSpace && - t->IsInterface() == ot->IsInterface() ) - { - asDELETE(ot, asCObjectType); - ot = CastToObjectType(t); - sharedExists = true; - break; - } - } - } - - if (isExternal && !sharedExists) - { - asCString msg; - msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, ot->name.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - asDELETE(ot, asCObjectType); - error = true; - return asERROR; - } - - if( sharedExists ) - { - existingShared.Insert(ot, true); - ot->AddRefInternal(); - } - else - { - if( ot->IsShared() ) - { - engine->sharedScriptTypes.PushLast(ot); - ot->AddRefInternal(); - } - - // Set this module as the owner - ot->module = module; - } - module->AddClassType(ot); - - if (isExternal) - module->m_externalTypes.PushLast(ot); - } - - if( error ) return asERROR; - - // Read func defs - count = ReadEncodedUInt(); - module->m_funcDefs.Allocate(count, false); - for( i = 0; i < count && !error; i++ ) - { - bool isNew, isExternal; - asCScriptFunction *funcDef = ReadFunction(isNew, false, true, true, &isExternal); - if(funcDef) - { - funcDef->module = module; - - asCFuncdefType *fdt = funcDef->funcdefType; - fdt->module = module; - - module->AddFuncDef(fdt); - engine->funcDefs.PushLast(fdt); - - // TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module - // Check if there is another identical funcdef from another module and if so reuse that instead - if(funcDef->IsShared()) - { - for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) - { - asCFuncdefType *f2 = engine->funcDefs[n]; - if( f2 == 0 || fdt == f2 ) - continue; - - if( !f2->funcdef->IsShared() ) - continue; - - if( f2->name == fdt->name && - f2->nameSpace == fdt->nameSpace && - f2->parentClass == fdt->parentClass && - f2->funcdef->IsSignatureExceptNameEqual(funcDef) ) - { - // Replace our funcdef for the existing one - module->ReplaceFuncDef(fdt, f2); - f2->AddRefInternal(); - - if (isExternal) - module->m_externalTypes.PushLast(f2); - - engine->funcDefs.RemoveValue(fdt); - - savedFunctions[savedFunctions.IndexOf(funcDef)] = f2->funcdef; - - if (fdt->parentClass) - { - // The real funcdef should already be in the object - asASSERT(fdt->parentClass->childFuncDefs.IndexOf(f2) >= 0); - - fdt->parentClass = 0; - } - - fdt->ReleaseInternal(); - funcDef = 0; - break; - } - } - } - - // Add the funcdef to the parentClass if this is a child funcdef - if (funcDef && fdt->parentClass) - fdt->parentClass->childFuncDefs.PushLast(fdt); - - // Check if an external shared funcdef was really found - if (isExternal && funcDef) - { - asCString msg; - msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - error = true; - return asERROR; - } - } - else - Error(TXT_INVALID_BYTECODE_d); - } - - // Read interface methods - for( i = 0; i < module->m_classTypes.GetLength() && !error; i++ ) - { - if( module->m_classTypes[i]->IsInterface() ) - ReadTypeDeclaration(module->m_classTypes[i], 2); - } - - // Read class methods and behaviours - for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i ) - { - if( !module->m_classTypes[i]->IsInterface() ) - ReadTypeDeclaration(module->m_classTypes[i], 2); - } - - // Read class properties - for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i ) - { - if( !module->m_classTypes[i]->IsInterface() ) - ReadTypeDeclaration(module->m_classTypes[i], 3); - } - - if( error ) return asERROR; - - // Read typedefs - count = ReadEncodedUInt(); - module->m_typeDefs.Allocate(count, false); - for( i = 0; i < count && !error; i++ ) - { - asCTypedefType *td = asNEW(asCTypedefType)(engine); - if( td == 0 ) - { - error = true; - return asOUT_OF_MEMORY; - } - - bool isExternal = false; - ReadTypeDeclaration(td, 1, &isExternal); - td->module = module; - module->AddTypeDef(td); - ReadTypeDeclaration(td, 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->m_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->m_scriptFunctions.GetLength(); - bool isNew, isExternal; - func = ReadFunction(isNew, true, true, true, &isExternal); - if( func == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - break; - } - - // Is the function shared and was it created now? - if( func->IsShared() && len != module->m_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->nameSpace == func->nameSpace && - realFunc->IsSignatureEqual(func) ) - { - // Replace the recently created function with the pre-existing function - module->m_scriptFunctions[module->m_scriptFunctions.GetLength()-1] = realFunc; - realFunc->AddRefInternal(); - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - engine->RemoveScriptFunction(func); - - // Insert the function in the dontTranslate array - dontTranslate.Insert(realFunc, true); - - if (isExternal) - module->m_externalFunctions.PushLast(realFunc); - - // Release the function, but make sure nothing else is released - func->id = 0; - if( func->scriptData ) - func->scriptData->byteCode.SetLength(0); - func->ReleaseInternal(); - func = 0; - break; - } - } - } - - // Check if an external shared func was really found - if (isExternal && func) - { - asCString msg; - msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, func->name.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); - error = true; - return asERROR; - } - } - - // globalFunctions[] - 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 references to know which goes into the globalFunctions array - asASSERT( !isNew ); - - module->m_globalFunctions.Put(func); - } - else - Error(TXT_INVALID_BYTECODE_d); - } - - if( error ) return asERROR; - - // bindInformations[] - count = ReadEncodedUInt(); - module->m_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->m_bindInformations.PushLast(info); - } - - if( error ) return asERROR; - - // usedTypes[] - count = ReadEncodedUInt(); - usedTypes.Allocate(count, false); - for( i = 0; i < count && !error; ++i ) - { - asCTypeInfo *ti = ReadTypeInfo(); - usedTypes.PushLast(ti); - } - - // 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++ ) - { - asCObjectType *ot = CastToObjectType(usedTypes[i]); - if( !ot || - !(ot->flags & asOBJ_TEMPLATE) || - !ot->beh.templateCallback ) - continue; - - bool dontGarbageCollect = false; - asCScriptFunction *callback = engine->scriptFunctions[ot->beh.templateCallback]; - if( !engine->CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) ) - { - asCString sub = ot->templateSubTypes[0].Format(ot->nameSpace); - for( asUINT n = 1; n < ot->templateSubTypes.GetLength(); n++ ) - { - sub += ","; - sub += ot->templateSubTypes[n].Format(ot->nameSpace); - } - asCString str; - str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - else - { - // If the callback said this template instance won't be garbage collected then remove the flag - if( dontGarbageCollect ) - ot->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->m_scriptFunctions.GetLength() && !error; i++ ) - if( module->m_scriptFunctions[i]->funcType == asFUNC_SCRIPT ) - TranslateFunction(module->m_scriptFunctions[i]); - - asCSymbolTable::iterator globIt = module->m_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->m_scriptFunctions.GetLength(); i++ ) - if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) ) - module->m_scriptFunctions[i]->AddReferences(); - - globIt = module->m_scriptGlobals.List(); - while( globIt ) - { - asCScriptFunction *initFunc = (*globIt)->GetInitFunc(); - if( initFunc ) - initFunc->AddReferences(); - globIt++; - } - return error ? asERROR : asSUCCESS; + TimeIt("asCReader::ReadInner"); + + // This function will load each entity one by one from the stream. + // If any error occurs, it will return to the caller who is + // responsible for cleaning up the partially loaded entities. + + engine->deferValidationOfTemplateTypes = true; + + unsigned long i, count; + asCScriptFunction* func; + + // Read the flag as 1 byte even on platforms with 4byte booleans + noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0; + + // Read enums + count = ReadEncodedUInt(); + module->m_enumTypes.Allocate(count, false); + for( i = 0; i < count && !error; i++ ) + { + asCEnumType *et = asNEW(asCEnumType)(engine); + if( et == 0 ) + { + error = true; + return asOUT_OF_MEMORY; + } + + bool isExternal = false; + ReadTypeDeclaration(et, 1, &isExternal); + + // If the type is shared then we should use the original if it exists + bool sharedExists = false; + if( et->IsShared() ) + { + for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) + { + asCTypeInfo *t = engine->sharedScriptTypes[n]; + if( t && + t->IsShared() && + t->name == et->name && + t->nameSpace == et->nameSpace && + (t->flags & asOBJ_ENUM) ) + { + asDELETE(et, asCEnumType); + et = CastToEnumType(t); + sharedExists = true; + break; + } + } + } + + if (isExternal && !sharedExists) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, et->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + asDELETE(et, asCEnumType); + error = true; + return asERROR; + } + + if( sharedExists ) + { + existingShared.Insert(et, true); + et->AddRefInternal(); + } + else + { + if( et->IsShared() ) + { + engine->sharedScriptTypes.PushLast(et); + et->AddRefInternal(); + } + + // Set this module as the owner + et->module = module; + } + module->AddEnumType(et); + + if (isExternal) + module->m_externalTypes.PushLast(et); + + ReadTypeDeclaration(et, 2); + } + + if( error ) return asERROR; + + // classTypes[] + // First restore the structure names, then the properties + count = ReadEncodedUInt(); + module->m_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; + } + + bool isExternal = false; + ReadTypeDeclaration(ot, 1, &isExternal); + + // 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->sharedScriptTypes.GetLength(); n++ ) + { + asCTypeInfo *ti = engine->sharedScriptTypes[n]; + asCObjectType *t = CastToObjectType(ti); + if( t && + t->IsShared() && + t->name == ot->name && + t->nameSpace == ot->nameSpace && + t->IsInterface() == ot->IsInterface() ) + { + asDELETE(ot, asCObjectType); + ot = CastToObjectType(t); + sharedExists = true; + break; + } + } + } + + if (isExternal && !sharedExists) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, ot->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + asDELETE(ot, asCObjectType); + error = true; + return asERROR; + } + + if( sharedExists ) + { + existingShared.Insert(ot, true); + ot->AddRefInternal(); + } + else + { + if( ot->IsShared() ) + { + engine->sharedScriptTypes.PushLast(ot); + ot->AddRefInternal(); + } + + // Set this module as the owner + ot->module = module; + } + module->AddClassType(ot); + + if (isExternal) + module->m_externalTypes.PushLast(ot); + } + + if( error ) return asERROR; + + // Read func defs + count = ReadEncodedUInt(); + module->m_funcDefs.Allocate(count, false); + for( i = 0; i < count && !error; i++ ) + { + bool isNew, isExternal; + asCScriptFunction *funcDef = ReadFunction(isNew, false, true, true, &isExternal); + if(funcDef) + { + funcDef->module = module; + + asCFuncdefType *fdt = funcDef->funcdefType; + fdt->module = module; + + module->AddFuncDef(fdt); + engine->funcDefs.PushLast(fdt); + + // TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module + // Check if there is another identical funcdef from another module and if so reuse that instead + if(funcDef->IsShared()) + { + for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) + { + asCFuncdefType *f2 = engine->funcDefs[n]; + if( f2 == 0 || fdt == f2 ) + continue; + + if( !f2->funcdef->IsShared() ) + continue; + + if( f2->name == fdt->name && + f2->nameSpace == fdt->nameSpace && + f2->parentClass == fdt->parentClass && + f2->funcdef->IsSignatureExceptNameEqual(funcDef) ) + { + // Replace our funcdef for the existing one + module->ReplaceFuncDef(fdt, f2); + f2->AddRefInternal(); + + if (isExternal) + module->m_externalTypes.PushLast(f2); + + engine->funcDefs.RemoveValue(fdt); + + savedFunctions[savedFunctions.IndexOf(funcDef)] = f2->funcdef; + + if (fdt->parentClass) + { + // The real funcdef should already be in the object + asASSERT(fdt->parentClass->childFuncDefs.IndexOf(f2) >= 0); + + fdt->parentClass = 0; + } + + fdt->ReleaseInternal(); + funcDef = 0; + break; + } + } + } + + // Add the funcdef to the parentClass if this is a child funcdef + if (funcDef && fdt->parentClass) + fdt->parentClass->childFuncDefs.PushLast(fdt); + + // Check if an external shared funcdef was really found + if (isExternal && funcDef) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + error = true; + return asERROR; + } + } + else + Error(TXT_INVALID_BYTECODE_d); + } + + // Read interface methods + for( i = 0; i < module->m_classTypes.GetLength() && !error; i++ ) + { + if( module->m_classTypes[i]->IsInterface() ) + ReadTypeDeclaration(module->m_classTypes[i], 2); + } + + // Read class methods and behaviours + for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i ) + { + if( !module->m_classTypes[i]->IsInterface() ) + ReadTypeDeclaration(module->m_classTypes[i], 2); + } + + // Read class properties + for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i ) + { + if( !module->m_classTypes[i]->IsInterface() ) + ReadTypeDeclaration(module->m_classTypes[i], 3); + } + + if( error ) return asERROR; + + // Read typedefs + count = ReadEncodedUInt(); + module->m_typeDefs.Allocate(count, false); + for( i = 0; i < count && !error; i++ ) + { + asCTypedefType *td = asNEW(asCTypedefType)(engine); + if( td == 0 ) + { + error = true; + return asOUT_OF_MEMORY; + } + + bool isExternal = false; + ReadTypeDeclaration(td, 1, &isExternal); + td->module = module; + module->AddTypeDef(td); + ReadTypeDeclaration(td, 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->m_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->m_scriptFunctions.GetLength(); + bool isNew, isExternal; + func = ReadFunction(isNew, true, true, true, &isExternal); + if( func == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + break; + } + + // Is the function shared and was it created now? + if( func->IsShared() && len != module->m_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->nameSpace == func->nameSpace && + realFunc->IsSignatureEqual(func) ) + { + // Replace the recently created function with the pre-existing function + module->m_scriptFunctions[module->m_scriptFunctions.GetLength()-1] = realFunc; + realFunc->AddRefInternal(); + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + engine->RemoveScriptFunction(func); + + // Insert the function in the dontTranslate array + dontTranslate.Insert(realFunc, true); + + if (isExternal) + module->m_externalFunctions.PushLast(realFunc); + + // Release the function, but make sure nothing else is released + func->id = 0; + if( func->scriptData ) + func->scriptData->byteCode.SetLength(0); + func->ReleaseInternal(); + func = 0; + break; + } + } + } + + // Check if an external shared func was really found + if (isExternal && func) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, func->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + error = true; + return asERROR; + } + } + + // globalFunctions[] + 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 references to know which goes into the globalFunctions array + asASSERT( !isNew ); + + module->m_globalFunctions.Put(func); + } + else + Error(TXT_INVALID_BYTECODE_d); + } + + if( error ) return asERROR; + + // bindInformations[] + count = ReadEncodedUInt(); + module->m_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->m_bindInformations.PushLast(info); + } + + if( error ) return asERROR; + + // usedTypes[] + count = ReadEncodedUInt(); + usedTypes.Allocate(count, false); + for( i = 0; i < count && !error; ++i ) + { + asCTypeInfo *ti = ReadTypeInfo(); + usedTypes.PushLast(ti); + } + + // 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++ ) + { + asCObjectType *ot = CastToObjectType(usedTypes[i]); + if( !ot || + !(ot->flags & asOBJ_TEMPLATE) || + !ot->beh.templateCallback ) + continue; + + bool dontGarbageCollect = false; + asCScriptFunction *callback = engine->scriptFunctions[ot->beh.templateCallback]; + if( !engine->CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) ) + { + asCString sub = ot->templateSubTypes[0].Format(ot->nameSpace); + for( asUINT n = 1; n < ot->templateSubTypes.GetLength(); n++ ) + { + sub += ","; + sub += ot->templateSubTypes[n].Format(ot->nameSpace); + } + asCString str; + str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + else + { + // If the callback said this template instance won't be garbage collected then remove the flag + if( dontGarbageCollect ) + ot->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->m_scriptFunctions.GetLength() && !error; i++ ) + if( module->m_scriptFunctions[i]->funcType == asFUNC_SCRIPT ) + TranslateFunction(module->m_scriptFunctions[i]); + + asCSymbolTable::iterator globIt = module->m_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->m_scriptFunctions.GetLength(); i++ ) + if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) ) + module->m_scriptFunctions[i]->AddReferences(); + + globIt = module->m_scriptGlobals.List(); + while( globIt ) + { + asCScriptFunction *initFunc = (*globIt)->GetInitFunc(); + if( initFunc ) + initFunc->AddReferences(); + globIt++; + } + return error ? asERROR : asSUCCESS; } void asCReader::ReadUsedStringConstants() { - TimeIt("asCReader::ReadUsedStringConstants"); + TimeIt("asCReader::ReadUsedStringConstants"); - asCString str; + asCString str; - asUINT count; - count = ReadEncodedUInt(); + asUINT count; + count = ReadEncodedUInt(); - if (count > 0 && engine->stringFactory == 0) - { - Error(TXT_STRINGS_NOT_RECOGNIZED); - return; - } + if (count > 0 && engine->stringFactory == 0) + { + Error(TXT_STRINGS_NOT_RECOGNIZED); + return; + } - usedStringConstants.Allocate(count, false); - for( asUINT i = 0; i < count; ++i ) - { - ReadString(&str); - usedStringConstants.PushLast(const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()))); - } + usedStringConstants.Allocate(count, false); + for( asUINT i = 0; i < count; ++i ) + { + ReadString(&str); + usedStringConstants.PushLast(const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()))); + } } void asCReader::ReadUsedFunctions() { - TimeIt("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); - asCObjectType *parentClass = 0; - ReadFunctionSignature(&func, &parentClass); - 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->m_bindInformations.GetLength(); i++ ) - { - asCScriptFunction *f = module->m_bindInformations[i]->importedFunctionSignature; - if( func.objectType != f->objectType || - func.funcType != f->funcType || - func.nameSpace != f->nameSpace || - !func.IsSignatureEqual(f) ) - continue; - - usedFunctions[n] = f; - break; - } - } - else if( func.funcType == asFUNC_FUNCDEF ) - { - const asCArray &funcs = module->m_funcDefs; - for( asUINT i = 0; i < funcs.GetLength(); i++ ) - { - asCScriptFunction *f = funcs[i]->funcdef; - if( f == 0 || - func.name != f->name || - !func.IsSignatureExceptNameAndObjectTypeEqual(f) || - funcs[i]->parentClass != parentClass ) - continue; - - asASSERT( f->objectType == 0 ); - - usedFunctions[n] = f; - break; - } - } - else - { - // TODO: optimize: Global functions should be searched for in module->globalFunctions - // TODO: optimize: funcdefs should be searched for in module->funcDefs - // TODO: optimize: object methods should be searched for directly in the object type - for( asUINT i = 0; i < module->m_scriptFunctions.GetLength(); i++ ) - { - asCScriptFunction *f = module->m_scriptFunctions[i]; - if( func.objectType != f->objectType || - func.funcType != f->funcType || - func.nameSpace != f->nameSpace || - !func.IsSignatureEqual(f) ) - continue; - - usedFunctions[n] = f; - break; - } - } - } - else if (c == 's') - { - // Look for shared entities in the engine, as they may not necessarily be part - // of the scope of the module if they have been inhereted from other modules. - if (func.funcType == asFUNC_FUNCDEF) - { - const asCArray &funcs = engine->funcDefs; - for (asUINT i = 0; i < funcs.GetLength(); i++) - { - asCScriptFunction *f = funcs[i]->funcdef; - if (f == 0 || - func.name != f->name || - !func.IsSignatureExceptNameAndObjectTypeEqual(f) || - funcs[i]->parentClass != parentClass) - continue; - - asASSERT(f->objectType == 0); - - usedFunctions[n] = f; - break; - } - } - else - { - for (asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++) - { - asCScriptFunction *f = engine->scriptFunctions[i]; - if (f == 0 || !f->IsShared() || - func.objectType != f->objectType || - func.funcType != f->funcType || - func.nameSpace != f->nameSpace || - !func.IsSignatureEqual(f)) - continue; - - usedFunctions[n] = f; - break; - } - } - } - else - { - asASSERT(c == 'a'); - - if( func.funcType == asFUNC_FUNCDEF ) - { - // This is a funcdef (registered or shared) - const asCArray &funcs = engine->funcDefs; - for( asUINT i = 0; i < funcs.GetLength(); i++ ) - { - asCScriptFunction *f = funcs[i]->funcdef; - if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) || funcs[i]->parentClass != parentClass ) - continue; - - asASSERT( f->objectType == 0 ); - - usedFunctions[n] = f; - break; - } - } - else if( func.name[0] == '$' ) - { - // This is a special function - - if( func.name == "$beh0" && func.objectType ) - { - if (func.objectType->flags & asOBJ_TEMPLATE) - { - // Look for the matching constructor inside the factory stubs generated for the template instance - // See asCCompiler::PerformFunctionCall - for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++) - { - asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]]; - - // Find the id of the real constructor and not the generated stub - asUINT id = 0; - asDWORD *bc = f->scriptData->byteCode.AddressOf(); - while (bc) - { - if ((*(asBYTE*)bc) == asBC_CALLSYS) - { - id = asBC_INTARG(bc); - break; - } - bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type]; - } - - f = engine->scriptFunctions[id]; - if (f == 0 || - !func.IsSignatureExceptNameAndObjectTypeEqual(f)) - continue; - - usedFunctions[n] = f; - break; - } - } - - if( usedFunctions[n] == 0 ) - { - // This is a class constructor, so we can search directly in the object type's constructors - for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++) - { - asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]]; - if (f == 0 || - !func.IsSignatureExceptNameAndObjectTypeEqual(f)) - continue; - - usedFunctions[n] = f; - break; - } - } - } - else if( func.name == "$fact" || func.name == "$beh3" ) - { - // This is a factory (or stub), so look for the function in the return type's factories - asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo()); - if( objType ) - { - for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ ) - { - asCScriptFunction *f = engine->scriptFunctions[objType->beh.factories[i]]; - if( f == 0 || - !func.IsSignatureExceptNameAndObjectTypeEqual(f) ) - continue; - - usedFunctions[n] = f; - break; - } - } - } - else if( func.name == "$list" ) - { - // listFactory is used for both factory is global and returns a handle and constructor that is a method - asCObjectType *objType = func.objectType ? func.objectType : CastToObjectType(func.returnType.GetTypeInfo()); - if( objType ) - { - asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory]; - if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) ) - usedFunctions[n] = f; - } - } - else if( func.name == "$beh2" ) - { - // This is a destructor, so check the object type's destructor - asCObjectType *objType = func.objectType; - if( objType ) - { - asCScriptFunction *f = engine->scriptFunctions[objType->beh.destruct]; - if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) ) - usedFunctions[n] = f; - } - } - else if( func.name == "$dlgte" ) - { - // This is the delegate factory - asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY); - asASSERT( f && func.IsSignatureEqual(f) ); - usedFunctions[n] = f; - } - else - { - // Must match one of the above cases - asASSERT(false); - } - } - else if( func.objectType == 0 ) - { - // This is a global function - const asCArray &funcs = engine->registeredGlobalFuncs.GetIndexes(func.nameSpace, func.name); - for( asUINT i = 0; i < funcs.GetLength(); i++ ) - { - asCScriptFunction *f = engine->registeredGlobalFuncs.Get(funcs[i]); - if( f == 0 || - !func.IsSignatureExceptNameAndObjectTypeEqual(f) ) - continue; - - usedFunctions[n] = f; - break; - } - } - else if( func.objectType ) - { - // It is a class member, so we can search directly in the object type's members - // TODO: virtual function is different that implemented method - for( asUINT i = 0; i < func.objectType->methods.GetLength(); i++ ) - { - asCScriptFunction *f = engine->scriptFunctions[func.objectType->methods[i]]; - if( f == 0 || - !func.IsSignatureEqual(f) ) - continue; - - usedFunctions[n] = f; - break; - } - } - - if( usedFunctions[n] == 0 ) - { - // TODO: clean up: This part of the code should never happen. All functions should - // be found in the above logic. The only valid reason to come here - // is if the bytecode is wrong and the function doesn't exist anyway. - // This loop is kept temporarily until we can be certain all scenarios - // are covered. - for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ ) - { - asCScriptFunction *f = engine->scriptFunctions[i]; - if( f == 0 || - func.objectType != f->objectType || - func.nameSpace != f->nameSpace || - !func.IsSignatureEqual(f) ) - continue; - - usedFunctions[n] = f; - break; - } - - // No function is expected to be found - asASSERT(usedFunctions[n] == 0); - } - } - - // 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; - } - } - } + TimeIt("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); + asCObjectType *parentClass = 0; + ReadFunctionSignature(&func, &parentClass); + 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->m_bindInformations.GetLength(); i++ ) + { + asCScriptFunction *f = module->m_bindInformations[i]->importedFunctionSignature; + if( func.objectType != f->objectType || + func.funcType != f->funcType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + else if( func.funcType == asFUNC_FUNCDEF ) + { + const asCArray &funcs = module->m_funcDefs; + for( asUINT i = 0; i < funcs.GetLength(); i++ ) + { + asCScriptFunction *f = funcs[i]->funcdef; + if( f == 0 || + func.name != f->name || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) || + funcs[i]->parentClass != parentClass ) + continue; + + asASSERT( f->objectType == 0 ); + + usedFunctions[n] = f; + break; + } + } + else + { + // TODO: optimize: Global functions should be searched for in module->globalFunctions + // TODO: optimize: funcdefs should be searched for in module->funcDefs + // TODO: optimize: object methods should be searched for directly in the object type + for( asUINT i = 0; i < module->m_scriptFunctions.GetLength(); i++ ) + { + asCScriptFunction *f = module->m_scriptFunctions[i]; + if( func.objectType != f->objectType || + func.funcType != f->funcType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + } + else if (c == 's') + { + // Look for shared entities in the engine, as they may not necessarily be part + // of the scope of the module if they have been inhereted from other modules. + if (func.funcType == asFUNC_FUNCDEF) + { + const asCArray &funcs = engine->funcDefs; + for (asUINT i = 0; i < funcs.GetLength(); i++) + { + asCScriptFunction *f = funcs[i]->funcdef; + if (f == 0 || + func.name != f->name || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) || + funcs[i]->parentClass != parentClass) + continue; + + asASSERT(f->objectType == 0); + + usedFunctions[n] = f; + break; + } + } + else + { + for (asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++) + { + asCScriptFunction *f = engine->scriptFunctions[i]; + if (f == 0 || !f->IsShared() || + func.objectType != f->objectType || + func.funcType != f->funcType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f)) + continue; + + usedFunctions[n] = f; + break; + } + } + } + else + { + asASSERT(c == 'a'); + + if( func.funcType == asFUNC_FUNCDEF ) + { + // This is a funcdef (registered or shared) + const asCArray &funcs = engine->funcDefs; + for( asUINT i = 0; i < funcs.GetLength(); i++ ) + { + asCScriptFunction *f = funcs[i]->funcdef; + if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) || funcs[i]->parentClass != parentClass ) + continue; + + asASSERT( f->objectType == 0 ); + + usedFunctions[n] = f; + break; + } + } + else if( func.name[0] == '$' ) + { + // This is a special function + + if( func.name == "$beh0" && func.objectType ) + { + if (func.objectType->flags & asOBJ_TEMPLATE) + { + // Look for the matching constructor inside the factory stubs generated for the template instance + // See asCCompiler::PerformFunctionCall + for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++) + { + asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]]; + + // Find the id of the real constructor and not the generated stub + asUINT id = 0; + asDWORD *bc = f->scriptData->byteCode.AddressOf(); + while (bc) + { + if ((*(asBYTE*)bc) == asBC_CALLSYS) + { + id = asBC_INTARG(bc); + break; + } + bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type]; + } + + f = engine->scriptFunctions[id]; + if (f == 0 || + !func.IsSignatureExceptNameAndObjectTypeEqual(f)) + continue; + + usedFunctions[n] = f; + break; + } + } + + if( usedFunctions[n] == 0 ) + { + // This is a class constructor, so we can search directly in the object type's constructors + for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++) + { + asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]]; + if (f == 0 || + !func.IsSignatureExceptNameAndObjectTypeEqual(f)) + continue; + + usedFunctions[n] = f; + break; + } + } + } + else if( func.name == "$fact" || func.name == "$beh3" ) + { + // This is a factory (or stub), so look for the function in the return type's factories + asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo()); + if( objType ) + { + for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ ) + { + asCScriptFunction *f = engine->scriptFunctions[objType->beh.factories[i]]; + if( f == 0 || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + } + else if( func.name == "$list" ) + { + // listFactory is used for both factory is global and returns a handle and constructor that is a method + asCObjectType *objType = func.objectType ? func.objectType : CastToObjectType(func.returnType.GetTypeInfo()); + if( objType ) + { + asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory]; + if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + usedFunctions[n] = f; + } + } + else if( func.name == "$beh2" ) + { + // This is a destructor, so check the object type's destructor + asCObjectType *objType = func.objectType; + if( objType ) + { + asCScriptFunction *f = engine->scriptFunctions[objType->beh.destruct]; + if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + usedFunctions[n] = f; + } + } + else if( func.name == "$dlgte" ) + { + // This is the delegate factory + asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY); + asASSERT( f && func.IsSignatureEqual(f) ); + usedFunctions[n] = f; + } + else + { + // Must match one of the above cases + asASSERT(false); + } + } + else if( func.objectType == 0 ) + { + // This is a global function + const asCArray &funcs = engine->registeredGlobalFuncs.GetIndexes(func.nameSpace, func.name); + for( asUINT i = 0; i < funcs.GetLength(); i++ ) + { + asCScriptFunction *f = engine->registeredGlobalFuncs.Get(funcs[i]); + if( f == 0 || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + else if( func.objectType ) + { + // It is a class member, so we can search directly in the object type's members + // TODO: virtual function is different that implemented method + for( asUINT i = 0; i < func.objectType->methods.GetLength(); i++ ) + { + asCScriptFunction *f = engine->scriptFunctions[func.objectType->methods[i]]; + if( f == 0 || + !func.IsSignatureEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + + if( usedFunctions[n] == 0 ) + { + // TODO: clean up: This part of the code should never happen. All functions should + // be found in the above logic. The only valid reason to come here + // is if the bytecode is wrong and the function doesn't exist anyway. + // This loop is kept temporarily until we can be certain all scenarios + // are covered. + for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ ) + { + asCScriptFunction *f = engine->scriptFunctions[i]; + if( f == 0 || + func.objectType != f->objectType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + + // No function is expected to be found + asASSERT(usedFunctions[n] == 0); + } + } + + // 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, asCObjectType **parentClass) { - 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()); - if (func->parameterTypes.GetLength() > 0) - { - 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 - if (func->parameterTypes.GetLength() > 0) - { - 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 = CastToObjectType(ReadTypeInfo()); - if( func->objectType ) - { - func->objectType->AddRefInternal(); - - asBYTE b; - ReadData(&b, 1); - func->SetReadOnly((b & 1) ? true : false); - func->SetPrivate((b & 2) ? true : false); - func->SetProtected((b & 4) ? true : false); - func->nameSpace = func->objectType->nameSpace; - } - else - { - if (func->funcType == asFUNC_FUNCDEF) - { - asBYTE b; - ReadData(&b, 1); - if (b == 'n') - { - asCString ns; - ReadString(&ns); - func->nameSpace = engine->AddNameSpace(ns.AddressOf()); - } - else if (b == 'o') - { - func->nameSpace = 0; - if (parentClass) - *parentClass = CastToObjectType(ReadTypeInfo()); - else - error = true; - } - else - error = true; - } - else - { - asCString ns; - ReadString(&ns); - func->nameSpace = engine->AddNameSpace(ns.AddressOf()); - } - } + 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()); + if (func->parameterTypes.GetLength() > 0) + { + 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 + if (func->parameterTypes.GetLength() > 0) + { + 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 = CastToObjectType(ReadTypeInfo()); + if( func->objectType ) + { + func->objectType->AddRefInternal(); + + asBYTE b; + ReadData(&b, 1); + func->SetReadOnly((b & 1) ? true : false); + func->SetPrivate((b & 2) ? true : false); + func->SetProtected((b & 4) ? true : false); + func->nameSpace = func->objectType->nameSpace; + } + else + { + if (func->funcType == asFUNC_FUNCDEF) + { + asBYTE b; + ReadData(&b, 1); + if (b == 'n') + { + asCString ns; + ReadString(&ns); + func->nameSpace = engine->AddNameSpace(ns.AddressOf()); + } + else if (b == 'o') + { + func->nameSpace = 0; + if (parentClass) + *parentClass = CastToObjectType(ReadTypeInfo()); + else + error = true; + } + else + error = true; + } + else + { + asCString ns; + ReadString(&ns); + func->nameSpace = engine->AddNameSpace(ns.AddressOf()); + } + } } asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC, bool *isExternal) { - isNew = false; - if (isExternal) *isExternal = 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; - - asCObjectType *parentClass = 0; - ReadFunctionSignature(func, &parentClass); - if( error ) - { - func->DestroyHalfCreated(); - return 0; - } - - if( func->funcType == asFUNC_SCRIPT ) - { - // Skip this for external shared entities - if (module->m_externalTypes.IndexOf(func->objectType) >= 0) - { - // Replace with the real function from the existing entity - isNew = false; - - asCObjectType *ot = func->objectType; - for (asUINT n = 0; n < ot->methods.GetLength(); n++) - { - asCScriptFunction *func2 = engine->scriptFunctions[ot->methods[n]]; - if (func2->funcType == asFUNC_VIRTUAL) - func2 = ot->virtualFunctionTable[func2->vfTableIdx]; - - if (func->IsSignatureEqual(func2)) - { - func->DestroyHalfCreated(); - - // as this is an existing function it shouldn't be translated as if just loaded - dontTranslate.Insert(func2, true); - - // update the saved functions for future references - savedFunctions[savedFunctions.GetLength() - 1] = func2; - - // As it is an existing function it shouldn't be added to the module or the engine - return func2; - } - } - } - else - { - char bits; - ReadData(&bits, 1); - func->SetShared((bits & 1) ? true : false); - func->SetExplicit((bits & 32) ? true : false); - func->dontCleanUpOnException = (bits & 2) ? true : false; - if ((bits & 4) && isExternal) - *isExternal = true; - - // for external shared functions the rest is not needed - if (!(bits & 4)) - { - 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(); - - func->scriptData->objVariablesOnHeap = 0; - if (bits & 8) - { - count = ReadEncodedUInt(); - func->scriptData->objVariablePos.Allocate(count, false); - func->scriptData->objVariableTypes.Allocate(count, false); - for (i = 0; i < count; ++i) - { - func->scriptData->objVariableTypes.PushLast(ReadTypeInfo()); - num = ReadEncodedUInt(); - func->scriptData->objVariablePos.PushLast(num); - - if (error) - { - // No need to continue (the error has already been reported before) - func->DestroyHalfCreated(); - return 0; - } - } - if (count > 0) - func->scriptData->objVariablesOnHeap = ReadEncodedUInt(); - - 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(); - asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt(); - func->scriptData->objVariableInfo[i].option = option; - if (option != asOBJ_INIT && - option != asOBJ_UNINIT && - option != asBLOCK_BEGIN && - option != asBLOCK_END && - option != asOBJ_VARDECL) - { - error = true; - func->DestroyHalfCreated(); - return 0; - } - } - } - - if (bits & 16) - { - // Read info on try/catch blocks - int length = ReadEncodedUInt(); - func->scriptData->tryCatchInfo.SetLength(length); - for (i = 0; i < length; ++i) - { - // The program position must be adjusted to be in number of instructions - func->scriptData->tryCatchInfo[i].tryPos = ReadEncodedUInt(); - func->scriptData->tryCatchInfo[i].catchPos = ReadEncodedUInt(); - } - } - - if (!noDebugInfo) - { - int 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) - { - int length = ReadEncodedUInt(); - func->scriptData->variables.Allocate(length, false); - for (i = 0; i < length; i++) - { - asSScriptVariable *var = asNEW(asSScriptVariable); - if (var == 0) - { - // Out of memory - error = true; - func->DestroyHalfCreated(); - return 0; - } - func->scriptData->variables.PushLast(var); - - var->declaredAtProgramPos = ReadEncodedUInt(); - var->stackOffset = ReadEncodedUInt(); - ReadString(&var->name); - ReadDataType(&var->type); - - if (error) - { - // No need to continue (the error has already been reported before) - func->DestroyHalfCreated(); - return 0; - } - } - } - - // Read script section name - if (!noDebugInfo) - { - asCString name; - ReadString(&name); - func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf()); - func->scriptData->declaredAt = ReadEncodedUInt(); - } - - // Read parameter names - if (!noDebugInfo) - { - asUINT countParam = asUINT(ReadEncodedUInt64()); - if (countParam > func->parameterTypes.GetLength()) - { - error = true; - func->DestroyHalfCreated(); - return 0; - } - func->parameterNames.SetLength(countParam); - for (asUINT n = 0; n < countParam; n++) - ReadString(&func->parameterNames[n]); - } - } - } - } - else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) - { - func->vfTableIdx = ReadEncodedUInt(); - } - else if( func->funcType == asFUNC_FUNCDEF ) - { - asBYTE bits; - ReadData(&bits, 1); - if( bits & 1 ) - func->SetShared(true); - if ((bits & 2) && isExternal) - *isExternal = true; - - // The asCFuncdefType constructor adds itself to the func->funcdefType member - asCFuncdefType *fdt = asNEW(asCFuncdefType)(engine, func); - fdt->parentClass = parentClass; - } - - // Methods loaded for shared objects, owned by other modules should not be created as new functions - if( func->objectType && func->objectType->module != module ) - { - // Return the real function from the object - asCScriptFunction *realFunc = 0; - bool found = false; - if( func->funcType == asFUNC_SCRIPT ) - { - realFunc = engine->scriptFunctions[func->objectType->beh.destruct]; - if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) - { - found = true; - } - for( asUINT n = 0; !found && n < func->objectType->beh.constructors.GetLength(); n++ ) - { - realFunc = engine->scriptFunctions[func->objectType->beh.constructors[n]]; - if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) - { - found = true; - break; - } - } - for( asUINT n = 0; !found && n < func->objectType->beh.factories.GetLength(); n++ ) - { - realFunc = engine->scriptFunctions[func->objectType->beh.factories[n]]; - if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) - { - found = true; - break; - } - } - for( asUINT n = 0; !found && n < func->objectType->methods.GetLength(); n++ ) - { - realFunc = engine->scriptFunctions[func->objectType->methods[n]]; - if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) - { - found = true; - break; - } - } - for( asUINT n = 0; !found && n < func->objectType->virtualFunctionTable.GetLength(); n++ ) - { - realFunc = func->objectType->virtualFunctionTable[n]; - if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) - { - found = true; - break; - } - } - } - else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) - { - // If the loaded function is a virtual function, then look for the identical virtual function in the methods array - for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ ) - { - realFunc = engine->scriptFunctions[func->objectType->methods[n]]; - if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) - { - asASSERT( func->vfTableIdx == realFunc->vfTableIdx ); - found = true; - break; - } - } - } - - if( found ) - { - // as this is an existing function it shouldn't be translated as if just loaded - dontTranslate.Insert(realFunc, true); - - // update the saved functions for future references - savedFunctions[savedFunctions.GetLength() - 1] = realFunc; - - if( realFunc->funcType == asFUNC_VIRTUAL && addToModule ) - { - // Virtual methods must be added to the module's script functions array, - // even if they are not owned by the module - module->m_scriptFunctions.PushLast(realFunc); - realFunc->AddRefInternal(); - } - } - else - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, func->objectType->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - - Error(TXT_INVALID_BYTECODE_d); - savedFunctions.PopLast(); - realFunc = 0; - } - - // Destroy the newly created function instance since it has been replaced by an existing function - isNew = false; - func->DestroyHalfCreated(); - - // As it is an existing function it shouldn't be added to the module or the engine - return realFunc; - } - - if( addToModule ) - { - // The refCount is already 1 - module->m_scriptFunctions.PushLast(func); - func->module = module; - } - if( addToEngine ) - { - func->id = engine->GetNextScriptFunctionId(); - engine->AddScriptFunction(func); - } - if( func->objectType ) - func->ComputeSignatureId(); - - return func; + isNew = false; + if (isExternal) *isExternal = 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; + + asCObjectType *parentClass = 0; + ReadFunctionSignature(func, &parentClass); + if( error ) + { + func->DestroyHalfCreated(); + return 0; + } + + if( func->funcType == asFUNC_SCRIPT ) + { + // Skip this for external shared entities + if (module->m_externalTypes.IndexOf(func->objectType) >= 0) + { + // Replace with the real function from the existing entity + isNew = false; + + asCObjectType *ot = func->objectType; + for (asUINT n = 0; n < ot->methods.GetLength(); n++) + { + asCScriptFunction *func2 = engine->scriptFunctions[ot->methods[n]]; + if (func2->funcType == asFUNC_VIRTUAL) + func2 = ot->virtualFunctionTable[func2->vfTableIdx]; + + if (func->IsSignatureEqual(func2)) + { + func->DestroyHalfCreated(); + + // as this is an existing function it shouldn't be translated as if just loaded + dontTranslate.Insert(func2, true); + + // update the saved functions for future references + savedFunctions[savedFunctions.GetLength() - 1] = func2; + + // As it is an existing function it shouldn't be added to the module or the engine + return func2; + } + } + } + else + { + char bits; + ReadData(&bits, 1); + func->SetShared((bits & 1) ? true : false); + func->SetExplicit((bits & 32) ? true : false); + func->dontCleanUpOnException = (bits & 2) ? true : false; + if ((bits & 4) && isExternal) + *isExternal = true; + + // for external shared functions the rest is not needed + if (!(bits & 4)) + { + 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(); + + func->scriptData->objVariablesOnHeap = 0; + if (bits & 8) + { + count = ReadEncodedUInt(); + func->scriptData->objVariablePos.Allocate(count, false); + func->scriptData->objVariableTypes.Allocate(count, false); + for (i = 0; i < count; ++i) + { + func->scriptData->objVariableTypes.PushLast(ReadTypeInfo()); + num = ReadEncodedUInt(); + func->scriptData->objVariablePos.PushLast(num); + + if (error) + { + // No need to continue (the error has already been reported before) + func->DestroyHalfCreated(); + return 0; + } + } + if (count > 0) + func->scriptData->objVariablesOnHeap = ReadEncodedUInt(); + + 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(); + asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt(); + func->scriptData->objVariableInfo[i].option = option; + if (option != asOBJ_INIT && + option != asOBJ_UNINIT && + option != asBLOCK_BEGIN && + option != asBLOCK_END && + option != asOBJ_VARDECL) + { + error = true; + func->DestroyHalfCreated(); + return 0; + } + } + } + + if (bits & 16) + { + // Read info on try/catch blocks + int length = ReadEncodedUInt(); + func->scriptData->tryCatchInfo.SetLength(length); + for (i = 0; i < length; ++i) + { + // The program position must be adjusted to be in number of instructions + func->scriptData->tryCatchInfo[i].tryPos = ReadEncodedUInt(); + func->scriptData->tryCatchInfo[i].catchPos = ReadEncodedUInt(); + } + } + + if (!noDebugInfo) + { + int 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) + { + int length = ReadEncodedUInt(); + func->scriptData->variables.Allocate(length, false); + for (i = 0; i < length; i++) + { + asSScriptVariable *var = asNEW(asSScriptVariable); + if (var == 0) + { + // Out of memory + error = true; + func->DestroyHalfCreated(); + return 0; + } + func->scriptData->variables.PushLast(var); + + var->declaredAtProgramPos = ReadEncodedUInt(); + var->stackOffset = ReadEncodedUInt(); + ReadString(&var->name); + ReadDataType(&var->type); + + if (error) + { + // No need to continue (the error has already been reported before) + func->DestroyHalfCreated(); + return 0; + } + } + } + + // Read script section name + if (!noDebugInfo) + { + asCString name; + ReadString(&name); + func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf()); + func->scriptData->declaredAt = ReadEncodedUInt(); + } + + // Read parameter names + if (!noDebugInfo) + { + asUINT countParam = asUINT(ReadEncodedUInt64()); + if (countParam > func->parameterTypes.GetLength()) + { + error = true; + func->DestroyHalfCreated(); + return 0; + } + func->parameterNames.SetLength(countParam); + for (asUINT n = 0; n < countParam; n++) + ReadString(&func->parameterNames[n]); + } + } + } + } + else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) + { + func->vfTableIdx = ReadEncodedUInt(); + } + else if( func->funcType == asFUNC_FUNCDEF ) + { + asBYTE bits; + ReadData(&bits, 1); + if( bits & 1 ) + func->SetShared(true); + if ((bits & 2) && isExternal) + *isExternal = true; + + // The asCFuncdefType constructor adds itself to the func->funcdefType member + asCFuncdefType *fdt = asNEW(asCFuncdefType)(engine, func); + fdt->parentClass = parentClass; + } + + // Methods loaded for shared objects, owned by other modules should not be created as new functions + if( func->objectType && func->objectType->module != module ) + { + // Return the real function from the object + asCScriptFunction *realFunc = 0; + bool found = false; + if( func->funcType == asFUNC_SCRIPT ) + { + realFunc = engine->scriptFunctions[func->objectType->beh.destruct]; + if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) + { + found = true; + } + for( asUINT n = 0; !found && n < func->objectType->beh.constructors.GetLength(); n++ ) + { + realFunc = engine->scriptFunctions[func->objectType->beh.constructors[n]]; + if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) + { + found = true; + break; + } + } + for( asUINT n = 0; !found && n < func->objectType->beh.factories.GetLength(); n++ ) + { + realFunc = engine->scriptFunctions[func->objectType->beh.factories[n]]; + if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) + { + found = true; + break; + } + } + for( asUINT n = 0; !found && n < func->objectType->methods.GetLength(); n++ ) + { + realFunc = engine->scriptFunctions[func->objectType->methods[n]]; + if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) + { + found = true; + break; + } + } + for( asUINT n = 0; !found && n < func->objectType->virtualFunctionTable.GetLength(); n++ ) + { + realFunc = func->objectType->virtualFunctionTable[n]; + if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) + { + found = true; + break; + } + } + } + else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) + { + // If the loaded function is a virtual function, then look for the identical virtual function in the methods array + for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ ) + { + realFunc = engine->scriptFunctions[func->objectType->methods[n]]; + if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) + { + asASSERT( func->vfTableIdx == realFunc->vfTableIdx ); + found = true; + break; + } + } + } + + if( found ) + { + // as this is an existing function it shouldn't be translated as if just loaded + dontTranslate.Insert(realFunc, true); + + // update the saved functions for future references + savedFunctions[savedFunctions.GetLength() - 1] = realFunc; + + if( realFunc->funcType == asFUNC_VIRTUAL && addToModule ) + { + // Virtual methods must be added to the module's script functions array, + // even if they are not owned by the module + module->m_scriptFunctions.PushLast(realFunc); + realFunc->AddRefInternal(); + } + } + else + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, func->objectType->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + + Error(TXT_INVALID_BYTECODE_d); + savedFunctions.PopLast(); + realFunc = 0; + } + + // Destroy the newly created function instance since it has been replaced by an existing function + isNew = false; + func->DestroyHalfCreated(); + + // As it is an existing function it shouldn't be added to the module or the engine + return realFunc; + } + + if( addToModule ) + { + // The refCount is already 1 + module->m_scriptFunctions.PushLast(func); + func->module = module; + } + if( addToEngine ) + { + func->id = engine->GetNextScriptFunctionId(); + engine->AddScriptFunction(func); + } + if( func->objectType ) + func->ComputeSignatureId(); + + return func; } void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExternal) { - if( phase == 1 ) - { - asASSERT(isExternal); - if (isExternal) - *isExternal = false; - - // Read the initial attributes - ReadString(&type->name); - ReadData(&type->flags, 4); - type->size = ReadEncodedUInt(); - asCString ns; - ReadString(&ns); - type->nameSpace = engine->AddNameSpace(ns.AddressOf()); - - // Verify that the flags match the asCTypeInfo - if ((CastToEnumType(type) && !(type->flags & asOBJ_ENUM)) || - (CastToFuncdefType(type) && !(type->flags & asOBJ_FUNCDEF)) || - (CastToObjectType(type) && !(type->flags & (asOBJ_REF | asOBJ_VALUE)))) - { - error = true; - return; - } - - // Reset the size of script classes, since it will be recalculated as properties are added - if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size != 0 ) - type->size = sizeof(asCScriptObject); - - asCObjectType *ot = CastToObjectType(type); - if (ot) - { - // Use the default script class behaviours - ot->beh = engine->scriptTypeBehaviours.beh; - ot->beh.construct = 0; - ot->beh.factory = 0; - ot->beh.constructors.PopLast(); // These will be read from the file - ot->beh.factories.PopLast(); // These will be read from the file - engine->scriptFunctions[ot->beh.addref]->AddRefInternal(); - engine->scriptFunctions[ot->beh.release]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal(); - engine->scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal(); - engine->scriptFunctions[ot->beh.copy]->AddRefInternal(); - // TODO: weak: Should not do this if the class has been declared with 'noweak' - engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); - } - - // external shared flag - if (type->flags & asOBJ_SHARED) - { - char c; - ReadData(&c, 1); - if (c == 'e') - *isExternal = true; - else if (c != ' ') - { - error = true; - return; - } - } - } - else if( phase == 2 ) - { - // external shared types doesn't store this - if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) - return; - - if( type->flags & asOBJ_ENUM ) - { - asCEnumType *t = CastToEnumType(type); - int count = ReadEncodedUInt(); - bool sharedExists = existingShared.MoveTo(0, type); - if( !sharedExists ) - { - t->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 - t->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 < t->enumValues.GetLength(); e++ ) - { - if( t->enumValues[e]->name == name && - t->enumValues[e]->value == value ) - { - found = true; - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - } - } - } - else if( type->flags & asOBJ_TYPEDEF ) - { - asCTypedefType *td = CastToTypedefType(type); - asASSERT(td); - eTokenType t = (eTokenType)ReadEncodedUInt(); - td->aliasForType = asCDataType::CreatePrimitive(t, false); - } - else - { - asCObjectType *ot = CastToObjectType(type); - asASSERT(ot); - - // If the type is shared and pre-existing, we should just - // validate that the loaded methods match the original - bool sharedExists = existingShared.MoveTo(0, type); - if( sharedExists ) - { - asCObjectType *dt = CastToObjectType(ReadTypeInfo()); - if( ot->derivedFrom != dt ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - } - else - { - ot->derivedFrom = CastToObjectType(ReadTypeInfo()); - if( ot->derivedFrom ) - ot->derivedFrom->AddRefInternal(); - } - - // interfaces[] / interfaceVFTOffsets[] - int size = ReadEncodedUInt(); - if( sharedExists ) - { - for( int n = 0; n < size; n++ ) - { - asCObjectType *intf = CastToObjectType(ReadTypeInfo()); - if (!ot->IsInterface()) - ReadEncodedUInt(); - - if( !type->Implements(intf) ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - } - } - else - { - ot->interfaces.Allocate(size, false); - if( !ot->IsInterface() ) - ot->interfaceVFTOffsets.Allocate(size, false); - for( int n = 0; n < size; n++ ) - { - asCObjectType *intf = CastToObjectType(ReadTypeInfo()); - ot->interfaces.PushLast(intf); - - if (!ot->IsInterface()) - { - asUINT offset = ReadEncodedUInt(); - ot->interfaceVFTOffsets.PushLast(offset); - } - } - } - - // behaviours - if( !ot->IsInterface() && type->flags != asOBJ_TYPEDEF && type->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, type->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->ReleaseInternal(); - } - dontTranslate.Insert(realFunc, true); - } - } - else - { - if( func ) - { - ot->beh.destruct = func->id; - func->AddRefInternal(); - } - else - ot->beh.destruct = 0; - } - - size = ReadEncodedUInt(); - for( int n = 0; n < size; n++ ) - { - 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 f = 0; f < ot->beh.constructors.GetLength(); f++ ) - { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[f]); - if( realFunc->IsSignatureEqual(func) ) - { - // If the function is not the last, then the substitution has already occurred before - if( savedFunctions[savedFunctions.GetLength()-1] == func ) - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - found = true; - dontTranslate.Insert(realFunc, true); - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->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->ReleaseInternal(); - } - } - else - { - ot->beh.constructors.PushLast(func->id); - func->AddRefInternal(); - - 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 f = 0; f < ot->beh.factories.GetLength(); f++ ) - { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[f]); - if( realFunc->IsSignatureEqual(func) ) - { - // If the function is not the last, then the substitution has already occurred before - if( savedFunctions[savedFunctions.GetLength()-1] == func ) - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - found = true; - dontTranslate.Insert(realFunc, true); - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->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->ReleaseInternal(); - } - } - else - { - ot->beh.factories.PushLast(func->id); - func->AddRefInternal(); - - 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 f = 0; f < ot->methods.GetLength(); f++ ) - { - asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[f]); - if( realFunc->IsSignatureEqual(func) ) - { - // If the function is not the last, then the substitution has already occurred before - if( savedFunctions[savedFunctions.GetLength()-1] == func ) - savedFunctions[savedFunctions.GetLength()-1] = realFunc; - found = true; - dontTranslate.Insert(realFunc, true); - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - } - if( isNew ) - { - // Destroy the function without releasing any references - if( func->id == func->signatureId ) - engine->signatureIds.RemoveValue(func); - func->id = 0; - if( func->scriptData ) - func->scriptData->byteCode.SetLength(0); - func->ReleaseInternal(); - } - } - 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].GetTypeInfo() == func->objectType && - (func->inOutFlags[0] & asTM_INREF) ) - { - engine->scriptFunctions[ot->beh.copy]->ReleaseInternal(); - ot->beh.copy = func->id; - func->AddRefInternal(); - } - - ot->methods.PushLast(func->id); - func->AddRefInternal(); - } - } - 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 f = 0; f < ot->virtualFunctionTable.GetLength(); f++ ) - { - asCScriptFunction *realFunc = ot->virtualFunctionTable[f]; - 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; - dontTranslate.Insert(realFunc, true); - break; - } - } - if( !found ) - { - asCString str; - str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->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->ReleaseInternal(); - } - } - else - { - ot->virtualFunctionTable.PushLast(func); - func->AddRefInternal(); - } - } - else - { - Error(TXT_INVALID_BYTECODE_d); - } - } - } - } - else if( phase == 3 ) - { - // external shared types doesn't store this - if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) - return; - - asCObjectType *ot = CastToObjectType(type); - - // This is only done for object types - asASSERT(ot); - - // properties[] - asUINT size = ReadEncodedUInt(); - for( asUINT n = 0; n < size; n++ ) - ReadObjectProperty(ot); - } + if( phase == 1 ) + { + asASSERT(isExternal); + if (isExternal) + *isExternal = false; + + // Read the initial attributes + ReadString(&type->name); + ReadData(&type->flags, 4); + type->size = ReadEncodedUInt(); + asCString ns; + ReadString(&ns); + type->nameSpace = engine->AddNameSpace(ns.AddressOf()); + + // Verify that the flags match the asCTypeInfo + if ((CastToEnumType(type) && !(type->flags & asOBJ_ENUM)) || + (CastToFuncdefType(type) && !(type->flags & asOBJ_FUNCDEF)) || + (CastToObjectType(type) && !(type->flags & (asOBJ_REF | asOBJ_VALUE)))) + { + error = true; + return; + } + + // Reset the size of script classes, since it will be recalculated as properties are added + if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size != 0 ) + type->size = sizeof(asCScriptObject); + + asCObjectType *ot = CastToObjectType(type); + if (ot) + { + // Use the default script class behaviours + ot->beh = engine->scriptTypeBehaviours.beh; + ot->beh.construct = 0; + ot->beh.factory = 0; + ot->beh.constructors.PopLast(); // These will be read from the file + ot->beh.factories.PopLast(); // These will be read from the file + engine->scriptFunctions[ot->beh.addref]->AddRefInternal(); + engine->scriptFunctions[ot->beh.release]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal(); + engine->scriptFunctions[ot->beh.copy]->AddRefInternal(); + // TODO: weak: Should not do this if the class has been declared with 'noweak' + engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); + } + + // external shared flag + if (type->flags & asOBJ_SHARED) + { + char c; + ReadData(&c, 1); + if (c == 'e') + *isExternal = true; + else if (c != ' ') + { + error = true; + return; + } + } + } + else if( phase == 2 ) + { + // external shared types doesn't store this + if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) + return; + + if( type->flags & asOBJ_ENUM ) + { + asCEnumType *t = CastToEnumType(type); + int count = ReadEncodedUInt(); + bool sharedExists = existingShared.MoveTo(0, type); + if( !sharedExists ) + { + t->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 + t->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 < t->enumValues.GetLength(); e++ ) + { + if( t->enumValues[e]->name == name && + t->enumValues[e]->value == value ) + { + found = true; + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + } + } + } + else if( type->flags & asOBJ_TYPEDEF ) + { + asCTypedefType *td = CastToTypedefType(type); + asASSERT(td); + eTokenType t = (eTokenType)ReadEncodedUInt(); + td->aliasForType = asCDataType::CreatePrimitive(t, false); + } + else + { + asCObjectType *ot = CastToObjectType(type); + asASSERT(ot); + + // If the type is shared and pre-existing, we should just + // validate that the loaded methods match the original + bool sharedExists = existingShared.MoveTo(0, type); + if( sharedExists ) + { + asCObjectType *dt = CastToObjectType(ReadTypeInfo()); + if( ot->derivedFrom != dt ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + } + else + { + ot->derivedFrom = CastToObjectType(ReadTypeInfo()); + if( ot->derivedFrom ) + ot->derivedFrom->AddRefInternal(); + } + + // interfaces[] / interfaceVFTOffsets[] + int size = ReadEncodedUInt(); + if( sharedExists ) + { + for( int n = 0; n < size; n++ ) + { + asCObjectType *intf = CastToObjectType(ReadTypeInfo()); + if (!ot->IsInterface()) + ReadEncodedUInt(); + + if( !type->Implements(intf) ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + } + } + else + { + ot->interfaces.Allocate(size, false); + if( !ot->IsInterface() ) + ot->interfaceVFTOffsets.Allocate(size, false); + for( int n = 0; n < size; n++ ) + { + asCObjectType *intf = CastToObjectType(ReadTypeInfo()); + ot->interfaces.PushLast(intf); + + if (!ot->IsInterface()) + { + asUINT offset = ReadEncodedUInt(); + ot->interfaceVFTOffsets.PushLast(offset); + } + } + } + + // behaviours + if( !ot->IsInterface() && type->flags != asOBJ_TYPEDEF && type->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, type->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->ReleaseInternal(); + } + dontTranslate.Insert(realFunc, true); + } + } + else + { + if( func ) + { + ot->beh.destruct = func->id; + func->AddRefInternal(); + } + else + ot->beh.destruct = 0; + } + + size = ReadEncodedUInt(); + for( int n = 0; n < size; n++ ) + { + 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 f = 0; f < ot->beh.constructors.GetLength(); f++ ) + { + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[f]); + if( realFunc->IsSignatureEqual(func) ) + { + // If the function is not the last, then the substitution has already occurred before + if( savedFunctions[savedFunctions.GetLength()-1] == func ) + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + found = true; + dontTranslate.Insert(realFunc, true); + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->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->ReleaseInternal(); + } + } + else + { + ot->beh.constructors.PushLast(func->id); + func->AddRefInternal(); + + 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 f = 0; f < ot->beh.factories.GetLength(); f++ ) + { + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[f]); + if( realFunc->IsSignatureEqual(func) ) + { + // If the function is not the last, then the substitution has already occurred before + if( savedFunctions[savedFunctions.GetLength()-1] == func ) + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + found = true; + dontTranslate.Insert(realFunc, true); + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->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->ReleaseInternal(); + } + } + else + { + ot->beh.factories.PushLast(func->id); + func->AddRefInternal(); + + 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 f = 0; f < ot->methods.GetLength(); f++ ) + { + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[f]); + if( realFunc->IsSignatureEqual(func) ) + { + // If the function is not the last, then the substitution has already occurred before + if( savedFunctions[savedFunctions.GetLength()-1] == func ) + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + found = true; + dontTranslate.Insert(realFunc, true); + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + if( isNew ) + { + // Destroy the function without releasing any references + if( func->id == func->signatureId ) + engine->signatureIds.RemoveValue(func); + func->id = 0; + if( func->scriptData ) + func->scriptData->byteCode.SetLength(0); + func->ReleaseInternal(); + } + } + 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].GetTypeInfo() == func->objectType && + (func->inOutFlags[0] & asTM_INREF) ) + { + engine->scriptFunctions[ot->beh.copy]->ReleaseInternal(); + ot->beh.copy = func->id; + func->AddRefInternal(); + } + + ot->methods.PushLast(func->id); + func->AddRefInternal(); + } + } + 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 f = 0; f < ot->virtualFunctionTable.GetLength(); f++ ) + { + asCScriptFunction *realFunc = ot->virtualFunctionTable[f]; + 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; + dontTranslate.Insert(realFunc, true); + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->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->ReleaseInternal(); + } + } + else + { + ot->virtualFunctionTable.PushLast(func); + func->AddRefInternal(); + } + } + else + { + Error(TXT_INVALID_BYTECODE_d); + } + } + } + } + else if( phase == 3 ) + { + // external shared types doesn't store this + if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) + return; + + asCObjectType *ot = CastToObjectType(type); + + // This is only done for object types + asASSERT(ot); + + // properties[] + asUINT size = ReadEncodedUInt(); + for( asUINT n = 0; n < size; n++ ) + ReadObjectProperty(ot); + } } asWORD asCReader::ReadEncodedUInt16() { - asDWORD dw = ReadEncodedUInt(); - if( (dw>>16) != 0 && (dw>>16) != 0xFFFF ) - { - Error(TXT_INVALID_BYTECODE_d); - } + asDWORD dw = ReadEncodedUInt(); + if( (dw>>16) != 0 && (dw>>16) != 0xFFFF ) + { + Error(TXT_INVALID_BYTECODE_d); + } - return asWORD(dw & 0xFFFF); + return asWORD(dw & 0xFFFF); } asUINT asCReader::ReadEncodedUInt() { - asQWORD qw = ReadEncodedUInt64(); - if( (qw>>32) != 0 && (qw>>32) != 0xFFFFFFFF ) - { - Error(TXT_INVALID_BYTECODE_d); - } + asQWORD qw = ReadEncodedUInt64(); + if( (qw>>32) != 0 && (qw>>32) != 0xFFFFFFFF ) + { + Error(TXT_INVALID_BYTECODE_d); + } - return asUINT(qw & 0xFFFFFFFFu); + 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; + 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) { - asUINT len = ReadEncodedUInt(); - if( len & 1 ) - { - asUINT idx = len/2; - if( idx < savedStrings.GetLength() ) - *str = savedStrings[idx]; - else - Error(TXT_INVALID_BYTECODE_d); - } - else if( len > 0 ) - { - len /= 2; - str->SetLength(len); - int r = stream->Read(str->AddressOf(), len); - if (r < 0) - Error(TXT_UNEXPECTED_END_OF_FILE); - - savedStrings.PushLast(*str); - } - else - str->SetLength(0); + asUINT len = ReadEncodedUInt(); + if( len & 1 ) + { + asUINT idx = len/2; + if( idx < savedStrings.GetLength() ) + *str = savedStrings[idx]; + else + Error(TXT_INVALID_BYTECODE_d); + } + else if( len > 0 ) + { + len /= 2; + str->SetLength(len); + int r = stream->Read(str->AddressOf(), len); + if (r < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); + + savedStrings.PushLast(*str); + } + else + str->SetLength(0); } void asCReader::ReadGlobalProperty() { - asCString name; - asCDataType type; + asCString name; + asCDataType type; - ReadString(&name); + ReadString(&name); - asCString ns; - ReadString(&ns); - asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); + asCString ns; + ReadString(&ns); + asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); - ReadDataType(&type); + ReadDataType(&type); - asCGlobalProperty *prop = module->AllocateGlobalProperty(name.AddressOf(), type, nameSpace); + 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; + // 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->ReleaseInternal(); - } + prop->SetInitFunc(func); + func->ReleaseInternal(); + } } void asCReader::ReadObjectProperty(asCObjectType *ot) { - asCString name; - ReadString(&name); - asCDataType dt; - ReadDataType(&dt); - int flags = ReadEncodedUInt(); - bool isPrivate = (flags & 1) ? true : false; - bool isProtected = (flags & 2) ? true : false; - bool isInherited = (flags & 4) ? true : false; - - // TODO: shared: If the type is shared and pre-existing, we should just - // validate that the loaded methods match the original - if( !existingShared.MoveTo(0, ot) ) - ot->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); + asCString name; + ReadString(&name); + asCDataType dt; + ReadDataType(&dt); + int flags = ReadEncodedUInt(); + bool isPrivate = (flags & 1) ? true : false; + bool isProtected = (flags & 2) ? true : false; + bool isInherited = (flags & 4) ? true : false; + + // TODO: shared: If the type is shared and pre-existing, we should just + // validate that the loaded methods match the original + if( !existingShared.MoveTo(0, ot) ) + ot->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); } void asCReader::ReadDataType(asCDataType *dt) { - // Check if this is a previously used type - asUINT idx = ReadEncodedUInt(); - if( idx != 0 ) - { - // Get the datatype from the cache - *dt = savedDataTypes[idx-1]; - return; - } - - // Read the type definition - eTokenType tokenType = (eTokenType)ReadEncodedUInt(); - - // Reserve a spot in the savedDataTypes - asUINT saveSlot = savedDataTypes.GetLength(); - savedDataTypes.PushLast(asCDataType()); - - // Read the datatype for the first time - asCTypeInfo *ti = 0; - if( tokenType == ttIdentifier ) - ti = ReadTypeInfo(); - - // Read type flags as a bitmask - // Endian-safe code - bool isObjectHandle, isHandleToConst, isReference, isReadOnly; - char b = 0; - ReadData(&b, 1); - LOAD_FROM_BIT(isObjectHandle, b, 0); - LOAD_FROM_BIT(isHandleToConst, b, 1); - LOAD_FROM_BIT(isReference, b, 2); - LOAD_FROM_BIT(isReadOnly, b, 3); - - if( tokenType == ttIdentifier ) - *dt = asCDataType::CreateType(ti, false); - else - *dt = asCDataType::CreatePrimitive(tokenType, false); - if( isObjectHandle ) - { - dt->MakeReadOnly(isHandleToConst ? true : false); - - // Here we must allow a scoped type to be a handle - // e.g. if the datatype is for a system function - dt->MakeHandle(true, true); - } - dt->MakeReadOnly(isReadOnly ? true : false); - dt->MakeReference(isReference ? true : false); - - // Update the previously saved slot - savedDataTypes[saveSlot] = *dt; + // Check if this is a previously used type + asUINT idx = ReadEncodedUInt(); + if( idx != 0 ) + { + // Get the datatype from the cache + *dt = savedDataTypes[idx-1]; + return; + } + + // Read the type definition + eTokenType tokenType = (eTokenType)ReadEncodedUInt(); + + // Reserve a spot in the savedDataTypes + asUINT saveSlot = savedDataTypes.GetLength(); + savedDataTypes.PushLast(asCDataType()); + + // Read the datatype for the first time + asCTypeInfo *ti = 0; + if( tokenType == ttIdentifier ) + ti = ReadTypeInfo(); + + // Read type flags as a bitmask + // Endian-safe code + bool isObjectHandle, isHandleToConst, isReference, isReadOnly; + char b = 0; + ReadData(&b, 1); + LOAD_FROM_BIT(isObjectHandle, b, 0); + LOAD_FROM_BIT(isHandleToConst, b, 1); + LOAD_FROM_BIT(isReference, b, 2); + LOAD_FROM_BIT(isReadOnly, b, 3); + + if( tokenType == ttIdentifier ) + *dt = asCDataType::CreateType(ti, false); + else + *dt = asCDataType::CreatePrimitive(tokenType, false); + if( isObjectHandle ) + { + dt->MakeReadOnly(isHandleToConst ? true : false); + + // Here we must allow a scoped type to be a handle + // e.g. if the datatype is for a system function + dt->MakeHandle(true, true); + } + dt->MakeReadOnly(isReadOnly ? true : false); + dt->MakeReference(isReference ? true : false); + + // Update the previously saved slot + savedDataTypes[saveSlot] = *dt; } asCTypeInfo* asCReader::ReadTypeInfo() { - asCTypeInfo *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()); - - asCTypeInfo *tmp = engine->GetRegisteredType(typeName.AddressOf(), nameSpace); - asCObjectType *tmpl = CastToObjectType(tmp); - 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, module); - } - - if( ot == 0 ) - { - // Show all subtypes in error message - asCString sub = subTypes[0].Format(nameSpace); - for( asUINT n = 1; n < subTypes.GetLength(); n++ ) - { - sub += ","; - sub += subTypes[n].Format(nameSpace); - } - 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 = CastToObjectType(ReadTypeInfo()); - 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 != "$obj" && typeName != "$func" ) - { - // Find the object type - ot = module->GetType(typeName.AddressOf(), nameSpace); - if (!ot) - ot = engine->GetRegisteredType(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 == "$obj" ) - { - ot = &engine->scriptTypeBehaviours; - } - else if( typeName == "$func" ) - { - ot = &engine->functionBehaviours; - } - else - asASSERT( false ); - } - else if (ch == 'c') - { - // Read the object type name - asCString typeName, ns; - ReadString(&typeName); - - // Read the parent class - asCObjectType *parentClass = CastToObjectType(ReadTypeInfo()); - if (parentClass == 0) - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - // Find the child type in the parentClass - for (asUINT n = 0; n < parentClass->childFuncDefs.GetLength(); n++) - { - if (parentClass->childFuncDefs[n]->name == typeName) - ot = parentClass->childFuncDefs[n]; - } - - if (ot == 0) - { - asCString str; - str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf()); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - } - else - { - // No object type - asASSERT( ch == '\0' || error ); - ot = 0; - } - - return ot; + asCTypeInfo *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()); + + asCTypeInfo *tmp = engine->GetRegisteredType(typeName.AddressOf(), nameSpace); + asCObjectType *tmpl = CastToObjectType(tmp); + 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, module); + } + + if( ot == 0 ) + { + // Show all subtypes in error message + asCString sub = subTypes[0].Format(nameSpace); + for( asUINT n = 1; n < subTypes.GetLength(); n++ ) + { + sub += ","; + sub += subTypes[n].Format(nameSpace); + } + 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 = CastToObjectType(ReadTypeInfo()); + 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 != "$obj" && typeName != "$func" ) + { + // Find the object type + ot = module->GetType(typeName.AddressOf(), nameSpace); + if (!ot) + ot = engine->GetRegisteredType(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 == "$obj" ) + { + ot = &engine->scriptTypeBehaviours; + } + else if( typeName == "$func" ) + { + ot = &engine->functionBehaviours; + } + else + asASSERT( false ); + } + else if (ch == 'c') + { + // Read the object type name + asCString typeName, ns; + ReadString(&typeName); + + // Read the parent class + asCObjectType *parentClass = CastToObjectType(ReadTypeInfo()); + if (parentClass == 0) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + // Find the child type in the parentClass + for (asUINT n = 0; n < parentClass->childFuncDefs.GetLength(); n++) + { + if (parentClass->childFuncDefs[n]->name == typeName) + ot = parentClass->childFuncDefs[n]; + } + + if (ot == 0) + { + asCString str; + str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + } + else + { + // No object type + 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; + 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; + 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; + 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; + *bc++ = c; + c = *(asBYTE*)&c; - // Read the bc as is - for( int n = 1; n < asBCTypeSize[asBCInfo[c].type]; n++ ) - ReadData(&*bc++, 4); - } - } + // Read the bc as is + for( int n = 1; n < asBCTypeSize[asBCInfo[c].type]; n++ ) + ReadData(&*bc++, 4); + } + } - numInstructions--; - } + numInstructions--; + } - // Correct the final size in case we over-estimated it - func->scriptData->byteCode.SetLengthNoConstruct(pos); + // Correct the final size in case we over-estimated it + func->scriptData->byteCode.SetLengthNoConstruct(pos); } void asCReader::ReadUsedTypeIds() { - TimeIt("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)); - } + TimeIt("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() { - TimeIt("asCReader::ReadUsedGlobalProps"); + TimeIt("asCReader::ReadUsedGlobalProps"); - int c = ReadEncodedUInt(); + int c = ReadEncodedUInt(); - usedGlobalProperties.Allocate(c, false); + usedGlobalProperties.Allocate(c, false); - for( int n = 0; n < c; n++ ) - { - asCString name, ns; - asCDataType type; - char moduleProp; + for( int n = 0; n < c; n++ ) + { + asCString name, ns; + asCDataType type; + char moduleProp; - ReadString(&name); - ReadString(&ns); - ReadDataType(&type); - ReadData(&moduleProp, 1); + ReadString(&name); + ReadString(&ns); + ReadDataType(&type); + ReadData(&moduleProp, 1); - asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); + asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); - // Find the real property - asCGlobalProperty *globProp = 0; - if( moduleProp ) - globProp = module->m_scriptGlobals.GetFirst(nameSpace, name); - else - globProp = engine->registeredGlobalProps.GetFirst(nameSpace, name); + // Find the real property + asCGlobalProperty *globProp = 0; + if( moduleProp ) + globProp = module->m_scriptGlobals.GetFirst(nameSpace, name); + else + globProp = engine->registeredGlobalProps.GetFirst(nameSpace, name); - void *prop = 0; - if( globProp && globProp->type == type ) - prop = globProp->GetAddressOfValue(); + void *prop = 0; + if( globProp && globProp->type == type ) + prop = globProp->GetAddressOfValue(); - usedGlobalProperties.PushLast(prop); + usedGlobalProperties.PushLast(prop); - if( prop == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - } - } + if( prop == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + } + } } void asCReader::ReadUsedObjectProps() { - TimeIt("asCReader::ReadUsedObjectProps"); - - asUINT c = ReadEncodedUInt(); - - usedObjectProperties.SetLength(c); - for( asUINT n = 0; n < c; n++ ) - { - asCObjectType *objType = CastToObjectType(ReadTypeInfo()); - if( objType == 0 ) - { - Error(TXT_INVALID_BYTECODE_d); - break; - } - - asCString name; - ReadString(&name); - - // Find the property - bool found = false; - for( asUINT p = 0; p < objType->properties.GetLength(); p++ ) - { - if( objType->properties[p]->name == name ) - { - usedObjectProperties[n].objType = objType; - usedObjectProperties[n].prop = objType->properties[p]; - found = true; - break; - } - } - - if( !found ) - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } + TimeIt("asCReader::ReadUsedObjectProps"); + + asUINT c = ReadEncodedUInt(); + + usedObjectProperties.SetLength(c); + for( asUINT n = 0; n < c; n++ ) + { + asCObjectType *objType = CastToObjectType(ReadTypeInfo()); + if( objType == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + break; + } + + asCString name; + ReadString(&name); + + // Find the property + bool found = false; + for( asUINT p = 0; p < objType->properties.GetLength(); p++ ) + { + if( objType->properties[p]->name == name ) + { + usedObjectProperties[n].objType = objType; + usedObjectProperties[n].prop = objType->properties[p]; + found = true; + break; + } + } + + if( !found ) + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } } short asCReader::FindObjectPropOffset(asWORD index) { - static asCObjectProperty *lastCompositeProp = 0; - if (lastCompositeProp) - { - if (index != 0) - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - short offset = (short)lastCompositeProp->byteOffset; - lastCompositeProp = 0; - return offset; - } - - if( index >= usedObjectProperties.GetLength() ) - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } - - if (usedObjectProperties[index].prop->compositeOffset || usedObjectProperties[index].prop->isCompositeIndirect) - { - lastCompositeProp = usedObjectProperties[index].prop; - return (short)lastCompositeProp->compositeOffset; - } - return (short)usedObjectProperties[index].prop->byteOffset; + static asCObjectProperty *lastCompositeProp = 0; + if (lastCompositeProp) + { + if (index != 0) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + short offset = (short)lastCompositeProp->byteOffset; + lastCompositeProp = 0; + return offset; + } + + if( index >= usedObjectProperties.GetLength() ) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + if (usedObjectProperties[index].prop->compositeOffset || usedObjectProperties[index].prop->isCompositeIndirect) + { + lastCompositeProp = usedObjectProperties[index].prop; + return (short)lastCompositeProp->compositeOffset; + } + return (short)usedObjectProperties[index].prop->byteOffset; } asCScriptFunction *asCReader::FindFunction(int idx) { - if( idx >= 0 && idx < (int)usedFunctions.GetLength() ) - return usedFunctions[idx]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } + 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 = CastToObjectType(FindType(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 || - c == asBC_Thiscall1 ) - { - // 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 = CastToObjectType(FindType(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 ) - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - else if( c == asBC_CALLBND ) - { - // Translate the function id - asUINT *fid = (asUINT*)&bc[n+1]; - if( *fid < module->m_bindInformations.GetLength() ) - { - sBindInfo *bi = module->m_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 index to pointer - asPWORD *index = (asPWORD*)&bc[n + 1]; - if ((*index & 1)) - { - if ((asUINT(*index)>>1) < usedGlobalProperties.GetLength()) - *(void**)index = usedGlobalProperties[asUINT(*index)>>1]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - else - { - // Only PGA and PshGPtr can hold string constants - asASSERT(c == asBC_PGA || c == asBC_PshGPtr); - - if ((asUINT(*index)>>1) < usedStringConstants.GetLength()) - *(void**)index = usedStringConstants[asUINT(*index)>>1]; - else - { - Error(TXT_INVALID_BYTECODE_d); - return; - } - } - } - else if( c == asBC_JMP || - 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 = CastToObjectType(func->GetTypeInfoOfLocalVar(asBC_SWORDARG0(&bc[n]))); - listAdjusters.PushLast(asNEW(SListAdjuster)(this, &bc[n], ot)); - } - else if( c == asBC_FREE ) - { - // Translate the index to the true object type - asPWORD *pot = (asPWORD*)&bc[n+1]; - *(asCObjectType**)pot = CastToObjectType(FindType(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]); - - // 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 || - c == asBC_ChkNullS ) - { - 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); - } - - for (n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++) - { - func->scriptData->tryCatchInfo[n].tryPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].tryPos]; - func->scriptData->tryCatchInfo[n].catchPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].catchPos]; - } - - // The program position (every even number) needs to be adjusted - // for the line numbers to be in number of dwords instead of number of instructions - for( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 ) - 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); + // 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 = CastToObjectType(FindType(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 || + c == asBC_Thiscall1 ) + { + // 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 = CastToObjectType(FindType(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 ) + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + else if( c == asBC_CALLBND ) + { + // Translate the function id + asUINT *fid = (asUINT*)&bc[n+1]; + if( *fid < module->m_bindInformations.GetLength() ) + { + sBindInfo *bi = module->m_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 index to pointer + asPWORD *index = (asPWORD*)&bc[n + 1]; + if ((*index & 1)) + { + if ((asUINT(*index)>>1) < usedGlobalProperties.GetLength()) + *(void**)index = usedGlobalProperties[asUINT(*index)>>1]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + else + { + // Only PGA and PshGPtr can hold string constants + asASSERT(c == asBC_PGA || c == asBC_PshGPtr); + + if ((asUINT(*index)>>1) < usedStringConstants.GetLength()) + *(void**)index = usedStringConstants[asUINT(*index)>>1]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + } + else if( c == asBC_JMP || + 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 = CastToObjectType(func->GetTypeInfoOfLocalVar(asBC_SWORDARG0(&bc[n]))); + listAdjusters.PushLast(asNEW(SListAdjuster)(this, &bc[n], ot)); + } + else if( c == asBC_FREE ) + { + // Translate the index to the true object type + asPWORD *pot = (asPWORD*)&bc[n+1]; + *(asCObjectType**)pot = CastToObjectType(FindType(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]); + + // 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 || + c == asBC_ChkNullS ) + { + 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); + } + + for (n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++) + { + func->scriptData->tryCatchInfo[n].tryPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].tryPos]; + func->scriptData->tryCatchInfo[n].catchPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].catchPos]; + } + + // The program position (every even number) needs to be adjusted + // for the line numbers to be in number of dwords instead of number of instructions + for( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 ) + 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) + reader(rd), allocMemBC(bc), maxOffset(0), patternType(listType), repeatCount(0), lastOffset(-1), nextOffset(0), nextTypeId(-1) { - asASSERT( patternType && (patternType->flags & asOBJ_LIST_PATTERN) ); + 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; + // 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 nextdt = patternType->engine->GetDataTypeFromTypeId(nextTypeId); - asUINT size; - if(nextdt.IsObjectHandle() || (nextdt.GetTypeInfo() && (nextdt.GetTypeInfo()->flags & asOBJ_REF)) ) - size = AS_PTR_SIZE*4; - else - size = nextdt.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; - if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->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; + 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 nextdt = patternType->engine->GetDataTypeFromTypeId(nextTypeId); + asUINT size; + if(nextdt.IsObjectHandle() || (nextdt.GetTypeInfo() && (nextdt.GetTypeInfo()->flags & asOBJ_REF)) ) + size = AS_PTR_SIZE*4; + else + size = nextdt.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; + if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->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 ); + // 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; + // Now move to the next patternNode + patternNode = patternNode->next; - repeatCount = rc; + repeatCount = rc; } void asCReader::SListAdjuster::AdjustAllocMem() { - allocMemBC[1] = maxOffset; + allocMemBC[1] = maxOffset; } void asCReader::SListAdjuster::SetNextType(int typeId) { - asASSERT( nextTypeId == -1 ); + asASSERT( nextTypeId == -1 ); - nextTypeId = typeId; + 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_Thiscall1 || - 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; + 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_Thiscall1 || + 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++ ) - { - // Determine the size the variable currently occupies on the stack - int size = AS_PTR_SIZE; - - // objVariableTypes is null if the type is a null pointer - if( func->scriptData->objVariableTypes[n] && - (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && - n >= func->scriptData->objVariablesOnHeap ) - { - 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; - } + // 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++ ) + { + // Determine the size the variable currently occupies on the stack + int size = AS_PTR_SIZE; + + // objVariableTypes is null if the type is a null pointer + if( func->scriptData->objVariableTypes[n] && + (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && + n >= func->scriptData->objVariablesOnHeap ) + { + 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; + 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_Thiscall1 || - 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 CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef; - - // 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) - { - if (func->parameterTypes[v].IsFuncdef()) - return CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef; - else - { - error = true; - return 0; - } - } - paramPos -= func->parameterTypes[v].GetSizeOnStackDWords(); - } - } - - return 0; + asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[programPos]; + + if( bc == asBC_CALL || + bc == asBC_CALLSYS || + bc == asBC_Thiscall1 || + 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 CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef; + + // 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) + { + if (func->parameterTypes[v].IsFuncdef()) + return CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef; + else + { + error = true; + return 0; + } + } + 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; - - bool bcAlloc = false; - - // Find out which function that will be called - asCScriptFunction *calledFunc = 0; - int stackDelta = 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_Thiscall1 || - bc == asBC_CALLINTF || - bc == asBC_ALLOC || - bc == asBC_CALLBND || - bc == asBC_CallPtr ) - { - // The alloc instruction allocates the object memory - // so it doesn't take the this pointer as input - if (bc == asBC_ALLOC) - bcAlloc = true; - - calledFunc = GetCalledFunction(func, n); - break; - } - 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); - } - - // Keep track of the stack size between the - // instruction that needs to be adjusted and the call - stackDelta += asBCInfo[bc].stackInc; - - 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 = -stackDelta; - if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc ) - { - currOffset++; - if( currOffset > 0 ) - numPtrs++; + // 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; + + bool bcAlloc = false; + + // Find out which function that will be called + asCScriptFunction *calledFunc = 0; + int stackDelta = 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_Thiscall1 || + bc == asBC_CALLINTF || + bc == asBC_ALLOC || + bc == asBC_CALLBND || + bc == asBC_CallPtr ) + { + // The alloc instruction allocates the object memory + // so it doesn't take the this pointer as input + if (bc == asBC_ALLOC) + bcAlloc = true; + + calledFunc = GetCalledFunction(func, n); + break; + } + 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); + } + + // Keep track of the stack size between the + // instruction that needs to be adjusted and the call + stackDelta += asBCInfo[bc].stackInc; + + 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 = -stackDelta; + if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc ) + { + currOffset++; + if( currOffset > 0 ) + numPtrs++; #if AS_PTR_SIZE == 2 - // For 64bit platforms it is necessary to increment the currOffset by one more - // DWORD since the stackDelta was counting the full 64bit size of the pointer - else if( stackDelta ) - currOffset++; + // For 64bit platforms it is necessary to increment the currOffset by one more + // DWORD since the stackDelta was counting the full 64bit size of the pointer + else if( stackDelta ) + currOffset++; #endif - } - if( offset > currOffset && calledFunc->DoesReturnOnStack() ) - { - currOffset++; - if( currOffset > 0 ) - numPtrs++; + } + if( offset > currOffset && calledFunc->DoesReturnOnStack() ) + { + currOffset++; + if( currOffset > 0 ) + numPtrs++; #if AS_PTR_SIZE == 2 - // For 64bit platforms it is necessary to increment the currOffset by one more - // DWORD since the stackDelta was counting the full 64bit size of the pointer - else if( stackDelta ) - currOffset++; + // For 64bit platforms it is necessary to increment the currOffset by one more + // DWORD since the stackDelta was counting the full 64bit size of the pointer + else if( stackDelta ) + currOffset++; #endif - } - for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ ) - { - if( offset <= currOffset ) break; - - if( !calledFunc->parameterTypes[p].IsPrimitive() || - calledFunc->parameterTypes[p].IsReference() ) - { - currOffset++; - if( currOffset > 0 ) - numPtrs++; + } + for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ ) + { + if( offset <= currOffset ) break; + + if( !calledFunc->parameterTypes[p].IsPrimitive() || + calledFunc->parameterTypes[p].IsReference() ) + { + currOffset++; + if( currOffset > 0 ) + numPtrs++; #if AS_PTR_SIZE == 2 - // For 64bit platforms it is necessary to increment the currOffset by one more - // DWORD since the stackDelta was counting the full 64bit size of the pointer - else if( stackDelta ) - currOffset++; + // For 64bit platforms it is necessary to increment the currOffset by one more + // DWORD since the stackDelta was counting the full 64bit size of the pointer + else if( stackDelta ) + currOffset++; #endif - // 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); + // 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; - } + if( idx >= 0 && idx < (int)usedTypeIds.GetLength() ) + return usedTypeIds[idx]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } } asCTypeInfo *asCReader::FindType(int idx) { - if( idx < 0 || idx >= (int)usedTypes.GetLength() ) - { - Error(TXT_INVALID_BYTECODE_d); - return 0; - } + if( idx < 0 || idx >= (int)usedTypes.GetLength() ) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } - return usedTypes[idx]; + 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), error(false), bytesWritten(0) + : module(_module), stream(_stream), engine(_engine), stripDebugInfo(_stripDebug), error(false), bytesWritten(0) { } int asCWriter::Error(const char *msg) { - // Don't write if it has already been reported an error earlier - if (!error) - { - asCString str; - str.Format(msg, bytesWritten); - engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - error = true; - } - - return asERROR; + // Don't write if it has already been reported an error earlier + if (!error) + { + asCString str; + str.Format(msg, bytesWritten); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + error = true; + } + + return asERROR; } int asCWriter::WriteData(const void *data, asUINT size) { - asASSERT(size == 1 || size == 2 || size == 4 || size == 8); - int ret = 0; + asASSERT(size == 1 || size == 2 || size == 4 || size == 8); + int ret = 0; #if defined(AS_BIG_ENDIAN) - for( asUINT n = 0; ret >= 0 && n < size; n++ ) - ret = stream->Write(((asBYTE*)data)+n, 1); + for( asUINT n = 0; ret >= 0 && n < size; n++ ) + ret = stream->Write(((asBYTE*)data)+n, 1); #else - for( int n = size-1; ret >= 0 && n >= 0; n-- ) - ret = stream->Write(((asBYTE*)data)+n, 1); + for( int n = size-1; ret >= 0 && n >= 0; n-- ) + ret = stream->Write(((asBYTE*)data)+n, 1); #endif - if (ret < 0) - Error(TXT_UNEXPECTED_END_OF_FILE); - bytesWritten += size; - return ret; + if (ret < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); + bytesWritten += size; + return ret; } int asCWriter::Write() { - TimeIt("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 - - // Write the flag as 1byte even on platforms with 4byte booleans - WriteEncodedInt64(stripDebugInfo ? 1 : 0); - - // Store enums - { - TimeIt("store enums"); - - count = (asUINT)module->m_enumTypes.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; i++ ) - { - WriteTypeDeclaration(module->m_enumTypes[i], 1); - WriteTypeDeclaration(module->m_enumTypes[i], 2); - } - } - - // Store type declarations first - { - TimeIt("type declarations"); - - count = (asUINT)module->m_classTypes.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; i++ ) - { - // Store only the name of the class/interface types - WriteTypeDeclaration(module->m_classTypes[i], 1); - } - } - - // Store func defs - { - TimeIt("func defs"); - - count = (asUINT)module->m_funcDefs.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; i++ ) - WriteFunction(module->m_funcDefs[i]->funcdef); - } - - // Now store all interface methods - { - TimeIt("interface methods"); - - count = (asUINT)module->m_classTypes.GetLength(); - for( i = 0; i < count; i++ ) - { - if( module->m_classTypes[i]->IsInterface() ) - WriteTypeDeclaration(module->m_classTypes[i], 2); - } - } - - // Then store the class methods and behaviours - { - TimeIt("class methods and behaviours"); - - for( i = 0; i < count; ++i ) - { - if( !module->m_classTypes[i]->IsInterface() ) - WriteTypeDeclaration(module->m_classTypes[i], 2); - } - } - - // Then store the class properties - { - TimeIt("class properties"); - - for( i = 0; i < count; ++i ) - { - if( !module->m_classTypes[i]->IsInterface() ) - WriteTypeDeclaration(module->m_classTypes[i], 3); - } - } - - // Store typedefs - { - TimeIt("type defs"); - - count = (asUINT)module->m_typeDefs.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; i++ ) - { - WriteTypeDeclaration(module->m_typeDefs[i], 1); - WriteTypeDeclaration(module->m_typeDefs[i], 2); - } - } - - // scriptGlobals[] - { - TimeIt("script globals"); - - count = (asUINT)module->m_scriptGlobals.GetSize(); - WriteEncodedInt64(count); - asCSymbolTable::iterator it = module->m_scriptGlobals.List(); - for( ; it; it++ ) - WriteGlobalProperty(*it); - } - - // scriptFunctions[] - { - TimeIt("scriptFunctions"); - - count = 0; - for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ ) - if( module->m_scriptFunctions[i]->objectType == 0 ) - count++; - WriteEncodedInt64(count); - for( i = 0; i < module->m_scriptFunctions.GetLength(); ++i ) - if( module->m_scriptFunctions[i]->objectType == 0 ) - WriteFunction(module->m_scriptFunctions[i]); - } - - // globalFunctions[] - { - TimeIt("globalFunctions"); - - count = (int)module->m_globalFunctions.GetSize(); - asCSymbolTable::iterator funcIt = module->m_globalFunctions.List(); - WriteEncodedInt64(count); - while( funcIt ) - { - WriteFunction(*funcIt); - funcIt++; - } - } - - // bindInformations[] - { - TimeIt("bindInformations"); - - count = (asUINT)module->m_bindInformations.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; ++i ) - { - WriteFunction(module->m_bindInformations[i]->importedFunctionSignature); - WriteString(&module->m_bindInformations[i]->importFromModule); - } - } - - // usedTypes[] - { - TimeIt("usedTypes"); - - count = (asUINT)usedTypes.GetLength(); - WriteEncodedInt64(count); - for( i = 0; i < count; ++i ) - WriteTypeInfo(usedTypes[i]); - } - - // usedTypeIds[] - WriteUsedTypeIds(); - - // usedFunctions[] - WriteUsedFunctions(); - - // usedGlobalProperties[] - WriteUsedGlobalProps(); - - // usedStringConstants[] - WriteUsedStringConstants(); - - // usedObjectProperties[] - WriteUsedObjectProps(); - - return error ? asERROR : asSUCCESS; + TimeIt("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 + + // Write the flag as 1byte even on platforms with 4byte booleans + WriteEncodedInt64(stripDebugInfo ? 1 : 0); + + // Store enums + { + TimeIt("store enums"); + + count = (asUINT)module->m_enumTypes.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; i++ ) + { + WriteTypeDeclaration(module->m_enumTypes[i], 1); + WriteTypeDeclaration(module->m_enumTypes[i], 2); + } + } + + // Store type declarations first + { + TimeIt("type declarations"); + + count = (asUINT)module->m_classTypes.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; i++ ) + { + // Store only the name of the class/interface types + WriteTypeDeclaration(module->m_classTypes[i], 1); + } + } + + // Store func defs + { + TimeIt("func defs"); + + count = (asUINT)module->m_funcDefs.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; i++ ) + WriteFunction(module->m_funcDefs[i]->funcdef); + } + + // Now store all interface methods + { + TimeIt("interface methods"); + + count = (asUINT)module->m_classTypes.GetLength(); + for( i = 0; i < count; i++ ) + { + if( module->m_classTypes[i]->IsInterface() ) + WriteTypeDeclaration(module->m_classTypes[i], 2); + } + } + + // Then store the class methods and behaviours + { + TimeIt("class methods and behaviours"); + + for( i = 0; i < count; ++i ) + { + if( !module->m_classTypes[i]->IsInterface() ) + WriteTypeDeclaration(module->m_classTypes[i], 2); + } + } + + // Then store the class properties + { + TimeIt("class properties"); + + for( i = 0; i < count; ++i ) + { + if( !module->m_classTypes[i]->IsInterface() ) + WriteTypeDeclaration(module->m_classTypes[i], 3); + } + } + + // Store typedefs + { + TimeIt("type defs"); + + count = (asUINT)module->m_typeDefs.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; i++ ) + { + WriteTypeDeclaration(module->m_typeDefs[i], 1); + WriteTypeDeclaration(module->m_typeDefs[i], 2); + } + } + + // scriptGlobals[] + { + TimeIt("script globals"); + + count = (asUINT)module->m_scriptGlobals.GetSize(); + WriteEncodedInt64(count); + asCSymbolTable::iterator it = module->m_scriptGlobals.List(); + for( ; it; it++ ) + WriteGlobalProperty(*it); + } + + // scriptFunctions[] + { + TimeIt("scriptFunctions"); + + count = 0; + for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ ) + if( module->m_scriptFunctions[i]->objectType == 0 ) + count++; + WriteEncodedInt64(count); + for( i = 0; i < module->m_scriptFunctions.GetLength(); ++i ) + if( module->m_scriptFunctions[i]->objectType == 0 ) + WriteFunction(module->m_scriptFunctions[i]); + } + + // globalFunctions[] + { + TimeIt("globalFunctions"); + + count = (int)module->m_globalFunctions.GetSize(); + asCSymbolTable::iterator funcIt = module->m_globalFunctions.List(); + WriteEncodedInt64(count); + while( funcIt ) + { + WriteFunction(*funcIt); + funcIt++; + } + } + + // bindInformations[] + { + TimeIt("bindInformations"); + + count = (asUINT)module->m_bindInformations.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; ++i ) + { + WriteFunction(module->m_bindInformations[i]->importedFunctionSignature); + WriteString(&module->m_bindInformations[i]->importFromModule); + } + } + + // usedTypes[] + { + TimeIt("usedTypes"); + + count = (asUINT)usedTypes.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; ++i ) + WriteTypeInfo(usedTypes[i]); + } + + // usedTypeIds[] + WriteUsedTypeIds(); + + // usedFunctions[] + WriteUsedFunctions(); + + // usedGlobalProperties[] + WriteUsedGlobalProps(); + + // usedStringConstants[] + WriteUsedStringConstants(); + + // usedObjectProperties[] + WriteUsedObjectProps(); + + return error ? asERROR : asSUCCESS; } int asCWriter::FindStringConstantIndex(void *str) { - asSMapNode *cursor = 0; - if (stringToIndexMap.MoveTo(&cursor, str)) - return cursor->value; - - usedStringConstants.PushLast(str); - int index = int(usedStringConstants.GetLength() - 1); - stringToIndexMap.Insert(str, index); - return index; + asSMapNode *cursor = 0; + if (stringToIndexMap.MoveTo(&cursor, str)) + return cursor->value; + + usedStringConstants.PushLast(str); + int index = int(usedStringConstants.GetLength() - 1); + stringToIndexMap.Insert(str, index); + return index; } void asCWriter::WriteUsedStringConstants() { - TimeIt("asCWriter::WriteUsedStringConstants"); - - asUINT count = (asUINT)usedStringConstants.GetLength(); - WriteEncodedInt64(count); - - asCString str; - for (asUINT i = 0; i < count; ++i) - { - asUINT length; - engine->stringFactory->GetRawStringData(usedStringConstants[i], 0, &length); - str.SetLength(length); - engine->stringFactory->GetRawStringData(usedStringConstants[i], str.AddressOf(), &length); - WriteString(&str); - } + TimeIt("asCWriter::WriteUsedStringConstants"); + + asUINT count = (asUINT)usedStringConstants.GetLength(); + WriteEncodedInt64(count); + + asCString str; + for (asUINT i = 0; i < count; ++i) + { + asUINT length; + engine->stringFactory->GetRawStringData(usedStringConstants[i], 0, &length); + str.SetLength(length); + engine->stringFactory->GetRawStringData(usedStringConstants[i], str.AddressOf(), &length); + WriteString(&str); + } } void asCWriter::WriteUsedFunctions() { - TimeIt("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 - asCScriptFunction *func = usedFunctions[n]; - if(func) - { - // Is the function from the module or the application? - c = func->module ? 'm' : 'a'; - - // Functions and methods that are shared should be stored as 's' as the bytecode - // may be imported from other modules (even if the current module have received ownership) - if (c == 'm' && func->IsShared() ) - c = 's'; - - WriteData(&c, 1); - WriteFunctionSignature(func); - } - else - { - // null function pointer - c = 'n'; - WriteData(&c, 1); - } - } + TimeIt("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 + asCScriptFunction *func = usedFunctions[n]; + if(func) + { + // Is the function from the module or the application? + c = func->module ? 'm' : 'a'; + + // Functions and methods that are shared should be stored as 's' as the bytecode + // may be imported from other modules (even if the current module have received ownership) + if (c == 'm' && func->IsShared() ) + c = 's'; + + WriteData(&c, 1); + WriteFunctionSignature(func); + } + 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 - // If the number of parameters is 0, then no need to save this - if (func->parameterTypes.GetLength() > 0) - { - 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 - // If the number of parameters is 0, then no need to save this - if (func->parameterTypes.GetLength() > 0) - { - 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]); - } - - WriteTypeInfo(func->objectType); - - if( func->objectType ) - { - asBYTE b = 0; - b += func->IsReadOnly() ? 1 : 0; - b += func->IsPrivate() ? 2 : 0; - b += func->IsProtected() ? 4 : 0; - WriteData(&b, 1); - } - else - { - if (func->funcType == asFUNC_FUNCDEF) - { - if (func->nameSpace) - { - // This funcdef was declared as global entity - asBYTE b = 'n'; - WriteData(&b, 1); - WriteString(&func->nameSpace->name); - } - else - { - // This funcdef was declared as class member - asBYTE b = 'o'; - WriteData(&b, 1); - WriteTypeInfo(func->funcdefType->parentClass); - } - } - else - WriteString(&func->nameSpace->name); - } + 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 + // If the number of parameters is 0, then no need to save this + if (func->parameterTypes.GetLength() > 0) + { + 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 + // If the number of parameters is 0, then no need to save this + if (func->parameterTypes.GetLength() > 0) + { + 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]); + } + + WriteTypeInfo(func->objectType); + + if( func->objectType ) + { + asBYTE b = 0; + b += func->IsReadOnly() ? 1 : 0; + b += func->IsPrivate() ? 2 : 0; + b += func->IsProtected() ? 4 : 0; + WriteData(&b, 1); + } + else + { + if (func->funcType == asFUNC_FUNCDEF) + { + if (func->nameSpace) + { + // This funcdef was declared as global entity + asBYTE b = 'n'; + WriteData(&b, 1); + WriteString(&func->nameSpace->name); + } + else + { + // This funcdef was declared as class member + asBYTE b = 'o'; + WriteData(&b, 1); + WriteTypeInfo(func->funcdefType->parentClass); + } + } + else + WriteString(&func->nameSpace->name); + } } void asCWriter::WriteFunction(asCScriptFunction* func) { - 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 ) - { - // Skip this for external shared entities - if (module->m_externalTypes.IndexOf(func->objectType) >= 0) - return; - - char bits = 0; - bits += func->IsShared() ? 1 : 0; - bits += func->dontCleanUpOnException ? 2 : 0; - if (module->m_externalFunctions.IndexOf(func) >= 0) - bits += 4; - if (func->scriptData->objVariablePos.GetLength() || func->scriptData->objVariableInfo.GetLength()) - bits += 8; - if (func->scriptData->tryCatchInfo.GetLength()) - bits += 16; - bits += func->IsExplicit() ? 32 : 0; - WriteData(&bits, 1); - - // For external shared functions the rest is not needed - if (bits & 4) - return; - - // Calculate the adjustment by position lookup table - CalculateAdjustmentByPos(func); - - WriteByteCode(func); - - asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace); - WriteEncodedInt64(varSpace); - - if (bits & 8) - { - count = (asUINT)func->scriptData->objVariablePos.GetLength(); - WriteEncodedInt64(count); - for (i = 0; i < count; ++i) - { - WriteTypeInfo(func->scriptData->objVariableTypes[i]); - WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i])); - } - if (count > 0) - WriteEncodedInt64(func->scriptData->objVariablesOnHeap); - - WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength()); - for (i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i) - { - // The program position must be adjusted to be in number of instructions - WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]); - WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset)); - WriteEncodedInt64(func->scriptData->objVariableInfo[i].option); - } - } - - if (bits & 16) - { - // Write info on try/catch blocks - WriteEncodedInt64((asUINT)func->scriptData->tryCatchInfo.GetLength()); - for (i = 0; i < func->scriptData->tryCatchInfo.GetLength(); ++i) - { - // The program position must be adjusted to be in number of instructions - WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].tryPos]); - WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].catchPos]); - } - } - - // The program position (every even number) needs to be adjusted - // 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 - { - 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); - } - } - - // Store script section name - if( !stripDebugInfo ) - { - if( func->scriptData->scriptSectionIdx >= 0 ) - WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]); - else - { - c = 0; - WriteData(&c, 1); - } - WriteEncodedInt64(func->scriptData->declaredAt); - } - - // Store the parameter names - if( !stripDebugInfo ) - { - 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); - } - else if( func->funcType == asFUNC_FUNCDEF ) - { - char bits = 0; - bits += func->IsShared() ? 1 : 0; - if (module->m_externalTypes.IndexOf(func->funcdefType) >= 0) - bits += 2; - WriteData(&bits,1); - } + 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 ) + { + // Skip this for external shared entities + if (module->m_externalTypes.IndexOf(func->objectType) >= 0) + return; + + char bits = 0; + bits += func->IsShared() ? 1 : 0; + bits += func->dontCleanUpOnException ? 2 : 0; + if (module->m_externalFunctions.IndexOf(func) >= 0) + bits += 4; + if (func->scriptData->objVariablePos.GetLength() || func->scriptData->objVariableInfo.GetLength()) + bits += 8; + if (func->scriptData->tryCatchInfo.GetLength()) + bits += 16; + bits += func->IsExplicit() ? 32 : 0; + WriteData(&bits, 1); + + // For external shared functions the rest is not needed + if (bits & 4) + return; + + // Calculate the adjustment by position lookup table + CalculateAdjustmentByPos(func); + + WriteByteCode(func); + + asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace); + WriteEncodedInt64(varSpace); + + if (bits & 8) + { + count = (asUINT)func->scriptData->objVariablePos.GetLength(); + WriteEncodedInt64(count); + for (i = 0; i < count; ++i) + { + WriteTypeInfo(func->scriptData->objVariableTypes[i]); + WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i])); + } + if (count > 0) + WriteEncodedInt64(func->scriptData->objVariablesOnHeap); + + WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength()); + for (i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i) + { + // The program position must be adjusted to be in number of instructions + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]); + WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset)); + WriteEncodedInt64(func->scriptData->objVariableInfo[i].option); + } + } + + if (bits & 16) + { + // Write info on try/catch blocks + WriteEncodedInt64((asUINT)func->scriptData->tryCatchInfo.GetLength()); + for (i = 0; i < func->scriptData->tryCatchInfo.GetLength(); ++i) + { + // The program position must be adjusted to be in number of instructions + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].tryPos]); + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].catchPos]); + } + } + + // The program position (every even number) needs to be adjusted + // 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 + { + 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); + } + } + + // Store script section name + if( !stripDebugInfo ) + { + if( func->scriptData->scriptSectionIdx >= 0 ) + WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]); + else + { + c = 0; + WriteData(&c, 1); + } + WriteEncodedInt64(func->scriptData->declaredAt); + } + + // Store the parameter names + if( !stripDebugInfo ) + { + 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); + } + else if( func->funcType == asFUNC_FUNCDEF ) + { + char bits = 0; + bits += func->IsShared() ? 1 : 0; + if (module->m_externalTypes.IndexOf(func->funcdefType) >= 0) + bits += 2; + WriteData(&bits,1); + } } void asCWriter::WriteTypeDeclaration(asCTypeInfo *type, int phase) { - if( phase == 1 ) - { - // name - WriteString(&type->name); - // flags - WriteData(&type->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( (type->flags & asOBJ_SCRIPT_OBJECT) && type->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(type->size); - } - - // namespace - WriteString(&type->nameSpace->name); - - // external shared flag - if ((type->flags & asOBJ_SHARED)) - { - char c = ' '; - if (module->m_externalTypes.IndexOf(type) >= 0) - c = 'e'; - WriteData(&c, 1); - } - } - else if( phase == 2 ) - { - // external shared types doesn't need to save this - if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) - return; - - if(type->flags & asOBJ_ENUM ) - { - // enumValues[] - asCEnumType *t = CastToEnumType(type); - int size = (int)t->enumValues.GetLength(); - WriteEncodedInt64(size); - - for( int n = 0; n < size; n++ ) - { - WriteString(&t->enumValues[n]->name); - WriteData(&t->enumValues[n]->value, 4); - } - } - else if(type->flags & asOBJ_TYPEDEF ) - { - asCTypedefType *td = CastToTypedefType(type); - eTokenType t = td->aliasForType.GetTokenType(); - WriteEncodedInt64(t); - } - else - { - asCObjectType *t = CastToObjectType(type); - WriteTypeInfo(t->derivedFrom); - - // interfaces[] / interfaceVFTOffsets[] - // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those? - int size = (asUINT)t->interfaces.GetLength(); - WriteEncodedInt64(size); - asUINT n; - asASSERT( t->IsInterface() || t->interfaces.GetLength() == t->interfaceVFTOffsets.GetLength() ); - for( n = 0; n < t->interfaces.GetLength(); n++ ) - { - WriteTypeInfo(t->interfaces[n]); - if( !t->IsInterface() ) - WriteEncodedInt64(t->interfaceVFTOffsets[n]); - } - - // behaviours - // TODO: Default behaviours should just be stored as a indicator - // to avoid storing the actual function object - if( !t->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM ) - { - WriteFunction(engine->scriptFunctions[t->beh.destruct]); - size = (int)t->beh.constructors.GetLength(); - WriteEncodedInt64(size); - for( n = 0; n < t->beh.constructors.GetLength(); n++ ) - { - WriteFunction(engine->scriptFunctions[t->beh.constructors[n]]); - WriteFunction(engine->scriptFunctions[t->beh.factories[n]]); - } - } - - // methods[] - // TODO: Avoid storing inherited methods in interfaces, as the reader - // can add those directly from the base interface - size = (int)t->methods.GetLength(); - WriteEncodedInt64(size); - for( n = 0; n < t->methods.GetLength(); n++ ) - { - WriteFunction(engine->scriptFunctions[t->methods[n]]); - } - - // virtualFunctionTable[] - // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader - size = (int)t->virtualFunctionTable.GetLength(); - WriteEncodedInt64(size); - for( n = 0; n < (asUINT)size; n++ ) - { - WriteFunction(t->virtualFunctionTable[n]); - } - } - } - else if( phase == 3 ) - { - // external shared types doesn't need to save this - if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) - return; - - // properties[] - asCObjectType *t = CastToObjectType(type); - - // This is only done for object types - asASSERT(t); - - asUINT size = (asUINT)t->properties.GetLength(); - WriteEncodedInt64(size); - for (asUINT n = 0; n < t->properties.GetLength(); n++) - { - WriteObjectProperty(t->properties[n]); - } - } + if( phase == 1 ) + { + // name + WriteString(&type->name); + // flags + WriteData(&type->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( (type->flags & asOBJ_SCRIPT_OBJECT) && type->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(type->size); + } + + // namespace + WriteString(&type->nameSpace->name); + + // external shared flag + if ((type->flags & asOBJ_SHARED)) + { + char c = ' '; + if (module->m_externalTypes.IndexOf(type) >= 0) + c = 'e'; + WriteData(&c, 1); + } + } + else if( phase == 2 ) + { + // external shared types doesn't need to save this + if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) + return; + + if(type->flags & asOBJ_ENUM ) + { + // enumValues[] + asCEnumType *t = CastToEnumType(type); + int size = (int)t->enumValues.GetLength(); + WriteEncodedInt64(size); + + for( int n = 0; n < size; n++ ) + { + WriteString(&t->enumValues[n]->name); + WriteData(&t->enumValues[n]->value, 4); + } + } + else if(type->flags & asOBJ_TYPEDEF ) + { + asCTypedefType *td = CastToTypedefType(type); + eTokenType t = td->aliasForType.GetTokenType(); + WriteEncodedInt64(t); + } + else + { + asCObjectType *t = CastToObjectType(type); + WriteTypeInfo(t->derivedFrom); + + // interfaces[] / interfaceVFTOffsets[] + // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those? + int size = (asUINT)t->interfaces.GetLength(); + WriteEncodedInt64(size); + asUINT n; + asASSERT( t->IsInterface() || t->interfaces.GetLength() == t->interfaceVFTOffsets.GetLength() ); + for( n = 0; n < t->interfaces.GetLength(); n++ ) + { + WriteTypeInfo(t->interfaces[n]); + if( !t->IsInterface() ) + WriteEncodedInt64(t->interfaceVFTOffsets[n]); + } + + // behaviours + // TODO: Default behaviours should just be stored as a indicator + // to avoid storing the actual function object + if( !t->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM ) + { + WriteFunction(engine->scriptFunctions[t->beh.destruct]); + size = (int)t->beh.constructors.GetLength(); + WriteEncodedInt64(size); + for( n = 0; n < t->beh.constructors.GetLength(); n++ ) + { + WriteFunction(engine->scriptFunctions[t->beh.constructors[n]]); + WriteFunction(engine->scriptFunctions[t->beh.factories[n]]); + } + } + + // methods[] + // TODO: Avoid storing inherited methods in interfaces, as the reader + // can add those directly from the base interface + size = (int)t->methods.GetLength(); + WriteEncodedInt64(size); + for( n = 0; n < t->methods.GetLength(); n++ ) + { + WriteFunction(engine->scriptFunctions[t->methods[n]]); + } + + // virtualFunctionTable[] + // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader + size = (int)t->virtualFunctionTable.GetLength(); + WriteEncodedInt64(size); + for( n = 0; n < (asUINT)size; n++ ) + { + WriteFunction(t->virtualFunctionTable[n]); + } + } + } + else if( phase == 3 ) + { + // external shared types doesn't need to save this + if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) + return; + + // properties[] + asCObjectType *t = CastToObjectType(type); + + // This is only done for object types + asASSERT(t); + + asUINT size = (asUINT)t->properties.GetLength(); + WriteEncodedInt64(size); + for (asUINT n = 0; n < t->properties.GetLength(); n++) + { + WriteObjectProperty(t->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); - } + 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) { - // First check if the string hasn't been saved already - asSMapNode *cursor = 0; - if (stringToIdMap.MoveTo(&cursor, *str)) - { - // Save a reference to the existing string - // The lowest bit is set to 1 to indicate a reference - WriteEncodedInt64(cursor->value*2+1); - return; - } - - // Save a new string - // The lowest bit is set to 0 to indicate a new string - asUINT len = (asUINT)str->GetLength(); - WriteEncodedInt64(len*2); - - if( len > 0 ) - { - stream->Write(str->AddressOf(), (asUINT)len); - bytesWritten += len; - - savedStrings.PushLast(*str); - stringToIdMap.Insert(*str, int(savedStrings.GetLength()) - 1); - } + // First check if the string hasn't been saved already + asSMapNode *cursor = 0; + if (stringToIdMap.MoveTo(&cursor, *str)) + { + // Save a reference to the existing string + // The lowest bit is set to 1 to indicate a reference + WriteEncodedInt64(cursor->value*2+1); + return; + } + + // Save a new string + // The lowest bit is set to 0 to indicate a new string + asUINT len = (asUINT)str->GetLength(); + WriteEncodedInt64(len*2); + + if( len > 0 ) + { + stream->Write(str->AddressOf(), (asUINT)len); + bytesWritten += len; + + savedStrings.PushLast(*str); + stringToIdMap.Insert(*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()); + // 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); - int flags = 0; - if( prop->isPrivate ) flags |= 1; - if( prop->isProtected ) flags |= 2; - if( prop->isInherited ) flags |= 4; - WriteEncodedInt64(flags); + WriteString(&prop->name); + WriteDataType(&prop->type); + int flags = 0; + if( prop->isPrivate ) flags |= 1; + if( prop->isProtected ) flags |= 2; + if( prop->isInherited ) flags |= 4; + WriteEncodedInt64(flags); } 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 ) - WriteTypeInfo(dt->GetTypeInfo()); - - // Endianess safe bitmask - char bits = 0; - SAVE_TO_BIT(bits, dt->IsObjectHandle(), 0); - SAVE_TO_BIT(bits, dt->IsHandleToConst(), 1); - SAVE_TO_BIT(bits, dt->IsReference(), 2); - SAVE_TO_BIT(bits, dt->IsReadOnly(), 3); - WriteData(&bits, 1); + // 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 ) + WriteTypeInfo(dt->GetTypeInfo()); + + // Endianess safe bitmask + char bits = 0; + SAVE_TO_BIT(bits, dt->IsObjectHandle(), 0); + SAVE_TO_BIT(bits, dt->IsHandleToConst(), 1); + SAVE_TO_BIT(bits, dt->IsReference(), 2); + SAVE_TO_BIT(bits, dt->IsReadOnly(), 3); + WriteData(&bits, 1); } void asCWriter::WriteTypeInfo(asCTypeInfo* ti) { - char ch; - - if( ti ) - { - // Check for template instances/specializations - asCObjectType *ot = CastToObjectType(ti); - if( ot && ot->templateSubTypes.GetLength() ) - { - // Check for list pattern type or template type - if( ot->flags & asOBJ_LIST_PATTERN ) - { - ch = 'l'; // list - WriteData(&ch, 1); - WriteTypeInfo(ot->templateSubTypes[0].GetTypeInfo()); - } - else - { - ch = 'a'; // array - 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[n].IsPrimitive() || ot->templateSubTypes[n].IsEnumType() ) - { - ch = 's'; // sub type - WriteData(&ch, 1); - WriteDataType(&ot->templateSubTypes[n]); - } - else - { - ch = 't'; // token - WriteData(&ch, 1); - eTokenType t = ot->templateSubTypes[n].GetTokenType(); - WriteEncodedInt64(t); - } - } - } - } - else if( ti->flags & asOBJ_TEMPLATE_SUBTYPE ) - { - ch = 's'; // sub type - WriteData(&ch, 1); - WriteString(&ti->name); - } - else if( !ti->GetParentType() ) - { - ch = 'o'; // object - WriteData(&ch, 1); - WriteString(&ti->name); - WriteString(&ti->nameSpace->name); - } - else - { - asASSERT(ti->flags & asOBJ_FUNCDEF); - - ch = 'c'; // child type - WriteData(&ch, 1); - WriteString(&ti->name); - WriteTypeInfo(CastToFuncdefType(ti)->parentClass); - } - } - else - { - ch = '\0'; - WriteData(&ch, 1); - } + char ch; + + if( ti ) + { + // Check for template instances/specializations + asCObjectType *ot = CastToObjectType(ti); + if( ot && ot->templateSubTypes.GetLength() ) + { + // Check for list pattern type or template type + if( ot->flags & asOBJ_LIST_PATTERN ) + { + ch = 'l'; // list + WriteData(&ch, 1); + WriteTypeInfo(ot->templateSubTypes[0].GetTypeInfo()); + } + else + { + ch = 'a'; // array + 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[n].IsPrimitive() || ot->templateSubTypes[n].IsEnumType() ) + { + ch = 's'; // sub type + WriteData(&ch, 1); + WriteDataType(&ot->templateSubTypes[n]); + } + else + { + ch = 't'; // token + WriteData(&ch, 1); + eTokenType t = ot->templateSubTypes[n].GetTokenType(); + WriteEncodedInt64(t); + } + } + } + } + else if( ti->flags & asOBJ_TEMPLATE_SUBTYPE ) + { + ch = 's'; // sub type + WriteData(&ch, 1); + WriteString(&ti->name); + } + else if( !ti->GetParentType() ) + { + ch = 'o'; // object + WriteData(&ch, 1); + WriteString(&ti->name); + WriteString(&ti->nameSpace->name); + } + else + { + asASSERT(ti->flags & asOBJ_FUNCDEF); + + ch = 'c'; // child type + WriteData(&ch, 1); + WriteString(&ti->name); + WriteTypeInfo(CastToFuncdefType(ti)->parentClass); + } + } + 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++ ) - { - // Determine the size the variable currently occupies on the stack - int size = AS_PTR_SIZE; - - // objVariableTypes is null if the variable type is a null pointer - if( func->scriptData->objVariableTypes[n] && - (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && - n >= func->scriptData->objVariablesOnHeap ) - { - size = func->scriptData->objVariableTypes[n]->GetSize(); - if( size < 4 ) - size = 1; - else - size /= 4; - } - - // If larger than 1 dword, adjust the offsets accordingly - if (size > 1) - { - // How much needs to be adjusted? - adjustments.PushLast(func->scriptData->objVariablePos[n]); - adjustments.PushLast(-(size - 1)); - } - } - - // 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 - asUINT 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++; - } - - // Store the number of instructions in the last position of bytecodeNbrByPos, - // so this can be easily queried in SaveBytecode. Normally this is already done - // as most functions end with BC_RET, but in some cases the last instruction in - // the function is not a BC_RET, e.g. when a function has a never ending loop. - bytecodeNbrByPos[length - 1] = num - 1; + // 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++ ) + { + // Determine the size the variable currently occupies on the stack + int size = AS_PTR_SIZE; + + // objVariableTypes is null if the variable type is a null pointer + if( func->scriptData->objVariableTypes[n] && + (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && + n >= func->scriptData->objVariablesOnHeap ) + { + size = func->scriptData->objVariableTypes[n]->GetSize(); + if( size < 4 ) + size = 1; + else + size /= 4; + } + + // If larger than 1 dword, adjust the offsets accordingly + if (size > 1) + { + // How much needs to be adjusted? + adjustments.PushLast(func->scriptData->objVariablePos[n]); + adjustments.PushLast(-(size - 1)); + } + } + + // 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 + asUINT 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++; + } + + // Store the number of instructions in the last position of bytecodeNbrByPos, + // so this can be easily queried in SaveBytecode. Normally this is already done + // as most functions end with BC_RET, but in some cases the last instruction in + // the function is not a BC_RET, e.g. when a function has a never ending loop. + bytecodeNbrByPos[length - 1] = num - 1; } 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; + 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; - - bool bcAlloc = false; - - // Find out which function that will be called - asCScriptFunction *calledFunc = 0; - int stackDelta = 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_Thiscall1 || - 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 ) - { - // The alloc instruction doesn't take the object pointer on the stack, - // as the memory will be allocated by the instruction itself - bcAlloc = true; - - // Find the function from the function id in the bytecode - int funcId = asBC_INTARG(&func->scriptData->byteCode[n+AS_PTR_SIZE]); - calledFunc = engine->scriptFunctions[funcId]; - 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 = CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef; - 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 = CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef; - 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); - } - - // Keep track of the stack size between the - // instruction that needs to be adjusted and the call - stackDelta += asBCInfo[bc].stackInc; - - 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 = -stackDelta; - if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc ) - { - currOffset += AS_PTR_SIZE; - if( currOffset > 0 ) - numPtrs++; - } - if( offset > currOffset && calledFunc->DoesReturnOnStack() ) - { - currOffset += AS_PTR_SIZE; - if( currOffset > 0 ) - numPtrs++; - } - 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 - currOffset += AS_PTR_SIZE; - if( currOffset > 0 ) - numPtrs++; - - // 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); + // 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; + + bool bcAlloc = false; + + // Find out which function that will be called + asCScriptFunction *calledFunc = 0; + int stackDelta = 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_Thiscall1 || + 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 ) + { + // The alloc instruction doesn't take the object pointer on the stack, + // as the memory will be allocated by the instruction itself + bcAlloc = true; + + // Find the function from the function id in the bytecode + int funcId = asBC_INTARG(&func->scriptData->byteCode[n+AS_PTR_SIZE]); + calledFunc = engine->scriptFunctions[funcId]; + 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 = CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef; + 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 = CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef; + 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); + } + + // Keep track of the stack size between the + // instruction that needs to be adjusted and the call + stackDelta += asBCInfo[bc].stackInc; + + 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 = -stackDelta; + if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc ) + { + currOffset += AS_PTR_SIZE; + if( currOffset > 0 ) + numPtrs++; + } + if( offset > currOffset && calledFunc->DoesReturnOnStack() ) + { + currOffset += AS_PTR_SIZE; + if( currOffset > 0 ) + numPtrs++; + } + 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 + currOffset += AS_PTR_SIZE; + if( currOffset > 0 ) + numPtrs++; + + // 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 tmpBC[4]; // The biggest instructions take up 4 DWORDs - asDWORD c = *(asBYTE*)bc; - - // Copy the instruction to a temp buffer so we can work on it before saving - memcpy(tmpBC, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD)); - - if( c == asBC_ALLOC ) // PTR_DW_ARG - { - // Translate the object type - asCObjectType *ot = *(asCObjectType**)(tmpBC+1); - *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot); - - // Translate the constructor func id, unless it is 0 - if( *(int*)&tmpBC[1+AS_PTR_SIZE] != 0 ) - { - // Increment 1 to the translated function id, as 0 will be reserved for no function - *(int*)&tmpBC[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmpBC[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*)(tmpBC+1) = FindTypeInfoIdx(*(asCObjectType**)(tmpBC+1)); - } - else if( c == asBC_JitEntry ) // PTR_ARG - { - // We don't store the JIT argument - *(asPWORD*)(tmpBC+1) = 0; - } - else if( c == asBC_TYPEID || // DW_ARG - c == asBC_Cast ) // DW_ARG - { - // Translate type ids into indices - *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); - } - else if( c == asBC_ADDSi || // W_DW_ARG - c == asBC_LoadThisR ) // W_DW_ARG - { - // Translate property offsets into indices - *(((short*)tmpBC)+1) = (short)FindObjectPropIndex(*(((short*)tmpBC)+1), *(int*)(tmpBC+1), bc); - - // Translate type ids into indices - *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); - } - else if( c == asBC_LoadRObjR || // rW_W_DW_ARG - c == asBC_LoadVObjR ) // rW_W_DW_ARG - { - asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmpBC+2)); - if( ot->flags & asOBJ_LIST_PATTERN ) - { - // List patterns have a different way of translating the offsets - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - *(((short*)tmpBC)+2) = (short)listAdj->AdjustOffset(*(((short*)tmpBC)+2), ot); - } - else - { - // Translate property offsets into indices - *(((short*)tmpBC)+2) = (short)FindObjectPropIndex(*(((short*)tmpBC)+2), *(int*)(tmpBC+2), bc); - } - - // Translate type ids into indices - *(int*)(tmpBC+2) = FindTypeIdIdx(*(int*)(tmpBC+2)); - } - else if( c == asBC_COPY ) // W_DW_ARG - { - // Translate type ids into indices - *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); - - // Update the WORDARG0 to 0, as this will be recalculated on the target platform - asBC_WORDARG0(tmpBC) = 0; - } - else if( c == asBC_RET ) // W_ARG - { - // Save with arg 0, as this will be recalculated on the target platform - asBC_WORDARG0(tmpBC) = 0; - } - else if( c == asBC_CALL || // DW_ARG - c == asBC_CALLINTF || // DW_ARG - c == asBC_CALLSYS || // DW_ARG - c == asBC_Thiscall1 ) // DW_ARG - { - // Translate the function id - *(int*)(tmpBC+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmpBC+1)]); - } - else if( c == asBC_FuncPtr ) // PTR_ARG - { - // Translate the function pointer - *(asPWORD*)(tmpBC+1) = FindFunctionIndex(*(asCScriptFunction**)(tmpBC+1)); - } - else if( c == asBC_CALLBND ) // DW_ARG - { - // Translate the function id - int funcId = tmpBC[1]; - for( asUINT n = 0; n < module->m_bindInformations.GetLength(); n++ ) - if( module->m_bindInformations[n]->importedFunctionSignature->id == funcId ) - { - funcId = n; - break; - } - - tmpBC[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 - { - // Check if the address is a global property or a string constant - void *ptr = *(void**)(tmpBC + 1); - if (engine->varAddressMap.MoveTo(0, ptr)) - { - // Translate global variable pointers into indices - // Flag the first bit to signal global property - *(asPWORD*)(tmpBC + 1) = (FindGlobalPropPtrIndex(*(void**)(tmpBC + 1)) << 1) + 1; - } - else - { - // Only PGA and PshGPtr can hold string constants - asASSERT(c == asBC_PGA || c == asBC_PshGPtr); - - // Translate string constants into indices - // Leave the first bit clear to signal string constant - *(asPWORD*)(tmpBC + 1) = FindStringConstantIndex(*(void**)(tmpBC + 1)) << 1; - } - } - else if( c == asBC_JMP || // DW_ARG - c == asBC_JZ || - 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*)(tmpBC+1); - - // Determine instruction number for next instruction and destination - int bcSeqNum = bytecodeNbrByPos[asUINT(bc - startBC)] + 1; - asDWORD *targetBC = bc + 2 + offset; - int targetBcSeqNum = bytecodeNbrByPos[asUINT(targetBC - startBC)]; - - // Set the offset in number of instructions - *(int*)(tmpBC+1) = targetBcSeqNum - bcSeqNum; - } - else if( c == asBC_GETOBJ || // W_ARG - c == asBC_GETOBJREF || - c == asBC_GETREF || - c == asBC_ChkNullS ) - { - // Adjust the offset according to the function call that comes after - asBC_WORDARG0(tmpBC) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmpBC), func, asDWORD(bc - startBC)); - } - else if( c == asBC_AllocMem ) - { - // It's not necessary to store the size of the list buffer, as it will be recalculated in the reader - asBC_DWORDARG(tmpBC) = 0; - - // Determine the type of the list pattern from the variable - short var = asBC_WORDARG0(tmpBC); - asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(var)); - - // Create this helper object to adjust the offset of the elements accessed in the buffer - listAdjusters.PushLast(asNEW(SListAdjuster)(ot)); - } - else if( c == asBC_FREE ) // wW_PTR_ARG - { - // Translate object type pointers into indices - asCObjectType *ot = *(asCObjectType**)(tmpBC+1); - *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot); - - // Pop and destroy the list adjuster helper that was created with asBC_AllocMem - if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) - { - 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]; - tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); - - // Tell the adjuster how many repeated values there are - listAdj->SetRepeatCount(tmpBC[2]); - } - else if( c == asBC_PshListElmnt ) // W_DW_ARG - { - // Adjust the offset in the initialization list - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); - } - else if( c == asBC_SetListType ) - { - // Adjust the offset in the initialization list - SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; - tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); - - // Inform the adjuster of the type id of the next element - listAdj->SetNextType(tmpBC[2]); - - // Translate the type id - tmpBC[2] = FindTypeIdIdx(tmpBC[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(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); - } - break; - - case asBCTYPE_wW_rW_ARG: - case asBCTYPE_wW_rW_DW_ARG: - case asBCTYPE_rW_rW_ARG: - { - asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); - asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC)); - } - break; - - case asBCTYPE_wW_rW_rW_ARG: - { - asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); - asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC)); - asBC_SWORDARG2(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG2(tmpBC)); - } - 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*)tmpBC)+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*)tmpBC)+1); - WriteEncodedInt64(w); - - // Write the dword argument - WriteEncodedInt64((int)tmpBC[1]); - } - break; - case asBCTYPE_DW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the argument - WriteEncodedInt64((int)tmpBC[1]); - } - break; - case asBCTYPE_DW_DW_ARG: - { - // Write the instruction code - asBYTE b = (asBYTE)c; - WriteData(&b, 1); - - // Write the dword argument - WriteEncodedInt64((int)tmpBC[1]); - - // Write the dword argument - WriteEncodedInt64((int)tmpBC[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*)tmpBC)+1); - WriteEncodedInt64(w); - - // Write the second argument - w = *(((short*)tmpBC)+2); - WriteEncodedInt64(w); - - // Write the third argument - w = *(((short*)tmpBC)+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*)tmpBC)+1); - WriteEncodedInt64(w); - - // Write the second argument - w = *(((short*)tmpBC)+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*)tmpBC)+1); - WriteEncodedInt64(w); - - // Write the second argument - w = *(((short*)tmpBC)+2); - WriteEncodedInt64(w); - - // Write the third argument - int dw = tmpBC[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*)&tmpBC[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*)&tmpBC[1]; - WriteEncodedInt64(qw); - - // Write the second argument - int dw = tmpBC[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*)tmpBC)+1); - WriteEncodedInt64(w); - - // Write the argument - asQWORD qw = *(asQWORD*)&tmpBC[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*)tmpBC)+1); - WriteEncodedInt64(w); - - // Write the dword argument - WriteEncodedInt64((int)tmpBC[1]); - - // Write the dword argument - WriteEncodedInt64((int)tmpBC[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(&tmpBC[n], 4); - } - } - - // Move to the next instruction - bc += asBCTypeSize[asBCInfo[c].type]; - length -= asBCTypeSize[asBCInfo[c].type]; - } + 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 tmpBC[4]; // The biggest instructions take up 4 DWORDs + asDWORD c = *(asBYTE*)bc; + + // Copy the instruction to a temp buffer so we can work on it before saving + memcpy(tmpBC, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD)); + + if( c == asBC_ALLOC ) // PTR_DW_ARG + { + // Translate the object type + asCObjectType *ot = *(asCObjectType**)(tmpBC+1); + *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot); + + // Translate the constructor func id, unless it is 0 + if( *(int*)&tmpBC[1+AS_PTR_SIZE] != 0 ) + { + // Increment 1 to the translated function id, as 0 will be reserved for no function + *(int*)&tmpBC[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmpBC[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*)(tmpBC+1) = FindTypeInfoIdx(*(asCObjectType**)(tmpBC+1)); + } + else if( c == asBC_JitEntry ) // PTR_ARG + { + // We don't store the JIT argument + *(asPWORD*)(tmpBC+1) = 0; + } + else if( c == asBC_TYPEID || // DW_ARG + c == asBC_Cast ) // DW_ARG + { + // Translate type ids into indices + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); + } + else if( c == asBC_ADDSi || // W_DW_ARG + c == asBC_LoadThisR ) // W_DW_ARG + { + // Translate property offsets into indices + *(((short*)tmpBC)+1) = (short)FindObjectPropIndex(*(((short*)tmpBC)+1), *(int*)(tmpBC+1), bc); + + // Translate type ids into indices + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); + } + else if( c == asBC_LoadRObjR || // rW_W_DW_ARG + c == asBC_LoadVObjR ) // rW_W_DW_ARG + { + asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmpBC+2)); + if( ot->flags & asOBJ_LIST_PATTERN ) + { + // List patterns have a different way of translating the offsets + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + *(((short*)tmpBC)+2) = (short)listAdj->AdjustOffset(*(((short*)tmpBC)+2), ot); + } + else + { + // Translate property offsets into indices + *(((short*)tmpBC)+2) = (short)FindObjectPropIndex(*(((short*)tmpBC)+2), *(int*)(tmpBC+2), bc); + } + + // Translate type ids into indices + *(int*)(tmpBC+2) = FindTypeIdIdx(*(int*)(tmpBC+2)); + } + else if( c == asBC_COPY ) // W_DW_ARG + { + // Translate type ids into indices + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); + + // Update the WORDARG0 to 0, as this will be recalculated on the target platform + asBC_WORDARG0(tmpBC) = 0; + } + else if( c == asBC_RET ) // W_ARG + { + // Save with arg 0, as this will be recalculated on the target platform + asBC_WORDARG0(tmpBC) = 0; + } + else if( c == asBC_CALL || // DW_ARG + c == asBC_CALLINTF || // DW_ARG + c == asBC_CALLSYS || // DW_ARG + c == asBC_Thiscall1 ) // DW_ARG + { + // Translate the function id + *(int*)(tmpBC+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmpBC+1)]); + } + else if( c == asBC_FuncPtr ) // PTR_ARG + { + // Translate the function pointer + *(asPWORD*)(tmpBC+1) = FindFunctionIndex(*(asCScriptFunction**)(tmpBC+1)); + } + else if( c == asBC_CALLBND ) // DW_ARG + { + // Translate the function id + int funcId = tmpBC[1]; + for( asUINT n = 0; n < module->m_bindInformations.GetLength(); n++ ) + if( module->m_bindInformations[n]->importedFunctionSignature->id == funcId ) + { + funcId = n; + break; + } + + tmpBC[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 + { + // Check if the address is a global property or a string constant + void *ptr = *(void**)(tmpBC + 1); + if (engine->varAddressMap.MoveTo(0, ptr)) + { + // Translate global variable pointers into indices + // Flag the first bit to signal global property + *(asPWORD*)(tmpBC + 1) = (FindGlobalPropPtrIndex(*(void**)(tmpBC + 1)) << 1) + 1; + } + else + { + // Only PGA and PshGPtr can hold string constants + asASSERT(c == asBC_PGA || c == asBC_PshGPtr); + + // Translate string constants into indices + // Leave the first bit clear to signal string constant + *(asPWORD*)(tmpBC + 1) = FindStringConstantIndex(*(void**)(tmpBC + 1)) << 1; + } + } + else if( c == asBC_JMP || // DW_ARG + c == asBC_JZ || + 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*)(tmpBC+1); + + // Determine instruction number for next instruction and destination + int bcSeqNum = bytecodeNbrByPos[asUINT(bc - startBC)] + 1; + asDWORD *targetBC = bc + 2 + offset; + int targetBcSeqNum = bytecodeNbrByPos[asUINT(targetBC - startBC)]; + + // Set the offset in number of instructions + *(int*)(tmpBC+1) = targetBcSeqNum - bcSeqNum; + } + else if( c == asBC_GETOBJ || // W_ARG + c == asBC_GETOBJREF || + c == asBC_GETREF || + c == asBC_ChkNullS ) + { + // Adjust the offset according to the function call that comes after + asBC_WORDARG0(tmpBC) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmpBC), func, asDWORD(bc - startBC)); + } + else if( c == asBC_AllocMem ) + { + // It's not necessary to store the size of the list buffer, as it will be recalculated in the reader + asBC_DWORDARG(tmpBC) = 0; + + // Determine the type of the list pattern from the variable + short var = asBC_WORDARG0(tmpBC); + asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(var)); + + // Create this helper object to adjust the offset of the elements accessed in the buffer + listAdjusters.PushLast(asNEW(SListAdjuster)(ot)); + } + else if( c == asBC_FREE ) // wW_PTR_ARG + { + // Translate object type pointers into indices + asCObjectType *ot = *(asCObjectType**)(tmpBC+1); + *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot); + + // Pop and destroy the list adjuster helper that was created with asBC_AllocMem + if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) + { + 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]; + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); + + // Tell the adjuster how many repeated values there are + listAdj->SetRepeatCount(tmpBC[2]); + } + else if( c == asBC_PshListElmnt ) // W_DW_ARG + { + // Adjust the offset in the initialization list + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); + } + else if( c == asBC_SetListType ) + { + // Adjust the offset in the initialization list + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); + + // Inform the adjuster of the type id of the next element + listAdj->SetNextType(tmpBC[2]); + + // Translate the type id + tmpBC[2] = FindTypeIdIdx(tmpBC[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(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); + } + break; + + case asBCTYPE_wW_rW_ARG: + case asBCTYPE_wW_rW_DW_ARG: + case asBCTYPE_rW_rW_ARG: + { + asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); + asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC)); + } + break; + + case asBCTYPE_wW_rW_rW_ARG: + { + asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); + asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC)); + asBC_SWORDARG2(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG2(tmpBC)); + } + 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*)tmpBC)+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*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[1]); + } + break; + case asBCTYPE_DW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the argument + WriteEncodedInt64((int)tmpBC[1]); + } + break; + case asBCTYPE_DW_DW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[1]); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[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*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the second argument + w = *(((short*)tmpBC)+2); + WriteEncodedInt64(w); + + // Write the third argument + w = *(((short*)tmpBC)+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*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the second argument + w = *(((short*)tmpBC)+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*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the second argument + w = *(((short*)tmpBC)+2); + WriteEncodedInt64(w); + + // Write the third argument + int dw = tmpBC[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*)&tmpBC[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*)&tmpBC[1]; + WriteEncodedInt64(qw); + + // Write the second argument + int dw = tmpBC[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*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the argument + asQWORD qw = *(asQWORD*)&tmpBC[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*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[1]); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[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(&tmpBC[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) ); + 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; + // 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.GetTypeInfo() && (dt.GetTypeInfo()->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; + // 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.GetTypeInfo() && (dt.GetTypeInfo()->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 ); + // 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; + // Now move to the next patternNode + patternNode = patternNode->next; - repeatCount = rc; + 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 ); + // 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; + // Inform the type id for the next adjustment + nextTypeId = typeId; } void asCWriter::WriteUsedTypeIds() { - TimeIt("asCWriter::WriteUsedTypeIds"); - - asUINT count = (asUINT)usedTypeIds.GetLength(); - WriteEncodedInt64(count); - for( asUINT n = 0; n < count; n++ ) - { - asCDataType dt = engine->GetDataTypeFromTypeId(usedTypeIds[n]); - WriteDataType(&dt); - } + TimeIt("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; + int i = usedGlobalProperties.IndexOf(ptr); + if( i >= 0 ) return i; - usedGlobalProperties.PushLast(ptr); - return (int)usedGlobalProperties.GetLength()-1; + usedGlobalProperties.PushLast(ptr); + return (int)usedGlobalProperties.GetLength()-1; } void asCWriter::WriteUsedGlobalProps() { - TimeIt("asCWriter::WriteUsedGlobalProps"); - - int c = (int)usedGlobalProperties.GetLength(); - WriteEncodedInt64(c); - - for( int n = 0; n < c; n++ ) - { - asPWORD *p = (asPWORD*)usedGlobalProperties[n]; - - // Find the property descriptor from the address - asCGlobalProperty *prop = 0; - asSMapNode *cursor; - if( engine->varAddressMap.MoveTo(&cursor, p) ) - { - prop = engine->varAddressMap.GetValue(cursor); - } - - 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 - char moduleProp = 0; - if( prop->realAddress == 0 ) - moduleProp = 1; - WriteData(&moduleProp, 1); - } + TimeIt("asCWriter::WriteUsedGlobalProps"); + + int c = (int)usedGlobalProperties.GetLength(); + WriteEncodedInt64(c); + + for( int n = 0; n < c; n++ ) + { + asPWORD *p = (asPWORD*)usedGlobalProperties[n]; + + // Find the property descriptor from the address + asCGlobalProperty *prop = 0; + asSMapNode *cursor; + if( engine->varAddressMap.MoveTo(&cursor, p) ) + { + prop = engine->varAddressMap.GetValue(cursor); + } + + 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 + char moduleProp = 0; + if( prop->realAddress == 0 ) + moduleProp = 1; + WriteData(&moduleProp, 1); + } } void asCWriter::WriteUsedObjectProps() { - TimeIt("asCWriter::WriteUsedObjectProps"); + TimeIt("asCWriter::WriteUsedObjectProps"); - int c = (int)usedObjectProperties.GetLength(); - WriteEncodedInt64(c); + int c = (int)usedObjectProperties.GetLength(); + WriteEncodedInt64(c); - for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) - { - WriteTypeInfo(usedObjectProperties[n].objType); - WriteString(&usedObjectProperties[n].prop->name); - } + for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) + { + WriteTypeInfo(usedObjectProperties[n].objType); + WriteString(&usedObjectProperties[n].prop->name); + } } int asCWriter::FindObjectPropIndex(short offset, int typeId, asDWORD *bc) { - // If the last property was a composite property, then just return 0, because it won't be translated - static bool lastWasComposite = false; - if (lastWasComposite) - { - lastWasComposite = false; - return 0; - } - - asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId); - asCObjectProperty *objProp = 0; - - // Look for composite properties first - for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++) - { - // TODO: Composite: Perhaps it would be better to add metadata to the bytecode instruction to give the exact property. - // That would also allow me to remove the typeId from the bytecode instruction itself - // Or perhaps a new bytecode instruction all together for accessing composite properties - // One that would do both offsets and indirection in a single go. - // TODO: Composite: Need to be able to handle instructions replaced in bytecode optimizations too - if (objType->properties[n]->compositeOffset == offset) - { - // This is a potential composite property. Need to check the following instructions to be sure - objProp = objType->properties[n]; - asDWORD *bcTemp = bc; - bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type]; - if (objProp->isCompositeIndirect) - { - // The next instruction would be a asBC_RDSPtr - if ((*(asBYTE*)bcTemp) != asBC_RDSPtr) - { - objProp = 0; - continue; - } - bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type]; - } - // The next instruction would be asBC_ADDSi - if ((*(asBYTE*)bcTemp) != asBC_ADDSi) - { - objProp = 0; - continue; - } - // Make sure the offset is the expected one - if (*(((short*)bcTemp) + 1) != objProp->byteOffset) - { - objProp = 0; - continue; - } - } - } - - // If none of the composite properties matched, then look for ordinary property - for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++) - { - if (objType->properties[n]->byteOffset == offset && !(objType->properties[n]->compositeOffset || objType->properties[n]->isCompositeIndirect)) - objProp = objType->properties[n]; - } - - asASSERT(objProp); - - // Remember if this is a composite property as the next call will then be for the same property - if (objProp->compositeOffset || objProp->isCompositeIndirect) - lastWasComposite = true; - - // Now check if the same property has already been accessed - for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) - { - if( usedObjectProperties[n].objType == objType && - usedObjectProperties[n].prop == objProp ) - return n; - } - - // Insert the new property - SObjProp prop = {objType, objProp}; - usedObjectProperties.PushLast(prop); - return (int)usedObjectProperties.GetLength() - 1; + // If the last property was a composite property, then just return 0, because it won't be translated + static bool lastWasComposite = false; + if (lastWasComposite) + { + lastWasComposite = false; + return 0; + } + + asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId); + asCObjectProperty *objProp = 0; + + // Look for composite properties first + for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++) + { + // TODO: Composite: Perhaps it would be better to add metadata to the bytecode instruction to give the exact property. + // That would also allow me to remove the typeId from the bytecode instruction itself + // Or perhaps a new bytecode instruction all together for accessing composite properties + // One that would do both offsets and indirection in a single go. + // TODO: Composite: Need to be able to handle instructions replaced in bytecode optimizations too + if (objType->properties[n]->compositeOffset == offset) + { + // This is a potential composite property. Need to check the following instructions to be sure + objProp = objType->properties[n]; + asDWORD *bcTemp = bc; + bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type]; + if (objProp->isCompositeIndirect) + { + // The next instruction would be a asBC_RDSPtr + if ((*(asBYTE*)bcTemp) != asBC_RDSPtr) + { + objProp = 0; + continue; + } + bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type]; + } + // The next instruction would be asBC_ADDSi + if ((*(asBYTE*)bcTemp) != asBC_ADDSi) + { + objProp = 0; + continue; + } + // Make sure the offset is the expected one + if (*(((short*)bcTemp) + 1) != objProp->byteOffset) + { + objProp = 0; + continue; + } + } + } + + // If none of the composite properties matched, then look for ordinary property + for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++) + { + if (objType->properties[n]->byteOffset == offset && !(objType->properties[n]->compositeOffset || objType->properties[n]->isCompositeIndirect)) + objProp = objType->properties[n]; + } + + asASSERT(objProp); + + // Remember if this is a composite property as the next call will then be for the same property + if (objProp->compositeOffset || objProp->isCompositeIndirect) + lastWasComposite = true; + + // Now check if the same property has already been accessed + for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) + { + if( usedObjectProperties[n].objType == objType && + usedObjectProperties[n].prop == objProp ) + return n; + } + + // Insert the new property + SObjProp prop = {objType, objProp}; + 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; + 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; + 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::FindTypeInfoIdx(asCTypeInfo *obj) { - asUINT n; - for( n = 0; n < usedTypes.GetLength(); n++ ) - { - if( usedTypes[n] == obj ) - return n; - } - - usedTypes.PushLast(obj); - return (int)usedTypes.GetLength() - 1; + 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 diff --git a/src/angelscript/source/as_restore.h b/src/angelscript/source/as_restore.h index 462c2ae5e08..8b9b343ad10 100644 --- a/src/angelscript/source/as_restore.h +++ b/src/angelscript/source/as_restore.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -48,107 +48,107 @@ BEGIN_AS_NAMESPACE class asCReader { public: - asCReader(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine); + asCReader(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine); - int Read(bool *wasDebugInfoStripped); + int Read(bool *wasDebugInfoStripped); protected: - asCModule *module; - asIBinaryStream *stream; - asCScriptEngine *engine; - bool noDebugInfo; - bool error; - asUINT bytesRead; - - int Error(const char *msg); - - int ReadInner(); - - int ReadData(void *data, asUINT size); - void ReadString(asCString *str); - asCScriptFunction *ReadFunction(bool &isNew, bool addToModule = true, bool addToEngine = true, bool addToGC = true, bool *isExternal = 0); - void ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass = 0); - void ReadGlobalProperty(); - void ReadObjectProperty(asCObjectType *ot); - void ReadDataType(asCDataType *dt); - asCTypeInfo *ReadTypeInfo(); - void ReadTypeDeclaration(asCTypeInfo *ot, int phase, bool *isExternal = 0); - void ReadByteCode(asCScriptFunction *func); - asWORD ReadEncodedUInt16(); - asUINT ReadEncodedUInt(); - asQWORD ReadEncodedUInt64(); - - void ReadUsedTypeIds(); - void ReadUsedFunctions(); - void ReadUsedGlobalProps(); - void ReadUsedStringConstants(); - void ReadUsedObjectProps(); - - asCTypeInfo * FindType(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; - asCObjectProperty *prop; - }; - 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; + asCModule *module; + asIBinaryStream *stream; + asCScriptEngine *engine; + bool noDebugInfo; + bool error; + asUINT bytesRead; + + int Error(const char *msg); + + int ReadInner(); + + int ReadData(void *data, asUINT size); + void ReadString(asCString *str); + asCScriptFunction *ReadFunction(bool &isNew, bool addToModule = true, bool addToEngine = true, bool addToGC = true, bool *isExternal = 0); + void ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass = 0); + void ReadGlobalProperty(); + void ReadObjectProperty(asCObjectType *ot); + void ReadDataType(asCDataType *dt); + asCTypeInfo *ReadTypeInfo(); + void ReadTypeDeclaration(asCTypeInfo *ot, int phase, bool *isExternal = 0); + void ReadByteCode(asCScriptFunction *func); + asWORD ReadEncodedUInt16(); + asUINT ReadEncodedUInt(); + asQWORD ReadEncodedUInt64(); + + void ReadUsedTypeIds(); + void ReadUsedFunctions(); + void ReadUsedGlobalProps(); + void ReadUsedStringConstants(); + void ReadUsedObjectProps(); + + asCTypeInfo * FindType(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; + asCObjectProperty *prop; + }; + 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 @@ -156,100 +156,100 @@ class asCReader class asCWriter { public: - asCWriter(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine, bool stripDebugInfo); + asCWriter(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine, bool stripDebugInfo); - int Write(); + int Write(); protected: - asCModule *module; - asIBinaryStream *stream; - asCScriptEngine *engine; - bool stripDebugInfo; - bool error; - asUINT bytesWritten; - - int Error(const char *msg); - - int 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 WriteTypeInfo(asCTypeInfo *ot); - void WriteTypeDeclaration(asCTypeInfo *ot, int phase); - void WriteByteCode(asCScriptFunction *func); - void WriteEncodedInt64(asINT64 i); - - // Helper functions for storing variable data - int FindTypeInfoIdx(asCTypeInfo *ti); - int FindTypeIdIdx(int typeId); - int FindFunctionIndex(asCScriptFunction *func); - int FindGlobalPropPtrIndex(void *); - int FindStringConstantIndex(void *str); - int FindObjectPropIndex(short offset, int typeId, asDWORD *bc); - - 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 stringToIndexMap; - - asCArray savedFunctions; - asCArray savedDataTypes; - asCArray savedStrings; - asCMap stringToIdMap; - asCArray adjustStackByPos; - asCArray adjustNegativeStackByPos; - asCArray bytecodeNbrByPos; - - struct SObjProp - { - asCObjectType *objType; - asCObjectProperty *prop; - }; - 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; + asCModule *module; + asIBinaryStream *stream; + asCScriptEngine *engine; + bool stripDebugInfo; + bool error; + asUINT bytesWritten; + + int Error(const char *msg); + + int 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 WriteTypeInfo(asCTypeInfo *ot); + void WriteTypeDeclaration(asCTypeInfo *ot, int phase); + void WriteByteCode(asCScriptFunction *func); + void WriteEncodedInt64(asINT64 i); + + // Helper functions for storing variable data + int FindTypeInfoIdx(asCTypeInfo *ti); + int FindTypeIdIdx(int typeId); + int FindFunctionIndex(asCScriptFunction *func); + int FindGlobalPropPtrIndex(void *); + int FindStringConstantIndex(void *str); + int FindObjectPropIndex(short offset, int typeId, asDWORD *bc); + + 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 stringToIndexMap; + + asCArray savedFunctions; + asCArray savedDataTypes; + asCArray savedStrings; + asCMap stringToIdMap; + asCArray adjustStackByPos; + asCArray adjustNegativeStackByPos; + asCArray bytecodeNbrByPos; + + struct SObjProp + { + asCObjectType *objType; + asCObjectProperty *prop; + }; + 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 diff --git a/src/angelscript/source/as_scriptcode.cpp b/src/angelscript/source/as_scriptcode.cpp index 833b401b61c..cbabce2caff 100644 --- a/src/angelscript/source/as_scriptcode.cpp +++ b/src/angelscript/source/as_scriptcode.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2015 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -44,108 +44,108 @@ BEGIN_AS_NAMESPACE asCScriptCode::asCScriptCode() { - lineOffset = 0; - code = 0; - codeLength = 0; - sharedCode = false; + lineOffset = 0; + code = 0; + codeLength = 0; + sharedCode = false; } asCScriptCode::~asCScriptCode() { - if( !sharedCode && code ) - { - asDELETEARRAY(code); - } + if( !sharedCode && code ) + { + asDELETEARRAY(code); + } } int asCScriptCode::SetCode(const char *in_name, const char *in_code, bool in_makeCopy) { - return SetCode(in_name, in_code, 0, in_makeCopy); + return SetCode(in_name, in_code, 0, in_makeCopy); } int asCScriptCode::SetCode(const char *in_name, const char *in_code, size_t in_length, bool in_makeCopy) { - if( !in_code) return asINVALID_ARG; - this->name = in_name ? in_name : ""; - if( !sharedCode && code ) - asDELETEARRAY(code); - - if( in_length == 0 ) - in_length = strlen(in_code); - if( in_makeCopy ) - { - codeLength = in_length; - sharedCode = false; - code = asNEWARRAY(char, in_length); - if( code == 0 ) - return asOUT_OF_MEMORY; - memcpy(code, in_code, in_length); - } - else - { - codeLength = in_length; - code = const_cast(in_code); - sharedCode = true; - } - - // Find the positions of each line - linePositions.PushLast(0); - for( size_t n = 0; n < in_length; n++ ) - if( in_code[n] == '\n' ) linePositions.PushLast(n+1); - linePositions.PushLast(in_length); - - return asSUCCESS; + if( !in_code) return asINVALID_ARG; + this->name = in_name ? in_name : ""; + if( !sharedCode && code ) + asDELETEARRAY(code); + + if( in_length == 0 ) + in_length = strlen(in_code); + if( in_makeCopy ) + { + codeLength = in_length; + sharedCode = false; + code = asNEWARRAY(char, in_length); + if( code == 0 ) + return asOUT_OF_MEMORY; + memcpy(code, in_code, in_length); + } + else + { + codeLength = in_length; + code = const_cast(in_code); + sharedCode = true; + } + + // Find the positions of each line + linePositions.PushLast(0); + for( size_t n = 0; n < in_length; n++ ) + if( in_code[n] == '\n' ) linePositions.PushLast(n+1); + linePositions.PushLast(in_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; + 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; + 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/src/angelscript/source/as_scriptcode.h b/src/angelscript/source/as_scriptcode.h index be1af3be609..df3b8862d29 100644 --- a/src/angelscript/source/as_scriptcode.h +++ b/src/angelscript/source/as_scriptcode.h @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -48,23 +48,23 @@ BEGIN_AS_NAMESPACE class asCScriptCode { public: - asCScriptCode(); - ~asCScriptCode(); + 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); + 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); + void ConvertPosToRowCol(size_t pos, int *row, int *col); - bool TokenEquals(size_t pos, size_t len, const char *str); + 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; + asCString name; + char *code; + size_t codeLength; + bool sharedCode; + int idx; + int lineOffset; + asCArray linePositions; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_scriptengine.cpp b/src/angelscript/source/as_scriptengine.cpp index d8aa274100e..d1519ddcca5 100644 --- a/src/angelscript/source/as_scriptengine.cpp +++ b/src/angelscript/source/as_scriptengine.cpp @@ -71,202 +71,202 @@ extern "C" AS_API const char * asGetLibraryVersion() { #ifdef _DEBUG - return ANGELSCRIPT_VERSION_STRING " DEBUG"; + return ANGELSCRIPT_VERSION_STRING " DEBUG"; #else - return ANGELSCRIPT_VERSION_STRING; + return ANGELSCRIPT_VERSION_STRING; #endif } AS_API const char * asGetLibraryOptions() { - const char *string = " " + const char *string = " " - // Options + // Options #ifdef AS_MAX_PORTABILITY - "AS_MAX_PORTABILITY " + "AS_MAX_PORTABILITY " #endif #ifdef AS_DEBUG - "AS_DEBUG " + "AS_DEBUG " #endif #ifdef AS_NO_CLASS_METHODS - "AS_NO_CLASS_METHODS " + "AS_NO_CLASS_METHODS " #endif #ifdef AS_USE_DOUBLE_AS_FLOAT - "AS_USE_DOUBLE_AS_FLOAT " + "AS_USE_DOUBLE_AS_FLOAT " #endif #ifdef AS_64BIT_PTR - "AS_64BIT_PTR " + "AS_64BIT_PTR " #endif #ifdef AS_NO_THREADS - "AS_NO_THREADS " + "AS_NO_THREADS " #endif #ifdef AS_NO_ATOMIC - "AS_NO_ATOMIC " + "AS_NO_ATOMIC " #endif #ifdef AS_NO_COMPILER - "AS_NO_COMPILER " + "AS_NO_COMPILER " #endif #ifdef AS_NO_MEMBER_INIT - "AS_NO_MEMBER_INIT " + "AS_NO_MEMBER_INIT " #endif #ifdef AS_NO_THISCALL_FUNCTOR_METHOD - "AS_NO_THISCALL_FUNCTOR_METHOD " + "AS_NO_THISCALL_FUNCTOR_METHOD " #endif #ifdef AS_NO_EXCEPTIONS - "AS_NO_EXCEPTIONS " + "AS_NO_EXCEPTIONS " #endif #ifdef WIP_16BYTE_ALIGN - "WIP_16BYTE_ALIGN " + "WIP_16BYTE_ALIGN " #endif #ifdef AS_BIG_ENDIAN - "AS_BIG_ENDIAN " + "AS_BIG_ENDIAN " #endif - // Target system + // Target system #ifdef AS_WIN - "AS_WIN " + "AS_WIN " #endif #ifdef AS_LINUX - "AS_LINUX " + "AS_LINUX " #endif #ifdef AS_MAC - "AS_MAC " + "AS_MAC " #endif #ifdef AS_SUN - "AS_SUN " + "AS_SUN " #endif #ifdef AS_BSD - "AS_BSD " + "AS_BSD " #endif #ifdef AS_XBOX - "AS_XBOX " + "AS_XBOX " #endif #ifdef AS_XBOX360 - "AS_XBOX360 " + "AS_XBOX360 " #endif #ifdef AS_PSP - "AS_PSP " + "AS_PSP " #endif #ifdef AS_PS2 - "AS_PS2 " + "AS_PS2 " #endif #ifdef AS_PS3 - "AS_PS3 " + "AS_PS3 " #endif #ifdef AS_PSVITA - "AS_PSVITA " + "AS_PSVITA " #endif #ifdef AS_DC - "AS_DC " + "AS_DC " #endif #ifdef AS_GC - "AS_GC " + "AS_GC " #endif #ifdef AS_WII - "AS_WII " + "AS_WII " #endif #ifdef AS_WIIU - "AS_WIIU " + "AS_WIIU " #endif #ifdef AS_IPHONE - "AS_IPHONE " + "AS_IPHONE " #endif #ifdef AS_ANDROID - "AS_ANDROID " + "AS_ANDROID " #endif #ifdef AS_HAIKU - "AS_HAIKU " + "AS_HAIKU " #endif #ifdef AS_ILLUMOS - "AS_ILLUMOS " + "AS_ILLUMOS " #endif #ifdef AS_MARMALADE - "AS_MARMALADE " + "AS_MARMALADE " #endif - // CPU family + // CPU family #ifdef AS_PPC - "AS_PPC " + "AS_PPC " #endif #ifdef AS_PPC_64 - "AS_PPC_64 " + "AS_PPC_64 " #endif #ifdef AS_X86 - "AS_X86 " + "AS_X86 " #endif #ifdef AS_MIPS - "AS_MIPS " + "AS_MIPS " #endif #ifdef AS_SH4 - "AS_SH4 " + "AS_SH4 " #endif #ifdef AS_XENON - "AS_XENON " + "AS_XENON " #endif #ifdef AS_ARM - "AS_ARM " + "AS_ARM " #endif #ifdef AS_SOFTFP - "AS_SOFTFP " + "AS_SOFTFP " #endif #ifdef AS_X64_GCC - "AS_X64_GCC " + "AS_X64_GCC " #endif #ifdef AS_X64_MSVC - "AS_X64_MSVC " + "AS_X64_MSVC " #endif #ifdef AS_SPARC - "AS_SPARC " + "AS_SPARC " #endif #ifdef AS_ARM64 - "AS_ARM64 " + "AS_ARM64 " #endif - ; + ; - return string; + return string; } AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version) { - // Verify the version that the application expects - if( (version/10000) != (ANGELSCRIPT_VERSION/10000) ) - return 0; + // 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)%100 != (ANGELSCRIPT_VERSION/100)%100 ) + return 0; - if( (version%100) > (ANGELSCRIPT_VERSION%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 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 the boolean type + asASSERT( sizeof(bool) == AS_SIZEOF_BOOL ); + asASSERT( true == VALUE_OF_BOOLEAN_TRUE ); - // Verify endianess + // Verify endianess #ifdef AS_BIG_ENDIAN - asDWORD dw = 0x00010203; - asQWORD qw = ((asQWORD(0x00010203)<<32)|asQWORD(0x04050607)); + 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)); + 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); + 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)(); + return asNEW(asCScriptEngine)(); } } // extern "C" @@ -275,2816 +275,2816 @@ AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version) // 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; - } - else - { - // The size is given in bytes, but we only store dwords - ep.maximumContextStackSize = (asUINT)value/4; - } - break; - - case asEP_INIT_STACK_SIZE: - if (value < 4) - { - // At least one dword - ep.initContextStackSize = 1; - } - else - { - // The size is given in bytes, but we only store dwords - ep.initContextStackSize = (asUINT)value / 4; - } - break; - - 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 <= 3 ) - 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; - - case asEP_DISALLOW_EMPTY_LIST_ELEMENTS: - ep.disallowEmptyListElements = value ? true : false; - break; - - case asEP_PRIVATE_PROP_AS_PROTECTED: - ep.privatePropAsProtected = value ? true : false; - break; - - case asEP_ALLOW_UNICODE_IDENTIFIERS: - ep.allowUnicodeIdentifiers = value ? true : false; - break; - - case asEP_HEREDOC_TRIM_MODE: - if (value <= 2) - ep.heredocTrimMode = (int)value; - else - return asINVALID_ARG; - break; - - case asEP_MAX_NESTED_CALLS: - if (value > 0xFFFFFFFF) - ep.maxNestedCalls = 0xFFFFFFFF; - else - ep.maxNestedCalls = (asUINT)value; - break; - - case asEP_GENERIC_CALL_MODE: - if (value > 1) - ep.genericCallMode = 1; - else - ep.genericCallMode = (asUINT)value; - break; - - case asEP_INIT_CALL_STACK_SIZE: - ep.initCallStackSize = (asUINT)value; - break; - - case asEP_MAX_CALL_STACK_SIZE: - ep.maxCallStackSize = (asUINT)value; - break; - - default: - return asINVALID_ARG; - } - - return asSUCCESS; + 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; + } + else + { + // The size is given in bytes, but we only store dwords + ep.maximumContextStackSize = (asUINT)value/4; + } + break; + + case asEP_INIT_STACK_SIZE: + if (value < 4) + { + // At least one dword + ep.initContextStackSize = 1; + } + else + { + // The size is given in bytes, but we only store dwords + ep.initContextStackSize = (asUINT)value / 4; + } + break; + + 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 <= 3 ) + 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; + + case asEP_DISALLOW_EMPTY_LIST_ELEMENTS: + ep.disallowEmptyListElements = value ? true : false; + break; + + case asEP_PRIVATE_PROP_AS_PROTECTED: + ep.privatePropAsProtected = value ? true : false; + break; + + case asEP_ALLOW_UNICODE_IDENTIFIERS: + ep.allowUnicodeIdentifiers = value ? true : false; + break; + + case asEP_HEREDOC_TRIM_MODE: + if (value <= 2) + ep.heredocTrimMode = (int)value; + else + return asINVALID_ARG; + break; + + case asEP_MAX_NESTED_CALLS: + if (value > 0xFFFFFFFF) + ep.maxNestedCalls = 0xFFFFFFFF; + else + ep.maxNestedCalls = (asUINT)value; + break; + + case asEP_GENERIC_CALL_MODE: + if (value > 1) + ep.genericCallMode = 1; + else + ep.genericCallMode = (asUINT)value; + break; + + case asEP_INIT_CALL_STACK_SIZE: + ep.initCallStackSize = (asUINT)value; + break; + + case asEP_MAX_CALL_STACK_SIZE: + ep.maxCallStackSize = (asUINT)value; + break; + + default: + return asINVALID_ARG; + } + + return asSUCCESS; } // interface asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const { - switch( property ) - { - case asEP_ALLOW_UNSAFE_REFERENCES: - return ep.allowUnsafeReferences; + switch( property ) + { + case asEP_ALLOW_UNSAFE_REFERENCES: + return ep.allowUnsafeReferences; - case asEP_OPTIMIZE_BYTECODE: - return ep.optimizeByteCode; + case asEP_OPTIMIZE_BYTECODE: + return ep.optimizeByteCode; - case asEP_COPY_SCRIPT_SECTIONS: - return ep.copyScriptSections; + case asEP_COPY_SCRIPT_SECTIONS: + return ep.copyScriptSections; - case asEP_MAX_STACK_SIZE: - return ep.maximumContextStackSize * 4; + case asEP_MAX_STACK_SIZE: + return ep.maximumContextStackSize * 4; - case asEP_INIT_STACK_SIZE: - return ep.initContextStackSize * 4; + case asEP_INIT_STACK_SIZE: + return ep.initContextStackSize * 4; - case asEP_USE_CHARACTER_LITERALS: - return ep.useCharacterLiterals; + case asEP_USE_CHARACTER_LITERALS: + return ep.useCharacterLiterals; - case asEP_ALLOW_MULTILINE_STRINGS: - return ep.allowMultilineStrings; + case asEP_ALLOW_MULTILINE_STRINGS: + return ep.allowMultilineStrings; - case asEP_ALLOW_IMPLICIT_HANDLE_TYPES: - return ep.allowImplicitHandleTypes; + case asEP_ALLOW_IMPLICIT_HANDLE_TYPES: + return ep.allowImplicitHandleTypes; - case asEP_BUILD_WITHOUT_LINE_CUES: - return ep.buildWithoutLineCues; + case asEP_BUILD_WITHOUT_LINE_CUES: + return ep.buildWithoutLineCues; - case asEP_INIT_GLOBAL_VARS_AFTER_BUILD: - return ep.initGlobalVarsAfterBuild; + case asEP_INIT_GLOBAL_VARS_AFTER_BUILD: + return ep.initGlobalVarsAfterBuild; - case asEP_REQUIRE_ENUM_SCOPE: - return ep.requireEnumScope; + case asEP_REQUIRE_ENUM_SCOPE: + return ep.requireEnumScope; - case asEP_SCRIPT_SCANNER: - return ep.scanner; + case asEP_SCRIPT_SCANNER: + return ep.scanner; - case asEP_INCLUDE_JIT_INSTRUCTIONS: - return ep.includeJitInstructions; + case asEP_INCLUDE_JIT_INSTRUCTIONS: + return ep.includeJitInstructions; - case asEP_STRING_ENCODING: - return ep.stringEncoding; + case asEP_STRING_ENCODING: + return ep.stringEncoding; - case asEP_PROPERTY_ACCESSOR_MODE: - return ep.propertyAccessorMode; + case asEP_PROPERTY_ACCESSOR_MODE: + return ep.propertyAccessorMode; - case asEP_EXPAND_DEF_ARRAY_TO_TMPL: - return ep.expandDefaultArrayToTemplate; + case asEP_EXPAND_DEF_ARRAY_TO_TMPL: + return ep.expandDefaultArrayToTemplate; - case asEP_AUTO_GARBAGE_COLLECT: - return ep.autoGarbageCollect; + case asEP_AUTO_GARBAGE_COLLECT: + return ep.autoGarbageCollect; - case asEP_DISALLOW_GLOBAL_VARS: - return ep.disallowGlobalVars; + case asEP_DISALLOW_GLOBAL_VARS: + return ep.disallowGlobalVars; - case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT: - return ep.alwaysImplDefaultConstruct; + case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT: + return ep.alwaysImplDefaultConstruct; - case asEP_COMPILER_WARNINGS: - return ep.compilerWarnings; + case asEP_COMPILER_WARNINGS: + return ep.compilerWarnings; - case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE: - return ep.disallowValueAssignForRefType; + case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE: + return ep.disallowValueAssignForRefType; - case asEP_ALTER_SYNTAX_NAMED_ARGS: - return ep.alterSyntaxNamedArgs; + case asEP_ALTER_SYNTAX_NAMED_ARGS: + return ep.alterSyntaxNamedArgs; - case asEP_DISABLE_INTEGER_DIVISION: - return ep.disableIntegerDivision; + case asEP_DISABLE_INTEGER_DIVISION: + return ep.disableIntegerDivision; - case asEP_DISALLOW_EMPTY_LIST_ELEMENTS: - return ep.disallowEmptyListElements; + case asEP_DISALLOW_EMPTY_LIST_ELEMENTS: + return ep.disallowEmptyListElements; - case asEP_PRIVATE_PROP_AS_PROTECTED: - return ep.privatePropAsProtected; + case asEP_PRIVATE_PROP_AS_PROTECTED: + return ep.privatePropAsProtected; - case asEP_ALLOW_UNICODE_IDENTIFIERS: - return ep.allowUnicodeIdentifiers; + case asEP_ALLOW_UNICODE_IDENTIFIERS: + return ep.allowUnicodeIdentifiers; - case asEP_HEREDOC_TRIM_MODE: - return ep.heredocTrimMode; + case asEP_HEREDOC_TRIM_MODE: + return ep.heredocTrimMode; - case asEP_MAX_NESTED_CALLS: - return ep.maxNestedCalls; + case asEP_MAX_NESTED_CALLS: + return ep.maxNestedCalls; - case asEP_GENERIC_CALL_MODE: - return ep.genericCallMode; + case asEP_GENERIC_CALL_MODE: + return ep.genericCallMode; - case asEP_INIT_CALL_STACK_SIZE: - return ep.initCallStackSize; + case asEP_INIT_CALL_STACK_SIZE: + return ep.initCallStackSize; - case asEP_MAX_CALL_STACK_SIZE: - return ep.maxCallStackSize; + case asEP_MAX_CALL_STACK_SIZE: + return ep.maxCallStackSize; - default: - return 0; - } + default: + return 0; + } - UNREACHABLE_RETURN; + UNREACHABLE_RETURN; } // interface asIScriptFunction *asCScriptEngine::CreateDelegate(asIScriptFunction *func, void *obj) { - if( func == 0 || obj == 0 ) - return 0; + if( func == 0 || obj == 0 ) + return 0; - // The function must be a class method - asITypeInfo *type = func->GetObjectType(); - if( type == 0 ) - return 0; + // The function must be a class method + asITypeInfo *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; + // 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); + // 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; - inDestructor = false; - - // Engine properties - { - ep.allowUnsafeReferences = false; - ep.optimizeByteCode = true; - ep.copyScriptSections = true; - ep.maximumContextStackSize = 0; // no limit - ep.initContextStackSize = 1024; // 4KB default init stack size - ep.useCharacterLiterals = false; - ep.allowMultilineStrings = false; - ep.allowImplicitHandleTypes = false; - // 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 = 3; // 0 = disable, 1 = app registered only, 2 = app and script created, 3 = flag with 'property' - 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; - ep.disallowEmptyListElements = false; - ep.privatePropAsProtected = false; - ep.allowUnicodeIdentifiers = false; - ep.heredocTrimMode = 1; // 0 = never trim, 1 = don't trim on single line, 2 = trim initial and final empty line - ep.maxNestedCalls = 100; - ep.genericCallMode = 1; // 0 = old (pre 2.33.0) behavior where generic ignored auto handles, 1 = treat handles like in native call - ep.initCallStackSize = 10; // 10 levels of calls - ep.maxCallStackSize = 0; // 0 = no limit - } - - gc.engine = this; - tok.engine = this; - - refCount.set(1); - stringFactory = 0; - configFailed = false; - isPrepared = false; - isBuilding = false; - deferValidationOfTemplateTypes = false; - lastModule = 0; - - typeIdSeqNbr = 0; - currentGroup = &defaultGroup; - defaultAccessMask = 0xFFFFFFFF; // All bits set so that built-in functions/types will be available to all modules - - 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; - - // Reserve function id 0 for no function - scriptFunctions.PushLast(0); - - // Reserve the first typeIds for the primitive types - typeIdSeqNbr = asTYPEID_DOUBLE + 1; - - // Make sure typeId for the built-in primitives are defined according to asETypeIdFlags - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)) == asTYPEID_VOID ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)) == asTYPEID_BOOL ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)) == asTYPEID_INT8 ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)) == asTYPEID_INT16 ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)) == asTYPEID_INT32 ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)) == asTYPEID_INT64 ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)) == asTYPEID_UINT8 ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)) == asTYPEID_UINT16 ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)) == asTYPEID_UINT32 ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)) == asTYPEID_UINT64 ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)) == asTYPEID_FLOAT ); - asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)) == asTYPEID_DOUBLE ); - - defaultArrayObjectType = 0; - - RegisterScriptObject(this); - RegisterScriptFunction(this); + asCThreadManager::Prepare(0); + + shuttingDown = false; + inDestructor = false; + + // Engine properties + { + ep.allowUnsafeReferences = false; + ep.optimizeByteCode = true; + ep.copyScriptSections = true; + ep.maximumContextStackSize = 0; // no limit + ep.initContextStackSize = 1024; // 4KB default init stack size + ep.useCharacterLiterals = false; + ep.allowMultilineStrings = false; + ep.allowImplicitHandleTypes = false; + // 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 = 3; // 0 = disable, 1 = app registered only, 2 = app and script created, 3 = flag with 'property' + 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; + ep.disallowEmptyListElements = false; + ep.privatePropAsProtected = false; + ep.allowUnicodeIdentifiers = false; + ep.heredocTrimMode = 1; // 0 = never trim, 1 = don't trim on single line, 2 = trim initial and final empty line + ep.maxNestedCalls = 100; + ep.genericCallMode = 1; // 0 = old (pre 2.33.0) behavior where generic ignored auto handles, 1 = treat handles like in native call + ep.initCallStackSize = 10; // 10 levels of calls + ep.maxCallStackSize = 0; // 0 = no limit + } + + gc.engine = this; + tok.engine = this; + + refCount.set(1); + stringFactory = 0; + configFailed = false; + isPrepared = false; + isBuilding = false; + deferValidationOfTemplateTypes = false; + lastModule = 0; + + typeIdSeqNbr = 0; + currentGroup = &defaultGroup; + defaultAccessMask = 0xFFFFFFFF; // All bits set so that built-in functions/types will be available to all modules + + 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; + + // Reserve function id 0 for no function + scriptFunctions.PushLast(0); + + // Reserve the first typeIds for the primitive types + typeIdSeqNbr = asTYPEID_DOUBLE + 1; + + // Make sure typeId for the built-in primitives are defined according to asETypeIdFlags + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)) == asTYPEID_VOID ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)) == asTYPEID_BOOL ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)) == asTYPEID_INT8 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)) == asTYPEID_INT16 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)) == asTYPEID_INT32 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)) == asTYPEID_INT64 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)) == asTYPEID_UINT8 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)) == asTYPEID_UINT16 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)) == asTYPEID_UINT32 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)) == asTYPEID_UINT64 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)) == asTYPEID_FLOAT ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)) == asTYPEID_DOUBLE ); + + defaultArrayObjectType = 0; + + RegisterScriptObject(this); + RegisterScriptFunction(this); #ifndef AS_NO_EXCEPTIONS - translateExceptionCallback = false; + translateExceptionCallback = false; #endif } void asCScriptEngine::DeleteDiscardedModules() { - // TODO: redesign: Prevent more than one thread from entering this function at the same time. - // If a thread is already doing the work for the clean-up the other thread should - // simply return, as the first thread will continue. - - ACQUIRESHARED(engineRWLock); - asUINT maxCount = discardedModules.GetLength(); - RELEASESHARED(engineRWLock); - - for( asUINT n = 0; n < maxCount; n++ ) - { - ACQUIRESHARED(engineRWLock); - asCModule *mod = discardedModules[n]; - RELEASESHARED(engineRWLock); - - if( !mod->HasExternalReferences(shuttingDown) ) - { - asDELETE(mod, asCModule); - n--; - } - - ACQUIRESHARED(engineRWLock); - // Determine the max count again, since another module may have been discarded during the processing - maxCount = discardedModules.GetLength(); - RELEASESHARED(engineRWLock); - } - - // Go over the list of global properties, to see if it is possible to clean - // up some variables that are no longer referred to by any functions - for( asUINT n = 0; n < globalProperties.GetLength(); n++ ) - { - asCGlobalProperty *prop = globalProperties[n]; - if( prop && prop->refCount.get() == 1 ) - RemoveGlobalProperty(prop); - } + // TODO: redesign: Prevent more than one thread from entering this function at the same time. + // If a thread is already doing the work for the clean-up the other thread should + // simply return, as the first thread will continue. + + ACQUIRESHARED(engineRWLock); + asUINT maxCount = discardedModules.GetLength(); + RELEASESHARED(engineRWLock); + + for( asUINT n = 0; n < maxCount; n++ ) + { + ACQUIRESHARED(engineRWLock); + asCModule *mod = discardedModules[n]; + RELEASESHARED(engineRWLock); + + if( !mod->HasExternalReferences(shuttingDown) ) + { + asDELETE(mod, asCModule); + n--; + } + + ACQUIRESHARED(engineRWLock); + // Determine the max count again, since another module may have been discarded during the processing + maxCount = discardedModules.GetLength(); + RELEASESHARED(engineRWLock); + } + + // Go over the list of global properties, to see if it is possible to clean + // up some variables that are no longer referred to by any functions + for( asUINT n = 0; n < globalProperties.GetLength(); n++ ) + { + asCGlobalProperty *prop = globalProperties[n]; + if( prop && prop->refCount.get() == 1 ) + RemoveGlobalProperty(prop); + } } asCScriptEngine::~asCScriptEngine() { - // TODO: clean-up: Clean up redundant code - - inDestructor = true; - - asASSERT(refCount.get() == 0); - - // If ShutDown hasn't been called yet do it now - if( !shuttingDown ) - { - AddRef(); - ShutDownAndRelease(); - } - - // Unravel the registered interface - if( defaultArrayObjectType ) - { - defaultArrayObjectType->ReleaseInternal(); - defaultArrayObjectType = 0; - } - - // Delete the functions for generated template types that may references object types - for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) - { - asCObjectType *templateType = generatedTemplateTypes[n]; - if( templateType ) - templateType->DestroyInternal(); - } - for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) - { - asCObjectType *type = listPatternTypes[n]; - if( type ) - type->ReleaseInternal(); - } - listPatternTypes.SetLength(0); - - // No script types must have survived - asASSERT( sharedScriptTypes.GetLength() == 0 ); - - // 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); - - mapTypeIdToTypeInfo.EraseAll(); - - // 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); - - // Any remaining objects in templateInstanceTypes is from generated template instances - for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ ) - { - asCObjectType *templateType = templateInstanceTypes[n]; - if( templateInstanceTypes[n] ) - templateType->ReleaseInternal(); - } - templateInstanceTypes.SetLength(0); - - asCSymbolTable::iterator it = registeredGlobalProps.List(); - for( ; it; it++ ) - { - RemoveGlobalProperty(*it); - (*it)->Release(); - } - registeredGlobalProps.Clear(); - - for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ ) - { - if( templateSubTypes[n] ) - { - templateSubTypes[n]->DestroyInternal(); - templateSubTypes[n]->ReleaseInternal(); - } - } - templateSubTypes.SetLength(0); - registeredTypeDefs.SetLength(0); - registeredEnums.SetLength(0); - registeredObjTypes.SetLength(0); - - asCSymbolTable::iterator funcIt = registeredGlobalFuncs.List(); - for( ; funcIt; funcIt++ ) - (*funcIt)->ReleaseInternal(); - registeredGlobalFuncs.Clear(); - - scriptTypeBehaviours.ReleaseAllFunctions(); - functionBehaviours.ReleaseAllFunctions(); - - for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ ) - if( scriptFunctions[n] ) - { - scriptFunctions[n]->DestroyInternal(); - - // Set the engine pointer to null to signal that the function is no longer part of the engine - scriptFunctions[n]->engine = 0; - } - scriptFunctions.SetLength(0); - - // Increase the internal ref count for these builtin object types, so the destructor is not called incorrectly - scriptTypeBehaviours.AddRefInternal(); - functionBehaviours.AddRefInternal(); - - // Destroy the funcdefs - // As funcdefs are shared between modules it shouldn't be a problem to keep the objects until the engine is released - for( asUINT n = 0; n < funcDefs.GetLength(); n++ ) - if( funcDefs[n] ) - { - funcDefs[n]->DestroyInternal(); - funcDefs[n]->ReleaseInternal(); - } - funcDefs.SetLength(0); - - // Free the global properties - for( asUINT n = 0; n < globalProperties.GetLength(); n++ ) - { - asCGlobalProperty *prop = globalProperties[n]; - if( prop ) - { - asASSERT( prop->refCount.get() == 1 ); - RemoveGlobalProperty(prop); - } - } - - // Free the script section names - for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ ) - asDELETE(scriptSectionNames[n],asCString); - scriptSectionNames.SetLength(0); - - // Clean the user data - for( asUINT 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( asUINT n = 0; n < nameSpaces.GetLength(); n++ ) - asDELETE(nameSpaces[n], asSNameSpace); - nameSpaces.SetLength(0); - - asCThreadManager::Unprepare(); + // TODO: clean-up: Clean up redundant code + + inDestructor = true; + + asASSERT(refCount.get() == 0); + + // If ShutDown hasn't been called yet do it now + if( !shuttingDown ) + { + AddRef(); + ShutDownAndRelease(); + } + + // Unravel the registered interface + if( defaultArrayObjectType ) + { + defaultArrayObjectType->ReleaseInternal(); + defaultArrayObjectType = 0; + } + + // Delete the functions for generated template types that may references object types + for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) + { + asCObjectType *templateType = generatedTemplateTypes[n]; + if( templateType ) + templateType->DestroyInternal(); + } + for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) + { + asCObjectType *type = listPatternTypes[n]; + if( type ) + type->ReleaseInternal(); + } + listPatternTypes.SetLength(0); + + // No script types must have survived + asASSERT( sharedScriptTypes.GetLength() == 0 ); + + // 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); + + mapTypeIdToTypeInfo.EraseAll(); + + // 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); + + // Any remaining objects in templateInstanceTypes is from generated template instances + for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ ) + { + asCObjectType *templateType = templateInstanceTypes[n]; + if( templateInstanceTypes[n] ) + templateType->ReleaseInternal(); + } + templateInstanceTypes.SetLength(0); + + asCSymbolTable::iterator it = registeredGlobalProps.List(); + for( ; it; it++ ) + { + RemoveGlobalProperty(*it); + (*it)->Release(); + } + registeredGlobalProps.Clear(); + + for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ ) + { + if( templateSubTypes[n] ) + { + templateSubTypes[n]->DestroyInternal(); + templateSubTypes[n]->ReleaseInternal(); + } + } + templateSubTypes.SetLength(0); + registeredTypeDefs.SetLength(0); + registeredEnums.SetLength(0); + registeredObjTypes.SetLength(0); + + asCSymbolTable::iterator funcIt = registeredGlobalFuncs.List(); + for( ; funcIt; funcIt++ ) + (*funcIt)->ReleaseInternal(); + registeredGlobalFuncs.Clear(); + + scriptTypeBehaviours.ReleaseAllFunctions(); + functionBehaviours.ReleaseAllFunctions(); + + for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ ) + if( scriptFunctions[n] ) + { + scriptFunctions[n]->DestroyInternal(); + + // Set the engine pointer to null to signal that the function is no longer part of the engine + scriptFunctions[n]->engine = 0; + } + scriptFunctions.SetLength(0); + + // Increase the internal ref count for these builtin object types, so the destructor is not called incorrectly + scriptTypeBehaviours.AddRefInternal(); + functionBehaviours.AddRefInternal(); + + // Destroy the funcdefs + // As funcdefs are shared between modules it shouldn't be a problem to keep the objects until the engine is released + for( asUINT n = 0; n < funcDefs.GetLength(); n++ ) + if( funcDefs[n] ) + { + funcDefs[n]->DestroyInternal(); + funcDefs[n]->ReleaseInternal(); + } + funcDefs.SetLength(0); + + // Free the global properties + for( asUINT n = 0; n < globalProperties.GetLength(); n++ ) + { + asCGlobalProperty *prop = globalProperties[n]; + if( prop ) + { + asASSERT( prop->refCount.get() == 1 ); + RemoveGlobalProperty(prop); + } + } + + // Free the script section names + for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ ) + asDELETE(scriptSectionNames[n],asCString); + scriptSectionNames.SetLength(0); + + // Clean the user data + for( asUINT 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( asUINT n = 0; n < nameSpaces.GetLength(); n++ ) + asDELETE(nameSpaces[n], asSNameSpace); + nameSpaces.SetLength(0); + + asCThreadManager::Unprepare(); } // 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; + // 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; + requestCtxFunc = requestCtx; + returnCtxFunc = returnCtx; + ctxCallbackParam = param; - return 0; + return 0; } // interface asIScriptContext *asCScriptEngine::RequestContext() { - if( requestCtxFunc ) - { - // The return callback must also exist - asASSERT( returnCtxFunc ); + if( requestCtxFunc ) + { + // The return callback must also exist + asASSERT( returnCtxFunc ); - asIScriptContext *ctx = requestCtxFunc(this, ctxCallbackParam); - return ctx; - } + asIScriptContext *ctx = requestCtxFunc(this, ctxCallbackParam); + return ctx; + } - // As fallback we create a new context - return CreateContext(); + // As fallback we create a new context + return CreateContext(); } // internal asCModule *asCScriptEngine::FindNewOwnerForSharedType(asCTypeInfo *in_type, asCModule *in_mod) { - asASSERT( in_type->IsShared() ); - - if( in_type->module != in_mod) - return in_type->module; - - for( asUINT n = 0; n < scriptModules.GetLength(); n++ ) - { - // TODO: optimize: If the modules already stored the shared types separately, this would be quicker - int foundIdx = -1; - asCModule *mod = scriptModules[n]; - if( mod == in_type->module ) continue; - if( in_type->flags & asOBJ_ENUM ) - foundIdx = mod->m_enumTypes.IndexOf(CastToEnumType(in_type)); - else if (in_type->flags & asOBJ_TYPEDEF) - foundIdx = mod->m_typeDefs.IndexOf(CastToTypedefType(in_type)); - else if (in_type->flags & asOBJ_FUNCDEF) - foundIdx = mod->m_funcDefs.IndexOf(CastToFuncdefType(in_type)); - else if (in_type->flags & asOBJ_TEMPLATE) - foundIdx = mod->m_templateInstances.IndexOf(CastToObjectType(in_type)); - else - foundIdx = mod->m_classTypes.IndexOf(CastToObjectType(in_type)); - - if( foundIdx >= 0 ) - { - in_type->module = mod; - break; - } - } - - return in_type->module; + asASSERT( in_type->IsShared() ); + + if( in_type->module != in_mod) + return in_type->module; + + for( asUINT n = 0; n < scriptModules.GetLength(); n++ ) + { + // TODO: optimize: If the modules already stored the shared types separately, this would be quicker + int foundIdx = -1; + asCModule *mod = scriptModules[n]; + if( mod == in_type->module ) continue; + if( in_type->flags & asOBJ_ENUM ) + foundIdx = mod->m_enumTypes.IndexOf(CastToEnumType(in_type)); + else if (in_type->flags & asOBJ_TYPEDEF) + foundIdx = mod->m_typeDefs.IndexOf(CastToTypedefType(in_type)); + else if (in_type->flags & asOBJ_FUNCDEF) + foundIdx = mod->m_funcDefs.IndexOf(CastToFuncdefType(in_type)); + else if (in_type->flags & asOBJ_TEMPLATE) + foundIdx = mod->m_templateInstances.IndexOf(CastToObjectType(in_type)); + else + foundIdx = mod->m_classTypes.IndexOf(CastToObjectType(in_type)); + + if( foundIdx >= 0 ) + { + in_type->module = mod; + break; + } + } + + return in_type->module; } // internal asCModule *asCScriptEngine::FindNewOwnerForSharedFunc(asCScriptFunction *in_func, asCModule *in_mod) { - asASSERT( in_func->IsShared() ); - asASSERT(!(in_func->funcType & asFUNC_FUNCDEF)); - - if( in_func->module != in_mod) - return in_func->module; - - if (in_func->objectType && in_func->objectType->module && - in_func->objectType->module != in_func->module) - { - // The object type for the method has already been transferred to - // another module, so transfer the method to the same module - in_func->module = in_func->objectType->module; - - // Make sure the function is listed in the module - // The compiler may not have done this earlier, since the object - // type is shared and originally compiled from another module - if (in_func->module->m_scriptFunctions.IndexOf(in_func) < 0) - { - in_func->module->m_scriptFunctions.PushLast(in_func); - in_func->AddRefInternal(); - } - } - - for( asUINT n = 0; n < scriptModules.GetLength(); n++ ) - { - // TODO: optimize: If the modules already stored the shared types separately, this would be quicker - int foundIdx = -1; - asCModule *mod = scriptModules[n]; - if( mod == in_func->module ) continue; - foundIdx = mod->m_scriptFunctions.IndexOf(in_func); - - if( foundIdx >= 0 ) - { - in_func->module = mod; - break; - } - } - - return in_func->module; + asASSERT( in_func->IsShared() ); + asASSERT(!(in_func->funcType & asFUNC_FUNCDEF)); + + if( in_func->module != in_mod) + return in_func->module; + + if (in_func->objectType && in_func->objectType->module && + in_func->objectType->module != in_func->module) + { + // The object type for the method has already been transferred to + // another module, so transfer the method to the same module + in_func->module = in_func->objectType->module; + + // Make sure the function is listed in the module + // The compiler may not have done this earlier, since the object + // type is shared and originally compiled from another module + if (in_func->module->m_scriptFunctions.IndexOf(in_func) < 0) + { + in_func->module->m_scriptFunctions.PushLast(in_func); + in_func->AddRefInternal(); + } + } + + for( asUINT n = 0; n < scriptModules.GetLength(); n++ ) + { + // TODO: optimize: If the modules already stored the shared types separately, this would be quicker + int foundIdx = -1; + asCModule *mod = scriptModules[n]; + if( mod == in_func->module ) continue; + foundIdx = mod->m_scriptFunctions.IndexOf(in_func); + + if( foundIdx >= 0 ) + { + in_func->module = mod; + break; + } + } + + return in_func->module; } // interface void asCScriptEngine::ReturnContext(asIScriptContext *ctx) { - if( returnCtxFunc ) - { - returnCtxFunc(this, ctx, ctxCallbackParam); - return; - } + if( returnCtxFunc ) + { + returnCtxFunc(this, ctx, ctxCallbackParam); + return; + } - // As fallback we just release the context - if( ctx ) - ctx->Release(); + // As fallback we just release the context + if( ctx ) + ctx->Release(); } // interface int asCScriptEngine::AddRef() const { - asASSERT( refCount.get() > 0 || inDestructor ); - return refCount.atomicInc(); + asASSERT( refCount.get() > 0 || inDestructor ); + return refCount.atomicInc(); } // interface int asCScriptEngine::Release() const { - int r = refCount.atomicDec(); + 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( !inDestructor ) - asDELETE(const_cast(this),asCScriptEngine); - return 0; - } + 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( !inDestructor ) + asDELETE(const_cast(this),asCScriptEngine); + return 0; + } - return r; + return r; } // interface int asCScriptEngine::ShutDownAndRelease() { - // Do a full garbage collection cycle to clean up any object that may still hold on to the engine - GarbageCollect(); + // Do a full garbage collection cycle to clean up any object that may still hold on to the engine + GarbageCollect(); - // Set the flag that the engine is being shutdown now. This will speed up - // the process, and will also allow the engine to warn about invalid calls - shuttingDown = true; + // Set the flag that the engine is being shutdown now. This will speed up + // the process, and will also allow the engine to warn about invalid calls + shuttingDown = true; - // 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); + // 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( asUINT n = (asUINT)scriptModules.GetLength(); n-- > 0; ) - if( scriptModules[n] ) - scriptModules[n]->Discard(); - scriptModules.SetLength(0); + // The modules must be deleted first, as they may use + // object types from the config groups + for( asUINT n = (asUINT)scriptModules.GetLength(); n-- > 0; ) + if( scriptModules[n] ) + scriptModules[n]->Discard(); + scriptModules.SetLength(0); - // Do another full garbage collection to destroy the object types/functions - // that may have been placed in the gc when destroying the modules - GarbageCollect(); + // Do another full garbage collection to destroy the object types/functions + // that may have been placed in the gc when destroying the modules + GarbageCollect(); - // Do another sweep to delete discarded modules, that may not have - // been deleted earlier due to still having external references - DeleteDiscardedModules(); + // Do another sweep to delete discarded modules, that may not have + // been deleted earlier due to still having external references + DeleteDiscardedModules(); - // 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. - gc.ReportAndReleaseUndestroyedObjects(); + // 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. + gc.ReportAndReleaseUndestroyedObjects(); - // Release the engine reference - return Release(); + // Release the engine reference + return Release(); } // internal asSNameSpace *asCScriptEngine::AddNameSpace(const char *name) { - // First check if it doesn't exist already - asSNameSpace *ns = FindNameSpace(name); - if( ns ) return ns; + // 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; + ns = asNEW(asSNameSpace); + if( ns == 0 ) + { + // Out of memory + return 0; + } + ns->name = name; - nameSpaces.PushLast(ns); + nameSpaces.PushLast(ns); - return ns; + return ns; } // internal asSNameSpace *asCScriptEngine::FindNameSpace(const char *name) const { - // TODO: optimize: Improve linear search - for( asUINT n = 0; n < nameSpaces.GetLength(); n++ ) - if( nameSpaces[n]->name == name ) - return nameSpaces[n]; + // TODO: optimize: Improve linear search + for( asUINT n = 0; n < nameSpaces.GetLength(); n++ ) + if( nameSpaces[n]->name == name ) + return nameSpaces[n]; - return 0; + return 0; } // interface const char *asCScriptEngine::GetDefaultNamespace() const { - return defaultNamespace->name.AddressOf(); + return defaultNamespace->name.AddressOf(); } // interface int asCScriptEngine::SetDefaultNamespace(const char *nameSpace) { - if( nameSpace == 0 ) - return ConfigError(asINVALID_ARG, "SetDefaultNamespace", nameSpace, 0); + 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; + 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); + 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); - // Make sure parent namespaces are registred in case of nested namespaces - if (expectIdentifier) - AddNameSpace(ns.SubString(0, pos + len).AddressOf()); + // Make sure parent namespaces are registred in case of nested namespaces + if (expectIdentifier) + AddNameSpace(ns.SubString(0, pos + len).AddressOf()); - expectIdentifier = !expectIdentifier; - } + expectIdentifier = !expectIdentifier; + } - // If the namespace ends with :: then strip it off - if( t == ttScope ) - ns.SetLength(ns.GetLength()-2); - } + // If the namespace ends with :: then strip it off + if( t == ttScope ) + ns.SetLength(ns.GetLength()-2); + } - defaultNamespace = AddNameSpace(ns.AddressOf()); + defaultNamespace = AddNameSpace(ns.AddressOf()); - return 0; + 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); + // 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); + // 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); + RELEASEEXCLUSIVE(engineRWLock); - return oldData; - } - } + return oldData; + } + } - userData.PushLast(type); - userData.PushLast(reinterpret_cast(data)); + userData.PushLast(type); + userData.PushLast(reinterpret_cast(data)); - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); - return 0; + 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); + // 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]); - } - } + for( asUINT n = 0; n < userData.GetLength(); n += 2 ) + { + if( userData[n] == type ) + { + RELEASESHARED(engineRWLock); + return reinterpret_cast(userData[n+1]); + } + } - RELEASESHARED(engineRWLock); + RELEASESHARED(engineRWLock); - return 0; + 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; + 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; + 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; + // 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; + jitCompiler = compiler; + return asSUCCESS; } asIJITCompiler *asCScriptEngine::GetJITCompiler() const { - return jitCompiler; + return jitCompiler; } // interface asETokenClass asCScriptEngine::ParseToken(const char *string, size_t stringLength, asUINT *tokenLength) const { - if( stringLength == 0 ) - stringLength = strlen(string); + if( stringLength == 0 ) + stringLength = strlen(string); - size_t len; - asETokenClass tc; - tok.GetToken(string, stringLength, &len, &tc); + size_t len; + asETokenClass tc; + tok.GetToken(string, stringLength, &len, &tc); - if( tokenLength ) - *tokenLength = (asUINT)len; + if( tokenLength ) + *tokenLength = (asUINT)len; - return tc; + return tc; } // interface asIScriptModule *asCScriptEngine::GetModule(const char *module, asEGMFlags flag) { - asCModule *mod = GetModule(module, false); + asCModule *mod = GetModule(module, false); - if( flag == asGM_ALWAYS_CREATE ) - { - if( mod != 0 ) - mod->Discard(); + if( flag == asGM_ALWAYS_CREATE ) + { + if( mod != 0 ) + mod->Discard(); - return GetModule(module, true); - } + return GetModule(module, true); + } - if( mod == 0 && flag == asGM_CREATE_IF_NOT_EXISTS ) - return GetModule(module, true); + if( mod == 0 && flag == asGM_CREATE_IF_NOT_EXISTS ) + return GetModule(module, true); - return mod; + return mod; } // interface int asCScriptEngine::DiscardModule(const char *module) { - asCModule *mod = GetModule(module, false); - if( mod == 0 ) return asNO_MODULE; + asCModule *mod = GetModule(module, false); + if( mod == 0 ) return asNO_MODULE; - mod->Discard(); + mod->Discard(); - return 0; + return 0; } // interface asUINT asCScriptEngine::GetModuleCount() const { - ACQUIRESHARED(engineRWLock); - asUINT length = asUINT(scriptModules.GetLength()); - RELEASESHARED(engineRWLock); - return length; + ACQUIRESHARED(engineRWLock); + asUINT length = asUINT(scriptModules.GetLength()); + RELEASESHARED(engineRWLock); + return length; } // interface asIScriptModule *asCScriptEngine::GetModuleByIndex(asUINT index) const { - asIScriptModule *mod = 0; - ACQUIRESHARED(engineRWLock); - if( index < scriptModules.GetLength() ) - mod = scriptModules[index]; - RELEASESHARED(engineRWLock); - return mod; + asIScriptModule *mod = 0; + ACQUIRESHARED(engineRWLock); + if( index < scriptModules.GetLength() ) + mod = scriptModules[index]; + RELEASESHARED(engineRWLock); + return mod; } // internal int asCScriptEngine::GetFactoryIdByDecl(const asCObjectType *ot, const char *decl) { - asCModule *mod = 0; + asCModule *mod = 0; - // Is this a script class? - if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size > 0 ) - mod = scriptFunctions[ot->beh.factories[0]]->module; + // 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); + asCBuilder bld(this, mod); - // Don't write parser errors to the message callback - bld.silent = true; + // 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; + 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( asUINT 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; - } - } + // Search for matching factory function + int id = -1; + for( asUINT 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; + if( id == -1 ) return asNO_FUNCTION; - return id; + return id; } // internal int asCScriptEngine::GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod) { - asCBuilder bld(this, mod); + asCBuilder bld(this, mod); - // Don't write parser errors to the message callback - bld.silent = true; + // Don't write parser errors to the message callback + bld.silent = true; - asCScriptFunction func(this, mod, asFUNC_DUMMY); + 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); - func.objectType->AddRefInternal(); + // 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); + func.objectType->AddRefInternal(); - int r = bld.ParseFunctionDeclaration(func.objectType, decl, &func, false); - if( r < 0 ) - return asINVALID_DECLARATION; + 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( asUINT 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; - } - } + // Search script functions for matching interface + int id = -1; + for( asUINT 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; + if( id == -1 ) return asNO_FUNCTION; - return id; + return id; } // internal asCString asCScriptEngine::GetFunctionDeclaration(int funcId) { - asCString str; - asCScriptFunction *func = GetScriptFunction(funcId); - if( func ) - str = func->GetDeclarationStr(); + asCString str; + asCScriptFunction *func = GetScriptFunction(funcId); + if( func ) + str = func->GetDeclarationStr(); - return str; + return str; } // internal asCScriptFunction *asCScriptEngine::GetScriptFunction(int funcId) const { - if( funcId < 0 || funcId >= (int)scriptFunctions.GetLength() ) - return 0; + if( funcId < 0 || funcId >= (int)scriptFunctions.GetLength() ) + return 0; - return scriptFunctions[funcId]; + return scriptFunctions[funcId]; } // interface asIScriptContext *asCScriptEngine::CreateContext() { - asIScriptContext *ctx = 0; - CreateContext(&ctx, false); - return ctx; + 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; + *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(); + // We need to make sure the engine has been + // prepared before any context is executed + PrepareEngine(); - return 0; + return 0; } // interface int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset, bool isCompositeIndirect) { - int r; - asCDataType dt; - asCBuilder bld(this, 0); - r = bld.ParseDataType(obj, &dt, defaultNamespace); - if( r < 0 ) - return ConfigError(r, "RegisterObjectProperty", obj, declaration); - - if (dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE))) - return ConfigError(asINVALID_OBJECT, "RegisterObjectProperty", obj, declaration); - - // Don't allow modifying generated template instances - if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) - return ConfigError(asINVALID_TYPE, "RegisterObjectProperty", obj, declaration); - - // Verify that the correct config group is used - if( currentGroup->FindType(dt.GetTypeInfo()->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); - - // 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); - // The composite offset must also obey the ADDSi restriction - if (compositeOffset > 32767 || compositeOffset < -32768) - return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration); - - asCObjectProperty *prop = asNEW(asCObjectProperty); - if( prop == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectProperty", obj, declaration); - - prop->name = name; - prop->type = type; - prop->byteOffset = byteOffset; - prop->isPrivate = false; - prop->isProtected = false; - prop->compositeOffset = compositeOffset; - prop->isCompositeIndirect = isCompositeIndirect; - prop->accessMask = defaultAccessMask; - - asCObjectType *ot = CastToObjectType(dt.GetTypeInfo()); - asUINT idx = ot->properties.GetLength(); - ot->properties.PushLast(prop); - - // Add references to types so they are not released too early - if( type.GetTypeInfo() ) - { - type.GetTypeInfo()->AddRefInternal(); - - // Add template instances to the config group - if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && !currentGroup->types.Exists(type.GetTypeInfo()) ) - currentGroup->types.PushLast(type.GetTypeInfo()); - } - - currentGroup->AddReferencesForType(this, type.GetTypeInfo()); - - // Return the index of the property to signal success - return idx; + int r; + asCDataType dt; + asCBuilder bld(this, 0); + r = bld.ParseDataType(obj, &dt, defaultNamespace); + if( r < 0 ) + return ConfigError(r, "RegisterObjectProperty", obj, declaration); + + if (dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE))) + return ConfigError(asINVALID_OBJECT, "RegisterObjectProperty", obj, declaration); + + // Don't allow modifying generated template instances + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) + return ConfigError(asINVALID_TYPE, "RegisterObjectProperty", obj, declaration); + + // Verify that the correct config group is used + if( currentGroup->FindType(dt.GetTypeInfo()->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); + + // 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); + // The composite offset must also obey the ADDSi restriction + if (compositeOffset > 32767 || compositeOffset < -32768) + return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration); + + asCObjectProperty *prop = asNEW(asCObjectProperty); + if( prop == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectProperty", obj, declaration); + + prop->name = name; + prop->type = type; + prop->byteOffset = byteOffset; + prop->isPrivate = false; + prop->isProtected = false; + prop->compositeOffset = compositeOffset; + prop->isCompositeIndirect = isCompositeIndirect; + prop->accessMask = defaultAccessMask; + + asCObjectType *ot = CastToObjectType(dt.GetTypeInfo()); + asUINT idx = ot->properties.GetLength(); + ot->properties.PushLast(prop); + + // Add references to types so they are not released too early + if( type.GetTypeInfo() ) + { + type.GetTypeInfo()->AddRefInternal(); + + // Add template instances to the config group + if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && !currentGroup->types.Exists(type.GetTypeInfo()) ) + currentGroup->types.PushLast(type.GetTypeInfo()); + } + + currentGroup->AddReferencesForType(this, type.GetTypeInfo()); + + // Return the index of the property to signal success + return idx; } // 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 - if( GetRegisteredType(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 ) - { - // If it is not in the defaultNamespace then the type was successfully parsed because - // it is declared in a parent namespace which shouldn't be treated as an error - if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace ) - 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, true, false); - 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]->AddRefInternal(); - st->beh.release = scriptTypeBehaviours.beh.release; - scriptFunctions[st->beh.release]->AddRefInternal(); - st->beh.copy = 0; - - allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); - registeredObjTypes.PushLast(st); - - currentGroup->types.PushLast(st); - - return GetTypeIdByDecl(name); + if( name == 0 ) return ConfigError(asINVALID_NAME, "RegisterInterface", 0, 0); + + // Verify if the name has been registered as a type already + if( GetRegisteredType(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 ) + { + // If it is not in the defaultNamespace then the type was successfully parsed because + // it is declared in a parent namespace which shouldn't be treated as an error + if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace ) + 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, true, false); + 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]->AddRefInternal(); + st->beh.release = scriptTypeBehaviours.beh.release; + scriptFunctions[st->beh.release]->AddRefInternal(); + st->beh.copy = 0; + + allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); + registeredObjTypes.PushLast(st); + + currentGroup->types.PushLast(st); + + return GetTypeIdByDecl(name); } // 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); + // 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); + 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); + asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_INTERFACE); + if( func == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterInterfaceMethod", intf, declaration); - func->objectType = CastToObjectType(dt.GetTypeInfo()); - func->objectType->AddRefInternal(); + func->objectType = CastToObjectType(dt.GetTypeInfo()); + func->objectType->AddRefInternal(); - 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); - } + 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.GetTypeInfo(), func->name.AddressOf(), 0, 0, false, false); - if( r < 0 ) - { - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asNAME_TAKEN, "RegisterInterfaceMethod", intf, declaration); - } + // Check name conflicts + r = bld.CheckNameConflictMember(dt.GetTypeInfo(), func->name.AddressOf(), 0, 0, false, false); + if( r < 0 ) + { + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asNAME_TAKEN, "RegisterInterfaceMethod", intf, declaration); + } - func->id = GetNextScriptFunctionId(); - AddScriptFunction(func); + func->id = GetNextScriptFunctionId(); + AddScriptFunction(func); - // The index into the interface's vftable chunk should be - // its index in the methods array. - func->vfTableIdx = int(func->objectType->methods.GetLength()); + // 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->objectType->methods.PushLast(func->id); - func->ComputeSignatureId(); + func->ComputeSignatureId(); - currentGroup->AddReferencesForFunc(this, func); + currentGroup->AddReferencesForFunc(this, func); - // Return function id as success - return func->id; + // 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 | asOBJ_IMPLICIT_HANDLE) ) - 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|asOBJ_IMPLICIT_HANDLE)) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - if( (flags & asOBJ_SCOPED) && (flags & (asOBJ_GC|asOBJ_NOHANDLE|asOBJ_NOCOUNT|asOBJ_IMPLICIT_HANDLE)) ) - 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); - - // Implicit handle is only allowed if the engine property for this is turned on - if( !ep.allowImplicitHandleTypes && (flags & asOBJ_IMPLICIT_HANDLE) ) - return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); - } - else if( flags & asOBJ_VALUE ) - { - // Cannot use reference flags - if( flags & (asOBJ_REF | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_NOCOUNT | asOBJ_IMPLICIT_HANDLE) ) - 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 + 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 | asOBJ_IMPLICIT_HANDLE) ) + 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|asOBJ_IMPLICIT_HANDLE)) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + if( (flags & asOBJ_SCOPED) && (flags & (asOBJ_GC|asOBJ_NOHANDLE|asOBJ_NOCOUNT|asOBJ_IMPLICIT_HANDLE)) ) + 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); + + // Implicit handle is only allowed if the engine property for this is turned on + if( !ep.allowImplicitHandleTypes && (flags & asOBJ_IMPLICIT_HANDLE) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + } + else if( flags & asOBJ_VALUE ) + { + // Cannot use reference flags + if( flags & (asOBJ_REF | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_NOCOUNT | asOBJ_IMPLICIT_HANDLE) ) + 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) ) + if( flags - (flags & asOBJ_MASK_VALID_FLAGS) ) #else - if( flags - (flags & (asOBJ_MASK_VALID_FLAGS | asOBJ_APP_ALIGN16)) ) + 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 - if( GetRegisteredType(typeName, defaultNamespace) ) - // This is not an irrepairable error, as it may just be that the same type is registered twice - return asALREADY_REGISTERED; - - 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; + 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 + if( GetRegisteredType(typeName, defaultNamespace) ) + // This is not an irrepairable error, as it may just be that the same type is registered twice + return asALREADY_REGISTERED; + + 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; + // 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->types.PushLast(type); - registeredObjTypes.PushLast(type); - registeredTemplateTypes.PushLast(type); - - // Define the template subtypes - for( asUINT subTypeIdx = 0; subTypeIdx < subtypeNames.GetLength(); subTypeIdx++ ) - { - asCTypeInfo *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(asCTypeInfo)(this); - if( subtype == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); - - subtype->name = subtypeNames[subTypeIdx]; - subtype->size = 0; - subtype->flags = asOBJ_TEMPLATE_SUBTYPE; - templateSubTypes.PushLast(subtype); - } - type->templateSubTypes.PushLast(asCDataType::CreateType(subtype, false)); - subtype->AddRefInternal(); - } - } - else - { - typeName = name; - - // Verify if the name has been registered as a type already - if( GetRegisteredType(typeName, defaultNamespace) ) - // This is not an irrepairable error, as it may just be that the same type is registered twice - return asALREADY_REGISTERED; - - // Keep the most recent template generated instance type, so we know what it was before parsing the datatype - asCObjectType *mostRecentTemplateInstanceType = 0; - asUINT originalSizeOfGeneratedTemplateTypes = (asUINT)generatedTemplateTypes.GetLength(); - if( originalSizeOfGeneratedTemplateTypes ) - mostRecentTemplateInstanceType = generatedTemplateTypes[originalSizeOfGeneratedTemplateTypes-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.GetTypeInfo()->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); - - r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true, false); - 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; + type->flags = flags; + type->accessMask = defaultAccessMask; + + // Store it in the object types + allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); + currentGroup->types.PushLast(type); + registeredObjTypes.PushLast(type); + registeredTemplateTypes.PushLast(type); + + // Define the template subtypes + for( asUINT subTypeIdx = 0; subTypeIdx < subtypeNames.GetLength(); subTypeIdx++ ) + { + asCTypeInfo *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(asCTypeInfo)(this); + if( subtype == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); + + subtype->name = subtypeNames[subTypeIdx]; + subtype->size = 0; + subtype->flags = asOBJ_TEMPLATE_SUBTYPE; + templateSubTypes.PushLast(subtype); + } + type->templateSubTypes.PushLast(asCDataType::CreateType(subtype, false)); + subtype->AddRefInternal(); + } + } + else + { + typeName = name; + + // Verify if the name has been registered as a type already + if( GetRegisteredType(typeName, defaultNamespace) ) + // This is not an irrepairable error, as it may just be that the same type is registered twice + return asALREADY_REGISTERED; + + // Keep the most recent template generated instance type, so we know what it was before parsing the datatype + asCObjectType *mostRecentTemplateInstanceType = 0; + asUINT originalSizeOfGeneratedTemplateTypes = (asUINT)generatedTemplateTypes.GetLength(); + if( originalSizeOfGeneratedTemplateTypes ) + mostRecentTemplateInstanceType = generatedTemplateTypes[originalSizeOfGeneratedTemplateTypes-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.GetTypeInfo()->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); + + r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true, false); + 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; + // 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->types.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 generated before? - if( generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) && - generatedTemplateTypes[generatedTemplateTypes.GetLength()-1] == mostRecentTemplateInstanceType ) - { - asCString str; - str.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, typeName.AddressOf()); - WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0); - } - - // If this is not a generated template instance type, then it means it is an - // already registered template specialization - if( !generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectType", name, 0); - - // TODO: Add this again. The type is used by the factory stubs so we need to discount that - // Is the template instance type already being used? -// if( dt.GetTypeInfo()->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.GetTypeInfo()->name; - // The namespace will be the same as the original template type - type->nameSpace = dt.GetTypeInfo()->nameSpace; - type->templateSubTypes.PushLast(dt.GetSubType()); - for( asUINT s = 0; s < type->templateSubTypes.GetLength(); s++ ) - if( type->templateSubTypes[s].GetTypeInfo() ) - type->templateSubTypes[s].GetTypeInfo()->AddRefInternal(); - type->size = byteSize; + type->flags = flags; + type->accessMask = defaultAccessMask; + + allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); + registeredObjTypes.PushLast(type); + + currentGroup->types.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 generated before? + if( generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) && + generatedTemplateTypes[generatedTemplateTypes.GetLength()-1] == mostRecentTemplateInstanceType ) + { + asCString str; + str.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, typeName.AddressOf()); + WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0); + } + + // If this is not a generated template instance type, then it means it is an + // already registered template specialization + if( !generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectType", name, 0); + + // TODO: Add this again. The type is used by the factory stubs so we need to discount that + // Is the template instance type already being used? +// if( dt.GetTypeInfo()->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.GetTypeInfo()->name; + // The namespace will be the same as the original template type + type->nameSpace = dt.GetTypeInfo()->nameSpace; + type->templateSubTypes.PushLast(dt.GetSubType()); + for( asUINT s = 0; s < type->templateSubTypes.GetLength(); s++ ) + if( type->templateSubTypes[s].GetTypeInfo() ) + type->templateSubTypes[s].GetTypeInfo()->AddRefInternal(); + type->size = byteSize; #ifdef WIP_16BYTE_ALIGN - // TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries - type->alignment = (flags & asOBJ_APP_ALIGN16) ? 16 : 4; + // 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; + type->flags = flags; + type->accessMask = defaultAccessMask; - templateInstanceTypes.PushLast(type); + templateInstanceTypes.PushLast(type); - currentGroup->types.PushLast(type); + currentGroup->types.PushLast(type); - // Remove the template instance type, which will no longer be used. - // It is possible that multiple template instances are generated if - // they have any relationship, so all of them must be removed - while( generatedTemplateTypes.GetLength() > originalSizeOfGeneratedTemplateTypes ) - RemoveTemplateInstanceType(generatedTemplateTypes[generatedTemplateTypes.GetLength()-1]); - } - } + // Remove the template instance type, which will no longer be used. + // It is possible that multiple template instances are generated if + // they have any relationship, so all of them must be removed + while( generatedTemplateTypes.GetLength() > originalSizeOfGeneratedTemplateTypes ) + RemoveTemplateInstanceType(generatedTemplateTypes[generatedTemplateTypes.GetLength()-1]); + } + } - // Return the type id as the success (except for template types) - if( flags & asOBJ_TEMPLATE ) - return asSUCCESS; + // Return the type id as the success (except for template types) + if( flags & asOBJ_TEMPLATE ) + return asSUCCESS; - return GetTypeIdByDecl(name); + return GetTypeIdByDecl(name); } // interface int asCScriptEngine::RegisterObjectBehaviour(const char *datatype, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) { - if( datatype == 0 ) return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", datatype, decl); + 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); + // 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.GetTypeInfo() == 0 || (type.IsObjectHandle() && !(type.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE)) ) - return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); + if( type.GetTypeInfo() == 0 || (type.IsObjectHandle() && !(type.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE)) ) + return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); - // Don't allow application to modify built-in types - if( type.GetTypeInfo() == &functionBehaviours || - type.GetTypeInfo() == &scriptTypeBehaviours ) - return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); + // Don't allow application to modify built-in types + if( type.GetTypeInfo() == &functionBehaviours || + type.GetTypeInfo() == &scriptTypeBehaviours ) + return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); - if( type.IsReadOnly() || type.IsReference() ) - return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); + if( type.IsReadOnly() || type.IsReference() ) + return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); - // Don't allow modifying generated template instances - if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(type.GetTypeInfo())) ) - return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); + // Don't allow modifying generated template instances + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(type.GetTypeInfo())) ) + return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); - return RegisterBehaviourToObjectType(CastToObjectType(type.GetTypeInfo()), behaviour, decl, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect); + return RegisterBehaviourToObjectType(CastToObjectType(type.GetTypeInfo()), behaviour, decl, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect); } // internal int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) { #ifdef AS_MAX_PORTABILITY - if( callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + 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, auxiliary, &internal); - if( r < 0 ) - return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - internal.compositeOffset = compositeOffset; - internal.isCompositeIndirect = isCompositeIndirect; - if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL ) - return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - - // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType - // If the object type is a template, make sure there are no generated instances already - if( objectType->flags & asOBJ_TEMPLATE ) - { - for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) - { - asCObjectType *tmpl = generatedTemplateTypes[n]; - if( tmpl->name == objectType->name && - tmpl->nameSpace == objectType->nameSpace && - !(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) - { - asCString msg; - msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf()); - WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf()); - return ConfigError(asERROR, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); - } - } - } - - 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; - func.objectType->AddRefInternal(); - } - - // Check if the method restricts that use of the template to value types or reference types - if( objectType->flags & asOBJ_TEMPLATE ) - { - r = SetTemplateRestrictions(objectType, &func, "RegisterObjectBehaviour", decl); - if (r < 0) - return r; - } - - 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]->AddRefInternal(); - 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.GetTypeInfo() == 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 ) - { - func.name = "$list"; - - // 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 - 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 ) - { - if( behaviour == asBEHAVE_LIST_FACTORY ) - func.name = "$list"; - - // 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 - 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.GetTypeInfo() == 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_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; + asSSystemFunctionInterface internal; + bool isMethod = !(behaviour == asBEHAVE_FACTORY || + behaviour == asBEHAVE_LIST_FACTORY || + behaviour == asBEHAVE_TEMPLATE_CALLBACK); + int r = DetectCallingConvention(isMethod, funcPointer, callConv, auxiliary, &internal); + if( r < 0 ) + return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + internal.compositeOffset = compositeOffset; + internal.isCompositeIndirect = isCompositeIndirect; + if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL ) + return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType + // If the object type is a template, make sure there are no generated instances already + if( objectType->flags & asOBJ_TEMPLATE ) + { + for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) + { + asCObjectType *tmpl = generatedTemplateTypes[n]; + if( tmpl->name == objectType->name && + tmpl->nameSpace == objectType->nameSpace && + !(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) + { + asCString msg; + msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf()); + WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf()); + return ConfigError(asERROR, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + } + } + + 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; + func.objectType->AddRefInternal(); + } + + // Check if the method restricts that use of the template to value types or reference types + if( objectType->flags & asOBJ_TEMPLATE ) + { + r = SetTemplateRestrictions(objectType, &func, "RegisterObjectBehaviour", decl); + if (r < 0) + return r; + } + + 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]->AddRefInternal(); + 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.GetTypeInfo() == 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 ) + { + func.name = "$list"; + + // 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 + 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 ) + { + if( behaviour == asBEHAVE_LIST_FACTORY ) + func.name = "$list"; + + // 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 + 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.GetTypeInfo() == 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_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::SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl) { - asASSERT(templateType->flags & asOBJ_TEMPLATE); - - for (asUINT subTypeIdx = 0; subTypeIdx < templateType->templateSubTypes.GetLength(); subTypeIdx++) - { - if (func->returnType.GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo()) - { - if (func->returnType.IsObjectHandle()) - templateType->acceptValueSubType = false; - else if (!func->returnType.IsReference()) - templateType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if (!func->returnType.IsObjectHandle() && !func->returnType.IsReference()) - return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl); - } - - for (asUINT n = 0; n < func->parameterTypes.GetLength(); n++) - { - if (func->parameterTypes[n].GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo()) - { - if (func->parameterTypes[n].IsObjectHandle() || - (!ep.allowUnsafeReferences && func->parameterTypes[n].IsReference() && func->inOutFlags[n] == asTM_INOUTREF)) - templateType->acceptValueSubType = false; - else if (!func->parameterTypes[n].IsReference()) - templateType->acceptRefSubType = false; - - // Can't support template subtypes by value, since each type is treated differently in the ABI - if (!func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference()) - return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl); - } - } - } - - return asSUCCESS; + asASSERT(templateType->flags & asOBJ_TEMPLATE); + + for (asUINT subTypeIdx = 0; subTypeIdx < templateType->templateSubTypes.GetLength(); subTypeIdx++) + { + if (func->returnType.GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo()) + { + if (func->returnType.IsObjectHandle()) + templateType->acceptValueSubType = false; + else if (!func->returnType.IsReference()) + templateType->acceptRefSubType = false; + + // Can't support template subtypes by value, since each type is treated differently in the ABI + if (!func->returnType.IsObjectHandle() && !func->returnType.IsReference()) + return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl); + } + + for (asUINT n = 0; n < func->parameterTypes.GetLength(); n++) + { + if (func->parameterTypes[n].GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo()) + { + if (func->parameterTypes[n].IsObjectHandle() || + (!ep.allowUnsafeReferences && func->parameterTypes[n].IsReference() && func->inOutFlags[n] == asTM_INOUTREF)) + templateType->acceptValueSubType = false; + else if (!func->parameterTypes[n].IsReference()) + templateType->acceptRefSubType = false; + + // Can't support template subtypes by value, since each type is treated differently in the ABI + if (!func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference()) + return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl); + } + } + } + + return asSUCCESS; } int asCScriptEngine::VerifyVarTypeNotInFunction(asCScriptFunction *func) { - // Don't allow var type in this function - if( func->returnType.GetTokenType() == ttQuestion ) - return asINVALID_DECLARATION; + // 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; + for( unsigned int n = 0; n < func->parameterTypes.GetLength(); n++ ) + if( func->parameterTypes[n].GetTokenType() == ttQuestion ) + return asINVALID_DECLARATION; - return 0; + 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; - if( f->objectType ) - f->objectType->AddRefInternal(); - f->id = id; - f->SetReadOnly(func.IsReadOnly()); - f->accessMask = defaultAccessMask; - f->parameterTypes = func.parameterTypes; - f->parameterNames = func.parameterNames; - f->inOutFlags = func.inOutFlags; - f->traits = func.traits; - for( n = 0; n < func.defaultArgs.GetLength(); n++ ) - if( func.defaultArgs[n] ) - f->defaultArgs.PushLast(asNEW(asCString)(*func.defaultArgs[n])); - else - f->defaultArgs.PushLast(0); - - AddScriptFunction(f); - - // If parameter type from other groups are used, add references - currentGroup->AddReferencesForFunc(this, f); - - return id; + 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; + if( f->objectType ) + f->objectType->AddRefInternal(); + f->id = id; + f->SetReadOnly(func.IsReadOnly()); + f->accessMask = defaultAccessMask; + f->parameterTypes = func.parameterTypes; + f->parameterNames = func.parameterNames; + f->inOutFlags = func.inOutFlags; + f->traits = func.traits; + for( n = 0; n < func.defaultArgs.GetLength(); n++ ) + if( func.defaultArgs[n] ) + f->defaultArgs.PushLast(asNEW(asCString)(*func.defaultArgs[n])); + else + f->defaultArgs.PushLast(0); + + AddScriptFunction(f); + + // If parameter type from other groups are used, add references + currentGroup->AddReferencesForFunc(this, f); + + 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); + // Don't accept a null pointer + if( pointer == 0 ) + return ConfigError(asINVALID_ARG, "RegisterGlobalProperty", declaration, 0); - asCDataType type; - asCString name; + 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); + 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); + // 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; + // 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); + prop->SetRegisteredAddress(pointer); + varAddressMap.Insert(prop->GetAddressOfValue(), prop); - asUINT idx = registeredGlobalProps.Put(prop); - prop->AddRef(); - currentGroup->globalProps.PushLast(prop); + asUINT idx = registeredGlobalProps.Put(prop); + prop->AddRef(); + currentGroup->globalProps.PushLast(prop); - currentGroup->AddReferencesForType(this, type.GetTypeInfo()); + currentGroup->AddReferencesForType(this, type.GetTypeInfo()); - // Return the index of the property to signal success - return int(idx); + // Return the index of the property to signal success + return int(idx); } // internal asCGlobalProperty *asCScriptEngine::AllocateGlobalProperty() { - asCGlobalProperty *prop = asNEW(asCGlobalProperty); - if( prop == 0 ) - { - // Out of memory - return 0; - } + 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; - } + // 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; + prop->id = (asUINT)globalProperties.GetLength(); + globalProperties.PushLast(prop); + return prop; } // internal void asCScriptEngine::RemoveGlobalProperty(asCGlobalProperty *prop) { - int index = globalProperties.IndexOf(prop); - if( index >= 0 ) - { - freeGlobalPropertyIds.PushLast(index); - globalProperties[index] = 0; + int index = globalProperties.IndexOf(prop); + if( index >= 0 ) + { + freeGlobalPropertyIds.PushLast(index); + globalProperties[index] = 0; - asSMapNode *node; - varAddressMap.MoveTo(&node, prop->GetAddressOfValue()); - asASSERT(node); - if( node ) - varAddressMap.Erase(node); + asSMapNode *node; + varAddressMap.MoveTo(&node, prop->GetAddressOfValue()); + asASSERT(node); + if( node ) + varAddressMap.Erase(node); - prop->Release(); - } + prop->Release(); + } } // interface asUINT asCScriptEngine::GetGlobalPropertyCount() const { - return asUINT(registeredGlobalProps.GetSize()); + 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; + 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( 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; - } + if( configGroup ) + { + asCConfigGroup *group = FindConfigGroupForGlobalVar(index); + if( group ) + *configGroup = group->groupName.AddressOf(); + else + *configGroup = 0; + } - return asSUCCESS; + return asSUCCESS; } // interface int asCScriptEngine::GetGlobalPropertyIndexByName(const char *in_name) const { - asCString name; - asSNameSpace *ns = 0; - if( DetermineNameAndNamespace(in_name, defaultNamespace, name, ns) < 0 ) - return asINVALID_ARG; - - // Find the global var id - while( ns ) - { - int id = registeredGlobalProps.GetFirstIndex(ns, name); - if( id >= 0 ) - return id; + asCString name; + asSNameSpace *ns = 0; + if( DetermineNameAndNamespace(in_name, defaultNamespace, name, ns) < 0 ) + return asINVALID_ARG; - // Recursively search parent namespace - ns = GetParentNameSpace(ns); - } + // Find the global var id + while( ns ) + { + int id = registeredGlobalProps.GetFirstIndex(ns, name); + if( id >= 0 ) + return id; - return asNO_GLOBAL_VAR; + // Recursively search parent namespace + ns = GetParentNameSpace(ns); + } + + return asNO_GLOBAL_VAR; } // 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); + // 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; + // 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; + asCString name; + asSNameSpace *ns; + asCDataType dt; + int r = bld.ParseVariableDeclaration(decl, defaultNamespace, name, ns, dt); + if( r < 0 ) + return r; - // Search for a match - while( ns ) - { - int id = registeredGlobalProps.GetFirstIndex(ns, name, asCCompGlobPropType(dt)); - if( id >= 0 ) - return id; + // Search for a match + while( ns ) + { + int id = registeredGlobalProps.GetFirstIndex(ns, name, asCCompGlobPropType(dt)); + if( id >= 0 ) + return id; - ns = GetParentNameSpace(ns); - } + ns = GetParentNameSpace(ns); + } - return asNO_GLOBAL_VAR; + return asNO_GLOBAL_VAR; } // interface int asCScriptEngine::RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) { - if( obj == 0 ) - return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); + 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); + // 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); - // Don't allow application to modify primitives or handles - if( dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE))) - return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); + // Don't allow application to modify primitives or handles + if( dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE))) + return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); - // Don't allow application to modify built-in types or funcdefs - if( dt.GetTypeInfo() == &functionBehaviours || - dt.GetTypeInfo() == &scriptTypeBehaviours || - CastToFuncdefType(dt.GetTypeInfo()) ) - return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); + // Don't allow application to modify built-in types or funcdefs + if( dt.GetTypeInfo() == &functionBehaviours || + dt.GetTypeInfo() == &scriptTypeBehaviours || + CastToFuncdefType(dt.GetTypeInfo()) ) + return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); - // Don't allow modifying generated template instances - if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) - return ConfigError(asINVALID_TYPE, "RegisterObjectMethod", obj, declaration); + // Don't allow modifying generated template instances + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) + return ConfigError(asINVALID_TYPE, "RegisterObjectMethod", obj, declaration); - return RegisterMethodToObjectType(CastToObjectType(dt.GetTypeInfo()), declaration, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect); + return RegisterMethodToObjectType(CastToObjectType(dt.GetTypeInfo()), declaration, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect); } // internal int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) { #ifdef AS_MAX_PORTABILITY - if( callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + if( callConv != asCALL_GENERIC ) + return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); #endif - asSSystemFunctionInterface internal; - int r = DetectCallingConvention(true, funcPointer, callConv, auxiliary, &internal); - if( r < 0 ) - return ConfigError(r, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - - internal.compositeOffset = compositeOffset; - internal.isCompositeIndirect = isCompositeIndirect; - if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL ) - return ConfigError(asINVALID_ARG, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - - // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType - // If the object type is a template, make sure there are no generated instances already - if( objectType->flags & asOBJ_TEMPLATE ) - { - for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) - { - asCObjectType *tmpl = generatedTemplateTypes[n]; - if( tmpl->name == objectType->name && - tmpl->nameSpace == objectType->nameSpace && - !(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) - { - asCString msg; - msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf()); - WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf()); - return ConfigError(asERROR, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - } - } - - 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; - func->objectType->AddRefInternal(); - - 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, false); - if( r < 0 ) - { - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asNAME_TAKEN, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - - // Validate property signature - if( func->IsProperty() && (r = bld.ValidateVirtualProperty(func)) < 0 ) - { - // Set as dummy function before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - if( r == -5 ) - return ConfigError(asNAME_TAKEN, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - else - return ConfigError(asINVALID_DECLARATION, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - } - - // Check against duplicate methods - if( func->name == "opConv" || func->name == "opImplConv" || func->name == "opCast" || func->name == "opImplCast" ) - { - // opConv and opCast are special methods that the compiler differentiates between by the return type - for( asUINT 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( asUINT 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; - AddScriptFunction(func); - - // If parameter type from other groups are used, add references - currentGroup->AddReferencesForFunc(this, func); - - // Check if the method restricts that use of the template to value types or reference types - if( func->objectType->flags & asOBJ_TEMPLATE ) - { - r = SetTemplateRestrictions(func->objectType, func, "RegisterObjectMethod", declaration); - if (r < 0) - return r; - } - - // TODO: beh.copy member will be removed, so this is not necessary - // Is this the default copy behaviour? - if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && !func->IsReadOnly() && - ((objectType->flags & asOBJ_SCRIPT_OBJECT) || func->parameterTypes[0].IsEqualExceptRefAndConst(asCDataType::CreateType(func->objectType, false))) ) - { - if( func->objectType->beh.copy != 0 ) - return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); - - func->objectType->beh.copy = func->id; - func->AddRefInternal(); - } - - // Return the function id as success - return func->id; + asSSystemFunctionInterface internal; + int r = DetectCallingConvention(true, funcPointer, callConv, auxiliary, &internal); + if( r < 0 ) + return ConfigError(r, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + + internal.compositeOffset = compositeOffset; + internal.isCompositeIndirect = isCompositeIndirect; + if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL ) + return ConfigError(asINVALID_ARG, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + + // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType + // If the object type is a template, make sure there are no generated instances already + if( objectType->flags & asOBJ_TEMPLATE ) + { + for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) + { + asCObjectType *tmpl = generatedTemplateTypes[n]; + if( tmpl->name == objectType->name && + tmpl->nameSpace == objectType->nameSpace && + !(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) + { + asCString msg; + msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf()); + WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf()); + return ConfigError(asERROR, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + } + } + + 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; + func->objectType->AddRefInternal(); + + 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, false); + if( r < 0 ) + { + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asNAME_TAKEN, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + + // Validate property signature + if( func->IsProperty() && (r = bld.ValidateVirtualProperty(func)) < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + if( r == -5 ) + return ConfigError(asNAME_TAKEN, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + else + return ConfigError(asINVALID_DECLARATION, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + + // Check against duplicate methods + if( func->name == "opConv" || func->name == "opImplConv" || func->name == "opCast" || func->name == "opImplCast" ) + { + // opConv and opCast are special methods that the compiler differentiates between by the return type + for( asUINT 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( asUINT 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; + AddScriptFunction(func); + + // If parameter type from other groups are used, add references + currentGroup->AddReferencesForFunc(this, func); + + // Check if the method restricts that use of the template to value types or reference types + if( func->objectType->flags & asOBJ_TEMPLATE ) + { + r = SetTemplateRestrictions(func->objectType, func, "RegisterObjectMethod", declaration); + if (r < 0) + return r; + } + + // TODO: beh.copy member will be removed, so this is not necessary + // Is this the default copy behaviour? + if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && !func->IsReadOnly() && + ((objectType->flags & asOBJ_SCRIPT_OBJECT) || func->parameterTypes[0].IsEqualExceptRefAndConst(asCDataType::CreateType(func->objectType, false))) ) + { + if( func->objectType->beh.copy != 0 ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + + func->objectType->beh.copy = func->id; + func->AddRefInternal(); + } + + // Return the function id as success + return func->id; } // interface int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary) { #ifdef AS_MAX_PORTABILITY - if( callConv != asCALL_GENERIC ) - return ConfigError(asNOT_SUPPORTED, "RegisterGlobalFunction", declaration, 0); + if( callConv != asCALL_GENERIC ) + return ConfigError(asNOT_SUPPORTED, "RegisterGlobalFunction", declaration, 0); #endif - asSSystemFunctionInterface internal; - int r = DetectCallingConvention(false, funcPointer, callConv, auxiliary, &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, false, false); - if( r < 0 ) - { - // Set as dummy function before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - return ConfigError(asNAME_TAKEN, "RegisterGlobalFunction", declaration, 0); - } - - // Validate property signature - if( func->IsProperty() && (r = bld.ValidateVirtualProperty(func)) < 0 ) - { - // Set as dummy function before deleting - func->funcType = asFUNC_DUMMY; - asDELETE(func,asCScriptFunction); - if( r == -5 ) - return ConfigError(asNAME_TAKEN, "RegisterGlobalFunction", declaration, 0); - else - return ConfigError(asINVALID_DECLARATION, "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(); - AddScriptFunction(func); - - currentGroup->scriptFunctions.PushLast(func); - func->accessMask = defaultAccessMask; - registeredGlobalFuncs.Put(func); - - // If parameter type from other groups are used, add references - currentGroup->AddReferencesForFunc(this, func); - - // Return the function id as success - return func->id; + asSSystemFunctionInterface internal; + int r = DetectCallingConvention(false, funcPointer, callConv, auxiliary, &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, false, false); + if( r < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asNAME_TAKEN, "RegisterGlobalFunction", declaration, 0); + } + + // Validate property signature + if( func->IsProperty() && (r = bld.ValidateVirtualProperty(func)) < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + if( r == -5 ) + return ConfigError(asNAME_TAKEN, "RegisterGlobalFunction", declaration, 0); + else + return ConfigError(asINVALID_DECLARATION, "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(); + AddScriptFunction(func); + + currentGroup->scriptFunctions.PushLast(func); + func->accessMask = defaultAccessMask; + registeredGlobalFuncs.Put(func); + + // If parameter type from other groups are used, add references + currentGroup->AddReferencesForFunc(this, func); + + // 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); + // 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++; + // Don't count the builtin delegate factory + index++; - if( index >= registeredGlobalFuncs.GetSize() ) - return 0; + if( index >= registeredGlobalFuncs.GetSize() ) + return 0; - return static_cast(const_cast(registeredGlobalFuncs.Get(index))); + 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; - - asSNameSpace *ns = defaultNamespace; - // Search script functions for matching interface - while( ns ) - { - asIScriptFunction *f = 0; - const asCArray &idxs = registeredGlobalFuncs.GetIndexes(ns, 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( asUINT 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; - } - } - } - - if( f ) - return f; - - // Recursively search parent namespaces - ns = GetParentNameSpace(ns); - } - - return 0; + 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; + + asSNameSpace *ns = defaultNamespace; + // Search script functions for matching interface + while( ns ) + { + asIScriptFunction *f = 0; + const asCArray &idxs = registeredGlobalFuncs.GetIndexes(ns, 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( asUINT 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; + } + } + } + + if( f ) + return f; + + // Recursively search parent namespaces + ns = GetParentNameSpace(ns); + } + + return 0; } asCTypeInfo *asCScriptEngine::GetRegisteredType(const asCString &type, asSNameSpace *ns) const { - asSMapNode *cursor; - if( allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(ns, type)) ) - return cursor->value; + asSMapNode *cursor; + if( allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(ns, type)) ) + return cursor->value; - return 0; + return 0; } @@ -3092,589 +3092,589 @@ asCTypeInfo *asCScriptEngine::GetRegisteredType(const asCString &type, asSNameSp 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->flags & asOBJ_REF) - { - 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; - } - } - else - { - if (type->beh.gcEnumReferences == 0) - { - infoMsg = TXT_VALUE_GC_REQUIRE_GC_BEHAVIOUR; - missingBehaviour = true; - } - } - } - // Verify that scoped ref types have the release behaviour - 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 - if( (type->flags & asOBJ_REF) && - !(type->flags & asOBJ_SCOPED) && - !(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 - if( (type->flags & asOBJ_VALUE) && - !(type->flags & asOBJ_POD) ) - { - if( type->beh.constructors.GetLength() == 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; + 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->flags & asOBJ_REF) + { + 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; + } + } + else + { + if (type->beh.gcEnumReferences == 0) + { + infoMsg = TXT_VALUE_GC_REQUIRE_GC_BEHAVIOUR; + missingBehaviour = true; + } + } + } + // Verify that scoped ref types have the release behaviour + 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 + if( (type->flags & asOBJ_REF) && + !(type->flags & asOBJ_SCOPED) && + !(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 + if( (type->flags & asOBJ_VALUE) && + !(type->flags & asOBJ_POD) ) + { + if( type->beh.constructors.GetLength() == 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_s_d, funcName, arg1, arg2, errorNames[-err], err); - else - str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, funcName, arg1, errorNames[-err], err); - } - else - str.Format(TXT_FAILED_IN_FUNC_s_s_d, funcName, errorNames[-err], err); - - WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - } - return err; + configFailed = true; + if( funcName ) + { + asCString str; + if( arg1 ) + { + if( arg2 ) + str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_s_d, funcName, arg1, arg2, errorNames[-err], err); + else + str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, funcName, arg1, errorNames[-err], err); + } + else + str.Format(TXT_FAILED_IN_FUNC_s_s_d, funcName, errorNames[-err], 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; + asCBuilder bld(this, 0); + asCDataType dt; + int r = bld.ParseDataType(type, &dt, defaultNamespace); + if( r < 0 ) return r; - if( dt.GetTypeInfo() == 0 || - !(dt.GetTypeInfo()->GetFlags() & asOBJ_TEMPLATE) ) - return asINVALID_TYPE; + if( dt.GetTypeInfo() == 0 || + !(dt.GetTypeInfo()->GetFlags() & asOBJ_TEMPLATE) ) + return asINVALID_TYPE; - defaultArrayObjectType = CastToObjectType(dt.GetTypeInfo()); - defaultArrayObjectType->AddRefInternal(); + defaultArrayObjectType = CastToObjectType(dt.GetTypeInfo()); + defaultArrayObjectType->AddRefInternal(); - return 0; + return 0; } // interface int asCScriptEngine::GetDefaultArrayTypeId() const { - if( defaultArrayObjectType ) - return GetTypeIdFromDataType(asCDataType::CreateType(defaultArrayObjectType, false)); + if( defaultArrayObjectType ) + return GetTypeIdFromDataType(asCDataType::CreateType(defaultArrayObjectType, false)); - return asINVALID_TYPE; + return asINVALID_TYPE; } // interface int asCScriptEngine::RegisterStringFactory(const char *datatype, asIStringFactory *factory) { - if (factory == 0) - return ConfigError(asINVALID_ARG, "RegisterStringFactory", datatype, 0); + if (factory == 0) + return ConfigError(asINVALID_ARG, "RegisterStringFactory", datatype, 0); - // Parse the data type - asCBuilder bld(this, 0); - asCDataType dt; - int r = bld.ParseDataType(datatype, &dt, defaultNamespace, true); - if (r < 0) - return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); + // Parse the data type + asCBuilder bld(this, 0); + asCDataType dt; + int r = bld.ParseDataType(datatype, &dt, defaultNamespace, true); + if (r < 0) + return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); - // Validate the type. It must not be reference or handle - if (dt.IsReference() || dt.IsObjectHandle()) - return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); + // Validate the type. It must not be reference or handle + if (dt.IsReference() || dt.IsObjectHandle()) + return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); - // All string literals will be treated as const - dt.MakeReadOnly(true); + // All string literals will be treated as const + dt.MakeReadOnly(true); - stringType = dt; - stringFactory = factory; + stringType = dt; + stringFactory = factory; - return asSUCCESS; + return asSUCCESS; } // interface int asCScriptEngine::GetStringFactoryReturnTypeId(asDWORD *flags) const { - if( stringFactory == 0 ) - return asNO_FUNCTION; + if( stringFactory == 0 ) + return asNO_FUNCTION; - if( flags ) - *flags = 0; - return GetTypeIdFromDataType(stringType); + if( flags ) + *flags = 0; + return GetTypeIdFromDataType(stringType); } // internal asCModule *asCScriptEngine::GetModule(const char *name, bool create) { - // Accept null as well as zero-length string - if( name == 0 ) name = ""; - - asCModule *retModule = 0; - - ACQUIRESHARED(engineRWLock); - if( lastModule && lastModule->m_name == name ) - retModule = lastModule; - else - { - // TODO: optimize: Improve linear search - for( asUINT n = 0; n < scriptModules.GetLength(); ++n ) - if( scriptModules[n] && scriptModules[n]->m_name == name ) - { - retModule = scriptModules[n]; - break; - } - } - RELEASESHARED(engineRWLock); - - if( retModule ) - { - ACQUIREEXCLUSIVE(engineRWLock); - lastModule = retModule; - RELEASEEXCLUSIVE(engineRWLock); - - return retModule; - } - - if( create ) - { - retModule = asNEW(asCModule)(name, this); - if( retModule == 0 ) - { - // Out of memory - return 0; - } - - ACQUIREEXCLUSIVE(engineRWLock); - scriptModules.PushLast(retModule); - lastModule = retModule; - RELEASEEXCLUSIVE(engineRWLock); - } - - return retModule; + // Accept null as well as zero-length string + if( name == 0 ) name = ""; + + asCModule *retModule = 0; + + ACQUIRESHARED(engineRWLock); + if( lastModule && lastModule->m_name == name ) + retModule = lastModule; + else + { + // TODO: optimize: Improve linear search + for( asUINT n = 0; n < scriptModules.GetLength(); ++n ) + if( scriptModules[n] && scriptModules[n]->m_name == name ) + { + retModule = scriptModules[n]; + break; + } + } + RELEASESHARED(engineRWLock); + + if( retModule ) + { + ACQUIREEXCLUSIVE(engineRWLock); + lastModule = retModule; + RELEASEEXCLUSIVE(engineRWLock); + + return retModule; + } + + if( create ) + { + retModule = asNEW(asCModule)(name, this); + if( retModule == 0 ) + { + // Out of memory + return 0; + } + + ACQUIREEXCLUSIVE(engineRWLock); + scriptModules.PushLast(retModule); + lastModule = retModule; + RELEASEEXCLUSIVE(engineRWLock); + } + + return retModule; } 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; + 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); + ACQUIREEXCLUSIVE(engineRWLock); + if( isBuilding ) + { + RELEASEEXCLUSIVE(engineRWLock); + return asBUILD_IN_PROGRESS; + } + isBuilding = true; + RELEASEEXCLUSIVE(engineRWLock); - return 0; + return 0; } // internal void asCScriptEngine::BuildCompleted() { - // Always free up pooled memory after a completed build - memoryMgr.FreeUnusedMemory(); + // Always free up pooled memory after a completed build + memoryMgr.FreeUnusedMemory(); - isBuilding = false; + isBuilding = false; } void asCScriptEngine::RemoveTemplateInstanceType(asCObjectType *t) { - // If there is a module that still owns the generated type, then don't remove it - if( t->module ) - return; + // If there is a module that still owns the generated type, then don't remove it + if( t->module ) + return; - // Don't remove it if there are external refernces - if( t->externalRefCount.get() ) - return; + // Don't remove it if there are external refernces + if( t->externalRefCount.get() ) + return; - // Only remove the template instance type if no config group is using it - if( defaultGroup.generatedTemplateInstances.Exists(t) ) - return; - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - if( configGroups[n]->generatedTemplateInstances.Exists(t) ) - return; + // Only remove the template instance type if no config group is using it + if( defaultGroup.generatedTemplateInstances.Exists(t) ) + return; + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + if( configGroups[n]->generatedTemplateInstances.Exists(t) ) + return; - t->DestroyInternal(); - templateInstanceTypes.RemoveValue(t); - generatedTemplateTypes.RemoveValue(t); - t->ReleaseInternal(); + t->DestroyInternal(); + templateInstanceTypes.RemoveValue(t); + generatedTemplateTypes.RemoveValue(t); + t->ReleaseInternal(); } // internal asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateType, asCArray &subTypes, asCModule *requestingModule) { - asUINT n; - - // Is there any template instance type or template specialization already with this subtype? - for( n = 0; n < templateInstanceTypes.GetLength(); n++ ) - { - asCObjectType *type = templateInstanceTypes[n]; - if( type && - type->name == templateType->name && - type->nameSpace == templateType->nameSpace && - type->templateSubTypes == subTypes ) - { - // If the template instance is generated, then the module should hold a reference - // to it so the config group can determine see that the template type is in use. - // Template specializations will be treated as normal types - if( requestingModule && generatedTemplateTypes.Exists(type) ) - { - if( type->module == 0 ) - { - // Set the ownership of this template type - // It may be without ownership if it was previously created from application with for example GetTypeInfoByDecl - type->module = requestingModule; - } - if( !requestingModule->m_templateInstances.Exists(type) ) - { - requestingModule->m_templateInstances.PushLast(type); - type->AddRefInternal(); - } - } - - 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].GetTypeInfo()->flags & asOBJ_VALUE)) ) - return 0; - - if( !templateType->acceptRefSubType && (subTypes[n].IsObject() && (subTypes[n].GetTypeInfo()->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; - - // If the template is being requested from a module, then the module should hold a reference to the type - if( requestingModule ) - { - // Set the ownership of this template type - ot->module = requestingModule; - requestingModule->m_templateInstances.PushLast(ot); - ot->AddRefInternal(); - } - else - { - // If the template type is not requested directly from a module, then set the ownership - // of it to the same module as one of the subtypes. If none of the subtypes are owned by] - // any module, the template instance will be without ownership and can be removed from the - // engine at any time (unless the application holds an external reference). - for( n = 0; n < subTypes.GetLength(); n++ ) - { - if( subTypes[n].GetTypeInfo() ) - { - ot->module = subTypes[n].GetTypeInfo()->module; - if( ot->module ) - { - ot->module->m_templateInstances.PushLast(ot); - ot->AddRefInternal(); - 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); - if( ot->module ) - { - ot->module->m_templateInstances.RemoveValue(ot); - ot->ReleaseInternal(); - } - ot->ReleaseInternal(); - 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]->AddRefInternal(); - } - - ot->methods = templateType->methods; - for( n = 0; n < ot->methods.GetLength(); n++ ) - scriptFunctions[ot->methods[n]]->AddRefInternal(); - - 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]]->AddRefInternal(); - - - // 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); - - // Any child funcdefs must be copied to the template instance (with adjustments in case of template subtypes) - // This must be done before resolving other methods, to make sure the other methods that may refer to the - // templated funcdef will resolve to the new funcdef - for (n = 0; n < templateType->childFuncDefs.GetLength(); n++) - { - asCFuncdefType *funcdef = GenerateNewTemplateFuncdef(templateType, ot, templateType->childFuncDefs[n]); - funcdef->parentClass = ot; - ot->childFuncDefs.PushLast(funcdef); - } - - // As the new template type is instantiated the engine should - // generate new functions to substitute the ones with the template subtype. - 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]->ReleaseInternal(); - 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]); - - 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]); - - if( ot->beh.constructors[n] == ot->beh.construct ) - ot->beh.construct = func->id; - - // Release previous constructor - scriptFunctions[ot->beh.constructors[n]]->ReleaseInternal(); - - 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); - - // Rename the function to easily identify it in LoadByteCode - func->name = "$list"; - - ot->beh.listFactory = func->id; - } - - ot->beh.addref = templateType->beh.addref; - if( scriptFunctions[ot->beh.addref] ) scriptFunctions[ot->beh.addref]->AddRefInternal(); - ot->beh.release = templateType->beh.release; - if( scriptFunctions[ot->beh.release] ) scriptFunctions[ot->beh.release]->AddRefInternal(); - ot->beh.destruct = templateType->beh.destruct; - if( scriptFunctions[ot->beh.destruct] ) scriptFunctions[ot->beh.destruct]->AddRefInternal(); - ot->beh.copy = templateType->beh.copy; - if( scriptFunctions[ot->beh.copy] ) scriptFunctions[ot->beh.copy]->AddRefInternal(); - ot->beh.gcGetRefCount = templateType->beh.gcGetRefCount; - if( scriptFunctions[ot->beh.gcGetRefCount] ) scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal(); - ot->beh.gcSetFlag = templateType->beh.gcSetFlag; - if( scriptFunctions[ot->beh.gcSetFlag] ) scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal(); - ot->beh.gcGetFlag = templateType->beh.gcGetFlag; - if( scriptFunctions[ot->beh.gcGetFlag] ) scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal(); - ot->beh.gcEnumReferences = templateType->beh.gcEnumReferences; - if( scriptFunctions[ot->beh.gcEnumReferences] ) scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal(); - ot->beh.gcReleaseAllReferences = templateType->beh.gcReleaseAllReferences; - if( scriptFunctions[ot->beh.gcReleaseAllReferences] ) scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal(); - ot->beh.getWeakRefFlag = templateType->beh.getWeakRefFlag; - if( scriptFunctions[ot->beh.getWeakRefFlag] ) scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); - - // 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]->ReleaseInternal(); - 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].GetTypeInfo() ) - ot->templateSubTypes[n].GetTypeInfo()->AddRefInternal(); - - // Copy the properties to the template instance - for( n = 0; n < templateType->properties.GetLength(); n++ ) - { - asCObjectProperty *prop = templateType->properties[n]; - ot->properties.PushLast(asNEW(asCObjectProperty)(*prop)); - if( prop->type.GetTypeInfo() ) - prop->type.GetTypeInfo()->AddRefInternal(); - } - - return ot; + asUINT n; + + // Is there any template instance type or template specialization already with this subtype? + for( n = 0; n < templateInstanceTypes.GetLength(); n++ ) + { + asCObjectType *type = templateInstanceTypes[n]; + if( type && + type->name == templateType->name && + type->nameSpace == templateType->nameSpace && + type->templateSubTypes == subTypes ) + { + // If the template instance is generated, then the module should hold a reference + // to it so the config group can determine see that the template type is in use. + // Template specializations will be treated as normal types + if( requestingModule && generatedTemplateTypes.Exists(type) ) + { + if( type->module == 0 ) + { + // Set the ownership of this template type + // It may be without ownership if it was previously created from application with for example GetTypeInfoByDecl + type->module = requestingModule; + } + if( !requestingModule->m_templateInstances.Exists(type) ) + { + requestingModule->m_templateInstances.PushLast(type); + type->AddRefInternal(); + } + } + + 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].GetTypeInfo()->flags & asOBJ_VALUE)) ) + return 0; + + if( !templateType->acceptRefSubType && (subTypes[n].IsObject() && (subTypes[n].GetTypeInfo()->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; + + // If the template is being requested from a module, then the module should hold a reference to the type + if( requestingModule ) + { + // Set the ownership of this template type + ot->module = requestingModule; + requestingModule->m_templateInstances.PushLast(ot); + ot->AddRefInternal(); + } + else + { + // If the template type is not requested directly from a module, then set the ownership + // of it to the same module as one of the subtypes. If none of the subtypes are owned by] + // any module, the template instance will be without ownership and can be removed from the + // engine at any time (unless the application holds an external reference). + for( n = 0; n < subTypes.GetLength(); n++ ) + { + if( subTypes[n].GetTypeInfo() ) + { + ot->module = subTypes[n].GetTypeInfo()->module; + if( ot->module ) + { + ot->module->m_templateInstances.PushLast(ot); + ot->AddRefInternal(); + 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); + if( ot->module ) + { + ot->module->m_templateInstances.RemoveValue(ot); + ot->ReleaseInternal(); + } + ot->ReleaseInternal(); + 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]->AddRefInternal(); + } + + ot->methods = templateType->methods; + for( n = 0; n < ot->methods.GetLength(); n++ ) + scriptFunctions[ot->methods[n]]->AddRefInternal(); + + 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]]->AddRefInternal(); + + + // 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); + + // Any child funcdefs must be copied to the template instance (with adjustments in case of template subtypes) + // This must be done before resolving other methods, to make sure the other methods that may refer to the + // templated funcdef will resolve to the new funcdef + for (n = 0; n < templateType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcdef = GenerateNewTemplateFuncdef(templateType, ot, templateType->childFuncDefs[n]); + funcdef->parentClass = ot; + ot->childFuncDefs.PushLast(funcdef); + } + + // As the new template type is instantiated the engine should + // generate new functions to substitute the ones with the template subtype. + 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]->ReleaseInternal(); + 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]); + + 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]); + + if( ot->beh.constructors[n] == ot->beh.construct ) + ot->beh.construct = func->id; + + // Release previous constructor + scriptFunctions[ot->beh.constructors[n]]->ReleaseInternal(); + + 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); + + // Rename the function to easily identify it in LoadByteCode + func->name = "$list"; + + ot->beh.listFactory = func->id; + } + + ot->beh.addref = templateType->beh.addref; + if( scriptFunctions[ot->beh.addref] ) scriptFunctions[ot->beh.addref]->AddRefInternal(); + ot->beh.release = templateType->beh.release; + if( scriptFunctions[ot->beh.release] ) scriptFunctions[ot->beh.release]->AddRefInternal(); + ot->beh.destruct = templateType->beh.destruct; + if( scriptFunctions[ot->beh.destruct] ) scriptFunctions[ot->beh.destruct]->AddRefInternal(); + ot->beh.copy = templateType->beh.copy; + if( scriptFunctions[ot->beh.copy] ) scriptFunctions[ot->beh.copy]->AddRefInternal(); + ot->beh.gcGetRefCount = templateType->beh.gcGetRefCount; + if( scriptFunctions[ot->beh.gcGetRefCount] ) scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal(); + ot->beh.gcSetFlag = templateType->beh.gcSetFlag; + if( scriptFunctions[ot->beh.gcSetFlag] ) scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal(); + ot->beh.gcGetFlag = templateType->beh.gcGetFlag; + if( scriptFunctions[ot->beh.gcGetFlag] ) scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal(); + ot->beh.gcEnumReferences = templateType->beh.gcEnumReferences; + if( scriptFunctions[ot->beh.gcEnumReferences] ) scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal(); + ot->beh.gcReleaseAllReferences = templateType->beh.gcReleaseAllReferences; + if( scriptFunctions[ot->beh.gcReleaseAllReferences] ) scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal(); + ot->beh.getWeakRefFlag = templateType->beh.getWeakRefFlag; + if( scriptFunctions[ot->beh.getWeakRefFlag] ) scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); + + // 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]->ReleaseInternal(); + 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].GetTypeInfo() ) + ot->templateSubTypes[n].GetTypeInfo()->AddRefInternal(); + + // Copy the properties to the template instance + for( n = 0; n < templateType->properties.GetLength(); n++ ) + { + asCObjectProperty *prop = templateType->properties[n]; + ot->properties.PushLast(asNEW(asCObjectProperty)(*prop)); + if( prop->type.GetTypeInfo() ) + prop->type.GetTypeInfo()->AddRefInternal(); + } + + return ot; } // interface asILockableSharedBool *asCScriptEngine::GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const { - // Make sure it is not a null pointer - if( obj == 0 || type == 0 ) return 0; + // 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; + 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 @@ -3683,991 +3683,991 @@ asILockableSharedBool *asCScriptEngine::GetWeakRefFlagOfScriptObject(void *obj, // ot is the new template instance that is being created. Used to find the target type asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot) { - asCDataType dt; - if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) - { - bool found = false; - for( asUINT n = 0; n < tmpl->templateSubTypes.GetLength(); n++ ) - { - if( orig.GetTypeInfo() == tmpl->templateSubTypes[n].GetTypeInfo() ) - { - found = true; - dt = ot->templateSubTypes[n]; - if( orig.IsObjectHandle() && !ot->templateSubTypes[n].IsObjectHandle() ) - { - dt.MakeHandle(true, true); - asASSERT(dt.IsObjectHandle()); - if( orig.IsHandleToConst() ) - dt.MakeHandleToConst(true); - dt.MakeReference(orig.IsReference()); - dt.MakeReadOnly(orig.IsReadOnly()); - } - else - { - // The target type is a handle, then check if the application - // wants this handle to be to a const object. This is done by - // flagging the type with 'if_handle_then_const' in the declaration. - if (dt.IsObjectHandle() && orig.HasIfHandleThenConst()) - dt.MakeHandleToConst(true); - - dt.MakeReference(orig.IsReference()); - dt.MakeReadOnly(ot->templateSubTypes[n].IsReadOnly() || orig.IsReadOnly()); - - // If the target is a @& then don't make the handle const, - // as it is not possible to declare functions with @const & - if (orig.IsReference() && dt.IsObjectHandle()) - dt.MakeReadOnly(false); - } - break; - } - } - asASSERT( found ); - UNUSED_VAR( found ); - } - else if( orig.GetTypeInfo() == tmpl ) - { - if( orig.IsObjectHandle() ) - dt = asCDataType::CreateObjectHandle(ot, false); - else - dt = asCDataType::CreateType(ot, false); - - dt.MakeReference(orig.IsReference()); - dt.MakeReadOnly(orig.IsReadOnly()); - } - else if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) - { - // The type is itself a template, so it is necessary to find the correct template instance type - asCArray tmplSubTypes; - asCObjectType *origType = CastToObjectType(orig.GetTypeInfo()); - bool needInstance = true; - - // Find the matching replacements for the subtypes - for( asUINT n = 0; n < origType->templateSubTypes.GetLength(); n++ ) - { - if( origType->templateSubTypes[n].GetTypeInfo() == 0 || - !(origType->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) - { - // The template is already an instance so we shouldn't attempt to create another instance - needInstance = false; - break; - } - - for( asUINT m = 0; m < tmpl->templateSubTypes.GetLength(); m++ ) - if( origType->templateSubTypes[n].GetTypeInfo() == tmpl->templateSubTypes[m].GetTypeInfo() ) - 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 && - registeredTemplateTypes[n]->nameSpace == origType->nameSpace ) - { - origType = registeredTemplateTypes[n]; - break; - } - - ntype = GetTemplateInstanceType(origType, tmplSubTypes, ot->module); - 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::CreateType(ntype, false); - - dt.MakeReference(orig.IsReference()); - dt.MakeReadOnly(orig.IsReadOnly()); - } - else if (orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(orig.GetTypeInfo())->parentClass == tmpl) - { - // The type is a child funcdef. Find the corresponding child funcdef in the template instance - for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++) - { - if (ot->childFuncDefs[n]->name == orig.GetTypeInfo()->name) - { - dt = orig; - dt.SetTypeInfo(ot->childFuncDefs[n]); - } - } - } - else - dt = orig; - - return dt; + asCDataType dt; + if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) + { + bool found = false; + for( asUINT n = 0; n < tmpl->templateSubTypes.GetLength(); n++ ) + { + if( orig.GetTypeInfo() == tmpl->templateSubTypes[n].GetTypeInfo() ) + { + found = true; + dt = ot->templateSubTypes[n]; + if( orig.IsObjectHandle() && !ot->templateSubTypes[n].IsObjectHandle() ) + { + dt.MakeHandle(true, true); + asASSERT(dt.IsObjectHandle()); + if( orig.IsHandleToConst() ) + dt.MakeHandleToConst(true); + dt.MakeReference(orig.IsReference()); + dt.MakeReadOnly(orig.IsReadOnly()); + } + else + { + // The target type is a handle, then check if the application + // wants this handle to be to a const object. This is done by + // flagging the type with 'if_handle_then_const' in the declaration. + if (dt.IsObjectHandle() && orig.HasIfHandleThenConst()) + dt.MakeHandleToConst(true); + + dt.MakeReference(orig.IsReference()); + dt.MakeReadOnly(ot->templateSubTypes[n].IsReadOnly() || orig.IsReadOnly()); + + // If the target is a @& then don't make the handle const, + // as it is not possible to declare functions with @const & + if (orig.IsReference() && dt.IsObjectHandle()) + dt.MakeReadOnly(false); + } + break; + } + } + asASSERT( found ); + UNUSED_VAR( found ); + } + else if( orig.GetTypeInfo() == tmpl ) + { + if( orig.IsObjectHandle() ) + dt = asCDataType::CreateObjectHandle(ot, false); + else + dt = asCDataType::CreateType(ot, false); + + dt.MakeReference(orig.IsReference()); + dt.MakeReadOnly(orig.IsReadOnly()); + } + else if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) + { + // The type is itself a template, so it is necessary to find the correct template instance type + asCArray tmplSubTypes; + asCObjectType *origType = CastToObjectType(orig.GetTypeInfo()); + bool needInstance = true; + + // Find the matching replacements for the subtypes + for( asUINT n = 0; n < origType->templateSubTypes.GetLength(); n++ ) + { + if( origType->templateSubTypes[n].GetTypeInfo() == 0 || + !(origType->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) + { + // The template is already an instance so we shouldn't attempt to create another instance + needInstance = false; + break; + } + + for( asUINT m = 0; m < tmpl->templateSubTypes.GetLength(); m++ ) + if( origType->templateSubTypes[n].GetTypeInfo() == tmpl->templateSubTypes[m].GetTypeInfo() ) + 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 && + registeredTemplateTypes[n]->nameSpace == origType->nameSpace ) + { + origType = registeredTemplateTypes[n]; + break; + } + + ntype = GetTemplateInstanceType(origType, tmplSubTypes, ot->module); + 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::CreateType(ntype, false); + + dt.MakeReference(orig.IsReference()); + dt.MakeReadOnly(orig.IsReadOnly()); + } + else if (orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(orig.GetTypeInfo())->parentClass == tmpl) + { + // The type is a child funcdef. Find the corresponding child funcdef in the template instance + for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++) + { + if (ot->childFuncDefs[n]->name == orig.GetTypeInfo()->name) + { + dt = orig; + dt.SetTypeInfo(ot->childFuncDefs[n]); + } + } + } + else + dt = orig; + + 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->id = GetNextScriptFunctionId(); - AddScriptFunction(func); - - func->traits = factory->traits; - func->SetShared(true); - if( templateType->flags & asOBJ_REF ) - { - func->name = "$fact"; - func->returnType = asCDataType::CreateObjectHandle(ot, false); - } - else - { - func->name = "$beh0"; - func->returnType = factory->returnType; // constructors return nothing - func->objectType = ot; - func->objectType->AddRefInternal(); - } - - // Skip the first parameter as this is the object type pointer that the stub will add - func->parameterTypes.SetLength(factory->parameterTypes.GetLength()-1); - func->parameterNames.SetLength(factory->parameterNames.GetLength()-1); - func->inOutFlags.SetLength(factory->inOutFlags.GetLength()-1); - func->defaultArgs.SetLength(factory->defaultArgs.GetLength()-1); - for( asUINT p = 1; p < factory->parameterTypes.GetLength(); p++ ) - { - func->parameterTypes[p-1] = factory->parameterTypes[p]; - func->parameterNames[p-1] = factory->parameterNames[p]; - func->inOutFlags[p-1] = factory->inOutFlags[p]; - func->defaultArgs[p-1] = factory->defaultArgs[p] ? asNEW(asCString)(*factory->defaultArgs[p]) : 0; - } - func->scriptData->objVariablesOnHeap = 0; - - // Generate the bytecode for the factory stub - asUINT bcLength = asBCTypeSize[asBCInfo[asBC_OBJTYPE].type] + - asBCTypeSize[asBCInfo[asBC_CALLSYS].type] + - 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->objectType ? AS_PTR_SIZE : 0); - - 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; + 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->id = GetNextScriptFunctionId(); + AddScriptFunction(func); + + func->traits = factory->traits; + func->SetShared(true); + if( templateType->flags & asOBJ_REF ) + { + func->name = "$fact"; + func->returnType = asCDataType::CreateObjectHandle(ot, false); + } + else + { + func->name = "$beh0"; + func->returnType = factory->returnType; // constructors return nothing + func->objectType = ot; + func->objectType->AddRefInternal(); + } + + // Skip the first parameter as this is the object type pointer that the stub will add + func->parameterTypes.SetLength(factory->parameterTypes.GetLength()-1); + func->parameterNames.SetLength(factory->parameterNames.GetLength()-1); + func->inOutFlags.SetLength(factory->inOutFlags.GetLength()-1); + func->defaultArgs.SetLength(factory->defaultArgs.GetLength()-1); + for( asUINT p = 1; p < factory->parameterTypes.GetLength(); p++ ) + { + func->parameterTypes[p-1] = factory->parameterTypes[p]; + func->parameterNames[p-1] = factory->parameterNames[p]; + func->inOutFlags[p-1] = factory->inOutFlags[p]; + func->defaultArgs[p-1] = factory->defaultArgs[p] ? asNEW(asCString)(*factory->defaultArgs[p]) : 0; + } + func->scriptData->objVariablesOnHeap = 0; + + // Generate the bytecode for the factory stub + asUINT bcLength = asBCTypeSize[asBCInfo[asBC_OBJTYPE].type] + + asBCTypeSize[asBCInfo[asBC_CALLSYS].type] + + 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->objectType ? AS_PTR_SIZE : 0); + + 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.GetTypeInfo() == templateType ) return true; - if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) return true; - if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) - { - asCObjectType *ot = CastToObjectType(type.GetTypeInfo()); - for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) - if( ot->templateSubTypes[n].GetTypeInfo() && - ot->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE ) - return true; - } - if (type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(type.GetTypeInfo())->parentClass == templateType) - return true; + if( type.GetTypeInfo() == templateType ) return true; + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) return true; + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) + { + asCObjectType *ot = CastToObjectType(type.GetTypeInfo()); + for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) + if( ot->templateSubTypes[n].GetTypeInfo() && + ot->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE ) + return true; + } + if (type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(type.GetTypeInfo())->parentClass == templateType) + return true; - return false; + return false; } bool asCScriptEngine::GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *ot, asCScriptFunction *func, asCScriptFunction **newFunc) { - // Due to the objectType it is always required to generate a new function, - // even if none of the function arguments needs to be changed. + // Due to the objectType it is always required to generate a new function, + // even if none of the function arguments needs to be changed. /* - // TODO: Can we store the new function in some other optimized way to avoid - // duplicating all information just because of the different objectType member? - 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; + // TODO: Can we store the new function in some other optimized way to avoid + // duplicating all information just because of the different objectType member? + 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; - } + asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcType); + if( func2 == 0 ) + { + // Out of memory + return false; + } - func2->name = func->name; + 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); + 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); - for (asUINT n = 0; n < func->defaultArgs.GetLength(); n++) - if (func->defaultArgs[n]) - func2->defaultArgs.PushLast(asNEW(asCString)(*func->defaultArgs[n])); - else - func2->defaultArgs.PushLast(0); + for (asUINT n = 0; n < func->defaultArgs.GetLength(); n++) + if (func->defaultArgs[n]) + func2->defaultArgs.PushLast(asNEW(asCString)(*func->defaultArgs[n])); + else + func2->defaultArgs.PushLast(0); - // TODO: template: Must be careful when instantiating templates for garbage collected types - // If the template hasn't been registered with the behaviours, it shouldn't - // permit instantiation of garbage collected types that in turn may refer to - // this instance. + // TODO: template: Must be careful when instantiating templates for garbage collected types + // If the template hasn't been registered with the behaviours, it shouldn't + // permit instantiation of garbage collected types that in turn may refer to + // this instance. - func2->parameterNames = func->parameterNames; - func2->inOutFlags = func->inOutFlags; - func2->traits = func->traits; - func2->SetReadOnly(func->IsReadOnly()); - func2->objectType = ot; - func2->objectType->AddRefInternal(); - func2->sysFuncIntf = asNEW(asSSystemFunctionInterface)(*func->sysFuncIntf); + func2->parameterNames = func->parameterNames; + func2->inOutFlags = func->inOutFlags; + func2->traits = func->traits; + func2->SetReadOnly(func->IsReadOnly()); + func2->objectType = ot; + func2->objectType->AddRefInternal(); + func2->sysFuncIntf = asNEW(asSSystemFunctionInterface)(*func->sysFuncIntf); - // Adjust the clean up instructions - if( func2->sysFuncIntf->callConv == ICC_GENERIC_FUNC || - func2->sysFuncIntf->callConv == ICC_GENERIC_METHOD ) - PrepareSystemFunctionGeneric(func2, func2->sysFuncIntf, this); - else - PrepareSystemFunction(func2, func2->sysFuncIntf, this); + // Adjust the clean up instructions + if( func2->sysFuncIntf->callConv == ICC_GENERIC_FUNC || + func2->sysFuncIntf->callConv == ICC_GENERIC_METHOD ) + PrepareSystemFunctionGeneric(func2, func2->sysFuncIntf, this); + else + PrepareSystemFunction(func2, func2->sysFuncIntf, this); - func2->id = GetNextScriptFunctionId(); - AddScriptFunction(func2); + func2->id = GetNextScriptFunctionId(); + AddScriptFunction(func2); - // Return the new function - *newFunc = func2; + // Return the new function + *newFunc = func2; - return true; + return true; } asCFuncdefType *asCScriptEngine::GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *ot, asCFuncdefType *func) { - // TODO: Only generate the new funcdef if it used the template subtypes. - // Remember to also update the clean up in asCObjectType::DestroyInternal so it doesn't delete - // child funcdefs that have not been created specificially for the template instance. - // Perhaps a new funcdef is always needed, since the funcdef will have a reference to the - // parent class (in this case the template instance). + // TODO: Only generate the new funcdef if it used the template subtypes. + // Remember to also update the clean up in asCObjectType::DestroyInternal so it doesn't delete + // child funcdefs that have not been created specificially for the template instance. + // Perhaps a new funcdef is always needed, since the funcdef will have a reference to the + // parent class (in this case the template instance). - asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcdef->funcType); - if (func2 == 0) - { - // Out of memory - return 0; - } + asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcdef->funcType); + if (func2 == 0) + { + // Out of memory + return 0; + } - func2->name = func->name; + func2->name = func->name; - func2->returnType = DetermineTypeForTemplate(func->funcdef->returnType, templateType, ot); - func2->parameterTypes.SetLength(func->funcdef->parameterTypes.GetLength()); - for (asUINT p = 0; p < func->funcdef->parameterTypes.GetLength(); p++) - func2->parameterTypes[p] = DetermineTypeForTemplate(func->funcdef->parameterTypes[p], templateType, ot); + func2->returnType = DetermineTypeForTemplate(func->funcdef->returnType, templateType, ot); + func2->parameterTypes.SetLength(func->funcdef->parameterTypes.GetLength()); + for (asUINT p = 0; p < func->funcdef->parameterTypes.GetLength(); p++) + func2->parameterTypes[p] = DetermineTypeForTemplate(func->funcdef->parameterTypes[p], templateType, ot); - // TODO: template: Must be careful when instantiating templates for garbage collected types - // If the template hasn't been registered with the behaviours, it shouldn't - // permit instantiation of garbage collected types that in turn may refer to - // this instance. + // TODO: template: Must be careful when instantiating templates for garbage collected types + // If the template hasn't been registered with the behaviours, it shouldn't + // permit instantiation of garbage collected types that in turn may refer to + // this instance. - func2->inOutFlags = func->funcdef->inOutFlags; - func2->SetReadOnly(func->funcdef->IsReadOnly()); - asASSERT(func->funcdef->objectType == 0); - asASSERT(func->funcdef->sysFuncIntf == 0); + func2->inOutFlags = func->funcdef->inOutFlags; + func2->SetReadOnly(func->funcdef->IsReadOnly()); + asASSERT(func->funcdef->objectType == 0); + asASSERT(func->funcdef->sysFuncIntf == 0); - func2->id = GetNextScriptFunctionId(); - AddScriptFunction(func2); + func2->id = GetNextScriptFunctionId(); + AddScriptFunction(func2); - asCFuncdefType *fdt2 = asNEW(asCFuncdefType)(this, func2); - funcDefs.PushLast(fdt2); // don't increase refCount as the constructor already set it to 1 + asCFuncdefType *fdt2 = asNEW(asCFuncdefType)(this, func2); + funcDefs.PushLast(fdt2); // don't increase refCount as the constructor already set it to 1 - // Return the new function - return fdt2; + // Return the new function + return fdt2; } void asCScriptEngine::CallObjectMethod(void *obj, int func) const { - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - CallObjectMethod(obj, s->sysFuncIntf, s); + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + CallObjectMethod(obj, s->sysFuncIntf, s); } void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, asCScriptFunction *s) const { #if defined(__GNUC__) || defined(AS_PSVITA) - 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; - - obj = (void*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - p.f.func = (asFUNCTION_t)(i->func); - p.f.baseOffset = asPWORD(i->baseOffset); - void (asCSimpleDummy::*f)() = p.mthd; - (((asCSimpleDummy*)obj)->*f)(); - } - else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ - { - void (*f)(void *) = (void (*)(void *))(i->func); - f(obj); - } + 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; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + p.f.func = (asFUNCTION_t)(i->func); + p.f.baseOffset = asPWORD(i->baseOffset); + void (asCSimpleDummy::*f)() = p.mthd; + (((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*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - obj = (void*)(asPWORD(obj) + i->baseOffset); - (((asCSimpleDummy*)obj)->*f)(); - } - else + 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*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + 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); - } + 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; + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + asSSystemFunctionInterface *i = s->sysFuncIntf; #if defined(__GNUC__) || defined(AS_PSVITA) - 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; - - obj = (void*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - p.f.func = (asFUNCTION_t)(i->func); - p.f.baseOffset = asPWORD(i->baseOffset); - bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())(p.mthd); - 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); - } + 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; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + p.f.func = (asFUNCTION_t)(i->func); + p.f.baseOffset = asPWORD(i->baseOffset); + bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())(p.mthd); + 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*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - obj = (void*)(asPWORD(obj) + i->baseOffset); - return (((asCSimpleDummy*)obj)->*f)(); - } - else + 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*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + 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); - } + 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; + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + asSSystemFunctionInterface *i = s->sysFuncIntf; #if defined(__GNUC__) || defined(AS_PSVITA) - 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); - - obj = (void*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - 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); - } + 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); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + 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*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - obj = (void*)(asPWORD(obj) + i->baseOffset); - return (((asCSimpleDummy*)obj)->*f)(); - } - else + 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*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + 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); - } + 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; + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + asSSystemFunctionInterface *i = s->sysFuncIntf; #if defined(__GNUC__) || defined(AS_PSVITA) - 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); - - obj = (void*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - 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); - } + 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); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + 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*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - obj = (void*)(asPWORD(obj) + i->baseOffset); - return (((asCSimpleDummy*)obj)->*f)(); - } - else + 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*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + 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); - } + 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::CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const { - asASSERT( obj != 0 ); - asASSERT( func != 0 ); - asSSystemFunctionInterface *i = func->sysFuncIntf; + asASSERT( obj != 0 ); + asASSERT( func != 0 ); + asSSystemFunctionInterface *i = func->sysFuncIntf; #ifndef AS_NO_CLASS_METHODS - if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) - { + if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) + { #if defined(__GNUC__) || defined(AS_PSVITA) - // 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); - - obj = (void*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))(p.mthd); - return (((asCSimpleDummy*)obj)->*f)(param1); + // 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); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))(p.mthd); + return (((asCSimpleDummy*)obj)->*f)(param1); #else - union - { - asSIMPLEMETHOD_t mthd; - asFUNCTION_t func; - } p; - p.func = (asFUNCTION_t)(i->func); - void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))p.mthd; - - obj = (void*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - obj = (void*)(asPWORD(obj) + i->baseOffset); - return (((asCSimpleDummy*)obj)->*f)(param1); + union + { + asSIMPLEMETHOD_t mthd; + asFUNCTION_t func; + } p; + p.func = (asFUNCTION_t)(i->func); + void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + obj = (void*)(asPWORD(obj) + i->baseOffset); + return (((asCSimpleDummy*)obj)->*f)(param1); #endif - } - else + } + else #endif - if( i->callConv == ICC_GENERIC_METHOD ) - { - asCGeneric gen(const_cast(this), func, obj, reinterpret_cast(¶m1)); - void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); - f(&gen); - return *(void **)gen.GetReturnPointer(); - } - else if( i->callConv == ICC_CDECL_OBJLAST ) - { - void *(*f)(int, void *) = (void *(*)(int, void *))(i->func); - return f(param1, obj); - } - else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/ - { - void *(*f)(void *, int) = (void *(*)(void *, int))(i->func); - return f(obj, param1); - } + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), func, obj, reinterpret_cast(¶m1)); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(void **)gen.GetReturnPointer(); + } + else if( i->callConv == ICC_CDECL_OBJLAST ) + { + void *(*f)(int, void *) = (void *(*)(int, void *))(i->func); + return f(param1, obj); + } + else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/ + { + void *(*f)(void *, int) = (void *(*)(void *, int))(i->func); + return f(obj, param1); + } } void *asCScriptEngine::CallGlobalFunctionRetPtr(int func) const { - asCScriptFunction *s = scriptFunctions[func]; - asASSERT( s != 0 ); - return CallGlobalFunctionRetPtr(s->sysFuncIntf, s); + 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); + 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(); - } + 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(); - } + 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); + 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 { #if defined(__GNUC__) || defined(AS_PSVITA) - 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); - - obj = (void*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - void (asCSimpleDummy::*f)(void*) = (void (asCSimpleDummy::*)(void*))(p.mthd); - (((asCSimpleDummy*)obj)->*f)(param); - } - else /*if( i->callConv == ICC_CDECL_OBJFIRST */ - { - void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); - f(obj, param); - } + 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); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + void (asCSimpleDummy::*f)(void*) = (void (asCSimpleDummy::*)(void*))(p.mthd); + (((asCSimpleDummy*)obj)->*f)(param); + } + 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*) ((char*) obj + i->compositeOffset); - if(i->isCompositeIndirect) - obj = *((void**)obj); - - obj = (void*)(asPWORD(obj) + i->baseOffset); - (((asCSimpleDummy*)obj)->*f)(param); - } - else + 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*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + 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); - } + 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); - } + 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(); - } + 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. + // 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); + // 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__); + return ((asALLOCFUNCDEBUG_t)userAlloc)(size, __FILE__, __LINE__); #else - return userAlloc(size); + return userAlloc(size); #endif #else #if defined(AS_DEBUG) - return ((asALLOCALIGNEDFUNCDEBUG_t)userAllocAligned)(size, type->alignment, __FILE__, __LINE__); + return ((asALLOCALIGNEDFUNCDEBUG_t)userAllocAligned)(size, type->alignment, __FILE__, __LINE__); #else - return userAllocAligned(size, type->alignment); + return userAllocAligned(size, type->alignment); #endif #endif } @@ -4675,1924 +4675,1924 @@ void *asCScriptEngine::CallAlloc(const asCObjectType *type) const void asCScriptEngine::CallFree(void *obj) const { #ifndef WIP_16BYTE_ALIGN - userFree(obj); + userFree(obj); #else - userFreeAligned(obj); + userFreeAligned(obj); #endif } // interface int asCScriptEngine::NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type) { - return gc.AddScriptObjectToGC(obj, static_cast(type)); + return gc.AddScriptObjectToGC(obj, static_cast(type)); } // interface int asCScriptEngine::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type) { - return gc.GetObjectInGC(idx, seqNbr, obj, type); + return gc.GetObjectInGC(idx, seqNbr, obj, type); } // interface int asCScriptEngine::GarbageCollect(asDWORD flags, asUINT iterations) { - int r = gc.GarbageCollect(flags, iterations); + int r = gc.GarbageCollect(flags, iterations); - if( r == 0 ) - { - // Delete any modules that have been discarded previously but not - // removed due to being referred to by objects in the garbage collector - DeleteDiscardedModules(); - } + if( r == 0 ) + { + // Delete any modules that have been discarded previously but not + // removed due to being referred to by objects in the garbage collector + DeleteDiscardedModules(); + } - return r; + return r; } // interface void asCScriptEngine::GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const { - gc.GetStatistics(currentSize, totalDestroyed, totalDetected, newObjects, totalNewDestroyed); + gc.GetStatistics(currentSize, totalDestroyed, totalDetected, newObjects, totalNewDestroyed); } // interface void asCScriptEngine::GCEnumCallback(void *reference) { - gc.GCEnumCallback(reference); + gc.GCEnumCallback(reference); } // interface void asCScriptEngine::ForwardGCEnumReferences(void *ref, asITypeInfo *type) { - asCTypeInfo *t = reinterpret_cast(type); - if ((t->flags & asOBJ_VALUE) && (t->flags & asOBJ_GC)) - { - CallObjectMethod(ref, this, CastToObjectType(t)->beh.gcEnumReferences); - } + asCTypeInfo *t = reinterpret_cast(type); + if ((t->flags & asOBJ_VALUE) && (t->flags & asOBJ_GC)) + { + CallObjectMethod(ref, this, CastToObjectType(t)->beh.gcEnumReferences); + } } // interface void asCScriptEngine::ForwardGCReleaseReferences(void *ref, asITypeInfo *type) { - asCTypeInfo *t = reinterpret_cast(type); - if ((t->flags & asOBJ_VALUE) && (t->flags & asOBJ_GC)) - { - CallObjectMethod(ref, this, CastToObjectType(t)->beh.gcReleaseAllReferences); - } + asCTypeInfo *t = reinterpret_cast(type); + if ((t->flags & asOBJ_VALUE) && (t->flags & asOBJ_GC)) + { + CallObjectMethod(ref, this, CastToObjectType(t)->beh.gcReleaseAllReferences); + } } // interface void asCScriptEngine::SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param) { - gc.circularRefDetectCallbackFunc = callback; - gc.circularRefDetectCallbackParam = param; + gc.circularRefDetectCallbackFunc = callback; + gc.circularRefDetectCallbackParam = param; } int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const { - if( dtIn.IsNullHandle() ) return asTYPEID_VOID; - - if( dtIn.GetTypeInfo() == 0 ) - { - // Primitives have pre-fixed typeIds - switch( dtIn.GetTokenType() ) - { - case ttVoid: return asTYPEID_VOID; - case ttBool: return asTYPEID_BOOL; - case ttInt8: return asTYPEID_INT8; - case ttInt16: return asTYPEID_INT16; - case ttInt: return asTYPEID_INT32; - case ttInt64: return asTYPEID_INT64; - case ttUInt8: return asTYPEID_UINT8; - case ttUInt16: return asTYPEID_UINT16; - case ttUInt: return asTYPEID_UINT32; - case ttUInt64: return asTYPEID_UINT64; - case ttFloat: return asTYPEID_FLOAT; - case ttDouble: return asTYPEID_DOUBLE; - default: - // All types should be covered by the above. The variable type is not really a type - asASSERT(dtIn.GetTokenType() == ttQuestion); - return -1; - } - } - - int typeId = -1; - asCTypeInfo *ot = dtIn.GetTypeInfo(); - asASSERT(ot != &functionBehaviours); - // Object's hold the typeId themselves - typeId = ot->typeId; - - if( typeId == -1 ) - { - ACQUIREEXCLUSIVE(engineRWLock); - // Make sure another thread didn't determine the typeId while we were waiting for the lock - if( ot->typeId == -1 ) - { - typeId = typeIdSeqNbr++; - if( ot->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT; - else if( ot->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE; - else if( ot->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this? - else typeId |= asTYPEID_APPOBJECT; - - ot->typeId = typeId; - - mapTypeIdToTypeInfo.Insert(typeId, ot); - } - RELEASEEXCLUSIVE(engineRWLock); - } - - // Add flags according to the requested type - if( dtIn.GetTypeInfo() && !(dtIn.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) - { - // The ASHANDLE types behave like handles, but are really - // value types so the typeId is never returned as a handle - if( dtIn.IsObjectHandle() ) - typeId |= asTYPEID_OBJHANDLE; - if( dtIn.IsHandleToConst() ) - typeId |= asTYPEID_HANDLETOCONST; - } - - return typeId; + if( dtIn.IsNullHandle() ) return asTYPEID_VOID; + + if( dtIn.GetTypeInfo() == 0 ) + { + // Primitives have pre-fixed typeIds + switch( dtIn.GetTokenType() ) + { + case ttVoid: return asTYPEID_VOID; + case ttBool: return asTYPEID_BOOL; + case ttInt8: return asTYPEID_INT8; + case ttInt16: return asTYPEID_INT16; + case ttInt: return asTYPEID_INT32; + case ttInt64: return asTYPEID_INT64; + case ttUInt8: return asTYPEID_UINT8; + case ttUInt16: return asTYPEID_UINT16; + case ttUInt: return asTYPEID_UINT32; + case ttUInt64: return asTYPEID_UINT64; + case ttFloat: return asTYPEID_FLOAT; + case ttDouble: return asTYPEID_DOUBLE; + default: + // All types should be covered by the above. The variable type is not really a type + asASSERT(dtIn.GetTokenType() == ttQuestion); + return -1; + } + } + + int typeId = -1; + asCTypeInfo *ot = dtIn.GetTypeInfo(); + asASSERT(ot != &functionBehaviours); + // Object's hold the typeId themselves + typeId = ot->typeId; + + if( typeId == -1 ) + { + ACQUIREEXCLUSIVE(engineRWLock); + // Make sure another thread didn't determine the typeId while we were waiting for the lock + if( ot->typeId == -1 ) + { + typeId = typeIdSeqNbr++; + if( ot->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT; + else if( ot->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE; + else if( ot->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this? + else typeId |= asTYPEID_APPOBJECT; + + ot->typeId = typeId; + + mapTypeIdToTypeInfo.Insert(typeId, ot); + } + RELEASEEXCLUSIVE(engineRWLock); + } + + // Add flags according to the requested type + if( dtIn.GetTypeInfo() && !(dtIn.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) + { + // The ASHANDLE types behave like handles, but are really + // value types so the typeId is never returned as a handle + if( dtIn.IsObjectHandle() ) + typeId |= asTYPEID_OBJHANDLE; + if( dtIn.IsHandleToConst() ) + typeId |= asTYPEID_HANDLETOCONST; + } + + return typeId; } asCDataType asCScriptEngine::GetDataTypeFromTypeId(int typeId) const { - int baseId = typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR); + int baseId = typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR); - if( typeId <= asTYPEID_DOUBLE ) - { - eTokenType type[] = {ttVoid, ttBool, ttInt8, ttInt16, ttInt, ttInt64, ttUInt8, ttUInt16, ttUInt, ttUInt64, ttFloat, ttDouble}; - return asCDataType::CreatePrimitive(type[typeId], false); - } + if( typeId <= asTYPEID_DOUBLE ) + { + eTokenType type[] = {ttVoid, ttBool, ttInt8, ttInt16, ttInt, ttInt64, ttUInt8, ttUInt16, ttUInt, ttUInt64, ttFloat, ttDouble}; + return asCDataType::CreatePrimitive(type[typeId], false); + } - // First check if the typeId is an object type - asCTypeInfo *ot = 0; - ACQUIRESHARED(engineRWLock); - asSMapNode *cursor = 0; - if( mapTypeIdToTypeInfo.MoveTo(&cursor, baseId) ) - ot = mapTypeIdToTypeInfo.GetValue(cursor); - RELEASESHARED(engineRWLock); + // First check if the typeId is an object type + asCTypeInfo *ot = 0; + ACQUIRESHARED(engineRWLock); + asSMapNode *cursor = 0; + if( mapTypeIdToTypeInfo.MoveTo(&cursor, baseId) ) + ot = mapTypeIdToTypeInfo.GetValue(cursor); + RELEASESHARED(engineRWLock); - if( ot ) - { - asCDataType dt = asCDataType::CreateType(ot, false); - if( typeId & asTYPEID_OBJHANDLE ) - dt.MakeHandle(true, true); - if( typeId & asTYPEID_HANDLETOCONST ) - dt.MakeHandleToConst(true); + if( ot ) + { + asCDataType dt = asCDataType::CreateType(ot, false); + if( typeId & asTYPEID_OBJHANDLE ) + dt.MakeHandle(true, true); + if( typeId & asTYPEID_HANDLETOCONST ) + dt.MakeHandleToConst(true); - return dt; - } + return dt; + } - return asCDataType(); + return asCDataType(); } asCObjectType *asCScriptEngine::GetObjectTypeFromTypeId(int typeId) const { - asCDataType dt = GetDataTypeFromTypeId(typeId); - return CastToObjectType(dt.GetTypeInfo()); + asCDataType dt = GetDataTypeFromTypeId(typeId); + return CastToObjectType(dt.GetTypeInfo()); } void asCScriptEngine::RemoveFromTypeIdMap(asCTypeInfo *type) { - ACQUIREEXCLUSIVE(engineRWLock); - asSMapNode *cursor = 0; - mapTypeIdToTypeInfo.MoveFirst(&cursor); - while( cursor ) - { - if(mapTypeIdToTypeInfo.GetValue(cursor) == type ) - { - mapTypeIdToTypeInfo.Erase(cursor); - break; - } - mapTypeIdToTypeInfo.MoveNext(&cursor, cursor); - } - RELEASEEXCLUSIVE(engineRWLock); + ACQUIREEXCLUSIVE(engineRWLock); + asSMapNode *cursor = 0; + mapTypeIdToTypeInfo.MoveFirst(&cursor); + while( cursor ) + { + if(mapTypeIdToTypeInfo.GetValue(cursor) == type ) + { + mapTypeIdToTypeInfo.Erase(cursor); + break; + } + mapTypeIdToTypeInfo.MoveNext(&cursor, cursor); + } + RELEASEEXCLUSIVE(engineRWLock); } // interface asITypeInfo *asCScriptEngine::GetTypeInfoByDecl(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); + 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; + // Don't write parser errors to the message callback + bld.silent = true; - int r = bld.ParseDataType(decl, &dt, defaultNamespace); - if (r < 0) - return 0; + int r = bld.ParseDataType(decl, &dt, defaultNamespace); + if (r < 0) + return 0; - return dt.GetTypeInfo(); + return dt.GetTypeInfo(); } // 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); + 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; + // 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; + int r = bld.ParseDataType(decl, &dt, defaultNamespace); + if( r < 0 ) + return asINVALID_TYPE; - return GetTypeIdFromDataType(dt); + return GetTypeIdFromDataType(dt); } // interface const char *asCScriptEngine::GetTypeDeclaration(int typeId, bool includeNamespace) const { - asCDataType dt = GetDataTypeFromTypeId(typeId); + asCDataType dt = GetDataTypeFromTypeId(typeId); - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = dt.Format(defaultNamespace, includeNamespace); + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = dt.Format(defaultNamespace, includeNamespace); - return tempString->AddressOf(); + return tempString->AddressOf(); } // interface int asCScriptEngine::GetSizeOfPrimitiveType(int typeId) const { - asCDataType dt = GetDataTypeFromTypeId(typeId); - if( !dt.IsPrimitive() ) return 0; + asCDataType dt = GetDataTypeFromTypeId(typeId); + if( !dt.IsPrimitive() ) return 0; - return dt.GetSizeInMemoryBytes(); + return dt.GetSizeInMemoryBytes(); } // interface int asCScriptEngine::RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast) { - if( newPtr == 0 ) return asINVALID_ARG; - *newPtr = 0; - - if( fromType == 0 || toType == 0 ) return asINVALID_ARG; - - // A null-pointer can always be cast to another type, so it will always be successful - if( obj == 0 ) - return asSUCCESS; - - if( fromType == toType ) - { - *newPtr = obj; - AddRefScriptObject(*newPtr, toType); - return asSUCCESS; - } - - // Check for funcdefs - if ((fromType->GetFlags() & asOBJ_FUNCDEF) && (toType->GetFlags() & asOBJ_FUNCDEF)) - { - asCFuncdefType *fromFunc = CastToFuncdefType(reinterpret_cast(fromType)); - asCFuncdefType *toFunc = CastToFuncdefType(reinterpret_cast(toType)); - - if (fromFunc && toFunc && fromFunc->funcdef->IsSignatureExceptNameEqual(toFunc->funcdef)) - { - *newPtr = obj; - AddRefScriptObject(*newPtr, toType); - return asSUCCESS; - } - - return asSUCCESS; - } - - // Look for ref cast behaviours - asCScriptFunction *universalCastFunc = 0; - asCObjectType *from = reinterpret_cast(fromType); - for( asUINT n = 0; n < from->methods.GetLength(); n++ ) - { - asCScriptFunction *func = scriptFunctions[from->methods[n]]; - if( func->name == "opImplCast" || - (!useOnlyImplicitCast && func->name == "opCast") ) - { - if( func->returnType.GetTypeInfo() == toType ) - { - *newPtr = CallObjectMethodRetPtr(obj, func->id); - // The ref cast behaviour returns a handle with incremented - // ref counter, so there is no need to call AddRef explicitly - // unless the function is registered with autohandle - if( func->sysFuncIntf->returnAutoHandle ) - AddRefScriptObject(*newPtr, toType); - return asSUCCESS; - } - else if( func->returnType.GetTokenType() == ttVoid && - func->parameterTypes.GetLength() == 1 && - func->parameterTypes[0].GetTokenType() == ttQuestion ) - { - universalCastFunc = func; - } - } - } - - // One last chance if the object has a void opCast(?&out) behaviour - if( universalCastFunc ) - { - // TODO: Add proper error handling - asIScriptContext *ctx = RequestContext(); - ctx->Prepare(universalCastFunc); - ctx->SetObject(obj); - ctx->SetArgVarType(0, newPtr, toType->GetTypeId() | asTYPEID_OBJHANDLE); - ctx->Execute(); - ReturnContext(ctx); - - // The opCast(?&out) method already incremented the - // refCount so there is no need to do it manually - return asSUCCESS; - } - - // For script classes and interfaces there is a quick route - if( (fromType->GetFlags() & asOBJ_SCRIPT_OBJECT) && (toType->GetFlags() & asOBJ_SCRIPT_OBJECT) ) - { - if( fromType == toType ) - { - *newPtr = obj; - reinterpret_cast(*newPtr)->AddRef(); - return asSUCCESS; - } - - // Up casts to base class or interface can be done implicitly - if( fromType->DerivesFrom(toType) || - fromType->Implements(toType) ) - { - *newPtr = obj; - reinterpret_cast(*newPtr)->AddRef(); - return asSUCCESS; - } - // Down casts to derived class or from interface can only be done explicitly - if( !useOnlyImplicitCast ) - { - // Get the true type of the object so the explicit cast can evaluate all possibilities - asITypeInfo *trueType = reinterpret_cast(obj)->GetObjectType(); - if (trueType->DerivesFrom(toType) || - trueType->Implements(toType)) - { - *newPtr = obj; - reinterpret_cast(*newPtr)->AddRef(); - return asSUCCESS; - } - } - } - - // The cast is not available, but it is still a success - return asSUCCESS; + if( newPtr == 0 ) return asINVALID_ARG; + *newPtr = 0; + + if( fromType == 0 || toType == 0 ) return asINVALID_ARG; + + // A null-pointer can always be cast to another type, so it will always be successful + if( obj == 0 ) + return asSUCCESS; + + if( fromType == toType ) + { + *newPtr = obj; + AddRefScriptObject(*newPtr, toType); + return asSUCCESS; + } + + // Check for funcdefs + if ((fromType->GetFlags() & asOBJ_FUNCDEF) && (toType->GetFlags() & asOBJ_FUNCDEF)) + { + asCFuncdefType *fromFunc = CastToFuncdefType(reinterpret_cast(fromType)); + asCFuncdefType *toFunc = CastToFuncdefType(reinterpret_cast(toType)); + + if (fromFunc && toFunc && fromFunc->funcdef->IsSignatureExceptNameEqual(toFunc->funcdef)) + { + *newPtr = obj; + AddRefScriptObject(*newPtr, toType); + return asSUCCESS; + } + + return asSUCCESS; + } + + // Look for ref cast behaviours + asCScriptFunction *universalCastFunc = 0; + asCObjectType *from = reinterpret_cast(fromType); + for( asUINT n = 0; n < from->methods.GetLength(); n++ ) + { + asCScriptFunction *func = scriptFunctions[from->methods[n]]; + if( func->name == "opImplCast" || + (!useOnlyImplicitCast && func->name == "opCast") ) + { + if( func->returnType.GetTypeInfo() == toType ) + { + *newPtr = CallObjectMethodRetPtr(obj, func->id); + // The ref cast behaviour returns a handle with incremented + // ref counter, so there is no need to call AddRef explicitly + // unless the function is registered with autohandle + if( func->sysFuncIntf->returnAutoHandle ) + AddRefScriptObject(*newPtr, toType); + return asSUCCESS; + } + else if( func->returnType.GetTokenType() == ttVoid && + func->parameterTypes.GetLength() == 1 && + func->parameterTypes[0].GetTokenType() == ttQuestion ) + { + universalCastFunc = func; + } + } + } + + // One last chance if the object has a void opCast(?&out) behaviour + if( universalCastFunc ) + { + // TODO: Add proper error handling + asIScriptContext *ctx = RequestContext(); + ctx->Prepare(universalCastFunc); + ctx->SetObject(obj); + ctx->SetArgVarType(0, newPtr, toType->GetTypeId() | asTYPEID_OBJHANDLE); + ctx->Execute(); + ReturnContext(ctx); + + // The opCast(?&out) method already incremented the + // refCount so there is no need to do it manually + return asSUCCESS; + } + + // For script classes and interfaces there is a quick route + if( (fromType->GetFlags() & asOBJ_SCRIPT_OBJECT) && (toType->GetFlags() & asOBJ_SCRIPT_OBJECT) ) + { + if( fromType == toType ) + { + *newPtr = obj; + reinterpret_cast(*newPtr)->AddRef(); + return asSUCCESS; + } + + // Up casts to base class or interface can be done implicitly + if( fromType->DerivesFrom(toType) || + fromType->Implements(toType) ) + { + *newPtr = obj; + reinterpret_cast(*newPtr)->AddRef(); + return asSUCCESS; + } + // Down casts to derived class or from interface can only be done explicitly + if( !useOnlyImplicitCast ) + { + // Get the true type of the object so the explicit cast can evaluate all possibilities + asITypeInfo *trueType = reinterpret_cast(obj)->GetObjectType(); + if (trueType->DerivesFrom(toType) || + trueType->Implements(toType)) + { + *newPtr = obj; + reinterpret_cast(*newPtr)->AddRef(); + return asSUCCESS; + } + } + } + + // The cast is not available, but it is still a success + return asSUCCESS; } // interface void *asCScriptEngine::CreateScriptObject(const asITypeInfo *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) ) - { - // TODO: How to report the reason the object couldn't be created, without writing to the message callback? optional argument with return code? - // TODO: Warn about the invalid call to message callback. Make it an optional, so the warning can be turned off -// asCString str; -// str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION); -// WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return 0; - } - - // 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) && (objType->flags & asOBJ_REF) ) - { - // The registered factory that takes the object type is moved - // to the construct behaviour when the type is instantiated + 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) ) + { + // TODO: How to report the reason the object couldn't be created, without writing to the message callback? optional argument with return code? + // TODO: Warn about the invalid call to message callback. Make it an optional, so the warning can be turned off +// asCString str; +// str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION); +// WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return 0; + } + + // 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) && (objType->flags & asOBJ_REF) ) + { + // 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); + ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType); #else - try - { - ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType); - } - catch (...) - { - asCContext *ctx = reinterpret_cast(asGetActiveContext()); - if (ctx) - ctx->HandleAppException(); - } + try + { + ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType); + } + catch (...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if (ctx) + ctx->HandleAppException(); + } #endif - } - else if( objType->flags & asOBJ_REF ) - { - // Call the default factory directly + } + else if( objType->flags & asOBJ_REF ) + { + // Call the default factory directly #ifdef AS_NO_EXCEPTIONS - ptr = CallGlobalFunctionRetPtr(objType->beh.factory); + ptr = CallGlobalFunctionRetPtr(objType->beh.factory); #else - try - { - ptr = CallGlobalFunctionRetPtr(objType->beh.factory); - } - catch(...) - { - asCContext *ctx = reinterpret_cast(asGetActiveContext()); - if( ctx ) - ctx->HandleAppException(); - } + try + { + ptr = CallGlobalFunctionRetPtr(objType->beh.factory); + } + catch(...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if( ctx ) + ctx->HandleAppException(); + } #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) ) - { - // TODO: How to report the reason the object couldn't be created, without writing to the message callback? optional argument with return code? - // TODO: Warn about the invalid call to message callback. Make it an optional, so the warning can be turned off -// asCString str; -// str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION); -// WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); - return 0; - } - - // Manually allocate the memory, then call the default constructor - ptr = CallAlloc(objType); - int funcIndex = objType->beh.construct; - if (funcIndex) - { - if (objType->flags & asOBJ_TEMPLATE) - { - // Templates of value types create script functions as the constructors - CallScriptObjectMethod(ptr, funcIndex); - } - else - { + } + else + { + // Make sure there is a default constructor or that it is a POD type + if( objType->beh.construct == 0 && !(objType->flags & asOBJ_POD) ) + { + // TODO: How to report the reason the object couldn't be created, without writing to the message callback? optional argument with return code? + // TODO: Warn about the invalid call to message callback. Make it an optional, so the warning can be turned off +// asCString str; +// str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION); +// WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return 0; + } + + // Manually allocate the memory, then call the default constructor + ptr = CallAlloc(objType); + int funcIndex = objType->beh.construct; + if (funcIndex) + { + if (objType->flags & asOBJ_TEMPLATE) + { + // Templates of value types create script functions as the constructors + CallScriptObjectMethod(ptr, funcIndex); + } + else + { #ifdef AS_NO_EXCEPTIONS - CallObjectMethod(ptr, funcIndex); + CallObjectMethod(ptr, funcIndex); #else - try - { - CallObjectMethod(ptr, funcIndex); - } - catch (...) - { - asCContext *ctx = reinterpret_cast(asGetActiveContext()); - if (ctx) - ctx->HandleAppException(); - - // Free the memory - CallFree(ptr); - ptr = 0; - } + try + { + CallObjectMethod(ptr, funcIndex); + } + catch (...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if (ctx) + ctx->HandleAppException(); + + // Free the memory + CallFree(ptr); + ptr = 0; + } #endif - } - } - } + } + } + } - return ptr; + return ptr; } // internal int asCScriptEngine::CallScriptObjectMethod(void *obj, int funcId) { - asIScriptContext *ctx = 0; - int r = 0; - bool isNested = false; - - // Use nested call in the context if there is an active context - ctx = asGetActiveContext(); - if (ctx) - { - // It may not always be possible to reuse the current context, - // in which case we'll have to create a new one any way. - if (ctx->GetEngine() == this && ctx->PushState() == asSUCCESS) - isNested = true; - else - ctx = 0; - } - - if (ctx == 0) - { - // Request a context from the engine - ctx = RequestContext(); - if (ctx == 0) - { - // TODO: How to best report this failure? - return asERROR; - } - } - - r = ctx->Prepare(scriptFunctions[funcId]); - if (r < 0) - { - if (isNested) - ctx->PopState(); - else - ReturnContext(ctx); - // TODO: How to best report this failure? - return asERROR; - } - - // Set the object - ctx->SetObject(obj); - - for (;;) - { - r = ctx->Execute(); - - // We can't allow this execution to be suspended - // so resume the execution immediately - if (r != asEXECUTION_SUSPENDED) - break; - } - - if (r != asEXECUTION_FINISHED) - { - if (isNested) - { - ctx->PopState(); - - // If the execution was aborted or an exception occurred, - // then we should forward that to the outer execution. - if (r == asEXECUTION_EXCEPTION) - { - // TODO: How to improve this exception - ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); - } - else if (r == asEXECUTION_ABORTED) - ctx->Abort(); - } - else - ReturnContext(ctx); - - // TODO: How to best report the error? - return asERROR; - } - - if (isNested) - ctx->PopState(); - else - ReturnContext(ctx); - - return asSUCCESS; + asIScriptContext *ctx = 0; + int r = 0; + bool isNested = false; + + // Use nested call in the context if there is an active context + ctx = asGetActiveContext(); + if (ctx) + { + // It may not always be possible to reuse the current context, + // in which case we'll have to create a new one any way. + if (ctx->GetEngine() == this && ctx->PushState() == asSUCCESS) + isNested = true; + else + ctx = 0; + } + + if (ctx == 0) + { + // Request a context from the engine + ctx = RequestContext(); + if (ctx == 0) + { + // TODO: How to best report this failure? + return asERROR; + } + } + + r = ctx->Prepare(scriptFunctions[funcId]); + if (r < 0) + { + if (isNested) + ctx->PopState(); + else + ReturnContext(ctx); + // TODO: How to best report this failure? + return asERROR; + } + + // Set the object + ctx->SetObject(obj); + + for (;;) + { + r = ctx->Execute(); + + // We can't allow this execution to be suspended + // so resume the execution immediately + if (r != asEXECUTION_SUSPENDED) + break; + } + + if (r != asEXECUTION_FINISHED) + { + if (isNested) + { + ctx->PopState(); + + // If the execution was aborted or an exception occurred, + // then we should forward that to the outer execution. + if (r == asEXECUTION_EXCEPTION) + { + // TODO: How to improve this exception + ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); + } + else if (r == asEXECUTION_ABORTED) + ctx->Abort(); + } + else + ReturnContext(ctx); + + // TODO: How to best report the error? + return asERROR; + } + + if (isNested) + ctx->PopState(); + else + ReturnContext(ctx); + + return asSUCCESS; } // interface void *asCScriptEngine::CreateUninitializedScriptObject(const asITypeInfo *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; + // 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)); + 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)); + // 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); + // Pre-initialize the memory so there are no invalid pointers + ScriptObject_ConstructUnitialized(objType, obj); - return obj; + return obj; } // interface void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asITypeInfo *type) { - if( origObj == 0 || type == 0 ) return 0; + if( origObj == 0 || type == 0 ) return 0; - void *newObj = 0; + void *newObj = 0; - const asCObjectType *ot = reinterpret_cast(type); - if ((ot->flags & asOBJ_SCRIPT_OBJECT) && ot->beh.copyfactory) - { - // Call the script class' default factory with a context - newObj = ScriptObjectCopyFactory(ot, origObj, this); - } - else if (ot->beh.copyfactory) - { - // Call the copy factory which will allocate the memory then copy the original object + const asCObjectType *ot = reinterpret_cast(type); + if ((ot->flags & asOBJ_SCRIPT_OBJECT) && ot->beh.copyfactory) + { + // Call the script class' default factory with a context + newObj = ScriptObjectCopyFactory(ot, origObj, this); + } + else if (ot->beh.copyfactory) + { + // Call the copy factory which will allocate the memory then copy the original object #ifdef AS_NO_EXCEPTIONS - newObj = CallGlobalFunctionRetPtr(ot->beh.copyfactory, origObj); + newObj = CallGlobalFunctionRetPtr(ot->beh.copyfactory, origObj); #else - try - { - newObj = CallGlobalFunctionRetPtr(ot->beh.copyfactory, origObj); - } - catch (...) - { - asCContext *ctx = reinterpret_cast(asGetActiveContext()); - if (ctx) - ctx->HandleAppException(); - } + try + { + newObj = CallGlobalFunctionRetPtr(ot->beh.copyfactory, origObj); + } + catch (...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if (ctx) + ctx->HandleAppException(); + } #endif - } - else if( ot->beh.copyconstruct ) - { - // Manually allocate the memory, then call the copy constructor - newObj = CallAlloc(ot); + } + else 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); + CallObjectMethod(newObj, origObj, ot->beh.copyconstruct); #else - try - { - CallObjectMethod(newObj, origObj, ot->beh.copyconstruct); - } - catch(...) - { - asCContext *ctx = reinterpret_cast(asGetActiveContext()); - if( ctx ) - ctx->HandleAppException(); - - // Free the memory - CallFree(newObj); - newObj = 0; - } + try + { + CallObjectMethod(newObj, origObj, ot->beh.copyconstruct); + } + catch(...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if( ctx ) + ctx->HandleAppException(); + + // 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; + } + else + { + // Allocate the object and then do a value assign + newObj = CreateScriptObject(type); + if( newObj == 0 ) return 0; - AssignScriptObject(newObj, origObj, type); - } + AssignScriptObject(newObj, origObj, type); + } - return newObj; + return newObj; } // internal void asCScriptEngine::ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type) { - if( type == 0 || mem == 0 || obj == 0 ) return; + if( type == 0 || mem == 0 || obj == 0 ) return; - // This function is only meant to be used for value types - asASSERT( type->flags & asOBJ_VALUE ); + // 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); + // 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); - } + AssignScriptObject(mem, obj, type); + } } // interface int asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type) { - // TODO: Warn about invalid call in message stream (make it optional) - if( type == 0 || dstObj == 0 || srcObj == 0 ) return asINVALID_ARG; - - const asCObjectType *objType = reinterpret_cast(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)) - { - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException("Cannot do value assignment"); - return asNOT_SUPPORTED; - } - - // 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); - } - - return asSUCCESS; + // TODO: Warn about invalid call in message stream (make it optional) + if( type == 0 || dstObj == 0 || srcObj == 0 ) return asINVALID_ARG; + + const asCObjectType *objType = reinterpret_cast(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)) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Cannot do value assignment"); + return asNOT_SUPPORTED; + } + + // 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); + } + + return asSUCCESS; } // interface void asCScriptEngine::AddRefScriptObject(void *obj, const asITypeInfo *type) { - // Make sure it is not a null pointer - if( obj == 0 || type == 0 ) return; - - const asCTypeInfo *ti = static_cast(type); - if (ti->flags & asOBJ_FUNCDEF) - { - CallObjectMethod(obj, functionBehaviours.beh.addref); - } - else - { - asCObjectType *objType = CastToObjectType(const_cast(ti)); - if (objType && objType->beh.addref) - { - // Call the addref behaviour - CallObjectMethod(obj, objType->beh.addref); - } - } + // Make sure it is not a null pointer + if( obj == 0 || type == 0 ) return; + + const asCTypeInfo *ti = static_cast(type); + if (ti->flags & asOBJ_FUNCDEF) + { + CallObjectMethod(obj, functionBehaviours.beh.addref); + } + else + { + asCObjectType *objType = CastToObjectType(const_cast(ti)); + if (objType && objType->beh.addref) + { + // Call the addref behaviour + CallObjectMethod(obj, objType->beh.addref); + } + } } // interface void asCScriptEngine::ReleaseScriptObject(void *obj, const asITypeInfo *type) { - // Make sure it is not a null pointer - if( obj == 0 || type == 0 ) return; - - const asCTypeInfo *ti = static_cast(type); - if (ti->flags & asOBJ_FUNCDEF) - { - CallObjectMethod(obj, functionBehaviours.beh.release); - } - else - { - asCObjectType *objType = CastToObjectType(const_cast(ti)); - if (objType && objType->flags & asOBJ_REF) - { - asASSERT((objType->flags & asOBJ_NOCOUNT) || objType->beh.release); - if (objType->beh.release) - { - // Call the release behaviour - CallObjectMethod(obj, objType->beh.release); - } - } - else if( objType ) - { - // Call the destructor - if (objType->beh.destruct) - CallObjectMethod(obj, objType->beh.destruct); - else if (objType->flags & asOBJ_LIST_PATTERN) - DestroyList((asBYTE*)obj, objType); - - // 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); - } - } + // Make sure it is not a null pointer + if( obj == 0 || type == 0 ) return; + + const asCTypeInfo *ti = static_cast(type); + if (ti->flags & asOBJ_FUNCDEF) + { + CallObjectMethod(obj, functionBehaviours.beh.release); + } + else + { + asCObjectType *objType = CastToObjectType(const_cast(ti)); + if (objType && objType->flags & asOBJ_REF) + { + asASSERT((objType->flags & asOBJ_NOCOUNT) || objType->beh.release); + if (objType->beh.release) + { + // Call the release behaviour + CallObjectMethod(obj, objType->beh.release); + } + } + else if( objType ) + { + // Call the destructor + if (objType->beh.destruct) + CallObjectMethod(obj, objType->beh.destruct); + else if (objType->flags & asOBJ_LIST_PATTERN) + DestroyList((asBYTE*)obj, objType); + + // 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 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; - } + // 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; + if( currentGroup != &defaultGroup ) + return asNOT_SUPPORTED; - asCConfigGroup *group = asNEW(asCConfigGroup)(); - if( group == 0 ) - return asOUT_OF_MEMORY; + asCConfigGroup *group = asNEW(asCConfigGroup)(); + if( group == 0 ) + return asOUT_OF_MEMORY; - group->groupName = groupName; + group->groupName = groupName; - configGroups.PushLast(group); - currentGroup = group; + configGroups.PushLast(group); + currentGroup = group; - return 0; + return 0; } // interface int asCScriptEngine::EndConfigGroup() { - // Raise error if trying to end the default config - if( currentGroup == &defaultGroup ) - return asERROR; + // Raise error if trying to end the default config + if( currentGroup == &defaultGroup ) + return asERROR; - currentGroup = &defaultGroup; + currentGroup = &defaultGroup; - return 0; + return 0; } // interface int asCScriptEngine::RemoveConfigGroup(const char *groupName) { - // It is not allowed to remove a group that is still in use. + // 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. + // 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]; + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + if( configGroups[n]->groupName == groupName ) + { + asCConfigGroup *group = configGroups[n]; - // Remove any unused generated template instances - // before verifying if the config group is still in use. - // RemoveTemplateInstanceType() checks if the instance is in use - for( asUINT g = generatedTemplateTypes.GetLength(); g-- > 0; ) - RemoveTemplateInstanceType(generatedTemplateTypes[g]); + // Remove any unused generated template instances + // before verifying if the config group is still in use. + // RemoveTemplateInstanceType() checks if the instance is in use + for( asUINT g = generatedTemplateTypes.GetLength(); g-- > 0; ) + RemoveTemplateInstanceType(generatedTemplateTypes[g]); - // Make sure the group isn't referenced by anyone - if( group->refCount > 0 ) - return asCONFIG_GROUP_IS_IN_USE; + // 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; + // 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 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); + // Remove the configurations registered with this group + group->RemoveConfiguration(this); - asDELETE(group,asCConfigGroup); - } - } + asDELETE(group,asCConfigGroup); + } + } - return 0; + 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]; - } - } + 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; + 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]; - } - } + 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; + return 0; } asCConfigGroup *asCScriptEngine::FindConfigGroupForTypeInfo(const asCTypeInfo *objType) const { - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - { - for( asUINT m = 0; m < configGroups[n]->types.GetLength(); m++ ) - { - if( configGroups[n]->types[m] == objType ) - return configGroups[n]; - } - } + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + for( asUINT m = 0; m < configGroups[n]->types.GetLength(); m++ ) + { + if( configGroups[n]->types[m] == objType ) + return configGroups[n]; + } + } - return 0; + return 0; } asCConfigGroup *asCScriptEngine::FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const { - for( asUINT n = 0; n < configGroups.GetLength(); n++ ) - { - asCFuncdefType *f = const_cast(funcDef); - if( configGroups[n]->types.Exists(f) ) - return configGroups[n]; - } + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + asCFuncdefType *f = const_cast(funcDef); + if( configGroups[n]->types.Exists(f) ) + return configGroups[n]; + } - return 0; + return 0; } // interface asDWORD asCScriptEngine::SetDefaultAccessMask(asDWORD defaultMask) { - asDWORD old = defaultAccessMask; - defaultAccessMask = defaultMask; - return old; + 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]; + // 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(); + return (int)scriptFunctions.GetLength(); } void asCScriptEngine::AddScriptFunction(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(); + // 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; - } + 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::RemoveScriptFunction(asCScriptFunction *func) { - if( func == 0 || func->id < 0 ) return; - int id = func->id & ~FUNC_IMPORTED; - if( func->funcType == asFUNC_IMPORTED ) - { - if( id >= (int)importedFunctions.GetLength() ) return; - - if( importedFunctions[id] ) - { - // Remove the function from the list of script functions - if( id == (int)importedFunctions.GetLength() - 1 ) - { - importedFunctions.PopLast(); - } - else - { - importedFunctions[id] = 0; - freeImportedFunctionIdxs.PushLast(id); - } - } - } - else - { - if( id >= (int)scriptFunctions.GetLength() ) return; - asASSERT( func == scriptFunctions[id] ); - - if( 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; - } - } - } - } - } + if( func == 0 || func->id < 0 ) return; + int id = func->id & ~FUNC_IMPORTED; + if( func->funcType == asFUNC_IMPORTED ) + { + if( id >= (int)importedFunctions.GetLength() ) return; + + if( importedFunctions[id] ) + { + // Remove the function from the list of script functions + if( id == (int)importedFunctions.GetLength() - 1 ) + { + importedFunctions.PopLast(); + } + else + { + importedFunctions[id] = 0; + freeImportedFunctionIdxs.PushLast(id); + } + } + } + else + { + if( id >= (int)scriptFunctions.GetLength() ) return; + asASSERT( func == scriptFunctions[id] ); + + if( 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; + } + } + } + } + } } // internal void asCScriptEngine::RemoveFuncdef(asCFuncdefType *funcdef) { - funcDefs.RemoveValue(funcdef); + funcDefs.RemoveValue(funcdef); } // 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); - asCObjectType *parentClass = 0; - int r = bld.ParseFunctionDeclaration(0, decl, func, false, 0, 0, defaultNamespace, 0, &parentClass); - if( r < 0 ) - { - // Set as dummy function before deleting - 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, true, false); - if( r < 0 ) - { - asDELETE(func,asCScriptFunction); - return ConfigError(asNAME_TAKEN, "RegisterFuncdef", decl, 0); - } - - func->id = GetNextScriptFunctionId(); - AddScriptFunction(func); - - asCFuncdefType *fdt = asNEW(asCFuncdefType)(this, func); - funcDefs.PushLast(fdt); // doesn't increase refcount - registeredFuncDefs.PushLast(fdt); // doesn't increase refcount - allRegisteredTypes.Insert(asSNameSpaceNamePair(fdt->nameSpace, fdt->name), fdt); // constructor already set the ref count to 1 - - currentGroup->types.PushLast(fdt); - if (parentClass) - { - parentClass->childFuncDefs.PushLast(fdt); - fdt->parentClass = parentClass; - - // Check if the method restricts that use of the template to value types or reference types - if (parentClass->flags & asOBJ_TEMPLATE) - { - r = SetTemplateRestrictions(parentClass, func, "RegisterFuncdef", decl); - if (r < 0) - return r; - } - } - - // If parameter type from other groups are used, add references - currentGroup->AddReferencesForFunc(this, func); - - // Return the type id as success - return GetTypeIdFromDataType(asCDataType::CreateType(fdt, false)); + 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); + asCObjectType *parentClass = 0; + int r = bld.ParseFunctionDeclaration(0, decl, func, false, 0, 0, defaultNamespace, 0, &parentClass); + if( r < 0 ) + { + // Set as dummy function before deleting + 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, true, false); + if( r < 0 ) + { + asDELETE(func,asCScriptFunction); + return ConfigError(asNAME_TAKEN, "RegisterFuncdef", decl, 0); + } + + func->id = GetNextScriptFunctionId(); + AddScriptFunction(func); + + asCFuncdefType *fdt = asNEW(asCFuncdefType)(this, func); + funcDefs.PushLast(fdt); // doesn't increase refcount + registeredFuncDefs.PushLast(fdt); // doesn't increase refcount + allRegisteredTypes.Insert(asSNameSpaceNamePair(fdt->nameSpace, fdt->name), fdt); // constructor already set the ref count to 1 + + currentGroup->types.PushLast(fdt); + if (parentClass) + { + parentClass->childFuncDefs.PushLast(fdt); + fdt->parentClass = parentClass; + + // Check if the method restricts that use of the template to value types or reference types + if (parentClass->flags & asOBJ_TEMPLATE) + { + r = SetTemplateRestrictions(parentClass, func, "RegisterFuncdef", decl); + if (r < 0) + return r; + } + } + + // If parameter type from other groups are used, add references + currentGroup->AddReferencesForFunc(this, func); + + // Return the type id as success + return GetTypeIdFromDataType(asCDataType::CreateType(fdt, false)); } // interface asUINT asCScriptEngine::GetFuncdefCount() const { - return asUINT(registeredFuncDefs.GetLength()); + return asUINT(registeredFuncDefs.GetLength()); } // interface asITypeInfo *asCScriptEngine::GetFuncdefByIndex(asUINT index) const { - if( index >= registeredFuncDefs.GetLength() ) - return 0; + if( index >= registeredFuncDefs.GetLength() ) + return 0; - return registeredFuncDefs[index]; + return registeredFuncDefs[index]; } // internal asCFuncdefType *asCScriptEngine::FindMatchingFuncdef(asCScriptFunction *func, asCModule *module) { - asCFuncdefType *funcDef = func->funcdefType; - - if (funcDef == 0) - { - // Check if there is any matching funcdefs already in the engine that can be reused - for (asUINT n = 0; n < funcDefs.GetLength(); n++) - { - if (funcDefs[n]->funcdef->IsSignatureExceptNameEqual(func)) - { - if (func->IsShared() && !funcDefs[n]->funcdef->IsShared()) - continue; - funcDef = funcDefs[n]; - break; - } - } - } - - if (funcDef == 0) - { - // Create a matching funcdef - asCScriptFunction *fd = asNEW(asCScriptFunction)(this, 0, asFUNC_FUNCDEF); - fd->name = func->name; - fd->nameSpace = func->nameSpace; - fd->SetShared(func->IsShared()); - - fd->returnType = func->returnType; - fd->parameterTypes = func->parameterTypes; - fd->inOutFlags = func->inOutFlags; - - funcDef = asNEW(asCFuncdefType)(this, fd); - funcDefs.PushLast(funcDef); // doesn't increase the refCount - - fd->id = GetNextScriptFunctionId(); - AddScriptFunction(fd); - - if (module) - { - // Add the new funcdef to the module so it will - // be available when saving the bytecode - funcDef->module = module; - module->AddFuncDef(funcDef); // the refCount was already accounted for in the constructor - } - - // Observe, if the funcdef is created without informing a module a reference will be stored in the - // engine's funcDefs array, but it will not be owned by any module. This means that it will live on - // until the engine is released. - } - - if (funcDef && module && funcDef->module && funcDef->module != module) - { - // Unless this is a registered funcDef the returned funcDef must - // be stored as part of the module for saving/loading bytecode - if (!module->m_funcDefs.Exists(funcDef)) - { - module->AddFuncDef(funcDef); - funcDef->AddRefInternal(); - } - else - { - asASSERT(funcDef->IsShared()); - } - } - - return funcDef; + asCFuncdefType *funcDef = func->funcdefType; + + if (funcDef == 0) + { + // Check if there is any matching funcdefs already in the engine that can be reused + for (asUINT n = 0; n < funcDefs.GetLength(); n++) + { + if (funcDefs[n]->funcdef->IsSignatureExceptNameEqual(func)) + { + if (func->IsShared() && !funcDefs[n]->funcdef->IsShared()) + continue; + funcDef = funcDefs[n]; + break; + } + } + } + + if (funcDef == 0) + { + // Create a matching funcdef + asCScriptFunction *fd = asNEW(asCScriptFunction)(this, 0, asFUNC_FUNCDEF); + fd->name = func->name; + fd->nameSpace = func->nameSpace; + fd->SetShared(func->IsShared()); + + fd->returnType = func->returnType; + fd->parameterTypes = func->parameterTypes; + fd->inOutFlags = func->inOutFlags; + + funcDef = asNEW(asCFuncdefType)(this, fd); + funcDefs.PushLast(funcDef); // doesn't increase the refCount + + fd->id = GetNextScriptFunctionId(); + AddScriptFunction(fd); + + if (module) + { + // Add the new funcdef to the module so it will + // be available when saving the bytecode + funcDef->module = module; + module->AddFuncDef(funcDef); // the refCount was already accounted for in the constructor + } + + // Observe, if the funcdef is created without informing a module a reference will be stored in the + // engine's funcDefs array, but it will not be owned by any module. This means that it will live on + // until the engine is released. + } + + if (funcDef && module && funcDef->module && funcDef->module != module) + { + // Unless this is a registered funcDef the returned funcDef must + // be stored as part of the module for saving/loading bytecode + if (!module->m_funcDefs.Exists(funcDef)) + { + module->AddFuncDef(funcDef); + funcDef->AddRefInternal(); + } + else + { + asASSERT(funcDef->IsShared()); + } + } + + return funcDef; } // interface // TODO: typedef: Accept complex types for the typedefs int asCScriptEngine::RegisterTypedef(const char *type, const char *decl) { - 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( GetRegisteredType(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, true, false); - 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 - asCTypedefType *td = asNEW(asCTypedefType)(this); - if( td == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterTypedef", type, decl); - - td->flags = asOBJ_TYPEDEF; - td->size = dataType.GetSizeInMemoryBytes(); - td->name = type; - td->nameSpace = defaultNamespace; - td->aliasForType = dataType; - - allRegisteredTypes.Insert(asSNameSpaceNamePair(td->nameSpace, td->name), td); - registeredTypeDefs.PushLast(td); - - currentGroup->types.PushLast(td); - - return GetTypeIdByDecl(type); + 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( GetRegisteredType(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, true, false); + 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 + asCTypedefType *td = asNEW(asCTypedefType)(this); + if( td == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterTypedef", type, decl); + + td->flags = asOBJ_TYPEDEF; + td->size = dataType.GetSizeInMemoryBytes(); + td->name = type; + td->nameSpace = defaultNamespace; + td->aliasForType = dataType; + + allRegisteredTypes.Insert(asSNameSpaceNamePair(td->nameSpace, td->name), td); + registeredTypeDefs.PushLast(td); + + currentGroup->types.PushLast(td); + + return GetTypeIdByDecl(type); } // interface asUINT asCScriptEngine::GetTypedefCount() const { - return asUINT(registeredTypeDefs.GetLength()); + return asUINT(registeredTypeDefs.GetLength()); } // interface asITypeInfo *asCScriptEngine::GetTypedefByIndex(asUINT index) const { - if( index >= registeredTypeDefs.GetLength() ) - return 0; + if( index >= registeredTypeDefs.GetLength() ) + return 0; - return registeredTypeDefs[index]; + return registeredTypeDefs[index]; } // interface int asCScriptEngine::RegisterEnum(const char *name) { - // Check the name - if( NULL == name ) - return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0); + // Check the name + if( NULL == name ) + return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0); - // Verify if the name has been registered as a type already - if( GetRegisteredType(name, defaultNamespace) ) - return asALREADY_REGISTERED; + // Verify if the name has been registered as a type already + if( GetRegisteredType(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 ) - { - // If it is not in the defaultNamespace then the type was successfully parsed because - // it is declared in a parent namespace which shouldn't be treated as an error - if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace ) - return ConfigError(asERROR, "RegisterEnum", name, 0); - } + // 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 ) + { + // If it is not in the defaultNamespace then the type was successfully parsed because + // it is declared in a parent namespace which shouldn't be treated as an error + if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace ) + 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); + // 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, true, false); - if( r < 0 ) - return ConfigError(asNAME_TAKEN, "RegisterEnum", name, 0); + r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true, false); + if( r < 0 ) + return ConfigError(asNAME_TAKEN, "RegisterEnum", name, 0); - asCEnumType *st = asNEW(asCEnumType)(this); - if( st == 0 ) - return ConfigError(asOUT_OF_MEMORY, "RegisterEnum", name, 0); + asCEnumType *st = asNEW(asCEnumType)(this); + if( st == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterEnum", name, 0); - asCDataType dataType; - dataType.CreatePrimitive(ttInt, false); + asCDataType dataType; + dataType.CreatePrimitive(ttInt, false); - st->flags = asOBJ_ENUM | asOBJ_SHARED; - st->size = 4; - st->name = name; - st->nameSpace = defaultNamespace; + 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); + allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); + registeredEnums.PushLast(st); - currentGroup->types.PushLast(st); + currentGroup->types.PushLast(st); - return GetTypeIdByDecl(name); + return GetTypeIdByDecl(name); } // 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); + // 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); + 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 - asCEnumType *ot = CastToEnumType(dt.GetTypeInfo()); - if( ot == 0 ) - return ConfigError(asINVALID_TYPE, "RegisterEnumValue", typeName, valueName); + // Store the enum value + asCEnumType *ot = CastToEnumType(dt.GetTypeInfo()); + if( ot == 0 ) + return ConfigError(asINVALID_TYPE, "RegisterEnumValue", typeName, valueName); - if( NULL == valueName ) - return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName); + if( NULL == valueName ) + return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName); - asUINT tokenLen = 0; - asETokenClass tokenClass = ParseToken(valueName, 0, &tokenLen); - if( tokenClass != asTC_IDENTIFIER || tokenLen != strlen(valueName) ) - return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName); + asUINT tokenLen = 0; + asETokenClass tokenClass = ParseToken(valueName, 0, &tokenLen); + if( tokenClass != asTC_IDENTIFIER || tokenLen != 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); - } + 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); + asSEnumValue *e = asNEW(asSEnumValue); + if( e == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterEnumValue", typeName, valueName); - e->name = valueName; - e->value = value; + e->name = valueName; + e->value = value; - ot->enumValues.PushLast(e); + ot->enumValues.PushLast(e); - return asSUCCESS; + return asSUCCESS; } // interface asUINT asCScriptEngine::GetEnumCount() const { - return registeredEnums.GetLength(); + return registeredEnums.GetLength(); } // interface asITypeInfo *asCScriptEngine::GetEnumByIndex(asUINT index) const { - if( index >= registeredEnums.GetLength() ) - return 0; + if( index >= registeredEnums.GetLength() ) + return 0; - return registeredEnums[index]; + return registeredEnums[index]; } // interface asUINT asCScriptEngine::GetObjectTypeCount() const { - return asUINT(registeredObjTypes.GetLength()); + return asUINT(registeredObjTypes.GetLength()); } // interface asITypeInfo *asCScriptEngine::GetObjectTypeByIndex(asUINT index) const { - if( index >= registeredObjTypes.GetLength() ) - return 0; + if( index >= registeredObjTypes.GetLength() ) + return 0; - return registeredObjTypes[index]; + return registeredObjTypes[index]; } // interface asITypeInfo *asCScriptEngine::GetTypeInfoByName(const char *in_name) const { - asCString name; - asSNameSpace *ns = 0; - if( DetermineNameAndNamespace(in_name, defaultNamespace, name, ns) < 0 ) - return 0; - - while (ns) - { - // Check the object types - for (asUINT n = 0; n < registeredObjTypes.GetLength(); n++) - { - if (registeredObjTypes[n]->name == name && - registeredObjTypes[n]->nameSpace == ns) - return registeredObjTypes[n]; - } - - // Perhaps it is a template type? In this case - // the returned type will be the generic type - for (asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++) - { - if (registeredTemplateTypes[n]->name == name && - registeredTemplateTypes[n]->nameSpace == ns) - return registeredTemplateTypes[n]; - } - - // Check the enum types - for (asUINT n = 0; n < registeredEnums.GetLength(); n++) - { - if (registeredEnums[n]->name == name && - registeredEnums[n]->nameSpace == ns) - return registeredEnums[n]; - } - - // Check the typedefs - for (asUINT n = 0; n < registeredTypeDefs.GetLength();n++) - { - if (registeredTypeDefs[n]->name == name && - registeredTypeDefs[n]->nameSpace == ns) - return registeredTypeDefs[n]; - } - - // Recursively search parent namespace - ns = GetParentNameSpace(ns); - } - - return 0; + asCString name; + asSNameSpace *ns = 0; + if( DetermineNameAndNamespace(in_name, defaultNamespace, name, ns) < 0 ) + return 0; + + while (ns) + { + // Check the object types + for (asUINT n = 0; n < registeredObjTypes.GetLength(); n++) + { + if (registeredObjTypes[n]->name == name && + registeredObjTypes[n]->nameSpace == ns) + return registeredObjTypes[n]; + } + + // Perhaps it is a template type? In this case + // the returned type will be the generic type + for (asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++) + { + if (registeredTemplateTypes[n]->name == name && + registeredTemplateTypes[n]->nameSpace == ns) + return registeredTemplateTypes[n]; + } + + // Check the enum types + for (asUINT n = 0; n < registeredEnums.GetLength(); n++) + { + if (registeredEnums[n]->name == name && + registeredEnums[n]->nameSpace == ns) + return registeredEnums[n]; + } + + // Check the typedefs + for (asUINT n = 0; n < registeredTypeDefs.GetLength();n++) + { + if (registeredTypeDefs[n]->name == name && + registeredTypeDefs[n]->nameSpace == ns) + return registeredTypeDefs[n]; + } + + // Recursively search parent namespace + ns = GetParentNameSpace(ns); + } + + return 0; } // internal int asCScriptEngine::DetermineNameAndNamespace(const char *in_name, asSNameSpace *implicitNs, asCString &out_name, asSNameSpace *&out_ns) const { - if( in_name == 0 ) - return asINVALID_ARG; - - asCString name = in_name; - asCString scope; - asSNameSpace *ns = implicitNs; - - // Check if the given name contains a scope - int pos = name.FindLast("::"); - if( pos >= 0 ) - { - scope = name.SubString(0, pos); - name = name.SubString(pos+2); - if( pos == 0 ) - { - // The scope is '::' so the search must start in the global namespace - ns = nameSpaces[0]; - } - else if( scope.SubString(0, 2) == "::" ) - { - // The scope starts with '::' so the given scope is fully qualified - ns = FindNameSpace(scope.SubString(2).AddressOf()); - } - else - { - // The scope doesn't start with '::' so it is relative to the current namespace - if( implicitNs->name == "" ) - ns = FindNameSpace(scope.AddressOf()); - else - ns = FindNameSpace((implicitNs->name + "::" + scope).AddressOf()); - } - } - - out_name = name; - out_ns = ns; - - return 0; + if( in_name == 0 ) + return asINVALID_ARG; + + asCString name = in_name; + asCString scope; + asSNameSpace *ns = implicitNs; + + // Check if the given name contains a scope + int pos = name.FindLast("::"); + if( pos >= 0 ) + { + scope = name.SubString(0, pos); + name = name.SubString(pos+2); + if( pos == 0 ) + { + // The scope is '::' so the search must start in the global namespace + ns = nameSpaces[0]; + } + else if( scope.SubString(0, 2) == "::" ) + { + // The scope starts with '::' so the given scope is fully qualified + ns = FindNameSpace(scope.SubString(2).AddressOf()); + } + else + { + // The scope doesn't start with '::' so it is relative to the current namespace + if( implicitNs->name == "" ) + ns = FindNameSpace(scope.AddressOf()); + else + ns = FindNameSpace((implicitNs->name + "::" + scope).AddressOf()); + } + } + + out_name = name; + out_ns = ns; + + return 0; } // interface asITypeInfo *asCScriptEngine::GetTypeInfoById(int typeId) const { - asCDataType dt = GetDataTypeFromTypeId(typeId); + asCDataType dt = GetDataTypeFromTypeId(typeId); - // Is the type id valid? - if (!dt.IsValid()) return 0; + // Is the type id valid? + if (!dt.IsValid()) return 0; - return dt.GetTypeInfo(); + return dt.GetTypeInfo(); } // interface asIScriptFunction *asCScriptEngine::GetFunctionById(int funcId) const { - return GetScriptFunction(funcId); + return GetScriptFunction(funcId); } // 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; - } + // 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; + return false; } // internal int asCScriptEngine::GetScriptSectionNameIndex(const char *name) { - ACQUIREEXCLUSIVE(engineRWLock); + 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? + // 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; - } - } + // 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); + asCString *str = asNEW(asCString)(name); + if( str ) + scriptSectionNames.PushLast(str); + int r = int(scriptSectionNames.GetLength()-1); - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); - return r; + return r; } // interface void asCScriptEngine::SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type) { - ACQUIREEXCLUSIVE(engineRWLock); + ACQUIREEXCLUSIVE(engineRWLock); - for( asUINT n = 0; n < cleanEngineFuncs.GetLength(); n++ ) - { - if( cleanEngineFuncs[n].type == type ) - { - cleanEngineFuncs[n].cleanFunc = callback; + for( asUINT n = 0; n < cleanEngineFuncs.GetLength(); n++ ) + { + if( cleanEngineFuncs[n].type == type ) + { + cleanEngineFuncs[n].cleanFunc = callback; - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); - return; - } - } - SEngineClean otc = {type, callback}; - cleanEngineFuncs.PushLast(otc); + return; + } + } + SEngineClean otc = {type, callback}; + cleanEngineFuncs.PushLast(otc); - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); } // interface void asCScriptEngine::SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type) { - ACQUIREEXCLUSIVE(engineRWLock); + ACQUIREEXCLUSIVE(engineRWLock); - for( asUINT n = 0; n < cleanModuleFuncs.GetLength(); n++ ) - { - if( cleanModuleFuncs[n].type == type ) - { - cleanModuleFuncs[n].cleanFunc = callback; + for( asUINT n = 0; n < cleanModuleFuncs.GetLength(); n++ ) + { + if( cleanModuleFuncs[n].type == type ) + { + cleanModuleFuncs[n].cleanFunc = callback; - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); - return; - } - } - SModuleClean otc = {type, callback}; - cleanModuleFuncs.PushLast(otc); + return; + } + } + SModuleClean otc = {type, callback}; + cleanModuleFuncs.PushLast(otc); - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); } // interface void asCScriptEngine::SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type) { - ACQUIREEXCLUSIVE(engineRWLock); + ACQUIREEXCLUSIVE(engineRWLock); - for( asUINT n = 0; n < cleanContextFuncs.GetLength(); n++ ) - { - if( cleanContextFuncs[n].type == type ) - { - cleanContextFuncs[n].cleanFunc = callback; + for( asUINT n = 0; n < cleanContextFuncs.GetLength(); n++ ) + { + if( cleanContextFuncs[n].type == type ) + { + cleanContextFuncs[n].cleanFunc = callback; - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); - return; - } - } - SContextClean otc = {type, callback}; - cleanContextFuncs.PushLast(otc); + return; + } + } + SContextClean otc = {type, callback}; + cleanContextFuncs.PushLast(otc); - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); } // interface void asCScriptEngine::SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type) { - ACQUIREEXCLUSIVE(engineRWLock); + ACQUIREEXCLUSIVE(engineRWLock); - for( asUINT n = 0; n < cleanFunctionFuncs.GetLength(); n++ ) - { - if( cleanFunctionFuncs[n].type == type ) - { - cleanFunctionFuncs[n].cleanFunc = callback; + for( asUINT n = 0; n < cleanFunctionFuncs.GetLength(); n++ ) + { + if( cleanFunctionFuncs[n].type == type ) + { + cleanFunctionFuncs[n].cleanFunc = callback; - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); - return; - } - } - SFunctionClean otc = {type, callback}; - cleanFunctionFuncs.PushLast(otc); + return; + } + } + SFunctionClean otc = {type, callback}; + cleanFunctionFuncs.PushLast(otc); - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); } // interface void asCScriptEngine::SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type) { - ACQUIREEXCLUSIVE(engineRWLock); + ACQUIREEXCLUSIVE(engineRWLock); - for( asUINT n = 0; n < cleanTypeInfoFuncs.GetLength(); n++ ) - { - if( cleanTypeInfoFuncs[n].type == type ) - { - cleanTypeInfoFuncs[n].cleanFunc = callback; + for( asUINT n = 0; n < cleanTypeInfoFuncs.GetLength(); n++ ) + { + if( cleanTypeInfoFuncs[n].type == type ) + { + cleanTypeInfoFuncs[n].cleanFunc = callback; - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); - return; - } - } - STypeInfoClean otc = {type, callback}; - cleanTypeInfoFuncs.PushLast(otc); + return; + } + } + STypeInfoClean otc = {type, callback}; + cleanTypeInfoFuncs.PushLast(otc); - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); } // interface void asCScriptEngine::SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type) { - ACQUIREEXCLUSIVE(engineRWLock); + ACQUIREEXCLUSIVE(engineRWLock); - for( asUINT n = 0; n < cleanScriptObjectFuncs.GetLength(); n++ ) - { - if( cleanScriptObjectFuncs[n].type == type ) - { - cleanScriptObjectFuncs[n].cleanFunc = callback; + for( asUINT n = 0; n < cleanScriptObjectFuncs.GetLength(); n++ ) + { + if( cleanScriptObjectFuncs[n].type == type ) + { + cleanScriptObjectFuncs[n].cleanFunc = callback; - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); - return; - } - } - SScriptObjClean soc = {type, callback}; - cleanScriptObjectFuncs.PushLast(soc); + return; + } + } + SScriptObjClean soc = {type, callback}; + cleanScriptObjectFuncs.PushLast(soc); - RELEASEEXCLUSIVE(engineRWLock); + RELEASEEXCLUSIVE(engineRWLock); } // interface int asCScriptEngine::SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv) { #ifdef AS_NO_EXCEPTIONS - return asNOT_SUPPORTED; + return asNOT_SUPPORTED; #else - if (callback.ptr.f.func == 0) - { - // Clear the callback - translateExceptionCallback = false; - return asSUCCESS; - } - - // Detect the new callback - translateExceptionCallback = true; - translateExceptionCallbackObj = param; - 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 (param == 0) - { - translateExceptionCallback = false; - return asINVALID_ARG; - } - } - int r = DetectCallingConvention(isObj, callback, callConv, 0, &translateExceptionCallbackFunc); - if (r < 0) - translateExceptionCallback = false; - - return r; + if (callback.ptr.f.func == 0) + { + // Clear the callback + translateExceptionCallback = false; + return asSUCCESS; + } + + // Detect the new callback + translateExceptionCallback = true; + translateExceptionCallbackObj = param; + 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 (param == 0) + { + translateExceptionCallback = false; + return asINVALID_ARG; + } + } + int r = DetectCallingConvention(isObj, callback, callConv, 0, &translateExceptionCallbackFunc); + if (r < 0) + translateExceptionCallback = false; + + return r; #endif } // 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 = CastToObjectType(scriptFunctions[listPatternFuncId]->returnType.GetTypeInfo()); - asASSERT( ot ); + // 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 = CastToObjectType(scriptFunctions[listPatternFuncId]->returnType.GetTypeInfo()); + asASSERT( ot ); - // Check if this object type already has a list pattern type - for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) - { - if( listPatternTypes[n]->templateSubTypes[0].GetTypeInfo() == ot ) - return listPatternTypes[n]; - } + // Check if this object type already has a list pattern type + for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) + { + if( listPatternTypes[n]->templateSubTypes[0].GetTypeInfo() == ot ) + return listPatternTypes[n]; + } - // Create a new list pattern type for the given object type - asCObjectType *lpt = asNEW(asCObjectType)(this); - lpt->templateSubTypes.PushLast(asCDataType::CreateType(ot, false)); - lpt->flags = asOBJ_LIST_PATTERN; - listPatternTypes.PushLast(lpt); + // Create a new list pattern type for the given object type + asCObjectType *lpt = asNEW(asCObjectType)(this); + lpt->templateSubTypes.PushLast(asCDataType::CreateType(ot, false)); + lpt->flags = asOBJ_LIST_PATTERN; + listPatternTypes.PushLast(lpt); - return lpt; + return lpt; } // internal void asCScriptEngine::DestroyList(asBYTE *buffer, const asCObjectType *listPatternType) { - asASSERT( listPatternType && (listPatternType->flags & asOBJ_LIST_PATTERN) ); + 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 = CastToObjectType(listPatternType->templateSubTypes[0].GetTypeInfo()); - asCScriptFunction *listFactory = scriptFunctions[ot->beh.listFactory]; - asASSERT( listFactory ); + // 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 = CastToObjectType(listPatternType->templateSubTypes[0].GetTypeInfo()); + asCScriptFunction *listFactory = scriptFunctions[ot->beh.listFactory]; + asASSERT( listFactory ); - asSListPatternNode *node = listFactory->listPattern; - DestroySubList(buffer, node); + asSListPatternNode *node = listFactory->listPattern; + DestroySubList(buffer, node); - asASSERT( node->type == asLPT_END ); + 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); - } - - asCTypeInfo *ti = dt.GetTypeInfo(); - if( ti && (ti->flags & asOBJ_ENUM) == 0 ) - { - // Free all instances of this type - if( ti->flags & asOBJ_VALUE ) - { - asUINT size = ti->GetSize(); - - // Align the offset to 4 bytes boundary - if( size >= 4 && (asPWORD(buffer) & 0x3) ) - buffer += 4 - (asPWORD(buffer) & 0x3); - - asCObjectType *ot = CastToObjectType(ti); - if( ot && ot->beh.destruct ) - { - // Only call the destructor if the object has been created - // We'll assume the object has been created if any byte in - // 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, ti); - 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; - } + 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); + } + + asCTypeInfo *ti = dt.GetTypeInfo(); + if( ti && (ti->flags & asOBJ_ENUM) == 0 ) + { + // Free all instances of this type + if( ti->flags & asOBJ_VALUE ) + { + asUINT size = ti->GetSize(); + + // Align the offset to 4 bytes boundary + if( size >= 4 && (asPWORD(buffer) & 0x3) ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + asCObjectType *ot = CastToObjectType(ti); + if( ot && ot->beh.destruct ) + { + // Only call the destructor if the object has been created + // We'll assume the object has been created if any byte in + // 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, ti); + 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; + } } // internal asSNameSpace *asCScriptEngine::GetParentNameSpace(asSNameSpace *ns) const { - if( ns == 0 ) return 0; - if( ns == nameSpaces[0] ) return 0; + if( ns == 0 ) return 0; + if( ns == nameSpaces[0] ) return 0; - asCString scope = ns->name; - int pos = scope.FindLast("::"); - if( pos >= 0 ) - { - scope = scope.SubString(0, pos); - return FindNameSpace(scope.AddressOf()); - } + asCString scope = ns->name; + int pos = scope.FindLast("::"); + if( pos >= 0 ) + { + scope = scope.SubString(0, pos); + return FindNameSpace(scope.AddressOf()); + } - return nameSpaces[0]; + return nameSpaces[0]; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_scriptengine.h b/src/angelscript/source/as_scriptengine.h index fdfc568aa7f..3dddcda1d2f 100644 --- a/src/angelscript/source/as_scriptengine.h +++ b/src/angelscript/source/as_scriptengine.h @@ -67,459 +67,459 @@ class asCScriptEngine : public asIScriptEngine // From asIScriptEngine //============================================================= public: - // Memory management - virtual int AddRef() const; - virtual int Release() const; - virtual int ShutDownAndRelease(); - - // 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 *auxiliary = 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, int compositeOffset = 0, bool isCompositeIndirect = false); - virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); - virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); - virtual int RegisterInterface(const char *name); - virtual int RegisterInterfaceMethod(const char *intf, const char *declaration); - virtual asUINT GetObjectTypeCount() const; - virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const; - - // String factory - virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory); - 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 asITypeInfo *GetEnumByIndex(asUINT index) const; - - // Funcdefs - virtual int RegisterFuncdef(const char *decl); - virtual asUINT GetFuncdefCount() const; - virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const; - - // Typedefs - // TODO: interface: Should perhaps rename this to Alias, since it doesn't really create a new type - virtual int RegisterTypedef(const char *type, const char *decl); - virtual asUINT GetTypedefCount() const; - virtual asITypeInfo *GetTypedefByIndex(asUINT index) 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; - - // Type identification - virtual int GetTypeIdByDecl(const char *decl) const; - virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const; - virtual int GetSizeOfPrimitiveType(int typeId) const; - virtual asITypeInfo *GetTypeInfoById(int typeId) const; - virtual asITypeInfo *GetTypeInfoByName(const char *name) const; - virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const; - - // Script execution - virtual asIScriptContext *CreateContext(); - virtual void *CreateScriptObject(const asITypeInfo *type); - virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type); - virtual void *CreateUninitializedScriptObject(const asITypeInfo *type); - virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj); - virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type); - virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type); - virtual void AddRefScriptObject(void *obj, const asITypeInfo *type); - virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false); - virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const; - - // Context pooling - virtual asIScriptContext *RequestContext(); - 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, asUINT *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, asITypeInfo *type); - virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj = 0, asITypeInfo **type = 0); - virtual void GCEnumCallback(void *reference); - virtual void ForwardGCEnumReferences(void *ref, asITypeInfo *type); - virtual void ForwardGCReleaseReferences(void *ref, asITypeInfo *type); - virtual void SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param = 0); - - // 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 SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type); - virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type); - - // Exception handling - virtual int SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv); + // Memory management + virtual int AddRef() const; + virtual int Release() const; + virtual int ShutDownAndRelease(); + + // 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 *auxiliary = 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, int compositeOffset = 0, bool isCompositeIndirect = false); + virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + virtual int RegisterInterface(const char *name); + virtual int RegisterInterfaceMethod(const char *intf, const char *declaration); + virtual asUINT GetObjectTypeCount() const; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const; + + // String factory + virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory); + 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 asITypeInfo *GetEnumByIndex(asUINT index) const; + + // Funcdefs + virtual int RegisterFuncdef(const char *decl); + virtual asUINT GetFuncdefCount() const; + virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const; + + // Typedefs + // TODO: interface: Should perhaps rename this to Alias, since it doesn't really create a new type + virtual int RegisterTypedef(const char *type, const char *decl); + virtual asUINT GetTypedefCount() const; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) 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; + + // Type identification + virtual int GetTypeIdByDecl(const char *decl) const; + virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const; + virtual int GetSizeOfPrimitiveType(int typeId) const; + virtual asITypeInfo *GetTypeInfoById(int typeId) const; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const; + + // Script execution + virtual asIScriptContext *CreateContext(); + virtual void *CreateScriptObject(const asITypeInfo *type); + virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type); + virtual void *CreateUninitializedScriptObject(const asITypeInfo *type); + virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj); + virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type); + virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type); + virtual void AddRefScriptObject(void *obj, const asITypeInfo *type); + virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false); + virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const; + + // Context pooling + virtual asIScriptContext *RequestContext(); + 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, asUINT *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, asITypeInfo *type); + virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj = 0, asITypeInfo **type = 0); + virtual void GCEnumCallback(void *reference); + virtual void ForwardGCEnumReferences(void *ref, asITypeInfo *type); + virtual void ForwardGCReleaseReferences(void *ref, asITypeInfo *type); + virtual void SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param = 0); + + // 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 SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type); + virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type); + + // Exception handling + virtual int SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv); //=========================================================== // internal methods //=========================================================== public: - asCScriptEngine(); - virtual ~asCScriptEngine(); + 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); + 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 *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); - int RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + int RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + int RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); - int VerifyVarTypeNotInFunction(asCScriptFunction *func); + int VerifyVarTypeNotInFunction(asCScriptFunction *func); - void *CallAlloc(const asCObjectType *objType) const; - void CallFree(void *obj) const; + 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 *CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const; - void CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; - bool CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; - int CallScriptObjectMethod(void *obj, int func); + void *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 *CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const; + void CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; + bool CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; + int CallScriptObjectMethod(void *obj, int func); - void ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type); + void ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type); - void DeleteDiscardedModules(); + void DeleteDiscardedModules(); - void RemoveTemplateInstanceType(asCObjectType *t); + void RemoveTemplateInstanceType(asCObjectType *t); - asCConfigGroup *FindConfigGroupForFunction(int funcId) const; - asCConfigGroup *FindConfigGroupForGlobalVar(int gvarId) const; - asCConfigGroup *FindConfigGroupForTypeInfo(const asCTypeInfo *type) const; - asCConfigGroup *FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const; + asCConfigGroup *FindConfigGroupForFunction(int funcId) const; + asCConfigGroup *FindConfigGroupForGlobalVar(int gvarId) const; + asCConfigGroup *FindConfigGroupForTypeInfo(const asCTypeInfo *type) const; + asCConfigGroup *FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const; - int RequestBuild(); - void BuildCompleted(); + int RequestBuild(); + void BuildCompleted(); - void PrepareEngine(); - bool isPrepared; + void PrepareEngine(); + bool isPrepared; - int CreateContext(asIScriptContext **context, bool isInternal); + int CreateContext(asIScriptContext **context, bool isInternal); - asCTypeInfo *GetRegisteredType(const asCString &name, asSNameSpace *ns) const; + asCTypeInfo *GetRegisteredType(const asCString &name, asSNameSpace *ns) const; - asCObjectType *GetListPatternType(int listPatternFuncId); - void DestroyList(asBYTE *buffer, const asCObjectType *listPatternType); - void DestroySubList(asBYTE *&buffer, asSListPatternNode *&patternNode); + asCObjectType *GetListPatternType(int listPatternFuncId); + void DestroyList(asBYTE *buffer, const asCObjectType *listPatternType); + void DestroySubList(asBYTE *&buffer, asSListPatternNode *&patternNode); - int AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal); + int AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal); - asCString GetFunctionDeclaration(int funcId); + asCString GetFunctionDeclaration(int funcId); - asCScriptFunction *GetScriptFunction(int funcId) const; + asCScriptFunction *GetScriptFunction(int funcId) const; - asCModule *GetModule(const char *name, bool create); - asCModule *GetModuleFromFuncId(int funcId); + 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 GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod); + int GetFactoryIdByDecl(const asCObjectType *ot, const char *decl); - int GetNextScriptFunctionId(); - void AddScriptFunction(asCScriptFunction *func); - void RemoveScriptFunction(asCScriptFunction *func); - void RemoveFuncdef(asCFuncdefType *func); + int GetNextScriptFunctionId(); + void AddScriptFunction(asCScriptFunction *func); + void RemoveScriptFunction(asCScriptFunction *func); + void RemoveFuncdef(asCFuncdefType *func); - int ConfigError(int err, const char *funcName, const char *arg1, const char *arg2); + 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(asCTypeInfo *type); + int GetTypeIdFromDataType(const asCDataType &dt) const; + asCDataType GetDataTypeFromTypeId(int typeId) const; + asCObjectType *GetObjectTypeFromTypeId(int typeId) const; + void RemoveFromTypeIdMap(asCTypeInfo *type); - bool IsTemplateType(const char *name) const; - int SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl); - asCObjectType *GetTemplateInstanceType(asCObjectType *templateType, asCArray &subTypes, asCModule *requestingModule); - asCScriptFunction *GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *templateInstanceType, int origFactoryId); - bool GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *templateInstanceType, asCScriptFunction *templateFunc, asCScriptFunction **newFunc); - asCFuncdefType *GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *templateInstanceType, asCFuncdefType *templateFuncdef); - asCDataType DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot); - bool RequireTypeReplacement(asCDataType &type, asCObjectType *templateType); + bool IsTemplateType(const char *name) const; + int SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl); + asCObjectType *GetTemplateInstanceType(asCObjectType *templateType, asCArray &subTypes, asCModule *requestingModule); + asCScriptFunction *GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *templateInstanceType, int origFactoryId); + bool GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *templateInstanceType, asCScriptFunction *templateFunc, asCScriptFunction **newFunc); + asCFuncdefType *GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *templateInstanceType, asCFuncdefType *templateFuncdef); + asCDataType DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot); + bool RequireTypeReplacement(asCDataType &type, asCObjectType *templateType); - asCModule *FindNewOwnerForSharedType(asCTypeInfo *type, asCModule *mod); - asCModule *FindNewOwnerForSharedFunc(asCScriptFunction *func, asCModule *mod); + asCModule *FindNewOwnerForSharedType(asCTypeInfo *type, asCModule *mod); + asCModule *FindNewOwnerForSharedFunc(asCScriptFunction *func, asCModule *mod); - asCFuncdefType *FindMatchingFuncdef(asCScriptFunction *func, asCModule *mod); + asCFuncdefType *FindMatchingFuncdef(asCScriptFunction *func, asCModule *mod); - int DetermineNameAndNamespace(const char *in_name, asSNameSpace *implicitNs, asCString &out_name, asSNameSpace *&out_ns) const; - - // Global property management - asCGlobalProperty *AllocateGlobalProperty(); - void RemoveGlobalProperty(asCGlobalProperty *prop); + int DetermineNameAndNamespace(const char *in_name, asSNameSpace *implicitNs, asCString &out_name, asSNameSpace *&out_ns) const; - int GetScriptSectionNameIndex(const char *name); + // Global property management + asCGlobalProperty *AllocateGlobalProperty(); + void RemoveGlobalProperty(asCGlobalProperty *prop); - // Namespace management - asSNameSpace *AddNameSpace(const char *name); - asSNameSpace *FindNameSpace(const char *name) const; - asSNameSpace *GetParentNameSpace(asSNameSpace *ns) const; + int GetScriptSectionNameIndex(const char *name); + + // Namespace management + asSNameSpace *AddNameSpace(const char *name); + asSNameSpace *FindNameSpace(const char *name) const; + asSNameSpace *GetParentNameSpace(asSNameSpace *ns) const; //=========================================================== // internal properties //=========================================================== - asCMemoryMgr memoryMgr; - - asCObjectType *defaultArrayObjectType; - asCObjectType scriptTypeBehaviours; - asCObjectType functionBehaviours; - - // Registered interface - asCArray registeredObjTypes; // doesn't increase ref count - asCArray registeredTypeDefs; // doesn't increase ref count - asCArray registeredEnums; // doesn't increase ref count - // TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used for global props - asCSymbolTable registeredGlobalProps; // increases ref count - asCSymbolTable registeredGlobalFuncs; - asCArray registeredFuncDefs; // doesn't increase ref count - asCArray registeredTemplateTypes; // doesn't increase ref count - asIStringFactory *stringFactory; - asCDataType stringType; - bool configFailed; - - // Stores all registered types - asCMap allRegisteredTypes; // increases ref count - - // 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; // increases ref count - - // Store information about list patterns - asCArray listPatternTypes; // increases ref count - - // 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; // increases ref count - asCArray freeGlobalPropertyIds; - - // 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; // doesn't increase ref count - - // Stores all functions, i.e. registered functions, script functions, class methods, behaviours, etc. - asCArray scriptFunctions; // doesn't increase ref count - asCArray freeScriptFunctionIds; - asCArray signatureIds; - - // An array with all module imported functions - asCArray importedFunctions; // doesn't increase ref count - asCArray freeImportedFunctionIdxs; - - // Synchronized - mutable asCAtomic refCount; - // Synchronized with engineRWLock - // This array holds all live script modules - asCArray scriptModules; - // Synchronized with engineRWLock - // This is a pointer to the last module that was requested. It is used for performance - // improvement, since it is common that the same module is accessed many times in a row - asCModule *lastModule; - // Synchronized with engineRWLock - // This flag is true if a script is currently being compiled. It is used to prevent multiple - // threads from requesting builds at the same time (without blocking) - bool isBuilding; - // Synchronized with engineRWLock - // This array holds modules that have been discard (thus are no longer visible to the application) - // but cannot yet be deleted due to having external references to some of the entities in them - asCArray discardedModules; - // This flag is set to true during compilations of scripts (or loading pre-compiled scripts) - // to delay the validation of template types until the subtypes have been fully declared - bool deferValidationOfTemplateTypes; - - // Tokenizer is instantiated once to share resources - asCTokenizer tok; - - // Stores shared script declared types (classes, interfaces, enums) - asCArray sharedScriptTypes; // increases ref count - // This array stores the template instances types that have been automatically generated from template types - asCArray generatedTemplateTypes; - // Stores the funcdefs - // TODO: redesign: Only shared funcdefs should be stored here - // a funcdef becomes shared if all arguments and the return type are shared (or application registered) - asCArray funcDefs; // doesn't increases ref count - - // Stores the names of the script sections for debugging purposes - asCArray scriptSectionNames; - - // Type identifiers - mutable int typeIdSeqNbr; - mutable asCMap mapTypeIdToTypeInfo; - - // 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; - - // 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 STypeInfoClean { asPWORD type; asCLEANTYPEINFOFUNC_t cleanFunc; }; - asCArray cleanTypeInfoFuncs; - struct SScriptObjClean { asPWORD type; asCLEANSCRIPTOBJECTFUNC_t cleanFunc; }; - asCArray cleanScriptObjectFuncs; - - // Synchronization for threads - DECLAREREADWRITELOCK(mutable engineRWLock) - - // Engine properties - struct - { - bool allowUnsafeReferences; - bool optimizeByteCode; - bool copyScriptSections; - asUINT maximumContextStackSize; - asUINT initContextStackSize; - 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; - // TODO: 3.0.0: Remove the alterSyntaxNamedArgs - int alterSyntaxNamedArgs; - bool disableIntegerDivision; - bool disallowEmptyListElements; - // TODO: 3.0.0: Remove the privatePropAsProtected - bool privatePropAsProtected; - bool allowUnicodeIdentifiers; - int heredocTrimMode; - asUINT maxNestedCalls; - asUINT genericCallMode; - asUINT initCallStackSize; - asUINT maxCallStackSize; - } ep; - - // Callbacks + asCMemoryMgr memoryMgr; + + asCObjectType *defaultArrayObjectType; + asCObjectType scriptTypeBehaviours; + asCObjectType functionBehaviours; + + // Registered interface + asCArray registeredObjTypes; // doesn't increase ref count + asCArray registeredTypeDefs; // doesn't increase ref count + asCArray registeredEnums; // doesn't increase ref count + // TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used for global props + asCSymbolTable registeredGlobalProps; // increases ref count + asCSymbolTable registeredGlobalFuncs; + asCArray registeredFuncDefs; // doesn't increase ref count + asCArray registeredTemplateTypes; // doesn't increase ref count + asIStringFactory *stringFactory; + asCDataType stringType; + bool configFailed; + + // Stores all registered types + asCMap allRegisteredTypes; // increases ref count + + // 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; // increases ref count + + // Store information about list patterns + asCArray listPatternTypes; // increases ref count + + // 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; // increases ref count + asCArray freeGlobalPropertyIds; + + // 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; // doesn't increase ref count + + // Stores all functions, i.e. registered functions, script functions, class methods, behaviours, etc. + asCArray scriptFunctions; // doesn't increase ref count + asCArray freeScriptFunctionIds; + asCArray signatureIds; + + // An array with all module imported functions + asCArray importedFunctions; // doesn't increase ref count + asCArray freeImportedFunctionIdxs; + + // Synchronized + mutable asCAtomic refCount; + // Synchronized with engineRWLock + // This array holds all live script modules + asCArray scriptModules; + // Synchronized with engineRWLock + // This is a pointer to the last module that was requested. It is used for performance + // improvement, since it is common that the same module is accessed many times in a row + asCModule *lastModule; + // Synchronized with engineRWLock + // This flag is true if a script is currently being compiled. It is used to prevent multiple + // threads from requesting builds at the same time (without blocking) + bool isBuilding; + // Synchronized with engineRWLock + // This array holds modules that have been discard (thus are no longer visible to the application) + // but cannot yet be deleted due to having external references to some of the entities in them + asCArray discardedModules; + // This flag is set to true during compilations of scripts (or loading pre-compiled scripts) + // to delay the validation of template types until the subtypes have been fully declared + bool deferValidationOfTemplateTypes; + + // Tokenizer is instantiated once to share resources + asCTokenizer tok; + + // Stores shared script declared types (classes, interfaces, enums) + asCArray sharedScriptTypes; // increases ref count + // This array stores the template instances types that have been automatically generated from template types + asCArray generatedTemplateTypes; + // Stores the funcdefs + // TODO: redesign: Only shared funcdefs should be stored here + // a funcdef becomes shared if all arguments and the return type are shared (or application registered) + asCArray funcDefs; // doesn't increases ref count + + // Stores the names of the script sections for debugging purposes + asCArray scriptSectionNames; + + // Type identifiers + mutable int typeIdSeqNbr; + mutable asCMap mapTypeIdToTypeInfo; + + // 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; + + // 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 STypeInfoClean { asPWORD type; asCLEANTYPEINFOFUNC_t cleanFunc; }; + asCArray cleanTypeInfoFuncs; + struct SScriptObjClean { asPWORD type; asCLEANSCRIPTOBJECTFUNC_t cleanFunc; }; + asCArray cleanScriptObjectFuncs; + + // Synchronization for threads + DECLAREREADWRITELOCK(mutable engineRWLock) + + // Engine properties + struct + { + bool allowUnsafeReferences; + bool optimizeByteCode; + bool copyScriptSections; + asUINT maximumContextStackSize; + asUINT initContextStackSize; + 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; + // TODO: 3.0.0: Remove the alterSyntaxNamedArgs + int alterSyntaxNamedArgs; + bool disableIntegerDivision; + bool disallowEmptyListElements; + // TODO: 3.0.0: Remove the privatePropAsProtected + bool privatePropAsProtected; + bool allowUnicodeIdentifiers; + int heredocTrimMode; + asUINT maxNestedCalls; + asUINT genericCallMode; + asUINT initCallStackSize; + asUINT maxCallStackSize; + } ep; + + // Callbacks #ifndef AS_NO_EXCEPTIONS - bool translateExceptionCallback; - asSSystemFunctionInterface translateExceptionCallbackFunc; - void * translateExceptionCallbackObj; + bool translateExceptionCallback; + asSSystemFunctionInterface translateExceptionCallbackFunc; + void * translateExceptionCallbackObj; #endif - // This flag is to allow a quicker shutdown when releasing the engine - bool shuttingDown; + // This flag is to allow a quicker shutdown when releasing the engine + bool shuttingDown; - // This flag is set when the engine's destructor is called, this is to - // avoid recursive calls if an object happens to increment/decrement - // the ref counter during shutdown - bool inDestructor; + // This flag is set when the engine's destructor is called, this is to + // avoid recursive calls if an object happens to increment/decrement + // the ref counter during shutdown + bool inDestructor; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_scriptfunction.cpp b/src/angelscript/source/as_scriptfunction.cpp index 2601454a9c6..d76d58bf280 100644 --- a/src/angelscript/source/as_scriptfunction.cpp +++ b/src/angelscript/source/as_scriptfunction.cpp @@ -56,61 +56,61 @@ BEGIN_AS_NAMESPACE static void ScriptFunction_AddRef_Generic(asIScriptGeneric *gen) { - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - self->AddRef(); + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + self->AddRef(); } static void ScriptFunction_Release_Generic(asIScriptGeneric *gen) { - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - self->Release(); + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + self->Release(); } static void ScriptFunction_GetRefCount_Generic(asIScriptGeneric *gen) { - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); } static void ScriptFunction_SetFlag_Generic(asIScriptGeneric *gen) { - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - self->SetFlag(); + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + self->SetFlag(); } static void ScriptFunction_GetFlag_Generic(asIScriptGeneric *gen) { - asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); + 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); + 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); + 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)); + asCScriptFunction *func = (asCScriptFunction*)gen->GetArgAddress(0); + void *obj = gen->GetArgAddress(1); + gen->SetReturnAddress(CreateDelegate(func, obj)); } // TODO: operator== /*static void ScriptFunction_opEquals_Generic(asIScriptGeneric *gen) { - asCScriptFunction *funcSelf = (asCScriptFunction*)gen->GetObject(); - asCScriptFunction *funcOther = (asCScriptFunction*)gen->GetArgAddress(0); - *(bool*)gen->GetAddressOfReturnLocation() = *funcSelf == *funcOther; + asCScriptFunction *funcSelf = (asCScriptFunction*)gen->GetObject(); + asCScriptFunction *funcOther = (asCScriptFunction*)gen->GetArgAddress(0); + *(bool*)gen->GetAddressOfReturnLocation() = *funcSelf == *funcOther; } */ @@ -119,120 +119,120 @@ static void ScriptFunction_CreateDelegate_Generic(asIScriptGeneric *gen) 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; - engine->functionBehaviours.name = "$func"; + // 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; + engine->functionBehaviours.name = "$func"; #ifndef AS_MAX_PORTABILITY - r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptFunction,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 ); - 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: 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 ); + 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: 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 ); + 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 + // 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 ); + 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 ); + 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]); + // 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::CreateType(&engine->functionBehaviours, false); - engine->scriptFunctions[r]->returnType.MakeHandle(true); + // Change the return type so the VM will know the function really returns a handle + engine->scriptFunctions[r]->returnType = asCDataType::CreateType(&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; - } + 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); + // 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; + return delegate; } // internal void asCScriptFunction::MakeDelegate(asCScriptFunction *func, void *obj) { - // Increase the reference of the function and object - func->AddRef(); - funcForDelegate = func; + // Increase the reference of the function and object + func->AddRef(); + funcForDelegate = func; - func->GetEngine()->AddRefScriptObject(obj, func->GetObjectType()); - objForDelegate = obj; + 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 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; + // 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::GetAuxiliary() const { - if (sysFuncIntf) - return sysFuncIntf->auxiliary; + if (sysFuncIntf) + return sysFuncIntf->auxiliary; - return 0; + return 0; } // interface void *asCScriptFunction::GetDelegateObject() const { - return objForDelegate; + return objForDelegate; } // interface asITypeInfo *asCScriptFunction::GetDelegateObjectType() const { - if( objForDelegate == 0 || funcForDelegate == 0 ) - return 0; + if( objForDelegate == 0 || funcForDelegate == 0 ) + return 0; - return funcForDelegate->objectType; + return funcForDelegate->objectType; } // interface asIScriptFunction *asCScriptFunction::GetDelegateFunction() const { - return funcForDelegate; + return funcForDelegate; } // TODO: operator== @@ -240,1486 +240,1486 @@ asIScriptFunction *asCScriptFunction::GetDelegateFunction() const // internal bool asCScriptFunction::operator==(const asCScriptFunction &other) const { - if( this == &other ) return true; + 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; - } + if( this->funcType == asFUNC_DELEGATE && other.funcType == asFUNC_DELEGATE ) + { + if( this->objForDelegate == other.objForDelegate && + this->funcForDelegate == other.funcForDelegate ) + return true; + } - return false; + return false; } */ // internal int asCScriptFunction::RegisterListPattern(const char *decl, asCScriptNode *listNodes) { - if( listNodes == 0 ) - return asINVALID_ARG; + 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; + // 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); + // Recursively parse the child + int r = ParseListPattern(node, decl, listNodes); - node->next = asNEW(asSListPatternNode)(asLPT_END); + node->next = asNEW(asSListPatternNode)(asLPT_END); - return r; + 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, CastToObjectType(returnType.GetTypeInfo())); - - 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; + 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, CastToObjectType(returnType.GetTypeInfo())); + + 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) { - funcType = _funcType; - if( funcType == asFUNC_DELEGATE ) - { - // Delegates behave like object instances, rather than script code - externalRefCount.set(1); - internalRefCount.set(0); - } - else - { - internalRefCount.set(1); - externalRefCount.set(0); - } - - this->engine = engine; - this->scriptData = 0; - module = mod; - objectType = 0; - name = ""; - sysFuncIntf = 0; - signatureId = 0; - dontCleanUpOnException = false; - vfTableIdx = -1; - gcFlag = false; - userData = 0; - id = 0; - accessMask = 0xFFFFFFFF; - nameSpace = engine->nameSpaces[0]; - objForDelegate = 0; - funcForDelegate = 0; - listPattern = 0; - funcdefType = 0; - - if( funcType == asFUNC_SCRIPT ) - AllocateScriptFunctionData(); - - // Notify the GC of delegates - if( funcType == asFUNC_DELEGATE ) - engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours); + funcType = _funcType; + if( funcType == asFUNC_DELEGATE ) + { + // Delegates behave like object instances, rather than script code + externalRefCount.set(1); + internalRefCount.set(0); + } + else + { + internalRefCount.set(1); + externalRefCount.set(0); + } + + this->engine = engine; + this->scriptData = 0; + module = mod; + objectType = 0; + name = ""; + sysFuncIntf = 0; + signatureId = 0; + dontCleanUpOnException = false; + vfTableIdx = -1; + gcFlag = false; + userData = 0; + id = 0; + accessMask = 0xFFFFFFFF; + nameSpace = engine->nameSpaces[0]; + objForDelegate = 0; + funcForDelegate = 0; + listPattern = 0; + funcdefType = 0; + + if( funcType == asFUNC_SCRIPT ) + AllocateScriptFunctionData(); + + // Notify the GC of delegates + if( funcType == asFUNC_DELEGATE ) + engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours); } void asCScriptFunction::AllocateScriptFunctionData() { - if( scriptData ) return; + if( scriptData ) return; - scriptData = asNEW(ScriptFunctionData); + scriptData = asNEW(ScriptFunctionData); - scriptData->stackNeeded = 0; - scriptData->variableSpace = 0; - scriptData->scriptSectionIdx = -1; - scriptData->declaredAt = 0; - scriptData->jitFunction = 0; + scriptData->stackNeeded = 0; + scriptData->variableSpace = 0; + scriptData->scriptSectionIdx = -1; + scriptData->declaredAt = 0; + scriptData->jitFunction = 0; } void asCScriptFunction::DeallocateScriptFunctionData() { - if( !scriptData ) return; + if( !scriptData ) return; - for( asUINT n = 0; n < scriptData->variables.GetLength(); n++ ) - asDELETE(scriptData->variables[n],asSScriptVariable); - scriptData->variables.SetLength(0); + for( asUINT n = 0; n < scriptData->variables.GetLength(); n++ ) + asDELETE(scriptData->variables[n],asSScriptVariable); + scriptData->variables.SetLength(0); - asDELETE(scriptData, ScriptFunctionData); - scriptData = 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 || - (externalRefCount.get() == 0 && internalRefCount.get() == 0) ); + // Dummy functions that are allocated on the stack are not reference counted + asASSERT( funcType == asFUNC_DUMMY || + (externalRefCount.get() == 0 && internalRefCount.get() == 0) ); - // Remove the script function from the engine's scriptFunctions array here - // Don't remove it before, because there may still be functions referring to it - // by index until now. If it was removed in DestroyInternal, those would not - // be able to release the refcount, thus causing memory leak. - if( engine && id != 0 && funcType != asFUNC_DUMMY ) - engine->RemoveScriptFunction(this); + // Remove the script function from the engine's scriptFunctions array here + // Don't remove it before, because there may still be functions referring to it + // by index until now. If it was removed in DestroyInternal, those would not + // be able to release the refcount, thus causing memory leak. + if( engine && id != 0 && funcType != asFUNC_DUMMY ) + engine->RemoveScriptFunction(this); - // If the engine pointer is 0, then DestroyInternal has already been called and there is nothing more to do - if( engine == 0 ) return; + // If the engine pointer is 0, then DestroyInternal has already been called and there is nothing more to do + if( engine == 0 ) return; - DestroyInternal(); + DestroyInternal(); - // Finally set the engine pointer to 0 because it must not be accessed again - engine = 0; + // Finally set the engine pointer to 0 because it must not be accessed again + engine = 0; } // internal void asCScriptFunction::DestroyHalfCreated() { - asASSERT( externalRefCount.get() == 0 && internalRefCount.get() == 1 ); + asASSERT( externalRefCount.get() == 0 && internalRefCount.get() == 1 ); - // Set the funcType to dummy so the destructor won't complain - funcType = asFUNC_DUMMY; + // 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); + // 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); - asDELETE(this, asCScriptFunction); + asDELETE(this, asCScriptFunction); } // 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; - - if( objectType ) - { - objectType->ReleaseInternal(); - objectType = 0; - } - - DeallocateScriptFunctionData(); - - // Deallocate list pattern data - while( listPattern ) - { - asSListPatternNode *n = listPattern->next; - asDELETE(listPattern, asSListPatternNode); - listPattern = n; - } + // 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; + + if( objectType ) + { + objectType->ReleaseInternal(); + objectType = 0; + } + + DeallocateScriptFunctionData(); + + // Deallocate list pattern data + while( listPattern ) + { + asSListPatternNode *n = listPattern->next; + asDELETE(listPattern, asSListPatternNode); + listPattern = n; + } } // interface int asCScriptFunction::GetId() const { - return id; + return id; } // interface int asCScriptFunction::AddRef() const { - gcFlag = false; - return externalRefCount.atomicInc(); + gcFlag = false; + return externalRefCount.atomicInc(); } // interface int asCScriptFunction::Release() const { - gcFlag = false; - int r = externalRefCount.atomicDec(); - if( r == 0 && - funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted - { - // There are no more external references, if there are also no - // internal references then it is time to delete the function - if( internalRefCount.get() == 0 ) - { - // If there are no internal references, then no module is owning the function - // For example if the function was dynamically compiled without adding it to the scope of the module - asASSERT( module == 0 ); + gcFlag = false; + int r = externalRefCount.atomicDec(); + if( r == 0 && + funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted + { + // There are no more external references, if there are also no + // internal references then it is time to delete the function + if( internalRefCount.get() == 0 ) + { + // If there are no internal references, then no module is owning the function + // For example if the function was dynamically compiled without adding it to the scope of the module + asASSERT( module == 0 ); - asDELETE(const_cast(this),asCScriptFunction); - } - } + asDELETE(const_cast(this),asCScriptFunction); + } + } - return r; + return r; } // internal int asCScriptFunction::AddRefInternal() { - return internalRefCount.atomicInc(); + return internalRefCount.atomicInc(); } // internal int asCScriptFunction::ReleaseInternal() { - int r = internalRefCount.atomicDec(); - if( r == 0 && - funcType != asFUNC_DUMMY ) - { - // There are no more internal references, if there are also no - // external references then it is time to delete the function - if( externalRefCount.get() == 0 ) - { - asDELETE(const_cast(this),asCScriptFunction); - } - } + int r = internalRefCount.atomicDec(); + if( r == 0 && + funcType != asFUNC_DUMMY ) + { + // There are no more internal references, if there are also no + // external references then it is time to delete the function + if( externalRefCount.get() == 0 ) + { + asDELETE(const_cast(this),asCScriptFunction); + } + } - return r; + return r; } // interface int asCScriptFunction::GetTypeId() const { - // This const cast is ok, the object won't be modified - asCDataType dt = asCDataType::CreateType(engine->FindMatchingFuncdef(const_cast(this), 0), false); - return engine->GetTypeIdFromDataType(dt); + // This const cast is ok, the object won't be modified + asCDataType dt = asCDataType::CreateType(engine->FindMatchingFuncdef(const_cast(this), 0), false); + return engine->GetTypeIdFromDataType(dt); } // interface bool asCScriptFunction::IsCompatibleWithTypeId(int typeId) const { - asCDataType dt = engine->GetDataTypeFromTypeId(typeId); + asCDataType dt = engine->GetDataTypeFromTypeId(typeId); - // Make sure the type is a function - if (!dt.IsFuncdef()) - return false; + // Make sure the type is a function + if (!dt.IsFuncdef()) + return false; - asCScriptFunction *func = CastToFuncdefType(dt.GetTypeInfo())->funcdef; - if( !IsSignatureExceptNameEqual(func) ) - return false; + asCScriptFunction *func = CastToFuncdefType(dt.GetTypeInfo())->funcdef; + 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; + // 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; + return true; } // interface const char *asCScriptFunction::GetModuleName() const { - if( module ) - return module->GetName(); + if( module ) + return module->GetName(); - return 0; + return 0; } // interface asIScriptModule *asCScriptFunction::GetModule() const { - return module; + return module; } // interface asITypeInfo *asCScriptFunction::GetObjectType() const { - return objectType; + return objectType; } // interface const char *asCScriptFunction::GetObjectName() const { - if( objectType ) - return objectType->GetName(); + if( objectType ) + return objectType->GetName(); - return 0; + return 0; } // interface const char *asCScriptFunction::GetName() const { - return name.AddressOf(); + return name.AddressOf(); } // interface const char *asCScriptFunction::GetNamespace() const { - if (nameSpace) - return nameSpace->name.AddressOf(); + if (nameSpace) + return nameSpace->name.AddressOf(); - return 0; + return 0; } // interface bool asCScriptFunction::IsReadOnly() const { - return traits.GetTrait(asTRAIT_CONST); + return traits.GetTrait(asTRAIT_CONST); } // interface bool asCScriptFunction::IsPrivate() const { - return traits.GetTrait(asTRAIT_PRIVATE); + return traits.GetTrait(asTRAIT_PRIVATE); } // interface bool asCScriptFunction::IsProtected() const { - return traits.GetTrait(asTRAIT_PROTECTED); + return traits.GetTrait(asTRAIT_PROTECTED); } // 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(); + // 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; + return s; } // internal int asCScriptFunction::GetSpaceNeededForReturnValue() { - return returnType.GetSizeOnStackDWords(); + return returnType.GetSizeOnStackDWords(); } // internal bool asCScriptFunction::DoesReturnOnStack() const { - if( returnType.GetTypeInfo() && - (returnType.GetTypeInfo()->flags & asOBJ_VALUE) && - !returnType.IsReference() ) - return true; + if( returnType.GetTypeInfo() && + (returnType.GetTypeInfo()->flags & asOBJ_VALUE) && + !returnType.IsReference() ) + return true; - return false; + 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 == "$beh0" || name == "$beh2")) ) - { - str = returnType.Format(nameSpace, includeNamespace); - str += " "; - } - if( objectType && includeObjectName ) - { - if( includeNamespace && objectType->nameSpace->name != "" ) - str += objectType->nameSpace->name + "::"; - - if( objectType->name != "" ) - str += objectType->name + "::"; - else - str += "_unnamed_type_::"; - } - else if (funcdefType && funcdefType->parentClass && includeObjectName) - { - if (includeNamespace && funcdefType->parentClass->nameSpace->name != "") - str += funcdefType->parentClass->nameSpace->name + "::"; - - if (funcdefType->parentClass->name != "") - str += funcdefType->parentClass->name + "::"; - else - str += "_unnamed_type_::"; - } - else if( includeNamespace && nameSpace->name != "" && !objectType ) - { - str += nameSpace->name + "::"; - } - if( name == "" ) - str += "_unnamed_function_("; - else if( name.SubString(0,4) == "$beh" && name.GetLength() == 5 ) - { - if( name[4] == '0' + asBEHAVE_CONSTRUCT ) - str += objectType->name + "("; - else if( name[4] == '0' + asBEHAVE_FACTORY ) - str += returnType.GetTypeInfo()->name + "("; - else if( name[4] == '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(nameSpace, includeNamespace); - 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(nameSpace, includeNamespace); - 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(nameSpace, includeNamespace); - } - - n = n->next; - } - } - - return str; + 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 == "$beh0" || name == "$beh2")) ) + { + str = returnType.Format(nameSpace, includeNamespace); + str += " "; + } + if( objectType && includeObjectName ) + { + if( includeNamespace && objectType->nameSpace->name != "" ) + str += objectType->nameSpace->name + "::"; + + if( objectType->name != "" ) + str += objectType->name + "::"; + else + str += "_unnamed_type_::"; + } + else if (funcdefType && funcdefType->parentClass && includeObjectName) + { + if (includeNamespace && funcdefType->parentClass->nameSpace->name != "") + str += funcdefType->parentClass->nameSpace->name + "::"; + + if (funcdefType->parentClass->name != "") + str += funcdefType->parentClass->name + "::"; + else + str += "_unnamed_type_::"; + } + else if( includeNamespace && nameSpace->name != "" && !objectType ) + { + str += nameSpace->name + "::"; + } + if( name == "" ) + str += "_unnamed_function_("; + else if( name.SubString(0,4) == "$beh" && name.GetLength() == 5 ) + { + if( name[4] == '0' + asBEHAVE_CONSTRUCT ) + str += objectType->name + "("; + else if( name[4] == '0' + asBEHAVE_FACTORY ) + str += returnType.GetTypeInfo()->name + "("; + else if( name[4] == '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(nameSpace, includeNamespace); + 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(nameSpace, includeNamespace); + 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(nameSpace, includeNamespace); + } + + 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; + 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]; - } - } + 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; + return funcType; } // interface asUINT asCScriptFunction::GetVarCount() const { - if( scriptData ) - return asUINT(scriptData->variables.GetLength()); - return 0; + if( scriptData ) + return asUINT(scriptData->variables.GetLength()); + return 0; } // interface int asCScriptFunction::GetVar(asUINT index, const char **out_name, int *out_typeId) const { - if( scriptData == 0 ) - return asNOT_SUPPORTED; - if( index >= scriptData->variables.GetLength() ) - return asINVALID_ARG; + if( scriptData == 0 ) + return asNOT_SUPPORTED; + if( index >= scriptData->variables.GetLength() ) + return asINVALID_ARG; - if( out_name ) - *out_name = scriptData->variables[index]->name.AddressOf(); - if( out_typeId ) - *out_typeId = engine->GetTypeIdFromDataType(scriptData->variables[index]->type); + if( out_name ) + *out_name = scriptData->variables[index]->name.AddressOf(); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(scriptData->variables[index]->type); - return asSUCCESS; + return asSUCCESS; } // interface const char *asCScriptFunction::GetVarDecl(asUINT index, bool includeNamespace) const { - if( scriptData == 0 || index >= scriptData->variables.GetLength() ) - return 0; + if( scriptData == 0 || index >= scriptData->variables.GetLength() ) + return 0; - asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = scriptData->variables[index]->type.Format(nameSpace, includeNamespace); - *tempString += " " + scriptData->variables[index]->name; + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = scriptData->variables[index]->type.Format(nameSpace, includeNamespace); + *tempString += " " + scriptData->variables[index]->name; - return tempString->AddressOf(); + return tempString->AddressOf(); } // internal void asCScriptFunction::AddVariable(asCString &in_name, asCDataType &in_type, int in_stackOffset) { - asASSERT( scriptData ); - asSScriptVariable *var = asNEW(asSScriptVariable); - if( var == 0 ) - { - // Out of memory - return; - } - var->name = in_name; - var->type = in_type; - var->stackOffset = in_stackOffset; - var->declaredAtProgramPos = 0; - scriptData->variables.PushLast(var); + asASSERT( scriptData ); + asSScriptVariable *var = asNEW(asSScriptVariable); + if( var == 0 ) + { + // Out of memory + return; + } + var->name = in_name; + var->type = in_type; + var->stackOffset = in_stackOffset; + var->declaredAtProgramPos = 0; + scriptData->variables.PushLast(var); } // internal asCTypeInfo *asCScriptFunction::GetTypeInfoOfLocalVar(short varOffset) { - asASSERT( scriptData ); + asASSERT( scriptData ); - for( asUINT n = 0; n < scriptData->objVariablePos.GetLength(); n++ ) - { - if( scriptData->objVariablePos[n] == varOffset ) - return scriptData->objVariableTypes[n]; - } + for( asUINT n = 0; n < scriptData->objVariablePos.GetLength(); n++ ) + { + if( scriptData->objVariablePos[n] == varOffset ) + return scriptData->objVariableTypes[n]; + } - return 0; + 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; + // 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; - } + // 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); + signatureId = id; + engine->signatureIds.PushLast(this); } // internal bool asCScriptFunction::IsSignatureEqual(const asCScriptFunction *func) const { - if( name != func->name || !IsSignatureExceptNameEqual(func) ) return false; + if( name != func->name || !IsSignatureExceptNameEqual(func) ) return false; - return true; + return true; } // internal bool asCScriptFunction::IsSignatureExceptNameEqual(const asCScriptFunction *func) const { - return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, func->objectType, func->IsReadOnly()); + return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, func->objectType, func->IsReadOnly()); } // internal bool asCScriptFunction::IsSignatureExceptNameEqual(const asCDataType &retType, const asCArray ¶mTypes, const asCArray ¶mInOut, const asCObjectType *objType, bool readOnly) const { - if( this->returnType != retType ) return false; + if( this->returnType != retType ) return false; - return IsSignatureExceptNameAndReturnTypeEqual(paramTypes, paramInOut, objType, readOnly); + return IsSignatureExceptNameAndReturnTypeEqual(paramTypes, paramInOut, objType, readOnly); } // internal bool asCScriptFunction::IsSignatureExceptNameAndObjectTypeEqual(const asCScriptFunction *func) const { - return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, objectType, IsReadOnly()); + return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, objectType, IsReadOnly()); } // internal bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCScriptFunction *func) const { - return IsSignatureExceptNameAndReturnTypeEqual(func->parameterTypes, func->inOutFlags, func->objectType, func->IsReadOnly()); + return IsSignatureExceptNameAndReturnTypeEqual(func->parameterTypes, func->inOutFlags, func->objectType, func->IsReadOnly()); } // internal bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCArray ¶mTypes, const asCArray ¶mInOut, const asCObjectType *objType, bool readOnly) const { - if( this->IsReadOnly() != readOnly ) return false; - if( (this->objectType != 0) != (objType != 0) ) return false; - if( this->inOutFlags != paramInOut ) return false; - if( this->parameterTypes != paramTypes ) return false; + if( this->IsReadOnly() != readOnly ) return false; + if( (this->objectType != 0) != (objType != 0) ) return false; + if( this->inOutFlags != paramInOut ) return false; + if( this->parameterTypes != paramTypes ) return false; - return true; + 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.GetTypeInfo() ) - { - returnType.GetTypeInfo()->AddRefInternal(); - - asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(returnType.GetTypeInfo()); - if( group != 0 ) group->AddRef(); - } - - for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) - if( parameterTypes[p].GetTypeInfo() ) - { - parameterTypes[p].GetTypeInfo()->AddRefInternal(); - - asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(parameterTypes[p].GetTypeInfo()); - if( group != 0 ) group->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]->AddRefInternal(); - - asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(scriptData->objVariableTypes[v]); - if( group != 0 ) group->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->AddRefInternal(); - } - break; - - // Object type and function - case asBC_ALLOC: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - asASSERT( objType ); - if( objType ) - objType->AddRefInternal(); - - int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE); - if( funcId ) - engine->scriptFunctions[funcId]->AddRefInternal(); - } - 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) - { - // The pointer is a string constant. In order to make sure the correct resource - // management is maintained we request a new string constant here, so the compiler - // or bytecode loader can release its copy afterwards. - asCString str; - asUINT length; - int r = engine->stringFactory->GetRawStringData(gvarPtr, 0, &length); - if (r >= 0) - { - str.SetLength(length); - engine->stringFactory->GetRawStringData(gvarPtr, str.AddressOf(), &length); - - // Get a new pointer (depending on the string factory implementation it may actually be the same) - gvarPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), length)); - asBC_PTRARG(&bc[n]) = (asPWORD)gvarPtr; - } - - // If we get an error from the string factory there is not - // anything we can do about it, except report a message. - // TODO: NEWSTRING: Write a message and then exit gracefully - asASSERT(r >= 0); - break; - } - - // Only addref the properties once - if( !ptrs.Exists(gvarPtr) ) - { - 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]->AddRefInternal(); - } - break; - - // Functions - case asBC_CALL: - case asBC_CALLINTF: - { - int funcId = asBC_INTARG(&bc[n]); - asASSERT( funcId > 0 ); - if( funcId > 0 ) - engine->scriptFunctions[funcId]->AddRefInternal(); - } - break; - - // Function pointers - case asBC_FuncPtr: - { - asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]); - asASSERT( func ); - if( func ) - func->AddRefInternal(); - } - break; - } - } - } + // 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.GetTypeInfo() ) + { + returnType.GetTypeInfo()->AddRefInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(returnType.GetTypeInfo()); + if( group != 0 ) group->AddRef(); + } + + for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) + if( parameterTypes[p].GetTypeInfo() ) + { + parameterTypes[p].GetTypeInfo()->AddRefInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(parameterTypes[p].GetTypeInfo()); + if( group != 0 ) group->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]->AddRefInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(scriptData->objVariableTypes[v]); + if( group != 0 ) group->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->AddRefInternal(); + } + break; + + // Object type and function + case asBC_ALLOC: + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); + asASSERT( objType ); + if( objType ) + objType->AddRefInternal(); + + int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE); + if( funcId ) + engine->scriptFunctions[funcId]->AddRefInternal(); + } + 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) + { + // The pointer is a string constant. In order to make sure the correct resource + // management is maintained we request a new string constant here, so the compiler + // or bytecode loader can release its copy afterwards. + asCString str; + asUINT length; + int r = engine->stringFactory->GetRawStringData(gvarPtr, 0, &length); + if (r >= 0) + { + str.SetLength(length); + engine->stringFactory->GetRawStringData(gvarPtr, str.AddressOf(), &length); + + // Get a new pointer (depending on the string factory implementation it may actually be the same) + gvarPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), length)); + asBC_PTRARG(&bc[n]) = (asPWORD)gvarPtr; + } + + // If we get an error from the string factory there is not + // anything we can do about it, except report a message. + // TODO: NEWSTRING: Write a message and then exit gracefully + asASSERT(r >= 0); + break; + } + + // Only addref the properties once + if( !ptrs.Exists(gvarPtr) ) + { + 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]->AddRefInternal(); + } + break; + + // Functions + case asBC_CALL: + case asBC_CALLINTF: + { + int funcId = asBC_INTARG(&bc[n]); + asASSERT( funcId > 0 ); + if( funcId > 0 ) + engine->scriptFunctions[funcId]->AddRefInternal(); + } + break; + + // Function pointers + case asBC_FuncPtr: + { + asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]); + asASSERT( func ); + if( func ) + func->AddRefInternal(); + } + break; + } + } + } } // internal void asCScriptFunction::ReleaseReferences() { - asCArray ptrs; - - // Only count references if there is any bytecode - if( scriptData && scriptData->byteCode.GetLength() ) - { - if( returnType.GetTypeInfo() ) - { - returnType.GetTypeInfo()->ReleaseInternal(); - - asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(returnType.GetTypeInfo()); - if( group != 0 ) group->Release(); - } - - for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) - if( parameterTypes[p].GetTypeInfo() ) - { - parameterTypes[p].GetTypeInfo()->ReleaseInternal(); - - asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(parameterTypes[p].GetTypeInfo()); - if( group != 0 ) group->Release(); - } - - 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]->ReleaseInternal(); - - asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(scriptData->objVariableTypes[v]); - if( group != 0 ) group->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->ReleaseInternal(); - } - break; - - // Object type and function - case asBC_ALLOC: - { - asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); - if( objType ) - objType->ReleaseInternal(); - - int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE); - if( funcId > 0 ) - { - asCScriptFunction *fptr = engine->scriptFunctions[funcId]; - if( fptr ) - fptr->ReleaseInternal(); - - // 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) - { - // The pointer is a string constant, so it needs to be released by the string factory - int r = engine->stringFactory->ReleaseStringConstant(gvarPtr); - UNUSED_VAR(r); - - // If we get an error from the string factory there is not - // anything we can do about it, except report a message. - // TODO: Write a message showing that the string couldn't be - // released. Include the first 10 characters and the length - // to make it easier to identify which string it was - asASSERT(r >= 0); - break; - } - - // Only release the properties once - if( !ptrs.Exists(gvarPtr) ) - { - 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 ) - { - asCScriptFunction *fptr = engine->scriptFunctions[funcId]; - if( fptr ) - fptr->ReleaseInternal(); - } - } - break; - - // Functions - case asBC_CALL: - case asBC_CALLINTF: - { - int funcId = asBC_INTARG(&bc[n]); - if( funcId ) - { - asCScriptFunction *fptr = engine->scriptFunctions[funcId]; - if( fptr ) - fptr->ReleaseInternal(); - - // 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->ReleaseInternal(); - } - 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; + asCArray ptrs; + + // Only count references if there is any bytecode + if( scriptData && scriptData->byteCode.GetLength() ) + { + if( returnType.GetTypeInfo() ) + { + returnType.GetTypeInfo()->ReleaseInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(returnType.GetTypeInfo()); + if( group != 0 ) group->Release(); + } + + for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) + if( parameterTypes[p].GetTypeInfo() ) + { + parameterTypes[p].GetTypeInfo()->ReleaseInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(parameterTypes[p].GetTypeInfo()); + if( group != 0 ) group->Release(); + } + + 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]->ReleaseInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(scriptData->objVariableTypes[v]); + if( group != 0 ) group->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->ReleaseInternal(); + } + break; + + // Object type and function + case asBC_ALLOC: + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); + if( objType ) + objType->ReleaseInternal(); + + int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE); + if( funcId > 0 ) + { + asCScriptFunction *fptr = engine->scriptFunctions[funcId]; + if( fptr ) + fptr->ReleaseInternal(); + + // 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) + { + // The pointer is a string constant, so it needs to be released by the string factory + int r = engine->stringFactory->ReleaseStringConstant(gvarPtr); + UNUSED_VAR(r); + + // If we get an error from the string factory there is not + // anything we can do about it, except report a message. + // TODO: Write a message showing that the string couldn't be + // released. Include the first 10 characters and the length + // to make it easier to identify which string it was + asASSERT(r >= 0); + break; + } + + // Only release the properties once + if( !ptrs.Exists(gvarPtr) ) + { + 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 ) + { + asCScriptFunction *fptr = engine->scriptFunctions[funcId]; + if( fptr ) + fptr->ReleaseInternal(); + } + } + break; + + // Functions + case asBC_CALL: + case asBC_CALLINTF: + { + int funcId = asBC_INTARG(&bc[n]); + if( funcId ) + { + asCScriptFunction *fptr = engine->scriptFunctions[funcId]; + if( fptr ) + fptr->ReleaseInternal(); + + // 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->ReleaseInternal(); + } + 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; - } + if( flags ) + { + if( returnType.IsReference() ) + { + *flags = asTM_INOUTREF; + *flags |= returnType.IsReadOnly() ? asTM_CONST : 0; + } + else + *flags = asTM_NONE; + } - return engine->GetTypeIdFromDataType(returnType); + return engine->GetTypeIdFromDataType(returnType); } // interface asUINT asCScriptFunction::GetParamCount() const { - return (asUINT)parameterTypes.GetLength(); + return (asUINT)parameterTypes.GetLength(); } // interface int asCScriptFunction::GetParam(asUINT index, int *out_typeId, asDWORD *out_flags, const char **out_name, const char **out_defaultArg) const { - if( index >= parameterTypes.GetLength() ) - return asINVALID_ARG; + if( index >= parameterTypes.GetLength() ) + return asINVALID_ARG; - if( out_typeId ) - *out_typeId = engine->GetTypeIdFromDataType(parameterTypes[index]); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(parameterTypes[index]); - if( out_flags ) - { - *out_flags = inOutFlags[index]; - *out_flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0; - } + if( out_flags ) + { + *out_flags = inOutFlags[index]; + *out_flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0; + } - if( out_name ) - { - // The parameter names are not stored if loading from bytecode without debug information - if( index < parameterNames.GetLength() ) - *out_name = parameterNames[index].AddressOf(); - else - *out_name = 0; - } + if( out_name ) + { + // The parameter names are not stored if loading from bytecode without debug information + if( index < parameterNames.GetLength() ) + *out_name = parameterNames[index].AddressOf(); + else + *out_name = 0; + } - if( out_defaultArg ) - { - if( index < defaultArgs.GetLength() && defaultArgs[index] ) - *out_defaultArg = defaultArgs[index]->AddressOf(); - else - *out_defaultArg = 0; - } + if( out_defaultArg ) + { + if( index < defaultArgs.GetLength() && defaultArgs[index] ) + *out_defaultArg = defaultArgs[index]->AddressOf(); + else + *out_defaultArg = 0; + } - return asSUCCESS; + return asSUCCESS; } // interface asIScriptEngine *asCScriptFunction::GetEngine() const { - return engine; + 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(); + 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(); + if( scriptData && scriptData->scriptSectionIdx >= 0 ) + return engine->scriptSectionNames[scriptData->scriptSectionIdx]->AddressOf(); - return 0; + return 0; } // interface const char *asCScriptFunction::GetConfigGroup() const { - asCConfigGroup *group = 0; - if( funcType != asFUNC_FUNCDEF ) - group = engine->FindConfigGroupForFunction(id); - else - group = engine->FindConfigGroupForFuncDef(this->funcdefType); + asCConfigGroup *group = 0; + if( funcType != asFUNC_FUNCDEF ) + group = engine->FindConfigGroupForFunction(id); + else + group = engine->FindConfigGroupForFuncDef(this->funcdefType); - if( group == 0 ) - return 0; + if( group == 0 ) + return 0; - return group->groupName.AddressOf(); + return group->groupName.AddressOf(); } // interface asDWORD asCScriptFunction::GetAccessMask() const { - return accessMask; + 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 ); + 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( scriptData == 0 ) return 0; - if( length ) - *length = (asUINT)scriptData->byteCode.GetLength(); + if( length ) + *length = (asUINT)scriptData->byteCode.GetLength(); - if( scriptData->byteCode.GetLength() ) - return scriptData->byteCode.AddressOf(); + if( scriptData->byteCode.GetLength() ) + return scriptData->byteCode.AddressOf(); - return 0; + 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); + // 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); + // 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); + RELEASEEXCLUSIVE(engine->engineRWLock); - return oldData; - } - } + return oldData; + } + } - userData.PushLast(type); - userData.PushLast(reinterpret_cast(data)); + userData.PushLast(type); + userData.PushLast(reinterpret_cast(data)); - RELEASEEXCLUSIVE(engine->engineRWLock); + RELEASEEXCLUSIVE(engine->engineRWLock); - return 0; + 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); + // 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]); - } - } + 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); + RELEASESHARED(engine->engineRWLock); - return 0; + 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; + asSMapNode *node; + if( engine->varAddressMap.MoveTo(&node, gvarPtr) ) + { + asASSERT(gvarPtr == node->value->GetAddressOfValue()); + return node->value; + } + return 0; } // internal int asCScriptFunction::GetRefCount() { - asASSERT( funcType == asFUNC_DELEGATE ); + asASSERT( funcType == asFUNC_DELEGATE ); - return externalRefCount.get(); + return externalRefCount.get(); } // internal void asCScriptFunction::SetFlag() { - gcFlag = true; + gcFlag = true; } // internal bool asCScriptFunction::GetFlag() { - return gcFlag; + return gcFlag; } // internal void asCScriptFunction::EnumReferences(asIScriptEngine *) { - asASSERT( funcType == asFUNC_DELEGATE ); + asASSERT( funcType == asFUNC_DELEGATE ); - // Delegate - if( objForDelegate ) - engine->GCEnumCallback(objForDelegate); + // Delegate + if( objForDelegate ) + engine->GCEnumCallback(objForDelegate); } // internal void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *) { - asASSERT( funcType == asFUNC_DELEGATE ); + asASSERT( funcType == asFUNC_DELEGATE ); - // Release paramaters + // Release paramaters - // Delegate - if( objForDelegate ) - engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType()); - objForDelegate = 0; + // Delegate + if( objForDelegate ) + engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType()); + objForDelegate = 0; } // interface bool asCScriptFunction::IsShared() const { - // All system functions are shared - if( funcType == asFUNC_SYSTEM ) return true; + // All system functions are shared + if( funcType == asFUNC_SYSTEM ) return true; - // All class methods for shared classes are also shared - asASSERT( objectType == 0 || objectType->engine == engine || objectType->engine == 0 ); - if( objectType && (objectType->flags & asOBJ_SHARED) ) return true; + // All class methods for shared classes are also shared + asASSERT( objectType == 0 || objectType->engine == engine || objectType->engine == 0 ); + if( objectType && (objectType->flags & asOBJ_SHARED) ) return true; - // funcdefs that are registered by the application are shared - if (funcType == asFUNC_FUNCDEF && module == 0) return true; + // funcdefs that are registered by the application are shared + if (funcType == asFUNC_FUNCDEF && module == 0) return true; - // Functions that have been specifically marked as shared are shared - return traits.GetTrait(asTRAIT_SHARED); + // Functions that have been specifically marked as shared are shared + return traits.GetTrait(asTRAIT_SHARED); } // interface bool asCScriptFunction::IsFinal() const { - return traits.GetTrait(asTRAIT_FINAL); + return traits.GetTrait(asTRAIT_FINAL); } // interface bool asCScriptFunction::IsOverride() const { - return traits.GetTrait(asTRAIT_OVERRIDE); + return traits.GetTrait(asTRAIT_OVERRIDE); } // interface bool asCScriptFunction::IsExplicit() const { - return traits.GetTrait(asTRAIT_EXPLICIT); + return traits.GetTrait(asTRAIT_EXPLICIT); } // interface bool asCScriptFunction::IsProperty() const { - return traits.GetTrait(asTRAIT_PROPERTY); + return traits.GetTrait(asTRAIT_PROPERTY); } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_scriptfunction.h b/src/angelscript/source/as_scriptfunction.h index 416f1d08ee2..b3c0983c7e0 100644 --- a/src/angelscript/source/as_scriptfunction.h +++ b/src/angelscript/source/as_scriptfunction.h @@ -58,81 +58,81 @@ struct asSNameSpace; struct asSScriptVariable { - asCString name; - asCDataType type; - int stackOffset; - asUINT declaredAtProgramPos; + asCString name; + asCDataType type; + int stackOffset; + asUINT declaredAtProgramPos; }; enum asEListPatternNodeType { - asLPT_REPEAT, - asLPT_REPEAT_SAME, - asLPT_START, - asLPT_END, - asLPT_TYPE + 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; + 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; + asSListPatternDataTypeNode(const asCDataType &dt) : asSListPatternNode(asLPT_TYPE), dataType(dt) {} + asSListPatternNode *Duplicate() { return asNEW(asSListPatternDataTypeNode)(dataType); } + asCDataType dataType; }; enum asEObjVarInfoOption { - asOBJ_UNINIT, // object is uninitialized/destroyed - asOBJ_INIT, // object is initialized - asBLOCK_BEGIN, // scope block begins - asBLOCK_END, // scope block ends - asOBJ_VARDECL // object variable is declared (but not necessarily initialized) + asOBJ_UNINIT, // object is uninitialized/destroyed + asOBJ_INIT, // object is initialized + asBLOCK_BEGIN, // scope block begins + asBLOCK_END, // scope block ends + asOBJ_VARDECL // object variable is declared (but not necessarily initialized) }; enum asEFuncTrait { - asTRAIT_CONSTRUCTOR = 1, - asTRAIT_DESTRUCTOR = 2, - asTRAIT_CONST = 4, - asTRAIT_PRIVATE = 8, - asTRAIT_PROTECTED = 16, - asTRAIT_FINAL = 32, - asTRAIT_OVERRIDE = 64, - asTRAIT_SHARED = 128, - asTRAIT_EXTERNAL = 256, - asTRAIT_EXPLICIT = 512, - asTRAIT_PROPERTY = 1024 + asTRAIT_CONSTRUCTOR = 1, + asTRAIT_DESTRUCTOR = 2, + asTRAIT_CONST = 4, + asTRAIT_PRIVATE = 8, + asTRAIT_PROTECTED = 16, + asTRAIT_FINAL = 32, + asTRAIT_OVERRIDE = 64, + asTRAIT_SHARED = 128, + asTRAIT_EXTERNAL = 256, + asTRAIT_EXPLICIT = 512, + asTRAIT_PROPERTY = 1024 }; struct asSFunctionTraits { - asSFunctionTraits() : traits(0) {} - void SetTrait(asEFuncTrait trait, bool set) { if (set) traits |= trait; else traits &= ~trait; } - bool GetTrait(asEFuncTrait trait) const { return (traits & trait) ? true : false; } + asSFunctionTraits() : traits(0) {} + void SetTrait(asEFuncTrait trait, bool set) { if (set) traits |= trait; else traits &= ~trait; } + bool GetTrait(asEFuncTrait trait) const { return (traits & trait) ? true : false; } protected: - asDWORD traits; + asDWORD traits; }; struct asSObjectVariableInfo { - asUINT programPos; - int variableOffset; - asEObjVarInfoOption option; + asUINT programPos; + int variableOffset; + asEObjVarInfoOption option; }; struct asSTryCatchInfo { - asUINT tryPos; - asUINT catchPos; + asUINT tryPos; + asUINT catchPos; }; struct asSSystemFunctionInterface; @@ -146,229 +146,229 @@ 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; - void *GetAuxiliary() const; - - // Function signature - asITypeInfo *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 IsProtected() const; - bool IsFinal() const; - bool IsOverride() const; - bool IsShared() const; - bool IsExplicit() const; - bool IsProperty() const; - asUINT GetParamCount() const; - int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const; - int GetReturnTypeId(asDWORD *flags = 0) const; - - // Type id for function pointers - int GetTypeId() const; - bool IsCompatibleWithTypeId(int typeId) const; - - // Delegates - void *GetDelegateObject() const; - asITypeInfo *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; + // 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; + void *GetAuxiliary() const; + + // Function signature + asITypeInfo *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 IsProtected() const; + bool IsFinal() const; + bool IsOverride() const; + bool IsShared() const; + bool IsExplicit() const; + bool IsProperty() const; + asUINT GetParamCount() const; + int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const; + int GetReturnTypeId(asDWORD *flags = 0) const; + + // Type id for function pointers + int GetTypeId() const; + bool IsCompatibleWithTypeId(int typeId) const; + + // Delegates + void *GetDelegateObject() const; + asITypeInfo *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 + //----------------------------------- + // Internal methods - void SetShared(bool set) { traits.SetTrait(asTRAIT_SHARED, set); } - void SetReadOnly(bool set) { traits.SetTrait(asTRAIT_CONST, set); } - void SetFinal(bool set) { traits.SetTrait(asTRAIT_FINAL, set); } - void SetOverride(bool set) { traits.SetTrait(asTRAIT_OVERRIDE, set); } - void SetExplicit(bool set) { traits.SetTrait(asTRAIT_EXPLICIT, set); } - void SetProtected(bool set) { traits.SetTrait(asTRAIT_PROTECTED, set); } - void SetPrivate(bool set) { traits.SetTrait(asTRAIT_PRIVATE, set); } - void SetProperty(bool set) { traits.SetTrait(asTRAIT_PROPERTY, set); } + void SetShared(bool set) { traits.SetTrait(asTRAIT_SHARED, set); } + void SetReadOnly(bool set) { traits.SetTrait(asTRAIT_CONST, set); } + void SetFinal(bool set) { traits.SetTrait(asTRAIT_FINAL, set); } + void SetOverride(bool set) { traits.SetTrait(asTRAIT_OVERRIDE, set); } + void SetExplicit(bool set) { traits.SetTrait(asTRAIT_EXPLICIT, set); } + void SetProtected(bool set) { traits.SetTrait(asTRAIT_PROTECTED, set); } + void SetPrivate(bool set) { traits.SetTrait(asTRAIT_PRIVATE, set); } + void SetProperty(bool set) { traits.SetTrait(asTRAIT_PROPERTY, set); } - asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType funcType); - ~asCScriptFunction(); + asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType funcType); + ~asCScriptFunction(); - // Keep an internal reference counter to separate references coming from - // application or script objects and references coming from the script code - int AddRefInternal(); - int ReleaseInternal(); + // Keep an internal reference counter to separate references coming from + // application or script objects and references coming from the script code + int AddRefInternal(); + int ReleaseInternal(); - void DestroyHalfCreated(); + void DestroyHalfCreated(); - // TODO: operator== - // TODO: 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: 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; + // TODO: operator== + // TODO: 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: 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 DestroyInternal(); - void AddVariable(asCString &name, asCDataType &type, int stackOffset); + 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; + 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; - asCTypeInfo *GetTypeInfoOfLocalVar(short varOffset); + asCTypeInfo *GetTypeInfoOfLocalVar(short varOffset); - void MakeDelegate(asCScriptFunction *func, void *obj); + void MakeDelegate(asCScriptFunction *func, void *obj); - int RegisterListPattern(const char *decl, asCScriptNode *listPattern); - int ParseListPattern(asSListPatternNode *&target, const char *decl, asCScriptNode *listPattern); + int RegisterListPattern(const char *decl, asCScriptNode *listPattern); + int ParseListPattern(asSListPatternNode *&target, const char *decl, asCScriptNode *listPattern); - bool DoesReturnOnStack() const; + bool DoesReturnOnStack() const; - void JITCompile(); + void JITCompile(); - void AddReferences(); - void ReleaseReferences(); + void AddReferences(); + void ReleaseReferences(); - void AllocateScriptFunctionData(); - void DeallocateScriptFunctionData(); + void AllocateScriptFunctionData(); + void DeallocateScriptFunctionData(); - asCGlobalProperty *GetPropertyByGlobalVarPtr(void *gvarPtr); + asCGlobalProperty *GetPropertyByGlobalVarPtr(void *gvarPtr); - // GC methods (for delegates) - int GetRefCount(); - void SetFlag(); - bool GetFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllHandles(asIScriptEngine *engine); + // GC methods (for delegates) + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); public: - //----------------------------------- - // Properties - - mutable asCAtomic externalRefCount; // Used for external referneces - asCAtomic internalRefCount; // Used for internal references - mutable bool gcFlag; - asCScriptEngine *engine; - asCModule *module; - - asCArray userData; - - // Function signature - asCString name; - asCDataType returnType; - asCArray parameterTypes; - asCArray parameterNames; - asCArray inOutFlags; - asCArray defaultArgs; - asSFunctionTraits traits; - asCObjectType *objectType; - int signatureId; - - int id; - - asEFuncType funcType; - asDWORD accessMask; - - // Namespace will be null for funcdefs that are declared as child funcdefs - // of a class. In this case the namespace shall be taken from the parentClass - // in the funcdefType - asSNameSpace *nameSpace; - - asCFuncdefType *funcdefType; // Doesn't increase refCount - - // Used by asFUNC_DELEGATE - void *objForDelegate; - asCScriptFunction *funcForDelegate; - - // 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 objVariablePos; // offset on stackframe - - // The first variables in above array are allocated on the heap, the rest on the stack. - // This variable shows how many are on the heap. - asUINT objVariablesOnHeap; - - // Holds information on scope for object variables on the stack - asCArray objVariableInfo; - - // Holds information on try/catch blocks for exception handling - asCArray tryCatchInfo; - - // 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 (row in the lower 20 bits, and column in the upper 12) - 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; + //----------------------------------- + // Properties + + mutable asCAtomic externalRefCount; // Used for external referneces + asCAtomic internalRefCount; // Used for internal references + mutable bool gcFlag; + asCScriptEngine *engine; + asCModule *module; + + asCArray userData; + + // Function signature + asCString name; + asCDataType returnType; + asCArray parameterTypes; + asCArray parameterNames; + asCArray inOutFlags; + asCArray defaultArgs; + asSFunctionTraits traits; + asCObjectType *objectType; + int signatureId; + + int id; + + asEFuncType funcType; + asDWORD accessMask; + + // Namespace will be null for funcdefs that are declared as child funcdefs + // of a class. In this case the namespace shall be taken from the parentClass + // in the funcdefType + asSNameSpace *nameSpace; + + asCFuncdefType *funcdefType; // Doesn't increase refCount + + // Used by asFUNC_DELEGATE + void *objForDelegate; + asCScriptFunction *funcForDelegate; + + // 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 objVariablePos; // offset on stackframe + + // The first variables in above array are allocated on the heap, the rest on the stack. + // This variable shows how many are on the heap. + asUINT objVariablesOnHeap; + + // Holds information on scope for object variables on the stack + asCArray objVariableInfo; + + // Holds information on try/catch blocks for exception handling + asCArray tryCatchInfo; + + // 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 (row in the lower 20 bits, and column in the upper 12) + 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 = "$dlgte"; diff --git a/src/angelscript/source/as_scriptnode.cpp b/src/angelscript/source/as_scriptnode.cpp index 9bd9cfd2b38..5f150d939ac 100644 --- a/src/angelscript/source/as_scriptnode.cpp +++ b/src/angelscript/source/as_scriptnode.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2015 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -44,134 +44,134 @@ 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; + 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 *nxt; - - while( node ) - { - nxt = node->next; - node->Destroy(engine); - node = nxt; - } - - // Return the memory to the memory manager - engine->memoryMgr.FreeScriptNode(this); + // Destroy all children + asCScriptNode *node = firstChild; + asCScriptNode *nxt; + + while( node ) + { + nxt = node->next; + node->Destroy(engine); + node = nxt; + } + + // 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 *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; + 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; - } - } + 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); + // 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; + 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/src/angelscript/source/as_scriptnode.h b/src/angelscript/source/as_scriptnode.h index e743f117218..258859ce1f8 100644 --- a/src/angelscript/source/as_scriptnode.h +++ b/src/angelscript/source/as_scriptnode.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2018 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -46,59 +46,59 @@ 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, - snScope, - snTryCatch + 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, + snScope, + snTryCatch }; struct sToken { - eTokenType type; - size_t pos; - size_t length; + eTokenType type; + size_t pos; + size_t length; }; class asCScriptEngine; @@ -106,31 +106,31 @@ class asCScriptEngine; class asCScriptNode { public: - asCScriptNode(eScriptNode nodeType); + asCScriptNode(eScriptNode nodeType); - void Destroy(asCScriptEngine *engine); - asCScriptNode *CreateCopy(asCScriptEngine *engine); + void Destroy(asCScriptEngine *engine); + asCScriptNode *CreateCopy(asCScriptEngine *engine); - void SetToken(sToken *token); - void AddChildLast(asCScriptNode *node); - void DisconnectParent(); + void SetToken(sToken *token); + void AddChildLast(asCScriptNode *node); + void DisconnectParent(); - void UpdateSourcePos(size_t pos, size_t length); + void UpdateSourcePos(size_t pos, size_t length); - eScriptNode nodeType; - eTokenType tokenType; - size_t tokenPos; - size_t tokenLength; + eScriptNode nodeType; + eTokenType tokenType; + size_t tokenPos; + size_t tokenLength; - asCScriptNode *parent; - asCScriptNode *next; - asCScriptNode *prev; - asCScriptNode *firstChild; - asCScriptNode *lastChild; + asCScriptNode *parent; + asCScriptNode *next; + asCScriptNode *prev; + asCScriptNode *firstChild; + asCScriptNode *lastChild; protected: - // Must call Destroy instead - ~asCScriptNode() {} + // Must call Destroy instead + ~asCScriptNode() {} }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_scriptobject.cpp b/src/angelscript/source/as_scriptobject.cpp index 260792eecfd..33077174d77 100644 --- a/src/angelscript/source/as_scriptobject.cpp +++ b/src/angelscript/source/as_scriptobject.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2019 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -40,1144 +40,1144 @@ 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; + 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; } // This helper function will call the copy factory, that is a script function // TODO: Clean up: This function is almost identical to ScriptObjectFactory. Should make better use of the identical code. asIScriptObject *ScriptObjectCopyFactory(const asCObjectType *objType, void *origObj, 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.copyfactory]); - if (r < 0) - { - if (isNested) - ctx->PopState(); - else - engine->ReturnContext(ctx); - return 0; - } - - // Let the context handle the case for argument by ref (&) or by handle (@) - ctx->SetArgObject(0, origObj); - - 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; + 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.copyfactory]); + if (r < 0) + { + if (isNested) + ctx->PopState(); + else + engine->ReturnContext(ctx); + return 0; + } + + // Let the context handle the case for argument by ref (&) or by handle (@) + ctx->SetArgObject(0, origObj); + + 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(); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + self->AddRef(); } static void ScriptObject_Release_Generic(asIScriptGeneric *gen) { - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - self->Release(); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + self->Release(); } static void ScriptObject_GetRefCount_Generic(asIScriptGeneric *gen) { - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); } static void ScriptObject_SetFlag_Generic(asIScriptGeneric *gen) { - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - self->SetFlag(); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + self->SetFlag(); } static void ScriptObject_GetFlag_Generic(asIScriptGeneric *gen) { - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); + 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(); + 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); + 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); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllHandles(engine); } static void ScriptObject_Assignment_Generic(asIScriptGeneric *gen) { - asCScriptObject *other = *(asCScriptObject**)gen->GetAddressOfArg(0); - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + asCScriptObject *other = *(asCScriptObject**)gen->GetAddressOfArg(0); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - *self = *other; + *self = *other; - *(asCScriptObject**)gen->GetAddressOfReturnLocation() = self; + *(asCScriptObject**)gen->GetAddressOfReturnLocation() = self; } static void ScriptObject_Construct_Generic(asIScriptGeneric *gen) { - asCObjectType *objType = *(asCObjectType**)gen->GetAddressOfArg(0); - asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + asCObjectType *objType = *(asCObjectType**)gen->GetAddressOfArg(0); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); - ScriptObject_Construct(objType, self); + ScriptObject_Construct(objType, self); } #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 = "$obj"; + // 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 = "$obj"; #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 ); + 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 ); + 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(asCObjectType *objType, asCScriptObject *self) { - new(self) asCScriptObject(objType); + new(self) asCScriptObject(objType); } void ScriptObject_ConstructUnitialized(asCObjectType *objType, asCScriptObject *self) { - new(self) asCScriptObject(objType, false); + new(self) asCScriptObject(objType, false); } asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize) { - refCount.set(1); - objType = ot; - objType->AddRef(); - isDestructCalled = false; - extra = 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 ) - { + refCount.set(1); + objType = ot; + objType->AddRef(); + isDestructCalled = false; + extra = 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.GetTypeInfo()->flags & asOBJ_REF ) - { - asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); - if( prop->type.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT ) - *ptr = (asPWORD)ScriptObjectFactory(prop->type.GetTypeInfo(), ot->engine); - else - *ptr = (asPWORD)AllocateUninitializedObject(prop->type.GetTypeInfo(), ot->engine); - } - } - } + // 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.GetTypeInfo()->flags & asOBJ_REF ) + { + asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); + if( prop->type.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT ) + *ptr = (asPWORD)ScriptObjectFactory(prop->type.GetTypeInfo(), ot->engine); + else + *ptr = (asPWORD)AllocateUninitializedObject(prop->type.GetTypeInfo(), 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.GetTypeInfo()->flags & asOBJ_REF) ) - { - asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); - *ptr = (asPWORD)AllocateUninitializedObject(CastToObjectType(prop->type.GetTypeInfo()), engine); - } - } - } - } + } + 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.GetTypeInfo()->flags & asOBJ_REF) ) + { + asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); + *ptr = (asPWORD)AllocateUninitializedObject(CastToObjectType(prop->type.GetTypeInfo()), engine); + } + } + } + } } void asCScriptObject::Destruct() { - // Call the destructor, which will also call the GCObject's destructor - this->~asCScriptObject(); + // Call the destructor, which will also call the GCObject's destructor + this->~asCScriptObject(); - // Free the memory + // Free the memory #ifndef WIP_16BYTE_ALIGN - userFree(this); + userFree(this); #else - // Script object memory is allocated through asCScriptEngine::CallAlloc() - // This free call must match the allocator used in CallAlloc(). - userFreeAligned(this); + // Script object memory is allocated through asCScriptEngine::CallAlloc() + // This free call must match the allocator used in CallAlloc(). + userFreeAligned(this); #endif } asCScriptObject::~asCScriptObject() { - if( extra ) - { - if( extra->weakRefFlag ) - { - extra->weakRefFlag->Release(); - extra->weakRefFlag = 0; - } - - if( objType->engine ) - { - // Clean the user data - for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 ) - { - if( extra->userData[n+1] ) - { - for( asUINT c = 0; c < objType->engine->cleanScriptObjectFuncs.GetLength(); c++ ) - if( objType->engine->cleanScriptObjectFuncs[c].type == extra->userData[n] ) - objType->engine->cleanScriptObjectFuncs[c].cleanFunc(this); - } - } - } - - asDELETE(extra, SExtra); - } - - // 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 = CastToObjectType(prop->type.GetTypeInfo()); - 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); - } - } - else if( prop->type.IsFuncdef() ) - { - // Release the function descriptor - asCScriptFunction **ptr = (asCScriptFunction**)(((char*)this) + prop->byteOffset); - if (*ptr) - { - (*ptr)->Release(); - *ptr = 0; - } - } - } - - objType->Release(); - objType = 0; - - // Something is really wrong if the refCount is not 0 by now - asASSERT( refCount.get() == 0 ); + if( extra ) + { + if( extra->weakRefFlag ) + { + extra->weakRefFlag->Release(); + extra->weakRefFlag = 0; + } + + if( objType->engine ) + { + // Clean the user data + for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 ) + { + if( extra->userData[n+1] ) + { + for( asUINT c = 0; c < objType->engine->cleanScriptObjectFuncs.GetLength(); c++ ) + if( objType->engine->cleanScriptObjectFuncs[c].type == extra->userData[n] ) + objType->engine->cleanScriptObjectFuncs[c].cleanFunc(this); + } + } + } + + asDELETE(extra, SExtra); + } + + // 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 = CastToObjectType(prop->type.GetTypeInfo()); + 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); + } + } + else if( prop->type.IsFuncdef() ) + { + // Release the function descriptor + asCScriptFunction **ptr = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + if (*ptr) + { + (*ptr)->Release(); + *ptr = 0; + } + } + } + + 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( (extra && extra->weakRefFlag) || hasRefCountReachedZero ) - return extra->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( !extra ) - extra = asNEW(SExtra); - if( !extra->weakRefFlag ) - extra->weakRefFlag = asNEW(asCLockableSharedBool); - - asReleaseExclusiveLock(); - - return extra->weakRefFlag; + // 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( (extra && extra->weakRefFlag) || hasRefCountReachedZero ) + return extra->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( !extra ) + extra = asNEW(SExtra); + if( !extra->weakRefFlag ) + extra->weakRefFlag = asNEW(asCLockableSharedBool); + + asReleaseExclusiveLock(); + + return extra->weakRefFlag; } void *asCScriptObject::GetUserData(asPWORD type) const { - if( !extra ) - return 0; - - // There may be multiple threads reading, but when - // setting the user data nobody must be reading. - // TODO: runtime optimize: Would it be worth it to have a rwlock per object type? - asAcquireSharedLock(); - - for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 ) - { - if( extra->userData[n] == type ) - { - void *userData = reinterpret_cast(extra->userData[n+1]); - asReleaseSharedLock(); - return userData; - } - } - - asReleaseSharedLock(); - - return 0; + if( !extra ) + return 0; + + // There may be multiple threads reading, but when + // setting the user data nobody must be reading. + // TODO: runtime optimize: Would it be worth it to have a rwlock per object type? + asAcquireSharedLock(); + + for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 ) + { + if( extra->userData[n] == type ) + { + void *userData = reinterpret_cast(extra->userData[n+1]); + asReleaseSharedLock(); + return userData; + } + } + + asReleaseSharedLock(); + + return 0; } void *asCScriptObject::SetUserData(void *data, asPWORD type) { - // Lock globally so no other thread can attempt - // to manipulate the extra data 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( !extra ) - extra = asNEW(SExtra); - - // 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 < extra->userData.GetLength(); n += 2 ) - { - if( extra->userData[n] == type ) - { - void *oldData = reinterpret_cast(extra->userData[n+1]); - extra->userData[n+1] = reinterpret_cast(data); - - asReleaseExclusiveLock(); - - return oldData; - } - } - - extra->userData.PushLast(type); - extra->userData.PushLast(reinterpret_cast(data)); - - asReleaseExclusiveLock(); - - return 0; + // Lock globally so no other thread can attempt + // to manipulate the extra data 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( !extra ) + extra = asNEW(SExtra); + + // 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 < extra->userData.GetLength(); n += 2 ) + { + if( extra->userData[n] == type ) + { + void *oldData = reinterpret_cast(extra->userData[n+1]); + extra->userData[n+1] = reinterpret_cast(data); + + asReleaseExclusiveLock(); + + return oldData; + } + } + + extra->userData.PushLast(type); + extra->userData.PushLast(reinterpret_cast(data)); + + asReleaseExclusiveLock(); + + return 0; } asIScriptEngine *asCScriptObject::GetEngine() const { - return objType->engine; + 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(); + // 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 && extra && extra->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. - extra->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; + // 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 && extra && extra->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. + extra->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); - } - } + // 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); + } + } } asITypeInfo *asCScriptObject::GetObjectType() const { - return objType; + return objType; } int asCScriptObject::GetRefCount() { - return refCount.get(); + return refCount.get(); } void asCScriptObject::SetFlag() { - gcFlag = true; + gcFlag = true; } bool asCScriptObject::GetFlag() { - return gcFlag; + return gcFlag; } // interface int asCScriptObject::GetTypeId() const { - asCDataType dt = asCDataType::CreateType(objType, false); - return objType->engine->GetTypeIdFromDataType(dt); + asCDataType dt = asCDataType::CreateType(objType, false); + return objType->engine->GetTypeIdFromDataType(dt); } asUINT asCScriptObject::GetPropertyCount() const { - return asUINT(objType->properties.GetLength()); + return asUINT(objType->properties.GetLength()); } int asCScriptObject::GetPropertyTypeId(asUINT prop) const { - if( prop >= objType->properties.GetLength() ) - return asINVALID_ARG; + if( prop >= objType->properties.GetLength() ) + return asINVALID_ARG; - return objType->engine->GetTypeIdFromDataType(objType->properties[prop]->type); + return objType->engine->GetTypeIdFromDataType(objType->properties[prop]->type); } const char *asCScriptObject::GetPropertyName(asUINT prop) const { - if( prop >= objType->properties.GetLength() ) - return 0; + if( prop >= objType->properties.GetLength() ) + return 0; - return objType->properties[prop]->name.AddressOf(); + return objType->properties[prop]->name.AddressOf(); } void *asCScriptObject::GetAddressOfProperty(asUINT prop) { - if( prop >= objType->properties.GetLength() ) - return 0; + 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->GetTypeInfo()->flags & asOBJ_REF) ) - return *(void**)(((char*)this) + objType->properties[prop]->byteOffset); + // Objects are stored by reference, so this must be dereferenced + asCDataType *dt = &objType->properties[prop]->type; + if( dt->IsObject() && !dt->IsObjectHandle() && + (dt->IsReference() || dt->GetTypeInfo()->flags & asOBJ_REF) ) + return *(void**)(((char*)this) + objType->properties[prop]->byteOffset); - 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]; - void *ptr = 0; - if (prop->type.IsObject()) - { - if (prop->type.IsReference() || (prop->type.GetTypeInfo()->flags & asOBJ_REF)) - ptr = *(void**)(((char*)this) + prop->byteOffset); - else - ptr = (void*)(((char*)this) + prop->byteOffset); - - // The members of the value type needs to be enumerated - // too, since the value type may be holding a reference. - if ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && (prop->type.GetTypeInfo()->flags & asOBJ_GC)) - { - reinterpret_cast(engine)->CallObjectMethod(ptr, engine, CastToObjectType(prop->type.GetTypeInfo())->beh.gcEnumReferences); - } - } - else if (prop->type.IsFuncdef()) - ptr = *(void**)(((char*)this) + prop->byteOffset); - - if (ptr) - ((asCScriptEngine*)engine)->GCEnumCallback(ptr); - } + // 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]; + void *ptr = 0; + if (prop->type.IsObject()) + { + if (prop->type.IsReference() || (prop->type.GetTypeInfo()->flags & asOBJ_REF)) + ptr = *(void**)(((char*)this) + prop->byteOffset); + else + ptr = (void*)(((char*)this) + prop->byteOffset); + + // The members of the value type needs to be enumerated + // too, since the value type may be holding a reference. + if ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && (prop->type.GetTypeInfo()->flags & asOBJ_GC)) + { + reinterpret_cast(engine)->CallObjectMethod(ptr, engine, CastToObjectType(prop->type.GetTypeInfo())->beh.gcEnumReferences); + } + } + else if (prop->type.IsFuncdef()) + 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]; - - if (prop->type.IsObject()) - { - if (prop->type.IsObjectHandle()) - { - void **ptr = (void**)(((char*)this) + prop->byteOffset); - if (*ptr) - { - asASSERT((prop->type.GetTypeInfo()->flags & asOBJ_NOCOUNT) || prop->type.GetBehaviour()->release); - if (prop->type.GetBehaviour()->release) - ((asCScriptEngine*)engine)->CallObjectMethod(*ptr, prop->type.GetBehaviour()->release); - *ptr = 0; - } - } - else if ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && (prop->type.GetTypeInfo()->flags & asOBJ_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. - void *ptr = 0; - if (prop->type.IsReference()) - ptr = *(void**)(((char*)this) + prop->byteOffset); - else - ptr = (void*)(((char*)this) + prop->byteOffset); - - reinterpret_cast(engine)->CallObjectMethod(ptr, engine, CastToObjectType(prop->type.GetTypeInfo())->beh.gcReleaseAllReferences); - } - } - else if (prop->type.IsFuncdef()) - { - asCScriptFunction **ptr = (asCScriptFunction**)(((char*)this) + prop->byteOffset); - if (*ptr) - { - (*ptr)->Release(); - *ptr = 0; - } - } - } + for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) + { + asCObjectProperty *prop = objType->properties[n]; + + if (prop->type.IsObject()) + { + if (prop->type.IsObjectHandle()) + { + void **ptr = (void**)(((char*)this) + prop->byteOffset); + if (*ptr) + { + asASSERT((prop->type.GetTypeInfo()->flags & asOBJ_NOCOUNT) || prop->type.GetBehaviour()->release); + if (prop->type.GetBehaviour()->release) + ((asCScriptEngine*)engine)->CallObjectMethod(*ptr, prop->type.GetBehaviour()->release); + *ptr = 0; + } + } + else if ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && (prop->type.GetTypeInfo()->flags & asOBJ_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. + void *ptr = 0; + if (prop->type.IsReference()) + ptr = *(void**)(((char*)this) + prop->byteOffset); + else + ptr = (void*)(((char*)this) + prop->byteOffset); + + reinterpret_cast(engine)->CallObjectMethod(ptr, engine, CastToObjectType(prop->type.GetTypeInfo())->beh.gcReleaseAllReferences); + } + } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **ptr = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + if (*ptr) + { + (*ptr)->Release(); + *ptr = 0; + } + } + } } asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject *self) { - return (*self = *other); + return (*self = *other); } asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other) { - CopyFromAs(&other, objType); - return *this; + CopyFromAs(&other, objType); + return *this; } // internal int asCScriptObject::CopyFromAs(const asCScriptObject *other, asCObjectType *in_objType) { - if( other != this ) - { - if( !other->objType->DerivesFrom(in_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 asERROR; - } - - // If the script class implements the opAssign method, it should be called - asCScriptEngine *engine = in_objType->engine; - asCScriptFunction *func = engine->scriptFunctions[in_objType->beh.copy]; - if( func->funcType == asFUNC_SYSTEM ) - { - // If derived, use the base class' assignment operator to copy the inherited - // properties. Then only copy new properties for the derived class - if( in_objType->derivedFrom ) - CopyFromAs(other, in_objType->derivedFrom); - - for( asUINT n = in_objType->derivedFrom ? in_objType->derivedFrom->properties.GetLength() : 0; - n < in_objType->properties.GetLength(); - n++ ) - { - asCObjectProperty *prop = in_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.GetTypeInfo()->flags & asOBJ_REF) ) - CopyObject(*src, *dst, CastToObjectType(prop->type.GetTypeInfo()), engine); - else - CopyObject(src, dst, CastToObjectType(prop->type.GetTypeInfo()), engine); - } - else - CopyHandle((asPWORD*)src, (asPWORD*)dst, CastToObjectType(prop->type.GetTypeInfo()), engine); - } - else if (prop->type.IsFuncdef()) - { - asCScriptFunction **dst = (asCScriptFunction**)(((char*)this) + prop->byteOffset); - asCScriptFunction **src = (asCScriptFunction**)(((char*)other) + prop->byteOffset); - if (*dst) - (*dst)->Release(); - *dst = *src; - if (*dst) - (*dst)->AddRef(); - } - else - { - 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 ) - return asERROR; - } - - r = ctx->Prepare(engine->scriptFunctions[in_objType->beh.copy]); - if( r < 0 ) - { - if( isNested ) - ctx->PopState(); - else - engine->ReturnContext(ctx); - return r; - } - - 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 asERROR; - } - - if( isNested ) - ctx->PopState(); - else - { - // Return the context to the engine - engine->ReturnContext(ctx); - } - } - } - - return asSUCCESS; + if( other != this ) + { + if( !other->objType->DerivesFrom(in_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 asERROR; + } + + // If the script class implements the opAssign method, it should be called + asCScriptEngine *engine = in_objType->engine; + asCScriptFunction *func = engine->scriptFunctions[in_objType->beh.copy]; + if( func->funcType == asFUNC_SYSTEM ) + { + // If derived, use the base class' assignment operator to copy the inherited + // properties. Then only copy new properties for the derived class + if( in_objType->derivedFrom ) + CopyFromAs(other, in_objType->derivedFrom); + + for( asUINT n = in_objType->derivedFrom ? in_objType->derivedFrom->properties.GetLength() : 0; + n < in_objType->properties.GetLength(); + n++ ) + { + asCObjectProperty *prop = in_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.GetTypeInfo()->flags & asOBJ_REF) ) + CopyObject(*src, *dst, CastToObjectType(prop->type.GetTypeInfo()), engine); + else + CopyObject(src, dst, CastToObjectType(prop->type.GetTypeInfo()), engine); + } + else + CopyHandle((asPWORD*)src, (asPWORD*)dst, CastToObjectType(prop->type.GetTypeInfo()), engine); + } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **dst = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + asCScriptFunction **src = (asCScriptFunction**)(((char*)other) + prop->byteOffset); + if (*dst) + (*dst)->Release(); + *dst = *src; + if (*dst) + (*dst)->AddRef(); + } + else + { + 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 ) + return asERROR; + } + + r = ctx->Prepare(engine->scriptFunctions[in_objType->beh.copy]); + if( r < 0 ) + { + if( isNested ) + ctx->PopState(); + else + engine->ReturnContext(ctx); + return r; + } + + 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 asERROR; + } + + if( isNested ) + ctx->PopState(); + else + { + // Return the context to the engine + engine->ReturnContext(ctx); + } + } + } + + return asSUCCESS; } int asCScriptObject::CopyFrom(const asIScriptObject *other) { - if( other == 0 ) return asINVALID_ARG; + if( other == 0 ) return asINVALID_ARG; - if( GetTypeId() != other->GetTypeId() ) - return asINVALID_TYPE; + if( GetTypeId() != other->GetTypeId() ) + return asINVALID_TYPE; - *this = *(asCScriptObject*)other; + *this = *(asCScriptObject*)other; - return asSUCCESS; + return asSUCCESS; } void *asCScriptObject::AllocateUninitializedObject(asCObjectType *in_objType, asCScriptEngine *engine) { - void *ptr = 0; - - if( in_objType->flags & asOBJ_SCRIPT_OBJECT ) - { - ptr = engine->CallAlloc(in_objType); - ScriptObject_ConstructUnitialized(in_objType, reinterpret_cast(ptr)); - } - else if( in_objType->flags & asOBJ_TEMPLATE ) - { - // Templates store the original factory that takes the object - // type as a hidden parameter in the construct behaviour - ptr = engine->CallGlobalFunctionRetPtr(in_objType->beh.construct, in_objType); - } - else if( in_objType->flags & asOBJ_REF ) - { - ptr = engine->CallGlobalFunctionRetPtr(in_objType->beh.factory); - } - else - { - ptr = engine->CallAlloc(in_objType); - int funcIndex = in_objType->beh.construct; - if( funcIndex ) - engine->CallObjectMethod(ptr, funcIndex); - } - - return ptr; + void *ptr = 0; + + if( in_objType->flags & asOBJ_SCRIPT_OBJECT ) + { + ptr = engine->CallAlloc(in_objType); + ScriptObject_ConstructUnitialized(in_objType, reinterpret_cast(ptr)); + } + else if( in_objType->flags & asOBJ_TEMPLATE ) + { + // Templates store the original factory that takes the object + // type as a hidden parameter in the construct behaviour + ptr = engine->CallGlobalFunctionRetPtr(in_objType->beh.construct, in_objType); + } + else if( in_objType->flags & asOBJ_REF ) + { + ptr = engine->CallGlobalFunctionRetPtr(in_objType->beh.factory); + } + else + { + ptr = engine->CallAlloc(in_objType); + int funcIndex = in_objType->beh.construct; + if( funcIndex ) + engine->CallObjectMethod(ptr, funcIndex); + } + + return ptr; } void asCScriptObject::FreeObject(void *ptr, asCObjectType *in_objType, asCScriptEngine *engine) { - if( in_objType->flags & asOBJ_REF ) - { - asASSERT( (in_objType->flags & asOBJ_NOCOUNT) || in_objType->beh.release ); - if(in_objType->beh.release ) - engine->CallObjectMethod(ptr, in_objType->beh.release); - } - else - { - if( in_objType->beh.destruct ) - engine->CallObjectMethod(ptr, in_objType->beh.destruct); - - engine->CallFree(ptr); - } + if( in_objType->flags & asOBJ_REF ) + { + asASSERT( (in_objType->flags & asOBJ_NOCOUNT) || in_objType->beh.release ); + if(in_objType->beh.release ) + engine->CallObjectMethod(ptr, in_objType->beh.release); + } + else + { + if( in_objType->beh.destruct ) + engine->CallObjectMethod(ptr, in_objType->beh.destruct); + + engine->CallFree(ptr); + } } void asCScriptObject::CopyObject(const void *src, void *dst, asCObjectType *in_objType, asCScriptEngine *engine) { - int funcIndex = in_objType->beh.copy; - if( funcIndex ) - { - asCScriptFunction *func = engine->scriptFunctions[in_objType->beh.copy]; - if( func->funcType == asFUNC_SYSTEM ) - engine->CallObjectMethod(dst, const_cast(src), funcIndex); - else - { - // Call the script class' opAssign method - asASSERT(in_objType->flags & asOBJ_SCRIPT_OBJECT ); - reinterpret_cast(dst)->CopyFrom(reinterpret_cast(src)); - } - } - else if( in_objType->size && (in_objType->flags & asOBJ_POD) ) - memcpy(dst, src, in_objType->size); + int funcIndex = in_objType->beh.copy; + if( funcIndex ) + { + asCScriptFunction *func = engine->scriptFunctions[in_objType->beh.copy]; + if( func->funcType == asFUNC_SYSTEM ) + engine->CallObjectMethod(dst, const_cast(src), funcIndex); + else + { + // Call the script class' opAssign method + asASSERT(in_objType->flags & asOBJ_SCRIPT_OBJECT ); + reinterpret_cast(dst)->CopyFrom(reinterpret_cast(src)); + } + } + else if( in_objType->size && (in_objType->flags & asOBJ_POD) ) + memcpy(dst, src, in_objType->size); } void asCScriptObject::CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *in_objType, asCScriptEngine *engine) { - // asOBJ_NOCOUNT doesn't have addref or release behaviours - asASSERT( (in_objType->flags & asOBJ_NOCOUNT) || (in_objType->beh.release && in_objType->beh.addref) ); - - if( *dst && in_objType->beh.release ) - engine->CallObjectMethod(*(void**)dst, in_objType->beh.release); - *dst = *src; - if( *dst && in_objType->beh.addref ) - engine->CallObjectMethod(*(void**)dst, in_objType->beh.addref); + // asOBJ_NOCOUNT doesn't have addref or release behaviours + asASSERT( (in_objType->flags & asOBJ_NOCOUNT) || (in_objType->beh.release && in_objType->beh.addref) ); + + if( *dst && in_objType->beh.release ) + engine->CallObjectMethod(*(void**)dst, in_objType->beh.release); + *dst = *src; + if( *dst && in_objType->beh.addref ) + engine->CallObjectMethod(*(void**)dst, in_objType->beh.addref); } // TODO: weak: Should move to its own file -asCLockableSharedBool::asCLockableSharedBool() : value(false) +asCLockableSharedBool::asCLockableSharedBool() : value(false) { - refCount.set(1); + refCount.set(1); } int asCLockableSharedBool::AddRef() const { - return refCount.atomicInc(); + return refCount.atomicInc(); } int asCLockableSharedBool::Release() const { - int r = refCount.atomicDec(); - if( r == 0 ) - asDELETE(const_cast(this), asCLockableSharedBool); - return r; + int r = refCount.atomicDec(); + if( r == 0 ) + asDELETE(const_cast(this), asCLockableSharedBool); + return r; } bool asCLockableSharedBool::Get() const { - return value; + 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(); + // 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); + ENTERCRITICALSECTION(lock); } void asCLockableSharedBool::Unlock() const { - LEAVECRITICALSECTION(lock); + LEAVECRITICALSECTION(lock); } // Interface -// Auxiliary function to allow applications to create shared +// Auxiliary function to allow applications to create shared // booleans without having to implement the logic for them AS_API asILockableSharedBool *asCreateLockableSharedBool() { - return asNEW(asCLockableSharedBool); + return asNEW(asCLockableSharedBool); } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_scriptobject.h b/src/angelscript/source/as_scriptobject.h index 77a435e6236..927318ecdd8 100644 --- a/src/angelscript/source/as_scriptobject.h +++ b/src/angelscript/source/as_scriptobject.h @@ -54,20 +54,20 @@ class asCObjectType; class asCLockableSharedBool : public asILockableSharedBool { public: - asCLockableSharedBool(); - int AddRef() const; - int Release() const; + asCLockableSharedBool(); + int AddRef() const; + int Release() const; - bool Get() const; - void Set(bool); + bool Get() const; + void Set(bool); - void Lock() const; - void Unlock() const; + void Lock() const; + void Unlock() const; protected: - mutable asCAtomic refCount; - bool value; - DECLARECRITICALSECTION(mutable lock) + mutable asCAtomic refCount; + bool value; + DECLARECRITICALSECTION(mutable lock) }; class asCScriptObject : public asIScriptObject @@ -77,77 +77,77 @@ class asCScriptObject : public asIScriptObject // From asIScriptObject //=================================== - // Memory management - int AddRef() const; - int Release() const; - asILockableSharedBool *GetWeakRefFlag() const; + // Memory management + int AddRef() const; + int Release() const; + asILockableSharedBool *GetWeakRefFlag() const; - // Type info - int GetTypeId() const; - asITypeInfo *GetObjectType() const; + // Type info + int GetTypeId() const; + asITypeInfo *GetObjectType() const; - // Class properties - asUINT GetPropertyCount() const; - int GetPropertyTypeId(asUINT prop) const; - const char *GetPropertyName(asUINT prop) const; - void *GetAddressOfProperty(asUINT prop); + // Class properties + asUINT GetPropertyCount() const; + int GetPropertyTypeId(asUINT prop) const; + const char *GetPropertyName(asUINT prop) const; + void *GetAddressOfProperty(asUINT prop); - // Miscellaneous - asIScriptEngine *GetEngine() const; - int CopyFrom(const asIScriptObject *other); + // Miscellaneous + asIScriptEngine *GetEngine() const; + int CopyFrom(const asIScriptObject *other); - // User data - void *SetUserData(void *data, asPWORD type = 0); - void *GetUserData(asPWORD type = 0) const; + // User data + void *SetUserData(void *data, asPWORD type = 0); + void *GetUserData(asPWORD type = 0) const; //==================================== // Internal //==================================== - asCScriptObject(asCObjectType *objType, bool doInitialize = true); - virtual ~asCScriptObject(); + asCScriptObject(asCObjectType *objType, bool doInitialize = true); + virtual ~asCScriptObject(); - asCScriptObject &operator=(const asCScriptObject &other); + asCScriptObject &operator=(const asCScriptObject &other); - // GC methods - void Destruct(); - int GetRefCount(); - void SetFlag(); - bool GetFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllHandles(asIScriptEngine *engine); + // GC methods + void Destruct(); + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); - // Used for properties - void *AllocateUninitializedObject(asCObjectType *objType, asCScriptEngine *engine); - void FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine); - void CopyObject(const void *src, void *dst, asCObjectType *objType, asCScriptEngine *engine); - void CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine); - int CopyFromAs(const asCScriptObject *other, asCObjectType *objType); + // Used for properties + void *AllocateUninitializedObject(asCObjectType *objType, asCScriptEngine *engine); + void FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine); + void CopyObject(const void *src, void *dst, asCObjectType *objType, asCScriptEngine *engine); + void CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine); + int CopyFromAs(const asCScriptObject *other, asCObjectType *objType); - void CallDestructor(); + void CallDestructor(); //============================================= // Properties //============================================= protected: - friend class asCContext; - asCObjectType *objType; - - mutable asCAtomic refCount; - mutable asBYTE gcFlag:1; - mutable asBYTE hasRefCountReachedZero:1; - bool isDestructCalled; - - // Most script classes instances won't have neither the weakRefFlags nor - // userData so we only allocate this if requested. Even when used it is - // not something that will be accessed all the time so having the extra - // indirection will not affect the performance significantly. - struct SExtra - { - SExtra() : weakRefFlag(0) {}; - asCLockableSharedBool *weakRefFlag; - asCArray userData; - }; - mutable SExtra *extra; + friend class asCContext; + asCObjectType *objType; + + mutable asCAtomic refCount; + mutable asBYTE gcFlag:1; + mutable asBYTE hasRefCountReachedZero:1; + bool isDestructCalled; + + // Most script classes instances won't have neither the weakRefFlags nor + // userData so we only allocate this if requested. Even when used it is + // not something that will be accessed all the time so having the extra + // indirection will not affect the performance significantly. + struct SExtra + { + SExtra() : weakRefFlag(0) {}; + asCLockableSharedBool *weakRefFlag; + asCArray userData; + }; + mutable SExtra *extra; }; void ScriptObject_Construct(asCObjectType *objType, asCScriptObject *self); diff --git a/src/angelscript/source/as_string.cpp b/src/angelscript/source/as_string.cpp index 8bd3edfe393..dcbc4450725 100644 --- a/src/angelscript/source/as_string.cpp +++ b/src/angelscript/source/as_string.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -30,9 +30,9 @@ #include "as_config.h" -#include // va_list, va_start(), etc -#include // strtod(), strtol() -#include // some compilers declare memcpy() here +#include // va_list, va_start(), etc +#include // strtod(), strtol() +#include // some compilers declare memcpy() here #if !defined(AS_NO_MEMORY_H) #include @@ -43,348 +43,348 @@ asCString::asCString() { - length = 0; - local[0] = 0; + length = 0; + local[0] = 0; } // Copy constructor asCString::asCString(const asCString &str) { - length = 0; - local[0] = 0; + length = 0; + local[0] = 0; - Assign(str.AddressOf(), str.length); + 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; + 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; + length = 0; + local[0] = 0; - Assign(str, len); + Assign(str, len); } asCString::asCString(const char *str) { - length = 0; - local[0] = 0; + length = 0; + local[0] = 0; - size_t len = strlen(str); - Assign(str, len); + size_t len = strlen(str); + Assign(str, len); } asCString::asCString(char ch) { - length = 0; - local[0] = 0; + length = 0; + local[0] = 0; - Assign(&ch, 1); + Assign(&ch, 1); } asCString::~asCString() { - if( length > 11 && dynamic ) - { - asDELETEARRAY(dynamic); - } + if( length > 11 && dynamic ) + { + asDELETEARRAY(dynamic); + } } char *asCString::AddressOf() { - if( length <= 11 ) - return local; - else - return dynamic; + if( length <= 11 ) + return local; + else + return dynamic; } const char *asCString::AddressOf() const { - if( length <= 11 ) - return local; - else - return dynamic; + if( length <= 11 ) + return local; + else + return dynamic; } void asCString::SetLength(size_t len) { - Allocate(len, true); + 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; + // 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); + Allocate(len, false); - // Copy the string - memcpy(AddressOf(), str, length); - AddressOf()[length] = 0; + // 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); + size_t len = str ? strlen(str) : 0; + Assign(str, len); - return *this; + return *this; } asCString &asCString::operator =(const asCString &str) { - Assign(str.AddressOf(), str.length); + Assign(str.AddressOf(), str.length); - return *this; + return *this; } #ifdef AS_CAN_USE_CPP11 asCString &asCString::operator =(asCString &&str) { - if( this != &str ) - { - if( length > 11 && dynamic ) - { - asDELETEARRAY(dynamic); - } + if( this != &str ) + { + if( length > 11 && dynamic ) + { + asDELETEARRAY(dynamic); + } - if ( str.length <= 11 ) - { - length = str.length; + if ( str.length <= 11 ) + { + length = str.length; - memcpy(local, str.local, length); - local[length] = 0; - } - else - { - dynamic = str.dynamic; - length = str.length; - } + memcpy(local, str.local, length); + local[length] = 0; + } + else + { + dynamic = str.dynamic; + length = str.length; + } - str.dynamic = 0; - str.length = 0; - } + str.dynamic = 0; + str.length = 0; + } - return *this; + return *this; } #endif // c++11 asCString &asCString::operator =(char ch) { - Assign(&ch, 1); + Assign(&ch, 1); - return *this; + return *this; } void asCString::Concatenate(const char *str, size_t len) { - asUINT oldLength = length; - SetLength(length + len); + asUINT oldLength = length; + SetLength(length + len); - memcpy(AddressOf() + oldLength, str, len); - AddressOf()[length] = 0; + memcpy(AddressOf() + oldLength, str, len); + AddressOf()[length] = 0; } asCString &asCString::operator +=(const char *str) { - size_t len = strlen(str); - Concatenate(str, len); + size_t len = strlen(str); + Concatenate(str, len); - return *this; + return *this; } asCString &asCString::operator +=(const asCString &str) { - Concatenate(str.AddressOf(), str.length); + Concatenate(str.AddressOf(), str.length); - return *this; + return *this; } asCString &asCString::operator +=(char ch) { - Concatenate(&ch, 1); + Concatenate(&ch, 1); - return *this; + return *this; } size_t asCString::GetLength() const { - return length; + return length; } // Returns the length size_t asCString::Format(const char *format, ...) { - va_list args; - va_start(args, format); + va_list args; + va_start(args, format); - const size_t startSize = 1024; - char tmp[startSize]; - int r = asVSNPRINTF(tmp, startSize-1, format, args); + const size_t startSize = 1024; + char tmp[startSize]; + int r = asVSNPRINTF(tmp, startSize-1, format, args); - if( r > 0 && r < int(startSize) ) - { - Assign(tmp, r); - } - else - { - // TODO: For some reason this doesn't work properly on Linux. Perhaps the - // problem is related to vsnprintf not keeping the state of va_arg. - // Perhaps I need to rewrite this in some way to keep the state - size_t n = startSize*2; - asCString str; // Use temporary string in case the current buffer is a parameter - str.Allocate(n, false); + if( r > 0 && r < int(startSize) ) + { + Assign(tmp, r); + } + else + { + // TODO: For some reason this doesn't work properly on Linux. Perhaps the + // problem is related to vsnprintf not keeping the state of va_arg. + // Perhaps I need to rewrite this in some way to keep the state + size_t n = startSize*2; + asCString str; // Use temporary string in case the current buffer is a parameter + str.Allocate(n, false); - while( (r = asVSNPRINTF(str.AddressOf(), n, format, args)) < 0 || r >= int(n) ) - { - n *= 2; - str.Allocate(n, false); - } + while( (r = asVSNPRINTF(str.AddressOf(), n, format, args)) < 0 || r >= int(n) ) + { + n *= 2; + str.Allocate(n, false); + } - Assign(str.AddressOf(), r); - } + Assign(str.AddressOf(), r); + } - va_end(args); + va_end(args); - return length; + return length; } -char &asCString::operator [](size_t index) +char &asCString::operator [](size_t index) { - asASSERT(index < length); + asASSERT(index < length); - return AddressOf()[index]; + return AddressOf()[index]; } const char &asCString::operator [](size_t index) const { - asASSERT(index < length); + asASSERT(index < length); - return AddressOf()[index]; + return AddressOf()[index]; } asCString asCString::SubString(size_t in_start, size_t in_length) const { - if( in_start >= GetLength() || in_length == 0 ) - return asCString(""); + if( in_start >= GetLength() || in_length == 0 ) + return asCString(""); - if( in_length == (size_t)(-1) ) in_length = GetLength() - in_start; + if( in_length == (size_t)(-1) ) in_length = GetLength() - in_start; - asCString tmp; - tmp.Assign(AddressOf() + in_start, in_length); + asCString tmp; + tmp.Assign(AddressOf() + in_start, in_length); - return tmp; + return tmp; } int asCString::Compare(const char *str) const { - return asCompareStrings(AddressOf(), length, str, strlen(str)); + return asCompareStrings(AddressOf(), length, str, strlen(str)); } int asCString::Compare(const asCString &str) const { - return asCompareStrings(AddressOf(), length, str.AddressOf(), str.GetLength()); + return asCompareStrings(AddressOf(), length, str.AddressOf(), str.GetLength()); } int asCString::Compare(const char *str, size_t len) const { - return asCompareStrings(AddressOf(), length, str, len); + return asCompareStrings(AddressOf(), length, str, len); } size_t asCString::RecalculateLength() { - SetLength(strlen(AddressOf())); + SetLength(strlen(AddressOf())); - return length; + 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. + // 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; + 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; - } + 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()); + if( last ) + return int(last - AddressOf()); - return -1; + return -1; } //----------------------------------------------------------------------------- @@ -392,96 +392,96 @@ int asCString::FindLast(const char *str, int *count) const bool operator ==(const asCString &a, const char *b) { - return a.Compare(b) == 0; + return a.Compare(b) == 0; } bool operator !=(const asCString &a, const char *b) { - return a.Compare(b) != 0; + return a.Compare(b) != 0; } bool operator ==(const asCString &a, const asCString &b) { - return a.Compare(b) == 0; + return a.Compare(b) == 0; } bool operator !=(const asCString &a, const asCString &b) { - return a.Compare(b) != 0; + return a.Compare(b) != 0; } bool operator ==(const char *a, const asCString &b) { - return b.Compare(a) == 0; + return b.Compare(a) == 0; } bool operator !=(const char *a, const asCString &b) { - return b.Compare(a) != 0; + return b.Compare(a) != 0; } bool operator <(const asCString &a, const asCString &b) { - return a.Compare(b) < 0; + return a.Compare(b) < 0; } asCString operator +(const asCString &a, const asCString &b) { - asCString res = a; - res += b; + asCString res = a; + res += b; - return res; + return res; } asCString operator +(const char *a, const asCString &b) { - asCString res = a; - res += b; + asCString res = a; + res += b; - return res; + return res; } asCString operator +(const asCString &a, const char *b) { - asCString res = a; - res += b; + asCString res = a; + res += b; - return res; + return res; } // wrapper class asCStringPointer::asCStringPointer() - : string(0), length(0), cstring(0) + : string(0), length(0), cstring(0) { } asCStringPointer::asCStringPointer(const char *str, size_t len) - : string(str), length(len), cstring(0) + : string(str), length(len), cstring(0) { } asCStringPointer::asCStringPointer(asCString *cstr) - : string(0), length(0), cstring(cstr) + : string(0), length(0), cstring(cstr) { } const char *asCStringPointer::AddressOf() const { - return string ? string : cstring->AddressOf(); + return string ? string : cstring->AddressOf(); } size_t asCStringPointer::GetLength() const { - return string ? length : cstring->GetLength(); + return string ? length : cstring->GetLength(); } bool asCStringPointer::operator==(const asCStringPointer& other) const { - return asCompareStrings(AddressOf(), GetLength(), other.AddressOf(), other.GetLength()) == 0; + 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; + return asCompareStrings(AddressOf(), GetLength(), other.AddressOf(), other.GetLength()) < 0; } diff --git a/src/angelscript/source/as_string.h b/src/angelscript/source/as_string.h index 0ee7469c0b2..02bd140ca28 100644 --- a/src/angelscript/source/as_string.h +++ b/src/angelscript/source/as_string.h @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -41,56 +41,56 @@ class asCString { public: - asCString(); - ~asCString(); + asCString(); + ~asCString(); #ifdef AS_CAN_USE_CPP11 - asCString(asCString &&); - asCString &operator =(asCString &&); + asCString(asCString &&); + asCString &operator =(asCString &&); #endif // c++11 - asCString(const asCString &); - asCString(const char *); - asCString(const char *, size_t length); - explicit asCString(char); + 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 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 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); + 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; + asCString SubString(size_t start, size_t length = (size_t)(-1)) const; - int FindLast(const char *str, int *count = 0) const; + int FindLast(const char *str, int *count = 0) const; - size_t Format(const char *fmt, ...); + 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; + 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(); + 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]; - }; + unsigned int length; + union + { + char *dynamic; + char local[12]; + }; }; // Helper functions @@ -114,21 +114,21 @@ asCString operator +(const asCString &, const asCString &); class asCStringPointer { public: - asCStringPointer(); - asCStringPointer(const char *str, size_t len); - asCStringPointer(asCString *cstr); + asCStringPointer(); + asCStringPointer(const char *str, size_t len); + asCStringPointer(asCString *cstr); - const char *AddressOf() const; - size_t GetLength() const; + const char *AddressOf() const; + size_t GetLength() const; - bool operator==(const asCStringPointer& other) const; - bool operator<(const asCStringPointer& other) 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; + // Either string/length or cstring is stored + const char *string; + size_t length; + asCString *cstring; }; #endif diff --git a/src/angelscript/source/as_string_util.cpp b/src/angelscript/source/as_string_util.cpp index 32edbedb006..93fd79d8d3d 100644 --- a/src/angelscript/source/as_string_util.cpp +++ b/src/angelscript/source/as_string_util.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2017 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -45,233 +45,233 @@ 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 + if( len1 == 0 ) + { + if( str2 == 0 || len2 == 0 ) return 0; // Equal - return 1; // The other string is larger than this - } + return 1; // The other string is larger than this + } - if( str2 == 0 ) - { - if( len1 == 0 ) - return 0; // Equal + if( str2 == 0 ) + { + if( len1 == 0 ) + return 0; // Equal - return -1; // The other string is smaller than this - } + 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 + if( len2 < len1 ) + { + int result = memcmp(str1, str2, len2); + if( result == 0 ) return -1; // The other string is smaller than this - return result; - } + return result; + } - int result = memcmp(str1, str2, len1); - if( result == 0 && len1 < len2 ) return 1; // The other string is larger than this + int result = memcmp(str1, str2, len1); + if( result == 0 && len1 < len2 ) return 1; // The other string is larger than this - return result; + 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; + // 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( 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, bool *overflow) { - asASSERT(base == 10 || base == 16 || base == 0); - - if (overflow) - *overflow = false; - - const char *end = string; - - static const asQWORD QWORD_MAX = (~asQWORD(0)); - - asQWORD res = 0; - if( base == 10 ) - { - while( *end >= '0' && *end <= '9' ) - { - if( overflow && ((res > QWORD_MAX / 10) || ((asUINT(*end - '0') > (QWORD_MAX - (QWORD_MAX / 10) * 10)) && res == QWORD_MAX / 10)) ) - *overflow = true; - res *= 10; - res += *end++ - '0'; - } - } - 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++) - { - if (overflow && ((res > QWORD_MAX / base) || ((asUINT(nbr) > (QWORD_MAX - (QWORD_MAX / base) * base)) && res == QWORD_MAX / base)) ) - *overflow = true; - - res = res * base + nbr; - } - } - } - - if( numScanned ) - *numScanned = end - string; - - return res; + asASSERT(base == 10 || base == 16 || base == 0); + + if (overflow) + *overflow = false; + + const char *end = string; + + static const asQWORD QWORD_MAX = (~asQWORD(0)); + + asQWORD res = 0; + if( base == 10 ) + { + while( *end >= '0' && *end <= '9' ) + { + if( overflow && ((res > QWORD_MAX / 10) || ((asUINT(*end - '0') > (QWORD_MAX - (QWORD_MAX / 10) * 10)) && res == QWORD_MAX / 10)) ) + *overflow = true; + res *= 10; + res += *end++ - '0'; + } + } + 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++) + { + if (overflow && ((res > QWORD_MAX / base) || ((asUINT(nbr) > (QWORD_MAX - (QWORD_MAX / base) * base)) && res == QWORD_MAX / base)) ) + *overflow = true; + + 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 +// 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; + 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; } // @@ -282,101 +282,101 @@ int asStringEncodeUTF8(unsigned int value, char *outEncodedBuffer) // 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; + 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 +// 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 ) - { + if( value < 0x10000 ) + { #ifndef AS_BIG_ENDIAN - outEncodedBuffer[0] = (value & 0xFF); - outEncodedBuffer[1] = ((value >> 8) & 0xFF); + outEncodedBuffer[0] = (value & 0xFF); + outEncodedBuffer[1] = ((value >> 8) & 0xFF); #else - outEncodedBuffer[1] = (value & 0xFF); - outEncodedBuffer[0] = ((value >> 8) & 0xFF); + 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; + 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); + 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); + outEncodedBuffer[1] = (surrogate1 & 0xFF); + outEncodedBuffer[0] = ((surrogate1 >> 8) & 0xFF); + outEncodedBuffer[3] = (surrogate2 & 0xFF); + outEncodedBuffer[2] = ((surrogate2 >> 8) & 0xFF); #endif - return 4; - } + return 4; + } } diff --git a/src/angelscript/source/as_string_util.h b/src/angelscript/source/as_string_util.h index 29174dfb844..019d2aceb42 100644 --- a/src/angelscript/source/as_string_util.h +++ b/src/angelscript/source/as_string_util.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2016 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: diff --git a/src/angelscript/source/as_symboltable.h b/src/angelscript/source/as_symboltable.h index 11a7115c0f9..2eecb937d00 100644 --- a/src/angelscript/source/as_symboltable.h +++ b/src/angelscript/source/as_symboltable.h @@ -58,8 +58,8 @@ 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() {}; + virtual bool operator()(const void*) const = 0; + virtual ~asIFilter() {}; }; @@ -77,22 +77,22 @@ 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; } + 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); + friend class asCSymbolTable; + asCSymbolTableIterator(asCSymbolTable *table); - void Next(); - void Previous(); + void Next(); + void Previous(); - asCSymbolTable* m_table; - unsigned int m_idx; + asCSymbolTable* m_table; + unsigned int m_idx; }; @@ -105,53 +105,53 @@ template class asCSymbolTable { public: - typedef asCSymbolTableIterator iterator; - typedef asCSymbolTableIterator const_iterator; + typedef asCSymbolTableIterator iterator; + typedef asCSymbolTableIterator const_iterator; - asCSymbolTable(asUINT initialCapacity = 0); + asCSymbolTable(asUINT 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 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; + 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(asUINT index); - const T* Get(asUINT index) const; - T* GetLast(); - const T* GetLast() 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(asUINT index); + const T* Get(asUINT index) const; + T* GetLast(); + const T* GetLast() const; - const asCArray &GetIndexes(const asSNameSpace *ns, const asCString &name) const; + const asCArray &GetIndexes(const asSNameSpace *ns, const asCString &name) const; - asUINT Put(T* entry); + asUINT Put(T* entry); - asUINT GetSize() const; + asUINT GetSize() const; - void SwapWith(asCSymbolTable &other); + void SwapWith(asCSymbolTable &other); - void Clear(); - bool Erase(asUINT idx); - void Allocate(asUINT elem_cnt, bool keep_data); + void Clear(); + bool Erase(asUINT idx); + void Allocate(asUINT elem_cnt, bool keep_data); - iterator List(); - const_iterator List() const; + iterator List(); + const_iterator List() const; private: - // Don't allow assignment - asCSymbolTable& operator=(const asCSymbolTable &other) { return *this; } + // Don't allow assignment + asCSymbolTable& operator=(const asCSymbolTable &other) { return *this; } - friend class asCSymbolTableIterator; - friend class asCSymbolTableIterator; + friend class asCSymbolTableIterator; + friend class asCSymbolTableIterator; - void GetKey(const T *entry, asSNameSpaceNamePair &key) const; - bool CheckIdx(asUINT idx) const; + void GetKey(const T *entry, asSNameSpaceNamePair &key) const; + bool CheckIdx(asUINT idx) const; - asCMap > m_map; - asCArray m_entries; - unsigned int m_size; + asCMap > m_map; + asCArray m_entries; + unsigned int m_size; }; @@ -160,12 +160,12 @@ class asCSymbolTable template void asCSymbolTable::SwapWith(asCSymbolTable &other) { - m_map.SwapWith(other.m_map); - m_entries.SwapWith(other.m_entries); + m_map.SwapWith(other.m_map); + m_entries.SwapWith(other.m_entries); - asUINT tmp = m_size; - m_size = other.m_size; - other.m_size = tmp; + asUINT tmp = m_size; + m_size = other.m_size; + other.m_size = tmp; } @@ -176,7 +176,7 @@ void asCSymbolTable::SwapWith(asCSymbolTable &other) template asCSymbolTable::asCSymbolTable(asUINT initialCapacity) : m_entries(initialCapacity) { - m_size = 0; + m_size = 0; } @@ -187,21 +187,21 @@ int asCSymbolTable::GetFirstIndex( 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( asUINT n = 0; n < arr.GetLength(); n++ ) - { - T *entry = m_entries[arr[n]]; - if( entry && filter(entry) ) - return arr[n]; - } - } - - return -1; + asSNameSpaceNamePair key(ns, name); + + asSMapNode > *cursor; + if( m_map.MoveTo(&cursor, key) ) + { + const asCArray &arr = m_map.GetValue(cursor); + for( asUINT n = 0; n < arr.GetLength(); n++ ) + { + T *entry = m_entries[arr[n]]; + if( entry && filter(entry) ) + return arr[n]; + } + } + + return -1; } @@ -209,14 +209,14 @@ int asCSymbolTable::GetFirstIndex( template const asCArray &asCSymbolTable::GetIndexes(const asSNameSpace *ns, const asCString &name) const { - asSNameSpaceNamePair key(ns, name); + asSNameSpaceNamePair key(ns, name); - asSMapNode > *cursor; - if( m_map.MoveTo(&cursor, key) ) - return m_map.GetValue(cursor); + asSMapNode > *cursor; + if( m_map.MoveTo(&cursor, key) ) + return m_map.GetValue(cursor); - static asCArray dummy; - return dummy; + static asCArray dummy; + return dummy; } @@ -225,9 +225,9 @@ const asCArray &asCSymbolTable::GetIndexes(const asSNameSpace *ns, co 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; + int idx = GetFirstIndex(ns, name, comp); + if (idx != -1) return m_entries[idx]; + return 0; } @@ -236,13 +236,13 @@ T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &name, co template int asCSymbolTable::GetFirstIndex(const asSNameSpace *ns, const asCString &name) const { - asSNameSpaceNamePair key(ns, name); + asSNameSpaceNamePair key(ns, name); - asSMapNode > *cursor; - if( m_map.MoveTo(&cursor, key) ) - return m_map.GetValue(cursor)[0]; + asSMapNode > *cursor; + if( m_map.MoveTo(&cursor, key) ) + return m_map.GetValue(cursor)[0]; - return -1; + return -1; } @@ -253,11 +253,11 @@ int asCSymbolTable::GetFirstIndex(const asSNameSpace *ns, const asCString &na template int asCSymbolTable::GetIndex(const T* entry) const { - for( asUINT n = 0; n < m_entries.GetLength(); n++ ) - if( m_entries[n] == entry ) - return n; + for( asUINT n = 0; n < m_entries.GetLength(); n++ ) + if( m_entries[n] == entry ) + return n; - return -1; + return -1; } @@ -268,16 +268,16 @@ int asCSymbolTable::GetIndex(const T* entry) const template T* asCSymbolTable::Get(asUINT idx) { - if( !CheckIdx(idx) ) - return 0; + if( !CheckIdx(idx) ) + return 0; - return m_entries[idx]; + return m_entries[idx]; } template const T* asCSymbolTable::Get(asUINT idx) const { - return const_cast< asCSymbolTable* >(this)->Get(idx); + return const_cast< asCSymbolTable* >(this)->Get(idx); } @@ -287,14 +287,14 @@ const T* asCSymbolTable::Get(asUINT idx) const template T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &name) { - int idx = GetFirstIndex(ns, name); - return Get(idx); + 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); + return const_cast< asCSymbolTable* >(this)->GetFirst(ns, name); } @@ -304,13 +304,13 @@ const T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &na template T* asCSymbolTable::GetLast() { - return Get(GetLastIndex()); + return Get(GetLastIndex()); } template const T* asCSymbolTable::GetLast() const { - return const_cast< asCSymbolTable* >(this)->GetLast(); + return const_cast< asCSymbolTable* >(this)->GetLast(); } @@ -322,9 +322,9 @@ const T* asCSymbolTable::GetLast() const template void asCSymbolTable::Clear() { - m_entries.SetLength(0); - m_map.EraseAll(); - m_size = 0; + m_entries.SetLength(0); + m_map.EraseAll(); + m_size = 0; } @@ -334,10 +334,10 @@ void asCSymbolTable::Clear() template void asCSymbolTable::Allocate(asUINT elemCnt, bool keepData) { - asASSERT( elemCnt >= m_entries.GetLength() ); - m_entries.Allocate(elemCnt, keepData); - if( !keepData ) - m_map.EraseAll(); + asASSERT( elemCnt >= m_entries.GetLength() ); + m_entries.Allocate(elemCnt, keepData); + if( !keepData ) + m_map.EraseAll(); } @@ -345,55 +345,55 @@ void asCSymbolTable::Allocate(asUINT elemCnt, bool keepData) template bool asCSymbolTable::Erase(asUINT 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; + 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; } @@ -402,23 +402,23 @@ bool asCSymbolTable::Erase(asUINT idx) template asUINT asCSymbolTable::Put(T *entry) { - asUINT idx = 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; + asUINT idx = 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; } @@ -428,7 +428,7 @@ asUINT asCSymbolTable::Put(T *entry) template void asCSymbolTable::GetKey(const T *entry, asSNameSpaceNamePair &key) const { - key = asSNameSpaceNamePair(entry->nameSpace, entry->name); + key = asSNameSpaceNamePair(entry->nameSpace, entry->name); } @@ -437,7 +437,7 @@ void asCSymbolTable::GetKey(const T *entry, asSNameSpaceNamePair &key) const template asUINT asCSymbolTable::GetSize() const { - return m_size; + return m_size; } @@ -446,7 +446,7 @@ asUINT asCSymbolTable::GetSize() const template bool asCSymbolTable::CheckIdx(asUINT idx) const { - return idx < m_entries.GetLength(); + return idx < m_entries.GetLength(); } @@ -455,9 +455,9 @@ bool asCSymbolTable::CheckIdx(asUINT idx) const template int asCSymbolTable::GetLastIndex() const { - int idx = int(m_entries.GetLength()) - 1; - asASSERT( idx == -1 || m_entries[idx] ); - return idx; + int idx = int(m_entries.GetLength()) - 1; + asASSERT( idx == -1 || m_entries[idx] ); + return idx; } @@ -466,7 +466,7 @@ int asCSymbolTable::GetLastIndex() const template asCSymbolTableIterator asCSymbolTable::List() { - return asCSymbolTableIterator(this); + return asCSymbolTableIterator(this); } @@ -475,7 +475,7 @@ asCSymbolTableIterator asCSymbolTable::List() template typename asCSymbolTable::const_iterator asCSymbolTable::List() const { - return asCSymbolTableIterator(const_cast< asCSymbolTable *>(this)); + return asCSymbolTableIterator(const_cast< asCSymbolTable *>(this)); } @@ -486,9 +486,9 @@ typename asCSymbolTable::const_iterator asCSymbolTable::List() const template asCSymbolTableIterator::asCSymbolTableIterator(asCSymbolTable *table) : m_table(table), m_idx(0) { - asUINT sz = m_table->m_entries.GetLength(); - while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) - m_idx++; + asUINT sz = m_table->m_entries.GetLength(); + while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) + m_idx++; } @@ -496,8 +496,8 @@ asCSymbolTableIterator::asCSymbolTableIterator(asCSymbolTable *table) template T2* asCSymbolTableIterator::operator*() const { - asASSERT(m_table->CheckIdx(m_idx)); - return m_table->m_entries[m_idx]; + asASSERT(m_table->CheckIdx(m_idx)); + return m_table->m_entries[m_idx]; } @@ -505,8 +505,8 @@ T2* asCSymbolTableIterator::operator*() const template T2* asCSymbolTableIterator::operator->() const { - asASSERT(m_table->CheckIdx(m_idx)); - return m_table->m_entries[m_idx]; + asASSERT(m_table->CheckIdx(m_idx)); + return m_table->m_entries[m_idx]; } @@ -514,8 +514,8 @@ T2* asCSymbolTableIterator::operator->() const template asCSymbolTableIterator& asCSymbolTableIterator::operator++(int) { - Next(); - return *this; + Next(); + return *this; } @@ -526,7 +526,7 @@ asCSymbolTableIterator& asCSymbolTableIterator::operator++(int) template asCSymbolTableIterator::operator bool() const { - return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0; + return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0; } @@ -534,10 +534,10 @@ asCSymbolTableIterator::operator bool() const template void asCSymbolTableIterator::Next() { - asUINT sz = m_table->m_entries.GetLength(); - m_idx++; - while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) - m_idx++; + asUINT sz = m_table->m_entries.GetLength(); + m_idx++; + while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) + m_idx++; } @@ -545,11 +545,11 @@ void asCSymbolTableIterator::Next() template void asCSymbolTableIterator::Previous() { - // overflow on stepping over first element - asUINT sz = m_table->m_entries.GetLength(); - m_idx--; - while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) - m_idx--; + // overflow on stepping over first element + asUINT sz = m_table->m_entries.GetLength(); + m_idx--; + while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) + m_idx--; } @@ -557,8 +557,8 @@ void asCSymbolTableIterator::Previous() template asCSymbolTableIterator& asCSymbolTableIterator::operator--(int) { - Previous(); - return *this; + Previous(); + return *this; } diff --git a/src/angelscript/source/as_texts.h b/src/angelscript/source/as_texts.h index 8a7acc7a441..4662acedbaa 100644 --- a/src/angelscript/source/as_texts.h +++ b/src/angelscript/source/as_texts.h @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2019 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -368,35 +368,35 @@ #define ERROR_NAME(x) #x static const char*const errorNames[] = { - ERROR_NAME(asSUCCESS), - ERROR_NAME(asERROR), - ERROR_NAME(asCONTEXT_ACTIVE), - ERROR_NAME(asCONTEXT_NOT_FINISHED), - ERROR_NAME(asCONTEXT_NOT_PREPARED), - ERROR_NAME(asINVALID_ARG), - ERROR_NAME(asNO_FUNCTION), - ERROR_NAME(asNOT_SUPPORTED), - ERROR_NAME(asINVALID_NAME), - ERROR_NAME(asNAME_TAKEN), - ERROR_NAME(asINVALID_DECLARATION), - ERROR_NAME(asINVALID_OBJECT), - ERROR_NAME(asINVALID_TYPE), - ERROR_NAME(asALREADY_REGISTERED), - ERROR_NAME(asMULTIPLE_FUNCTIONS), - ERROR_NAME(asNO_MODULE), - ERROR_NAME(asNO_GLOBAL_VAR), - ERROR_NAME(asINVALID_CONFIGURATION), - ERROR_NAME(asINVALID_INTERFACE), - ERROR_NAME(asCANT_BIND_ALL_FUNCTIONS), - ERROR_NAME(asLOWER_ARRAY_DIMENSION_NOT_REGISTERED), - ERROR_NAME(asWRONG_CONFIG_GROUP), - ERROR_NAME(asCONFIG_GROUP_IS_IN_USE), - ERROR_NAME(asILLEGAL_BEHAVIOUR_FOR_TYPE), - ERROR_NAME(asWRONG_CALLING_CONV), - ERROR_NAME(asBUILD_IN_PROGRESS), - ERROR_NAME(asINIT_GLOBAL_VARS_FAILED), - ERROR_NAME(asOUT_OF_MEMORY), - ERROR_NAME(asMODULE_IS_IN_USE) + ERROR_NAME(asSUCCESS), + ERROR_NAME(asERROR), + ERROR_NAME(asCONTEXT_ACTIVE), + ERROR_NAME(asCONTEXT_NOT_FINISHED), + ERROR_NAME(asCONTEXT_NOT_PREPARED), + ERROR_NAME(asINVALID_ARG), + ERROR_NAME(asNO_FUNCTION), + ERROR_NAME(asNOT_SUPPORTED), + ERROR_NAME(asINVALID_NAME), + ERROR_NAME(asNAME_TAKEN), + ERROR_NAME(asINVALID_DECLARATION), + ERROR_NAME(asINVALID_OBJECT), + ERROR_NAME(asINVALID_TYPE), + ERROR_NAME(asALREADY_REGISTERED), + ERROR_NAME(asMULTIPLE_FUNCTIONS), + ERROR_NAME(asNO_MODULE), + ERROR_NAME(asNO_GLOBAL_VAR), + ERROR_NAME(asINVALID_CONFIGURATION), + ERROR_NAME(asINVALID_INTERFACE), + ERROR_NAME(asCANT_BIND_ALL_FUNCTIONS), + ERROR_NAME(asLOWER_ARRAY_DIMENSION_NOT_REGISTERED), + ERROR_NAME(asWRONG_CONFIG_GROUP), + ERROR_NAME(asCONFIG_GROUP_IS_IN_USE), + ERROR_NAME(asILLEGAL_BEHAVIOUR_FOR_TYPE), + ERROR_NAME(asWRONG_CALLING_CONV), + ERROR_NAME(asBUILD_IN_PROGRESS), + ERROR_NAME(asINIT_GLOBAL_VARS_FAILED), + ERROR_NAME(asOUT_OF_MEMORY), + ERROR_NAME(asMODULE_IS_IN_USE) }; #endif diff --git a/src/angelscript/source/as_thread.cpp b/src/angelscript/source/as_thread.cpp index 63ab15e1df2..a148517bf41 100644 --- a/src/angelscript/source/as_thread.cpp +++ b/src/angelscript/source/as_thread.cpp @@ -55,54 +55,54 @@ extern "C" AS_API int asThreadCleanup() { - return asCThreadManager::CleanupLocalData(); + return asCThreadManager::CleanupLocalData(); } AS_API asIThreadManager *asGetThreadManager() { - return threadManager; + return threadManager; } AS_API int asPrepareMultithread(asIThreadManager *externalThreadMgr) { - return asCThreadManager::Prepare(externalThreadMgr); + return asCThreadManager::Prepare(externalThreadMgr); } AS_API void asUnprepareMultithread() { - asCThreadManager::Unprepare(); + asCThreadManager::Unprepare(); } AS_API void asAcquireExclusiveLock() { - if( threadManager ) - { - ACQUIREEXCLUSIVE(threadManager->appRWLock); - } + if( threadManager ) + { + ACQUIREEXCLUSIVE(threadManager->appRWLock); + } } AS_API void asReleaseExclusiveLock() { - if( threadManager ) - { - RELEASEEXCLUSIVE(threadManager->appRWLock); - } + if( threadManager ) + { + RELEASEEXCLUSIVE(threadManager->appRWLock); + } } AS_API void asAcquireSharedLock() { - if( threadManager ) - { - ACQUIRESHARED(threadManager->appRWLock); - } + if( threadManager ) + { + ACQUIRESHARED(threadManager->appRWLock); + } } AS_API void asReleaseSharedLock() { - if( threadManager ) - { - RELEASESHARED(threadManager->appRWLock); - } + if( threadManager ) + { + RELEASESHARED(threadManager->appRWLock); + } } } @@ -115,199 +115,199 @@ __declspec(thread) asCThreadLocalData *asCThreadManager::tld = 0; asCThreadManager::asCThreadManager() { - // We're already in the critical section when this function is called + // We're already in the critical section when this function is called #ifdef AS_NO_THREADS - tld = 0; + 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 + // 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; + 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; + // 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); + 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 + // 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; + if( tld ) + { + asDELETE(tld,asCThreadLocalData); + } + tld = 0; #endif } int asCThreadManager::CleanupLocalData() { - if( threadManager == 0 ) - return 0; + if( threadManager == 0 ) + return 0; #ifndef AS_NO_THREADS #if defined AS_POSIX_THREADS - asCThreadLocalData *tld = (asCThreadLocalData*)pthread_getspecific((pthread_key_t)threadManager->tlsKey); + 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 + #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; + 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; + 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; + 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); - } + 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 + #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; + return tld; #else - if( threadManager->tld == 0 ) - threadManager->tld = asNEW(asCThreadLocalData)(); + if( threadManager->tld == 0 ) + threadManager->tld = asNEW(asCThreadLocalData)(); - return threadManager->tld; + return threadManager->tld; #endif } @@ -327,15 +327,15 @@ asCThreadLocalData::~asCThreadLocalData() asCThreadCriticalSection::asCThreadCriticalSection() { #if defined AS_POSIX_THREADS - pthread_mutex_init(&cs, 0); + 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); + // 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); + // Only the non-Ex version is available on WinXP and older + // MinGW also only defines this version + InitializeCriticalSection(&cs); #endif #endif } @@ -343,58 +343,58 @@ asCThreadCriticalSection::asCThreadCriticalSection() asCThreadCriticalSection::~asCThreadCriticalSection() { #if defined AS_POSIX_THREADS - pthread_mutex_destroy(&cs); + pthread_mutex_destroy(&cs); #elif defined AS_WINDOWS_THREADS - DeleteCriticalSection(&cs); + DeleteCriticalSection(&cs); #endif } void asCThreadCriticalSection::Enter() { #if defined AS_POSIX_THREADS - pthread_mutex_lock(&cs); + pthread_mutex_lock(&cs); #elif defined AS_WINDOWS_THREADS - EnterCriticalSection(&cs); + EnterCriticalSection(&cs); #endif } void asCThreadCriticalSection::Leave() { #if defined AS_POSIX_THREADS - pthread_mutex_unlock(&cs); + pthread_mutex_unlock(&cs); #elif defined AS_WINDOWS_THREADS - LeaveCriticalSection(&cs); + LeaveCriticalSection(&cs); #endif } bool asCThreadCriticalSection::TryEnter() { #if defined AS_POSIX_THREADS - return !pthread_mutex_trylock(&cs); + return !pthread_mutex_trylock(&cs); #elif defined AS_WINDOWS_THREADS - return TryEnterCriticalSection(&cs) ? true : false; + return TryEnterCriticalSection(&cs) ? true : false; #else - return true; + return true; #endif } asCThreadReadWriteLock::asCThreadReadWriteLock() { #if defined AS_POSIX_THREADS - int r = pthread_rwlock_init(&lock, 0); - asASSERT( r == 0 ); - UNUSED_VAR(r); + 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 + // 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); + // 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); + readLocks = CreateSemaphoreW(NULL, maxReaders, maxReaders, 0); + InitializeCriticalSection(&writeLock); #endif #endif } @@ -402,61 +402,61 @@ asCThreadReadWriteLock::asCThreadReadWriteLock() asCThreadReadWriteLock::~asCThreadReadWriteLock() { #if defined AS_POSIX_THREADS - pthread_rwlock_destroy(&lock); + pthread_rwlock_destroy(&lock); #elif defined AS_WINDOWS_THREADS - DeleteCriticalSection(&writeLock); - CloseHandle(readLocks); + DeleteCriticalSection(&writeLock); + CloseHandle(readLocks); #endif } void asCThreadReadWriteLock::AcquireExclusive() { #if defined AS_POSIX_THREADS - pthread_rwlock_wrlock(&lock); + 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); + // 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); + pthread_rwlock_unlock(&lock); #elif defined AS_WINDOWS_THREADS - // Release all readers at once - ReleaseSemaphore(readLocks, maxReaders, 0); + // Release all readers at once + ReleaseSemaphore(readLocks, maxReaders, 0); #endif } void asCThreadReadWriteLock::AcquireShared() { #if defined AS_POSIX_THREADS - pthread_rwlock_rdlock(&lock); + pthread_rwlock_rdlock(&lock); #elif defined AS_WINDOWS_THREADS - // Lock a reader slot - WaitForSingleObjectEx(readLocks, INFINITE, FALSE); + // Lock a reader slot + WaitForSingleObjectEx(readLocks, INFINITE, FALSE); #endif } void asCThreadReadWriteLock::ReleaseShared() { #if defined AS_POSIX_THREADS - pthread_rwlock_unlock(&lock); + pthread_rwlock_unlock(&lock); #elif defined AS_WINDOWS_THREADS - // Release the reader slot - ReleaseSemaphore(readLocks, 1, 0); + // Release the reader slot + ReleaseSemaphore(readLocks, 1, 0); #endif } diff --git a/src/angelscript/source/as_thread.h b/src/angelscript/source/as_thread.h index 813d4c0f0f4..80aa0fa3024 100644 --- a/src/angelscript/source/as_thread.h +++ b/src/angelscript/source/as_thread.h @@ -52,37 +52,37 @@ class asCThreadLocalData; class asCThreadManager : public asIThreadManager { public: - static asCThreadLocalData *GetLocalData(); - static int CleanupLocalData(); + static asCThreadLocalData *GetLocalData(); + static int CleanupLocalData(); - static int Prepare(asIThreadManager *externalThreadMgr); - static void Unprepare(); + static int Prepare(asIThreadManager *externalThreadMgr); + static void Unprepare(); - // This read/write lock can be used by the application to provide simple synchronization - DECLAREREADWRITELOCK(appRWLock) + // This read/write lock can be used by the application to provide simple synchronization + DECLAREREADWRITELOCK(appRWLock) protected: - asCThreadManager(); - ~asCThreadManager(); + 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; + // 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; + // 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; + asDWORD tlsKey; #endif - DECLARECRITICALSECTION(criticalSection) + DECLARECRITICALSECTION(criticalSection) #else - asCThreadLocalData *tld; + asCThreadLocalData *tld; #endif }; @@ -93,14 +93,14 @@ class asIScriptContext; class asCThreadLocalData { public: - asCArray activeContexts; - asCString string; + asCArray activeContexts; + asCString string; protected: - friend class asCThreadManager; + friend class asCThreadManager; - asCThreadLocalData(); - ~asCThreadLocalData(); + asCThreadLocalData(); + ~asCThreadLocalData(); }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_tokendef.h b/src/angelscript/source/as_tokendef.h index ed24ab53bdd..44ac846e6f3 100644 --- a/src/angelscript/source/as_tokendef.h +++ b/src/angelscript/source/as_tokendef.h @@ -45,258 +45,258 @@ 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 - ttProtected, // protected - ttNamespace, // namespace - ttMixin, // mixin - ttAuto, // auto - ttTry, // try - ttCatch // catch + 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 + ttProtected, // protected + ttNamespace, // namespace + ttMixin, // mixin + ttAuto, // auto + ttTry, // try + ttCatch // catch }; struct sTokenWord { - const char *word; - size_t wordLength; - eTokenType tokenType; + 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("catch" , ttCatch), - asTokenDef("class" , ttClass), - asTokenDef("const" , ttConst), - asTokenDef("continue" , ttContinue), - asTokenDef("default" , ttDefault), - asTokenDef("do" , ttDo), + 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("catch" , ttCatch), + asTokenDef("class" , ttClass), + asTokenDef("const" , ttConst), + asTokenDef("continue" , ttContinue), + asTokenDef("default" , ttDefault), + asTokenDef("do" , ttDo), #ifdef AS_USE_DOUBLE_AS_FLOAT - asTokenDef("double" , ttFloat), + asTokenDef("double" , ttFloat), #else - asTokenDef("double" , ttDouble), + 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("protected" , ttProtected), - asTokenDef("return" , ttReturn), - asTokenDef("switch" , ttSwitch), - asTokenDef("true" , ttTrue), - asTokenDef("try" , ttTry), - 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), + 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("protected" , ttProtected), + asTokenDef("return" , ttReturn), + asTokenDef("switch" , ttSwitch), + asTokenDef("true" , ttTrue), + asTokenDef("try" , ttTry), + 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); diff --git a/src/angelscript/source/as_tokenizer.cpp b/src/angelscript/source/as_tokenizer.cpp index 2017a12ec22..e27551df208 100644 --- a/src/angelscript/source/as_tokenizer.cpp +++ b/src/angelscript/source/as_tokenizer.cpp @@ -2,23 +2,23 @@ AngelCode Scripting Library Copyright (c) 2003-2015 Andreas Jonsson - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -49,426 +49,426 @@ 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; - } + 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]); - } + // 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; + 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; + 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); + 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; + eTokenType tokenType; + size_t tlen; + asETokenClass t = ParseToken(source, sourceLength, tlen, tokenType); + if( tc ) *tc = t; + if( tokenLength ) *tokenLength = tlen; - return tokenType; + 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; + 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; + // 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( sourceLength < 2 ) + return false; - if( source[0] != '/' ) - return false; + if( source[0] != '/' ) + return false; - if( source[1] == '/' ) - { - // One-line comment + if( source[1] == '/' ) + { + // One-line comment - // Find the length - size_t n; - for( n = 2; n < sourceLength; n++ ) - { - if( source[n] == '\n' ) - break; - } + // 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; + tokenType = ttOnelineComment; + tokenLength = n < sourceLength ? n+1 : n; - return true; - } + return true; + } - if( source[1] == '*' ) - { - // Multi-line comment + if( source[1] == '*' ) + { + // Multi-line comment - // Find the length - size_t n; - for( n = 2; n < sourceLength-1; ) - { - if( source[n++] == '*' && source[n] == '/' ) - break; - } + // Find the length + size_t n; + for( n = 2; n < sourceLength-1; ) + { + if( source[n++] == '*' && source[n] == '/' ) + break; + } - tokenType = ttMultilineComment; - tokenLength = n+1; + tokenType = ttMultilineComment; + tokenLength = n+1; - return true; - } + return true; + } - return false; + 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 - { + // 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; + tokenType = ttFloatConstant; #else - tokenType = ttDoubleConstant; + 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++ ) - { + 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; - } + // 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; - } + 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; - } + tokenType = ttNonTerminatedStringConstant; + tokenLength = n; + } - return true; - } + return true; + } - return false; + return false; } bool asCTokenizer::IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const { - // char is unsigned by default on some architectures, e.g. ppc and arm - // Make sure the value is always treated as signed in the below comparisons - signed char c = source[0]; - - // Starting with letter or underscore - if( (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - c == '_' || - (c < 0 && engine->ep.allowUnicodeIdentifiers) ) - { - tokenType = ttIdentifier; - tokenLength = 1; - - for( size_t n = 1; n < sourceLength; n++ ) - { - c = source[n]; - if( (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '_' || - (c < 0 && engine->ep.allowUnicodeIdentifiers) ) - tokenLength++; - else - break; - } - - // Make sure the identifier isn't a reserved keyword - if( IsKeyWord(source, tokenLength, tokenLength, tokenType) ) - return false; - - return true; - } - - return false; + // char is unsigned by default on some architectures, e.g. ppc and arm + // Make sure the value is always treated as signed in the below comparisons + signed char c = source[0]; + + // Starting with letter or underscore + if( (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c == '_' || + (c < 0 && engine->ep.allowUnicodeIdentifiers) ) + { + tokenType = ttIdentifier; + tokenLength = 1; + + for( size_t n = 1; n < sourceLength; n++ ) + { + c = source[n]; + if( (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_' || + (c < 0 && engine->ep.allowUnicodeIdentifiers) ) + tokenLength++; + else + break; + } + + // 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; + 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/src/angelscript/source/as_tokenizer.h b/src/angelscript/source/as_tokenizer.h index 38a08c103cc..bb867cbb4af 100644 --- a/src/angelscript/source/as_tokenizer.h +++ b/src/angelscript/source/as_tokenizer.h @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -50,27 +50,27 @@ 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); + 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; + friend class asCScriptEngine; - asCTokenizer(); - ~asCTokenizer(); + 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; + 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 asCScriptEngine *engine; - const sTokenWord **keywordTable[256]; + const sTokenWord **keywordTable[256]; }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_typeinfo.cpp b/src/angelscript/source/as_typeinfo.cpp index 04f240d9e9b..f7ef0120958 100644 --- a/src/angelscript/source/as_typeinfo.cpp +++ b/src/angelscript/source/as_typeinfo.cpp @@ -42,36 +42,36 @@ BEGIN_AS_NAMESPACE asCTypeInfo::asCTypeInfo() { - externalRefCount.set(0); - internalRefCount.set(1); // start with one internal ref-count - engine = 0; - module = 0; - size = 0; - flags = 0; - typeId = -1; // start as -1 to signal that it hasn't been defined + externalRefCount.set(0); + internalRefCount.set(1); // start with one internal ref-count + engine = 0; + module = 0; + size = 0; + flags = 0; + typeId = -1; // start as -1 to signal that it hasn't been defined - scriptSectionIdx = -1; - declaredAt = 0; + scriptSectionIdx = -1; + declaredAt = 0; - accessMask = 0xFFFFFFFF; - nameSpace = 0; + accessMask = 0xFFFFFFFF; + nameSpace = 0; } asCTypeInfo::asCTypeInfo(asCScriptEngine *in_engine) { - externalRefCount.set(0); - internalRefCount.set(1); // start with one internal ref count - engine = in_engine; - module = 0; - size = 0; - flags = 0; - typeId = -1; // start as -1 to signal that it hasn't been defined + externalRefCount.set(0); + internalRefCount.set(1); // start with one internal ref count + engine = in_engine; + module = 0; + size = 0; + flags = 0; + typeId = -1; // start as -1 to signal that it hasn't been defined - scriptSectionIdx = -1; - declaredAt = 0; + scriptSectionIdx = -1; + declaredAt = 0; - accessMask = 0xFFFFFFFF; - nameSpace = engine->nameSpaces[0]; + accessMask = 0xFFFFFFFF; + nameSpace = engine->nameSpaces[0]; } asCTypeInfo::~asCTypeInfo() @@ -81,394 +81,394 @@ asCTypeInfo::~asCTypeInfo() // interface int asCTypeInfo::AddRef() const { - return externalRefCount.atomicInc(); + return externalRefCount.atomicInc(); } // interface int asCTypeInfo::Release() const { - int r = externalRefCount.atomicDec(); + int r = externalRefCount.atomicDec(); - if (r == 0) - { - // There are no more external references, if there are also no - // internal references then it is time to delete the object type - if (internalRefCount.get() == 0) - { - // If the engine is no longer set, then it has already been - // released and we must take care of the deletion ourselves - asDELETE(const_cast(this), asCTypeInfo); - } - } + if (r == 0) + { + // There are no more external references, if there are also no + // internal references then it is time to delete the object type + if (internalRefCount.get() == 0) + { + // If the engine is no longer set, then it has already been + // released and we must take care of the deletion ourselves + asDELETE(const_cast(this), asCTypeInfo); + } + } - return r; + return r; } int asCTypeInfo::AddRefInternal() { - return internalRefCount.atomicInc(); + return internalRefCount.atomicInc(); } int asCTypeInfo::ReleaseInternal() { - int r = internalRefCount.atomicDec(); + int r = internalRefCount.atomicDec(); - if (r == 0) - { - // There are no more internal references, if there are also no - // external references then it is time to delete the object type - if (externalRefCount.get() == 0) - { - // If the engine is no longer set, then it has already been - // released and we must take care of the deletion ourselves - asDELETE(const_cast(this), asCTypeInfo); - } - } + if (r == 0) + { + // There are no more internal references, if there are also no + // external references then it is time to delete the object type + if (externalRefCount.get() == 0) + { + // If the engine is no longer set, then it has already been + // released and we must take care of the deletion ourselves + asDELETE(const_cast(this), asCTypeInfo); + } + } - return r; + return r; } // interface asIScriptModule *asCTypeInfo::GetModule() const { - return module; + return module; } void *asCTypeInfo::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); + // 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); + // 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); + RELEASEEXCLUSIVE(engine->engineRWLock); - return oldData; - } - } + return oldData; + } + } - userData.PushLast(type); - userData.PushLast(reinterpret_cast(data)); + userData.PushLast(type); + userData.PushLast(reinterpret_cast(data)); - RELEASEEXCLUSIVE(engine->engineRWLock); + RELEASEEXCLUSIVE(engine->engineRWLock); - return 0; + return 0; } void *asCTypeInfo::GetUserData(asPWORD type) const { - // There may be multiple threads reading, but when - // setting the user data nobody must be reading. - ACQUIRESHARED(engine->engineRWLock); + // 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]); - } - } + 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); + RELEASESHARED(engine->engineRWLock); - return 0; + return 0; } // interface const char *asCTypeInfo::GetName() const { - return name.AddressOf(); + return name.AddressOf(); } // interface const char *asCTypeInfo::GetNamespace() const { - if( nameSpace ) - return nameSpace->name.AddressOf(); + if( nameSpace ) + return nameSpace->name.AddressOf(); - return 0; + return 0; } // interface asDWORD asCTypeInfo::GetFlags() const { - return flags; + return flags; } // interface asUINT asCTypeInfo::GetSize() const { - return size; + return size; } // interface int asCTypeInfo::GetTypeId() const { - if (typeId == -1) - { - // We need a non const pointer to create the asCDataType object. - // We're not breaking anything here because this function is not - // modifying the object, so this const cast is safe. - asCTypeInfo *ot = const_cast(this); + if (typeId == -1) + { + // We need a non const pointer to create the asCDataType object. + // We're not breaking anything here because this function is not + // modifying the object, so this const cast is safe. + asCTypeInfo *ot = const_cast(this); - // The engine will define the typeId for this object type - engine->GetTypeIdFromDataType(asCDataType::CreateType(ot, false)); - } + // The engine will define the typeId for this object type + engine->GetTypeIdFromDataType(asCDataType::CreateType(ot, false)); + } - return typeId; + return typeId; } // interface asIScriptEngine *asCTypeInfo::GetEngine() const { - return engine; + return engine; } // interface const char *asCTypeInfo::GetConfigGroup() const { - asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(this); - if (group == 0) - return 0; + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(this); + if (group == 0) + return 0; - return group->groupName.AddressOf(); + return group->groupName.AddressOf(); } // interface asDWORD asCTypeInfo::GetAccessMask() const { - return accessMask; + return accessMask; } // interface int asCTypeInfo::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const { - UNUSED_VAR(index); - if (out_name) *out_name = 0; - if (out_typeId) *out_typeId = 0; - if (out_isPrivate) *out_isPrivate = false; - if (out_isProtected) *out_isProtected = false; - if (out_offset) *out_offset = 0; - if (out_isReference) *out_isReference = false; - if (out_accessMask) *out_accessMask = 0; - if (out_compositeOffset) *out_compositeOffset = 0; - if (out_isCompositeIndirect) *out_isCompositeIndirect = false; - return -1; + UNUSED_VAR(index); + if (out_name) *out_name = 0; + if (out_typeId) *out_typeId = 0; + if (out_isPrivate) *out_isPrivate = false; + if (out_isProtected) *out_isProtected = false; + if (out_offset) *out_offset = 0; + if (out_isReference) *out_isReference = false; + if (out_accessMask) *out_accessMask = 0; + if (out_compositeOffset) *out_compositeOffset = 0; + if (out_isCompositeIndirect) *out_isCompositeIndirect = false; + return -1; } // internal asCObjectType *CastToObjectType(asCTypeInfo *ti) { - // Allow call on null pointer - if (ti == 0) return 0; + // Allow call on null pointer + if (ti == 0) return 0; - // TODO: type: Should List pattern have its own type class? - if ((ti->flags & (asOBJ_VALUE | asOBJ_REF | asOBJ_LIST_PATTERN)) && !(ti->flags & asOBJ_FUNCDEF)) - return reinterpret_cast(ti); + // TODO: type: Should List pattern have its own type class? + if ((ti->flags & (asOBJ_VALUE | asOBJ_REF | asOBJ_LIST_PATTERN)) && !(ti->flags & asOBJ_FUNCDEF)) + return reinterpret_cast(ti); - return 0; + return 0; } // internal asCEnumType *CastToEnumType(asCTypeInfo *ti) { - // Allow call on null pointer - if (ti == 0) return 0; + // Allow call on null pointer + if (ti == 0) return 0; - if (ti->flags & (asOBJ_ENUM)) - return reinterpret_cast(ti); + if (ti->flags & (asOBJ_ENUM)) + return reinterpret_cast(ti); - return 0; + return 0; } // internal asCTypedefType *CastToTypedefType(asCTypeInfo *ti) { - // Allow call on null pointer - if (ti == 0) return 0; + // Allow call on null pointer + if (ti == 0) return 0; - if (ti->flags & (asOBJ_TYPEDEF)) - return reinterpret_cast(ti); + if (ti->flags & (asOBJ_TYPEDEF)) + return reinterpret_cast(ti); - return 0; + return 0; } // internal asCFuncdefType *CastToFuncdefType(asCTypeInfo *ti) { - // Allow call on null pointer - if (ti == 0) return 0; + // Allow call on null pointer + if (ti == 0) return 0; - if (ti->flags & (asOBJ_FUNCDEF)) - return reinterpret_cast(ti); + if (ti->flags & (asOBJ_FUNCDEF)) + return reinterpret_cast(ti); - return 0; + return 0; } // internal void asCTypeInfo::CleanUserData() { - asASSERT(engine); - for (asUINT n = 0; n < userData.GetLength(); n += 2) - { - if (userData[n + 1]) - { - for (asUINT c = 0; c < engine->cleanTypeInfoFuncs.GetLength(); c++) - if (engine->cleanTypeInfoFuncs[c].type == userData[n]) - engine->cleanTypeInfoFuncs[c].cleanFunc(this); - } - } - userData.SetLength(0); + asASSERT(engine); + for (asUINT n = 0; n < userData.GetLength(); n += 2) + { + if (userData[n + 1]) + { + for (asUINT c = 0; c < engine->cleanTypeInfoFuncs.GetLength(); c++) + if (engine->cleanTypeInfoFuncs[c].type == userData[n]) + engine->cleanTypeInfoFuncs[c].cleanFunc(this); + } + } + userData.SetLength(0); } // internal bool asCTypeInfo::IsShared() const { - // Types that can be declared by scripts need to have the explicit flag asOBJ_SHARED - if (flags & (asOBJ_SCRIPT_OBJECT | asOBJ_ENUM)) return flags & asOBJ_SHARED ? true : false; + // Types that can be declared by scripts need to have the explicit flag asOBJ_SHARED + if (flags & (asOBJ_SCRIPT_OBJECT | asOBJ_ENUM)) return flags & asOBJ_SHARED ? true : false; - // Otherwise we assume the type to be shared - return true; + // Otherwise we assume the type to be shared + return true; } //////////////////////////////////////////////////////////////////////////////////////// asCEnumType::~asCEnumType() { - asUINT n; - for (n = 0; n < enumValues.GetLength(); n++) - { - if (enumValues[n]) - asDELETE(enumValues[n], asSEnumValue); - } - enumValues.SetLength(0); + asUINT n; + for (n = 0; n < enumValues.GetLength(); n++) + { + if (enumValues[n]) + asDELETE(enumValues[n], asSEnumValue); + } + enumValues.SetLength(0); } // interface asUINT asCEnumType::GetEnumValueCount() const { - return enumValues.GetLength(); + return enumValues.GetLength(); } // interface const char *asCEnumType::GetEnumValueByIndex(asUINT index, int *outValue) const { - if (outValue) - *outValue = 0; + if (outValue) + *outValue = 0; - if (index >= enumValues.GetLength()) - return 0; + if (index >= enumValues.GetLength()) + return 0; - if (outValue) - *outValue = enumValues[index]->value; + if (outValue) + *outValue = enumValues[index]->value; - return enumValues[index]->name.AddressOf(); + return enumValues[index]->name.AddressOf(); } ////////////////////////////////////////////////////////////////////////////////////////// asCTypedefType::~asCTypedefType() { - DestroyInternal(); + DestroyInternal(); } void asCTypedefType::DestroyInternal() { - if (engine == 0) return; + if (engine == 0) return; - // Release the object types held by the alias - if (aliasForType.GetTypeInfo()) - aliasForType.GetTypeInfo()->ReleaseInternal(); + // Release the object types held by the alias + if (aliasForType.GetTypeInfo()) + aliasForType.GetTypeInfo()->ReleaseInternal(); - aliasForType = asCDataType::CreatePrimitive(ttVoid, false); + aliasForType = asCDataType::CreatePrimitive(ttVoid, false); - CleanUserData(); + CleanUserData(); - // Remove the type from the engine - if (typeId != -1) - engine->RemoveFromTypeIdMap(this); + // Remove the type from the engine + if (typeId != -1) + engine->RemoveFromTypeIdMap(this); - // Clear the engine pointer to mark the object type as invalid - engine = 0; + // Clear the engine pointer to mark the object type as invalid + engine = 0; } // interface int asCTypedefType::GetTypedefTypeId() const { - return engine->GetTypeIdFromDataType(aliasForType); + return engine->GetTypeIdFromDataType(aliasForType); } ////////////////////////////////////////////////////////////////////////////////////////// asCFuncdefType::asCFuncdefType(asCScriptEngine *en, asCScriptFunction *func) : asCTypeInfo(en) { - asASSERT(func->funcType == asFUNC_FUNCDEF); - asASSERT(func->funcdefType == 0); + asASSERT(func->funcType == asFUNC_FUNCDEF); + asASSERT(func->funcdefType == 0); - // A function pointer is special kind of reference type - // It must be possible to garbage collect, as funcdefs can form circular references if used as delegates - flags = asOBJ_REF | asOBJ_GC | asOBJ_FUNCDEF | (func->IsShared() ? asOBJ_SHARED : 0); - name = func->name; - nameSpace = func->nameSpace; - module = func->module; - accessMask = func->accessMask; - funcdef = func; // reference already counted by the asCScriptFunction constructor - parentClass = 0; + // A function pointer is special kind of reference type + // It must be possible to garbage collect, as funcdefs can form circular references if used as delegates + flags = asOBJ_REF | asOBJ_GC | asOBJ_FUNCDEF | (func->IsShared() ? asOBJ_SHARED : 0); + name = func->name; + nameSpace = func->nameSpace; + module = func->module; + accessMask = func->accessMask; + funcdef = func; // reference already counted by the asCScriptFunction constructor + parentClass = 0; - func->funcdefType = this; + func->funcdefType = this; } asCFuncdefType::~asCFuncdefType() { - DestroyInternal(); + DestroyInternal(); } void asCFuncdefType::DestroyInternal() { - if (engine == 0) return; + if (engine == 0) return; - // Release the funcdef - if( funcdef ) - funcdef->ReleaseInternal(); - funcdef = 0; + // Release the funcdef + if( funcdef ) + funcdef->ReleaseInternal(); + funcdef = 0; - // Detach from parent class - if (parentClass) - { - parentClass->childFuncDefs.RemoveValue(this); - parentClass = 0; - } + // Detach from parent class + if (parentClass) + { + parentClass->childFuncDefs.RemoveValue(this); + parentClass = 0; + } - CleanUserData(); + CleanUserData(); - // Remove the type from the engine - if (typeId != -1) - engine->RemoveFromTypeIdMap(this); + // Remove the type from the engine + if (typeId != -1) + engine->RemoveFromTypeIdMap(this); - // Clear the engine pointer to mark the object type as invalid - engine = 0; + // Clear the engine pointer to mark the object type as invalid + engine = 0; } // interface asIScriptFunction *asCFuncdefType::GetFuncdefSignature() const { - return funcdef; + return funcdef; } // interface asITypeInfo *asCFuncdefType::GetParentType() const { - return parentClass; + return parentClass; } END_AS_NAMESPACE diff --git a/src/angelscript/source/as_typeinfo.h b/src/angelscript/source/as_typeinfo.h index a5643dda5da..4ef97d380db 100644 --- a/src/angelscript/source/as_typeinfo.h +++ b/src/angelscript/source/as_typeinfo.h @@ -55,186 +55,186 @@ struct asSNameSpace; // TODO: type: asCPrimitiveType shall be implemented to represent primitives (void, int, double, etc) -// TODO: type: asCTypeInfo should have an internal virtual method GetBehaviours. For asCObjectType it -// should return the beh member. For asCFuncdefType it should return the beh member of -// engine->functionBehaviours. This will allow the code that needs the behaviour to handle +// TODO: type: asCTypeInfo should have an internal virtual method GetBehaviours. For asCObjectType it +// should return the beh member. For asCFuncdefType it should return the beh member of +// engine->functionBehaviours. This will allow the code that needs the behaviour to handle // both object types and funcdefs the same way class asCTypeInfo : public asITypeInfo { public: - //===================================== - // From asITypeInfo - //===================================== - asIScriptEngine *GetEngine() const; - const char *GetConfigGroup() const; - asDWORD GetAccessMask() const; - asIScriptModule *GetModule() const; - - // Memory management - int AddRef() const; - int Release() const; - - // Type info - const char *GetName() const; - const char *GetNamespace() const; - asITypeInfo *GetBaseType() const { return 0; } - bool DerivesFrom(const asITypeInfo *objType) const { UNUSED_VAR(objType); return 0; } - asDWORD GetFlags() const; - asUINT GetSize() const; - int GetTypeId() const; - int GetSubTypeId(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return -1; } - asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return 0; } - asUINT GetSubTypeCount() const { return 0; } - - // Interfaces - asUINT GetInterfaceCount() const { return 0; } - asITypeInfo *GetInterface(asUINT index) const { UNUSED_VAR(index); return 0; } - bool Implements(const asITypeInfo *objType) const { UNUSED_VAR(objType); return false; } - - // Factories - asUINT GetFactoryCount() const { return 0; } - asIScriptFunction *GetFactoryByIndex(asUINT index) const { UNUSED_VAR(index); return 0; } - asIScriptFunction *GetFactoryByDecl(const char *decl) const { UNUSED_VAR(decl); return 0; } - - // Methods - asUINT GetMethodCount() const { return 0; } - asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const { UNUSED_VAR(index); UNUSED_VAR(getVirtual); return 0; } - asIScriptFunction *GetMethodByName(const char *in_name, bool getVirtual) const { UNUSED_VAR(in_name); UNUSED_VAR(getVirtual); return 0; } - asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const { UNUSED_VAR(decl); UNUSED_VAR(getVirtual); return 0; } - - // Properties - asUINT GetPropertyCount() const { return 0; } - int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const; - const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const { UNUSED_VAR(index); UNUSED_VAR(includeNamespace); return 0; } - - // Behaviours - asUINT GetBehaviourCount() const { return 0; } - asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const { UNUSED_VAR(index); UNUSED_VAR(outBehaviour); return 0; } - - // Child types - asUINT GetChildFuncdefCount() const { return 0; } - asITypeInfo *GetChildFuncdef(asUINT index) const { UNUSED_VAR(index); return 0; } - asITypeInfo *GetParentType() const { return 0; } - - // Enums - virtual asUINT GetEnumValueCount() const { return 0; } - virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const { UNUSED_VAR(index); if (outValue) *outValue = 0; return 0; } - - // Typedef - virtual int GetTypedefTypeId() const { return asERROR; } - - // Funcdef - virtual asIScriptFunction *GetFuncdefSignature() const { return 0; } - - // User data - void *SetUserData(void *data, asPWORD type); - void *GetUserData(asPWORD type) const; - - //=========================================== - // Internal - //=========================================== + //===================================== + // From asITypeInfo + //===================================== + asIScriptEngine *GetEngine() const; + const char *GetConfigGroup() const; + asDWORD GetAccessMask() const; + asIScriptModule *GetModule() const; + + // Memory management + int AddRef() const; + int Release() const; + + // Type info + const char *GetName() const; + const char *GetNamespace() const; + asITypeInfo *GetBaseType() const { return 0; } + bool DerivesFrom(const asITypeInfo *objType) const { UNUSED_VAR(objType); return 0; } + asDWORD GetFlags() const; + asUINT GetSize() const; + int GetTypeId() const; + int GetSubTypeId(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return -1; } + asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return 0; } + asUINT GetSubTypeCount() const { return 0; } + + // Interfaces + asUINT GetInterfaceCount() const { return 0; } + asITypeInfo *GetInterface(asUINT index) const { UNUSED_VAR(index); return 0; } + bool Implements(const asITypeInfo *objType) const { UNUSED_VAR(objType); return false; } + + // Factories + asUINT GetFactoryCount() const { return 0; } + asIScriptFunction *GetFactoryByIndex(asUINT index) const { UNUSED_VAR(index); return 0; } + asIScriptFunction *GetFactoryByDecl(const char *decl) const { UNUSED_VAR(decl); return 0; } + + // Methods + asUINT GetMethodCount() const { return 0; } + asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const { UNUSED_VAR(index); UNUSED_VAR(getVirtual); return 0; } + asIScriptFunction *GetMethodByName(const char *in_name, bool getVirtual) const { UNUSED_VAR(in_name); UNUSED_VAR(getVirtual); return 0; } + asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const { UNUSED_VAR(decl); UNUSED_VAR(getVirtual); return 0; } + + // Properties + asUINT GetPropertyCount() const { return 0; } + int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const; + const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const { UNUSED_VAR(index); UNUSED_VAR(includeNamespace); return 0; } + + // Behaviours + asUINT GetBehaviourCount() const { return 0; } + asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const { UNUSED_VAR(index); UNUSED_VAR(outBehaviour); return 0; } + + // Child types + asUINT GetChildFuncdefCount() const { return 0; } + asITypeInfo *GetChildFuncdef(asUINT index) const { UNUSED_VAR(index); return 0; } + asITypeInfo *GetParentType() const { return 0; } + + // Enums + virtual asUINT GetEnumValueCount() const { return 0; } + virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const { UNUSED_VAR(index); if (outValue) *outValue = 0; return 0; } + + // Typedef + virtual int GetTypedefTypeId() const { return asERROR; } + + // Funcdef + virtual asIScriptFunction *GetFuncdefSignature() const { return 0; } + + // User data + void *SetUserData(void *data, asPWORD type); + void *GetUserData(asPWORD type) const; + + //=========================================== + // Internal + //=========================================== public: - asCTypeInfo(asCScriptEngine *engine); - virtual ~asCTypeInfo(); + asCTypeInfo(asCScriptEngine *engine); + virtual ~asCTypeInfo(); - // Keep an internal reference counter to separate references coming from - // application or script objects and references coming from the script code - virtual int AddRefInternal(); - virtual int ReleaseInternal(); + // Keep an internal reference counter to separate references coming from + // application or script objects and references coming from the script code + virtual int AddRefInternal(); + virtual int ReleaseInternal(); - virtual void DestroyInternal() {} + virtual void DestroyInternal() {} - void CleanUserData(); + void CleanUserData(); - bool IsShared() const; + bool IsShared() const; - // These can be safely used on null pointers (which will return null) - friend asCObjectType *CastToObjectType(asCTypeInfo *); - friend asCEnumType *CastToEnumType(asCTypeInfo *); - friend asCTypedefType *CastToTypedefType(asCTypeInfo *); - friend asCFuncdefType *CastToFuncdefType(asCTypeInfo *); + // These can be safely used on null pointers (which will return null) + friend asCObjectType *CastToObjectType(asCTypeInfo *); + friend asCEnumType *CastToEnumType(asCTypeInfo *); + friend asCTypedefType *CastToTypedefType(asCTypeInfo *); + friend asCFuncdefType *CastToFuncdefType(asCTypeInfo *); - asCString name; - asSNameSpace *nameSpace; - int size; - mutable int typeId; - asDWORD flags; - asDWORD accessMask; + asCString name; + asSNameSpace *nameSpace; + int size; + mutable int typeId; + asDWORD flags; + asDWORD accessMask; - // Store the script section where the code was declared - int scriptSectionIdx; - // Store the location where the function was declared (row in the lower 20 bits, and column in the upper 12) - int declaredAt; + // Store the script section where the code was declared + int scriptSectionIdx; + // Store the location where the function was declared (row in the lower 20 bits, and column in the upper 12) + int declaredAt; - asCScriptEngine *engine; - asCModule *module; - asCArray userData; + asCScriptEngine *engine; + asCModule *module; + asCArray userData; protected: - friend class asCScriptEngine; - friend class asCConfigGroup; - friend class asCModule; - friend class asCObjectType; - asCTypeInfo(); - - mutable asCAtomic externalRefCount; - asCAtomic internalRefCount; + friend class asCScriptEngine; + friend class asCConfigGroup; + friend class asCModule; + friend class asCObjectType; + asCTypeInfo(); + + mutable asCAtomic externalRefCount; + asCAtomic internalRefCount; }; struct asSEnumValue { - asCString name; - int value; + asCString name; + int value; }; class asCEnumType : public asCTypeInfo { public: - asCEnumType(asCScriptEngine *engine) : asCTypeInfo(engine) {} - ~asCEnumType(); + asCEnumType(asCScriptEngine *engine) : asCTypeInfo(engine) {} + ~asCEnumType(); - asCArray enumValues; + asCArray enumValues; - asUINT GetEnumValueCount() const; - const char *GetEnumValueByIndex(asUINT index, int *outValue) const; + asUINT GetEnumValueCount() const; + const char *GetEnumValueByIndex(asUINT index, int *outValue) const; protected: - asCEnumType() : asCTypeInfo() {} + asCEnumType() : asCTypeInfo() {} }; class asCTypedefType : public asCTypeInfo { public: - asCTypedefType(asCScriptEngine *engine) : asCTypeInfo(engine) {} - ~asCTypedefType(); + asCTypedefType(asCScriptEngine *engine) : asCTypeInfo(engine) {} + ~asCTypedefType(); - void DestroyInternal(); + void DestroyInternal(); - asCDataType aliasForType; // increase refCount for typeinfo inside datatype + asCDataType aliasForType; // increase refCount for typeinfo inside datatype - int GetTypedefTypeId() const; + int GetTypedefTypeId() const; protected: - asCTypedefType() : asCTypeInfo() {} + asCTypedefType() : asCTypeInfo() {} }; class asCFuncdefType : public asCTypeInfo { public: - asCFuncdefType(asCScriptEngine *engine, asCScriptFunction *func); - ~asCFuncdefType(); + asCFuncdefType(asCScriptEngine *engine, asCScriptFunction *func); + ~asCFuncdefType(); - asIScriptFunction *GetFuncdefSignature() const; - asITypeInfo *GetParentType() const; + asIScriptFunction *GetFuncdefSignature() const; + asITypeInfo *GetParentType() const; - void DestroyInternal(); - asCScriptFunction *funcdef; // increases refCount - asCObjectType *parentClass; // doesn't increase refCount + void DestroyInternal(); + asCScriptFunction *funcdef; // increases refCount + asCObjectType *parentClass; // doesn't increase refCount protected: - asCFuncdefType() : asCTypeInfo(), funcdef(0), parentClass(0) {} + asCFuncdefType() : asCTypeInfo(), funcdef(0), parentClass(0) {} }; END_AS_NAMESPACE diff --git a/src/angelscript/source/as_variablescope.cpp b/src/angelscript/source/as_variablescope.cpp index aca36dae165..1ed5a9c416d 100644 --- a/src/angelscript/source/as_variablescope.cpp +++ b/src/angelscript/source/as_variablescope.cpp @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -46,93 +46,93 @@ BEGIN_AS_NAMESPACE asCVariableScope::asCVariableScope(asCVariableScope *parent) { - this->parent = parent; - Reset(); + this->parent = parent; + Reset(); } asCVariableScope::~asCVariableScope() { - Reset(); + 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); + 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; + // 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; + // 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; + // 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 diff --git a/src/angelscript/source/as_variablescope.h b/src/angelscript/source/as_variablescope.h index d4b220a018a..cbe9c41a3d8 100644 --- a/src/angelscript/source/as_variablescope.h +++ b/src/angelscript/source/as_variablescope.h @@ -2,23 +2,23 @@ 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 + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product + this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source + 3. This notice may not be removed or altered from any source distribution. The original version of this library can be located at: @@ -51,33 +51,33 @@ BEGIN_AS_NAMESPACE struct sVariable { - asCString name; - asCDataType type; - int stackOffset; - bool isInitialized; - bool isPureConstant; - asQWORD constantValue; - bool onHeap; + asCString name; + asCDataType type; + int stackOffset; + bool isInitialized; + bool isPureConstant; + asQWORD constantValue; + bool onHeap; }; class asCVariableScope { public: - asCVariableScope(asCVariableScope *parent); - ~asCVariableScope(); + asCVariableScope(asCVariableScope *parent); + ~asCVariableScope(); - void Reset(); + void Reset(); - int DeclareVariable(const char *name, const asCDataType &type, int stackOffset, bool isObjectOnHeap); - sVariable *GetVariable(const char *name); - sVariable *GetVariableByOffset(int offset); + int DeclareVariable(const char *name, const asCDataType &type, int stackOffset, bool isObjectOnHeap); + sVariable *GetVariable(const char *name); + sVariable *GetVariableByOffset(int offset); - asCVariableScope *parent; + asCVariableScope *parent; - bool isBreakScope; - bool isContinueScope; + bool isBreakScope; + bool isContinueScope; - asCArray variables; + asCArray variables; }; END_AS_NAMESPACE diff --git a/src/avrdude/AUTHORS b/src/avrdude/AUTHORS index 6abbec06626..81e82a1fb45 100644 --- a/src/avrdude/AUTHORS +++ b/src/avrdude/AUTHORS @@ -1,28 +1,28 @@ AVRDUDE was written by: - Brian S. Dean + Brian S. Dean Contributors: - Joerg Wunsch - Eric Weddington - Jan-Hinnerk Reichert - Alex Shepherd - Martin Thomas - Theodore A. Roth - Michael Holzt - Colin O'Flynn - Thomas Fischl - David Hoerl - Michal Ludvig - Darell Tan - Wolfgang Moser - Ville Voipio - Hannes Weisbach - Doug Springer - Brett Hagman - Rene Liebscher - Jim Paris + Joerg Wunsch + Eric Weddington + Jan-Hinnerk Reichert + Alex Shepherd + Martin Thomas + Theodore A. Roth + Michael Holzt + Colin O'Flynn + Thomas Fischl + David Hoerl + Michal Ludvig + Darell Tan + Wolfgang Moser + Ville Voipio + Hannes Weisbach + Doug Springer + Brett Hagman + Rene Liebscher + Jim Paris For minor contributions, please see the ChangeLog files. diff --git a/src/avrdude/COPYING b/src/avrdude/COPYING index e69cf7e6ca0..9573c7b7769 100644 --- a/src/avrdude/COPYING +++ b/src/avrdude/COPYING @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it diff --git a/src/avrdude/ChangeLog b/src/avrdude/ChangeLog index 879fbf95761..efe1b9833af 100644 --- a/src/avrdude/ChangeLog +++ b/src/avrdude/ChangeLog @@ -1,99 +1,99 @@ 2018-01-17 Joerg Wunsch (cherry-picked) - Submitted by Reinhard Max - patch #8311: Add IPv6 support to the -Pnet:host:port option - * ser_posix.c (net_open): Rewrite to use getaddrinfo() - rather than gethostbyname() - * avrdude.1: Document IPv6 feature - * doc/avrdude.texi: (Dito) + Submitted by Reinhard Max + patch #8311: Add IPv6 support to the -Pnet:host:port option + * ser_posix.c (net_open): Rewrite to use getaddrinfo() + rather than gethostbyname() + * avrdude.1: Document IPv6 feature + * doc/avrdude.texi: (Dito) 2016-05-10 Joerg Wunsch - Submitted by Hannes Jochriem: - * avrdude.conf.in (ehajo-isp): New programmer. + Submitted by Hannes Jochriem: + * avrdude.conf.in (ehajo-isp): New programmer. 2016-04-20 Joerg Wunsch - * configure.ac (libftdi1): Rather than hardcoding the library - providing the libusb-1.0 API, use the result from the previous - probe. This helps detecting libftdi1 on FreeBSD where the - libusb-1.0 API is provided by the system's libusb. + * configure.ac (libftdi1): Rather than hardcoding the library + providing the libusb-1.0 API, use the result from the previous + probe. This helps detecting libftdi1 on FreeBSD where the + libusb-1.0 API is provided by the system's libusb. 2016-04-18 Joerg Wunsch - * usb_hidapi.c (usbhid_open): Correctly calculate the - offset for serial number matching + * usb_hidapi.c (usbhid_open): Correctly calculate the + offset for serial number matching 2016-03-28 Joerg Wunsch - bug #47550: Linux GPIO broken - * linuxgpio.c: Replace %ud by %u in snprintf calls. + bug #47550: Linux GPIO broken + * linuxgpio.c: Replace %ud by %u in snprintf calls. 2016-03-02 Joerg Wunsch - * usb_hidapi.c (usbhid_recv): Bump read timeout to 300 ms. + * usb_hidapi.c (usbhid_recv): Bump read timeout to 300 ms. 2016-02-20 Joerg Wunsch - * jtag3.c: add support for libhidapi as (optional) transport for - CMSIS-DAP compliant debuggers (JTAGICE3 with firmware 3+, - AtmelICE, EDBG, mEDBG) - * usb_hidapi.c: (New file) - * libavrdude.h: Mention usbhid_serdev - * configure.ac: Bump version date + * jtag3.c: add support for libhidapi as (optional) transport for + CMSIS-DAP compliant debuggers (JTAGICE3 with firmware 3+, + AtmelICE, EDBG, mEDBG) + * usb_hidapi.c: (New file) + * libavrdude.h: Mention usbhid_serdev + * configure.ac: Bump version date 2016-02-18 Joerg Wunsch - (Obtained from patch #8717: pattch for mcprog and libhidapi support) - * configure.ac: Probe for libhidapi - * Makefile.am: Add @LIBHIDAPI@ + (Obtained from patch #8717: pattch for mcprog and libhidapi support) + * configure.ac: Probe for libhidapi + * Makefile.am: Add @LIBHIDAPI@ 2016-02-16 Joerg Wunsch - * doc/avrdude.texi: Bump copyright year. + * doc/avrdude.texi: Bump copyright year. 2016-02-16 Joerg Wunsch - * configure.ac: Bump for post-release 6.3. + * configure.ac: Bump for post-release 6.3. 2016-02-16 Joerg Wunsch - * configure.ac: Released version 6.3. + * configure.ac: Released version 6.3. 2016-02-15 Joerg Wunsch - patch #8894: Spelling in 6.2 doc - * doc/avrdude.texi: Various spelling fixes. + patch #8894: Spelling in 6.2 doc + * doc/avrdude.texi: Various spelling fixes. 2016-02-15 Joerg Wunsch - patch #8895: Spelling in 6.2 code - * avrftdi.c (avrftdi_open): Spell fix. + patch #8895: Spelling in 6.2 code + * avrftdi.c (avrftdi_open): Spell fix. 2016-02-15 Joerg Wunsch - patch #8896: Silence cppcheck warnings in 6.2 code - * linuxgpio.c: Use %ud to print GPIO values. + patch #8896: Silence cppcheck warnings in 6.2 code + * linuxgpio.c: Use %ud to print GPIO values. 2016-02-15 Joerg Wunsch - patch #8735: ATtiny28 support in avrdude.conf - * avrdude.conf.in (ATtiny28): New device. + patch #8735: ATtiny28 support in avrdude.conf + * avrdude.conf.in (ATtiny28): New device. 2016-02-15 Joerg Wunsch - * avrdude.conf.in (ATmega48PB, ATmega88PB, ATmega168PB): New - devices. + * avrdude.conf.in (ATmega48PB, ATmega88PB, ATmega168PB): New + devices. 2016-02-15 Joerg Wunsch - patch #8435: Implementing mEDBG CMSIS-DAP protocol - * usb_libusb.c: Add endpoint IDs for Xplained Mini, correctly - transfer trailing ZLP when needed - * avrdude.conf.in (xplainedmini, xplainedmini_dw): New entries. - * jtag3.c (jtag3_edbg_send, jtag3_edbg_recv_frame): Implement - fragmentation needed for the 64-byte EP size of the Xplained Mini - * avrdude.1: Document the change - * doc/avrdude.texi: (Dito.) + patch #8435: Implementing mEDBG CMSIS-DAP protocol + * usb_libusb.c: Add endpoint IDs for Xplained Mini, correctly + transfer trailing ZLP when needed + * avrdude.conf.in (xplainedmini, xplainedmini_dw): New entries. + * jtag3.c (jtag3_edbg_send, jtag3_edbg_recv_frame): Implement + fragmentation needed for the 64-byte EP size of the Xplained Mini + * avrdude.1: Document the change + * doc/avrdude.texi: (Dito.) diff --git a/src/avrdude/ChangeLog-2001 b/src/avrdude/ChangeLog-2001 index 048dcf1c239..340dad5d72a 100644 --- a/src/avrdude/ChangeLog-2001 +++ b/src/avrdude/ChangeLog-2001 @@ -1,598 +1,598 @@ 2001-12-30 Brian S. Dean - * main.c: Update version. + * main.c: Update version. - * avrdude.conf.sample: Clarify a comment. + * avrdude.conf.sample: Clarify a comment. - * avrdude.conf.sample: fix address bits + * avrdude.conf.sample: fix address bits - * avrdude.1: Bring up to date. + * avrdude.1: Bring up to date. 2001-12-29 Brian S. Dean - * avrdude.conf.sample: Add the AVR3 progammer. + * avrdude.conf.sample: Add the AVR3 progammer. - * avr.c, avrdude.conf.sample, config_gram.y, main.c, pindefs.h: - Fix VCC assertion. + * avr.c, avrdude.conf.sample, config_gram.y, main.c, pindefs.h: + Fix VCC assertion. - Make the BUFF pin a mask like VCC to allow multiple pins to be - asserted at the same time (STK200 has two buffer enable lines). + Make the BUFF pin a mask like VCC to allow multiple pins to be + asserted at the same time (STK200 has two buffer enable lines). - Add the STK200 programmer. + Add the STK200 programmer. - Fix EEPROM address line selection for several parts. + Fix EEPROM address line selection for several parts. 2001-12-15 Brian S. Dean - * avrdude.conf.sample: fix spelling error + * avrdude.conf.sample: fix spelling error 2001-11-24 Brian S. Dean - * Makefile: - Change "WARNING" to "NOTE" when overwriting the avrprog.conf file. + * Makefile: + Change "WARNING" to "NOTE" when overwriting the avrprog.conf file. - * avrdude.1: Add my e-mail address. + * avrdude.1: Add my e-mail address. - * avrdude.conf.sample: - Add comments about instruction formats. Correct an instruction - specification (cut&paste error). + * avrdude.conf.sample: + Add comments about instruction formats. Correct an instruction + specification (cut&paste error). 2001-11-21 Brian S. Dean - * avr.c, config_gram.y, lexer.l, term.c: - In interactive mode, reset the address and length if we start dumping - a memory type different than the previous one. - - * avr.c, avrdude.conf.sample, config_gram.y: - Allow instruction data to be specified more flexibly, which can be - used to make the instruction input more readable in the config file. - - * main.c: Bump version number. - - * Makefile, avr.c, avr.h, avrdude.conf.sample, config.c, config.h: - * config_gram.y, fileio.c, fileio.h, lexer.l, main.c, term.c: - This is a major re-write of the programming algorithms. The Atmel - serial programming instructions are not very orthoganal, i.e., the - "read fuse bits" instruction on an ATMega103 is an entirely different - opcode and data format from the _same_ instruction for an ATMega163! - Thus, it becomes impossible to have a single instruction encoding - (varying the data) across the chip lines. - - This set of changes allows and requires instruction encodings to be - defined on a per-part basis within the configuration file. Hopefully - I've defined the encoding scheme in a general enough way so it is - useful in describing the instruction formats for yet-to-be invented - Atmel chips. I've tried hard to make it match very closely with the - specification in Atmel's data sheets for their parts. It's a little - more verbose than what I initially hoped for, but I've tried to keep - it as concise as I could, while still remaining reasonably flexible. + * avr.c, config_gram.y, lexer.l, term.c: + In interactive mode, reset the address and length if we start dumping + a memory type different than the previous one. + + * avr.c, avrdude.conf.sample, config_gram.y: + Allow instruction data to be specified more flexibly, which can be + used to make the instruction input more readable in the config file. + + * main.c: Bump version number. + + * Makefile, avr.c, avr.h, avrdude.conf.sample, config.c, config.h: + * config_gram.y, fileio.c, fileio.h, lexer.l, main.c, term.c: + This is a major re-write of the programming algorithms. The Atmel + serial programming instructions are not very orthoganal, i.e., the + "read fuse bits" instruction on an ATMega103 is an entirely different + opcode and data format from the _same_ instruction for an ATMega163! + Thus, it becomes impossible to have a single instruction encoding + (varying the data) across the chip lines. + + This set of changes allows and requires instruction encodings to be + defined on a per-part basis within the configuration file. Hopefully + I've defined the encoding scheme in a general enough way so it is + useful in describing the instruction formats for yet-to-be invented + Atmel chips. I've tried hard to make it match very closely with the + specification in Atmel's data sheets for their parts. It's a little + more verbose than what I initially hoped for, but I've tried to keep + it as concise as I could, while still remaining reasonably flexible. 2001-11-19 Brian S. Dean - * avr.c, avr.h, avrdude.conf.sample, main.c, ppi.c, term.c: - Add support for ATMega163. + * avr.c, avr.h, avrdude.conf.sample, main.c, ppi.c, term.c: + Add support for ATMega163. - Add support for reading/writing ATMega163 lock and fuse bits. - Unfortunately, in looking at the specs for other ATMega parts, they - use entirely different instruction formats for these commands. Thus, - these routines won't work for the ATMega103, for example. + Add support for reading/writing ATMega163 lock and fuse bits. + Unfortunately, in looking at the specs for other ATMega parts, they + use entirely different instruction formats for these commands. Thus, + these routines won't work for the ATMega103, for example. - Add support for sending raw command bytes via the interactive terminal - interface. This allows one to execute any programming instruction on - the target device, whether or not avrprog supports it explicitly or - not. Thus, one can use this feature to program fuse / lock bits, or - access any other feature of a current or future device that avrprog - does not know how to do. + Add support for sending raw command bytes via the interactive terminal + interface. This allows one to execute any programming instruction on + the target device, whether or not avrprog supports it explicitly or + not. Thus, one can use this feature to program fuse / lock bits, or + access any other feature of a current or future device that avrprog + does not know how to do. - Add in comments, an experimental instruction format in the - configuration file. If this works out, it would allow supporting new - parts and non-orthoganal instructions across existing parts without - making avrprog code changes. + Add in comments, an experimental instruction format in the + configuration file. If this works out, it would allow supporting new + parts and non-orthoganal instructions across existing parts without + making avrprog code changes. 2001-11-17 Brian S. Dean - * avrdude.conf.sample: Add ATMEGA163 part. + * avrdude.conf.sample: Add ATMEGA163 part. 2001-11-11 Brian S. Dean - * main.c: output formatting + * main.c: output formatting 2001-11-05 Brian S. Dean - * ppi.c: Get ppi.h from /usr/include, not /sys. + * ppi.c: Get ppi.h from /usr/include, not /sys. 2001-10-31 Brian S. Dean - * avr.c, avrdude.conf.sample, main.c: Correct version string. - Update read/write status more frequently. - Prefix ATMega parts with an 'm'. + * avr.c, avrdude.conf.sample, main.c: Correct version string. + Update read/write status more frequently. + Prefix ATMega parts with an 'm'. 2001-10-16 Brian S. Dean - * avr.c: Change ording for memory display. + * avr.c: Change ording for memory display. - * config_gram.y: comment + * config_gram.y: comment - * avr.c, avr.h, avrdude.conf.sample, config_gram.y, lexer.l, term.c: - Fix (again, hopefully) page addressing for the ATMega parts. + * avr.c, avr.h, avrdude.conf.sample, config_gram.y, lexer.l, term.c: + Fix (again, hopefully) page addressing for the ATMega parts. - Rename the poorly chosen name "bank" to "page" for page addressing. - Atmel calls it "page" in their documentation. + Rename the poorly chosen name "bank" to "page" for page addressing. + Atmel calls it "page" in their documentation. - * config_gram.y, main.c: Fix an (non)exit. - Silence a couple of compiler warnings. + * config_gram.y, main.c: Fix an (non)exit. + Silence a couple of compiler warnings. - * avr.c, avr.h, avrdude.conf.sample, config_gram.y, main.c: - Fix ATMega flash addressing. Add an ATMEGA16 part. Perform sanity - checking on the memory parameters for parts that do bank addressing. + * avr.c, avr.h, avrdude.conf.sample, config_gram.y, main.c: + Fix ATMega flash addressing. Add an ATMEGA16 part. Perform sanity + checking on the memory parameters for parts that do bank addressing. 2001-10-15 Brian S. Dean - * config.c, config.h, lists.h: Add copyright. + * config.c, config.h, lists.h: Add copyright. - * config_gram.y, lexer.l, lists.c: Add copyrights. + * config_gram.y, lexer.l, lists.c: Add copyrights. - * Makefile: Attempt to install avrprog.conf. + * Makefile: Attempt to install avrprog.conf. - * avrdude.conf.sample: Correct dt006 pinout. + * avrdude.conf.sample: Correct dt006 pinout. - * Makefile, lexer.l: - Try and detect an old-style config file and print an appropriate error - message and a suggestion for correcting it. + * Makefile, lexer.l: + Try and detect an old-style config file and print an appropriate error + message and a suggestion for correcting it. - * Makefile, avr.c, avrdude.1, avrdude.conf.sample: Update the man page. + * Makefile, avr.c, avrdude.1, avrdude.conf.sample: Update the man page. - Miscellaneous minor cleanups. + Miscellaneous minor cleanups. 2001-10-14 Brian S. Dean - * Makefile, Makefile.inc, avr.c, avr.h, avrdude.conf.sample: - * config.c, config.h, config_gram.y, lexer.l, lists.c, lists.h: - * main.c, pindefs.h, term.c: - Use lex/yacc for parsing the config file. Re-work the config file - format using a more human-readable format. + * Makefile, Makefile.inc, avr.c, avr.h, avrdude.conf.sample: + * config.c, config.h, config_gram.y, lexer.l, lists.c, lists.h: + * main.c, pindefs.h, term.c: + Use lex/yacc for parsing the config file. Re-work the config file + format using a more human-readable format. - Read part descriptions from the config file now instead of hard-coding - them. + Read part descriptions from the config file now instead of hard-coding + them. - Update usage(). + Update usage(). - Cleanup unused code. + Cleanup unused code. - * Makefile, avr.c, avr.h, fileio.c, term.c: - First cut at supporting the ATmega 103 which uses bank addressing and - has a 128K flash. + * Makefile, avr.c, avr.h, fileio.c, term.c: + First cut at supporting the ATmega 103 which uses bank addressing and + has a 128K flash. - Due to the bank addressing required, interactive update of the flash - is not supported, though the eeprom can be updated interactively. - Both memories can be programmed via non-interactive mode. + Due to the bank addressing required, interactive update of the flash + is not supported, though the eeprom can be updated interactively. + Both memories can be programmed via non-interactive mode. - Intel Hex Record type '04' is now generated as required for outputing - memory contents that go beyond 64K. + Intel Hex Record type '04' is now generated as required for outputing + memory contents that go beyond 64K. 2001-10-13 Brian S. Dean - * avr.c, avr.h, fileio.c, fileio.h, main.c, ppi.c, ppi.h, term.c: - * term.h: - Style fixes. + * avr.c, avr.h, fileio.c, fileio.h, main.c, ppi.c, ppi.h, term.c: + * term.h: + Style fixes. - * avr.c, avr.h, fileio.c, fileio.h, main.c, term.c: - Commit changes in preparation for support the ATMega line. + * avr.c, avr.h, fileio.c, fileio.h, main.c, term.c: + Commit changes in preparation for support the ATMega line. 2001-10-01 Brian S. Dean - * Makefile: Don't override CFLAGS. + * Makefile: Don't override CFLAGS. - * avrdude.1: Correct default pin assignment. + * avrdude.1: Correct default pin assignment. - * avr.c, fileio.c, main.c, ppi.c, term.c: - Remove debugging code - it served its purpose. + * avr.c, fileio.c, main.c, ppi.c, term.c: + Remove debugging code - it served its purpose. - Update copyrights. + Update copyrights. 2001-09-21 Brian S. Dean - * main.c: - Be sure to read the exit specs after the pin configuration has been - assigned, otherwise, we may apply the exit specs to the wrong pins. + * main.c: + Be sure to read the exit specs after the pin configuration has been + assigned, otherwise, we may apply the exit specs to the wrong pins. - * main.c: debugging + * main.c: debugging 2001-09-20 Brian S. Dean - * avrdude.1, avrdude.conf.sample, main.c: - Prefix pin config entries in the config file with a "c:". Later, I - might make part descriptions read in this way and we can use a - different letter for those (p). This will make the parsing easier to - distinguish between the entry types. + * avrdude.1, avrdude.conf.sample, main.c: + Prefix pin config entries in the config file with a "c:". Later, I + might make part descriptions read in this way and we can use a + different letter for those (p). This will make the parsing easier to + distinguish between the entry types. - * main.c: Initialize pin configuration description. + * main.c: Initialize pin configuration description. 2001-09-19 Brian S. Dean - * AVRprog.pdf, Makefile, avr.c, avrdude.1, avrdude.conf.sample: - * avrdude.pdf, fileio.c, fileio.h, main.c, pindefs.h, term.c: - Make the pin definitions configurable based on entries in a config - file. This makes supporting other programmers much easier. + * AVRprog.pdf, Makefile, avr.c, avrdude.1, avrdude.conf.sample: + * avrdude.pdf, fileio.c, fileio.h, main.c, pindefs.h, term.c: + Make the pin definitions configurable based on entries in a config + file. This makes supporting other programmers much easier. - Rename AVRprog.pdf to avrprog.pdf. + Rename AVRprog.pdf to avrprog.pdf. 2001-04-29 Brian S. Dean - * avrprog-programmer.jpg: Remove this image file from the repository. + * avrprog-programmer.jpg: Remove this image file from the repository. 2001-04-26 Brian S. Dean - * avrprog-schematic.jpg: - Remove this image, use AVRprog.pdf as the preferred schematic for the - programmer. + * avrprog-schematic.jpg: + Remove this image, use AVRprog.pdf as the preferred schematic for the + programmer. 2001-04-25 Brian S. Dean - * AVRprog.pdf, Makefile, avrdude.1: - Add a schematic provided by Joerg Wunch and also update the manual - page (also updated by Joerg) to reference the schematic. + * AVRprog.pdf, Makefile, avrdude.1: + Add a schematic provided by Joerg Wunch and also update the manual + page (also updated by Joerg) to reference the schematic. 2001-02-25 Brian S. Dean - * Makefile, Makefile.inc: Automate dependency generation. + * Makefile, Makefile.inc: Automate dependency generation. 2001-02-08 Brian S. Dean - * main.c: Turn off ready led when finished programming. + * main.c: Turn off ready led when finished programming. - * main.c: update version + * main.c: update version - * avr.c, main.c: Correct a few comments. + * avr.c, main.c: Correct a few comments. - * Makefile, avr.c, term.c: Makefile : update dependencies + * Makefile, avr.c, term.c: Makefile : update dependencies - avr.c : correct status led updates + avr.c : correct status led updates - term.c : update status leds on write, make the address and length - arguments for dump optional. + term.c : update status leds on write, make the address and length + arguments for dump optional. 2001-01-26 Brian S. Dean - * main.c: Version 1.1 + * main.c: Version 1.1 - * main.c: - Hmmm ... cvs co -D does not work. Change the revision - timestamp to a full date/time value. + * main.c: + Hmmm ... cvs co -D does not work. Change the revision + timestamp to a full date/time value. - * avr.c, fileio.c, main.c, ppi.c, term.c: - Add a -V option to display the version information about each - component module. This is intended for support purposes, so that I - can tell unambiguously what version a binary out in the field is. + * avr.c, fileio.c, main.c, ppi.c, term.c: + Add a -V option to display the version information about each + component module. This is intended for support purposes, so that I + can tell unambiguously what version a binary out in the field is. - Additionally, display a revision timestamp along with the version - number. This also is intended for aiding in support and is the Unix - time of the latest component module. Having this, should allow me to - do a "cvs co -D timestamp avrprog" and get exactly the source of the - version that is being reported. + Additionally, display a revision timestamp along with the version + number. This also is intended for aiding in support and is the Unix + time of the latest component module. Having this, should allow me to + do a "cvs co -D timestamp avrprog" and get exactly the source of the + version that is being reported. - * fileio.c: - Return the maximum address (+1) written as opposed to the actual - number of bytes written. The presence of an Intel Hex address - record can cause these two number to be different; but the callers - of this routine need the former. + * fileio.c: + Return the maximum address (+1) written as opposed to the actual + number of bytes written. The presence of an Intel Hex address + record can cause these two number to be different; but the callers + of this routine need the former. - * main.c: - Fix a place where we were exiting without applying the exit-specs. + * main.c: + Fix a place where we were exiting without applying the exit-specs. - Wrap a long line. + Wrap a long line. - * avr.c, fileio.c: avr.c: Update a comment. + * avr.c, fileio.c: avr.c: Update a comment. - fileio.c: Properly handle all the Intel Hex record types that I can - find information about. + fileio.c: Properly handle all the Intel Hex record types that I can + find information about. 2001-01-25 Brian S. Dean - * Usage, avr.h: Get rid of the Usage file. + * Usage, avr.h: Get rid of the Usage file. 2001-01-24 Brian S. Dean - * Makefile, avr.c, avr.h, main.c, pindefs.h, ppi.c: - Move pin definitions to their own file. + * Makefile, avr.c, avr.h, main.c, pindefs.h, ppi.c: + Move pin definitions to their own file. - First pass at providing feedback via the optionally connected leds. I - don't actually have any of these attached to my programmer, so I can - only guess as whether this is toggling them on and off correctly. + First pass at providing feedback via the optionally connected leds. I + don't actually have any of these attached to my programmer, so I can + only guess as whether this is toggling them on and off correctly. - Also, enable and disable the optional 74367 buffer. + Also, enable and disable the optional 74367 buffer. - * avr.h, main.c, ppi.c, ppi.h, avr.c: - Rearrange the pinout for the programmer to be a little more logical. - Provide hooks to support a buffered programmer, pin 6 is now used to - enable a buffer that can be used to isolate the target system from the - parallel port pins. This is important when programming the target - in-system. + * avr.h, main.c, ppi.c, ppi.h, avr.c: + Rearrange the pinout for the programmer to be a little more logical. + Provide hooks to support a buffered programmer, pin 6 is now used to + enable a buffer that can be used to isolate the target system from the + parallel port pins. This is important when programming the target + in-system. - Totally change the way the pin definitions are defined. Actually - set/clear pins based on the way more intuitive pin number, instead of - PPI data register, bit number combination. A table of pin data is - used so that any hardware inversion done by the parallel port is - accounted for, what you set is actually what appears at the pin. - Retain the old method for handling Vcc, however, because the hold - method is much easier to use when setting / retrieving multiple pins - simultaneously. + Totally change the way the pin definitions are defined. Actually + set/clear pins based on the way more intuitive pin number, instead of + PPI data register, bit number combination. A table of pin data is + used so that any hardware inversion done by the parallel port is + accounted for, what you set is actually what appears at the pin. + Retain the old method for handling Vcc, however, because the hold + method is much easier to use when setting / retrieving multiple pins + simultaneously. 2001-01-22 Brian S. Dean - * Makefile: Don't gzip the man page. + * Makefile: Don't gzip the man page. - * avrdude.1: .Nm macro fix. Submitted by Joerg. + * avrdude.1: .Nm macro fix. Submitted by Joerg. - * main.c: Cosmetic, don't output a preceding linefeed for usage(). + * main.c: Cosmetic, don't output a preceding linefeed for usage(). - * Makefile, avr.c, avr.h, fileio.c, term.c: - Makefile : use gzip -f for man page installation so that we don't get - prompted. + * Makefile, avr.c, avr.h, fileio.c, term.c: + Makefile : use gzip -f for man page installation so that we don't get + prompted. - avr.c avr.h fileio.c term.c : + avr.c avr.h fileio.c term.c : - Change the avrpart data structure so that the typedef AVRMEM is - used as an index into an array for the sizes of the memory types - and also for pointers to buffers that represent the chip data for - that memory type. This removes a lot of conditional code of the - form: + Change the avrpart data structure so that the typedef AVRMEM is + used as an index into an array for the sizes of the memory types + and also for pointers to buffers that represent the chip data for + that memory type. This removes a lot of conditional code of the + form: - switch (memtype) { - case AVR_FLASH : - ... - } + switch (memtype) { + case AVR_FLASH : + ... + } - Also, re-code avr_read_byte() and avr_write_byte() to properly - handle the flash memory type without having to tell them whether - they should program the high byte or the low byte - figure that - out from the address itself. For flash memory type, these - routines now take the actual byte address instead of the word - address. This _greatly_ simplifies many otherwise simple - operations, such a reading or writing a range of memory, by not - having to worry about whether the address starts on an odd byte - or an even byte. + Also, re-code avr_read_byte() and avr_write_byte() to properly + handle the flash memory type without having to tell them whether + they should program the high byte or the low byte - figure that + out from the address itself. For flash memory type, these + routines now take the actual byte address instead of the word + address. This _greatly_ simplifies many otherwise simple + operations, such a reading or writing a range of memory, by not + having to worry about whether the address starts on an odd byte + or an even byte. 2001-01-20 Brian S. Dean - * avr.c, avr.h, fileio.c, fileio.h, main.c: - Return error codes instead of exiting, thus making sure that we exit - only via main() so that the exitspecs are properly applied. + * avr.c, avr.h, fileio.c, fileio.h, main.c: + Return error codes instead of exiting, thus making sure that we exit + only via main() so that the exitspecs are properly applied. - When reading input data from a file, remember how many bytes were read - and write and verify only that many bytes. + When reading input data from a file, remember how many bytes were read + and write and verify only that many bytes. - Don't complain when an input file size is smaller than the memory size - we are programming. This is normal. + Don't complain when an input file size is smaller than the memory size + we are programming. This is normal. - * fileio.c: - Correct checksum calculation; failure to account for the value of the - record type was causing non-zero record types to be calculated - incorrectly. + * fileio.c: + Correct checksum calculation; failure to account for the value of the + record type was causing non-zero record types to be calculated + incorrectly. - * Makefile, main.c: Makefile : install the man page + * Makefile, main.c: Makefile : install the man page - main.c : drop the giant usage text now that we have a man page. + main.c : drop the giant usage text now that we have a man page. - * avrdude.1: - Add initial man page graciously contributed by Joerg Wunsch. Thanks - Joerg! + * avrdude.1: + Add initial man page graciously contributed by Joerg Wunsch. Thanks + Joerg! 2001-01-19 Brian S. Dean - * term.c: - Accept abbreviations for eeprom and flash for the dump and write - commands. + * term.c: + Accept abbreviations for eeprom and flash for the dump and write + commands. - Fix small bug keeping 1 character command lines from being added to - the history. + Fix small bug keeping 1 character command lines from being added to + the history. - * term.c: - Implement enough state in cmd_dump so that if it is called with no - arguments, it successively dumps the next chunk of data of the same - previously specified length. + * term.c: + Implement enough state in cmd_dump so that if it is called with no + arguments, it successively dumps the next chunk of data of the same + previously specified length. - * term.c, term.h, fileio.c, fileio.h, main.c, ppi.c, ppi.h: - * Makefile, avr.c, avr.h, avrprog.c: - The program was getting too large for a single file. Split it up into - more modular pieces. + * term.c, term.h, fileio.c, fileio.h, main.c, ppi.c, ppi.h: + * Makefile, avr.c, avr.h, avrprog.c: + The program was getting too large for a single file. Split it up into + more modular pieces. - Also, accept command abbreviations as long as they are not ambiguous. + Also, accept command abbreviations as long as they are not ambiguous. - * avrprog.c: - Add ability to specify the state of the power and reset pins on - program exit. Default to leaving the pins in the state they were when - we found them. + * avrprog.c: + Add ability to specify the state of the power and reset pins on + program exit. Default to leaving the pins in the state they were when + we found them. - Contributed by: Joerg Wunsch + Contributed by: Joerg Wunsch 2001-01-18 Brian S. Dean - * Makefile, avrprog.c: - Switch to using readline() for getting terminal input. I can't seem - to get the history capabilities working yet, but even so, it does - better handling of the prompt and strips newlines for us, so it's - still a win. + * Makefile, avrprog.c: + Switch to using readline() for getting terminal input. I can't seem + to get the history capabilities working yet, but even so, it does + better handling of the prompt and strips newlines for us, so it's + still a win. - Add a few new commands for terminal mode: help, sig, part, erase. - Display rudimentory help using the help command. + Add a few new commands for terminal mode: help, sig, part, erase. + Display rudimentory help using the help command. - Add some function prototypes. + Add some function prototypes. - * Usage, avrprog.c: - Change -c (interactive command mode) to the more intuitive -t - (terminal mode). + * Usage, avrprog.c: + Change -c (interactive command mode) to the more intuitive -t + (terminal mode). - Make binary format the default for output. + Make binary format the default for output. - Update the parts table with corrections for old values and add some - new values. + Update the parts table with corrections for old values and add some + new values. 2001-01-15 Brian S. Dean - * avrprog.c: - Automatically verify on-chip data with what we just programmed. + * avrprog.c: + Automatically verify on-chip data with what we just programmed. - * avrprog.c, Makefile: - Prepare the Makefile for integration into the FreeBSD ports tree. + * avrprog.c, Makefile: + Prepare the Makefile for integration into the FreeBSD ports tree. - Fix a few "may be used uninitialized" bugs found by -Wall. + Fix a few "may be used uninitialized" bugs found by -Wall. 2001-01-14 Brian S. Dean - * avrprog.c: Free a buffer. + * avrprog.c: Free a buffer. - * avrprog.c: - Use a smarter programming algorithm - read the existing data byte - first and only write the new one if it is different. + * avrprog.c: + Use a smarter programming algorithm - read the existing data byte + first and only write the new one if it is different. - Add -n option which is a test mode in which the chip is not actually - updated. This option does not affect writes in interactive mode. + Add -n option which is a test mode in which the chip is not actually + updated. This option does not affect writes in interactive mode. - * avrprog.c: Add the "dump" and "write" interactive commands. + * avrprog.c: Add the "dump" and "write" interactive commands. - * avrprog.c: - Correctly produce and handle "end of record" for intel hex files. + * avrprog.c: + Correctly produce and handle "end of record" for intel hex files. 2001-01-13 Brian S. Dean - * avrprog.c: - Re-enable writing to the chip. I should probably should make this a - command-line selectable option so that I don't keep forgetting and - committing it with it disabled. + * avrprog.c: + Re-enable writing to the chip. I should probably should make this a + command-line selectable option so that I don't keep forgetting and + committing it with it disabled. - * avrprog.c: - Add a newline before exiting due to command line errors. Perform a - bit more option compatibility testing between -c, -i, and -o. + * avrprog.c: + Add a newline before exiting due to command line errors. Perform a + bit more option compatibility testing between -c, -i, and -o. - * avrprog.c: Add input file format auto-detection support. + * avrprog.c: Add input file format auto-detection support. - * Usage, avrprog.c: Say what the defaults are. + * Usage, avrprog.c: Say what the defaults are. - * avrprog-programmer.jpg, Usage, avrprog-schematic.jpg: New files. + * avrprog-programmer.jpg, Usage, avrprog-schematic.jpg: New files. - * avrprog.c: Correct usage text. + * avrprog.c: Correct usage text. - * avrprog.c: - Parameterize a few additional items per chip. Print out all per-chip - parameters on startup. Use the per-chip parameters in the code - instead of hard-coded values for the 2313. + * avrprog.c: + Parameterize a few additional items per chip. Print out all per-chip + parameters on startup. Use the per-chip parameters in the code + instead of hard-coded values for the 2313. - * avrprog.c: Fix filename assignment error. + * avrprog.c: Fix filename assignment error. - Clean up debugging code a little, utilize fileio() instead of making - direct calls to b2ihex(). + Clean up debugging code a little, utilize fileio() instead of making + direct calls to b2ihex(). - * avrprog.c: A lot of general code cleanup. + * avrprog.c: A lot of general code cleanup. - Re-work command line options to be more intuitive. + Re-work command line options to be more intuitive. - Support Intel Hex input and output file formats. Provide hooks to - support Motorola S-Record as well. + Support Intel Hex input and output file formats. Provide hooks to + support Motorola S-Record as well. - Add a few more part-specific parameters to the avrpart structure. + Add a few more part-specific parameters to the avrpart structure. - Only write the flash or eeprom if the data to be written is not 0xff. + Only write the flash or eeprom if the data to be written is not 0xff. 2000-12-31 Brian S. Dean - * avrprog.c: Update a comment. + * avrprog.c: Update a comment. - * avrprog.c: - Provide the ability to tie additionally tie pins 6-9 of the parallel - port to Vcc in order to supply more current. + * avrprog.c: + Provide the ability to tie additionally tie pins 6-9 of the parallel + port to Vcc in order to supply more current. - Fix a typo on the size of the S1200's Flash. + Fix a typo on the size of the S1200's Flash. - Bring RESET low when programming is completed. + Bring RESET low when programming is completed. - * avrprog.c: - Correct pin connection comments. Elaborate a bit on Vcc connection. + * avrprog.c: + Correct pin connection comments. Elaborate a bit on Vcc connection. - * avrprog.c: - Update after receiving some good feedback from Joerg Wunsch. We - should now be able to program AT90S1200's. + * avrprog.c: + Update after receiving some good feedback from Joerg Wunsch. We + should now be able to program AT90S1200's. 2000-12-30 Brian S. Dean - * avrprog.c: Don't limit eeprom addresses. + * avrprog.c: Don't limit eeprom addresses. 2000-12-20 Brian S. Dean - * Makefile, avrprog.c: - Add support for the 8515. Make the addition for other devices easier. + * Makefile, avrprog.c: + Add support for the 8515. Make the addition for other devices easier. 2000-08-27 Brian S. Dean - * avrprog.c: - Clear all bits except AVR_RESET when finished reading or programming - the Atmel device. + * avrprog.c: + Clear all bits except AVR_RESET when finished reading or programming + the Atmel device. 2000-08-07 Brian S. Dean - * avrprog.c: update announcement message + * avrprog.c: update announcement message - * avrprog.c: Update announcement message. + * avrprog.c: Update announcement message. - * avrprog.c: Return the correct return code from 'main()'. + * avrprog.c: Return the correct return code from 'main()'. - * avrprog.c: - Add ppi_pulse() function and fix ppi_toggle() to actully toggle - instead of pulse. + * avrprog.c: + Add ppi_pulse() function and fix ppi_toggle() to actully toggle + instead of pulse. - Make all abnormal returns after the parallel port has been opened go - through a single exit point at the bottom of 'main()'. + Make all abnormal returns after the parallel port has been opened go + through a single exit point at the bottom of 'main()'. 2000-08-06 Brian S. Dean - * Makefile, avrprog.c: Makefile: add --pedantic compiler option + * Makefile, avrprog.c: Makefile: add --pedantic compiler option - avrprog.c: + avrprog.c: - Add lots of comments, move getop() variable declarations to - the top of the program. + Add lots of comments, move getop() variable declarations to + the top of the program. - Add a typedef name to the AVR memory type and use it for - function declarations. + Add a typedef name to the AVR memory type and use it for + function declarations. - Add a usleep() delay in the sense loop to avoid becoming a cpu - hog. + Add a usleep() delay in the sense loop to avoid becoming a cpu + hog. - Print out a version string so that folks know what version of - the software they are running. + Print out a version string so that folks know what version of + the software they are running. - Be sure and close the parallel device and the i/o file when - terminating abnormally. + Be sure and close the parallel device and the i/o file when + terminating abnormally. - * avrprog.c: Print out version information when invoked. + * avrprog.c: Print out version information when invoked. - * Makefile, avrprog.c: Makefile: Add an install target. + * Makefile, avrprog.c: Makefile: Add an install target. - avrprog.c: + avrprog.c: - Add license. + Add license. - Document the header a bit better. + Document the header a bit better. - Add capability to read out and display the device signature bytes. + Add capability to read out and display the device signature bytes. - Add capability to power the device from the parallel port. + Add capability to power the device from the parallel port. - Eliminate debug print facility. + Eliminate debug print facility. - Provide 'avr_cmd()' function. + Provide 'avr_cmd()' function. - When memory locations don't program, generate a newline so that the - information is not overwritten and lost. + When memory locations don't program, generate a newline so that the + information is not overwritten and lost. - Don't print out the message about needing to specify a file if the - user is not requesting an operation that requires the file. + Don't print out the message about needing to specify a file if the + user is not requesting an operation that requires the file. 2000-08-05 Brian S. Dean - * avrprog.c: Pring usage when no arguments are supplied. + * avrprog.c: Pring usage when no arguments are supplied. - * Makefile, avrprog.c: Initial check-in + * Makefile, avrprog.c: Initial check-in - * Makefile, avrprog.c: New file. + * Makefile, avrprog.c: New file. diff --git a/src/avrdude/ChangeLog-2002 b/src/avrdude/ChangeLog-2002 index 9bfa030a97f..b7a37b29123 100644 --- a/src/avrdude/ChangeLog-2002 +++ b/src/avrdude/ChangeLog-2002 @@ -1,237 +1,237 @@ 2002-12-12 Brian S. Dean - * main.c: minor cleanup + * main.c: minor cleanup 2002-12-07 Brian S. Dean - * avrdude.1, main.c: - If the stk500 is being used, default to using the first serial port. + * avrdude.1, main.c: + If the stk500 is being used, default to using the first serial port. 2002-12-03 Brian S. Dean - * avrdude.1: Mention STK500 support. + * avrdude.1: Mention STK500 support. 2002-12-01 Brian S. Dean - * stk500.c: Remove unused code. + * stk500.c: Remove unused code. - * CHANGELOG, stk500.c: - Document changes since the previous version in the CHANGELOG. + * CHANGELOG, stk500.c: + Document changes since the previous version in the CHANGELOG. - Cleanup stk500.c a bit. + Cleanup stk500.c a bit. - * stk500.c: Fix cut and paste braino. + * stk500.c: Fix cut and paste braino. - * avr.c, avrdude.conf.sample, main.c, pgm.h, stk500.c: - The STK500 can perform paged read/write operations even on standard - "non-paged" parts. Take advantage of that and use the faster internal - routines of the STK500 for those parts as well. + * avr.c, avrdude.conf.sample, main.c, pgm.h, stk500.c: + The STK500 can perform paged read/write operations even on standard + "non-paged" parts. Take advantage of that and use the faster internal + routines of the STK500 for those parts as well. - * avr.c, avr.h, avrpart.h, main.c, pgm.c, pgm.h, stk500.c: - Optimize reading and writing for the STK500 programmer if the part - supports paged reads and writes. This greatly decreases the - program/verify time from about 4.5 minutes down to about 10 seconds in - a 12K program size test case. + * avr.c, avr.h, avrpart.h, main.c, pgm.c, pgm.h, stk500.c: + Optimize reading and writing for the STK500 programmer if the part + supports paged reads and writes. This greatly decreases the + program/verify time from about 4.5 minutes down to about 10 seconds in + a 12K program size test case. - Print out the hardware and firmware version for the STK500 if verbose - is enabled. + Print out the hardware and firmware version for the STK500 if verbose + is enabled. - * avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l, pgm.h: - * ppi.c, ppi.h, stk500.c, stk500.h, stk500_private.h: - Add basic support for STK500. + * avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l, pgm.h: + * ppi.c, ppi.h, stk500.c, stk500.h, stk500_private.h: + Add basic support for STK500. 2002-11-30 Brian S. Dean - * avrdude.conf.sample, config.c, config.h, config_gram.y, lexer.l: - * main.c, pgm.c, pgm.h, ppi.c, ppi.h, term.c, term.h, Makefile: - * avr.c, avr.h: - Seperate programmer operations out into a driver-like interface so - that programmers other than the direct parallel port connection can be - supported. + * avrdude.conf.sample, config.c, config.h, config_gram.y, lexer.l: + * main.c, pgm.c, pgm.h, ppi.c, ppi.h, term.c, term.h, Makefile: + * avr.c, avr.h: + Seperate programmer operations out into a driver-like interface so + that programmers other than the direct parallel port connection can be + supported. 2002-11-23 Brian S. Dean - * CHANGELOG, main.c, term.c: - term.c - when in interactive terminal mode and dumping memory using - the 'dump ' command without any address information, - and the end of memory is reached, wrap back around to zero on - the next invocation. + * CHANGELOG, main.c, term.c: + term.c - when in interactive terminal mode and dumping memory using + the 'dump ' command without any address information, + and the end of memory is reached, wrap back around to zero on + the next invocation. - CHANGELOG - describe changes + CHANGELOG - describe changes - main.c - update version number + main.c - update version number - * main.c: - When getting ready to initiate communications with the AVR device, - first pull /RESET low for a short period of time before enabling the - buffer chip. This sequence allows the AVR to be reset before the - buffer is enabled to avoid a short period of time where the AVR may be - driving the programming lines at the same time the programmer tries - to. Of course, if a buffer is being used, then the /RESET line from - the programmer needs to be directly connected to the AVR /RESET line - and not via the buffer chip. + * main.c: + When getting ready to initiate communications with the AVR device, + first pull /RESET low for a short period of time before enabling the + buffer chip. This sequence allows the AVR to be reset before the + buffer is enabled to avoid a short period of time where the AVR may be + driving the programming lines at the same time the programmer tries + to. Of course, if a buffer is being used, then the /RESET line from + the programmer needs to be directly connected to the AVR /RESET line + and not via the buffer chip. 2002-11-06 Brian S. Dean - * CHANGELOG: Update changelog. + * CHANGELOG: Update changelog. - * avr.c, avr.h, main.c: Fix -Y option. Reported by Joerg Wunsch. + * avr.c, avr.h, main.c: Fix -Y option. Reported by Joerg Wunsch. 2002-11-01 Brian S. Dean - * CHANGELOG, main.c: Version update and CHANGELOG entry. + * CHANGELOG, main.c: Version update and CHANGELOG entry. - * avr.c: - Be backward compatible with the 2-byte rewrite cycle counter which - appeared in version 2.1.0, but was changed to a 4 byte counter in - version 2.1.1. Reminded by Joerg Wunsch. + * avr.c: + Be backward compatible with the 2-byte rewrite cycle counter which + appeared in version 2.1.0, but was changed to a 4 byte counter in + version 2.1.1. Reminded by Joerg Wunsch. 2002-10-29 Brian S. Dean - * CHANGELOG, avrdude.1, main.c: - Add '-V' (no verify) flag requested by Joerg Wunsch. Update the man - page. + * CHANGELOG, avrdude.1, main.c: + Add '-V' (no verify) flag requested by Joerg Wunsch. Update the man + page. 2002-10-13 Brian S. Dean - * CHANGELOG, avrdude.1: Update man page and changelog. + * CHANGELOG, avrdude.1: Update man page and changelog. - * main.c: Update version number. + * main.c: Update version number. 2002-10-12 Brian S. Dean - * Makefile: Remove --pedantic and -g from the compiler options. + * Makefile: Remove --pedantic and -g from the compiler options. 2002-10-11 Brian S. Dean - * avr.c, term.c: - Use a four byte value instead of a two byte value for the programming - cycle count stored at the end of EEPROM. It seems as though Atmel was - greatly conservative in claiming a 1000 count reliability for the - FLASH. I current have a part that has been reprogrammed 173330 times, - and counting. + * avr.c, term.c: + Use a four byte value instead of a two byte value for the programming + cycle count stored at the end of EEPROM. It seems as though Atmel was + greatly conservative in claiming a 1000 count reliability for the + FLASH. I current have a part that has been reprogrammed 173330 times, + and counting. - Fix a compiler warning. + Fix a compiler warning. - * avrdude.conf.sample: - Fix ATMega128 instruction encoding for reading the low and high fuse - bits. Thanks to Joerg Wunsch for tripping over this. + * avrdude.conf.sample: + Fix ATMega128 instruction encoding for reading the low and high fuse + bits. Thanks to Joerg Wunsch for tripping over this. 2002-08-01 Brian S. Dean - * avr.c, avrdude.1, main.c: - Move erase-rewrite cycle increment to within the chip erase routine so - that it is tracked no matter where the erase was initiated: command - line mode or interactive mode, without code duplicaiton. + * avr.c, avrdude.1, main.c: + Move erase-rewrite cycle increment to within the chip erase routine so + that it is tracked no matter where the erase was initiated: command + line mode or interactive mode, without code duplicaiton. - * CHANGELOG: Recent updates. + * CHANGELOG: Recent updates. - * avr.c: Eliminate unused variables. + * avr.c: Eliminate unused variables. - * avr.c, avr.h, avrdude.1, fileio.c, main.c: - Implement a way of tracking how many erase-rewrite cycles a part has - undergone. This utilizes the last two bytes of EEPROM to maintain a - counter that is incremented each time the part is erased. + * avr.c, avr.h, avrdude.1, fileio.c, main.c: + Implement a way of tracking how many erase-rewrite cycles a part has + undergone. This utilizes the last two bytes of EEPROM to maintain a + counter that is incremented each time the part is erased. 2002-07-27 Brian S. Dean - * avr.c, main.c: - Fix a typo in a comment. Display the size of memory being written. - Display the correct memory name in an error message (previously - hardcoded). + * avr.c, main.c: + Fix a typo in a comment. Display the size of memory being written. + Display the correct memory name in an error message (previously + hardcoded). 2002-06-22 Brian S. Dean - * CHANGELOG, avrdude.conf.sample: - Add support for ATtiny15 - contributed by Asher Hoskins - + * CHANGELOG, avrdude.conf.sample: + Add support for ATtiny15 - contributed by Asher Hoskins + 2002-04-23 Brian S. Dean - * CHANGELOG: Say what changed. + * CHANGELOG: Say what changed. 2002-04-07 Brian S. Dean - * Makefile, avrdude.conf.sample: - Backup the config file to a timestamped name to keep from possibly - overwriting user-modified configs. + * Makefile, avrdude.conf.sample: + Backup the config file to a timestamped name to keep from possibly + overwriting user-modified configs. - Add read/write instructions for all memory types for ATMEGA103, - ATMEGA128, ATMEGA16, and ATMEGA8. + Add read/write instructions for all memory types for ATMEGA103, + ATMEGA128, ATMEGA16, and ATMEGA8. 2002-04-05 Brian S. Dean - * avrdude.conf.sample: - Add support for ATMEGA128; untested; requested by Jeff Gardner - . + * avrdude.conf.sample: + Add support for ATMEGA128; untested; requested by Jeff Gardner + . 2002-02-15 Brian S. Dean - * avrdude.conf.sample: Minor ordering. + * avrdude.conf.sample: Minor ordering. - * CHANGELOG, main.c: Update version numbers. + * CHANGELOG, main.c: Update version numbers. 2002-02-14 Brian S. Dean - * CHANGELOG: Summarize latest updates. + * CHANGELOG: Summarize latest updates. - * avrdude.conf.sample, config_gram.y: - Make pwroff_after_write a yes/no field instead of a numeric. + * avrdude.conf.sample, config_gram.y: + Make pwroff_after_write a yes/no field instead of a numeric. - * avrdude.conf.sample: Document the pwroff_after_write flag. + * avrdude.conf.sample: Document the pwroff_after_write flag. - * avr.c: Enable the extra part verbosity when verbosity >= 3. + * avr.c: Enable the extra part verbosity when verbosity >= 3. - * avr.c, avr.h, avrdude.conf.sample, config_gram.y, lexer.l: - * main.c, term.c: - Fix error reporting by avr_write_byte(). + * avr.c, avr.h, avrdude.conf.sample, config_gram.y, lexer.l: + * main.c, term.c: + Fix error reporting by avr_write_byte(). - Fix setting of status LEDs under various write-fail conditions. + Fix setting of status LEDs under various write-fail conditions. - Add a flag to indicate that a memory type requires the device to - possibly be powered off and back on after a write to it. This is due - to a hardware problem on some Atmel devices, see: + Add a flag to indicate that a memory type requires the device to + possibly be powered off and back on after a write to it. This is due + to a hardware problem on some Atmel devices, see: - http://www.atmel.com/atmel/acrobat/doc1280.pdf + http://www.atmel.com/atmel/acrobat/doc1280.pdf - Add greater verbosity to the part-display code when verbose>1 to - display avrprog's encoding of the defined programming instructions. - This is primarily for debugging purposes. + Add greater verbosity to the part-display code when verbose>1 to + display avrprog's encoding of the defined programming instructions. + This is primarily for debugging purposes. - Part updates: + Part updates: - * add the AT90S4414 part + * add the AT90S4414 part - * add fuse and lock bit access instructions for the AT90S1200, - AT90S4434, and AT90S8515. + * add fuse and lock bit access instructions for the AT90S1200, + AT90S4434, and AT90S8515. - * add the pwroff_after_write flag to the fuse bits for the AT90S2333 - and AT90S4433 parts + * add the pwroff_after_write flag to the fuse bits for the AT90S2333 + and AT90S4433 parts 2002-02-09 Brian S. Dean - * avrdude.conf.sample: - Updates to the 2333 and 4433 parts, contributed by Joerg Wunsh. + * avrdude.conf.sample: + Updates to the 2333 and 4433 parts, contributed by Joerg Wunsh. 2002-01-18 Brian S. Dean - * CHANGELOG: Add changelog. + * CHANGELOG: Add changelog. 2002-01-12 Brian S. Dean - * main.c: Add (c) to copyright. + * main.c: Add (c) to copyright. - * fileio.c, fileio.h, lexer.l, lists.c, lists.h, main.c: - * pindefs.h, ppi.c, ppi.h, term.c, term.h, avr.c, avr.h: - * config.c, config.h, config_gram.y: - Update version number. Update copyright. + * fileio.c, fileio.h, lexer.l, lists.c, lists.h, main.c: + * pindefs.h, ppi.c, ppi.h, term.c, term.h, avr.c, avr.h: + * config.c, config.h, config_gram.y: + Update version number. Update copyright. - * avrdude.1: Update copyright and add description of "default". + * avrdude.1: Update copyright and add description of "default". - Submitted by: Joerg Wunsch + Submitted by: Joerg Wunsch - * avr.c, term.c: - Fix programming of write-only memories (such as lock bits on the - 2313). + * avr.c, term.c: + Fix programming of write-only memories (such as lock bits on the + 2313). diff --git a/src/avrdude/ChangeLog-2003 b/src/avrdude/ChangeLog-2003 index 1115bdfbc1f..f7e19d4b0c5 100644 --- a/src/avrdude/ChangeLog-2003 +++ b/src/avrdude/ChangeLog-2003 @@ -1,1095 +1,1095 @@ 2003-12-01 Eric B. Weddington - * doc/avrdude.texi: Update devices and programmers supported. + * doc/avrdude.texi: Update devices and programmers supported. 2003-12-01 Eric B. Weddington - * doc/avrdude.texi: Add missing -D option to user manual. - [This fixes bug #6804] + * doc/avrdude.texi: Add missing -D option to user manual. + [This fixes bug #6804] 2003-11-30 Jan-Hinnerk Reichert - * avrpart.c,main.c: Moved list_parts() and locate_part() - from main.c to avrpart.c. - * avrpart.h: Added prototypes for list_parts() and - locate_part(). + * avrpart.c,main.c: Moved list_parts() and locate_part() + from main.c to avrpart.c. + * avrpart.h: Added prototypes for list_parts() and + locate_part(). 2003-11-30 Jan-Hinnerk Reichert - * avrpart.c, avr.c: Moved elementary functions on types - OPCODE, AVRMEM and AVRPART from avr.c to new file avrpart.c. - * avr.h: Removed prototypes for moved functions. - * avrpart.h: Added prototypes for functions in avrpart.c. - * Makefile.am: Added new file avrpart.c. + * avrpart.c, avr.c: Moved elementary functions on types + OPCODE, AVRMEM and AVRPART from avr.c to new file avrpart.c. + * avr.h: Removed prototypes for moved functions. + * avrpart.h: Added prototypes for functions in avrpart.c. + * Makefile.am: Added new file avrpart.c. 2003-11-28 Michael Mayer - * lexer.l: New programmer type "butterfly". - * config_gram.y: New token K_BUTTERFLY. - * avrdude.conf.in: Added programmer definition. - * butterfly.c, butterfly.h: Cloned from avr910.?, changed to work - with the Atmel Butterfly device. - * Makefile.am: Added butterfly.[ch] to avrdude_SOURCES. + * lexer.l: New programmer type "butterfly". + * config_gram.y: New token K_BUTTERFLY. + * avrdude.conf.in: Added programmer definition. + * butterfly.c, butterfly.h: Cloned from avr910.?, changed to work + with the Atmel Butterfly device. + * Makefile.am: Added butterfly.[ch] to avrdude_SOURCES. 2003-11-26 Joerg Wunsch - * main.c: Make the -U parser tolerate colons in filenames. - * avrdude.1, doc/avrdude.texi: Document the -U changes. + * main.c: Make the -U parser tolerate colons in filenames. + * avrdude.1, doc/avrdude.texi: Document the -U changes. 2003-11-21 Jan-Hinnerk Reichert - * ppi.c: Major speed tuning. Since ioctl() is expensive read from - shadowregisters where possible. + * ppi.c: Major speed tuning. Since ioctl() is expensive read from + shadowregisters where possible. 2003-11-19 Eric B. Weddington - * NEWS: Update news from items in ChangeLog. + * NEWS: Update news from items in ChangeLog. 2003-11-19 Theodore A. Roth [Contributed by Jan-Hinnerk Reichert ] - * avr.c (avr_write_byte_default): Improve polling algorithm to speed up - programming of byte oriented parallel programmers. + * avr.c (avr_write_byte_default): Improve polling algorithm to speed up + programming of byte oriented parallel programmers. 2003-11-14 Brian S. Dean [Contributed by Erik Christiansen ] - * avrdude.conf.in: - Add ATmega64 part. + * avrdude.conf.in: + Add ATmega64 part. 2003-11-08 Joerg Wunsch - * avrdude.conf.in: - Add "fuse" and "lock" definitions for the AT90S8535. Actually, - this is stolen from the AT90S8515 since the datasheet says it's - the same there. + * avrdude.conf.in: + Add "fuse" and "lock" definitions for the AT90S8535. Actually, + this is stolen from the AT90S8515 since the datasheet says it's + the same there. 2003-10-13 Bill Somerville - * stk500.c (stk500_paged_write): Limit blocks written to no bigger - than memory device size. - (stk500_paged_write): Send whole block at once. - (stk500_paged_load): Limit blocks read to no bigger than memory - device size. - [This fixes bug #5713.] + * stk500.c (stk500_paged_write): Limit blocks written to no bigger + than memory device size. + (stk500_paged_write): Send whole block at once. + (stk500_paged_load): Limit blocks read to no bigger than memory + device size. + [This fixes bug #5713.] 2003-10-13 Eric B. Weddington - * avrdude.conf.in: Fix for unterminated character error. + * avrdude.conf.in: Fix for unterminated character error. 2003-10-13 Eric B. Weddington - * avrdude.conf.in: Add ATmega8515 definition. - Contributed by: Matthias Weißer - * NEWS: Add note about ATmega8515 definition. + * avrdude.conf.in: Add ATmega8515 definition. + Contributed by: Matthias Weißer + * NEWS: Add note about ATmega8515 definition. 2003-09-24 Eric B. Weddington - * doc/TODO: Updated TODO list. + * doc/TODO: Updated TODO list. 2003-09-22 Eric B. Weddington - * windows/Makefile.am: Correct makefile so loaddrv does not link - to Cygwin DLL. + * windows/Makefile.am: Correct makefile so loaddrv does not link + to Cygwin DLL. 2003-09-18 Eric B. Weddington - * doc/avrdude.texi: Minor corrections. Change description of -P - to reference platform dependencies. + * doc/avrdude.texi: Minor corrections. Change description of -P + to reference platform dependencies. 2003-09-16 Eric B. Weddington - * stk500.c: If writing flash, skip empty pages in paged write. + * stk500.c: If writing flash, skip empty pages in paged write. 2003-09-06 Theodore A. Roth - * NEWS: Add 'Current:' header. - * configure.ac (AC_INIT): Add cvs back to version since we're - back in dev cycle (post release). + * NEWS: Add 'Current:' header. + * configure.ac (AC_INIT): Add cvs back to version since we're + back in dev cycle (post release). 2003-09-06 Theodore A. Roth - * AVRDUDE 4.2.0 has been released (cvs release tag is "release_4_2_0"). + * AVRDUDE 4.2.0 has been released (cvs release tag is "release_4_2_0"). 2003-09-06 Theodore A. Roth - * NEWS: Update for 4.2.0 release. Add note about read/write of fuses - support for avr910. - * configure.ac (AC_INIT): Set version to 4.2.0. + * NEWS: Update for 4.2.0 release. Add note about read/write of fuses + support for avr910. + * configure.ac (AC_INIT): Set version to 4.2.0. 2003-09-05 Theodore A. Roth [Contributed by Jan-Hinnerk Reichert ] - * avr.c (avr_read_byte): If pgm->read_byte method fails, retry with - avr_read_byte_default. - * avr.c (avr_write_byte): If pgm->write_byte method fails, retry with - avr_write_byte_default. - * avr910.c (avr910_cmd): Implement using universal command. + * avr.c (avr_read_byte): If pgm->read_byte method fails, retry with + avr_read_byte_default. + * avr.c (avr_write_byte): If pgm->write_byte method fails, retry with + avr_write_byte_default. + * avr910.c (avr910_cmd): Implement using universal command. 2003-09-04 Theodore A. Roth - * Makefile.am: Change AM_CPPFLAGS to avrdude_CPPFLAGS. - Define avrdude_CFLAGS. - * configure.ac: Set ENABLE_WARNINGS to "-Wall" if using gcc. + * Makefile.am: Change AM_CPPFLAGS to avrdude_CPPFLAGS. + Define avrdude_CFLAGS. + * configure.ac: Set ENABLE_WARNINGS to "-Wall" if using gcc. 2003-09-02 Eric B. Weddington - * doc/avrdude.texi: Add note about privileges needed to load - the giveio driver for Windows. + * doc/avrdude.texi: Add note about privileges needed to load + the giveio driver for Windows. 2003-08-29 Brian S. Dean - * avrdude.1: - * main.c: - Perform an auto erase before programming if the flash memory is - anywhere specified to be written by any of the -U requests. + * avrdude.1: + * main.c: + Perform an auto erase before programming if the flash memory is + anywhere specified to be written by any of the -U requests. - To remain backward compatible with previous versions, disable this - feature if any of the old-style memory specification operations are - specified (-i, -o). + To remain backward compatible with previous versions, disable this + feature if any of the old-style memory specification operations are + specified (-i, -o). - Implement the -D option to explicitly disable the auto erase default. + Implement the -D option to explicitly disable the auto erase default. - Deprecate the old-style memory specification options (-f, -i, -I, -m, - and -o) in favor of the new -U option which allows one to operate on - multiple memories on a single command line. + Deprecate the old-style memory specification options (-f, -i, -I, -m, + and -o) in favor of the new -U option which allows one to operate on + multiple memories on a single command line. 2003-08-28 Eric B. Weddington - * avr910.c: - * fileio.c: - * main.c: - * stk500.c: - More code cleanup to remove warnings. + * avr910.c: + * fileio.c: + * main.c: + * stk500.c: + More code cleanup to remove warnings. 2003-08-27 Theodore A. Roth - * main.c (update_progress_no_tty): Properly terminate progress. Also - fixes stk500 problem where number of bytes written is less than a page. + * main.c (update_progress_no_tty): Properly terminate progress. Also + fixes stk500 problem where number of bytes written is less than a page. 2003-08-27 Theodore A. Roth - * avrdude.spec.in: Fix broken rpmbuild on RedHat-9. + * avrdude.spec.in: Fix broken rpmbuild on RedHat-9. 2003-08-25 Eric B. Weddington - * fileio.c: - * main.c: - * ppiwin.c: - * ser_posix.c: - * stk500.c: - Minor code cleanup to remove warnings. + * fileio.c: + * main.c: + * ppiwin.c: + * ser_posix.c: + * stk500.c: + Minor code cleanup to remove warnings. 2003-08-21 Brian S. Dean - * avrdude.1: - * main.c: + * avrdude.1: + * main.c: - Introduce a new option, -U, for performing memory operions. - Its argument is a 4 field string (fields seperated by colons) - which indicate what memory type to operate on, what operation - to perform is (read, write, or verify), the filename to read - from, write to, or verify against, and an optional file format - field. Multple -U options can be specified to operate on more - than one memory at a time with a single invocation. For - example, to update both the flash and the eeprom at the same - time one can now specify the following: + Introduce a new option, -U, for performing memory operions. + Its argument is a 4 field string (fields seperated by colons) + which indicate what memory type to operate on, what operation + to perform is (read, write, or verify), the filename to read + from, write to, or verify against, and an optional file format + field. Multple -U options can be specified to operate on more + than one memory at a time with a single invocation. For + example, to update both the flash and the eeprom at the same + time one can now specify the following: - avrdude -p -e -U flash:w:main.hex:i -U eeprom:w:eeprom.hex:i + avrdude -p -e -U flash:w:main.hex:i -U eeprom:w:eeprom.hex:i 2003-08-20 Brian S. Dean - * ppiwin.c: - Timing related fixes for the Windows platform. Several folks have - reported that this patch fixes verify errors on the Windows platform - that are apparently timing related. Submitted by: Alex Shepherd - , who indicates that this patch was based on - code from the UISP project. + * ppiwin.c: + Timing related fixes for the Windows platform. Several folks have + reported that this patch fixes verify errors on the Windows platform + that are apparently timing related. Submitted by: Alex Shepherd + , who indicates that this patch was based on + code from the UISP project. 2003-08-01 Theodore A. Roth - * avrdude.1: Document the -q option. - * doc/avrdude.texi: Document the -q option. - Fix some typos left over from pasting in man output. + * avrdude.1: Document the -q option. + * doc/avrdude.texi: Document the -q option. + Fix some typos left over from pasting in man output. 2003-07-30 Brian S. Dean - * main.c: Add elapsed time information to the new progress bar. + * main.c: Add elapsed time information to the new progress bar. 2003-07-29 Theodore A. Roth - * avr.c: - * avr.h: - * avr910.c: - * main.c: - * stk500.c: - New progress reporting implementation. + * avr.c: + * avr.h: + * avr910.c: + * main.c: + * stk500.c: + New progress reporting implementation. 2003-07-24 Joerg Wunsch - * avrdude.1: - * doc/avrdude.texi: - * pgm.c: - * pgm.h: - * stk500.c: - * stk500_private.h: - * term.c: Add support for displaying and setting the various - operational parameters of the STK500 (Vtarget, Varef, clock). + * avrdude.1: + * doc/avrdude.texi: + * pgm.c: + * pgm.h: + * stk500.c: + * stk500_private.h: + * term.c: Add support for displaying and setting the various + operational parameters of the STK500 (Vtarget, Varef, clock). 2003/07/22 Brian S. Dean - * avrdude.conf.in: - Add 'picoweb' programming cable programmer. - Contributed by Rune Christensen . + * avrdude.conf.in: + Add 'picoweb' programming cable programmer. + Contributed by Rune Christensen . 2003-06-18 Brian S. Dean - * avrdude.conf.in: - Add the 'sp12' (Steve Bolt's) programmer. - Submitted by Larry Barello . + * avrdude.conf.in: + Add the 'sp12' (Steve Bolt's) programmer. + Submitted by Larry Barello . 2003-06-17 Brian S. Dean - * avrdude.conf.in: - Properly identify the "ALF" programmer. - - Extend ATmega8 calibration memory to support all 4 calibration bytes. - Savannah bug #3835. Submitted by Francisco T. A. Silva - . - - Add a few AVR910 programmer device codes. Savannah bug #3569 - sorry - I can't tell who submitted this to give proper credit. - - Add support for the ATtiny12. Submitted by Pontifex + * avrdude.conf.in: + Properly identify the "ALF" programmer. + + Extend ATmega8 calibration memory to support all 4 calibration bytes. + Savannah bug #3835. Submitted by Francisco T. A. Silva + . + + Add a few AVR910 programmer device codes. Savannah bug #3569 - sorry + I can't tell who submitted this to give proper credit. + + Add support for the ATtiny12. Submitted by Pontifex 2003-05-22 Brian S. Dean - * avr.c: - * avr.h: - * fileio.c: - Optimize flash memory handling a little bit by ignoring 0xff data that - resides above the last non-0xff data value in the address space. Only - do this for flash memory since writing a 0xff to flash is a no-op. - This has the affect of creating smaller output files when dumping - memory contents from flash if the program in flash does not consume - the whole memory space. It also results in shorter programming times - when avrdude is asked to load a file into flash that has lots of 0xff - filled data past the last non-0xff data value. + * avr.c: + * avr.h: + * fileio.c: + Optimize flash memory handling a little bit by ignoring 0xff data that + resides above the last non-0xff data value in the address space. Only + do this for flash memory since writing a 0xff to flash is a no-op. + This has the affect of creating smaller output files when dumping + memory contents from flash if the program in flash does not consume + the whole memory space. It also results in shorter programming times + when avrdude is asked to load a file into flash that has lots of 0xff + filled data past the last non-0xff data value. 2003-05-13 Theodore A. Roth - * avr910.c (avr910_paged_write_flash): Add code to send the 'm' - command ("issue page write" cmd) for each page. + * avr910.c (avr910_paged_write_flash): Add code to send the 'm' + command ("issue page write" cmd) for each page. 2003-05-13 Theodore A. Roth - * avrdude.conf.in: Add pagel and bs2 entries for at90s1200 device. + * avrdude.conf.in: Add pagel and bs2 entries for at90s1200 device. 2003-05-13 Theodore A. Roth - * doc/TODO: Add note about avr910 device codes. + * doc/TODO: Add note about avr910 device codes. 2003-05-04 Theodore A. Roth - * configure.ac: Check for ncurses library (since it can be a - replacement for termcap). + * configure.ac: Check for ncurses library (since it can be a + replacement for termcap). 2003-05-02 Theodore A. Roth - * avrdude.conf.in: Add avr decodes for devices known in avr910 - firmware version 2.3. - Add missing stk500 devocde for 2343. + * avrdude.conf.in: Add avr decodes for devices known in avr910 + firmware version 2.3. + Add missing stk500 devocde for 2343. 2003-04-23 Eric B. Weddington - * fileio.c: Fix for bug #3293. Set correct open mode for raw format - for Windows. + * fileio.c: Fix for bug #3293. Set correct open mode for raw format + for Windows. 2003-04-19 Brian S. Dean - * avrdude.1: - * fileio.c: - * fileio.h: - * main.c: - Implement and "immediate mode" for file input - this allows - one to specify byte values on the command line instead of via - a file. This can be good for specifying fuse bytes and - eliminates the need to create single-byte files or using - interactive terminal mode for these single-byte memories. - Requested by several folks on the mailing list. + * avrdude.1: + * fileio.c: + * fileio.h: + * main.c: + Implement and "immediate mode" for file input - this allows + one to specify byte values on the command line instead of via + a file. This can be good for specifying fuse bytes and + eliminates the need to create single-byte files or using + interactive terminal mode for these single-byte memories. + Requested by several folks on the mailing list. 2003-04-18 Theodore A. Roth - * configure.ac: Add cvs suffix back to version. - * doc/TODO: Add a few items. + * configure.ac: Add cvs suffix back to version. + * doc/TODO: Add a few items. 2003-04-18 Theodore A. Roth - * AVRDUDE 4.1.0 has been released (cvs release tag is "release_4_1_0"). + * AVRDUDE 4.1.0 has been released (cvs release tag is "release_4_1_0"). 2003-04-17 Theodore A. Roth - * configure.ac: Set version to 4.1.0. - * doc/avrdude.texi: Add note about avr910 programmer type. + * configure.ac: Set version to 4.1.0. + * doc/avrdude.texi: Add note about avr910 programmer type. 2003-04-17 Eric B. Weddington - * NEWS: Replace TBD with new release version. + * NEWS: Replace TBD with new release version. 2003-04-17 Eric B. Weddington - * avrdude.conf.in: Change name of pony programmer to pony-stk200 - to better describe the hardware (PonyProg is software that works - with various hardware). + * avrdude.conf.in: Change name of pony programmer to pony-stk200 + to better describe the hardware (PonyProg is software that works + with various hardware). 2003-04-16 Eric B. Weddington - * avrdude.conf.in: Add support for ATtiny26 - Submitted by Artur Lipowski - * NEWS: List new devices supported: ATtiny26 + * avrdude.conf.in: Add support for ATtiny26 + Submitted by Artur Lipowski + * NEWS: List new devices supported: ATtiny26 2003-04-16 Eric B. Weddington - * avrdude.conf.in: Add support for ATmega8535 - Submitted by Alexander Peter - * NEWS: List new devices supported: ATmega8535 + * avrdude.conf.in: Add support for ATmega8535 + Submitted by Alexander Peter + * NEWS: List new devices supported: ATmega8535 2003-04-09 Theodore A. Roth - * avr910.c: Reading a 16 bit word in paged load needs to swap the - bytes since the 'R' command returns MSB first and the internal buffer - stores LSB first. + * avr910.c: Reading a 16 bit word in paged load needs to swap the + bytes since the 'R' command returns MSB first and the internal buffer + stores LSB first. 2003-04-07 Theodore A. Roth - * stk500.c: Don't print out read/write byte progress unless the verbose - option is given. + * stk500.c: Don't print out read/write byte progress unless the verbose + option is given. 2003-04-05 Theodore A. Roth - * avr910.c: Re-add the avr910 byte read/write methods which were - removed in my previous patch. Terminal mode read/writes are broken - without those methods. D'oh! + * avr910.c: Re-add the avr910 byte read/write methods which were + removed in my previous patch. Terminal mode read/writes are broken + without those methods. D'oh! 2003-04-05 Theodore A. Roth - * avr910.c: Refactor to allow probing for auto addr increment. If auto - incr supported by programmer hw, don't send addr for every byte. + * avr910.c: Refactor to allow probing for auto addr increment. If auto + incr supported by programmer hw, don't send addr for every byte. 2003-04-03 Eric B. Weddington - - * confwin.c: Fix bug that allows garbage for non-existent user - config filename on Windows. + + * confwin.c: Fix bug that allows garbage for non-existent user + config filename on Windows. 2003-03-29 Brian S. Dean - * avrdude.conf.in: - Add the ATmega32 part. This part definition was contributed by: - Daniel Williamson and - Ruwan Jayanetti - The resulting part definition used was actually somewhat of a merge of - the two submitted definitions. + * avrdude.conf.in: + Add the ATmega32 part. This part definition was contributed by: + Daniel Williamson and + Ruwan Jayanetti + The resulting part definition used was actually somewhat of a merge of + the two submitted definitions. 2003-03-24 Theodore A. Roth - * NEWS: Add note about avr910 support. + * NEWS: Add note about avr910 support. 2003-03-23 Theodore A. Roth - * avr.c (avr_write): Add call to pgm->write_setup() before the write - loop. - * avr910.c: Change all show_func_info() calls to no_show_func_info(). - Add read/write to/from flash/eeprom memory functionality. - * pgm.c: Initialize pgm->write_setup. - * pgm.h: Add write_setup field to PROGRAMMER structure. - * ser_posix.c: Remove unneeded cast in verbosity code. + * avr.c (avr_write): Add call to pgm->write_setup() before the write + loop. + * avr910.c: Change all show_func_info() calls to no_show_func_info(). + Add read/write to/from flash/eeprom memory functionality. + * pgm.c: Initialize pgm->write_setup. + * pgm.h: Add write_setup field to PROGRAMMER structure. + * ser_posix.c: Remove unneeded cast in verbosity code. 2003-03-23 Theodore A. Roth - * ser_posix.c: Limit verbose output to 2 chars. + * ser_posix.c: Limit verbose output to 2 chars. 2003-03-23 Theodore A. Roth - * ser_posix.c: Add verbose level > 3 output for send and recv functions. + * ser_posix.c: Add verbose level > 3 output for send and recv functions. 2003-03-23 Theodore A. Roth - * avr.c: Add avr_read_byte_default(). - Have avr_read_byte() call pgm->read_byte() or avr_read_byte_default(). - Add avr_write_byte_default(). - Have avr_write_byte() call pgm->write_byte or avr_write_byte_default(). - * pgm.c: Initialize pgm->write_byte and pgm->read_byte. - * pgm.h: Add write_byte and read_byte fields to struct programmer_t. + * avr.c: Add avr_read_byte_default(). + Have avr_read_byte() call pgm->read_byte() or avr_read_byte_default(). + Add avr_write_byte_default(). + Have avr_write_byte() call pgm->write_byte or avr_write_byte_default(). + * pgm.c: Initialize pgm->write_byte and pgm->read_byte. + * pgm.h: Add write_byte and read_byte fields to struct programmer_t. 2003-03-17 Theodore A. Roth - * avrdude.conf.in: Fix typo for devicecode deprecation comment. + * avrdude.conf.in: Fix typo for devicecode deprecation comment. 2003-03-17 Eric B. Weddington - * avrdude.conf.in: Add Bascom SAMPLE programmer. - Submitted by Larry Barello + * avrdude.conf.in: Add Bascom SAMPLE programmer. + Submitted by Larry Barello 2003-03-16 Theodore A. Roth - * avr.c (avr_read): Use pgm->read_sig_bytes to read signature bytes if - available. - * avr910.c (avr910_vfy_cmd_sent): New function. - (avr910_chip_erase): Add support for chip erase. - (avr910_enter_prog_mode): New function. - (avr910_leave_prog_mode): New function. - (avr910_initialize): Add code to select device type and enter prog mode. - (avr910_close): Leave programming mode before closing serial port. - (avr910_read_sig_bytes): New function. - (avr910_initpgm): Add avr910_read_sig_bytes method to pgm initializer. - * avrdude.conf.in: Add note about deprecating devicecode. - Change all occurences of devicecode to stk500_devcode. - Add avr910_devcode to a few parts for testing. - * avrpart.h (struct avrpart): Change devicecode field to stk500_devcode. - (struct avrpart): Add avr910_devcode field. - * config_gram.y: Add K_STK500_DEVCODE and K_AVR910_DEVCODE tokens. - Generate an error if devicecode is found in the config file. - Handle parsing of avr910_devcode and stk500_devcode. - * lexer.l: Handle parsing of avr910_devcode and stk500_devcode. - * pgm.c: Initialize pgm->read_sig_bytes field. - * pgm.h: Add pgm->read_sig_bytes field. - * stk500.c: Use stk500_devcode instead of devicecode. + * avr.c (avr_read): Use pgm->read_sig_bytes to read signature bytes if + available. + * avr910.c (avr910_vfy_cmd_sent): New function. + (avr910_chip_erase): Add support for chip erase. + (avr910_enter_prog_mode): New function. + (avr910_leave_prog_mode): New function. + (avr910_initialize): Add code to select device type and enter prog mode. + (avr910_close): Leave programming mode before closing serial port. + (avr910_read_sig_bytes): New function. + (avr910_initpgm): Add avr910_read_sig_bytes method to pgm initializer. + * avrdude.conf.in: Add note about deprecating devicecode. + Change all occurences of devicecode to stk500_devcode. + Add avr910_devcode to a few parts for testing. + * avrpart.h (struct avrpart): Change devicecode field to stk500_devcode. + (struct avrpart): Add avr910_devcode field. + * config_gram.y: Add K_STK500_DEVCODE and K_AVR910_DEVCODE tokens. + Generate an error if devicecode is found in the config file. + Handle parsing of avr910_devcode and stk500_devcode. + * lexer.l: Handle parsing of avr910_devcode and stk500_devcode. + * pgm.c: Initialize pgm->read_sig_bytes field. + * pgm.h: Add pgm->read_sig_bytes field. + * stk500.c: Use stk500_devcode instead of devicecode. 2003-03-16 Theodore A. Roth - * avrdude.conf.in: Add avr910 and pavr programmers. - * config_gram.y: Add parsing of avr910 programmer. - * lexer.l: Add avr910 token. - * avr910.c: [this is still work in progress] - Add some debug output. - Add probe for programmer presense. - * main.c: Set port to default_serial if programmer type is avr910. + * avrdude.conf.in: Add avr910 and pavr programmers. + * config_gram.y: Add parsing of avr910 programmer. + * lexer.l: Add avr910 token. + * avr910.c: [this is still work in progress] + Add some debug output. + Add probe for programmer presense. + * main.c: Set port to default_serial if programmer type is avr910. 2003-03-13 Theodore A. Roth - * ser_posix.c, ser_win32.c, serial.h: - Change baud from int to long to avoid a 16-bit int overflow. + * ser_posix.c, ser_win32.c, serial.h: + Change baud from int to long to avoid a 16-bit int overflow. 2003-03-12 Theodore A. Roth - * Makefile.am (avrdude_SOURCES): Add avr910.[ch], serial.h and - ser_posix.c files. - * avr910.c: New file (stubs for avr910 serial programmer). - * avr910.h: New file. - * ser_posix.c: New file. - * ser_win32.c: New file (just stubs for now). - * serial.h: New file. - * stk500.c: Move all the code for accessing the posix serial ports - into ser_posix. This will make a native win32 port easier and allows - the avr910 programmer to share the serial code. + * Makefile.am (avrdude_SOURCES): Add avr910.[ch], serial.h and + ser_posix.c files. + * avr910.c: New file (stubs for avr910 serial programmer). + * avr910.h: New file. + * ser_posix.c: New file. + * ser_win32.c: New file (just stubs for now). + * serial.h: New file. + * stk500.c: Move all the code for accessing the posix serial ports + into ser_posix. This will make a native win32 port easier and allows + the avr910 programmer to share the serial code. 2003-03-12 Theodore A. Roth - * configure.ac (AC_INIT): Set version to 4.0.0cvs since we're done - with 4.0.0 release. + * configure.ac (AC_INIT): Set version to 4.0.0cvs since we're done + with 4.0.0 release. 2003-03-12 - * AVRDUDE 4.0.0 has been released (cvs release tag is "release_4_0_0"). + * AVRDUDE 4.0.0 has been released (cvs release tag is "release_4_0_0"). 2003-03-11 Theodore A. Roth - * Makefile.am: Add CLEANFILES to remove all files from a make. - * doc/Makefile.am: Ditto + * Makefile.am: Add CLEANFILES to remove all files from a make. + * doc/Makefile.am: Ditto 2003-03-11 Theodore A. Roth - * windows/Makefile.am: Fix uninstall-local rule (forget the $$file - part of the rm command). + * windows/Makefile.am: Fix uninstall-local rule (forget the $$file + part of the rm command). 2003-03-11 Theodore A. Roth - * AUTHORS: Updated. - * CHANGELOG: Move contents to NEWS and remove file. - * ChangeLog: All of the changes for this year. - * ChangeLog-2001: All 2001 changes. - * ChangeLog-2002: All 2002 changes. - * Makefile.am (EXTRA_DIST): Remove CHANGELOG and and Change-200[12]. - * NEWS: Moved contents of CHANGELOG file here. - * README: Add note pointing to savannah site. + * AUTHORS: Updated. + * CHANGELOG: Move contents to NEWS and remove file. + * ChangeLog: All of the changes for this year. + * ChangeLog-2001: All 2001 changes. + * ChangeLog-2002: All 2002 changes. + * Makefile.am (EXTRA_DIST): Remove CHANGELOG and and Change-200[12]. + * NEWS: Moved contents of CHANGELOG file here. + * README: Add note pointing to savannah site. 2003-03-11 Eric Weddington - * doc/avrdude.texi: - Add Install and Documentation sections for Windows. Fix typo. + * doc/avrdude.texi: + Add Install and Documentation sections for Windows. Fix typo. 2003-03-10 Theodore A. Roth - * Makefile.am: * Makefile.am (EXTRA_DIST): Add CHANGELOG. + * Makefile.am: * Makefile.am (EXTRA_DIST): Add CHANGELOG. 2003-03-10 Brian S. Dean - * stk500.c: Disable debugging printf. + * stk500.c: Disable debugging printf. - * configure.ac: Update version number in preparation for release. + * configure.ac: Update version number in preparation for release. 2003-03-10 Theodore A. Roth - * doc/avrdude.texi: - Add comment before each node to make them stand out better. - Use @option{} command for options instead of @code{}. - Merge FreeBSD and Linux platform dependent information. + * doc/avrdude.texi: + Add comment before each node to make them stand out better. + Use @option{} command for options instead of @code{}. + Merge FreeBSD and Linux platform dependent information. 2003-03-10 Brian S. Dean - * avrdude.1: Minor man page updates to better reflect reality. + * avrdude.1: Minor man page updates to better reflect reality. 2003-03-10 Joerg Wunsch - * bootstrap: - Export all the AUTO* variables. Hopefully, that way the generated - Makefile might get them correctly. + * bootstrap: + Export all the AUTO* variables. Hopefully, that way the generated + Makefile might get them correctly. - * bootstrap: - Export ${AUTOCONF} so automake will find it by whatever name it will be - called today. + * bootstrap: + Export ${AUTOCONF} so automake will find it by whatever name it will be + called today. 2003-03-06 Eric Weddington - * doc/avrdude.texi: - Add notes about ability to list parts and list programmers in the - config file in -p and -c descriptions. Change info about where to - find Windows search method in -C description. + * doc/avrdude.texi: + Add notes about ability to list parts and list programmers in the + config file in -p and -c descriptions. Change info about where to + find Windows search method in -C description. - * main.c: - Change software version from hardcoded value to getting it from - the configuration. + * main.c: + Change software version from hardcoded value to getting it from + the configuration. 2003-03-06 Theodore A. Roth - * avrdude.spec.in: * avrdude.spec.in: Add docs sub-package. - Add %post and %preun scriptlets for handling info files. + * avrdude.spec.in: * avrdude.spec.in: Add docs sub-package. + Add %post and %preun scriptlets for handling info files. - * configure.ac, doc/Makefile.am: - * configure.ac: Add --enable-versioned-doc option and set DOC_INST_DIR. - * doc/Makefile.am: Add rules to install docs in DOC_INST_DIR. + * configure.ac, doc/Makefile.am: + * configure.ac: Add --enable-versioned-doc option and set DOC_INST_DIR. + * doc/Makefile.am: Add rules to install docs in DOC_INST_DIR. - * doc/Makefile.am: - Delete the lines which where commented out in previous commit. + * doc/Makefile.am: + Delete the lines which where commented out in previous commit. - * configure.ac, doc/Makefile.am: - * configure.ac: Remove hack to make work with automake-1.5. - * doc/Makefile.am: Remove extra rules that were needed to work with - automake-1.5. + * configure.ac, doc/Makefile.am: + * configure.ac: Remove hack to make work with automake-1.5. + * doc/Makefile.am: Remove extra rules that were needed to work with + automake-1.5. - * bootstrap: - * bootstrap: Force use of autoconf-2.57 and automake-1.7.x. + * bootstrap: + * bootstrap: Force use of autoconf-2.57 and automake-1.7.x. 2003-03-05 Joerg Wunsch - * avrdude.conf.in: Add a definition for the popular Ponyprog dongle. + * avrdude.conf.in: Add a definition for the popular Ponyprog dongle. - Submitted by: Daniel Williamson + Submitted by: Daniel Williamson 2003-03-05 Brian S. Dean - * main.c: - Check the programmer type against 'STK500' instead of the programmer - name when checking to see if we should default to the default_serial - port instead of the default_parallel port. This has us do the right - thing for the new 'avrisp' programmer. + * main.c: + Check the programmer type against 'STK500' instead of the programmer + name when checking to see if we should default to the default_serial + port instead of the default_parallel port. This has us do the right + thing for the new 'avrisp' programmer. - * stk500.c: - Make the page size used for non-paged parts for the 'paged_write' - command be 128 bytes. This cuts 6 seconds off the programming time - for uploading a 6K file into an AT90S8515 vs the time loading the same - file using a 16 byte buffer, and the response feedback is still good. + * stk500.c: + Make the page size used for non-paged parts for the 'paged_write' + command be 128 bytes. This cuts 6 seconds off the programming time + for uploading a 6K file into an AT90S8515 vs the time loading the same + file using a 16 byte buffer, and the response feedback is still good. - * avr.c, stk500.c: - Fix stk500 page write (Program Page command). This is supported after - all on non-paged-memory parts. The problem was that the page size was - defaulting to 256 (maximum for the stk500), but the timeout for a - response from the stk500 before declaring it dead was only 0.5 - seconds. But it takes much longer than 0.5 seconds to program 256 - bytes, so we just weren't waiting long enough. + * avr.c, stk500.c: + Fix stk500 page write (Program Page command). This is supported after + all on non-paged-memory parts. The problem was that the page size was + defaulting to 256 (maximum for the stk500), but the timeout for a + response from the stk500 before declaring it dead was only 0.5 + seconds. But it takes much longer than 0.5 seconds to program 256 + bytes, so we just weren't waiting long enough. - Fix this in two ways - increase the timeout to 5 seconds, and decrease - the page size to 16 bytes for non-paged parts. The programming time - for 16 bytes is short enough to provide the user with some feedback - that something is happening. + Fix this in two ways - increase the timeout to 5 seconds, and decrease + the page size to 16 bytes for non-paged parts. The programming time + for 16 bytes is short enough to provide the user with some feedback + that something is happening. - * avr.c, stk500.c: - Don't call the programmer's 'paged_write' routine unless the memory - itself is paged as it doesn't appear to work otherwise. + * avr.c, stk500.c: + Don't call the programmer's 'paged_write' routine unless the memory + itself is paged as it doesn't appear to work otherwise. - * avrdude.conf.in: Fix device codes for at90s8515 and at90s8535. + * avrdude.conf.in: Fix device codes for at90s8515 and at90s8535. - * avrdude.conf.in: - Add PAGEL and BS2 parms for parts I have datasheets for. + * avrdude.conf.in: + Add PAGEL and BS2 parms for parts I have datasheets for. - * config_gram.y: - Do that last commit slightly differently - this way results in no - shift-reduce conflicts. + * config_gram.y: + Do that last commit slightly differently - this way results in no + shift-reduce conflicts. - * config_gram.y: - It shouldn't be an error to have an empty configuration file. This - causes some shift-reduce conflicts, but I think they are OK. + * config_gram.y: + It shouldn't be an error to have an empty configuration file. This + causes some shift-reduce conflicts, but I think they are OK. - * main.c: - Print out a list of valid parts for '-p ?' and a list of valid - programmers for '-c ?'. + * main.c: + Print out a list of valid parts for '-p ?' and a list of valid + programmers for '-c ?'. 2003-03-04 Eric Weddington - * doc/avrdude.texi: Minor Windows doc corrections. + * doc/avrdude.texi: Minor Windows doc corrections. - * doc/TODO: Add TODO file. + * doc/TODO: Add TODO file. - * avrdude.conf.in: Add AVR ISP programmer. + * avrdude.conf.in: Add AVR ISP programmer. 2003-03-04 Brian S. Dean - * stk500.c: - Don't try to set extended device programming parameters if they - haven't been specified in the config file for the part. + * stk500.c: + Don't try to set extended device programming parameters if they + haven't been specified in the config file for the part. - * stk500.c: Set extended device parameters for all firmware versions. + * stk500.c: Set extended device parameters for all firmware versions. - * stk500.c: - First attempt at supporting STK500 firmware past 1.10. Thanks to - Jason Kyle for the needed protocol information. + * stk500.c: + First attempt at supporting STK500 firmware past 1.10. Thanks to + Jason Kyle for the needed protocol information. 2003-03-03 Theodore A. Roth - * doc/Makefile.am: - * doc/Makefile.am: Add ps and pdf rules since they aren't supplied by - automake versions prior to 1.7. + * doc/Makefile.am: + * doc/Makefile.am: Add ps and pdf rules since they aren't supplied by + automake versions prior to 1.7. - * doc/avrdude.texi: - * doc/avrdude.texi: Add node and menu information for the info system. + * doc/avrdude.texi: + * doc/avrdude.texi: Add node and menu information for the info system. - * Makefile.am, configure.ac, doc/Makefile.am, doc/avrdude.texi: - * Makefile.am (SUBDIRS): Add doc dir. - * configure.ac (AC_CONFIG_FILES): Add doc/Makefile. - * doc/Makefile.am: New file. - * doc/avrdude.texi: Use automatically generated version.texi. + * Makefile.am, configure.ac, doc/Makefile.am, doc/avrdude.texi: + * Makefile.am (SUBDIRS): Add doc dir. + * configure.ac (AC_CONFIG_FILES): Add doc/Makefile. + * doc/Makefile.am: New file. + * doc/avrdude.texi: Use automatically generated version.texi. 2003-03-02 Brian S. Dean - * doc/avrdude.texi: Initial manual. + * doc/avrdude.texi: Initial manual. 2003-02-27 Theodore A. Roth - * term.c: * term.c: Use fgets() if readline() is not available. + * term.c: * term.c: Use fgets() if readline() is not available. 2003-02-27 Joerg Wunsch - * bootstrap: - Oops, accidentally spammed the repository with my private version of - "bootstrap". Back out that change. + * bootstrap: + Oops, accidentally spammed the repository with my private version of + "bootstrap". Back out that change. - * bootstrap, lexer.l: - Ignore \r as white space, to make the Windows people happy. + * bootstrap, lexer.l: + Ignore \r as white space, to make the Windows people happy. 2003-02-27 Theodore A. Roth - * Makefile.am (EXTRA_DIST): Add avrdude.spec and make entries one - per line so future patches are obvious as to what changed. - * avrdude.spec.in: New file to support creation of binaries in rpm - format. - * configure.ac (AC_OUTPUT): Add avrdude.spec. Reorder so that - Makefile is the last entry. + * Makefile.am (EXTRA_DIST): Add avrdude.spec and make entries one + per line so future patches are obvious as to what changed. + * avrdude.spec.in: New file to support creation of binaries in rpm + format. + * configure.ac (AC_OUTPUT): Add avrdude.spec. Reorder so that + Makefile is the last entry. 2003-02-26 Theodore A. Roth - * Makefile.am (SUBDIRS): Add windows dir. - * configure.ac: If $target is a windows system, build whats in - windows sub dir. - * windows/Makefile.am: New file. + * Makefile.am (SUBDIRS): Add windows dir. + * configure.ac: If $target is a windows system, build whats in + windows sub dir. + * windows/Makefile.am: New file. 2003-02-25 Theodore A. Roth - * ChangeLog: Point reader to the CHANGELOG file. - * Makefile.am (EXTRA_DIST): Rename avrdude.conf.sample to - avrdude.conf.in. - Remove avrdude.conf and distclean-local rules. - Add install-exec-local and backup-avrdude-conf rules. - * avrdude.conf.in: - Set default_parallel to "@DEFAULT_PAR_PORT@" for autoconf expansion. - Set default_serial to "@DEFAULT_SER_PORT@" for autoconf expansion. - * configure.ac: Add call to AC_CANONICAL_{BUILD,HOST,TARGET} macros. - Set DEFAULT_PAR_PORT and DEFAULT_SER_PORT based on $host. - Add copyright header. - Define avrdude_version so AC_INIT and AM_INIT_AUTOMAKE are sure - to get the same version. - - * avrdude.conf.in, avrdude.conf.sample: - Renamed avrdude.conf.sample to avrdude.conf.in. + * ChangeLog: Point reader to the CHANGELOG file. + * Makefile.am (EXTRA_DIST): Rename avrdude.conf.sample to + avrdude.conf.in. + Remove avrdude.conf and distclean-local rules. + Add install-exec-local and backup-avrdude-conf rules. + * avrdude.conf.in: + Set default_parallel to "@DEFAULT_PAR_PORT@" for autoconf expansion. + Set default_serial to "@DEFAULT_SER_PORT@" for autoconf expansion. + * configure.ac: Add call to AC_CANONICAL_{BUILD,HOST,TARGET} macros. + Set DEFAULT_PAR_PORT and DEFAULT_SER_PORT based on $host. + Add copyright header. + Define avrdude_version so AC_INIT and AM_INIT_AUTOMAKE are sure + to get the same version. + + * avrdude.conf.in, avrdude.conf.sample: + Renamed avrdude.conf.sample to avrdude.conf.in. 2003-02-25 Eric Weddington - * ppiwin.c: CRs again. + * ppiwin.c: CRs again. - * confwin.c, confwin.h: Get rid of CRs. + * confwin.c, confwin.h: Get rid of CRs. - * main.c, Makefile.am: Get rid of CRs again. + * main.c, Makefile.am: Get rid of CRs again. 2003-02-24 Joerg Wunsch - * avrdude.1: Atmel has rearranged their web site, so now the AVR - docs have been moved to a more logically sounding URL. + * avrdude.1: Atmel has rearranged their web site, so now the AVR + docs have been moved to a more logically sounding URL. 2003-02-24 Eric Weddington - * Makefile.am, main.c: Integrate Windows search of config files. + * Makefile.am, main.c: Integrate Windows search of config files. - * confwin.c, confwin.h: config file search on Windows. + * confwin.c, confwin.h: config file search on Windows. - * ppiwin.c: Change port value from lpt1alt to lpt3. Other - formatting changes. + * ppiwin.c: Change port value from lpt1alt to lpt3. Other + formatting changes. - * windows/giveio.c: - Add giveio device driver source. Requires MS DDK to build. + * windows/giveio.c: + Add giveio device driver source. Requires MS DDK to build. - * windows/giveio.sys: Add giveio device driver binary. + * windows/giveio.sys: Add giveio device driver binary. - * giveio.sys, install_giveio.bat, remove_giveio.bat, status_giveio.bat: - Move Windows specific files. + * giveio.sys, install_giveio.bat, remove_giveio.bat, status_giveio.bat: + Move Windows specific files. - * windows/loaddrv.c, windows/loaddrv.h, windows/remove_giveio.bat: - * windows/status_giveio.bat, windows/install_giveio.bat: - Add Windows specific files. + * windows/loaddrv.c, windows/loaddrv.h, windows/remove_giveio.bat: + * windows/status_giveio.bat, windows/install_giveio.bat: + Add Windows specific files. - * main.c: Usage back to stderr. + * main.c: Usage back to stderr. 2003-02-22 Brian S. Dean - * CHANGELOG: Add note about .avrduderc. + * CHANGELOG: Add note about .avrduderc. - * avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, main.c, - * par.c, pgm.c, pgm.h: - Add the ability to read a per-user config file located at - $HOME/.avrduderc. Entries from .avrduderc take precedence over those - from the system wide config file in ${PREFIX}/etc/avrdude.conf. + * avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, main.c, + * par.c, pgm.c, pgm.h: + Add the ability to read a per-user config file located at + $HOME/.avrduderc. Entries from .avrduderc take precedence over those + from the system wide config file in ${PREFIX}/etc/avrdude.conf. - Track and display the config file name and line number when we print - out the available parts and programmers. This is useful in case - someone has overridden a definition in their .avrduderc file and is - wondering why the definition in the system wide config file is not - being used. + Track and display the config file name and line number when we print + out the available parts and programmers. This is useful in case + someone has overridden a definition in their .avrduderc file and is + wondering why the definition in the system wide config file is not + being used. - Remove the default programmer 'stk500' from the distributed config - file. + Remove the default programmer 'stk500' from the distributed config + file. - * CHANGELOG: Spelling. + * CHANGELOG: Spelling. 2003-02-21 Brian S. Dean - * CHANGELOG: - Put some stuff in the CHANGELOG for this upcoming new version before I - forget. + * CHANGELOG: + Put some stuff in the CHANGELOG for this upcoming new version before I + forget. - * main.c: - Update comment due to removal of the default parallel port pin config. + * main.c: + Update comment due to removal of the default parallel port pin config. - * config.c, config.h, config_gram.y, lexer.l, main.c: - * avrdude.conf.sample: - Introduce 'default_programmer' to the config file instead of requiring - one of the programmers to be tagged "default" within its definition. + * config.c, config.h, config_gram.y, lexer.l, main.c: + * avrdude.conf.sample: + Introduce 'default_programmer' to the config file instead of requiring + one of the programmers to be tagged "default" within its definition. - Also, axe the notion of a compiled-in default programmer. It is - kind've pointless now that nearly all configuration comes from the - config file, thus, avrdude is not very useful without the config file, - and thus, having a programmer compiled-in offers little or no benefit. + Also, axe the notion of a compiled-in default programmer. It is + kind've pointless now that nearly all configuration comes from the + config file, thus, avrdude is not very useful without the config file, + and thus, having a programmer compiled-in offers little or no benefit. 2003-02-21 Eric Weddington - * main.c: Change usage text to be verbose. + * main.c: Change usage text to be verbose. - * giveio.sys: Add Windows parallel port device driver (binary). + * giveio.sys: Add Windows parallel port device driver (binary). - * install_giveio.bat, remove_giveio.bat, status_giveio.bat: - Windows batch files to work with giveio.sys. + * install_giveio.bat, remove_giveio.bat, status_giveio.bat: + Windows batch files to work with giveio.sys. 2003-02-21 Brian S. Dean - * avrdude.conf.sample, config.c, config.h, config_gram.y, lexer.l: - * main.c: - Add port name defaults to the config file instead of hard-coding. - This adds 'default_parallel' and 'default_serial' keywords to the - grammar, which take quoted string arguments. + * avrdude.conf.sample, config.c, config.h, config_gram.y, lexer.l: + * main.c: + Add port name defaults to the config file instead of hard-coding. + This adds 'default_parallel' and 'default_serial' keywords to the + grammar, which take quoted string arguments. - * avrdude.conf.sample: - Document the recent additions to the config file. + * avrdude.conf.sample: + Document the recent additions to the config file. - * stk500.c, avr.c, avrpart.h, config_gram.y, lexer.l, par.c: - Add the ability to specify which pin to pulse when retrying entry into - programming mode. Use 'retry_pulse' in the per-part specification - that can currently take values of 'reset' or 'sck', the default being - 'sck' which preserves the previous behaviour. Some newer parts - indicate that /RESET should be pulsed, while older parts say to pulse - SCK. + * stk500.c, avr.c, avrpart.h, config_gram.y, lexer.l, par.c: + Add the ability to specify which pin to pulse when retrying entry into + programming mode. Use 'retry_pulse' in the per-part specification + that can currently take values of 'reset' or 'sck', the default being + 'sck' which preserves the previous behaviour. Some newer parts + indicate that /RESET should be pulsed, while older parts say to pulse + SCK. 2003-02-20 Eric Weddington - * main.c, par.c: - Make verbose global. Make debug code in par_cmd() based on verbose=2. + * main.c, par.c: + Make verbose global. Make debug code in par_cmd() based on verbose=2. 2003-02-20 Brian S. Dean - * stk500.c: Fix pseudo/full parallel mode selection logic. + * stk500.c: Fix pseudo/full parallel mode selection logic. - * avrdude.conf.sample: - Woops, didn't really mean to commit those changes that slipped in with - the last commit. Those were just there for testing. + * avrdude.conf.sample: + Woops, didn't really mean to commit those changes that slipped in with + the last commit. Those were just there for testing. - * avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l: - * stk500.c: - Add 'serial' and 'parallel' keywords to the grammar so that one can - say whether parts support these programming modes or not. Possible - values for 'serial' are 'yes' or 'no'. Possible values for 'parallel' - are 'yes', 'no', or 'pseudo'. Add a bit mask of flags to the AVRPART - structure to capture these settings. Use these within - stk500_initialize() to set the device parameters correctly. + * avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l: + * stk500.c: + Add 'serial' and 'parallel' keywords to the grammar so that one can + say whether parts support these programming modes or not. Possible + values for 'serial' are 'yes' or 'no'. Possible values for 'parallel' + are 'yes', 'no', or 'pseudo'. Add a bit mask of flags to the AVRPART + structure to capture these settings. Use these within + stk500_initialize() to set the device parameters correctly. - Defaults for 'serial' and 'parallel' are 'yes' unless specified - otherwise. + Defaults for 'serial' and 'parallel' are 'yes' unless specified + otherwise. 2003-02-20 Eric Weddington - * Makefile.am, ppiwin.c: Get rid of CRs. + * Makefile.am, ppiwin.c: Get rid of CRs. - * Makefile.am: Add ppiwin.c to avrdude_SOURCES. + * Makefile.am: Add ppiwin.c to avrdude_SOURCES. - * ppiwin.c: Added ppiwin.c: Windows parallel port driver. + * ppiwin.c: Added ppiwin.c: Windows parallel port driver. - * stk500.c: - Add error message for fail to enter programming mode. Fix typos. + * stk500.c: + Add error message for fail to enter programming mode. Fix typos. 2003-02-20 Brian S. Dean - * avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l: - Add a few parameters needed for parallel programming: assignment of - PAGEL and BS2 signals and the disposition of the reset pin - ('dedicated' or 'io'). + * avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l: + Add a few parameters needed for parallel programming: assignment of + PAGEL and BS2 signals and the disposition of the reset pin + ('dedicated' or 'io'). 2003-02-20 Theodore A. Roth - * avrdude.1: Fix spacing for m169 entry. (tabs not spaces ;-) + * avrdude.1: Fix spacing for m169 entry. (tabs not spaces ;-) 2003-02-20 Brian S. Dean - * avrdude.1, fileio.c, main.c: Add Motorola S-record support. + * avrdude.1, fileio.c, main.c: Add Motorola S-record support. - Submitted by: "Alexey V.Levdikov" + Submitted by: "Alexey V.Levdikov" 2003-02-19 Theodore A. Roth - * avrdude.1: Add m169 to list of supported targets. + * avrdude.1: Add m169 to list of supported targets. 2003-02-19 Joerg Wunsch - * avrdude.conf.sample, avrdude.1: - My colleague contributed a part definition for the AT90S2343. + * avrdude.conf.sample, avrdude.1: + My colleague contributed a part definition for the AT90S2343. - Submitted by: Mirko Kaffka + Submitted by: Mirko Kaffka 2003-02-18 Theodore A. Roth - * avrdude.conf.sample: - Add support for mega169. (tested with stk500 with 1.7 firmware) + * avrdude.conf.sample: + Add support for mega169. (tested with stk500 with 1.7 firmware) - * avrdude.conf.sample: - Add commments to separate parts (makes it easier for the eye to parse). + * avrdude.conf.sample: + Add commments to separate parts (makes it easier for the eye to parse). 2003-02-15 Theodore A. Roth - * Makefile.am: Add $srcdir to sample config filename so that - building in a separate dir works. + * Makefile.am: Add $srcdir to sample config filename so that + building in a separate dir works. 2003-02-15 Joerg Wunsch - * Makefile.am: - Only GNU make sets $< in non-inference rules, so rather explicitly - spell the source file(s) to remain compatible. + * Makefile.am: + Only GNU make sets $< in non-inference rules, so rather explicitly + spell the source file(s) to remain compatible. 2003-02-14 Theodore A. Roth - * Makefile.am: Add distclean rule and EXTRA_DIST list to get 'make - distcheck' to succeed. - - These changes add basic support for a autoconf/automake based - build system. - - * .cvsignore: Ignore autoconf files. - * AUTHORS: New file. - * ChangeLog: New file. - * Makefile: Removed file. - * Makefile.am: New file. - * NEWS: New file. - * README: New file. - * bootstrap: New file. - * configure.ac: New file. - * avr.c: Include ac_cfg.h (generated by autoconf). - * config.c: Include ac_cfg.h. - Include config_gram.h instead of y.tab.h. - * config.h: If HAS_YYSTYPE is not defined, define YYSTYPE. - * config_gram.y: Include ac_cfg.h. - * fileio.c: Include ac_cfg.h. - * lexer.l: Include config_gram.h instead of y.tab.h. - * lists.c: Include ac_cfg.h. - * main.c: Include ac_cfg.h. - * par.c: Include ac_cfg.h. - * pgm.c: Include ac_cfg.h. - * ppi.c: Include ac_cfg.h. - * stk500.c: Include ac_cfg.h. - * term.c: Include ac_cfg.h. + * Makefile.am: Add distclean rule and EXTRA_DIST list to get 'make + distcheck' to succeed. + + These changes add basic support for a autoconf/automake based + build system. + + * .cvsignore: Ignore autoconf files. + * AUTHORS: New file. + * ChangeLog: New file. + * Makefile: Removed file. + * Makefile.am: New file. + * NEWS: New file. + * README: New file. + * bootstrap: New file. + * configure.ac: New file. + * avr.c: Include ac_cfg.h (generated by autoconf). + * config.c: Include ac_cfg.h. + Include config_gram.h instead of y.tab.h. + * config.h: If HAS_YYSTYPE is not defined, define YYSTYPE. + * config_gram.y: Include ac_cfg.h. + * fileio.c: Include ac_cfg.h. + * lexer.l: Include config_gram.h instead of y.tab.h. + * lists.c: Include ac_cfg.h. + * main.c: Include ac_cfg.h. + * par.c: Include ac_cfg.h. + * pgm.c: Include ac_cfg.h. + * ppi.c: Include ac_cfg.h. + * stk500.c: Include ac_cfg.h. + * term.c: Include ac_cfg.h. 2003-02-14 Brian S. Dean - * stk500.c: Fix typos. Fix error messages. + * stk500.c: Fix typos. Fix error messages. 2003-02-13 Brian S. Dean - * Makefile, avrdude.conf.sample, config_gram.y, lexer.l, main.c: - * par.c, par.h, ppi.c, ppi.h, stk500.c: - Split higher level parallel port programmer code off from ppi.c into - its own file par.c, leaving low level parallel port accessor routines - in ppi.c to help with portability. Change the programmer type to - 'PAR' now instead of 'PPI' - 'PAR' represents the parallel port - programmer type. + * Makefile, avrdude.conf.sample, config_gram.y, lexer.l, main.c: + * par.c, par.h, ppi.c, ppi.h, stk500.c: + Split higher level parallel port programmer code off from ppi.c into + its own file par.c, leaving low level parallel port accessor routines + in ppi.c to help with portability. Change the programmer type to + 'PAR' now instead of 'PPI' - 'PAR' represents the parallel port + programmer type. - Be more liberal with 'static' function declarations within the - programmer implimentation files - these functions should never be - called directly - always use the programmer function references. + Be more liberal with 'static' function declarations within the + programmer implimentation files - these functions should never be + called directly - always use the programmer function references. - There are still a few places in 'main.c' that directly reference the - parallel programmer explicitly (par_getpinmask). These should be - fixed somehow. + There are still a few places in 'main.c' that directly reference the + parallel programmer explicitly (par_getpinmask). These should be + fixed somehow. - Axe a few unused functions. + Axe a few unused functions. 2003-02-12 Theodore A. Roth - * .cvsignore: New file. + * .cvsignore: New file. - * stk500.c: Remove need for inttypes.h. + * stk500.c: Remove need for inttypes.h. - * lexer.l: Define YY_NO_UNPUT to quell a compiler warning. + * lexer.l: Define YY_NO_UNPUT to quell a compiler warning. - * Makefile: Remove YACC assignment. - Add '-b y' options to YACC invocation. - Remove leading '-' from 'include .depend'. + * Makefile: Remove YACC assignment. + Add '-b y' options to YACC invocation. + Remove leading '-' from 'include .depend'. 2003-02-12 Joerg Wunsch - * config_gram.y: - Declare the internally used static functions on top, to get rid of the - compiler warnings. + * config_gram.y: + Declare the internally used static functions on top, to get rid of the + compiler warnings. - Reported by: bison-generated parsers + Reported by: bison-generated parsers 2003-02-11 Theodore A. Roth - * linux_ppdev.h: New file. - * ppi.c: Include system dependant parallel port interface file. - (ppi_open): Add call to ppi_claim(). - (ppi_close): Add call to ppi_release(). - * ppi.h: Define ppi_claim() and ppi_release() as NOPs if not previously - defined. - * stk500.c: Include inttypes header to quell compiler warning. + * linux_ppdev.h: New file. + * ppi.c: Include system dependant parallel port interface file. + (ppi_open): Add call to ppi_claim(). + (ppi_close): Add call to ppi_release(). + * ppi.h: Define ppi_claim() and ppi_release() as NOPs if not previously + defined. + * stk500.c: Include inttypes header to quell compiler warning. 2003-02-11 Joerg Wunsch - * pgm.c, ppi.c, stk500.c: Fix some implicit declaration warnings. + * pgm.c, ppi.c, stk500.c: Fix some implicit declaration warnings. - * config_gram.y: - Move the C declarations to the top of the file. While [b]yacc doesn't - care, bison does, and this is normally the way it's meant to be - anyway. + * config_gram.y: + Move the C declarations to the top of the file. While [b]yacc doesn't + care, bison does, and this is normally the way it's meant to be + anyway. 2003-02-11 Theodore A. Roth - * Makefile: Generate dependencies specific to the target system. - Explicitly use byacc. + * Makefile: Generate dependencies specific to the target system. + Explicitly use byacc. - * Makefile: - Remove reference to avr-gcc in depend rule (cut & paste error). + * Makefile: + Remove reference to avr-gcc in depend rule (cut & paste error). 2003-02-09 Brian S. Dean - * main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h, stk500.c: - * stk500.h, stk500_private.h, term.c, term.h, CHANGELOG, COPYING: - * Makefile, avr.c, avr.h, avrdude.1, avrdude.conf.sample: - * avrdude.pdf, avrpart.h, config.c, config.h, config_gram.y: - * fileio.c, fileio.h, lexer.l, lists.c, lists.h: - Test commit in new public repository. Before this time this repo - existed on a private system. Commits made by 'bsd' on the old system - were made by Brian Dean (bdean on the current system). + * main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h, stk500.c: + * stk500.h, stk500_private.h, term.c, term.h, CHANGELOG, COPYING: + * Makefile, avr.c, avr.h, avrdude.1, avrdude.conf.sample: + * avrdude.pdf, avrpart.h, config.c, config.h, config_gram.y: + * fileio.c, fileio.h, lexer.l, lists.c, lists.h: + Test commit in new public repository. Before this time this repo + existed on a private system. Commits made by 'bsd' on the old system + were made by Brian Dean (bdean on the current system). 2003-02-08 Brian S. Dean - * Makefile, avr.c, avr.h, avrdude.1, avrpart.h, config.c, - * config.h, config_gram.y, fileio.c, fileio.h, lexer.l, lists.c: - * lists.h, main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h: - * stk500.c, stk500.h, term.c, term.h: - The last part of that last commit message should read: + * Makefile, avr.c, avr.h, avrdude.1, avrpart.h, config.c, + * config.h, config_gram.y, fileio.c, fileio.h, lexer.l, lists.c: + * lists.h, main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h: + * stk500.c, stk500.h, term.c, term.h: + The last part of that last commit message should read: - All others - modify program description. + All others - modify program description. - * Makefile, avr.c, avr.h, avrdude.1, avrpart.h, config.c: - * config.h, config_gram.y, fileio.c, fileio.h, lexer.l, lists.c: - * lists.h, main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h: - * stk500.c, stk500.h, term.c, term.h: - Makefile: include a target to automatically generate the dependency - list. + * Makefile, avr.c, avr.h, avrdude.1, avrpart.h, config.c: + * config.h, config_gram.y, fileio.c, fileio.h, lexer.l, lists.c: + * lists.h, main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h: + * stk500.c, stk500.h, term.c, term.h: + Makefile: include a target to automatically generate the dependency + list. - All others + All others 2003-02-06 Brian S. Dean - * avrdude.1: Update license to GPL, permission by Joerg Wunsch. - - * lexer.l: Add GPL. - - * Makefile, config_gram.y: Add GPL to the Makefile and config_gram.y. - - * Makefile, stk500.h: - Add stk500.h as a dependency for stk500.c. Remove carraige returns - from stk500.h - don't know how those got in there (pointed out by Ted - Roth). - - * COPYING, avr.c, avr.h, avrpart.h, config.c, config.h, fileio.c: - * fileio.h, lists.c, lists.h, main.c, pgm.c, pgm.h, pindefs.h: - * ppi.c, ppi.h, stk500.c, stk500.h, term.c, term.h: - Re-license using the GNU GPL. Thanks to Ted Roth for the patch. - - * avr.c, avr.h, config.c, config.h, config_gram.y, fileio.c: - * fileio.h, lexer.l, lists.c, lists.h, main.c, pgm.c, pgm.h: - * pindefs.h, ppi.c, ppi.h, stk500.c, stk500.h, term.c, term.h: - Get rid of the verbose printing of individual file CVS version ids. - This was intended to be used for identifying code in the field for - incoming bug reports, but I've never really found it all that useful. - - * CHANGELOG, Makefile, Makefile.inc, avr.c, avrdude.1: - * avrdude.conf.sample, config_gram.y, lexer.l, main.c, stk500.c: - * term.c: - Change the name from AVRPROG to AVRDUDE. - - This change represents a name change only. There is currently an - effort to port AVRPROG to other platforms including Linux and Windows. - Since Atmel's programmer binary that's included within their AVR - Studio software is named AVRPROG.EXE on the Windows OS, there is the - chance for confusion if we keep calling this program AVRPROG as well. - Up until now the name hasn't really been a problem since there was no - chance to confuse 'avrprog' on Unix with Atmel's AVRPROG because - Atmel's tools only run on Windows. But with the Unix 'avrprog' - possibly being ported to Windows, I felt a name change was the best - way to avoid problems. - - So - from this point forward, my FreeBSD Unix program formerly - known as AVRPROG will subsequently be known as AVRDUDE (AVR - Downloader/UploaDEr). - - This change also represents a time when the AVRDUDE sources move from - my own private repository to a public repository. This will give - other developers a chance to port AVRDUDE to other platforms and - extend its functionality to support additional programming hardware, - etc. - - So goodbye AVRPROG, welcome AVRDUDE! + * avrdude.1: Update license to GPL, permission by Joerg Wunsch. + + * lexer.l: Add GPL. + + * Makefile, config_gram.y: Add GPL to the Makefile and config_gram.y. + + * Makefile, stk500.h: + Add stk500.h as a dependency for stk500.c. Remove carraige returns + from stk500.h - don't know how those got in there (pointed out by Ted + Roth). + + * COPYING, avr.c, avr.h, avrpart.h, config.c, config.h, fileio.c: + * fileio.h, lists.c, lists.h, main.c, pgm.c, pgm.h, pindefs.h: + * ppi.c, ppi.h, stk500.c, stk500.h, term.c, term.h: + Re-license using the GNU GPL. Thanks to Ted Roth for the patch. + + * avr.c, avr.h, config.c, config.h, config_gram.y, fileio.c: + * fileio.h, lexer.l, lists.c, lists.h, main.c, pgm.c, pgm.h: + * pindefs.h, ppi.c, ppi.h, stk500.c, stk500.h, term.c, term.h: + Get rid of the verbose printing of individual file CVS version ids. + This was intended to be used for identifying code in the field for + incoming bug reports, but I've never really found it all that useful. + + * CHANGELOG, Makefile, Makefile.inc, avr.c, avrdude.1: + * avrdude.conf.sample, config_gram.y, lexer.l, main.c, stk500.c: + * term.c: + Change the name from AVRPROG to AVRDUDE. + + This change represents a name change only. There is currently an + effort to port AVRPROG to other platforms including Linux and Windows. + Since Atmel's programmer binary that's included within their AVR + Studio software is named AVRPROG.EXE on the Windows OS, there is the + chance for confusion if we keep calling this program AVRPROG as well. + Up until now the name hasn't really been a problem since there was no + chance to confuse 'avrprog' on Unix with Atmel's AVRPROG because + Atmel's tools only run on Windows. But with the Unix 'avrprog' + possibly being ported to Windows, I felt a name change was the best + way to avoid problems. + + So - from this point forward, my FreeBSD Unix program formerly + known as AVRPROG will subsequently be known as AVRDUDE (AVR + Downloader/UploaDEr). + + This change also represents a time when the AVRDUDE sources move from + my own private repository to a public repository. This will give + other developers a chance to port AVRDUDE to other platforms and + extend its functionality to support additional programming hardware, + etc. + + So goodbye AVRPROG, welcome AVRDUDE! diff --git a/src/avrdude/ChangeLog-2004-2006 b/src/avrdude/ChangeLog-2004-2006 index 20e5b2e8bff..2fc868d61d6 100644 --- a/src/avrdude/ChangeLog-2004-2006 +++ b/src/avrdude/ChangeLog-2004-2006 @@ -1,1644 +1,1644 @@ 2006-12-23 Joerg Wunsch - * configure.ac (AC_INIT): Bump version to 5.3cvs (again). + * configure.ac (AC_INIT): Bump version to 5.3cvs (again). 2006-12-22 Joerg Wunsch - * configure.ac (AC_INIT): Bump version to 5.3.1. - * avrdude.conf.in (frank-stk200): Fix syntax error. - * ser_avrdoper.c: Make #ifdef for Win32/libhid - consistent with the initial check: use the HID driver - only iff found, otherwise use libusb. + * configure.ac (AC_INIT): Bump version to 5.3.1. + * avrdude.conf.in (frank-stk200): Fix syntax error. + * ser_avrdoper.c: Make #ifdef for Win32/libhid + consistent with the initial check: use the HID driver + only iff found, otherwise use libusb. 2006-12-21 Joerg Wunsch - * configure.ac (AC_INIT): Bump version to 5.3cvs. + * configure.ac (AC_INIT): Bump version to 5.3cvs. 2006-12-21 Joerg Wunsch - Released AVRDUDE 5.3. + Released AVRDUDE 5.3. 2006-12-21 Joerg Wunsch - * configure.ac (AC_INIT): Bump version to 5.3. + * configure.ac (AC_INIT): Bump version to 5.3. 2006-12-21 Joerg Wunsch - Submitted by Vince VG: - * avrdude.conf.in (frank-stk200): New programmer added. - * doc/avrdude.texi: Mention frank-stk200. - Closes patch #5502: one other programmer + Submitted by Vince VG: + * avrdude.conf.in (frank-stk200): New programmer added. + * doc/avrdude.texi: Mention frank-stk200. + Closes patch #5502: one other programmer 2006-12-21 Joerg Wunsch - Submitted by Christian Starkjohann: - * ser_avrdoper.c (usbOpenDevice): clear the error code when - returning successfully. + Submitted by Christian Starkjohann: + * ser_avrdoper.c (usbOpenDevice): clear the error code when + returning successfully. 2006-12-21 Joerg Wunsch - Submitted by Christian Starkjohann: - patch #5507: Support for AVR-Doper USB programmer in HID mode - * configure.ac: Add hooks to detect the Win32 HID library, - as well as the existence of . - * Makefile.am: Add new files. - * my_ddk_hidsdi.h: (New file.) - * ser_avrdoper.c: (New file.) - * serial.h: Add declaration for avrdoper_serdev. - * stk500v2.c: Add hook to divert to the AVR Doper code. - * avrdude.1: Document the AVR Doper support. - * doc/avrdude.texi: (Ditto.) + Submitted by Christian Starkjohann: + patch #5507: Support for AVR-Doper USB programmer in HID mode + * configure.ac: Add hooks to detect the Win32 HID library, + as well as the existence of . + * Makefile.am: Add new files. + * my_ddk_hidsdi.h: (New file.) + * ser_avrdoper.c: (New file.) + * serial.h: Add declaration for avrdoper_serdev. + * stk500v2.c: Add hook to divert to the AVR Doper code. + * avrdude.1: Document the AVR Doper support. + * doc/avrdude.texi: (Ditto.) 2006-12-15 Joerg Wunsch - Submitted by ivanv at netman.ru - * jtagmkI.c: fix length for single-byte write operations. - Closes bug #18527 JTAG ICE: fuse bits have been writen incorrectly + Submitted by ivanv at netman.ru + * jtagmkI.c: fix length for single-byte write operations. + Closes bug #18527 JTAG ICE: fuse bits have been writen incorrectly 2006-12-11 Joerg Wunsch - * jtagmkII.c (jtagmkII_paged_write): Remove a debugging - usleep(1000000) that accidentally crept in in rev 1.19. + * jtagmkII.c (jtagmkII_paged_write): Remove a debugging + usleep(1000000) that accidentally crept in in rev 1.19. 2006-12-11 Joerg Wunsch - * ser_posix.c (ser_open): Do fill in fdp->ifd before already - using it in ser_setspeed(). + * ser_posix.c (ser_open): Do fill in fdp->ifd before already + using it in ser_setspeed(). 2006-12-11 Joerg Wunsch - * jtagmkI.c (jtagmkI_close): revert baud rate to the initial - value in case we had changed it. - Fixes bug #18262: JTAGMKI/JTAG1 Reset Bug + * jtagmkI.c (jtagmkI_close): revert baud rate to the initial + value in case we had changed it. + Fixes bug #18262: JTAGMKI/JTAG1 Reset Bug 2006-12-11 Colin O'Flynn - * safemode.c: Stop ignoring return values! - Closes bug #18339 + * safemode.c: Stop ignoring return values! + Closes bug #18339 2006-12-11 Joerg Wunsch - Submitted by Nick Lott: - * avrdude.conf.in: Fix signature for ATmega8515. - Closes bug #18348: ATMEGA8515 Signature is wrong in avrdude.conf + Submitted by Nick Lott: + * avrdude.conf.in: Fix signature for ATmega8515. + Closes bug #18348: ATMEGA8515 Signature is wrong in avrdude.conf 2006-12-11 Joerg Wunsch - * avr.c: Fix a bug introduced in rev. 1.69, when implementing the - fallback from each programmer's paged_load() or paged_write() - method, respectively. The return value needs to be checked for - being greater or equal than 0 rather equal to 0 in order to - assume the operation has been successful. - Fixes bug #18489: avrdude is too slow (20 byte/s) + * avr.c: Fix a bug introduced in rev. 1.69, when implementing the + fallback from each programmer's paged_load() or paged_write() + method, respectively. The return value needs to be checked for + being greater or equal than 0 rather equal to 0 in order to + assume the operation has been successful. + Fixes bug #18489: avrdude is too slow (20 byte/s) 2006-12-11 Joerg Wunsch - * avr910.c: Make the code compile warning-free: - - declare a dummy "struct timezone" for some Win32 systems (MinGW) - - fix a few printf() argument types - - get rid off the prevailing "all filedescriptors are of type int" - attitude - The last item required a large sweep across the code, in order to - replace all "int fd"s by "struct filedescriptor *fd"s, and pass - pointers (as we cannot pass a union directly). In return, the - code is now supposed to be fully 64-bit safe, rather than relying - on a 64-bit pointer being converted to a (32-bit) int and back - to a pointer as we did previously. - * butterfly.c: (Ditto.) - * jtagmkI.c: (Ditto.) - * jtagmkII.c: (Ditto.) - * lists.c: (Ditto.) - * par.c: (Ditto.) - * pgm.h: (Ditto.) - * ppi.c: (Ditto.) - * ppi.h: (Ditto.) - * ppiwin.c: (Ditto.) - * ser_posix.c: (Ditto.) - * ser_win32.c: (Ditto.) - * serbb_posix.c: (Ditto.) - * serbb_win32.c: (Ditto.) - * serial.h: (Ditto.) - * stk500.c: (Ditto.) - * stk500v2.c: (Ditto.) - * usb_libusb.c: (Ditto.) + * avr910.c: Make the code compile warning-free: + - declare a dummy "struct timezone" for some Win32 systems (MinGW) + - fix a few printf() argument types + - get rid off the prevailing "all filedescriptors are of type int" + attitude + The last item required a large sweep across the code, in order to + replace all "int fd"s by "struct filedescriptor *fd"s, and pass + pointers (as we cannot pass a union directly). In return, the + code is now supposed to be fully 64-bit safe, rather than relying + on a 64-bit pointer being converted to a (32-bit) int and back + to a pointer as we did previously. + * butterfly.c: (Ditto.) + * jtagmkI.c: (Ditto.) + * jtagmkII.c: (Ditto.) + * lists.c: (Ditto.) + * par.c: (Ditto.) + * pgm.h: (Ditto.) + * ppi.c: (Ditto.) + * ppi.h: (Ditto.) + * ppiwin.c: (Ditto.) + * ser_posix.c: (Ditto.) + * ser_win32.c: (Ditto.) + * serbb_posix.c: (Ditto.) + * serbb_win32.c: (Ditto.) + * serial.h: (Ditto.) + * stk500.c: (Ditto.) + * stk500v2.c: (Ditto.) + * usb_libusb.c: (Ditto.) 2006-11-23 Joerg Wunsch - Implement EEPROM access through debugWire. - * jtagmkII.c: Extend the jtagmkII_read_byte() and - jtagmkII_write_byte() methods to handle EEPROM through - debugWire. - * avrpart.h: Implement the "flash instruction" parameter. - * config_gram.y: (Ditto.) - * lexer.l: (Ditto.) - * avrdude.conf.in: (Ditto.) - * avrdude.1: Document the EEPROM access through dW. - * doc/avrdude.texi: (Ditto.) - * tools/get-dw-params.xsl: Extend to extract the flash - instruction field. + Implement EEPROM access through debugWire. + * jtagmkII.c: Extend the jtagmkII_read_byte() and + jtagmkII_write_byte() methods to handle EEPROM through + debugWire. + * avrpart.h: Implement the "flash instruction" parameter. + * config_gram.y: (Ditto.) + * lexer.l: (Ditto.) + * avrdude.conf.in: (Ditto.) + * avrdude.1: Document the EEPROM access through dW. + * doc/avrdude.texi: (Ditto.) + * tools/get-dw-params.xsl: Extend to extract the flash + instruction field. 2006-11-23 Joerg Wunsch - * avr.c (avr_read, avr_write): if the paged access returns a - failure, fall back to byte access. + * avr.c (avr_read, avr_write): if the paged access returns a + failure, fall back to byte access. 2006-11-21 Joerg Wunsch - * jtagmkII.c: In jtagmkII_read_byte() and jtagmkII_write_byte(), - return an error upon failure now that the upper layers won't fall - back to the cmd() method anymore in that case. + * jtagmkII.c: In jtagmkII_read_byte() and jtagmkII_write_byte(), + return an error upon failure now that the upper layers won't fall + back to the cmd() method anymore in that case. 2006-11-21 Joerg Wunsch - Implement debugWire programming support. - * avrpart.h: Implement debugWire support. - * config_gram.y: (Ditto.) - * jtagmkII.c: (Ditto.) - * jtagmkII.h: (Ditto.) - * lexer.l: (Ditto.) - * avrdude.conf.in: Add the new dW programmers. - * avrdude.1: Document the dW support. - * doc/avrdude.texi: (Ditto.) - * tools/get-dw-params.xsl: XSL stylesheet to extract the dW - parameters from the XML files. + Implement debugWire programming support. + * avrpart.h: Implement debugWire support. + * config_gram.y: (Ditto.) + * jtagmkII.c: (Ditto.) + * jtagmkII.h: (Ditto.) + * lexer.l: (Ditto.) + * avrdude.conf.in: Add the new dW programmers. + * avrdude.1: Document the dW support. + * doc/avrdude.texi: (Ditto.) + * tools/get-dw-params.xsl: XSL stylesheet to extract the dW + parameters from the XML files. 2006-11-20 Joerg Wunsch - * jtagmkI.c (jtagmkI_close): remove two unused variables. + * jtagmkI.c (jtagmkI_close): remove two unused variables. 2006-11-20 Joerg Wunsch - * avr.c: Replace the fallback of avr_read_byte() and avr_write_byte() to - avr_read_byte_default() and avr_write_byte_default (resp.) by directly - calling the latter functions from within all programmers that don't - implement their own read_byte()/write_byte() methods. In turn, make the - read_byte() and write_byte() methods mandatory, and the cmd() method - (direct ISP command) optional instead (it's effectively mandatory for - any programmer using avr_read_byte_default()/avr_write_byte_default() - though). Remove all the pointless cmd() method stubs from those programmers - that don't need it. - Eliminate avr_read_byte() as it was now completely identical to - pgm->read_byte(). - * avr.h: (Ditto.) - * bitbang.c: (Ditto.) - * butterfly.c: (Ditto.) - * jtagmkI.c: (Ditto.) - * jtagmkII.c: (Ditto.) - * par.c: (Ditto.) - * pgm.c: (Ditto.) - * safemode.c: (Ditto.) - * serbb_posix.c: (Ditto.) - * serbb_win32.c: (Ditto.) - * stk500.c: (Ditto.) - * stk500v2.c: (Ditto.) - * term.c: (Ditto.) - * usbasp.c: (Ditto.) + * avr.c: Replace the fallback of avr_read_byte() and avr_write_byte() to + avr_read_byte_default() and avr_write_byte_default (resp.) by directly + calling the latter functions from within all programmers that don't + implement their own read_byte()/write_byte() methods. In turn, make the + read_byte() and write_byte() methods mandatory, and the cmd() method + (direct ISP command) optional instead (it's effectively mandatory for + any programmer using avr_read_byte_default()/avr_write_byte_default() + though). Remove all the pointless cmd() method stubs from those programmers + that don't need it. + Eliminate avr_read_byte() as it was now completely identical to + pgm->read_byte(). + * avr.h: (Ditto.) + * bitbang.c: (Ditto.) + * butterfly.c: (Ditto.) + * jtagmkI.c: (Ditto.) + * jtagmkII.c: (Ditto.) + * par.c: (Ditto.) + * pgm.c: (Ditto.) + * safemode.c: (Ditto.) + * serbb_posix.c: (Ditto.) + * serbb_win32.c: (Ditto.) + * stk500.c: (Ditto.) + * stk500v2.c: (Ditto.) + * term.c: (Ditto.) + * usbasp.c: (Ditto.) 2006-11-13 Joerg Wunsch - * jtagmkI.c: Avoid sending a CMD_RESET when leaving programming - mode, and CMD_GO when closing the connection. They cause the - activity LED on the ICE to continue to flicker, and are not - necessary anyway (the target starts to run by itself when leaving - programmng mode). - This is a partial fix for bug #18262: JTAGMKI/JTAG1 Reset Bug + * jtagmkI.c: Avoid sending a CMD_RESET when leaving programming + mode, and CMD_GO when closing the connection. They cause the + activity LED on the ICE to continue to flicker, and are not + necessary anyway (the target starts to run by itself when leaving + programmng mode). + This is a partial fix for bug #18262: JTAGMKI/JTAG1 Reset Bug 2006-11-12 Colin O'Flunn - * avrdude.conf.in: Add read command for lockbits for Tiny2313. - Applies patch #5538 + * avrdude.conf.in: Add read command for lockbits for Tiny2313. + Applies patch #5538 2006-11-10 Joerg Wunsch - * avrdude.conf.in: Add signatures for ATmega325/3250/645/6450. + * avrdude.conf.in: Add signatures for ATmega325/3250/645/6450. 2006-11-08 Joerg Wunsch - * configure.ac: Preserve ${LDFLAGS} inherited from environment - for Win32 environments. + * configure.ac: Preserve ${LDFLAGS} inherited from environment + for Win32 environments. 2006-11-07 Joerg Wunsch - * configure.ac: Don't pretend --enable-doc were the default. + * configure.ac: Don't pretend --enable-doc were the default. 2006-11-02 Joerg Wunsch - * avrdude.conf.in: Fix the width of the efuse memory area for a - number of AVRs. - Closes bug #18182: Wrong setting of eFuse configuration for - mega640/1280/1281/2560/2561 in avrdude 5.2 + * avrdude.conf.in: Fix the width of the efuse memory area for a + number of AVRs. + Closes bug #18182: Wrong setting of eFuse configuration for + mega640/1280/1281/2560/2561 in avrdude 5.2 2006-11-01 Joerg Wunsch - * avrdude.conf.in: Implement HVSP and PP modes for the AVR Dragon. - * config_gram.y: (Ditto.) - * jtagmkII.c: (Ditto.) - * jtagmkII_private.h: (Ditto.) - * lexer.l: (Ditto.) - * stk500v2.c: (Ditto.) - * stk500v2.h: (Ditto.) - * avrdude.1: Document the HVSP and PP support for the Dragon. - * doc/avrdude.texi: (Ditto.) + * avrdude.conf.in: Implement HVSP and PP modes for the AVR Dragon. + * config_gram.y: (Ditto.) + * jtagmkII.c: (Ditto.) + * jtagmkII_private.h: (Ditto.) + * lexer.l: (Ditto.) + * stk500v2.c: (Ditto.) + * stk500v2.h: (Ditto.) + * avrdude.1: Document the HVSP and PP support for the Dragon. + * doc/avrdude.texi: (Ditto.) 2006-10-27 Joerg Wunsch - * jtagmkI.c: Implement a flags field in struct serdev, and populate it - with a flag that indicates whether the underlying communication can - dynamically change its speed or not. This flag is set for true serial - communication but clear for USB communication. Don't try to adjust - the speed when talking over a communication channel that doesn't - support it. (The Dragon does not even support the respective parameter.) - * jtagmkII.c: (Ditto.) - * ser_posix.c: (Ditto.) - * ser_win32.c: (Ditto.) - * serial.h: (Ditto.) - * usb_libusb.c: (Ditto.) + * jtagmkI.c: Implement a flags field in struct serdev, and populate it + with a flag that indicates whether the underlying communication can + dynamically change its speed or not. This flag is set for true serial + communication but clear for USB communication. Don't try to adjust + the speed when talking over a communication channel that doesn't + support it. (The Dragon does not even support the respective parameter.) + * jtagmkII.c: (Ditto.) + * ser_posix.c: (Ditto.) + * ser_win32.c: (Ditto.) + * serial.h: (Ditto.) + * usb_libusb.c: (Ditto.) 2006-10-26 Joerg Wunsch - * avrdude.conf.in: Add support for the AVR Dragon (JTAG and ISP mode). - * config_gram.y: (Ditto.) - * jtagmkII.c: (Ditto.) - * jtagmkII.h: (Ditto.) - * lexer.l: (Ditto.) - * stk500v2.c: (Ditto.) - * stk500v2.h: (Ditto.) - * usbdevs.h: (Ditto.) - * avrdude.1: Document the AVR Dragon support. - * doc/avrdude.texi: (Ditto.) + * avrdude.conf.in: Add support for the AVR Dragon (JTAG and ISP mode). + * config_gram.y: (Ditto.) + * jtagmkII.c: (Ditto.) + * jtagmkII.h: (Ditto.) + * lexer.l: (Ditto.) + * stk500v2.c: (Ditto.) + * stk500v2.h: (Ditto.) + * usbdevs.h: (Ditto.) + * avrdude.1: Document the AVR Dragon support. + * doc/avrdude.texi: (Ditto.) 2006-10-09 Joerg Wunsch - Released AVRDUDE 5.2. + Released AVRDUDE 5.2. 2006-10-09 Joerg Wunsch - * configure.ac: Bump version to 5.2 + * configure.ac: Bump version to 5.2 2006-10-09 Joerg Wunsch - Submitted by John Voltz: add AVR053 oscillator calibration. - * main.c: Add the -O option. - * pgm.c: Add the hook for the perform_osccal() method. - * pgm.h: (Ditto.) - * stk500v2.c: Implement perform_osccal(). - * avrdude.1: Document the -O option. - * doc/avrdude.texi: (Ditto.) - Partially closes bug #17487: AVR RC oscillator calibration - routine not supported (feature request) + Submitted by John Voltz: add AVR053 oscillator calibration. + * main.c: Add the -O option. + * pgm.c: Add the hook for the perform_osccal() method. + * pgm.h: (Ditto.) + * stk500v2.c: Implement perform_osccal(). + * avrdude.1: Document the -O option. + * doc/avrdude.texi: (Ditto.) + Partially closes bug #17487: AVR RC oscillator calibration + routine not supported (feature request) 2006-10-09 Joerg Wunsch - Submitted by freckle@sf.net: - * stk500.c (stk500_paged_write): Send the command and the data - payload within a single write(). - patch #5025: Improve stk500.c robustness + Submitted by freckle@sf.net: + * stk500.c (stk500_paged_write): Send the command and the data + payload within a single write(). + patch #5025: Improve stk500.c robustness - Submitted by Matthias Ringwald: - * stk500.c (stk500_open): do not flush the serial line after - getting in sync with the programmer. - patch #5293: stk500.c: no drain after sync (-> allow BTnode - Bootloader to work on cygwin) + Submitted by Matthias Ringwald: + * stk500.c (stk500_open): do not flush the serial line after + getting in sync with the programmer. + patch #5293: stk500.c: no drain after sync (-> allow BTnode + Bootloader to work on cygwin) 2006-09-29 Joerg Wunsch - * pgm.h: Fix prototype for gettimeofday(). - Closes bug #17884: another gettimeofday conflict under win32/cygwin + * pgm.h: Fix prototype for gettimeofday(). + Closes bug #17884: another gettimeofday conflict under win32/cygwin 2006-09-24 Joerg Wunsch - Submitted by Thomas Fischl (initially): - * configure.ac: Add the CoreFoundation and IOKit framework - linker flags on MacOS X when configuring for USB support. - patch #4685: Libusb on MacOS X: detection and additional includes + Submitted by Thomas Fischl (initially): + * configure.ac: Add the CoreFoundation and IOKit framework + linker flags on MacOS X when configuring for USB support. + patch #4685: Libusb on MacOS X: detection and additional includes 2006-09-20 Joerg Wunsch - * avr910.c: As there is a lot of ambiguity about the AVR910 - device codes, allow the user to override the device code - verification with the -F option. - * main.c: Make ovsigck a global variable. + * avr910.c: As there is a lot of ambiguity about the AVR910 + device codes, allow the user to override the device code + verification with the -F option. + * main.c: Make ovsigck a global variable. 2006-09-20 Joerg Wunsch - Add the "stk500generic" programmer that auto-probes for STK500 - either firmware version 1 or 2. - * Makefile.am (avrdude_SOURCES): add the new files - stk500generic.c and stk500generic.h. - * avrdude.conf.in: Add the stk500generic programmer type, and - change the "stk500" entry to point to this programmer. - * config_gram.y: Add the stk500generic keyword. - * lexer.l: (Ditto.) - * stk500.c: Change the stk500v1 code to not call exit() - prematurely when failing to open the programmer, but instead - return an error status. - * stk500generic.c: (New file.) Stub programmer implementation. - Probe for either stk500v1 or stk500v2, and adjust the current pgm - appropriately. - * stk500generic.h: (New file.) Declare the public interface(s) - of stk500generic.c. - * doc/avrdude.texi: Document the changed behaviour of stk500. + Add the "stk500generic" programmer that auto-probes for STK500 + either firmware version 1 or 2. + * Makefile.am (avrdude_SOURCES): add the new files + stk500generic.c and stk500generic.h. + * avrdude.conf.in: Add the stk500generic programmer type, and + change the "stk500" entry to point to this programmer. + * config_gram.y: Add the stk500generic keyword. + * lexer.l: (Ditto.) + * stk500.c: Change the stk500v1 code to not call exit() + prematurely when failing to open the programmer, but instead + return an error status. + * stk500generic.c: (New file.) Stub programmer implementation. + Probe for either stk500v1 or stk500v2, and adjust the current pgm + appropriately. + * stk500generic.h: (New file.) Declare the public interface(s) + of stk500generic.c. + * doc/avrdude.texi: Document the changed behaviour of stk500. 2006-09-18 Joerg Wunsch - * avrdude.conf.in: Various fixes for ancient processors and their - capabilities. For the AT90S1200 and the AT90S8515, fuse bit - handling via ISP, and lock bit reading via ISP are not supported - at all. For the AT90S4414 (small brother of the AT90S8515), add - the ability to write the lock bits, and add a definition for the - fuse bits (usable for HV programming). For the AT90S2313, add the - "fuse" memory range, so it's available for HV programming. + * avrdude.conf.in: Various fixes for ancient processors and their + capabilities. For the AT90S1200 and the AT90S8515, fuse bit + handling via ISP, and lock bit reading via ISP are not supported + at all. For the AT90S4414 (small brother of the AT90S8515), add + the ability to write the lock bits, and add a definition for the + fuse bits (usable for HV programming). For the AT90S2313, add the + "fuse" memory range, so it's available for HV programming. - Resolves bug #17796: avrdude will not program or verify lockbits - with Atmel STK protocol programmers + Resolves bug #17796: avrdude will not program or verify lockbits + with Atmel STK protocol programmers 2006-09-17 Joerg Wunsch - Submitted by Thomas Fischl: - * usbasp.c: Check for USBasp with new as well as old VID/PID - pair, warn the user about upgrading the firmware in case an - old one has been found. - * usbasp.h: Add new VID/PID. + Submitted by Thomas Fischl: + * usbasp.c: Check for USBasp with new as well as old VID/PID + pair, warn the user about upgrading the firmware in case an + old one has been found. + * usbasp.h: Add new VID/PID. 2006-09-15 Joerg Wunsch - * avrdude.conf.in: Fix some mistakes for the ATtinyX61 family: - . high fuse has 8 bits - . there is an extended fuse (just one bit) - . the calibration area is only 1 byte + * avrdude.conf.in: Fix some mistakes for the ATtinyX61 family: + . high fuse has 8 bits + . there is an extended fuse (just one bit) + . the calibration area is only 1 byte 2006-09-12 Joerg Wunsch - * doc/avrdude.texi: Convert some of the tables to multitables - in order to beautify the result. + * doc/avrdude.texi: Convert some of the tables to multitables + in order to beautify the result. 2006-09-10 Joerg Wunsch - Contributed by Thomas Fischl: add support for USBasp. - patch #4686: Add support for USBasp, a simple USB programmer - * usbasp.c: New file, implement the USBasp driver. - * usbasp.h: New file, interface declarations for USBasp. - * Makefile.am: Wire the new files into the build. - * avrdude.conf.in: Add the usbasp programmer entry. - * config_gram.y: Add the usbasp token. - * lexer.l: (Ditto.) - * avrdude.1: Document the USBasp programmer. - * doc/avrdude.texi: (Ditto.) + Contributed by Thomas Fischl: add support for USBasp. + patch #4686: Add support for USBasp, a simple USB programmer + * usbasp.c: New file, implement the USBasp driver. + * usbasp.h: New file, interface declarations for USBasp. + * Makefile.am: Wire the new files into the build. + * avrdude.conf.in: Add the usbasp programmer entry. + * config_gram.y: Add the usbasp token. + * lexer.l: (Ditto.) + * avrdude.1: Document the USBasp programmer. + * doc/avrdude.texi: (Ditto.) 2006-09-08 Joerg Wunsch - * main.c: Implement -U filename as a shorthand for - -U flash:w:filename:a. - * avrdude.1: Document this. - * doc/avrdude.texi: (Ditto.) + * main.c: Implement -U filename as a shorthand for + -U flash:w:filename:a. + * avrdude.1: Document this. + * doc/avrdude.texi: (Ditto.) 2006-09-08 Joerg Wunsch - Implement numerical output formats for decimal, hexadecimal, - octal, and binary numbers. - Closes bug #16129: more output formats for fuse bits - (avrdude enhancement request) - * fileio.c: Implement fileio_num() and the itoa_simple() - helper function. - * fileio.h: Add new file formats to FILEFMT. - * main.c: Parse the new file formats. - * avrdude.1: Document all this. - * doc/avrdude.texi: (Ditto.) + Implement numerical output formats for decimal, hexadecimal, + octal, and binary numbers. + Closes bug #16129: more output formats for fuse bits + (avrdude enhancement request) + * fileio.c: Implement fileio_num() and the itoa_simple() + helper function. + * fileio.h: Add new file formats to FILEFMT. + * main.c: Parse the new file formats. + * avrdude.1: Document all this. + * doc/avrdude.texi: (Ditto.) 2006-09-08 Joerg Wunsch - * fileio.c: CPP statements start in column #1. - * stk500v2.c: Hide two debug/trace statements behind "verbose". + * fileio.c: CPP statements start in column #1. + * stk500v2.c: Hide two debug/trace statements behind "verbose". 2006-09-07 Joerg Wunsch - * avrdude.1: Describe how to disable the DWEN fuse. - * doc/avrdude.texi: (Ditto.) + * avrdude.1: Describe how to disable the DWEN fuse. + * doc/avrdude.texi: (Ditto.) 2006-09-07 Joerg Wunsch - * jtagmkII.c: Translate numerical response codes to strings. + * jtagmkII.c: Translate numerical response codes to strings. 2006-09-07 Joerg Wunsch - * avrdude.1: The avr109 programmer type no longer chokes on - a wrong avr910 device ID, so remove that description. - * doc/avrdude.texi: (Ditto.) + * avrdude.1: The avr109 programmer type no longer chokes on + a wrong avr910 device ID, so remove that description. + * doc/avrdude.texi: (Ditto.) 2006-09-07 Joerg Wunsch - * jtagmkII.c: When failing to start in ISP mode, try - debugWire instead. This requires the user to eventually - restart AVRDUE from scratch then. + * jtagmkII.c: When failing to start in ISP mode, try + debugWire instead. This requires the user to eventually + restart AVRDUE from scratch then. 2006-09-06 Joerg Wunsch - Add support for the JTAG ICE mkII in ISP mode. - * avrdude.conf.in (jtag2isp): New programmer entry. - * config_gram.y: Add K_JTAG_MKII_ISP. - * jtagmkII.c: Restructure and export some more functions. - * jtagmkII.h: Declare exported functions. - * jtagmkII_private.h: Prepare file to be included in stk500v2.c. - * lexer.l: Add jtagmkii_isp token. - * stk500v2.c: Implement glue to jtagmkII.c. - * stk500v2.h: Declare stk500v2_jtagmkII_initpgm(). - * avrdude.1: Document the new programmer support. - * doc/avrdude.texi: (Ditto.) + Add support for the JTAG ICE mkII in ISP mode. + * avrdude.conf.in (jtag2isp): New programmer entry. + * config_gram.y: Add K_JTAG_MKII_ISP. + * jtagmkII.c: Restructure and export some more functions. + * jtagmkII.h: Declare exported functions. + * jtagmkII_private.h: Prepare file to be included in stk500v2.c. + * lexer.l: Add jtagmkii_isp token. + * stk500v2.c: Implement glue to jtagmkII.c. + * stk500v2.h: Declare stk500v2_jtagmkII_initpgm(). + * avrdude.1: Document the new programmer support. + * doc/avrdude.texi: (Ditto.) 2006-09-01 Joerg Wunsch - * main.c: Add date and time of compilation to the verbose - greeting message. - Idea taken from patch #3172: Adds date and time of compile - to usage message + * main.c: Add date and time of compilation to the verbose + greeting message. + Idea taken from patch #3172: Adds date and time of compile + to usage message 2006-09-01 Joerg Wunsch - Contributed by as - patch #4372: Better synchronization for stk500 - * stk500.c: Sync three times, and drop any noise inbetween. + Contributed by as + patch #4372: Better synchronization for stk500 + * stk500.c: Sync three times, and drop any noise inbetween. 2006-09-01 Joerg Wunsch - * avrdude.conf.in (ATtiny261, ATtiny461, ATtiny861): new - entries. + * avrdude.conf.in (ATtiny261, ATtiny461, ATtiny861): new + entries. 2006-09-01 Joerg Wunsch - * butterfly.c: Remove the device support decision based on - the old AVR910 device codes; we've got signature verification - now so better rely on that. - * avr910.c: Revert the signature bytes returned, as it already - happened in butterfly.c. This closes bug #14998: Signature Bytes - read in wrong order (avr910 mode) + * butterfly.c: Remove the device support decision based on + the old AVR910 device codes; we've got signature verification + now so better rely on that. + * avr910.c: Revert the signature bytes returned, as it already + happened in butterfly.c. This closes bug #14998: Signature Bytes + read in wrong order (avr910 mode) 2006-09-01 Joerg Wunsch - Submitted by Wim Lewis. - * serbb_posix.c: Improve error handling. - patch #4923: Better error reporting for serial-bitbang programmers + Submitted by Wim Lewis. + * serbb_posix.c: Improve error handling. + patch #4923: Better error reporting for serial-bitbang programmers 2006-08-31 Joerg Wunsch - * avrdude.conf.in: Introduce a "stk500v1" entry, so we - can switch the default "stk500" to "stk500v2" some day. + * avrdude.conf.in: Introduce a "stk500v1" entry, so we + can switch the default "stk500" to "stk500v2" some day. 2006-08-31 Joerg Wunsch - The major part of this change has been contributed by - . - Implements patch #4635: Add support for terminal/console - servers for serial programmers - * ser_posix.c: Add net_open(), and divert to it for net:host:port. - * ser_win32.c: Recognize net:host:port, and bail out. - * avrdude.1: Document the net:host:port connection option. - * doc/avrdude.texi: (Ditto.) + The major part of this change has been contributed by + . + Implements patch #4635: Add support for terminal/console + servers for serial programmers + * ser_posix.c: Add net_open(), and divert to it for net:host:port. + * ser_win32.c: Recognize net:host:port, and bail out. + * avrdude.1: Document the net:host:port connection option. + * doc/avrdude.texi: (Ditto.) 2006-08-31 Joerg Wunsch - Fix for bug #16627: Butterfly programmer does not reset after - programming - * butterfly.c: Wait for the device's response after sending - an "E" command. + Fix for bug #16627: Butterfly programmer does not reset after + programming + * butterfly.c: Wait for the device's response after sending + an "E" command. 2006-08-31 Joerg Wunsch - Tentative fix for bug #16156: Problem with Si-Prog - * serbb_posix.c: Disable reset before closing. - * serbb_win32.c: (Ditto.) + Tentative fix for bug #16156: Problem with Si-Prog + * serbb_posix.c: Disable reset before closing. + * serbb_win32.c: (Ditto.) 2006-08-30 Joerg Wunsch - Rewrite the serbb code so the pin numbering matches the - DB9 connector, and fix some related bugs in serbb_posix.c. - Closes bug #16265: dasa2 does not work under posix - * avrdude.conf.in: New serbb pin numbering; added "siprog" - as an alias for "ponyser". - * serbb_posix.c: New pin numbering, fix some confusion. - * serbb_win32.c: New pin numbering. - The generic and Posix-related parts of these changes have - been contributed by Hanns-Konrad Unger + Rewrite the serbb code so the pin numbering matches the + DB9 connector, and fix some related bugs in serbb_posix.c. + Closes bug #16265: dasa2 does not work under posix + * avrdude.conf.in: New serbb pin numbering; added "siprog" + as an alias for "ponyser". + * serbb_posix.c: New pin numbering, fix some confusion. + * serbb_win32.c: New pin numbering. + The generic and Posix-related parts of these changes have + been contributed by Hanns-Konrad Unger 2006-08-30 Joerg Wunsch - Contributed by the anonymous developer of patch #5096: - * avrdude.conf.in (blaster): Add an entry for the Altera - byteblaster. + Contributed by the anonymous developer of patch #5096: + * avrdude.conf.in (blaster): Add an entry for the Altera + byteblaster. 2006-08-30 Joerg Wunsch - Rework the exit specs so they actually work again. It should be - possible to extend them for other programmers than PPI now (serbb, - stk500*). - * pgm.h: Keep the exit specs in an abstract form inside struct - programmer_t. (Should be moved out into some programmer-specific - structure.) Rename the getexitspecs() method into - parseexitspecs(). - * main.c: Move the exit specs stuff out to the programmer - implementation. - * par.c: Implement the new exit spec handling. Everything is now - done using the generic abstraction layer. - Closes bug #16443: No disable Resetsignal at the end of - Programming Session - Obviates need for patch #5057: quick and dirty Hack to unset Reset - after Programming + Rework the exit specs so they actually work again. It should be + possible to extend them for other programmers than PPI now (serbb, + stk500*). + * pgm.h: Keep the exit specs in an abstract form inside struct + programmer_t. (Should be moved out into some programmer-specific + structure.) Rename the getexitspecs() method into + parseexitspecs(). + * main.c: Move the exit specs stuff out to the programmer + implementation. + * par.c: Implement the new exit spec handling. Everything is now + done using the generic abstraction layer. + Closes bug #16443: No disable Resetsignal at the end of + Programming Session + Obviates need for patch #5057: quick and dirty Hack to unset Reset + after Programming 2006-08-29 Joerg Wunsch - This patch has been contributed by an anonymous developer - via the patch tracking system. - patch #5096: Allow VCC and BUFF to be any pin in parallel mode - * config_gram.y: Release the restriction to PPIDATA pins. - * par.c: Rework the code to introduce a function par_setmany() - that builds on top of par_setpin(), and use that function for the - PPI_AVR_VCC and PPI_AVR_BUFF pin collections. This also abstracts - the polarity of these signals appropriately. + This patch has been contributed by an anonymous developer + via the patch tracking system. + patch #5096: Allow VCC and BUFF to be any pin in parallel mode + * config_gram.y: Release the restriction to PPIDATA pins. + * par.c: Rework the code to introduce a function par_setmany() + that builds on top of par_setpin(), and use that function for the + PPI_AVR_VCC and PPI_AVR_BUFF pin collections. This also abstracts + the polarity of these signals appropriately. 2006-08-28 Joerg Wunsch - Contributed by Ned Konz: - * ser_posix.c: Open the serial port with O_NONBLOCK, and - save and restore the port state before exiting. - patch #5008: Patch for (5.1) ser_posix.c for O_NONBLOCK open - and restoring serial port state on close - Closes bug #12622: avrdude hangs on macosx/darwin with PL-2303 - usb-to-serial and Butterfly + Contributed by Ned Konz: + * ser_posix.c: Open the serial port with O_NONBLOCK, and + save and restore the port state before exiting. + patch #5008: Patch for (5.1) ser_posix.c for O_NONBLOCK open + and restoring serial port state on close + Closes bug #12622: avrdude hangs on macosx/darwin with PL-2303 + usb-to-serial and Butterfly 2006-08-22 Joerg Wunsch - * bitbang.c: Move the bitbang prerequisite checks out from - main() into their own bitbang_check_prerequisites(). - * bitbang.h: (Ditto.) - * main.c: (Ditto.) - * par.c: (Ditto.) - * serbb_posix.c: (Ditto.) - * serbb_win32.c: (Ditto.) + * bitbang.c: Move the bitbang prerequisite checks out from + main() into their own bitbang_check_prerequisites(). + * bitbang.h: (Ditto.) + * main.c: (Ditto.) + * par.c: (Ditto.) + * serbb_posix.c: (Ditto.) + * serbb_win32.c: (Ditto.) 2006-08-22 Joerg Wunsch - * avrdude.conf.in: Add page mode parameters for all "eeprom" - memory definitions that are organized in pages. - * avr.c (avr_write_byte_default): Consider using the loadpage - instructions only if the respective memory is marked "paged". - Closes bug #17199: EEPROM fails verification on ATmega645 with - pony-stk200 hardware - Closes bug #16849: EEPROM write fails for AT90USB1287 with - mode 0x41 - Closes bug #15146: stk500v2_paged_write: loadpage instruction - not defined for part + * avrdude.conf.in: Add page mode parameters for all "eeprom" + memory definitions that are organized in pages. + * avr.c (avr_write_byte_default): Consider using the loadpage + instructions only if the respective memory is marked "paged". + Closes bug #17199: EEPROM fails verification on ATmega645 with + pony-stk200 hardware + Closes bug #16849: EEPROM write fails for AT90USB1287 with + mode 0x41 + Closes bug #15146: stk500v2_paged_write: loadpage instruction + not defined for part 2006-08-22 Joerg Wunsch - * doc/avrdude.info (-c): Change "avrispmk2" into "avrisp2" as that - is the programmer actually supported by avrdude.conf.in. - Closes bug #15677: documentation mentions wrong programmer-id - "avrispmk2" + * doc/avrdude.info (-c): Change "avrispmk2" into "avrisp2" as that + is the programmer actually supported by avrdude.conf.in. + Closes bug #15677: documentation mentions wrong programmer-id + "avrispmk2" 2006-08-21 Joerg Wunsch - * avrdude.conf.in: Fix various AVR910 device codes. Add the code - tables from both, AVR910 and AVR109. Change avr910_devcode of - the ATtiny2313 to 0x5e (ATtiny26). - Closes bug #16671: Tiny2313 avr910_devcode is bad - Closes bug #15826: avr910 device type for ATmega8 wrong + * avrdude.conf.in: Fix various AVR910 device codes. Add the code + tables from both, AVR910 and AVR109. Change avr910_devcode of + the ATtiny2313 to 0x5e (ATtiny26). + Closes bug #16671: Tiny2313 avr910_devcode is bad + Closes bug #15826: avr910 device type for ATmega8 wrong 2006-08-21 Joerg Wunsch - * avrdude.conf.in: Add (rather conservative) write delay timing - values to the *fuse and lock memory spaces of all devices where - they have been missing. Add the lock memory space to the ATmega48 - section. - Closes bug #14920: tiny2313 fuses and AVRDUDE 5.0 - Closes bug #15751: atmega48: no lock bits defined + * avrdude.conf.in: Add (rather conservative) write delay timing + values to the *fuse and lock memory spaces of all devices where + they have been missing. Add the lock memory space to the ATmega48 + section. + Closes bug #14920: tiny2313 fuses and AVRDUDE 5.0 + Closes bug #15751: atmega48: no lock bits defined 2006-08-21 Joerg Wunsch - * avrdude.conf.in: Fix the size of the calibration memory space - for ATtiny13, ATmega64, ATmega16, ATmega32, ATmega8535, ATtiny25, - ATtiny45, ATtiny85. - Closes bug #17383: Wrong calibration section in avrdude.conf... + * avrdude.conf.in: Fix the size of the calibration memory space + for ATtiny13, ATmega64, ATmega16, ATmega32, ATmega8535, ATtiny25, + ATtiny45, ATtiny85. + Closes bug #17383: Wrong calibration section in avrdude.conf... 2006-08-21 Joerg Wunsch - * avrdude.conf.in (ATmega324): Correct the pagesize from 256 to - 128. - This closes bug #16410: ATMega164/324/644 cannot be programmed + * avrdude.conf.in (ATmega324): Correct the pagesize from 256 to + 128. + This closes bug #16410: ATMega164/324/644 cannot be programmed 2006-08-20 Joerg Wunsch - * configure.ac: Check for gettimeofday(). - * ppiwin.c (gettimeofday): Define gettimeofday() replacement - only if !defined(HAVE_GETTIMEOFDAY); use correct protype. + * configure.ac: Check for gettimeofday(). + * ppiwin.c (gettimeofday): Define gettimeofday() replacement + only if !defined(HAVE_GETTIMEOFDAY); use correct protype. 2006-08-18 Joerg Wunsch - * stk500v2: Minor cosmetic changes: STK500 firmware version - numbers are M.NN, so always display the minor number as two - digits. Examine the response to the sign-on command to see which - programmer hardware we are talking to, and then restrict the - STK500 topcard display to devices detected as STK500. + * stk500v2: Minor cosmetic changes: STK500 firmware version + numbers are M.NN, so always display the minor number as two + digits. Examine the response to the sign-on command to see which + programmer hardware we are talking to, and then restrict the + STK500 topcard display to devices detected as STK500. 2006-08-18 Joerg Wunsch - * Makefile.am: Add a dist-hook, and make it remove lexer.c, - config_gram.c, and config_gram.h from the source distribution - archive. These files are supposed to be generated on the target - system. - Closes bug #15536: avrdude-5.1 compilation fails on Gentoo/amd64 + * Makefile.am: Add a dist-hook, and make it remove lexer.c, + config_gram.c, and config_gram.h from the source distribution + archive. These files are supposed to be generated on the target + system. + Closes bug #15536: avrdude-5.1 compilation fails on Gentoo/amd64 2006-08-17 Joerg Wunsch - * stk500v2.c: unreverse the argument order for - CMD_CHIP_ERASE_HVSP; Atmel says AVR068 is right, and - stk500.exe is wrong. - * configure.ac (AC_CHECK_LIB[usb]): Fix the generation - of HAVE_LIBUSB in ac_cfg.h. + * stk500v2.c: unreverse the argument order for + CMD_CHIP_ERASE_HVSP; Atmel says AVR068 is right, and + stk500.exe is wrong. + * configure.ac (AC_CHECK_LIB[usb]): Fix the generation + of HAVE_LIBUSB in ac_cfg.h. 2006-08-17 Joerg Wunsch - Submitted by Neil Davey: - patch #4539: Ability to control the bit clock (usleep) delay - for ppi interface - * bitbang.c: Implement bitbang_delay() and its calibration. - * bitbang.h: Declare bitbang_delay(). - * main.c: Add the ispdelay option (-i). - * pgm.h (struct programmer_t): Add the ispdelay parameter. - * par.c: Add calls to bitbang_delay() when requested. - * serbb_posix.c: (Ditto.) - * serbb_win32.c: (Ditto.) - * avrdude.1: Document the new -i option. - * doc/avrdude.texi: (Ditto.) + Submitted by Neil Davey: + patch #4539: Ability to control the bit clock (usleep) delay + for ppi interface + * bitbang.c: Implement bitbang_delay() and its calibration. + * bitbang.h: Declare bitbang_delay(). + * main.c: Add the ispdelay option (-i). + * pgm.h (struct programmer_t): Add the ispdelay parameter. + * par.c: Add calls to bitbang_delay() when requested. + * serbb_posix.c: (Ditto.) + * serbb_win32.c: (Ditto.) + * avrdude.1: Document the new -i option. + * doc/avrdude.texi: (Ditto.) 2006-08-14 Joerg Wunsch - Submitted by : - * avrdude.conf.in (ATmega48, ATmega88, ATmega168): patch #5100: - mega88 EEPROM support (extended for ATmega48 and ATmega168 - jw). + Submitted by : + * avrdude.conf.in (ATmega48, ATmega88, ATmega168): patch #5100: + mega88 EEPROM support (extended for ATmega48 and ATmega168 - jw). 2006-08-14 Joerg Wunsch - Submitted by : - * stk500v2.c (stk500v2_open): patch #5273: Emit error message - if user requests usb and no libusb support + Submitted by : + * stk500v2.c (stk500v2_open): patch #5273: Emit error message + if user requests usb and no libusb support 2006-08-14 Joerg Wunsch - * avrdude.conf.in: Add HVSP/PP mode parameters for all AVRs. + * avrdude.conf.in: Add HVSP/PP mode parameters for all AVRs. 2006-08-13 Joerg Wunsch - * tools: New directory. - * tools/get-hv-params.xsl: New file, extract high-voltage - programming parameters from Atmel XML files, and produce - an avrdude.conf[.in] snippet. + * tools: New directory. + * tools/get-hv-params.xsl: New file, extract high-voltage + programming parameters from Atmel XML files, and produce + an avrdude.conf[.in] snippet. 2006-08-11 Joerg Wunsch - * configure.ac (AC_CHECK_LIB([usb]): implement a private LIBUSB - macro to add this library to, to prevent it from being - automatically linked to all binaries. This should fix the Win32 - build of loaddrv. - * Makefile.am (avrdude_LDADD): add LIBUSB here. + * configure.ac (AC_CHECK_LIB([usb]): implement a private LIBUSB + macro to add this library to, to prevent it from being + automatically linked to all binaries. This should fix the Win32 + build of loaddrv. + * Makefile.am (avrdude_LDADD): add LIBUSB here. 2006-08-10 Eric B. Weddington - Contributed by Bob Paddock - * avrdude.conf.in: Patch #4780. Provide support for mega325, - mega3250, mega645, mega6450. + Contributed by Bob Paddock + * avrdude.conf.in: Patch #4780. Provide support for mega325, + mega3250, mega645, mega6450. 2006-08-10 Joerg Wunsch - * avrdude.conf.in (ATtiny11): fix the HVSP control stack, - add delay values required for flash and EEPROM. - * stk500v2.c: reverse the argument order for - CMD_CHIP_ERASE_HVSP; AVR068 and stk500.exe differ here. + * avrdude.conf.in (ATtiny11): fix the HVSP control stack, + add delay values required for flash and EEPROM. + * stk500v2.c: reverse the argument order for + CMD_CHIP_ERASE_HVSP; AVR068 and stk500.exe differ here. 2006-08-09 Joerg Wunsch - * stk500v2.c (stk500v2_program_enable): Fix a typo - (synchloops vs. synchcycles). + * stk500v2.c (stk500v2_program_enable): Fix a typo + (synchloops vs. synchcycles). 2006-08-04 Joerg Wunsch - * avrdude.conf.in: Add parallel programming definitions for - the ATmega8/48/88/168. + * avrdude.conf.in: Add parallel programming definitions for + the ATmega8/48/88/168. 2006-07-22 Joerg Wunsch - * avrdude.conf.in: Add the ATtiny11, an HVSP-only device. + * avrdude.conf.in: Add the ATtiny11, an HVSP-only device. 2006-07-21 Joerg Wunsch - Implement STK500 (v2) HVSP mode. - * stk500v2.c: Add new functions for HVSP support. - * stk500v2.h: Add prototype for the stk500hvsp programmer. - * avrpart.h: Add fields to struct avrpart for new features. - * config_gram.y: Extend the configuration syntax for new - features required for HVSP support. - * lexer.l: (Ditto.) - * avrdude.conf.in: Add HVSP support for ATtiny13 and - ATtiny45 as an example. - * avrdude.1: Document stk500hvsp. - * doc/avrdude.texi: (Ditto.) + Implement STK500 (v2) HVSP mode. + * stk500v2.c: Add new functions for HVSP support. + * stk500v2.h: Add prototype for the stk500hvsp programmer. + * avrpart.h: Add fields to struct avrpart for new features. + * config_gram.y: Extend the configuration syntax for new + features required for HVSP support. + * lexer.l: (Ditto.) + * avrdude.conf.in: Add HVSP support for ATtiny13 and + ATtiny45 as an example. + * avrdude.1: Document stk500hvsp. + * doc/avrdude.texi: (Ditto.) 2006-07-21 Joerg Wunsch - * avrpart.c: Print the very verbose memory details only - in debug level > 4. + * avrpart.c: Print the very verbose memory details only + in debug level > 4. 2006-07-19 Joerg Wunsch - * stk500v2.c: Add more parameters for PP mode. Fix the - non-paged write operations for old AVRs. - * lexer.l: Add more parameters for PP mode. - * config_gram.y: (Ditto.) - * avrpart.h: (Ditto.) - * avrdude.conf.in: Use the new PP mode parameters; add PP mode - definitions for AT90S8515. - * avrdude.1: Document the stk500pp support. - * doc/avrdude.texi: (Ditto.) + * stk500v2.c: Add more parameters for PP mode. Fix the + non-paged write operations for old AVRs. + * lexer.l: Add more parameters for PP mode. + * config_gram.y: (Ditto.) + * avrpart.h: (Ditto.) + * avrdude.conf.in: Use the new PP mode parameters; add PP mode + definitions for AT90S8515. + * avrdude.1: Document the stk500pp support. + * doc/avrdude.texi: (Ditto.) 2006-07-19 Joerg Wunsch - * stk500v2.c: Hide stk500v2_set_sck_period_mk2() behind an #if - defined(HAVE_LIBUSB) as it is only used there (for the AVRISP - mkII). + * stk500v2.c: Hide stk500v2_set_sck_period_mk2() behind an #if + defined(HAVE_LIBUSB) as it is only used there (for the AVRISP + mkII). 2006-07-17 Joerg Wunsch - * stk500v2.c: Fix all bugs in stk500pp. Eliminate pagebuf, and - use a stack-allocated buffer instead, as the pagesize can be at - most 256 for all current AVRs anyway. + * stk500v2.c: Fix all bugs in stk500pp. Eliminate pagebuf, and + use a stack-allocated buffer instead, as the pagesize can be at + most 256 for all current AVRs anyway. 2006-07-17 Joerg Wunsch - * main.c: Use mem->desc in place of upd->memtype in more places to - give the full name of the respective memory area, instead of - the (possibly abbreviated) name the user typed in the -U option. + * main.c: Use mem->desc in place of upd->memtype in more places to + give the full name of the respective memory area, instead of + the (possibly abbreviated) name the user typed in the -U option. 2006-07-16 Joerg Wunsch - First stab at an implementation of the STK500 parallel programming - feature (v2 firmware only), named "stk500pp". Still not yet - complete: EEPROM writes not working, documentation missing, only - ATmega16 parameters available in avrdude.conf.in, some parameters - not yet implemented. - * avrdude.conf.in: Add sample parameters for PP mode to ATmega16. - * avrpart.h: Add the parallel programming control parameters. - * avrpart.c: (Ditto.) - * config_gram.y: Add stk500pp configuration grammar. - * lexer.l: Add stk500pp token recognition. - * stk500v2.h: Add declaration for stk500pp_initpgm(). - * stk500v2.c: Add stk500pp implementation. + First stab at an implementation of the STK500 parallel programming + feature (v2 firmware only), named "stk500pp". Still not yet + complete: EEPROM writes not working, documentation missing, only + ATmega16 parameters available in avrdude.conf.in, some parameters + not yet implemented. + * avrdude.conf.in: Add sample parameters for PP mode to ATmega16. + * avrpart.h: Add the parallel programming control parameters. + * avrpart.c: (Ditto.) + * config_gram.y: Add stk500pp configuration grammar. + * lexer.l: Add stk500pp token recognition. + * stk500v2.h: Add declaration for stk500pp_initpgm(). + * stk500v2.c: Add stk500pp implementation. 2006-07-11 Joerg Wunsch - * avrdude.conf.in: Fix the signatures for the - ATmega164/324 devices. + * avrdude.conf.in: Fix the signatures for the + ATmega164/324 devices. 2006-07-10 Joerg Wunsch - * avrdude.conf.in: Enter the signatures for the - ATmega164/324/644 devices. + * avrdude.conf.in: Enter the signatures for the + ATmega164/324/644 devices. 2006-05-25 Joerg Wunsch - * stk500v2.c: Implement extended addressing needed - for the ATmega256x devices. - * avrdude.1: Document ATmega256x support. - * doc/avrdude.texi: Document ATmega256x support. - Also document Solaris port defaults. + * stk500v2.c: Implement extended addressing needed + for the ATmega256x devices. + * avrdude.1: Document ATmega256x support. + * doc/avrdude.texi: Document ATmega256x support. + Also document Solaris port defaults. 2006-05-24 Joerg Wunsch - * avr.c: Start implementing support for ATmega256x; - jtag2 and bitbang programmers are working, stk500v2 - still needs to be done. - * avrdude.conf.in: (Ditto.) - * avrpart.c: (Ditto.) - * avrpart.h: (Ditto.) - * config_gram.y: (Ditto.) - * lexer.l: (Ditto.) + * avr.c: Start implementing support for ATmega256x; + jtag2 and bitbang programmers are working, stk500v2 + still needs to be done. + * avrdude.conf.in: (Ditto.) + * avrpart.c: (Ditto.) + * avrpart.h: (Ditto.) + * config_gram.y: (Ditto.) + * lexer.l: (Ditto.) 2006-04-18 Joerg Wunsch - Contributed by Julius Luukko : - * avrdude.conf.in: Add the "ere-isp-avr" programmer. + Contributed by Julius Luukko : + * avrdude.conf.in: Add the "ere-isp-avr" programmer. 2006-04-13 Joerg Wunsch - * par.c: Add logic to negate parallel-port signals in - avrdude.conf using a tilde. + * par.c: Add logic to negate parallel-port signals in + avrdude.conf using a tilde. - Contributed by Bram Daams: - * avrdude.conf.in: Add the "atisp" programmer entry that - makes use of negated signals. + Contributed by Bram Daams: + * avrdude.conf.in: Add the "atisp" programmer entry that + makes use of negated signals. 2006-03-28 Joerg Wunsch - * avrdude.conf.in: Add entries for AT90USB{64,128}{6,7} + * avrdude.conf.in: Add entries for AT90USB{64,128}{6,7} 2006-03-23 Colin O'Flynn - Contributed by Wim Lewis, fix a few typos (patch #4987) - * avrdude.1: Typo fix + Contributed by Wim Lewis, fix a few typos (patch #4987) + * avrdude.1: Typo fix 2006-02-27 Colin O'Flynn - Contributed by Wim Lewis, add support for checking device - signatures in detail (patch #4924 and #4925) - * avrdude.conf.in: Add signatures - * avrpart.c: Set default signature - * avrpart.h: Variable for signature - * config_gram.y: More signature reading - * lexer.l: Define that signatures exist - * main.c: Read signatures and check them against hardware + Contributed by Wim Lewis, add support for checking device + signatures in detail (patch #4924 and #4925) + * avrdude.conf.in: Add signatures + * avrpart.c: Set default signature + * avrpart.h: Variable for signature + * config_gram.y: More signature reading + * lexer.l: Define that signatures exist + * main.c: Read signatures and check them against hardware 2006-02-21 Joerg Wunsch - * avrdude.conf.in: Fix paged flash write for AT90PWMx - (error in datasheet). + * avrdude.conf.in: Fix paged flash write for AT90PWMx + (error in datasheet). 2006-01-23 Joerg Wunsch - * configure.in: Bump version. + * configure.in: Bump version. 2006-01-17 Colin O'Flynn - * main.c: Fixed a typo in safemode variable names, fixed bug 15113 - * avrdude.conf.in : Added BS2 and pagel to M162, Patch 4766 - * main.c, stk500v2.c: Added patch 4804 from eolson@mit.edu - Which stops sck from being writtend needlessly + * main.c: Fixed a typo in safemode variable names, fixed bug 15113 + * avrdude.conf.in : Added BS2 and pagel to M162, Patch 4766 + * main.c, stk500v2.c: Added patch 4804 from eolson@mit.edu + Which stops sck from being writtend needlessly 2006-01-13 Joerg Wunsch - Contributed by David Moore: add support for the - AVRISP mkII device. (Savannah patch #4789.) - * serial.h: Declare usb_serdev_frame device descriptor. - * stk500v2.c: Implementation of the AVRISP mkII handling. - * usb_libusb.c: Add USB handling for short-frame delimited - AVRISP mkII USB protocol; add distinction of different - devices in usbdev_open(). - * jtagmkII.c: Tell usbdev_open() to search for the JTAG ICE mkII. - * usbdevs.h: (New file.) - * Makefile.am: Add usbdevs.h, as well as some other forgotten - files "make distcheck" complained about. - * avrdude.conf.in: Add more aliases for the AVRISP mkII. - * avrdude.1: Document how to use the AVRISP mkII. - * doc/avrdude.texi: (Ditto.) + Contributed by David Moore: add support for the + AVRISP mkII device. (Savannah patch #4789.) + * serial.h: Declare usb_serdev_frame device descriptor. + * stk500v2.c: Implementation of the AVRISP mkII handling. + * usb_libusb.c: Add USB handling for short-frame delimited + AVRISP mkII USB protocol; add distinction of different + devices in usbdev_open(). + * jtagmkII.c: Tell usbdev_open() to search for the JTAG ICE mkII. + * usbdevs.h: (New file.) + * Makefile.am: Add usbdevs.h, as well as some other forgotten + files "make distcheck" complained about. + * avrdude.conf.in: Add more aliases for the AVRISP mkII. + * avrdude.1: Document how to use the AVRISP mkII. + * doc/avrdude.texi: (Ditto.) 2006-01-12 Joerg Wunsch - * avrdude.conf.in: Add EEPROM page instructions for the - ATmega169 so it will work for STK500v2. + * avrdude.conf.in: Add EEPROM page instructions for the + ATmega169 so it will work for STK500v2. 2005-12-16 Joerg Wunsch - * avrdude.conf.in: Added support for ATtiny24/44/84. + * avrdude.conf.in: Added support for ATtiny24/44/84. 2005-12-05 Colin O'Flynn - * avrdude.conf.in: Added m162 support for stk500v2 + * avrdude.conf.in: Added m162 support for stk500v2 2005-12-01 Joerg Wunsch - * avrdude.conf.in: fix the number of significant bits for - the efuse memory in ATmega48/88/168; the datasheet is a bit - off here as well. + * avrdude.conf.in: fix the number of significant bits for + the efuse memory in ATmega48/88/168; the datasheet is a bit + off here as well. 2005-11-29 Joerg Wunsch - * avrdude.1: update for JTAG ICE mkI support. - * doc/avrdude.texi: (Ditto.) + * avrdude.1: update for JTAG ICE mkI support. + * doc/avrdude.texi: (Ditto.) 2005-11-29 Joerg Wunsch - Submitted by Galen Seitz: - patch #4459: Fix for rpm package builds - * avrdude.spec.in: update the RPM spec file: - - Default to enable-doc=yes during configure. - - Move info file to docs package. - - Make building of docs package conditional. Basic - idea copied from avr-gcc. + Submitted by Galen Seitz: + patch #4459: Fix for rpm package builds + * avrdude.spec.in: update the RPM spec file: + - Default to enable-doc=yes during configure. + - Move info file to docs package. + - Make building of docs package conditional. Basic + idea copied from avr-gcc. 2005-11-29 Joerg Wunsch - Submitted by someone who thinks he's called "Daper": - Fix bug #15013: Wrong use of PPICLAIM (kernel: ppdev0: claim the - port first) - * par.c: don't claim/release here (thus win_ppdev.h not needed - anymore) - * ppi.c: claim/release here. - * freebsd_ppi.h: ppi_claim/ppi_release now take an fd as parameter. - * solaris_ecpp.h: (Ditto.) - * linux_ppdev.h: (Ditto.) (Also add copyright.) - * win_ppdev.h: Not needed anymore, remove. + Submitted by someone who thinks he's called "Daper": + Fix bug #15013: Wrong use of PPICLAIM (kernel: ppdev0: claim the + port first) + * par.c: don't claim/release here (thus win_ppdev.h not needed + anymore) + * ppi.c: claim/release here. + * freebsd_ppi.h: ppi_claim/ppi_release now take an fd as parameter. + * solaris_ecpp.h: (Ditto.) + * linux_ppdev.h: (Ditto.) (Also add copyright.) + * win_ppdev.h: Not needed anymore, remove. 2005-11-28 Joerg Wunsch - * jtagmkI.c: Improve the communication startup with the ICE. + * jtagmkI.c: Improve the communication startup with the ICE. 2005-11-28 Joerg Wunsch - * configure.ac: enable parport access on x86_64 Linux and - FreeBSD systems. + * configure.ac: enable parport access on x86_64 Linux and + FreeBSD systems. 2005-11-27 Joerg Wunsch - * avrdude.conf.in: add the "calibration" space to ATmega16. + * avrdude.conf.in: add the "calibration" space to ATmega16. 2005-11-25 Colin O'Flynn - Fixed bug 15051, building for Windows breaks. - * par.c: ppi_claim and ppi_release definitions now in a Windows header file - * ppi.c: Only included if you are building for Windows - * win_ppdev.h: Initial Commit, see par.c + Fixed bug 15051, building for Windows breaks. + * par.c: ppi_claim and ppi_release definitions now in a Windows header file + * ppi.c: Only included if you are building for Windows + * win_ppdev.h: Initial Commit, see par.c 2005-11-24 Joerg Wunsch - Add basic support for the Atmel JTAG ICE mkI: - * config_gram.y: add mkI support to config sytax. - * lexer.l: (Ditto.) - * avrdude.conf.in: add sample programmer entries. - * jtagmkI.c: New file - * jtagmkI.h: New file - * jtagmkI_private.h: New file - * Makefile.am: include new files in build. + Add basic support for the Atmel JTAG ICE mkI: + * config_gram.y: add mkI support to config sytax. + * lexer.l: (Ditto.) + * avrdude.conf.in: add sample programmer entries. + * jtagmkI.c: New file + * jtagmkI.h: New file + * jtagmkI_private.h: New file + * Makefile.am: include new files in build. 2005-11-24 Colin O'Flynn - Fix bug 14681 - Serial Communication Fails on -vvvv with Windows - * ser_win32.c: Patched with Brian Dean's patch + Fix bug 14681 - Serial Communication Fails on -vvvv with Windows + * ser_win32.c: Patched with Brian Dean's patch 2005-11-05 Colin O'Flynn - Patch #4532 by Manfred Bartz - * avrdude.conf.in: added support for ATMega168 (also added support - for the stk500v2 protocol which was not in the patch). + Patch #4532 by Manfred Bartz + * avrdude.conf.in: added support for ATMega168 (also added support + for the stk500v2 protocol which was not in the patch). 2005-11-03 Joerg Wunsch - Add ecpp(7D) (parallel port) for Solaris. - * configure.ac: add Solaris' default parallel port. - * linux_ppdev.h: change parallel port access to the new style. - * freebsd_ppi.h: New file, abstract FreeBSD's ppi(4). - * solaris_ecpp.h: New file, abstract Solaris' ecpp(7D). - * par.c: change header inclusion sequence. - * pgm.h: remove obsolete ppi_claim() and ppi_release() dummies. - * ppi.c: change header inclusion sequence, use new parport - abstraction, drop obsolete dummy implementation. + Add ecpp(7D) (parallel port) for Solaris. + * configure.ac: add Solaris' default parallel port. + * linux_ppdev.h: change parallel port access to the new style. + * freebsd_ppi.h: New file, abstract FreeBSD's ppi(4). + * solaris_ecpp.h: New file, abstract Solaris' ecpp(7D). + * par.c: change header inclusion sequence. + * pgm.h: remove obsolete ppi_claim() and ppi_release() dummies. + * ppi.c: change header inclusion sequence, use new parport + abstraction, drop obsolete dummy implementation. 2005-11-02 Joerg Wunsch - * config.h: change YYSTYPE to be a single word, to work around - a bug in Solaris' yacc. - * lexer.l: remove incompatibilities with Solaris' default lex, - bump resource limits for lex. + * config.h: change YYSTYPE to be a single word, to work around + a bug in Solaris' yacc. + * lexer.l: remove incompatibilities with Solaris' default lex, + bump resource limits for lex. 2005-11-01 Joerg Wunsch - Make avrdude Solaris-compatible. - * Makefile.am: distclean avrdude.conf. - * avrdude.conf.in: make the parallel-port programmers optional. - * bitbang.c: move the bitbang features out into PROGRAMMER. - * configure.ac: introduce --enable-parport, add Solaris. - * lexer.l: replace str by strng to work around problems in some - versions of flex. - * main.c: move getexitspecs into the respective programmer's - domain; replace rindex by the C-standard strrchr. - * par.c: make parallel port optional. - * par.h: everything but par_initpgm() is private now. - * pgm.h: add setping/getping/highpulsepin/getexitspecs. - * serbb_posix.c: generalize bitbang interface; replace - cfmakeraw() by explicit code. - * serbb_win32.c: generalize bitbang interface. + Make avrdude Solaris-compatible. + * Makefile.am: distclean avrdude.conf. + * avrdude.conf.in: make the parallel-port programmers optional. + * bitbang.c: move the bitbang features out into PROGRAMMER. + * configure.ac: introduce --enable-parport, add Solaris. + * lexer.l: replace str by strng to work around problems in some + versions of flex. + * main.c: move getexitspecs into the respective programmer's + domain; replace rindex by the C-standard strrchr. + * par.c: make parallel port optional. + * par.h: everything but par_initpgm() is private now. + * pgm.h: add setping/getping/highpulsepin/getexitspecs. + * serbb_posix.c: generalize bitbang interface; replace + cfmakeraw() by explicit code. + * serbb_win32.c: generalize bitbang interface. 2005-10-20 Joerg Wunsch - * butterfly.c: fix yet another sign extension bug. + * butterfly.c: fix yet another sign extension bug. 2005-10-14 Joerg Wunsch - * avrdude.conf.in (ATmega8515): fix size of calibration - memory. + * avrdude.conf.in (ATmega8515): fix size of calibration + memory. 2005-10-09 Joerg Wunsch - * avrdude.conf.in: add support for ATmega640/1280/1281. - * avrdude.1: document the above. - * doc/avrdude.texi: (Ditto.) + * avrdude.conf.in: add support for ATmega640/1280/1281. + * avrdude.1: document the above. + * doc/avrdude.texi: (Ditto.) 2005-09-27 Joerg Wunsch - * doc/avrdude.texi: Polish up the docs a bit. Use smallexample - instead of example for wide tty output. Document a trick to - find out about the serial numbers of all JTAG ICEs attached - to USB. + * doc/avrdude.texi: Polish up the docs a bit. Use smallexample + instead of example for wide tty output. Document a trick to + find out about the serial numbers of all JTAG ICEs attached + to USB. 2005-09-26 Joerg Wunsch - * jtagmkII.c (jtagmkII_paged_write): default the page size early so the - buffer will be allocated correctly. - * usb_libusb.c: fix libusb handling; now it works with libusb-win32 as - well. + * jtagmkII.c (jtagmkII_paged_write): default the page size early so the + buffer will be allocated correctly. + * usb_libusb.c: fix libusb handling; now it works with libusb-win32 as + well. 2005-09-21 Joerg Wunsch - * main.c(do_op): use mem->desc in place of upd->memtype to - give the full name of the respective memory area, instead of - the (possibly abbreviated) name the user typed in the -U option. + * main.c(do_op): use mem->desc in place of upd->memtype to + give the full name of the respective memory area, instead of + the (possibly abbreviated) name the user typed in the -U option. 2005-09-21 Joerg Wunsch - * main.c: Add the forgotten -B option to the option string in - getopt(); sort the -s option into order. + * main.c: Add the forgotten -B option to the option string in + getopt(); sort the -s option into order. 2005/09/21 Brian S. Dean - * avr.c: - * main.c: - * safemode.c: - * safemode.h: - * term.h: - This is Colin O'Flynn's mega patch for updating safemode support: + * avr.c: + * main.c: + * safemode.c: + * safemode.h: + * term.h: + This is Colin O'Flynn's mega patch for updating safemode support: - * add support for parts with just 'fuse' memory + * add support for parts with just 'fuse' memory - * if any fuse memories are altered, reflect those changes in the - post-programming safemode check so that safemode no longer - complains about fuses which were intentionally altered; this - eliminates the need to completely disable safemode using -u in - order to program fuses. + * if any fuse memories are altered, reflect those changes in the + post-programming safemode check so that safemode no longer + complains about fuses which were intentionally altered; this + eliminates the need to completely disable safemode using -u in + order to program fuses. - * provide -s option which will not ask to restore fuses, it will - just do it + * provide -s option which will not ask to restore fuses, it will + just do it 2005-09-19 Joerg Wunsch - * butterfly.c (butterfly_initialize): make the device code unsigned so - it wouldn't sign-extend when >= 0x80. + * butterfly.c (butterfly_initialize): make the device code unsigned so + it wouldn't sign-extend when >= 0x80. 2005-09-18 Joerg Wunsch - Add the serial bit-bang driver, contributed by Michael Holzt. - * bitbang.h: New file. - * bitbang.c: New file. - * serbb.h: New file. - * serbb_posix.c: New file. - * serbb_win32.c: New file. - * Makefile.am: Include new files. - * config_gram.y: Add serbb to configuration language. - * lexer.l: (Ditto.) - * par.c: Centralize bit-bang code in bitbang.c. - * par.h: Declare newly published functions. - * pgm.h (struct programmer_t): Add a flag field for private use - by the programmer. - * pindefs.h: Add definitions for negated serbb pins. - * avrdude.conf.in: Add serbb programmers ponyser, dasa, and dasa3. - * avrdude.1: Document serbb code. - * doc/avrdude.texi: (Ditto.) + Add the serial bit-bang driver, contributed by Michael Holzt. + * bitbang.h: New file. + * bitbang.c: New file. + * serbb.h: New file. + * serbb_posix.c: New file. + * serbb_win32.c: New file. + * Makefile.am: Include new files. + * config_gram.y: Add serbb to configuration language. + * lexer.l: (Ditto.) + * par.c: Centralize bit-bang code in bitbang.c. + * par.h: Declare newly published functions. + * pgm.h (struct programmer_t): Add a flag field for private use + by the programmer. + * pindefs.h: Add definitions for negated serbb pins. + * avrdude.conf.in: Add serbb programmers ponyser, dasa, and dasa3. + * avrdude.1: Document serbb code. + * doc/avrdude.texi: (Ditto.) 2005/09/18 Brian S. Dean - * avrdude.conf.in: Patch #4078: add VCC pin definition for DAPA - programmer. + * avrdude.conf.in: Patch #4078: add VCC pin definition for DAPA + programmer. 2005/09/18 Brian S. Dean - * avr910.c: This is patch #3277 which appears to fix a number of - issues with the avr910 programmer. + * avr910.c: This is patch #3277 which appears to fix a number of + issues with the avr910 programmer. - Fixes the following problems with paged writes in avr910.c: - - failure to re-set address after page writes; - - no polling or delay after page writes; - - no page writes when not using auto-increment; - - an extraneous page write when data ends on page boundary. + Fixes the following problems with paged writes in avr910.c: + - failure to re-set address after page writes; + - no polling or delay after page writes; + - no page writes when not using auto-increment; + - an extraneous page write when data ends on page boundary. 2005-09-17 Joerg Wunsch - * avrdude.conf.in: Fix the poll values for the ATmega103's EEPROM - so they eventually match the XML file. - This fixes bug #7492: EEPROM writing fail on atmega103 with - atavrisp + * avrdude.conf.in: Fix the poll values for the ATmega103's EEPROM + so they eventually match the XML file. + This fixes bug #7492: EEPROM writing fail on atmega103 with + atavrisp 2005-09-17 Joerg Wunsch - * avrdude.conf.in: The ATmega128 has four oscillator calibration - bytes, not only a single one. - This closes bug #11496: Memory bank calibration on atmega128 - should have 4 bytes + * avrdude.conf.in: The ATmega128 has four oscillator calibration + bytes, not only a single one. + This closes bug #11496: Memory bank calibration on atmega128 + should have 4 bytes 2005/09/17 Brian S. Dean - * avrdude.1: - Document -q -q. Expand a little on the description of the 'part' - command. + * avrdude.1: + Document -q -q. Expand a little on the description of the 'part' + command. 2005/09/16 Brian S. Dean - * fileio.c: - * main.c: - Implement -q -q to be very very quiet. + * fileio.c: + * main.c: + Implement -q -q to be very very quiet. 2005/09/16 Brian S. Dean - * avrdude.conf.in: - Add DAPA programmer. + * avrdude.conf.in: + Add DAPA programmer. 2005/09/16 Brian S. Dean - * avrdude.conf.in: - * stk500v2.c: - This fixes EEPROM access using the STK500V2 programmer, partially - undoing part of a previous general fixup commit. Choose the correct - read/write operations with the stk500v2 program function - the correct - one depends on the memory type. EEPROM is byte addressable so uses - read/write. FLASH is word addressable and so uses read_lo/write_lo. + * avrdude.conf.in: + * stk500v2.c: + This fixes EEPROM access using the STK500V2 programmer, partially + undoing part of a previous general fixup commit. Choose the correct + read/write operations with the stk500v2 program function - the correct + one depends on the memory type. EEPROM is byte addressable so uses + read/write. FLASH is word addressable and so uses read_lo/write_lo. 2005-09-16 Joerg Wunsch - * avrdude.1: document the memtypes for -U - * doc/avrdude.texi: (Ditto.) - Closes bug #13501: should be listed in the man page + * avrdude.1: document the memtypes for -U + * doc/avrdude.texi: (Ditto.) + Closes bug #13501: should be listed in the man page 2005-09-16 Joerg Wunsch - * doc/Makefile.am: add logic to detect the misf^H^H^H^H - gratitous API change in recent versions of texi2html where - the output directory has changed names. - Fix for: - bug #13026: The build fails with texi2html 1.76 - bug #12715: make issues during install - patch #3091: commandline fix for latest version of texi2html + * doc/Makefile.am: add logic to detect the misf^H^H^H^H + gratitous API change in recent versions of texi2html where + the output directory has changed names. + Fix for: + bug #13026: The build fails with texi2html 1.76 + bug #12715: make issues during install + patch #3091: commandline fix for latest version of texi2html 2005-09-16 Joerg Wunsch - * usb_libusb.c (usbdev_drain): actually implement draining to aid - synchronizing against a JTAG ICE in weird state. + * usb_libusb.c (usbdev_drain): actually implement draining to aid + synchronizing against a JTAG ICE in weird state. 2005-09-16 Joerg Wunsch - * butterfly.c: improve the butterfly initialization so it is more likely - to synchonize; [bug #9787: avrdude 4.4.0 correct butterfly interface] + * butterfly.c: improve the butterfly initialization so it is more likely + to synchonize; [bug #9787: avrdude 4.4.0 correct butterfly interface] 2005-09-14 Joerg Wunsch - * jtagmkII.c (jtagmkII_paged_load): return the number of bytes read. - This makes EEPROM block reads work again. + * jtagmkII.c (jtagmkII_paged_load): return the number of bytes read. + This makes EEPROM block reads work again. 2005-09-14 Joerg Wunsch - * avrdude.conf.in: add a jtag2slow programmer alias, and make - "jtag2" default to 115200 Bd. - * doc/avrdude.texi: document the above changes. + * avrdude.conf.in: add a jtag2slow programmer alias, and make + "jtag2" default to 115200 Bd. + * doc/avrdude.texi: document the above changes. 2005/09/14 Brian S. Dean - * avrdude.conf.in: - Change bit 0 of the ATmega169 efuse 'write' opcode from 'x' (ignore) - to 'i' (input). Even though this bit should be ignored, it should not - be changed. The 'x' setting sets the bit to zero which programs it - and could cause undefined behaviour. Setting to 'i' enables it to be - rewritten to its old value. + * avrdude.conf.in: + Change bit 0 of the ATmega169 efuse 'write' opcode from 'x' (ignore) + to 'i' (input). Even though this bit should be ignored, it should not + be changed. The 'x' setting sets the bit to zero which programs it + and could cause undefined behaviour. Setting to 'i' enables it to be + rewritten to its old value. - A better solution might be to read the fuse byte, apply the new value - while leaving the 'x' bit alone, then writing the value back. The - current fix is a workaround which allows the developer to change the - bit as desired. + A better solution might be to read the fuse byte, apply the new value + while leaving the 'x' bit alone, then writing the value back. The + current fix is a workaround which allows the developer to change the + bit as desired. 2005-08-30 Joerg Wunsch - * usb_libusb.c: Consistently use unsigned char for buffers. + * usb_libusb.c: Consistently use unsigned char for buffers. 2005-08-29 Brian S. Dean - * avr910.c: Eliminate compiler warnings. GCC 4.x elicits many - signedness warnings when passing unsigned char * when char * is in - the prototype and vice versa. Clean these up along with a few - others. - * butterfly.c: (Ditto.) - * jtagmkII.c: (Ditto.) - * safemode.c: (Ditto.) - * safemode.h: (Ditto.) - * ser_posix.c: (Ditto.) - * serial.h: (Ditto.) - * stk500.c: (Ditto.) - * stk500v2.c: (Ditto.) + * avr910.c: Eliminate compiler warnings. GCC 4.x elicits many + signedness warnings when passing unsigned char * when char * is in + the prototype and vice versa. Clean these up along with a few + others. + * butterfly.c: (Ditto.) + * jtagmkII.c: (Ditto.) + * safemode.c: (Ditto.) + * safemode.h: (Ditto.) + * ser_posix.c: (Ditto.) + * serial.h: (Ditto.) + * stk500.c: (Ditto.) + * stk500v2.c: (Ditto.) 2005-08-28 Joerg Wunsch - * avrdude.conf.in: Add support for the ATtiny25/45/85. Note that - only the ATtiny45 appears to have a complete XML description right - now. - * avrdude.1: Mention all the recently added device support: AT90PWM2/3, - ATmega164/324/644, ATmega329x/649x, ATtiny25/45/85. - * doc/avrdude.texi: (Ditto.) + * avrdude.conf.in: Add support for the ATtiny25/45/85. Note that + only the ATtiny45 appears to have a complete XML description right + now. + * avrdude.1: Mention all the recently added device support: AT90PWM2/3, + ATmega164/324/644, ATmega329x/649x, ATtiny25/45/85. + * doc/avrdude.texi: (Ditto.) 2005/08/28 Brian S. Dean - * avrdude.conf.in: - * stk500v2.c: - This is patch # 4338, obsoletes patch #4327, provides fixes for bugs - #13693, #13871, and #14212. - - This provides bug fixes to the STK500V2 programmer type. - - - incorrect token used from avrdude.conf.in - - wrong command sent to programmer, hence no write to eeprom. - - programmer was said to start writing at 0x0000 and continue - page by page and was not repositionned when a gap was found - in the hex file, or when the hex file start address was not - 0x0000. Hence the verify procedure was correct, not the - write procedure. - - speed up of flash write to skip empty pages (full of 0xFF) - by re-enabling a dedicated function for that task. - - stk500v2_paged_load() was not returning the number of byte - read, so empty hex files were generated when reading memory. + * avrdude.conf.in: + * stk500v2.c: + This is patch # 4338, obsoletes patch #4327, provides fixes for bugs + #13693, #13871, and #14212. + + This provides bug fixes to the STK500V2 programmer type. + + - incorrect token used from avrdude.conf.in + - wrong command sent to programmer, hence no write to eeprom. + - programmer was said to start writing at 0x0000 and continue + page by page and was not repositionned when a gap was found + in the hex file, or when the hex file start address was not + 0x0000. Hence the verify procedure was correct, not the + write procedure. + - speed up of flash write to skip empty pages (full of 0xFF) + by re-enabling a dedicated function for that task. + - stk500v2_paged_load() was not returning the number of byte + read, so empty hex files were generated when reading memory. 2005-08-17 Joerg Wunsch - * avrdude.conf.in: fix the EEPROM size for ATmega329x/649x. + * avrdude.conf.in: fix the EEPROM size for ATmega329x/649x. 2005-08-16 Joerg Wunsch - * avrdude.conf.in: Add support for the AT90PWM2/3. + * avrdude.conf.in: Add support for the AT90PWM2/3. 2005-07-27 Joerg Wunsch - (This work has been done as part of a contract with Atmel, Dresden.) - * butterfly.c: Implement full support for AVR109 boot loaders. - * avrdude.conf.in: add avr109 and avr911 as alias for butterfly. - * avrdude.1: Document the AVR109 addition. - * doc/avrdude.texi: (Ditto.) + (This work has been done as part of a contract with Atmel, Dresden.) + * butterfly.c: Implement full support for AVR109 boot loaders. + * avrdude.conf.in: add avr109 and avr911 as alias for butterfly. + * avrdude.1: Document the AVR109 addition. + * doc/avrdude.texi: (Ditto.) 2005-07-26 Brian S. Dean - * main.c: - Don't call exit() directly here - set the exit value and jump to the - main_exit: label to ensure the programmer is released correctly. + * main.c: + Don't call exit() directly here - set the exit value and jump to the + main_exit: label to ensure the programmer is released correctly. - * stk500v2.c: - The stk500v2_getsync() function was improperly checking for success, - thus it was falsely reporting that it failed when it was actually - working correctly. Fixed. + * stk500v2.c: + The stk500v2_getsync() function was improperly checking for success, + thus it was falsely reporting that it failed when it was actually + working correctly. Fixed. 2005-07-25 Joerg Wunsch - * usb_libusb.c: Catch benign errors when reading the serial #. + * usb_libusb.c: Catch benign errors when reading the serial #. 2005-06-19 Joerg Wunsch - * Makefile.am: Implement libusb-base USB transport for the - JTAG ICE mkII. - * configure.ac: ditto. - * jtagmkII.c: ditto. - * ser_posix.c: ditto. - * ser_win32.c: ditto. - * serial.h: ditto. - * usb_libusb.c: ditto (New file). - * avrdude.1: document the USB transport. - * doc/avrdude.texi: ditto. + * Makefile.am: Implement libusb-base USB transport for the + JTAG ICE mkII. + * configure.ac: ditto. + * jtagmkII.c: ditto. + * ser_posix.c: ditto. + * ser_win32.c: ditto. + * serial.h: ditto. + * usb_libusb.c: ditto (New file). + * avrdude.1: document the USB transport. + * doc/avrdude.texi: ditto. 2005-06-15 Joerg Wunsch - * avrdude.conf.in: The AT90CAN128 has AllowFullPageBitstream = no. + * avrdude.conf.in: The AT90CAN128 has AllowFullPageBitstream = no. 2005-06-14 Joerg Wunsch - * avrdude.conf.in: Add support for the ATmega164/324/644. - * jtagmkII.c: If enter_progmode fails with RSP_ILLEGAL_JTAG_ID, give - the user a hint that the JTAGEN fuse might be unset. + * avrdude.conf.in: Add support for the ATmega164/324/644. + * jtagmkII.c: If enter_progmode fails with RSP_ILLEGAL_JTAG_ID, give + the user a hint that the JTAGEN fuse might be unset. 2005-06-11 Joerg Wunsch - * avrdude.conf.in: Add support for the ATmega329x/649x. + * avrdude.conf.in: Add support for the ATmega329x/649x. 2005-05-27 Joerg Wunsch - * jtagmkII.c: fix a signedness bug when shifting bits; when - discarding a packet for being overly long, restart the state - machine instead of attempting to drop a preposterous amount - of data. + * jtagmkII.c: fix a signedness bug when shifting bits; when + discarding a packet for being overly long, restart the state + machine instead of attempting to drop a preposterous amount + of data. 2005-05-19 Joerg Wunsch - * avrdude.1: - * doc/avrdude.texi: Document that the JTAG ICE mkII code currently - cannot write to flash one byte at a time. Also mention the bug - tracker interface on savannah. + * avrdude.1: + * doc/avrdude.texi: Document that the JTAG ICE mkII code currently + cannot write to flash one byte at a time. Also mention the bug + tracker interface on savannah. 2005/05/14 Brian S. Dean - * configure.ac: - * main.c: - Update version for beta release and copyright message. - Change the default port to 'serial' for the newly added serial - programmers stk500v2 and jtagmkii. + * configure.ac: + * main.c: + Update version for beta release and copyright message. + Change the default port to 'serial' for the newly added serial + programmers stk500v2 and jtagmkii. 2005-05-10 Joerg Wunsch - * Makefile.am: - * avr910.c: - * avrdude.1: - * avrdude.conf.in: - * avrpart.c: - * avrpart.h: - * butterfly.c: - * config_gram.y: - * crc16.c: - * crc16.h: - * jtagmkII.c: - * jtagmkII.h: - * jtagmkII_private.h: - * lexer.l: - * main.c: - * pgm.h: - * serial.h: - * ser_posix.c: - * ser_win32.c: - * stk500.c: - * stk500v2.c: - * stk500v2.h: - * stk500v2_private.h: - * doc/avrdude.texi: - - Mega-commit to bring in both, the STK500v2 support from Erik - Walthinsen, as well as JTAG ICE mkII support (by me). - - Note that for the JTAG ICE, I did change a few things in the - internal API. Notably I made the serial receive timeout - configurable by the backends via an exported variable (done in - both the Posix and the Win32 implementation), and I made the - serial_recv() function return a -1 instead of bailing out with - exit(1) upon encountering a receive timeout (currently only done - in the Posix implementation). Both measures together allow me to - receive a datastreem from the ICE at 115 kbps on a somewhat lossy - PCI multi-UART card that occasionally drops a character. The JTAG - ICE mkII protocol has enough of safety layers to allow recovering - from these events, but the previous code wasn't prepared for any - kind of recovery. The Win32 change for this still has to be done. + * Makefile.am: + * avr910.c: + * avrdude.1: + * avrdude.conf.in: + * avrpart.c: + * avrpart.h: + * butterfly.c: + * config_gram.y: + * crc16.c: + * crc16.h: + * jtagmkII.c: + * jtagmkII.h: + * jtagmkII_private.h: + * lexer.l: + * main.c: + * pgm.h: + * serial.h: + * ser_posix.c: + * ser_win32.c: + * stk500.c: + * stk500v2.c: + * stk500v2.h: + * stk500v2_private.h: + * doc/avrdude.texi: + + Mega-commit to bring in both, the STK500v2 support from Erik + Walthinsen, as well as JTAG ICE mkII support (by me). + + Note that for the JTAG ICE, I did change a few things in the + internal API. Notably I made the serial receive timeout + configurable by the backends via an exported variable (done in + both the Posix and the Win32 implementation), and I made the + serial_recv() function return a -1 instead of bailing out with + exit(1) upon encountering a receive timeout (currently only done + in the Posix implementation). Both measures together allow me to + receive a datastreem from the ICE at 115 kbps on a somewhat lossy + PCI multi-UART card that occasionally drops a character. The JTAG + ICE mkII protocol has enough of safety layers to allow recovering + from these events, but the previous code wasn't prepared for any + kind of recovery. The Win32 change for this still has to be done. 2005/02/11 Brian S. Dean - * main.c: - Exit non-zero if safe-mode reverts fuse bits that were requested on - the command-line. + * main.c: + Exit non-zero if safe-mode reverts fuse bits that were requested on + the command-line. - Variable declarations must only appear at the beginning of a block. + Variable declarations must only appear at the beginning of a block. 2005/02/10 Brian S. Dean - * avrdude.1: - Document -u option to disable safe mode. + * avrdude.1: + Document -u option to disable safe mode. 2005/02/10 Brian S. Dean - * configure.ac: - doc/Makefile is now dependent on whether or not doc is enabled. + * configure.ac: + doc/Makefile is now dependent on whether or not doc is enabled. 2005/02/10 Brian S. Dean - * Makefile.am: - * configure.ac: - Disable the doc build by default; the tools needed to build - doc are either not available on all systems or are at best - inconvenient to build and install. The doc can still be built, one - just needs to specify --enable-doc at configure time. + * Makefile.am: + * configure.ac: + Disable the doc build by default; the tools needed to build + doc are either not available on all systems or are at best + inconvenient to build and install. The doc can still be built, one + just needs to specify --enable-doc at configure time. 2005-01-24 Colin O'Flynn - * main.c: Add "safe mode". Fuse settings will be restored at the end - of a programming session unless the -u switch is specified. - * safemode.c: New file. Safe mode support. - * safemode.h: New file. Safe mode support. - * Makefile.am: Add new files. - * doc/avrdude.texi: Document new Safe Mode feature and switch. + * main.c: Add "safe mode". Fuse settings will be restored at the end + of a programming session unless the -u switch is specified. + * safemode.c: New file. Safe mode support. + * safemode.h: New file. Safe mode support. + * Makefile.am: Add new files. + * doc/avrdude.texi: Document new Safe Mode feature and switch. 2004/12/22 Brian S. Dean - * avrdude.conf.in: - Add support for "Xilinx JTAG cable". Contributed by: - Tymm + * avrdude.conf.in: + Add support for "Xilinx JTAG cable". Contributed by: + Tymm - Add support for the AT90CAN128. Not sure if all the instruction - encoding is correct, specifically the address bits don't exactly match - those of the preliminary datasheet that I have, but I don't see how - they could be right. Tested with STK500 and it works there. - Instruction encodings have not been tested due to lack of a parallel - port on my Mac development box. + Add support for the AT90CAN128. Not sure if all the instruction + encoding is correct, specifically the address bits don't exactly match + those of the preliminary datasheet that I have, but I don't see how + they could be right. Tested with STK500 and it works there. + Instruction encodings have not been tested due to lack of a parallel + port on my Mac development box. 2004-07-19 Theodore A. Roth - * avrdude.1: Remove reference to ppi programmer schematic. - * configure.ac (AC_INIT): Set version to "4.4.0cvs". + * avrdude.1: Remove reference to ppi programmer schematic. + * configure.ac (AC_INIT): Set version to "4.4.0cvs". 2004-07-18 Theodore A. Roth - * AVRDUDE 4.4.0 has been released (cvs release tag is "release_4_4_0"). + * AVRDUDE 4.4.0 has been released (cvs release tag is "release_4_4_0"). 2004-07-18 Theodore A. Roth - * Makefile.am (EXTRA_DIST): Remove avrdude.pdf since it is no longer - supplied. - * NEWS: Fix typo. - * bootstrap: Delete the autom4te.cache dir before running the - autotools. - * configure.ac (AC_INIT): Set version to 4.4.0. + * Makefile.am (EXTRA_DIST): Remove avrdude.pdf since it is no longer + supplied. + * NEWS: Fix typo. + * bootstrap: Delete the autom4te.cache dir before running the + autotools. + * configure.ac (AC_INIT): Set version to 4.4.0. 2004-07-17 Jan-Hinnerk Reichert - * avrdude.1: Fixed obvious copy and paste error - (Patch #3199 contributed by Galen Seitz) + * avrdude.1: Fixed obvious copy and paste error + (Patch #3199 contributed by Galen Seitz) 2004-07-15 Theodore A. Roth - * main.c (main): Don't indent CPP directives. - When showing update progress in a no tty situation, use unbuffered IO - for all systems, not just win32 native. - Update copyright year when printing version. - Remove warning about native win32 being experimental. - Split a line string. - * ppiwin.c: Update copyright year. - Add cvs Id keyword. - (usleep): Cleanup debug CPP directives to improve readability. - * ser_win32.c: Include to fix failing build. + * main.c (main): Don't indent CPP directives. + When showing update progress in a no tty situation, use unbuffered IO + for all systems, not just win32 native. + Update copyright year when printing version. + Remove warning about native win32 being experimental. + Split a line string. + * ppiwin.c: Update copyright year. + Add cvs Id keyword. + (usleep): Cleanup debug CPP directives to improve readability. + * ser_win32.c: Include to fix failing build. 2004-07-08 Theodore A. Roth - * AUTHORS: Add names of recent major contributors. - * ser_win32.c: Assign copyright to Martin J. Thomas since he did all - real work on this file. + * AUTHORS: Add names of recent major contributors. + * ser_win32.c: Assign copyright to Martin J. Thomas since he did all + real work on this file. 2004-07-07 Jan-Hinnerk Reichert - * NEWS, doc/TODO: Updated NEWS and TODO + * NEWS, doc/TODO: Updated NEWS and TODO 2004-07-07 Jan-Hinnerk Reichert - * stk500.c, term.c, doc/avrdude.texi, avrdude.1: - added "sck"-command to the terminal mode. - This command allows slowing down of the SCK of - STK500-programmers. + * stk500.c, term.c, doc/avrdude.texi, avrdude.1: + added "sck"-command to the terminal mode. + This command allows slowing down of the SCK of + STK500-programmers. 2004-07-05 Jan-Hinnerk Reichert - * *.c, *.h: Removed unnecessary includes of - config.h + * *.c, *.h: Removed unnecessary includes of + config.h 2004-07-04 Jan-Hinnerk Reichert - * avr.h: Removed some unused prototypes + * avr.h: Removed some unused prototypes 2004-07-04 Jan-Hinnerk Reichert - * stk500.c: Fixed fosc behaviour for values exceeding - maximum frequency (contributed by Galen Seitz) + * stk500.c: Fixed fosc behaviour for values exceeding + maximum frequency (contributed by Galen Seitz) 2004-07-04 Jan-Hinnerk Reichert - * avrdude.conf.in: Added support for - ATtiny2313 (contributed by Bob Paddock) + * avrdude.conf.in: Added support for + ATtiny2313 (contributed by Bob Paddock) 2004-06-25 Joerg Wunsch - * avrdude.conf.in: Fix efuse bits for ATmega169. + * avrdude.conf.in: Fix efuse bits for ATmega169. 2004-06-24 Alex Shepherd - Merged in Win32 Native changes contributed by Martin Thomas - Changed all instances of __CYGWIN__ conditional compilation to - WIN32NATIVE - - * ser_win32.c: fleshed out all the previous stubs - * ser_posix.c: added WIN32NATIVE conditional compilation to skip - all function to allow ser_win32.c functions to operate - * ppi.h: removed commented code - * pgh.h: added usleep macros - * main.c: stdout,stderr tweaks for Win32 - * configure.ac: added CFLAGS and LDFLAGS for Win32Native - * config_gram.y: added strtok_r macro - * buterfly.c: added various stub functions and EXIT processing - * avr910.c: added return 0 to avr910_open() and included time headers - * term.c: added warning about libreadline not supported in WIN32NATIVE + Merged in Win32 Native changes contributed by Martin Thomas + Changed all instances of __CYGWIN__ conditional compilation to + WIN32NATIVE + + * ser_win32.c: fleshed out all the previous stubs + * ser_posix.c: added WIN32NATIVE conditional compilation to skip + all function to allow ser_win32.c functions to operate + * ppi.h: removed commented code + * pgh.h: added usleep macros + * main.c: stdout,stderr tweaks for Win32 + * configure.ac: added CFLAGS and LDFLAGS for Win32Native + * config_gram.y: added strtok_r macro + * buterfly.c: added various stub functions and EXIT processing + * avr910.c: added return 0 to avr910_open() and included time headers + * term.c: added warning about libreadline not supported in WIN32NATIVE 2004-06-17 Jan-Hinnerk Reichert - * avrdude.conf.in: Added support for - - tiny13 (contributed by Pawel Moll) - - mega48 and mega88 (contributed by Galen Seitz) - However, the STK500-code for mega8 remains unchanged. + * avrdude.conf.in: Added support for + - tiny13 (contributed by Pawel Moll) + - mega48 and mega88 (contributed by Galen Seitz) + However, the STK500-code for mega8 remains unchanged. 2004-05-19 Brian S. Dean - * main.c: - * stk500.c: Allow the baud rate to be specified on the command - line with a new -b switch. The specified baud rate will - override the default serial port baud rate for a particular - programmer. + * main.c: + * stk500.c: Allow the baud rate to be specified on the command + line with a new -b switch. The specified baud rate will + override the default serial port baud rate for a particular + programmer. 2004-05-19 Brian S. Dean - * ppi.c: Stub-out the ppi_* functions in ppi.c with empty - wrappers that simply return an error code in order to build - successfully on MacOS X. This allows avrdude to work on MacOS - X and was tested using a USB<->RS232 cable adapter, - specifically Keyspan model USA-19HS. + * ppi.c: Stub-out the ppi_* functions in ppi.c with empty + wrappers that simply return an error code in order to build + successfully on MacOS X. This allows avrdude to work on MacOS + X and was tested using a USB<->RS232 cable adapter, + specifically Keyspan model USA-19HS. 2004-04-23 Joerg Wunsch - * lists.h, lists.c: Drop LISTSZ and the check for - it in lcreat(). + * lists.h, lists.c: Drop LISTSZ and the check for + it in lcreat(). 2004-04-17 Jan-Hinnerk Reichert - * avr910.c: Hopefully fixed that weird "first byte not - programmed"-error in a good way (previous fix was not - working with all firmwares) + * avr910.c: Hopefully fixed that weird "first byte not + programmed"-error in a good way (previous fix was not + working with all firmwares) 2004-02-10 Jan-Hinnerk Reichert - * avrdude.1, doc/avrdude.texi, doc/TODO: - Removed the deprecated options from documentation + * avrdude.1, doc/avrdude.texi, doc/TODO: + Removed the deprecated options from documentation 2004-02-10 Jan-Hinnerk Reichert - * main.c: Removed deprecated options. + * main.c: Removed deprecated options. 2004-01-28 Jan-Hinnerk Reichert - * pgm.c, main.c, avr910.c, butterfly.c, stk500.c: - Changed default for powerup, powerdown and LED-commands - to do nothing and return OK. Then removed these commands - from avr910, butterfly and stk500. - * pgm.c: Fixed wrong type for default_open introduced by - the cleanup yesterday. + * pgm.c, main.c, avr910.c, butterfly.c, stk500.c: + Changed default for powerup, powerdown and LED-commands + to do nothing and return OK. Then removed these commands + from avr910, butterfly and stk500. + * pgm.c: Fixed wrong type for default_open introduced by + the cleanup yesterday. 2004-01-29 Jan-Hinnerk Reichert - * par.c: changed order of port-read/writes in par_txrx(). - This change should increase immunity to delays in the - programmer-hardware. - Also did some unrelated cleanup in par_txrx(). + * par.c: changed order of port-read/writes in par_txrx(). + This change should increase immunity to delays in the + programmer-hardware. + Also did some unrelated cleanup in par_txrx(). 2004-01-28 Jan-Hinnerk Reichert - * pgm.[ch], main.c, par.c, avr910.c, butterfly.c, stk500.c: - Move save/restore-functionality into open/close. - * par.c: open/close now saves/restores PPICTRL, too. - * TODO: exitspecs don't work if RESET is in PPICTRL. + * pgm.[ch], main.c, par.c, avr910.c, butterfly.c, stk500.c: + Move save/restore-functionality into open/close. + * par.c: open/close now saves/restores PPICTRL, too. + * TODO: exitspecs don't work if RESET is in PPICTRL. 2004-01-26 Theodore A. Roth - * configure.ac (AC_INIT): Post release version update. + * configure.ac (AC_INIT): Post release version update. 2004-01-26 Theodore A. Roth - * AVRDUDE 4.3.0 has been released (cvs release tag is "release_4_3_0"). + * AVRDUDE 4.3.0 has been released (cvs release tag is "release_4_3_0"). 2004-01-26 Theodore A. Roth - * configure.ac: Update copyright year. - (AC_INIT): Set version to 4.3.0. + * configure.ac: Update copyright year. + (AC_INIT): Set version to 4.3.0. 2004-01-25 Theodore A. Roth - * ChangeLog: Minor formatting cleanups. - Move to all 2003 entries to ChangeLog-2003. - * ChangeLog-2003: New file. - * Makefile.am: Update copyright year. - (EXTRA_DIST): Add ChangeLog-2003. + * ChangeLog: Minor formatting cleanups. + Move to all 2003 entries to ChangeLog-2003. + * ChangeLog-2003: New file. + * Makefile.am: Update copyright year. + (EXTRA_DIST): Add ChangeLog-2003. 2004-01-17 Jan-Hinnerk Reichert - * doc/avrdude.texi: Get rid of those black boxes marking "overfull - hbox". + * doc/avrdude.texi: Get rid of those black boxes marking "overfull + hbox". 2004-01-17 Jan-Hinnerk Reichert - * doc/avrdude.texi: New appendix "Troubleshooting". + * doc/avrdude.texi: New appendix "Troubleshooting". 2004-01-12 Jan-Hinnerk Reichert - * avr910.c, avrpart.c, avrpart.h, doc/TODO: - Look up devicecode and report device. + * avr910.c, avrpart.c, avrpart.h, doc/TODO: + Look up devicecode and report device. 2004-01-03 Jan-Hinnerk Reichert - * avr910.c, pgm.c, pgm.h, config_gram.y, lexer.l: Add new configuration - parameter baudrate to support avr910-programmers with non-standard - baudrates. - * avrdude.conf.in, doc/avrdude.texi: Added "baudrate" to documentation. + * avr910.c, pgm.c, pgm.h, config_gram.y, lexer.l: Add new configuration + parameter baudrate to support avr910-programmers with non-standard + baudrates. + * avrdude.conf.in, doc/avrdude.texi: Added "baudrate" to documentation. 2004-01-03 Jan-Hinnerk Reichert - * avr910.c: Removed debugging stuff that is no longer needed. + * avr910.c: Removed debugging stuff that is no longer needed. 2004-01-03 Jan-Hinnerk Reichert - * doc/TODO: Removed two items. + * doc/TODO: Removed two items. 2004-01-03 Jan-Hinnerk Reichert - * main.c, avr.c, avr.h, par.c, stk500.c: Add function - avr_chip_erase() to unify handling of cycle-count. - Makes cycle-count work for avr910-programmers. + * main.c, avr.c, avr.h, par.c, stk500.c: Add function + avr_chip_erase() to unify handling of cycle-count. + Makes cycle-count work for avr910-programmers. diff --git a/src/avrdude/ChangeLog-2007 b/src/avrdude/ChangeLog-2007 index 3514da7e00a..bff15b977c1 100644 --- a/src/avrdude/ChangeLog-2007 +++ b/src/avrdude/ChangeLog-2007 @@ -1,364 +1,364 @@ 2007-11-08 Joerg Wunsch - * main.c: Partially revert the line buffered output change, - and turn stderr into unbuffered output while producing the - progress report. + * main.c: Partially revert the line buffered output change, + and turn stderr into unbuffered output while producing the + progress report. 2007-11-07 Joerg Wunsch - * main.c: Add setup and teardown hooks to the programmer - definition. If present, call the setup hook immediately after - finding the respective programmer object, and schedule the - teardown hook to be called upon exit. This allows the - programmer implementation to dynamically allocate private - programmer data. - * pgm.c: (Ditto.) - * pgm.h: (Ditto.) - * avr910.c: Convert static programmer data into dynamically - allocated data. - * butterfly.c: (Ditto.) - * jtagmkI.c: (Ditto.) - * jtagmkII.c: (Ditto.) - * stk500v2.c: (Ditto.) - * usbasp.c: (Ditto.) - * usbtiny.c: (Ditto.) + * main.c: Add setup and teardown hooks to the programmer + definition. If present, call the setup hook immediately after + finding the respective programmer object, and schedule the + teardown hook to be called upon exit. This allows the + programmer implementation to dynamically allocate private + programmer data. + * pgm.c: (Ditto.) + * pgm.h: (Ditto.) + * avr910.c: Convert static programmer data into dynamically + allocated data. + * butterfly.c: (Ditto.) + * jtagmkI.c: (Ditto.) + * jtagmkII.c: (Ditto.) + * stk500v2.c: (Ditto.) + * usbasp.c: (Ditto.) + * usbtiny.c: (Ditto.) 2007-11-06 Joerg Wunsch - * butterfly.c: Remove the no_show_func_info() calls, as Brian - promised some 4 years ago. + * butterfly.c: Remove the no_show_func_info() calls, as Brian + promised some 4 years ago. 2007-11-06 Joerg Wunsch - * main.c: Add the -x option to pass extended parameters to - the programmer backend. - * pgm.c: (Ditto.) - * pgm.h: (Ditto.) - * jtagmkII.c: Implement the extended parameter jtagchain= - to support JTAG daisy-chains. - * avrdude.1: Document all of the above. - * doc/avrdude.texi: (Ditto.) + * main.c: Add the -x option to pass extended parameters to + the programmer backend. + * pgm.c: (Ditto.) + * pgm.h: (Ditto.) + * jtagmkII.c: Implement the extended parameter jtagchain= + to support JTAG daisy-chains. + * avrdude.1: Document all of the above. + * doc/avrdude.texi: (Ditto.) 2007-10-30 Joerg Wunsch - * configure.ac (AC_INIT): Bump version for post-release. + * configure.ac (AC_INIT): Bump version for post-release. 2007-10-29 Joerg Wunsch - * configure.ac (AC_INIT): Bump version, releasing avrdude-5.5. + * configure.ac (AC_INIT): Bump version, releasing avrdude-5.5. 2007-10-29 Joerg Wunsch - Submitted by : - patch #5007: Patch for line-buffering of stdout and stderr - * main.c: call setvbuf() for stdout and stderr. + Submitted by : + patch #5007: Patch for line-buffering of stdout and stderr + * main.c: call setvbuf() for stdout and stderr. 2007-10-29 Joerg Wunsch - Submitted by : - patch #5953: Add AT90CAN64 and AT90CAN32 to avrdude.conf - * avrdude.conf.in: Add entry for AT90CAN64 and AT90CAN32. + Submitted by : + patch #5953: Add AT90CAN64 and AT90CAN32 to avrdude.conf + * avrdude.conf.in: Add entry for AT90CAN64 and AT90CAN32. 2007-10-29 Joerg Wunsch - Submitted by Wolfgang Moser: - patch #6121: ISP support for the C2N232I device (serial port - bitbanging) - * avrdude.conf.in: Add entry for c2n232i. + Submitted by Wolfgang Moser: + patch #6121: ISP support for the C2N232I device (serial port + bitbanging) + * avrdude.conf.in: Add entry for c2n232i. 2007-10-29 Joerg Wunsch - Submitted by : - patch #6141: accept binary format immediate values - * fileio.c: Detect a 0b prefix, and call strtoul() differently - in that case. + Submitted by : + patch #6141: accept binary format immediate values + * fileio.c: Detect a 0b prefix, and call strtoul() differently + in that case. 2007-10-29 Joerg Wunsch - bug #21076: -vvvv serial receive prints are empty in Win32 build - * ser_win32.c (ser_recv): Drop the essentially unused variable - "len", and use the variable "read" in order to track how many - bytes have just been read in. + bug #21076: -vvvv serial receive prints are empty in Win32 build + * ser_win32.c (ser_recv): Drop the essentially unused variable + "len", and use the variable "read" in order to track how many + bytes have just been read in. 2007-10-29 Joerg Wunsch - bug #21145: atmega329p not recognized - * avrdude.conf.in: Add definitions for the ATmega329P/3290P. - Same as ATmega329/3290 except of the different signature. + bug #21145: atmega329p not recognized + * avrdude.conf.in: Add definitions for the ATmega329P/3290P. + Same as ATmega329/3290 except of the different signature. 2007-10-29 Joerg Wunsch - bug #21152: Unable to program atmega324p with avrdude 5.4 and AVRISP - using default configuration file. - * avrdude.conf.in: Uncomment the (bogus) stk500_devcode lines for - the ATmega164P, ATmega324P, ATmega644, and ATmega644P definitions. - This only affects users of STK500v1 firmware. + bug #21152: Unable to program atmega324p with avrdude 5.4 and AVRISP + using default configuration file. + * avrdude.conf.in: Uncomment the (bogus) stk500_devcode lines for + the ATmega164P, ATmega324P, ATmega644, and ATmega644P definitions. + This only affects users of STK500v1 firmware. 2007-10-29 Joerg Wunsch - Submitted by : - Patch #6233: Add support for USBtinyISP programmer - * usbtiny.c: New file. - * usbtiny.h: (Ditto.) - * Makefile.am: Include usbtiny into the build. - * avrdude.conf.in: (Ditto.) - * config_gram.y: (Ditto.) - * lexer.l: (Ditto.) - * avrdude.1: Document the usbtiny support. - * doc/avrdude.texi: (Ditto.) + Submitted by : + Patch #6233: Add support for USBtinyISP programmer + * usbtiny.c: New file. + * usbtiny.h: (Ditto.) + * Makefile.am: Include usbtiny into the build. + * avrdude.conf.in: (Ditto.) + * config_gram.y: (Ditto.) + * lexer.l: (Ditto.) + * avrdude.1: Document the usbtiny support. + * doc/avrdude.texi: (Ditto.) 2007-10-29 Joerg Wunsch - * doc/avrdude.texi: Sort list of supported programmers into - alphabetical order, add all missing programmers. + * doc/avrdude.texi: Sort list of supported programmers into + alphabetical order, add all missing programmers. 2007-07-24 Thomas Fischl - * usbasp.c: Added long addresses to support devices with more + * usbasp.c: Added long addresses to support devices with more than 64kB flash. Closes bug #20558: Long address problem with USBasp. 2007-06-27 Joerg Wunsch - * Makefile.am (EXTRA_DIST): Add ChangeLog-2004-2006. + * Makefile.am (EXTRA_DIST): Add ChangeLog-2004-2006. 2007-05-16 Joerg Wunsch - * configure.ac (AC_INIT): Bump version for post-release. + * configure.ac (AC_INIT): Bump version for post-release. 2007-05-16 Joerg Wunsch - * configure.ac (AC_INIT): Bump version, releasing avrdude-5.4. + * configure.ac (AC_INIT): Bump version, releasing avrdude-5.4. 2007-05-16 Joerg Wunsch - * avrdude.conf.in: Fix AVR910 devcodes. It seems that the AVR109 - listing refers to "BOOT"-type code, while the standard codes are - different (usually one below). + * avrdude.conf.in: Fix AVR910 devcodes. It seems that the AVR109 + listing refers to "BOOT"-type code, while the standard codes are + different (usually one below). 2007-05-16 Joerg Wunsch - * avr.c (avr_read, avr_write): only use the paged_load and - paged_write backend functions iff the memory area in question has - a page_size != 0. - This is supposed to fix bug #19234: avrdude-5.3.1 segfaults when - stk500v1 tries to program an ATtiny15 + * avr.c (avr_read, avr_write): only use the paged_load and + paged_write backend functions iff the memory area in question has + a page_size != 0. + This is supposed to fix bug #19234: avrdude-5.3.1 segfaults when + stk500v1 tries to program an ATtiny15 2007-05-15 Joerg Wunsch - * avr910.c: Fall back to avr_{read,write}_byte_default(). Fixes - bug #18803: Fuse reading regression in avrdude 5.3.1 with avr910 - programmer + * avr910.c: Fall back to avr_{read,write}_byte_default(). Fixes + bug #18803: Fuse reading regression in avrdude 5.3.1 with avr910 + programmer 2007-05-15 Colin O'Flynn - * avrdude.conf.in: Rename the ATmega164 and ATmega324 into - ATmega164P and ATmega324P, resp. Add an entry for the ATmega644P. - Fixes bug #19769: ATmega164p not recognized + * avrdude.conf.in: Rename the ATmega164 and ATmega324 into + ATmega164P and ATmega324P, resp. Add an entry for the ATmega644P. + Fixes bug #19769: ATmega164p not recognized 2007-05-15 Joerg Wunsch - * ser_posix.c (ser_send): Don't select() on the output fd before - trying to write something to the serial line. That kind of - polling isn't very useful anyway, and it seems it breaks for the - Linux CP210x USB<->RS-232 bridge driver which is certainly a bug - in the driver, but we can just avoid that bug alltogether. + * ser_posix.c (ser_send): Don't select() on the output fd before + trying to write something to the serial line. That kind of + polling isn't very useful anyway, and it seems it breaks for the + Linux CP210x USB<->RS-232 bridge driver which is certainly a bug + in the driver, but we can just avoid that bug alltogether. 2007-05-15 Joerg Wunsch - * avrdude.conf.in: Fix the STK500v2 ISP delay parameter for - ATmega640/1280/1281/2560/2561. Atmel has changed the XML - files after the initial release. + * avrdude.conf.in: Fix the STK500v2 ISP delay parameter for + ATmega640/1280/1281/2560/2561. Atmel has changed the XML + files after the initial release. 2007-05-01 Colin O'Flynn - * safemode.c: -Oops - bug in verbose output. Fixed. - -Fixed handling of cases where programmer cannot read fuses (AVR910) - * main.c: -Also fixing handling of cases where programmer cannot - read fuses - This should close one or more bugs (18803, 19570) + * safemode.c: -Oops - bug in verbose output. Fixed. + -Fixed handling of cases where programmer cannot read fuses (AVR910) + * main.c: -Also fixing handling of cases where programmer cannot + read fuses + This should close one or more bugs (18803, 19570) 2007-05-01 Colin O'Flynn - * safemode.c: Added verbose output from safemode routines. + * safemode.c: Added verbose output from safemode routines. 2007-03-25 Colin O'Flynn - * stk500generic.c: Forgot to close the serial port before trying to - open it again, caused problems on Windows machines. - Closes bug #19411 + * stk500generic.c: Forgot to close the serial port before trying to + open it again, caused problems on Windows machines. + Closes bug #19411 2007-02-26 Joerg Wunsch - * avrdude.conf.in: Add the AT90PWM2/3B devices. + * avrdude.conf.in: Add the AT90PWM2/3B devices. 2007-02-02 Thomas Fischl - * usbasp.c: Changed return value of function usbasp_initialize to stop - avrdude on communication errors between programmer and target. - Closes bug #18581: safemode destroys fuse bits + * usbasp.c: Changed return value of function usbasp_initialize to stop + avrdude on communication errors between programmer and target. + Closes bug #18581: safemode destroys fuse bits 2007-02-01 Joerg Wunsch - * config_gram.y: Remove duplicate definition of token K_WRITEPAGE + * config_gram.y: Remove duplicate definition of token K_WRITEPAGE 2007-01-30 Joerg Wunsch - * butterfly.c: Implement ATmega256x support for butterfly/avr109. + * butterfly.c: Implement ATmega256x support for butterfly/avr109. 2007-01-30 Joerg Wunsch - * configure.ac: Fix subdir handling. Now finally, "make - distcheck" will include the documentation into the tarball even if - the configure had been run without the --enable-doc. + * configure.ac: Fix subdir handling. Now finally, "make + distcheck" will include the documentation into the tarball even if + the configure had been run without the --enable-doc. 2007-01-30 Joerg Wunsch - * safemode.c: Obtain progname from avrdude.h rather than trying to - roll our own (duplicate) copy of it. - * avr910.c: Constify char pointers. - * avrpart.c: (Ditto.) - * avrpart.h: (Ditto.) - * butterfly.c: (Ditto.) - * config.c: (Ditto.) - * config.h: (Ditto.) - * jtagmkI.c: (Ditto.) - * jtagmkII.c: (Ditto.) - * par.c: (Ditto.) - * pgm.c: (Ditto.) - * pgm.h: (Ditto.) - * serbb_posix.c: (Ditto.) - * serbb_win32.c: (Ditto.) - * stk500.c: (Ditto.) - * stk500v2.c: (Ditto.) - * usbasp.c: (Ditto.) + * safemode.c: Obtain progname from avrdude.h rather than trying to + roll our own (duplicate) copy of it. + * avr910.c: Constify char pointers. + * avrpart.c: (Ditto.) + * avrpart.h: (Ditto.) + * butterfly.c: (Ditto.) + * config.c: (Ditto.) + * config.h: (Ditto.) + * jtagmkI.c: (Ditto.) + * jtagmkII.c: (Ditto.) + * par.c: (Ditto.) + * pgm.c: (Ditto.) + * pgm.h: (Ditto.) + * serbb_posix.c: (Ditto.) + * serbb_win32.c: (Ditto.) + * stk500.c: (Ditto.) + * stk500v2.c: (Ditto.) + * usbasp.c: (Ditto.) 2007-01-29 Joerg Wunsch - * avrpart.c: More backend/library abstraction and generalization: - turn the list_parts() and list_programmers() functions into - general list iteration functions that call a caller-supplied - callback for each element. Implement list_parts() and - list_programmers() as private functions in main.c based on that - approach. - * avrpart.h: (Ditto.) - * main.c: (Ditto.) - * pgm.c: (Ditto.) - * pgm.h: (Ditto.) + * avrpart.c: More backend/library abstraction and generalization: + turn the list_parts() and list_programmers() functions into + general list iteration functions that call a caller-supplied + callback for each element. Implement list_parts() and + list_programmers() as private functions in main.c based on that + approach. + * avrpart.h: (Ditto.) + * main.c: (Ditto.) + * pgm.c: (Ditto.) + * pgm.h: (Ditto.) 2007-01-25 Joerg Wunsch - * Makefile.am: Rearrange everything so it is now built into a - libavrdude.a library, and link main.c against that library. - * configure.ac: Add AC_PROG_RANLIB as we are building a library - now. + * Makefile.am: Rearrange everything so it is now built into a + libavrdude.a library, and link main.c against that library. + * configure.ac: Add AC_PROG_RANLIB as we are building a library + now. 2007-01-24 Joerg Wunsch - Major code cleanup. - - Make all internal functions "static". - - Make sure each module's header and implementation file match. - - Remove all library-like functionality from main.c, so only - the actual frontend remains in main.c. - - Add C++ brackets to all header files. - * avr.c: (Ditto.) - * avr.h: (Ditto.) - * avr910.c: (Ditto.) - * avr910.h: (Ditto.) - * avrdude.h: (Ditto.) - * avrpart.c: (Ditto.) - * avrpart.h: (Ditto.) - * bitbang.h: (Ditto.) - * butterfly.h: (Ditto.) - * config.c: (Ditto.) - * config.h: (Ditto.) - * confwin.h: (Ditto.) - * crc16.c: (Ditto.) - * crc16.h: (Ditto.) - * fileio.c: (Ditto.) - * fileio.h: (Ditto.) - * jtagmkI.h: (Ditto.) - * jtagmkII.h: (Ditto.) - * lexer.l: (Ditto.) - * lists.h: (Ditto.) - * main.c: (Ditto.) - * par.h: (Ditto.) - * pgm.c: (Ditto.) - * pgm.h: (Ditto.) - * ppi.c: (Ditto.) - * ppi.h: (Ditto.) - * safemode.h: (Ditto.) - * serbb.h: (Ditto.) - * serial.h: (Ditto.) - * stk500.h: (Ditto.) - * stk500v2.c: (Ditto.) - * stk500v2.h: (Ditto.) - * term.c: (Ditto.) - * term.h: (Ditto.) - * usbasp.h: (Ditto.) - * update.c: New file. - * update.h: New file. - * Makefile.am: Include update.c and update.h. + Major code cleanup. + - Make all internal functions "static". + - Make sure each module's header and implementation file match. + - Remove all library-like functionality from main.c, so only + the actual frontend remains in main.c. + - Add C++ brackets to all header files. + * avr.c: (Ditto.) + * avr.h: (Ditto.) + * avr910.c: (Ditto.) + * avr910.h: (Ditto.) + * avrdude.h: (Ditto.) + * avrpart.c: (Ditto.) + * avrpart.h: (Ditto.) + * bitbang.h: (Ditto.) + * butterfly.h: (Ditto.) + * config.c: (Ditto.) + * config.h: (Ditto.) + * confwin.h: (Ditto.) + * crc16.c: (Ditto.) + * crc16.h: (Ditto.) + * fileio.c: (Ditto.) + * fileio.h: (Ditto.) + * jtagmkI.h: (Ditto.) + * jtagmkII.h: (Ditto.) + * lexer.l: (Ditto.) + * lists.h: (Ditto.) + * main.c: (Ditto.) + * par.h: (Ditto.) + * pgm.c: (Ditto.) + * pgm.h: (Ditto.) + * ppi.c: (Ditto.) + * ppi.h: (Ditto.) + * safemode.h: (Ditto.) + * serbb.h: (Ditto.) + * serial.h: (Ditto.) + * stk500.h: (Ditto.) + * stk500v2.c: (Ditto.) + * stk500v2.h: (Ditto.) + * term.c: (Ditto.) + * term.h: (Ditto.) + * usbasp.h: (Ditto.) + * update.c: New file. + * update.h: New file. + * Makefile.am: Include update.c and update.h. 2007-01-24 Joerg Wunsch - Move all "extern" declarations into a centreal header file. - * Makefile.am: Add new avrdude.h. - * avrdude.h: New file. - * avr.c: Replace private extern decl's by #include "avrdude.h". - * avr910.c: (Ditto.) - * avrpart.c: (Ditto.) - * bitbang.c: (Ditto.) - * butterfly.c: (Ditto.) - * config.c: (Ditto.) - * config_gram.y: (Ditto.) - * fileio.c: (Ditto.) - * jtagmkI.c: (Ditto.) - * jtagmkII.c: (Ditto.) - * lexer.l: (Ditto.) - * main.c: (Ditto.) - * par.c: (Ditto.) - * pgm.c: (Ditto.) - * ppi.c: (Ditto.) - * ppiwin.c: (Ditto.) - * ser_avrdoper.c: (Ditto.) - * ser_posix.c: (Ditto.) - * ser_win32.c: (Ditto.) - * serbb_posix.c: (Ditto.) - * serbb_win32.c: (Ditto.) - * stk500.c: (Ditto.) - * stk500generic.c: (Ditto.) - * stk500v2.c: (Ditto.) - * term.c: (Ditto.) - * usb_libusb.c: (Ditto.) - * usbasp.c: (Ditto.) + Move all "extern" declarations into a centreal header file. + * Makefile.am: Add new avrdude.h. + * avrdude.h: New file. + * avr.c: Replace private extern decl's by #include "avrdude.h". + * avr910.c: (Ditto.) + * avrpart.c: (Ditto.) + * bitbang.c: (Ditto.) + * butterfly.c: (Ditto.) + * config.c: (Ditto.) + * config_gram.y: (Ditto.) + * fileio.c: (Ditto.) + * jtagmkI.c: (Ditto.) + * jtagmkII.c: (Ditto.) + * lexer.l: (Ditto.) + * main.c: (Ditto.) + * par.c: (Ditto.) + * pgm.c: (Ditto.) + * ppi.c: (Ditto.) + * ppiwin.c: (Ditto.) + * ser_avrdoper.c: (Ditto.) + * ser_posix.c: (Ditto.) + * ser_win32.c: (Ditto.) + * serbb_posix.c: (Ditto.) + * serbb_win32.c: (Ditto.) + * stk500.c: (Ditto.) + * stk500generic.c: (Ditto.) + * stk500v2.c: (Ditto.) + * term.c: (Ditto.) + * usb_libusb.c: (Ditto.) + * usbasp.c: (Ditto.) 2007-01-13 Joerg Wunsch - * avrdude.conf.in (ATmega8): Bump the delay values for flash - and EEPROM, based on the current Atmel XML file. + * avrdude.conf.in (ATmega8): Bump the delay values for flash + and EEPROM, based on the current Atmel XML file. 2007-01-12 Joerg Wunsch - * configure.ac: Improve the detection of the Win32 HID library, - and the presence of the header ddk/hidsdi.h. It now works - correctly under Cygwin and several flavours of MinGW. - * Makefile.am: Add new LIBHID pattern. + * configure.ac: Improve the detection of the Win32 HID library, + and the presence of the header ddk/hidsdi.h. It now works + correctly under Cygwin and several flavours of MinGW. + * Makefile.am: Add new LIBHID pattern. 2007-01-11 Joerg Wunsch - * butterfly.c (butterfly_initialize): when sending the 'T' - command (which is ignored by current AVR109 bootloaders), - send the first reply from the list of supported device - codes back rather than using avrdude.conf's idea about - an AVR910 device code. Apparently, this solves disagreements - between different versions of at least the ATmega8 AVR910 - device code. - Closes bug #18727: Writing flash failed + * butterfly.c (butterfly_initialize): when sending the 'T' + command (which is ignored by current AVR109 bootloaders), + send the first reply from the list of supported device + codes back rather than using avrdude.conf's idea about + an AVR910 device code. Apparently, this solves disagreements + between different versions of at least the ATmega8 AVR910 + device code. + Closes bug #18727: Writing flash failed 2007-01-07 Joerg Wunsch - Reported by Till Harbaum: - * avrdude.conf.in (ATtiny25/45/85): Change HVSP reset from - 500 microseconds to 1 ms, matching the most recent Atmel XML - specs. + Reported by Till Harbaum: + * avrdude.conf.in (ATtiny25/45/85): Change HVSP reset from + 500 microseconds to 1 ms, matching the most recent Atmel XML + specs. diff --git a/src/avrdude/ChangeLog-2008 b/src/avrdude/ChangeLog-2008 index f43a10abbe2..17d723cfab4 100644 --- a/src/avrdude/ChangeLog-2008 +++ b/src/avrdude/ChangeLog-2008 @@ -1,185 +1,185 @@ 2008-11-20 Joerg Wunsch - * avrdude.h: Change the prototype for usleep() to be more Cygwin- - friendly. - * ppiwin.c: (Ditto.) + * avrdude.h: Change the prototype for usleep() to be more Cygwin- + friendly. + * ppiwin.c: (Ditto.) 2008-11-06 Joerg Wunsch - Submitted by limor - * usbtiny.c (usbtiny_cmd): Replace sizeof() by a fixed constant - 4 for the result array, because otherwise it would take the size - of a pointer which miserably fails on 64-bit machines. + Submitted by limor + * usbtiny.c (usbtiny_cmd): Replace sizeof() by a fixed constant + 4 for the result array, because otherwise it would take the size + of a pointer which miserably fails on 64-bit machines. 2008-11-05 Joerg Wunsch - patch #6609: Using PCI parallel port cards on Windows - * ppiwin.c (ppi_open): If the port parameter passed from the - -p option is neither lpt1/2/3, try interpreting it directly as - a base address. - * avrdude.1: Document the change. - * doc/avrdude.texi: (Ditto.) + patch #6609: Using PCI parallel port cards on Windows + * ppiwin.c (ppi_open): If the port parameter passed from the + -p option is neither lpt1/2/3, try interpreting it directly as + a base address. + * avrdude.1: Document the change. + * doc/avrdude.texi: (Ditto.) 2008-11-04 Joerg Wunsch - bug #22882: Erase Cycle Counter does not work for stk500v2 - * stk500v2.c (stk500v2_chip_erase,stk500hv_chip_erase): Return - the expected 0 for success rather than a protocol-dependant - number. - + bug #22882: Erase Cycle Counter does not work for stk500v2 + * stk500v2.c (stk500v2_chip_erase,stk500hv_chip_erase): Return + the expected 0 for success rather than a protocol-dependant + number. + 2008-11-04 Joerg Wunsch - bug #22883: Chip Erase performed even with no-write flag (-n) - * main.c: Do not erase the chip if both, -e and -n options have - been specified. + bug #22883: Chip Erase performed even with no-write flag (-n) + * main.c: Do not erase the chip if both, -e and -n options have + been specified. 2008-11-04 Joerg Wunsch - bug #24589: AT90USB64* have wrong signature - * avrdude.conf.in: Uncomment the correct, and delete the wrong - signature for AT90USB646/647. Alas, the datasheet has never been - corrected for years. + bug #24589: AT90USB64* have wrong signature + * avrdude.conf.in: Uncomment the correct, and delete the wrong + signature for AT90USB646/647. Alas, the datasheet has never been + corrected for years. 2008-10-31 Joerg Wunsch - * jtagmkII.c: Fix a serious memory corruption that happened when - using the JTAG ICE mkII (or AVR Dragon) in ISP mode. The wrong - set of per-programmer private data had been allocated (stk500v2 - vs. jtagmkII) which was too small to hold the actual data. - * jtagmkII.h: (Ditto.) - * stk500v2.c: (Ditto.) + * jtagmkII.c: Fix a serious memory corruption that happened when + using the JTAG ICE mkII (or AVR Dragon) in ISP mode. The wrong + set of per-programmer private data had been allocated (stk500v2 + vs. jtagmkII) which was too small to hold the actual data. + * jtagmkII.h: (Ditto.) + * stk500v2.c: (Ditto.) 2008-07-29 Joerg Wunsch - * jtagmkII.c: Implement Xmega JTAG support. - * jtagmkII_private.h: Add EMULATOR_MODE_JTAG_XMEGA. + * jtagmkII.c: Implement Xmega JTAG support. + * jtagmkII_private.h: Add EMULATOR_MODE_JTAG_XMEGA. 2008-07-29 Joerg Wunsch - * main.c: Remember whether the device initialization worked, and - allow to continue with -F if it failed yet do not attempt to - perform anything on the device itself. That way, -tF could be - specified for programmers like the STK500/STK600 even without a - device connected, just in order to allow changing parameters on - the programmer itself. - * avrdude.1: Document that possible use of the -F option. - * doc/avrdude.texi: (Ditto.) + * main.c: Remember whether the device initialization worked, and + allow to continue with -F if it failed yet do not attempt to + perform anything on the device itself. That way, -tF could be + specified for programmers like the STK500/STK600 even without a + device connected, just in order to allow changing parameters on + the programmer itself. + * avrdude.1: Document that possible use of the -F option. + * doc/avrdude.texi: (Ditto.) 2008-07-29 Joerg Wunsch - * stk500v2.c (stk600_xprog_paged_write): Fix a fatal miscalculation - of the number of bytes to be written which caused a malloc chunk - corruption. + * stk500v2.c (stk600_xprog_paged_write): Fix a fatal miscalculation + of the number of bytes to be written which caused a malloc chunk + corruption. 2008-07-27 Joerg Wunsch - First implementation of ATxmega support. By now, only the - PDI mode of the STK600 is supported. Single-byte EEPROM - (and flash) updates do not work yet. - * avr.c: "boot" memory is a candidate memory region for paged - operations, besides "flash" and "eeprom". - * avrdude.conf.in: add ATxmega128A1 and ATxmega128A1revD - * avrpart.h: add the AVRPART_HAS_PDI flag (used to distinguish - ATxmega parts from classic AVRs), the nvm_base part field, and - the offset field for a memory region. - * config_gram.y: add "has_pdi", "nvm_base", and "offset" - * lexer.l: (Ditto.) - * main.c: disable auto_erase for ATxmega parts - * stk500v2.c: implement the XPROG functionality, and divert to - this for ATxmega parts - * avrdude.1: Document the changes. - * doc/avrdude.texi: (Ditto.) + First implementation of ATxmega support. By now, only the + PDI mode of the STK600 is supported. Single-byte EEPROM + (and flash) updates do not work yet. + * avr.c: "boot" memory is a candidate memory region for paged + operations, besides "flash" and "eeprom". + * avrdude.conf.in: add ATxmega128A1 and ATxmega128A1revD + * avrpart.h: add the AVRPART_HAS_PDI flag (used to distinguish + ATxmega parts from classic AVRs), the nvm_base part field, and + the offset field for a memory region. + * config_gram.y: add "has_pdi", "nvm_base", and "offset" + * lexer.l: (Ditto.) + * main.c: disable auto_erase for ATxmega parts + * stk500v2.c: implement the XPROG functionality, and divert to + this for ATxmega parts + * avrdude.1: Document the changes. + * doc/avrdude.texi: (Ditto.) 2008-07-25 Joerg Wunsch - Fix a bunch of warnings. - * avr910.c (avr910_paged_load): possible unitialized use of - rd_size - * jtagmkI.c (jtagmkI_initialize): pointer signedness mixup - * jtagmkII.c (jtagmkII_print_parms1): propagate const'ness - of parameter - * usbasp.c (usbasp_transmit): pointer signedness mixup - * ser_avrdoper.c (usbGetReport): remove useless pointer deref + Fix a bunch of warnings. + * avr910.c (avr910_paged_load): possible unitialized use of + rd_size + * jtagmkI.c (jtagmkI_initialize): pointer signedness mixup + * jtagmkII.c (jtagmkII_print_parms1): propagate const'ness + of parameter + * usbasp.c (usbasp_transmit): pointer signedness mixup + * ser_avrdoper.c (usbGetReport): remove useless pointer deref 2008-07-25 Joerg Wunsch - Contributed by Ville Voipio: - patch #6501: New autotools support for avrdude - * Makefile.am: add @WINDOWS_DIRS@ to SUBDIR - * bootstrap: allow for autconf-2.61 and automake-1.10, too - * configure.ac: fix @WINDOWS_DIRS@ recursion, replace - AC_PROG_CC by AM_PROG_CC_C_O, for esoteric reasons + Contributed by Ville Voipio: + patch #6501: New autotools support for avrdude + * Makefile.am: add @WINDOWS_DIRS@ to SUBDIR + * bootstrap: allow for autconf-2.61 and automake-1.10, too + * configure.ac: fix @WINDOWS_DIRS@ recursion, replace + AC_PROG_CC by AM_PROG_CC_C_O, for esoteric reasons 2008-06-13 Joerg Wunsch - Contributed by Janos Sallai : - patch #6074: added support for crossbow's MIB510 programmer - * avrdude.conf.in: Add entry for mib510. - * stk500.c: Add special hooks to handle the MIB510 programmer. - It mostly talks STK500v1 protocol but has a special hello and - goodbye sequence, and uses a fixed block size of 256 bytes. - * doc/avrdude.texi: Document support for mib510. + Contributed by Janos Sallai : + patch #6074: added support for crossbow's MIB510 programmer + * avrdude.conf.in: Add entry for mib510. + * stk500.c: Add special hooks to handle the MIB510 programmer. + It mostly talks STK500v1 protocol but has a special hello and + goodbye sequence, and uses a fixed block size of 256 bytes. + * doc/avrdude.texi: Document support for mib510. 2008-06-07 Joerg Wunsch - Contributed by Klaus Leidinger : - * main.c: Realign verbose messages. - * avrpart.c: (Ditto.) - * avr910.c: Print the device code selected in verbose mode. - * butterfly.c: (Ditto.) + Contributed by Klaus Leidinger : + * main.c: Realign verbose messages. + * avrpart.c: (Ditto.) + * avr910.c: Print the device code selected in verbose mode. + * butterfly.c: (Ditto.) 2008-06-07 Joerg Wunsch - Contributed by Klaus Leidinger : - Add check for buffermode feature, and use it if present. Can be - turned off using -x no_blockmode. - * avr910.c: Implement buffermode test and usage. - * avrdude.1: Document -x no_blockmode. - * doc/avrdude.texi: (Ditto.) + Contributed by Klaus Leidinger : + Add check for buffermode feature, and use it if present. Can be + turned off using -x no_blockmode. + * avr910.c: Implement buffermode test and usage. + * avrdude.1: Document -x no_blockmode. + * doc/avrdude.texi: (Ditto.) 2008-03-24 Joerg Wunsch - * usb_libusb.c: #undef interface for Win32 + * usb_libusb.c: #undef interface for Win32 2008-03-24 Joerg Wunsch - * avr910.c: Add support for the -x devcode option. - * avrdude.1: Document -x devcode for avr910. - * doc/avrdude.texi: (Ditto.) + * avr910.c: Add support for the -x devcode option. + * avrdude.1: Document -x devcode for avr910. + * doc/avrdude.texi: (Ditto.) 2008-03-14 Joerg Wunsch - Add initial support for the Atmel STK600, for - "classic" AVRs (AT90, ATtiny, ATmega) in both, - ISP and high-voltage programming modes. - * Makefile.am: Add -lm. - * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. - * config_gram.y: Add support for the stk600* keywords. - * lexer.l: (Ditto.) - * pgm.h: Add the "chan" parameter to set_varef(). - * stk500.c: (Ditto.) - * serial.h: Add USB endpoint support to struct filedescriptor. - * stk500v2.c: Implement the meat of the STK600 support. - * stk500v2.h: Add new prototypes for stk600*() programmers. - * stk500v2_private.h: Add new constants used in the STK600. - * term.c: Add AREF channel support. - * usb_libusb.c: Automatically determine the correct write - endpoint ID, the STK600 uses 0x83 while all other tools use - 0x82. Propagate the EP to use through struct filedescriptor. - * usbdevs.h: Add the STK600 USB product ID. - * tools/get-stk600-cards.xsl: XSL transformation for - targetboards.xml to obtain the list of socket and routing - card IDs, to be used in stk500v2.c (for displaying the - names). - * tools/get-stk600-devices.xsl: XSL transformation for - targetboards.xml to obtain the table of socket/routing cards - and their respective AVR device support for doc/avrdude.texi. - * avrdude.1: Document all the STK600 stuff. - * doc/avrdude.texi: Ditto. Added a new chapter for - Programmer Specific Information. + Add initial support for the Atmel STK600, for + "classic" AVRs (AT90, ATtiny, ATmega) in both, + ISP and high-voltage programming modes. + * Makefile.am: Add -lm. + * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. + * config_gram.y: Add support for the stk600* keywords. + * lexer.l: (Ditto.) + * pgm.h: Add the "chan" parameter to set_varef(). + * stk500.c: (Ditto.) + * serial.h: Add USB endpoint support to struct filedescriptor. + * stk500v2.c: Implement the meat of the STK600 support. + * stk500v2.h: Add new prototypes for stk600*() programmers. + * stk500v2_private.h: Add new constants used in the STK600. + * term.c: Add AREF channel support. + * usb_libusb.c: Automatically determine the correct write + endpoint ID, the STK600 uses 0x83 while all other tools use + 0x82. Propagate the EP to use through struct filedescriptor. + * usbdevs.h: Add the STK600 USB product ID. + * tools/get-stk600-cards.xsl: XSL transformation for + targetboards.xml to obtain the list of socket and routing + card IDs, to be used in stk500v2.c (for displaying the + names). + * tools/get-stk600-devices.xsl: XSL transformation for + targetboards.xml to obtain the table of socket/routing cards + and their respective AVR device support for doc/avrdude.texi. + * avrdude.1: Document all the STK600 stuff. + * doc/avrdude.texi: Ditto. Added a new chapter for + Programmer Specific Information. 2008-01-26 Joerg Wunsch - * stk500v2.c (stk500v2_recv): Make length computation unsigned so - it cannot accidentally become negative. + * stk500v2.c (stk500v2_recv): Make length computation unsigned so + it cannot accidentally become negative. diff --git a/src/avrdude/ChangeLog-2009 b/src/avrdude/ChangeLog-2009 index 1f993cbcfe4..941d53bece5 100644 --- a/src/avrdude/ChangeLog-2009 +++ b/src/avrdude/ChangeLog-2009 @@ -1,411 +1,411 @@ 2009-11-09 David Hoerl - * fileio.c: ihex2bin did not properly handle files > 64K bytes - * usb_libusb.c: re-enabled usb_reset for Macs (no reset causes lots of failures) - * avrdude.1: spacing issue for avr32 fixed. + * fileio.c: ihex2bin did not properly handle files > 64K bytes + * usb_libusb.c: re-enabled usb_reset for Macs (no reset causes lots of failures) + * avrdude.1: spacing issue for avr32 fixed. 2009-11-09 Michal Ludvig - * buspirate.c: Implemented reset= and speed= extended parameters. - * avrdude.1: Document the change. + * buspirate.c: Implemented reset= and speed= extended parameters. + * avrdude.1: Document the change. 2009-11-04 Michal Ludvig - * configure.ac, Makefile.am: Test if GCC accepts -Wno-pointer-sign + * configure.ac, Makefile.am: Test if GCC accepts -Wno-pointer-sign 2009-11-04 Michal Ludvig - * buspirate.c: Implemented 'BinMode' support for - firmware 2.7 and higher. - * avrdude.1: Added info about BusPirate. + * buspirate.c: Implemented 'BinMode' support for + firmware 2.7 and higher. + * avrdude.1: Added info about BusPirate. 2009-11-03 Michal Ludvig - * arduino.c: Add on to bug #26703 / patch #6866 - clear DTR/RTS - when closing the port. - * Makefile.am: Silent warnings about signedness - they're useless - and annoying, especially for 'char' vars. + * arduino.c: Add on to bug #26703 / patch #6866 - clear DTR/RTS + when closing the port. + * Makefile.am: Silent warnings about signedness - they're useless + and annoying, especially for 'char' vars. 2009-10-22 David Hoerl - * usb_libusb.c: disabled usb_reset for Macs (same as FreeBSD) + * usb_libusb.c: disabled usb_reset for Macs (same as FreeBSD) 2009-10-12 Michal Ludvig - * main.c: Re-added default to serial port for BusPirate. + * main.c: Re-added default to serial port for BusPirate. 2009-10-12 David Hoerl - * main.c: removed some avr32 code that was pushed into jtagmkII.c - * jtagmkII.c: consolodated the avr32 reset code and avr32_chipreset - * avrpart.h: modified AVRPART flags for avr32 - * lexer.l: added is_avr32 flag - only way to get yacc code to set flag - * avrdude.conf.in: updated avr32 section to include "is_avr32" flag + * main.c: removed some avr32 code that was pushed into jtagmkII.c + * jtagmkII.c: consolodated the avr32 reset code and avr32_chipreset + * avrpart.h: modified AVRPART flags for avr32 + * lexer.l: added is_avr32 flag - only way to get yacc code to set flag + * avrdude.conf.in: updated avr32 section to include "is_avr32" flag 2009-10-12 David Hoerl - * config_gram.y: Restored inadvertantly removed buspirate entry - * lexer.l: Restored inadvertantly removed buspirate entry + * config_gram.y: Restored inadvertantly removed buspirate entry + * lexer.l: Restored inadvertantly removed buspirate entry 2009-10-12 Michal Ludvig - * buspirate.c: Replace GNU-only %as with %s in sscanf call. - * ser_win32.c(ser_set_dtr_rts): Fixed typo in parameter name. - * NEWS: Announce BusPirate. + * buspirate.c: Replace GNU-only %as with %s in sscanf call. + * ser_win32.c(ser_set_dtr_rts): Fixed typo in parameter name. + * NEWS: Announce BusPirate. 2009-10-11 David Hoerl - Support for AVR32 - - * AUTHORS: added myself - * NEWS: announced AVR32 support - * main.c: AVR32 flag tests to avoid several code blocks - * fileio.c: mods to ihex read function to handle address offsets and - size of avr32 - * jtagmkI.c: added cast to printf call to remove warning - * arduino.c: added header file to bring in prototype for usleep() - * config_gram.y: added defines for avr32, new jtag_mkii variant for avr32 - * jtagmkII_private.h: new jtag_mkii message types defined (used by - avr32program) - * jtagmkII.h: extern jtagmkII_avr32_initpgm() addition - * jtagmkII.c: huge amount of code in support of avr32 - * avrpart.h: additional flags to AVRPART for avr32 - * usb_libusb.c: modified verbose test for USB read per-byte messages by - by one, so with verbose=3 you get just full messages, 4 gives you bytes - too - * lexer.l: additions for avr32 + Support for AVR32 + + * AUTHORS: added myself + * NEWS: announced AVR32 support + * main.c: AVR32 flag tests to avoid several code blocks + * fileio.c: mods to ihex read function to handle address offsets and + size of avr32 + * jtagmkI.c: added cast to printf call to remove warning + * arduino.c: added header file to bring in prototype for usleep() + * config_gram.y: added defines for avr32, new jtag_mkii variant for avr32 + * jtagmkII_private.h: new jtag_mkii message types defined (used by + avr32program) + * jtagmkII.h: extern jtagmkII_avr32_initpgm() addition + * jtagmkII.c: huge amount of code in support of avr32 + * avrpart.h: additional flags to AVRPART for avr32 + * usb_libusb.c: modified verbose test for USB read per-byte messages by + by one, so with verbose=3 you get just full messages, 4 gives you bytes + too + * lexer.l: additions for avr32 2009-10-10 Michal Ludvig - Support for Arduino auto-reset: - * serial.h, ser_avrdoper.c, ser_posix.c, ser_win32.c: Added - serial_device.set_dtr_rts implementations. - * arduino.c, stk500.c, stk500.h: Call serial_set_dtr_rts() - to reset Arduino board before program upload. - Inspired by patch #6866, resolves bug #26703 + Support for Arduino auto-reset: + * serial.h, ser_avrdoper.c, ser_posix.c, ser_win32.c: Added + serial_device.set_dtr_rts implementations. + * arduino.c, stk500.c, stk500.h: Call serial_set_dtr_rts() + to reset Arduino board before program upload. + Inspired by patch #6866, resolves bug #26703 2009-10-08 Michal Ludvig - * buspirate.c: Optimised buspirate_cmd() - reading 1kB EEPROM now - takes only 14 sec instead of almost 2 mins with the original - implementation. + * buspirate.c: Optimised buspirate_cmd() - reading 1kB EEPROM now + takes only 14 sec instead of almost 2 mins with the original + implementation. 2009-10-08 Michal Ludvig - * buspirate.c, buspirate.h: Support for the BusPirate programmer - * config_gram.y, avrdude.conf.in, main.c, lexer.l, Makefile.am: - Glue for BusPirate. + * buspirate.c, buspirate.h: Support for the BusPirate programmer + * config_gram.y, avrdude.conf.in, main.c, lexer.l, Makefile.am: + Glue for BusPirate. 2009-08-17 Joerg Wunsch - * usb_libusb.c (usbdev_close): Repair the logic around the - conditional compilation of usb_reset() introduced in r798. + * usb_libusb.c (usbdev_close): Repair the logic around the + conditional compilation of usb_reset() introduced in r798. 2009-07-11 Joerg Wunsch - * configure.ac: We are post-5.8 now. + * configure.ac: We are post-5.8 now. 2009-07-11 Joerg Wunsch - * configure.ac: Prepare for releasing version 5.8 + * configure.ac: Prepare for releasing version 5.8 2009-07-11 Joerg Wunsch - Submitted by Roger Wolff: - bug #26527: bug in unicode conversion - * ser_avrdoper.c (convertUniToAscii): when encountering a UTF-16 - character that cannot be converted to ASCII, increment the UTF-16 - pointer anyway when proceeding. + Submitted by Roger Wolff: + bug #26527: bug in unicode conversion + * ser_avrdoper.c (convertUniToAscii): when encountering a UTF-16 + character that cannot be converted to ASCII, increment the UTF-16 + pointer anyway when proceeding. 2009-07-11 Joerg Wunsch - * jtagmkI.c (jtagmkI_send): Replace %zd format by %u since not all - implementations do understand the C99 formatting options (sigh). - * jtagmkII.c (jtagmkII_send): (Ditto.) - * stk500v2.c (stk500v2_recv): (Ditto.) + * jtagmkI.c (jtagmkI_send): Replace %zd format by %u since not all + implementations do understand the C99 formatting options (sigh). + * jtagmkII.c (jtagmkII_send): (Ditto.) + * stk500v2.c (stk500v2_recv): (Ditto.) 2009-07-11 Joerg Wunsch - bug #26002: HVPP of EEPROM with AVR Dragon and ATmega8 Fails - * avrdude.conf.in (ATmega8): add page size for EEPROM. + bug #26002: HVPP of EEPROM with AVR Dragon and ATmega8 Fails + * avrdude.conf.in (ATmega8): add page size for EEPROM. 2009-07-07 Joerg Wunsch - * stk500v2.c: Fix a serious memory corruption problem resulting - out of the chaining of both, the stk500v2 and the jtagmkII - programmers for some programming hardware (JTAG ICE mkII and AVR - Dragon running in ISP, HVSP or PP mode), where both programmers - have to maintain their private programmer data. + * stk500v2.c: Fix a serious memory corruption problem resulting + out of the chaining of both, the stk500v2 and the jtagmkII + programmers for some programming hardware (JTAG ICE mkII and AVR + Dragon running in ISP, HVSP or PP mode), where both programmers + have to maintain their private programmer data. 2009-07-02 Joerg Wunsch - * configure.ac: Post-release (is pre-release...) + * configure.ac: Post-release (is pre-release...) 2009-07-02 Joerg Wunsch - * configure.ac: Prepare for releasing version 5.7 + * configure.ac: Prepare for releasing version 5.7 2009-07-02 Joerg Wunsch - * main.c: Add my name to the copyright output when being verbose. + * main.c: Add my name to the copyright output when being verbose. 2009-07-02 Joerg Wunsch - Contributed by Shaun Jackman - bug #21798: Fix both XSLT scripts - * tools/get-dw-params.xsl (format-hex): Add the parameter count. - * tools/get-hv-params.xsl (format_cstack): Ditto. + Contributed by Shaun Jackman + bug #21798: Fix both XSLT scripts + * tools/get-dw-params.xsl (format-hex): Add the parameter count. + * tools/get-hv-params.xsl (format_cstack): Ditto. 2009-07-02 Joerg Wunsch - bug #21922: ATmega163 still not working in version 5.5 - * avrdude.conf.in (atmega163): fill in stk500v2 parameters, correct - some flash programming parameters as well. + bug #21922: ATmega163 still not working in version 5.5 + * avrdude.conf.in (atmega163): fill in stk500v2 parameters, correct + some flash programming parameters as well. 2009-07-02 Joerg Wunsch - bug #22206: avrdude: ser_setspeed(): tcsetattr() failed - * ser_posix.c (ser_setspeed): Don't pass TCSAFLUSH to tcsetattr() as - it apparently fails to work on Solaris. After reading the - documentation again, it seems TCSAFLUSH and TCSANOW are indeed - mutually exclusive. + bug #22206: avrdude: ser_setspeed(): tcsetattr() failed + * ser_posix.c (ser_setspeed): Don't pass TCSAFLUSH to tcsetattr() as + it apparently fails to work on Solaris. After reading the + documentation again, it seems TCSAFLUSH and TCSANOW are indeed + mutually exclusive. 2009-07-02 Joerg Wunsch - bug #22234: WINDOWS version: HOWTO: Specify Serial Ports Larger than COM9 - * ser_win32.c (ser_open): prepend \\.\ to any COM port name, so it is - safe to be used for COM ports above 9. + bug #22234: WINDOWS version: HOWTO: Specify Serial Ports Larger than COM9 + * ser_win32.c (ser_open): prepend \\.\ to any COM port name, so it is + safe to be used for COM ports above 9. 2009-07-02 Joerg Wunsch - bug #26408: Crash in stk500v2_open() - * stk500generic.c: Implement setup and teardown hooks, calling in turn - the respective hooks of the stk500v2 implementation. + bug #26408: Crash in stk500v2_open() + * stk500generic.c: Implement setup and teardown hooks, calling in turn + the respective hooks of the stk500v2 implementation. 2009-07-02 Joerg Wunsch - bug #26130: Avrdude doesn't display it's version. - * main.c (usage): add a version number display to the default usage - message. + bug #26130: Avrdude doesn't display it's version. + * main.c (usage): add a version number display to the default usage + message. 2009-07-01 Joerg Wunsch - bug #26412: avrdude segfaults when called with a programmer that does not - support it - * main.c: do not call pgm->perform_osccal() unless it is != 0. + bug #26412: avrdude segfaults when called with a programmer that does not + support it + * main.c: do not call pgm->perform_osccal() unless it is != 0. 2009-06-24 Joerg Wunsch - Contributed by Zoltan Laday: - patch #6825: xmega problems with JTAGICEmkII - * jtagmkII.c: Many fixes for Xmega devices. - * jtagmkII_private.h: Add various new constants required for - Xmega devices. - * avrdude.conf.in: New devices: ATXMEGA64A1, ATXMEGA192A1, - ATXMEGA256A1, ATXMEGA64A3, ATXMEGA128A3, ATXMEGA192A3, - ATXMEGA256A3, ATXMEGA256A3B, ATXMEGA16A4, ATXMEGA32A4, - ATXMEGA64A4, ATXMEGA128A4 - * avr.c (avr_read, avr_write): Add more names for (Xmega) - memory areas that require paged operation. + Contributed by Zoltan Laday: + patch #6825: xmega problems with JTAGICEmkII + * jtagmkII.c: Many fixes for Xmega devices. + * jtagmkII_private.h: Add various new constants required for + Xmega devices. + * avrdude.conf.in: New devices: ATXMEGA64A1, ATXMEGA192A1, + ATXMEGA256A1, ATXMEGA64A3, ATXMEGA128A3, ATXMEGA192A3, + ATXMEGA256A3, ATXMEGA256A3B, ATXMEGA16A4, ATXMEGA32A4, + ATXMEGA64A4, ATXMEGA128A4 + * avr.c (avr_read, avr_write): Add more names for (Xmega) + memory areas that require paged operation. 2009-06-24 Joerg Wunsch - * stk500v2.c (stk600_xprog_write_byte): Handle writing fuse bytes. + * stk500v2.c (stk600_xprog_write_byte): Handle writing fuse bytes. 2009-04-28 Joerg Wunsch - Submitted by Carl Hamilton: - * update.c (parse_op): correctly \0-terminate buf after filling - it, before it is potentially used as the source of a call to - strlen or strcpy. + Submitted by Carl Hamilton: + * update.c (parse_op): correctly \0-terminate buf after filling + it, before it is potentially used as the source of a call to + strlen or strcpy. 2009-04-14 Joerg Wunsch - * doc/avrdude.texi: Merge the -P 0xXXX option description from - avrdude.1. + * doc/avrdude.texi: Merge the -P 0xXXX option description from + avrdude.1. 2009-04-14 Joerg Wunsch - * configure.ac: declare AM_PROG_CC_C_O to avoid the warning - "compiling `config_gram.c' with per-target flags - requires `AM_PROG_CC_C_O' in `configure.ac'" + * configure.ac: declare AM_PROG_CC_C_O to avoid the warning + "compiling `config_gram.c' with per-target flags + requires `AM_PROG_CC_C_O' in `configure.ac'" 2009-03-22 Joerg Wunsch - bug #25971: "error writing to " with multiple -U params. - * fileio.c: Do not close the input/output stream when working on an - stdio stream. + bug #25971: "error writing to " with multiple -U params. + * fileio.c: Do not close the input/output stream when working on an + stdio stream. 2009-02-28 Thomas Fischl - Based on patch #6484 commited by Jurgis Brigmanis: - * usbasp.c: added software control for ISP speed - * usbasp.h: (Ditto.) + Based on patch #6484 commited by Jurgis Brigmanis: + * usbasp.c: added software control for ISP speed + * usbasp.h: (Ditto.) 2009-02-28 Joerg Wunsch - * avr910.c (avr910_read_byte_flash): Eliminate a static variable that - hasn't been in use for 5 years. + * avr910.c (avr910_read_byte_flash): Eliminate a static variable that + hasn't been in use for 5 years. 2009-02-27 Joerg Wunsch - * configure.ac: Post-release 5.6. + * configure.ac: Post-release 5.6. 2009-02-27 Joerg Wunsch - * configure.ac: Prepare for releasing version 5.6. + * configure.ac: Prepare for releasing version 5.6. 2009-02-27 Joerg Wunsch - Submitted by Ed Okerson: - * jtagmkII.c (jtagmkII_read_byte): Fix signature reading of - Xmega. + Submitted by Ed Okerson: + * jtagmkII.c (jtagmkII_read_byte): Fix signature reading of + Xmega. 2009-02-26 Joerg Wunsch - Submitted by Mikael Hermansson: - * avrdude.conf.in (ATxmega256A3): new device. - * stk500v2 (stk500v2_initialize): Enable the AVRISPmkII as a - PDI-capable device for ATxmega parts. + Submitted by Mikael Hermansson: + * avrdude.conf.in (ATxmega256A3): new device. + * stk500v2 (stk500v2_initialize): Enable the AVRISPmkII as a + PDI-capable device for ATxmega parts. 2009-02-25 Joerg Wunsch - Submitted by Lars Immisch: - patch #6750: Arduino support - new programmer-id - * arduino.c: New file, inherits stk500.c. - * arduino.h: New file. - * Makefile.am: Add arduino.c and arduino.h. - * config_gram.y: Add arduino keyword. - * lexer.l: (Ditto.) - * avrdude.conf.in: (Ditto.) - * avrdude.1: Document the new programmer type. - * doc/avrdude.texi: (Ditto.) + Submitted by Lars Immisch: + patch #6750: Arduino support - new programmer-id + * arduino.c: New file, inherits stk500.c. + * arduino.h: New file. + * Makefile.am: Add arduino.c and arduino.h. + * config_gram.y: Add arduino keyword. + * lexer.l: (Ditto.) + * avrdude.conf.in: (Ditto.) + * avrdude.1: Document the new programmer type. + * doc/avrdude.texi: (Ditto.) 2009-02-25 Joerg Wunsch - * stk500v2.c: Turn all non-const static data into instance data. + * stk500v2.c: Turn all non-const static data into instance data. 2009-02-25 Joerg Wunsch - * Makefile.am: Move term.[ch] from the library into the CLI - application section, as it is not useful for anything else but - the CLI frontend. + * Makefile.am: Move term.[ch] from the library into the CLI + application section, as it is not useful for anything else but + the CLI frontend. 2009-02-25 Joerg Wunsch - * avrdude.conf.in (ATmega1284P): new device. + * avrdude.conf.in (ATmega1284P): new device. 2009-02-23 Joerg Wunsch - More fixes for Solaris, including fixes for the Sunpro compiler: - * avr.h: Remove stray semicolon. - * configure.ac: Add check for predefined types uint_t and ulong_t. - * confwin.c: Include "avrdude.h" on top to avoid empty translation - unit warning. - * ppwin.c: (Ditto.) - * ser_win32.c: (Ditto.) - * serbb_win32.c: (Ditto.) - * jtagmkII.c (jtagmkII_recv): remove unreachable "return". - * stk500.c (stk500_initialize): (Ditto.) - * par.c: Test for both, __sun__ and __sun to see whether we are - being compiled on Solaris. - * ppi.c: (Ditto.) - * stk500v2.c: Implement the DEBUG and DEBUGRECV macros in a way - that is compatible with the ISO C99 standard. - * usbtiny.c: Only typedef uint_t and ulong_t if they have not - been found already by the autoconf checks. + More fixes for Solaris, including fixes for the Sunpro compiler: + * avr.h: Remove stray semicolon. + * configure.ac: Add check for predefined types uint_t and ulong_t. + * confwin.c: Include "avrdude.h" on top to avoid empty translation + unit warning. + * ppwin.c: (Ditto.) + * ser_win32.c: (Ditto.) + * serbb_win32.c: (Ditto.) + * jtagmkII.c (jtagmkII_recv): remove unreachable "return". + * stk500.c (stk500_initialize): (Ditto.) + * par.c: Test for both, __sun__ and __sun to see whether we are + being compiled on Solaris. + * ppi.c: (Ditto.) + * stk500v2.c: Implement the DEBUG and DEBUGRECV macros in a way + that is compatible with the ISO C99 standard. + * usbtiny.c: Only typedef uint_t and ulong_t if they have not + been found already by the autoconf checks. 2009-02-23 Joerg Wunsch - bug #22204: Solaris10/11 Undefiniertes Symbol gethostbyname socket - connect - * configure.ac: Add checks for gethostent() and socket(). - While being here, remove some old cruft left from ancient days. + bug #22204: Solaris10/11 Undefiniertes Symbol gethostbyname socket + connect + * configure.ac: Add checks for gethostent() and socket(). + While being here, remove some old cruft left from ancient days. 2009-02-22 Joerg Wunsch - * lexer.l: Bump the %p size so AT&T lex will continue to work. + * lexer.l: Bump the %p size so AT&T lex will continue to work. 2009-02-19 Joerg Wunsch - (Partially) submitted by John Voltz: - bug #20004: AVRDUDE update (-U) operations do not close files - * fileio.c (fmt_autodetect, fileio): fclose() files. + (Partially) submitted by John Voltz: + bug #20004: AVRDUDE update (-U) operations do not close files + * fileio.c (fmt_autodetect, fileio): fclose() files. 2009-02-18 Joerg Wunsch - * usbtiny.c: Replace all but one (very unlikely to trigger) exit(1) - by return -1. + * usbtiny.c: Replace all but one (very unlikely to trigger) exit(1) + by return -1. 2009-02-18 Joerg Wunsch - Submitted by Dick Streefland: - patch #6749: make reading from the USBtinyISP programmer more robust - * usbtiny.c: Add code to retry failed communication attempts. + Submitted by Dick Streefland: + patch #6749: make reading from the USBtinyISP programmer more robust + * usbtiny.c: Add code to retry failed communication attempts. 2009-02-17 Joerg Wunsch - Submitted by Nick Hibma: - bug #22271: usb_reset in usb_libusb.c not necessary in FreeBSD 6.x - * usb_libusb.c (usbdev_close): Do not call usb_reset() on FreeBSD. - It is not necessary there. + Submitted by Nick Hibma: + bug #22271: usb_reset in usb_libusb.c not necessary in FreeBSD 6.x + * usb_libusb.c (usbdev_close): Do not call usb_reset() on FreeBSD. + It is not necessary there. 2009-02-17 Joerg Wunsch - Submitted by Andrew O. Shadoura: - bug #25156: add direct SPI transfer mode - * bitbang.c: Implement direct SPI transfers. - * bitbang.h: (Ditto.) - * par.c: (Ditto.) - * pgm.c: (Ditto.) - * pgm.h: (Ditto.) - * term.c: Add the "spi" and "pgm" commands. - * avrdude.1: Document the changes. - * doc/avrdude.texi: (Ditto.) + Submitted by Andrew O. Shadoura: + bug #25156: add direct SPI transfer mode + * bitbang.c: Implement direct SPI transfers. + * bitbang.h: (Ditto.) + * par.c: (Ditto.) + * pgm.c: (Ditto.) + * pgm.h: (Ditto.) + * term.c: Add the "spi" and "pgm" commands. + * avrdude.1: Document the changes. + * doc/avrdude.texi: (Ditto.) 2009-02-17 Joerg Wunsch - Submitted by Limor ("Lady Ada"): - bug #24749: add support for '328p - * avrdude.conf.in (ATmega328P): new device support. + Submitted by Limor ("Lady Ada"): + bug #24749: add support for '328p + * avrdude.conf.in (ATmega328P): new device support. 2009-02-17 Joerg Wunsch - Submitted by "Womo": - bug #25241: AT90USB162, AT90USB82 device support patch for avrdude-5.5 - (also: bug #21745: AT90USBxx2 support) - * avrdude.conf.in (AT90USB162, AT90USB82): new device support. + Submitted by "Womo": + bug #25241: AT90USB162, AT90USB82 device support patch for avrdude-5.5 + (also: bug #21745: AT90USBxx2 support) + * avrdude.conf.in (AT90USB162, AT90USB82): new device support. 2009-02-17 Joerg Wunsch - Submitted by Evangelos Arkalis: - patch #6069: Atmel AT89ISP Cable - * avrdude.conf.in (89isp): new programmer support. + Submitted by Evangelos Arkalis: + patch #6069: Atmel AT89ISP Cable + * avrdude.conf.in (89isp): new programmer support. 2009-02-16 Joerg Wunsch - Submitted by Bob Paddock: - patch #6748: ATTiny88 Config - * avrdude.conf.in (ATtiny88): new device support. + Submitted by Bob Paddock: + patch #6748: ATTiny88 Config + * avrdude.conf.in (ATtiny88): new device support. 2009-02-16 Joerg Wunsch - Submitted by Mark Litwack: - patch #6261: avrdude won't use dragon/debugwire to write a file - to eeprom - * jtagmkII.c (jtagmkII_paged_write): when in debugWire mode, - implement a paged write to EEPROM as a series of byte writes. + Submitted by Mark Litwack: + patch #6261: avrdude won't use dragon/debugwire to write a file + to eeprom + * jtagmkII.c (jtagmkII_paged_write): when in debugWire mode, + implement a paged write to EEPROM as a series of byte writes. 2009-02-16 Joerg Wunsch - Submitted by Janos Sallai: - patch #6542: paged_load fails on the MIB510 programming board - * stk500.c: Add a workaround for the different signon sequence on - MIB510 programmers. + Submitted by Janos Sallai: + patch #6542: paged_load fails on the MIB510 programming board + * stk500.c: Add a workaround for the different signon sequence on + MIB510 programmers. 2009-02-05 Joerg Wunsch - * avrdude.conf.in: Add the ATmega128RFA1. - * avrdude.1: document the addition of ATmega128RFA1. - * doc/avrdude.texi: (Ditto.) + * avrdude.conf.in: Add the ATmega128RFA1. + * avrdude.1: document the addition of ATmega128RFA1. + * doc/avrdude.texi: (Ditto.) diff --git a/src/avrdude/ChangeLog-2010 b/src/avrdude/ChangeLog-2010 index 45effefa46a..e7a4a114b6a 100644 --- a/src/avrdude/ChangeLog-2010 +++ b/src/avrdude/ChangeLog-2010 @@ -1,354 +1,354 @@ 2010-12-17 Joerg Wunsch - * avrdude.conf.in (ATmega128RFA1): Bump two timing values in order to - improve ISP programming stability, in particular with the STK600. + * avrdude.conf.in (ATmega128RFA1): Bump two timing values in order to + improve ISP programming stability, in particular with the STK600. 2010-12-14 Joerg Wunsch - * stk500v2.c (stk500v2_command): Detect warning status codes. + * stk500v2.c (stk500v2_command): Detect warning status codes. 2010-10-22 Nils Springob - * serial.h: serial_open() calls will now return -1 on error (no call to exit()) - * buspirate.c: (Dito.) - * jtagmkII.c: (Dito.) - * butterfly.c: (Dito.) - * jtagmkI.c: (Dito.) - * arduino.c: (Dito.) - * avr910.c: (Dito.) - * stk500.c: (Dito.) - * ser_avrdoper.c: (Dito.) - * stk500v2.c: (Dito.) - * ser_posix.c: (Dito.) - * usb_libusb.c: (Dito.) + * serial.h: serial_open() calls will now return -1 on error (no call to exit()) + * buspirate.c: (Dito.) + * jtagmkII.c: (Dito.) + * butterfly.c: (Dito.) + * jtagmkI.c: (Dito.) + * arduino.c: (Dito.) + * avr910.c: (Dito.) + * stk500.c: (Dito.) + * ser_avrdoper.c: (Dito.) + * stk500v2.c: (Dito.) + * ser_posix.c: (Dito.) + * usb_libusb.c: (Dito.) 2010-07-27 Joerg Wunsch - bug #30566: MinGW + Ubuntu 9.04 - * stk500v2.c (stk500v2_open): use same condition to refer to the AVR - Doper support as used in the definition in ser_avrdoper.c. - (Thanks to Christian Starkjohann for the analysis of the problem.) + bug #30566: MinGW + Ubuntu 9.04 + * stk500v2.c (stk500v2_open): use same condition to refer to the AVR + Doper support as used in the definition in ser_avrdoper.c. + (Thanks to Christian Starkjohann for the analysis of the problem.) 2010-07-19 Michal Ludvig - * buspirate.c: Added compatibility with BusPirate "NewUI" firmware 5.x - (contributed by Kari Knuuttila) + * buspirate.c: Added compatibility with BusPirate "NewUI" firmware 5.x + (contributed by Kari Knuuttila) 2010-07-12 Nils Springob - * avrdude.conf.in (atmega88p): New device. + * avrdude.conf.in (atmega88p): New device. 2010-06-03 Joerg Wunsch - bug #29913: 246 Byte Bug - AVRdude crashes - doc/avrdude.texi (Troubleshooting): Mention the libusb 0.1 API - wrapper issue that is present in some Linux versions. + bug #29913: 246 Byte Bug - AVRdude crashes + doc/avrdude.texi (Troubleshooting): Mention the libusb 0.1 API + wrapper issue that is present in some Linux versions. 2010-03-19 Joerg Wunsch - bug #29263: Can't build avrdude on windows using latest cygwin 1.7.1 - * doc/avrdude.texi: Remove the recommendation for building - Win32 binaries under Cygwin; mention MinGW as an alternative - environment. + bug #29263: Can't build avrdude on windows using latest cygwin 1.7.1 + * doc/avrdude.texi: Remove the recommendation for building + Win32 binaries under Cygwin; mention MinGW as an alternative + environment. 2010-03-08 Michal Ludvig - * ser_posix.c(ser_set_dtr_rts): Fixed DTR on/off to make - Arduino auto-reset work. (bug #29108, patch #7100) + * ser_posix.c(ser_set_dtr_rts): Fixed DTR on/off to make + Arduino auto-reset work. (bug #29108, patch #7100) 2010-03-05 Joerg Wunsch - * buspirate.c: Replace printf() by fprintf(stderr) - * safemode.c: (Dito.) - * usbtiny.c: (Dito.) + * buspirate.c: Replace printf() by fprintf(stderr) + * safemode.c: (Dito.) + * usbtiny.c: (Dito.) 2010-01-22 Joerg Wunsch - Cleanup Cygwin builds. - * windows/Makefile.am (loaddrv_LDFLAGS): remove, the -mno-cygwin - flag is supposed to be set in CFLAGS by ./configure - * configure.ac: add a check for the presence of usleep(), add a - check whether the linker accepts -static - * avrdude.h: protect prototype for usleep by !defined(HAVE_USLEEP) - * ppwin.c (usleep): protect by !defined(HAVE_USLEEP) - * main.c: silence "array subscript of type char" compiler warnings - by casting all arguments to tolower()/toupper() and isspace()/ - isdigit()/ispunct() to "int" - * butterfly.c: (Dito.) - * avr910.c: (Dito.) + Cleanup Cygwin builds. + * windows/Makefile.am (loaddrv_LDFLAGS): remove, the -mno-cygwin + flag is supposed to be set in CFLAGS by ./configure + * configure.ac: add a check for the presence of usleep(), add a + check whether the linker accepts -static + * avrdude.h: protect prototype for usleep by !defined(HAVE_USLEEP) + * ppwin.c (usleep): protect by !defined(HAVE_USLEEP) + * main.c: silence "array subscript of type char" compiler warnings + by casting all arguments to tolower()/toupper() and isspace()/ + isdigit()/ispunct() to "int" + * butterfly.c: (Dito.) + * avr910.c: (Dito.) 2010-01-19 Joerg Wunsch - * configure.ac: Bump for post-5.10. + * configure.ac: Bump for post-5.10. 2010-01-19 Joerg Wunsch - * configure.ac: Released version 5.10. + * configure.ac: Released version 5.10. 2010-01-19 Joerg Wunsch - bug #28677: Cygwin's GCC no longer supports -mno-cygwin option - * configure.ac: For Win32 environments, add a check whether the - compiler understands the -mno-cygwin option. If not, don't use - it but suggest using a different compiler. + bug #28677: Cygwin's GCC no longer supports -mno-cygwin option + * configure.ac: For Win32 environments, add a check whether the + compiler understands the -mno-cygwin option. If not, don't use + it but suggest using a different compiler. 2010-01-18 David Hoerl - bug #28660: Problem with loading intel hex rom files that exceed - 0x10000 bytes - * fileio.c: Fix two byte shifts. + bug #28660: Problem with loading intel hex rom files that exceed + 0x10000 bytes + * fileio.c: Fix two byte shifts. 2010-01-15 Joerg Wunsch - Submitted by Michael biebl: - * configure.ac: Fix FreeBSD default serial port name. - * doc/avrdude.texi: (Dito.) + Submitted by Michael biebl: + * configure.ac: Fix FreeBSD default serial port name. + * doc/avrdude.texi: (Dito.) 2010-01-15 Joerg Wunsch - * jtagmkII.c: If entering JTAG mode fails with a bad JTAG ID - message, retry with external reset applied (in case the target - is in sleep mode or has asserted the JTD bit). + * jtagmkII.c: If entering JTAG mode fails with a bad JTAG ID + message, retry with external reset applied (in case the target + is in sleep mode or has asserted the JTD bit). 2010-01-15 Joerg Wunsch - Submitted by Aurelien Jarno: - * configure.ac: Fix build for GNU/kFreeBSD. - * ppi.c: (Dito.) - * par.c: (Dito.) + Submitted by Aurelien Jarno: + * configure.ac: Fix build for GNU/kFreeBSD. + * ppi.c: (Dito.) + * par.c: (Dito.) 2010-01-15 Joerg Wunsch - * configure.ac: Bump version for post-5.8. + * configure.ac: Bump version for post-5.8. 2010-01-15 Joerg Wunsch - * configure.ac: Bump version for release 5.8. + * configure.ac: Bump version for release 5.8. 2010-01-15 Joerg Wunsch - Submitted by Soren Jorvang: - bug #28611: -i delay not being applied to all serial port - bit banging state transitions - * serbb_win32.c: Apply ispdelay everywhere. - * serbb_posix.c: (Dito.) + Submitted by Soren Jorvang: + bug #28611: -i delay not being applied to all serial port + bit banging state transitions + * serbb_win32.c: Apply ispdelay everywhere. + * serbb_posix.c: (Dito.) 2010-01-15 Joerg Wunsch - * stk500v2_private.h: Implement TPI mode for AVRISPmkII/STK600 - * config_gram.y: (Dito.) - * avrpart.h: (Dito.) - * stk500v2.c: (Dito.) - * main.c: (Dito.) - * lexer.l: (Dito.) - * avrdude.conf.in: Add ATtiny4/5/9/10 - * avrdude.1: Document TPI and new device support. - * doc/avrdude.texi: (Dito.) + * stk500v2_private.h: Implement TPI mode for AVRISPmkII/STK600 + * config_gram.y: (Dito.) + * avrpart.h: (Dito.) + * stk500v2.c: (Dito.) + * main.c: (Dito.) + * lexer.l: (Dito.) + * avrdude.conf.in: Add ATtiny4/5/9/10 + * avrdude.1: Document TPI and new device support. + * doc/avrdude.texi: (Dito.) 2010-01-14 Joerg Wunsch - Submitted by clint fisher: - patch #7038: Adding Atmega32U4 Device to avrdude.conf.in - * avrdude.conf.in (atmega32u4): New device. - * avrdude.1: Document the new device support. - * doc/avrdude.texi: (Dito.) + Submitted by clint fisher: + patch #7038: Adding Atmega32U4 Device to avrdude.conf.in + * avrdude.conf.in (atmega32u4): New device. + * avrdude.1: Document the new device support. + * doc/avrdude.texi: (Dito.) 2010-01-14 Joerg Wunsch - Submitted by Thomas Pircher: - patch #6927: Documentation patches - * doc/avrdude.texi: Fix various typos, and remove the last - remnants of obsoleted options -i/-o/-m/-f. - * avrdude.1: Merge typo fixes from avrdude.texi where - applicable. + Submitted by Thomas Pircher: + patch #6927: Documentation patches + * doc/avrdude.texi: Fix various typos, and remove the last + remnants of obsoleted options -i/-o/-m/-f. + * avrdude.1: Merge typo fixes from avrdude.texi where + applicable. 2010-01-14 Joerg Wunsch - * avrdude.1: Update documentation to match the reality (device - support, memory areas). - * doc/avrdude.texi: Update documentation to match the - reality (device support, programmer support, memory areas). - Merge buspirate-specific comments from avrdude.1. - * jtagmkII.c: Add some firmware feature checks. + * avrdude.1: Update documentation to match the reality (device + support, memory areas). + * doc/avrdude.texi: Update documentation to match the + reality (device support, programmer support, memory areas). + Merge buspirate-specific comments from avrdude.1. + * jtagmkII.c: Add some firmware feature checks. 2010-01-13 Joerg Wunsch - * jtagmkII.c: Implement PDI mode support for the JTAG ICE mkII - and the AVR Dragon. - * jtagmkII.h: (Dito.) - * config_gram.y: (Dito.) - * jtagmkII_private.h: (Dito.) - * avrdude.conf.in: (Dito.) - * lexer.l: (Dito.) + * jtagmkII.c: Implement PDI mode support for the JTAG ICE mkII + and the AVR Dragon. + * jtagmkII.h: (Dito.) + * config_gram.y: (Dito.) + * jtagmkII_private.h: (Dito.) + * avrdude.conf.in: (Dito.) + * lexer.l: (Dito.) 2010-01-13 Joerg Wunsch - * stk500v2.c: Update STK600 routing and socket card data from XML - file. + * stk500v2.c: Update STK600 routing and socket card data from XML + file. 2010-01-13 Joerg Wunsch - * stk500v2.c: Cleanup the open/close handling to avoid accessing - unallocated memory (in the atexit handler) in case of bailing out. - * main.c: (Ditto.) + * stk500v2.c: Cleanup the open/close handling to avoid accessing + unallocated memory (in the atexit handler) in case of bailing out. + * main.c: (Ditto.) 2010-01-13 Joerg Wunsch - * jtagmkII.c: Stylistic changes: move #defines out into - jtagmkII_private.h, drop all #if 0 blocks, fold overly long lines, - move the *_initpgm() functions to the end of the file; while being - here, remove all trailing whitespace. - * jtagmkII_private.h: move AVR32 #defines here. + * jtagmkII.c: Stylistic changes: move #defines out into + jtagmkII_private.h, drop all #if 0 blocks, fold overly long lines, + move the *_initpgm() functions to the end of the file; while being + here, remove all trailing whitespace. + * jtagmkII_private.h: move AVR32 #defines here. 2010-01-12 Joerg Wunsch - * bootstrap: autoconf 2.62 works well. + * bootstrap: autoconf 2.62 works well. 2010-01-12 Joerg Wunsch - Various fixes for Xmega devices. - * avrdude.conf.in: Correctly declare EEPROM page sizes for - all Xmega devices (0x20 instead of 0x100). - * avr.c: If a memory region has a page size declared, try - using the paged IO routines regardless of the target memory - name. Xmega EEPROM requires to be written in paged mode. - Correctly use a long (rather than unsigned long) variable to - evaluate the success status of the paged mode write attempt. - * stk500v2.c: Don't apply TIF space offsets twice (bug #27995: - AVRDUDE 5.8svn fails to program and read XMEGA); use - stk500v2_loadaddr() prior to paged mode (EEPROM and flash) writes, - otherwise programming of flash areas will fail; while being there, - check the return value of stk500v2_loadaddr() everywhere; use the - correct write/erase mode bits (same as AVR Studio does). + Various fixes for Xmega devices. + * avrdude.conf.in: Correctly declare EEPROM page sizes for + all Xmega devices (0x20 instead of 0x100). + * avr.c: If a memory region has a page size declared, try + using the paged IO routines regardless of the target memory + name. Xmega EEPROM requires to be written in paged mode. + Correctly use a long (rather than unsigned long) variable to + evaluate the success status of the paged mode write attempt. + * stk500v2.c: Don't apply TIF space offsets twice (bug #27995: + AVRDUDE 5.8svn fails to program and read XMEGA); use + stk500v2_loadaddr() prior to paged mode (EEPROM and flash) writes, + otherwise programming of flash areas will fail; while being there, + check the return value of stk500v2_loadaddr() everywhere; use the + correct write/erase mode bits (same as AVR Studio does). 2010-01-12 Michal Ludvig - * buspirate.c: Initialise firmware version to v0.0 - prior to parsing the buspirate banner. + * buspirate.c: Initialise firmware version to v0.0 + prior to parsing the buspirate banner. 2010-01-11 Joerg Wunsch - Clean-up the Xmega erase functions. - * jtagmkII_private.h: Add CMND_XMEGA_ERASE as well as - the various XMEGA_ERASE_* definitions (from updated - appnote AVR067) - * jtagmkII.c (jtagmkII_chip_erase): Correctly implement Xmega chip - erase based on CMND_XMEGA_ERASE. After erasing an Xmega part, do - *not* reinitialize the world, as a subsequent programming - operation will fail (for unknown reasons). Actually, this was - really only required for ancient AVRs, but doesn't hurt on mega - and tiny devices. - * jtagmkII.c (jtagmkII_pre_write): Remove, this turned out - to be just a chip erase. - * jtagmkII.c (jtagmkII_program_disable): Don't try reading - "hfuse" for Xmega parts; they don't have it. - * main.c (main): Re-enable auto-erase. It's been done - before (as "jtagmkII_pre_write") in jtagmkII_paged_write() - anyway. Xmega boot and application flash areas should be - handled separately in the future, so auto_erase can only - affect the area just being programmed. + Clean-up the Xmega erase functions. + * jtagmkII_private.h: Add CMND_XMEGA_ERASE as well as + the various XMEGA_ERASE_* definitions (from updated + appnote AVR067) + * jtagmkII.c (jtagmkII_chip_erase): Correctly implement Xmega chip + erase based on CMND_XMEGA_ERASE. After erasing an Xmega part, do + *not* reinitialize the world, as a subsequent programming + operation will fail (for unknown reasons). Actually, this was + really only required for ancient AVRs, but doesn't hurt on mega + and tiny devices. + * jtagmkII.c (jtagmkII_pre_write): Remove, this turned out + to be just a chip erase. + * jtagmkII.c (jtagmkII_program_disable): Don't try reading + "hfuse" for Xmega parts; they don't have it. + * main.c (main): Re-enable auto-erase. It's been done + before (as "jtagmkII_pre_write") in jtagmkII_paged_write() + anyway. Xmega boot and application flash areas should be + handled separately in the future, so auto_erase can only + affect the area just being programmed. 2010-01-11 Joerg Wunsch - * main.c (main): disable safemode for Xmega parts. + * main.c (main): disable safemode for Xmega parts. 2010-01-12 Michal Ludvig - * buspirate.c: If the BusPirate doesn't respond - to a standard a reset command assume it was in binmode - and attempt to exit to text mode first. + * buspirate.c: If the BusPirate doesn't respond + to a standard a reset command assume it was in binmode + and attempt to exit to text mode first. 2010-01-08 Joerg Wunsch - * bitbang.c: Fix Win32 build error: move freq up to the file - level. - * buspirate.c: Fix Win32 build warning: include to - to get a declaration for alloca(). + * bitbang.c: Fix Win32 build error: move freq up to the file + level. + * buspirate.c: Fix Win32 build warning: include to + to get a declaration for alloca(). 2010-01-08 Thomas Fischl - bug #28520: Programming with USBasp with low clock speed fails - * usbasp.c: Change blocksize depending on sck frequency to - avoid usb transmition timeouts. + bug #28520: Programming with USBasp with low clock speed fails + * usbasp.c: Change blocksize depending on sck frequency to + avoid usb transmition timeouts. 2010-01-08 Joerg Wunsch - bug #27505: serbb_posix does not cope with inverted pins - * serbb_posix (serbb_highpulsepin): apply PIN_MASK when - checking pin numbers. - * serbb_win32 (serbb_highpulsepin): (Dito.) + bug #27505: serbb_posix does not cope with inverted pins + * serbb_posix (serbb_highpulsepin): apply PIN_MASK when + checking pin numbers. + * serbb_win32 (serbb_highpulsepin): (Dito.) 2010-01-08 Joerg Wunsch - bug #28516: Linux/Dragon: Error message on exit - * stk500v2.c: Fix the "bad response to GO command: - RSP_ILLEGAL_EMULATOR_MODE" message. jtagmkII_close() - has been called with the wrong pgm->cookie. Wrap it - inside stk500v2_jtagmkII_close(), adjusting the cookie - data appropriately. + bug #28516: Linux/Dragon: Error message on exit + * stk500v2.c: Fix the "bad response to GO command: + RSP_ILLEGAL_EMULATOR_MODE" message. jtagmkII_close() + has been called with the wrong pgm->cookie. Wrap it + inside stk500v2_jtagmkII_close(), adjusting the cookie + data appropriately. 2010-01-08 Joerg Wunsch - Submitted by Doug: - patch #7010: Win32 enhanced bitbang_delay - * bitbang.c (bitbang_calibrate_delay, bitbang_delay): On Win32, - use the high-resolution performance counter rather than the - uneducated delay loop guess if it is available on the target - hardware. + Submitted by Doug: + patch #7010: Win32 enhanced bitbang_delay + * bitbang.c (bitbang_calibrate_delay, bitbang_delay): On Win32, + use the high-resolution performance counter rather than the + uneducated delay loop guess if it is available on the target + hardware. 2010-01-08 Joerg Wunsch - Submitted by Gerard: - patch #6828: Using arbitrary BAUD rates - * ser_posix.c (serial_baud_lookup): Allow non-standard baud - rates. - * ser_win32.c (serial_baud_lookup): (Dito.) + Submitted by Gerard: + patch #6828: Using arbitrary BAUD rates + * ser_posix.c (serial_baud_lookup): Allow non-standard baud + rates. + * ser_win32.c (serial_baud_lookup): (Dito.) 2010-01-07 Joerg Wunsch - Submitted by Eric Trein: - bug #27596: AT90s2333 is not correctly supported in avrdude.conf - * avrdude.conf.in (at90s2333): add various STK500v2 parameters. + Submitted by Eric Trein: + bug #27596: AT90s2333 is not correctly supported in avrdude.conf + * avrdude.conf.in (at90s2333): add various STK500v2 parameters. 2010-01-07 Joerg Wunsch - Submitted by Gyorgy Szekely: - bug #28458: Buffer line is incorrectly released for PP programmers - * par.c (par_close): use par_setmany() rather than par_setpin() - for PPI_AVR_BUFF. + Submitted by Gyorgy Szekely: + bug #28458: Buffer line is incorrectly released for PP programmers + * par.c (par_close): use par_setmany() rather than par_setpin() + for PPI_AVR_BUFF. 2010-01-07 Joerg Wunsch - Submitted by Lukasz Goralczyk: - bug #27507: SIGSEGV when using avrdragon (avrdude 5.8) - * stk500v2.c (stk500v2_dragon_isp_initpgm): Use - stk500v2_jtagmkII_setup/stk500v2_jtagmkII_rather than their - jtagII counterparts, to get the private data properly - initialized. + Submitted by Lukasz Goralczyk: + bug #27507: SIGSEGV when using avrdragon (avrdude 5.8) + * stk500v2.c (stk500v2_dragon_isp_initpgm): Use + stk500v2_jtagmkII_setup/stk500v2_jtagmkII_rather than their + jtagII counterparts, to get the private data properly + initialized. 2010-01-07 Joerg Wunsch - * buspirate.c: Cosmetics: remove UTF-8 dashes, adjust for 8-column - hard tabs. + * buspirate.c: Cosmetics: remove UTF-8 dashes, adjust for 8-column + hard tabs. 2010-01-07 Joerg Wunsch - * buspirate.c: add $ Id $ line. - * buspirate.h: add $ Id $ line. + * buspirate.c: add $ Id $ line. + * buspirate.h: add $ Id $ line. 2010-01-07 Joerg Wunsch - Fix a few warnings that came up recently (some of them only triggered - by recent GCC versions). - * config_gram.y (parse_cmdbits): "brkt possibly used uninitialized" - (GCC errs here) - * jtagmkII.c (jtagmkII_reset32): "status possibly used uninitialized" - (I think GCC errs, too) - * buspirate.c: "pointers differ in signedness" (mismatch between - string processing and the use of "unsigned char" throughought the - AVRDUDE API) + Fix a few warnings that came up recently (some of them only triggered + by recent GCC versions). + * config_gram.y (parse_cmdbits): "brkt possibly used uninitialized" + (GCC errs here) + * jtagmkII.c (jtagmkII_reset32): "status possibly used uninitialized" + (I think GCC errs, too) + * buspirate.c: "pointers differ in signedness" (mismatch between + string processing and the use of "unsigned char" throughought the + AVRDUDE API) 2010-01-01 Joerg Wunsch - * jtagmkII.c (jtagmkII_smc_init32): replace sleep() by usleep() for - win32 compatibility. + * jtagmkII.c (jtagmkII_smc_init32): replace sleep() by usleep() for + win32 compatibility. diff --git a/src/avrdude/ChangeLog-2011 b/src/avrdude/ChangeLog-2011 index d8fffba0134..bef8a30a8a4 100644 --- a/src/avrdude/ChangeLog-2011 +++ b/src/avrdude/ChangeLog-2011 @@ -1,489 +1,489 @@ 2011-12-30 Rene Liebscher - * avrdude.conf.in: Added is_at90s1200 option to part description - * doc/avrdude.texi: Added missing options to part definition - * config_gram.y: Fixed resetting of is_at90s1200 and is_avr32 flags + * avrdude.conf.in: Added is_at90s1200 option to part description + * doc/avrdude.texi: Added missing options to part definition + * config_gram.y: Fixed resetting of is_at90s1200 and is_avr32 flags 2011-12-30 Rene Liebscher - patch #7693: Fix config file atmel URLs - * avrdude.conf.in: Updated URLs - * avrpart.h: Updated URLs - * doc/avrdude.texi: Updated URLs + patch #7693: Fix config file atmel URLs + * avrdude.conf.in: Updated URLs + * avrpart.h: Updated URLs + * doc/avrdude.texi: Updated URLs 2011-12-30 Joerg Wunsch - * ser_posix.c (baud_lookup_table): Conditionalize the inclusion of - non-standard baud rates (only baud rates up to B38400 are - standardized by the Single UNIX Specification). + * ser_posix.c (baud_lookup_table): Conditionalize the inclusion of + non-standard baud rates (only baud rates up to B38400 are + standardized by the Single UNIX Specification). 2011-12-29 Rene Liebscher - bug #34302: Feature request : device configuration with parent classes - * config_gram.y: Added part parent rule and allow overwriting existing - data at several places - * avrdude.conf.in: Added description comment and m328/m328p as example - * avrpart.c: avr_dup_mem-functions now copy buf and tags memory block - only they are already allocated. - * lexer.l: Added parent as valid token - - (not in original patch) - * avrpart.c: New function avr_dup_opcode. avr_dup_mem/avr_dup_part- - functions now duplicate the opcodes in their op-array to avoid memory leaks. - * doc/avrdude.texi: Added description of part parent feature + bug #34302: Feature request : device configuration with parent classes + * config_gram.y: Added part parent rule and allow overwriting existing + data at several places + * avrdude.conf.in: Added description comment and m328/m328p as example + * avrpart.c: avr_dup_mem-functions now copy buf and tags memory block + only they are already allocated. + * lexer.l: Added parent as valid token + + (not in original patch) + * avrpart.c: New function avr_dup_opcode. avr_dup_mem/avr_dup_part- + functions now duplicate the opcodes in their op-array to avoid memory leaks. + * doc/avrdude.texi: Added description of part parent feature 2011-12-29 Rene Liebscher - patch #7687: Autogenerating programmers and parts lists for docs - (generating the parts lists, programmers lists follows later) - * doc/Makefile.am: Add rule how to create avrdude before generating parts list + patch #7687: Autogenerating programmers and parts lists for docs + (generating the parts lists, programmers lists follows later) + * doc/Makefile.am: Add rule how to create avrdude before generating parts list 2011-12-29 Rene Liebscher - patch #7687: Autogenerating programmers and parts lists for docs - (generating the parts lists, programmers lists follows later) - * doc/avrdude.texi: Add include of generated table of parts - * doc/Makefile.am: Add generating of table of parts in parts.texi - * doc/parts_comments.txt: Adding file containing part commenz references - * avrdude.1: Remove table of parts and mention "-p ?" option - * avrpart.c: Use AVR_DESCLEN for strncasecmp at list sorting + patch #7687: Autogenerating programmers and parts lists for docs + (generating the parts lists, programmers lists follows later) + * doc/avrdude.texi: Add include of generated table of parts + * doc/Makefile.am: Add generating of table of parts in parts.texi + * doc/parts_comments.txt: Adding file containing part commenz references + * avrdude.1: Remove table of parts and mention "-p ?" option + * avrpart.c: Use AVR_DESCLEN for strncasecmp at list sorting 2011-12-22 Rene Liebscher - * configure.ac: Add writing of definition of confsubst to config.status, - so it can run alone, not only called by configure. + * configure.ac: Add writing of definition of confsubst to config.status, + so it can run alone, not only called by configure. 2011-12-17 Rene Liebscher - patch #7680: Fixing timeout problem in ser_recv in ser_win32.c - * ser_win32.c: Return -1 at timeout in ser_recv(). + patch #7680: Fixing timeout problem in ser_recv in ser_win32.c + * ser_win32.c: Return -1 at timeout in ser_recv(). 2011-12-17 Rene Liebscher - * config_gram.y: Fixed another memory leak, when define an operation - more than once - * avrdude.conf.in: Fixed double definition at ATmega6490 + * config_gram.y: Fixed another memory leak, when define an operation + more than once + * avrdude.conf.in: Fixed double definition at ATmega6490 2011-12-17 Rene Liebscher - * config_gram.y: Restructuring and compacting programmer definition - part of grammar (in preparation of patch #7688) + * config_gram.y: Restructuring and compacting programmer definition + part of grammar (in preparation of patch #7688) 2011-12-17 Rene Liebscher - * avrdude.conf.in: Update documentation of programmer definition - * doc/avrdude.texi: Update documentation of programmer definition - and add list of implemented programmer types + * avrdude.conf.in: Update documentation of programmer definition + * doc/avrdude.texi: Update documentation of programmer definition + and add list of implemented programmer types 2011-12-17 Rene Liebscher - patch #7667: Minor memory handling fixes - * config_gram.y: Added several free_token() calls. + patch #7667: Minor memory handling fixes + * config_gram.y: Added several free_token() calls. 2011-12-16 Rene Liebscher - patch #7671: Sorting programmers and parts lists for console output - * avrdude.conf.in: change part desc of several parts to common pattern - AT(mega|tiny|xmega)[0-9]+[A-Z]* (Upper case AT, lower case in middle) - * list.[ch]: added sorting function lsort() - * pgm.[ch]: added function sort_programmers() - * avrpart.[ch]: added function sort_avrparts() - * main.c: use sort functions in list_programmers() and list_parts() - * main.c: list functions show config file info only at verbose mode + patch #7671: Sorting programmers and parts lists for console output + * avrdude.conf.in: change part desc of several parts to common pattern + AT(mega|tiny|xmega)[0-9]+[A-Z]* (Upper case AT, lower case in middle) + * list.[ch]: added sorting function lsort() + * pgm.[ch]: added function sort_programmers() + * avrpart.[ch]: added function sort_avrparts() + * main.c: use sort functions in list_programmers() and list_parts() + * main.c: list functions show config file info only at verbose mode 2011-10-19 Joerg Wunsch - * configure.ac: Replace "cvs" in version number by "svn". + * configure.ac: Replace "cvs" in version number by "svn". 2011-10-10 Joerg Wunsch - bug #34518: loading intel hex files > 64k using record-type 4 - (Extended Linear Address Record) - fileio.c: Replace the change from r928 (handling of 0x8000000 - offset in AVR32 files) by a completely different logic that no - longer breaks hex files for other devices starting with an - offset; also apply a similar change to S-record files, as well - as when writing files. - fileio.c: (Ditto.) + bug #34518: loading intel hex files > 64k using record-type 4 + (Extended Linear Address Record) + fileio.c: Replace the change from r928 (handling of 0x8000000 + offset in AVR32 files) by a completely different logic that no + longer breaks hex files for other devices starting with an + offset; also apply a similar change to S-record files, as well + as when writing files. + fileio.c: (Ditto.) 2011-09-15 Joerg Wunsch - * avrftdi.c: Remove stray printf()s by fprintf(stderr) - * usbtiny.c: (Ditto.) + * avrftdi.c: Remove stray printf()s by fprintf(stderr) + * usbtiny.c: (Ditto.) 2011-09-15 Joerg Wunsch - * main.c: Restrict the cyclecounter readout to those cases where - it has been explicitly requested (by -y or -Y), rather than always - attempting to read the last EEPROM bytes. + * main.c: Restrict the cyclecounter readout to those cases where + it has been explicitly requested (by -y or -Y), rather than always + attempting to read the last EEPROM bytes. 2011-09-15 Joerg Wunsch - * stk500v2.c (stk600_xprog_paged_load, stk600_xprog_paged_write): - Fix regression in the AVRISPmkII/STK600 TPI handling introduced - by the USBasp's TPI implementation which added a pagesize even for - the minor memory regions of TPI devices. Also fix wrong offset - introduced by the memory tagging patch. + * stk500v2.c (stk600_xprog_paged_load, stk600_xprog_paged_write): + Fix regression in the AVRISPmkII/STK600 TPI handling introduced + by the USBasp's TPI implementation which added a pagesize even for + the minor memory regions of TPI devices. Also fix wrong offset + introduced by the memory tagging patch. 2011-09-15 Joerg Wunsch - * avr.c (avr_read, avr_write): Don't bail out on TPI parts if - their programmer doesn't provide a (low-level) cmd_tpi method; - instead, fall back to the normal programmer methods which are - supposed to handle the situation. - This fixes a regression where the recent bitbang-TPI implementation - broke TPI handling of STK600/AVRISPmkII. + * avr.c (avr_read, avr_write): Don't bail out on TPI parts if + their programmer doesn't provide a (low-level) cmd_tpi method; + instead, fall back to the normal programmer methods which are + supposed to handle the situation. + This fixes a regression where the recent bitbang-TPI implementation + broke TPI handling of STK600/AVRISPmkII. 2011-09-14 Joerg Wunsch - Mega-commit to bring in memory tagging. - Each memory image byte is now tagged as it's being read from a file. - Only bytes read from a file will be written or verified (modulo page - granularity requirements). - * avrpart.h: Add memory tags. - * avrpart.c: Allocate and initialize tag area. - * update.h: Drop unused parameter "verify" from do_op(). - * pgm.h: Add parameter base_addr to the paged_load and paged_write - methods, respectively. - * avr.h: New parameter to avr_read: second AVRPART to verify against. - * fileio.c: Track all memory regions that have been read from an - input file by tagging them. - * update.c: Call avr_read() with the new parameter list. - * main.c: Call avr_initmem() to initialize the memory regions, rather - than trying to duplicate an unitialized part, and then let the - original part rot away. - * avr.c: Implement the heart of the new featureset. For paged memory - areas, when writing or verifying, call the paged_write and paged_load - methods, respectively, once per page instead of on the entire memory. - When writing, only write bytes or pages that have content read from a - file. Whe verifying, only read memory bytes or pages where the - verification data have been read from a file. Only verify those bytes - that have been read from a file. - * avrftdi.c: Implement the new API for paged_load and paged_write, - respectively. - * jtagmkII.c: (Ditto.) - * butterfly.c: (Ditto.) - * jtagmkI.c: (Ditto.) - * avr910.c: (Ditto.) - * stk500.c: (Ditto.) - * usbasp.c: (Ditto.) - * stk500v2.c: (Ditto.) - * usbtiny.c: (Ditto.) + Mega-commit to bring in memory tagging. + Each memory image byte is now tagged as it's being read from a file. + Only bytes read from a file will be written or verified (modulo page + granularity requirements). + * avrpart.h: Add memory tags. + * avrpart.c: Allocate and initialize tag area. + * update.h: Drop unused parameter "verify" from do_op(). + * pgm.h: Add parameter base_addr to the paged_load and paged_write + methods, respectively. + * avr.h: New parameter to avr_read: second AVRPART to verify against. + * fileio.c: Track all memory regions that have been read from an + input file by tagging them. + * update.c: Call avr_read() with the new parameter list. + * main.c: Call avr_initmem() to initialize the memory regions, rather + than trying to duplicate an unitialized part, and then let the + original part rot away. + * avr.c: Implement the heart of the new featureset. For paged memory + areas, when writing or verifying, call the paged_write and paged_load + methods, respectively, once per page instead of on the entire memory. + When writing, only write bytes or pages that have content read from a + file. Whe verifying, only read memory bytes or pages where the + verification data have been read from a file. Only verify those bytes + that have been read from a file. + * avrftdi.c: Implement the new API for paged_load and paged_write, + respectively. + * jtagmkII.c: (Ditto.) + * butterfly.c: (Ditto.) + * jtagmkI.c: (Ditto.) + * avr910.c: (Ditto.) + * stk500.c: (Ditto.) + * usbasp.c: (Ditto.) + * stk500v2.c: (Ditto.) + * usbtiny.c: (Ditto.) 2011-09-13 Joerg Wunsch - * stk500v2.c (stk500v2_command): Treat warnings as errors rather than - success. + * stk500v2.c (stk500v2_command): Treat warnings as errors rather than + success. 2011-08-30 Joerg Wunsch - bug #34027: avrdude AT90S1200 Problem (part 3 - documentation) - * avrdude.1: Document the programmer type restrictions for AT90S1200 - devices. - * doc/avrdude.texi: (Ditto.) + bug #34027: avrdude AT90S1200 Problem (part 3 - documentation) + * avrdude.1: Document the programmer type restrictions for AT90S1200 + devices. + * doc/avrdude.texi: (Ditto.) 2011-08-30 Joerg Wunsch - bug #34027: avrdude AT90S1200 Problem (part 2 - stk500v2 and relatives) - * stk500v2.c (stk500v2_initialize): For the AT90S1200, release - /RESET for a moment before reinitializing, as this is required by - its programming protocol. + bug #34027: avrdude AT90S1200 Problem (part 2 - stk500v2 and relatives) + * stk500v2.c (stk500v2_initialize): For the AT90S1200, release + /RESET for a moment before reinitializing, as this is required by + its programming protocol. 2011-08-30 Joerg Wunsch - * configure.ac: In AC_CHECK_LIB for libftdi, check for - ftdi_usb_get_strings() rathern than ftdi_init(), as this is a more - specific thing to search for in order to make sure getting a - recent enough libftdi. + * configure.ac: In AC_CHECK_LIB for libftdi, check for + ftdi_usb_get_strings() rathern than ftdi_init(), as this is a more + specific thing to search for in order to make sure getting a + recent enough libftdi. 2011-08-29 Joerg Wunsch - bug #34027: avrdude AT90S1200 Problem (part 1 - bitbang - programmers) - * config_gram.y: Introduce new keyword "is_at90s1200". - * lexer.l: (Ditto.) - * avrdude.conf.in: Applew new keyword to the AT90S1200 device. - * avrpart.h: Introduce new flag AVRPART_IS_AT90S1200, reflecting - the is_at90s1200 configuration keyword. - * bitbang.c (bitbang_initialize): Replace existing test for - AT90S1200 by AVRPART_IS_AT90S1200 - * avr.c (avr_write_byte_default): Avoid the pre-write reading for - the AT90S1200, as this appears to sometimes corrupt the high byte - by pre-programming the low byte just written into it. + bug #34027: avrdude AT90S1200 Problem (part 1 - bitbang + programmers) + * config_gram.y: Introduce new keyword "is_at90s1200". + * lexer.l: (Ditto.) + * avrdude.conf.in: Applew new keyword to the AT90S1200 device. + * avrpart.h: Introduce new flag AVRPART_IS_AT90S1200, reflecting + the is_at90s1200 configuration keyword. + * bitbang.c (bitbang_initialize): Replace existing test for + AT90S1200 by AVRPART_IS_AT90S1200 + * avr.c (avr_write_byte_default): Avoid the pre-write reading for + the AT90S1200, as this appears to sometimes corrupt the high byte + by pre-programming the low byte just written into it. 2011-08-27 Joerg Wunsch - * configure.ac: Bump version for post-5.11. + * configure.ac: Bump version for post-5.11. 2011-08-27 Joerg Wunsch - * configure.ac: Bump version for releasing AVRDUDE 5.11. + * configure.ac: Bump version for releasing AVRDUDE 5.11. 2011-08-26 Joerg Wunsch - * avrdude.1: Update the list of supported AVR devices. - * doc/avrdude.texi: (Ditto). + * avrdude.1: Update the list of supported AVR devices. + * doc/avrdude.texi: (Ditto). 2011-08-26 Joerg Wunsch - * configure.ac: add -lusb as "other libraries" when checking - for libftdi. + * configure.ac: add -lusb as "other libraries" when checking + for libftdi. 2011-08-26 Joerg Wunsch - Submitted by Juergen Weigert: - patch #7056: adding support for mikrokopter bootloader to butterfly - * butterfly.c: Add some specific logic to handle the - mikrokopter.de butterfly bootloader. - * butterfly.h: Add one related function declaration. - * config_gram.y: Add butterfly_mk keyword. - * lexer.l: (Ditto.) - * avrdude.conf.in: Add entry for butterfly_mk. + Submitted by Juergen Weigert: + patch #7056: adding support for mikrokopter bootloader to butterfly + * butterfly.c: Add some specific logic to handle the + mikrokopter.de butterfly bootloader. + * butterfly.h: Add one related function declaration. + * config_gram.y: Add butterfly_mk keyword. + * lexer.l: (Ditto.) + * avrdude.conf.in: Add entry for butterfly_mk. 2011-08-26 Joerg Wunsch - Submitted by Stefan Tomanek: - patch #7542: add default_bitclock to configuration files - * config.c: Add the new keyword and its handling. - * config.h: (Ditto.) - * config_gram.y: (Ditto.) - * avrdude.conf.in: (Ditto.) - * main.c: (Ditto.) - * lexer.l: (Ditto.) - * avrdude.1: Document the change. - * doc/avrdude.texi: (Ditto.) + Submitted by Stefan Tomanek: + patch #7542: add default_bitclock to configuration files + * config.c: Add the new keyword and its handling. + * config.h: (Ditto.) + * config_gram.y: (Ditto.) + * avrdude.conf.in: (Ditto.) + * main.c: (Ditto.) + * lexer.l: (Ditto.) + * avrdude.1: Document the change. + * doc/avrdude.texi: (Ditto.) 2011-08-26 Joerg Wunsch - Submitted by Brett Hagman: - patch #7603: wiring - programmer type for Wiring boards - (based on STK500v2) - * wiring.c: New file. - * wiring.h: (Ditto.) - * Makefile.am: Add new files. - * stk500v2_private.h: Reorganize so some functions and struct - pdata are globally known. - * stk500v2.c: (Ditto.) - * stk500v2.h: (Ditto.) - * lexer.l: Add new programmer keywords. - * config_gram.y: (Ditto.) - * avrdude.conf.in: Add "wiring" programmer entry. - * avrdude.1: Document the new programmer. - * doc/avrdude.texi: (Ditto.) - * AUTHORS: Add Brett Hagman. + Submitted by Brett Hagman: + patch #7603: wiring - programmer type for Wiring boards + (based on STK500v2) + * wiring.c: New file. + * wiring.h: (Ditto.) + * Makefile.am: Add new files. + * stk500v2_private.h: Reorganize so some functions and struct + pdata are globally known. + * stk500v2.c: (Ditto.) + * stk500v2.h: (Ditto.) + * lexer.l: Add new programmer keywords. + * config_gram.y: (Ditto.) + * avrdude.conf.in: Add "wiring" programmer entry. + * avrdude.1: Document the new programmer. + * doc/avrdude.texi: (Ditto.) + * AUTHORS: Add Brett Hagman. 2011-08-26 Joerg Wunsch - Submitted by an anonymous contributor on the mailinglist: - * avrdude.conf (jtagkey): Add a definition for the Amontec - JTAGKey + Submitted by an anonymous contributor on the mailinglist: + * avrdude.conf (jtagkey): Add a definition for the Amontec + JTAGKey 2011-08-26 Joerg Wunsch - Submitted by Juergen Weigert: - bug #22720: avrdude-5.5 ignores buff settings in avrdude.conf - (Note that the actual bug the subject is about has been fixed - long ago.) - * update.c (do_op): fix a diagnostic message - * pgm.h: add exit_datahigh field - * par.c: set and act upon the exit_datahigh field - * avrdude.1: document the new -E options - * doc/avrdude.texi: (Ditto.) + Submitted by Juergen Weigert: + bug #22720: avrdude-5.5 ignores buff settings in avrdude.conf + (Note that the actual bug the subject is about has been fixed + long ago.) + * update.c (do_op): fix a diagnostic message + * pgm.h: add exit_datahigh field + * par.c: set and act upon the exit_datahigh field + * avrdude.1: document the new -E options + * doc/avrdude.texi: (Ditto.) 2011-08-26 Joerg Wunsch - bug #33811: Parallel make fails - * Makefile.am (BUILT_SOURCES): Add this macro. + bug #33811: Parallel make fails + * Makefile.am (BUILT_SOURCES): Add this macro. 2011-08-26 Joerg Wunsch - bug #33114: Segfault after setting the DWEN fuse with Dragon - * jtagII.c (jtagmkII_getsync): Instead of exit()ing from - deep within the tree when detecting the "need debugWIRE" - situation, properly pass this up as a return code. - * jtagII_private.h (JTAGII_GETSYNC_FAIL_GRACEFUL): New constant. - * stk500v2.c (stk500v2_jtagmkII_open): Don't tell anything - anymore when receiving a JTAGII_GETSYNC_FAIL_GRACEFUL from - jtagmkII_getsync(); silently give up (all necessary has been - said already). + bug #33114: Segfault after setting the DWEN fuse with Dragon + * jtagII.c (jtagmkII_getsync): Instead of exit()ing from + deep within the tree when detecting the "need debugWIRE" + situation, properly pass this up as a return code. + * jtagII_private.h (JTAGII_GETSYNC_FAIL_GRACEFUL): New constant. + * stk500v2.c (stk500v2_jtagmkII_open): Don't tell anything + anymore when receiving a JTAGII_GETSYNC_FAIL_GRACEFUL from + jtagmkII_getsync(); silently give up (all necessary has been + said already). 2011-08-26 Joerg Wunsch - Reported by Jason Hecker: - * usbasp.c (libusb_to_errno): Conditionalize some error codes - that apparently are lacking on MinGW. + Reported by Jason Hecker: + * usbasp.c (libusb_to_errno): Conditionalize some error codes + that apparently are lacking on MinGW. 2011-08-25 Joerg Wunsch - Fix warnings. - * ser_avrdoper.c: add so exit() is declared. - * usbtiny.c (usbtiny_open): provide an initializer to a - "may be used uninitialized" variable (since GCC could not - fully detect the logic behind). + Fix warnings. + * ser_avrdoper.c: add so exit() is declared. + * usbtiny.c (usbtiny_open): provide an initializer to a + "may be used uninitialized" variable (since GCC could not + fully detect the logic behind). 2011-08-25 Joerg Wunsch - * configure.ac: Add a check for FreeBSD's libusb-1.0 - compatible library that is found in libusb.a/.so on - FreeBSD 8+. + * configure.ac: Add a check for FreeBSD's libusb-1.0 + compatible library that is found in libusb.a/.so on + FreeBSD 8+. 2011-08-25 Joerg Wunsch - Submitted by Doug Springer, based on work by - Wolfgang Moser, Ville Voipio, Hannes Weisbach - patch #7486: Patch to add FT2232C/D, FT2232H, FT4232H, - usbvid, usbpid, usbdev for USB support - Based on #7062 - * avrftdi.c: New file. - * avrftdi.h: (Ditto.) - * configure.ac: Add check for libftdi. - * config_gram.y: Add AVRFTDI and per-programmer USB string - keywords. - * lexer.l: (Ditto.) - * avrdude.conf.in: Add avrftdi and 2232HIO programmers. - * pgm.h: Add USB parameters. - * Makefile.am: Add avrftdi.c and avrftdi.h. - * AUTHORS: Mention the new authors. - * avrdude.1: Document the changes. - * doc/avrdude.texi: (Ditto.) + Submitted by Doug Springer, based on work by + Wolfgang Moser, Ville Voipio, Hannes Weisbach + patch #7486: Patch to add FT2232C/D, FT2232H, FT4232H, + usbvid, usbpid, usbdev for USB support - Based on #7062 + * avrftdi.c: New file. + * avrftdi.h: (Ditto.) + * configure.ac: Add check for libftdi. + * config_gram.y: Add AVRFTDI and per-programmer USB string + keywords. + * lexer.l: (Ditto.) + * avrdude.conf.in: Add avrftdi and 2232HIO programmers. + * pgm.h: Add USB parameters. + * Makefile.am: Add avrftdi.c and avrftdi.h. + * AUTHORS: Mention the new authors. + * avrdude.1: Document the changes. + * doc/avrdude.texi: (Ditto.) 2011-08-23 Joerg Wunsch - bug #29585: Fix license - * doc/avrdude.texi: Add FDL as an option to the licensing - statement, as the savannah administration would like it - that way. + bug #29585: Fix license + * doc/avrdude.texi: Add FDL as an option to the licensing + statement, as the savannah administration would like it + that way. 2011-08-23 Joerg Wunsch - Submitted by Darell Tan: - patch #7244: TPI bitbang implementation - * bitbang.c: Add TPI bitbang stuff. - * bitbang.h: (Ditto.) - * avr.c: (Ditto.) - * avr.h: (Ditto.) - * pgm.c: (Ditto.) - * pgm.h: (Ditto.) - * serbb_posix.c: Wire bitbang_cmd_tpi into the struct pgm. - * serbb_win32.c: (Ditto.) - * par.c: (Ditto.) - * doc/avrdude.texi: Document the TPI bitbang support. + Submitted by Darell Tan: + patch #7244: TPI bitbang implementation + * bitbang.c: Add TPI bitbang stuff. + * bitbang.h: (Ditto.) + * avr.c: (Ditto.) + * avr.h: (Ditto.) + * pgm.c: (Ditto.) + * pgm.h: (Ditto.) + * serbb_posix.c: Wire bitbang_cmd_tpi into the struct pgm. + * serbb_win32.c: (Ditto.) + * par.c: (Ditto.) + * doc/avrdude.texi: Document the TPI bitbang support. 2011-08-17 Joerg Wunsch - Submitted by Grygoriy Fuchedzhy: - bug #31779: Add support for addressing usbtinyisp with -P option - * usbtiny.c (usbtiny_open): Add logic to distinguish multiple USBtinyISP - programmers by their bus:device tuple. - * doc/avrdude.texi: Document the new functionality. - * avrdude.1: (Ditto.) + Submitted by Grygoriy Fuchedzhy: + bug #31779: Add support for addressing usbtinyisp with -P option + * usbtiny.c (usbtiny_open): Add logic to distinguish multiple USBtinyISP + programmers by their bus:device tuple. + * doc/avrdude.texi: Document the new functionality. + * avrdude.1: (Ditto.) 2011-08-16 Joerg Wunsch - Submitted by Timon Van Overveldt: - bug #30268: Debugwire broken in avrdude-5.10 - * jtagmkII.c (jtagmkII_initialize): only try setting up a JTAG chain when - the programmer is using JTAG. + Submitted by Timon Van Overveldt: + bug #30268: Debugwire broken in avrdude-5.10 + * jtagmkII.c (jtagmkII_initialize): only try setting up a JTAG chain when + the programmer is using JTAG. 2011-08-16 Joerg Wunsch - bug #29636: AVRDude issues invalid CMD_CHECK_TARGET_CONNECTION - on the AVRISP-MKII - * stk500v2.c (stk500v2_program_enable): Rewrite the logic to - explain ISP activation failures. - * stk500v2_private.h: Fix the various STATUS_* constants; - AVR069 and AVR079 disagreed in their values, even though they - are apparently implementing the same logic behind. + bug #29636: AVRDude issues invalid CMD_CHECK_TARGET_CONNECTION + on the AVRISP-MKII + * stk500v2.c (stk500v2_program_enable): Rewrite the logic to + explain ISP activation failures. + * stk500v2_private.h: Fix the various STATUS_* constants; + AVR069 and AVR079 disagreed in their values, even though they + are apparently implementing the same logic behind. 2011-08-16 Joerg Wunsch - bug #29650: Programming timeouts in ATmega128RFA1 are too slow - * avrdude.conf.in (ATmega128RFA1): Bump write delay values for flash and - EEPROM to 50 ms. + bug #29650: Programming timeouts in ATmega128RFA1 are too slow + * avrdude.conf.in (ATmega128RFA1): Bump write delay values for flash and + EEPROM to 50 ms. 2011-08-16 Joerg Wunsch - * avrdude.conf.in (ATmega8515, ATmega8535, ATmega48, ATmega88, ATmega88P, - ATtiny88, ATmega168, ATmega168P, ATmega328P): Bump delay value for STK500v2 - EEPROM write operation to 5, according to the respective XML files. + * avrdude.conf.in (ATmega8515, ATmega8535, ATmega48, ATmega88, ATmega88P, + ATtiny88, ATmega168, ATmega168P, ATmega328P): Bump delay value for STK500v2 + EEPROM write operation to 5, according to the respective XML files. 2011-08-16 Joerg Wunsch - Submitted by Darcy Houlahan: - bug #29694: error in avrdude.conf for attiny84 eeprom - * avrdude.conf.in (ATtiny84, ATtiny85): fix A7 bit in EEPROM write - command. + Submitted by Darcy Houlahan: + bug #29694: error in avrdude.conf for attiny84 eeprom + * avrdude.conf.in (ATtiny84, ATtiny85): fix A7 bit in EEPROM write + command. 2011-08-16 Joerg Wunsch - Submitted by Durant Gilles: - * avrdude.conf.in (ATtiny4313): Fix flash addressing bits for manual ISP - algorithm. + Submitted by Durant Gilles: + * avrdude.conf.in (ATtiny4313): Fix flash addressing bits for manual ISP + algorithm. 2011-08-16 Joerg Wunsch - Submitted by Philip: - bug #31386: A "BUILD.svn" or similar "how to get started" doc would be helpful - * BUILD-FROM-SVN: New file. + Submitted by Philip: + bug #31386: A "BUILD.svn" or similar "how to get started" doc would be helpful + * BUILD-FROM-SVN: New file. 2011-08-15 Joerg Wunsch - Submitted by Nic Jones: - bug #32539: [Documentation][Patch] Man page is misleading - re: Dragon & PDI - * doc/avrdude.texi: Update information about PDI connections - on AVR Dragon + Submitted by Nic Jones: + bug #32539: [Documentation][Patch] Man page is misleading + re: Dragon & PDI + * doc/avrdude.texi: Update information about PDI connections + on AVR Dragon 2011-08-12 Joerg Wunsch - * usbasp.c: Add so this actually compiles - again. + * usbasp.c: Add so this actually compiles + again. 2011-08-12 Joerg Wunsch - Contributed by tixiv@gmx.net: - bug #33345: File auto detection as binary doesn't open - file in binary mode on Windows - * fileio.c: Move the decision about opening files in - binary mode until before the fopen() call. + Contributed by tixiv@gmx.net: + bug #33345: File auto detection as binary doesn't open + file in binary mode on Windows + * fileio.c: Move the decision about opening files in + binary mode until before the fopen() call. 2011-06-16 Thomas Fischl - * avrdude.conf.in: Fix part id of ATtiny9. + * avrdude.conf.in: Fix part id of ATtiny9. 2011-05-28 Thomas Fischl - Based on patch #7440 commited by Slawomir FraÅ›: - * usbasp.c: added TPI support for USBasp - * usbasp.h: (Ditto.) + Based on patch #7440 commited by Slawomir FraÅ›: + * usbasp.c: added TPI support for USBasp + * usbasp.h: (Ditto.) 2011-05-11 Joerg Wunsch - * avrdude.conf.in: Add support for ATmega168P. + * avrdude.conf.in: Add support for ATmega168P. 2011-05-11 Joerg Wunsch - * avrdude.conf.in: Fix abbreviated name for ATmega324PA. + * avrdude.conf.in: Fix abbreviated name for ATmega324PA. 2011-05-11 Joerg Wunsch - Submitted by Lech Perczak: - bug #30946: Added support for ATmega8/16/32U2 - * avrdude.conf.in: Add ATmega8/16/32U2 entries. + Submitted by Lech Perczak: + bug #30946: Added support for ATmega8/16/32U2 + * avrdude.conf.in: Add ATmega8/16/32U2 entries. 2011-05-11 Joerg Wunsch - Submitted by David A Lyons: - patch #7393: Adding ATtiny4313 Device to avrdude.conf.in - * avrdude.conf.in: Add ATtiny4313 data. + Submitted by David A Lyons: + patch #7393: Adding ATtiny4313 Device to avrdude.conf.in + * avrdude.conf.in: Add ATtiny4313 data. 2011-05-11 Joerg Wunsch - * usb_libusb.c: Bump timeout values to allow for slow clock - speeds. - * jtagmkII.c: (Ditto.) + * usb_libusb.c: Bump timeout values to allow for slow clock + speeds. + * jtagmkII.c: (Ditto.) 2011-03-04 Eric B. Weddington - Thanks to Vitaly Chernookiy for the patch. - * avrdude.conf.in: Add support for atmega324pa. - * ChangeLog-2010: New file, rotate ChangeLog for new year. + Thanks to Vitaly Chernookiy for the patch. + * avrdude.conf.in: Add support for atmega324pa. + * ChangeLog-2010: New file, rotate ChangeLog for new year. diff --git a/src/avrdude/ChangeLog-2012 b/src/avrdude/ChangeLog-2012 index bb5751a6dbc..cb04f03aca2 100644 --- a/src/avrdude/ChangeLog-2012 +++ b/src/avrdude/ChangeLog-2012 @@ -1,729 +1,729 @@ 2012-12-18 Joerg Wunsch - * usbdefs.h (USBDEV_BULK_EP_WRITE_STK600) - (USBDEV_BULK_EP_READ_STK600): new define values - * stk500v2.c (stk600_open): use the STK600 EP values, - as they are different from AVRISPmkII + * usbdefs.h (USBDEV_BULK_EP_WRITE_STK600) + (USBDEV_BULK_EP_READ_STK600): new define values + * stk500v2.c (stk600_open): use the STK600 EP values, + as they are different from AVRISPmkII 2012-12-18 Joerg Wunsch - bug #37942: Latest SVN can't program in dragon_jtag mode - * jtagmkII.c (jtagmkII_initialize): For Xmega devices, and - firmware >= 7.x, don't trigger a RESET, in order to work around a - firmware bug that appears to be present in at least firmware 7.24 - for the Dragon. + bug #37942: Latest SVN can't program in dragon_jtag mode + * jtagmkII.c (jtagmkII_initialize): For Xmega devices, and + firmware >= 7.x, don't trigger a RESET, in order to work around a + firmware bug that appears to be present in at least firmware 7.24 + for the Dragon. 2012-12-04 Joerg Wunsch - * config_gram.y: Implement the "ocdrev" keyword - * avrpart.c: (Dito) - * avrpart.h: (Dito) - * lexer.l: (Dito) - * avrdude.conf.in: Add "ocdrev" key/value pairs, based - on the AS6 XML file information. - * jtag3.c: Use the ocdrev in the parameter block. + * config_gram.y: Implement the "ocdrev" keyword + * avrpart.c: (Dito) + * avrpart.h: (Dito) + * lexer.l: (Dito) + * avrdude.conf.in: Add "ocdrev" key/value pairs, based + on the AS6 XML file information. + * jtag3.c: Use the ocdrev in the parameter block. 2012-12-03 Joerg Wunsch - * jtag3.c: Make jtag3_command() public - * jtag3.h: (Dito.) - * jtag3_private.h: Add two new commands - * stk500v2.c: Implement the "MonCon disable" hack that - allows temporarily falling back to ISP when trying to - talk to a part that has debugWIRE enabled + * jtag3.c: Make jtag3_command() public + * jtag3.h: (Dito.) + * jtag3_private.h: Add two new commands + * stk500v2.c: Implement the "MonCon disable" hack that + allows temporarily falling back to ISP when trying to + talk to a part that has debugWIRE enabled 2012-12-03 Rene Liebscher - * pickit2.c: reordered #includes for non-usb configuration + * pickit2.c: reordered #includes for non-usb configuration 2012-12-03 Joerg Wunsch - * jtag3.c: Enable interactive adjustment of the various - clock frequencies (JTAG Xmega, JTAG megaAVR, PDI Xmega) - through the set_sck_period() callback. + * jtag3.c: Enable interactive adjustment of the various + clock frequencies (JTAG Xmega, JTAG megaAVR, PDI Xmega) + through the set_sck_period() callback. 2012-12-03 Joerg Wunsch - * jtag3.c: Remove unused code that was left over from - cloning the jtagmkII.c implementation + * jtag3.c: Remove unused code that was left over from + cloning the jtagmkII.c implementation 2012-12-03 Joerg Wunsch - * pgm_type.c: Add "jtagice3_isp" programmer hook - * avrdude.conf.in: Add "jtag3isp" programmer - * jtag3.c: jtag3_setparm() is now public - * jtag3.h: (Dito) - * stk500v2_private.h: Command 0x1D is CMD_SPI_MULTI only - for STK500v2, AVRISPmkII, and JTAGICEmkII; for JTAGICE3, - it's CMD_SET_SCK now; also add CMD_GET_SCK - * avrpart.c (avr_get_output_index): New function - * avrpart.h: (Dito) - * stk500v2.c: Implement the pasthrough programmer glue logic - for JTAGICE3 in ISP mode - * stk500v2.h: (Dito) - * avrdude.1: Document the JTAGICE3 support. + * pgm_type.c: Add "jtagice3_isp" programmer hook + * avrdude.conf.in: Add "jtag3isp" programmer + * jtag3.c: jtag3_setparm() is now public + * jtag3.h: (Dito) + * stk500v2_private.h: Command 0x1D is CMD_SPI_MULTI only + for STK500v2, AVRISPmkII, and JTAGICEmkII; for JTAGICE3, + it's CMD_SET_SCK now; also add CMD_GET_SCK + * avrpart.c (avr_get_output_index): New function + * avrpart.h: (Dito) + * stk500v2.c: Implement the pasthrough programmer glue logic + for JTAGICE3 in ISP mode + * stk500v2.h: (Dito) + * avrdude.1: Document the JTAGICE3 support. 2012-11-30 Joerg Wunsch - * jtag3.c (jtag3_read_byte, jtag3_write_byte): Remove the - m->offset from addr, JTAGICE3 doesn't need it anymore (similar - to JTAGICEmkII with 7+ firmware) - * jtag3.c (jtag3_read_byte): Allow for full-page reads of - EEPROM also for Xmega and debugWIRE, allow for signature - read in debugWIRE + * jtag3.c (jtag3_read_byte, jtag3_write_byte): Remove the + m->offset from addr, JTAGICE3 doesn't need it anymore (similar + to JTAGICEmkII with 7+ firmware) + * jtag3.c (jtag3_read_byte): Allow for full-page reads of + EEPROM also for Xmega and debugWIRE, allow for signature + read in debugWIRE 2012-11-30 Joerg Wunsch - * jtag3_private.h: Add two more error detail codes I stumbled - across during development - * jtag3.c: (Dito.) - * usb_libusb.c: Reduce timeouts from 100 to 10 s, still long - enough, but not getting cold feet when something goes wrong. + * jtag3_private.h: Add two more error detail codes I stumbled + across during development + * jtag3.c: (Dito.) + * usb_libusb.c: Reduce timeouts from 100 to 10 s, still long + enough, but not getting cold feet when something goes wrong. 2012-11-29 Joerg Wunsch - * jtag3.c: Handle events returned by the ICE - * usbdevs.h: Add defines that mark an event in return - from usb_recv_frame(). - * usb_libusb.c: (Dito.) + * jtag3.c: Handle events returned by the ICE + * usbdevs.h: Add defines that mark an event in return + from usb_recv_frame(). + * usb_libusb.c: (Dito.) 2012-11-29 Joerg Wunsch - * avrdude.conf.in: Remove "has_jtag" from Xmega A4 and D4 - devices, as they only have PDI. - * jtag3.c (jtag3_page_erase): Actually implement this. + * avrdude.conf.in: Remove "has_jtag" from Xmega A4 and D4 + devices, as they only have PDI. + * jtag3.c (jtag3_page_erase): Actually implement this. 2012-11-29 Joerg Wunsch - bug #37265: wrong page sizes for XMega64xx in avrdude.conf - * avrdude.conf.in: Fix page sizes for all Xmega devices, - by cross-checking against Atmel Studio's device XML files + bug #37265: wrong page sizes for XMega64xx in avrdude.conf + * avrdude.conf.in: Fix page sizes for all Xmega devices, + by cross-checking against Atmel Studio's device XML files 2012-11-29 Joerg Wunsch - * jtag3.c: Fill in the missing pieces for Xmega support (both, - PDI and JTAG). - * jtagmkII.c (jtagmkII_set_xmega_params): Use "fuse1" rather - than "fuse0" memory space to fill in the NVM offset from, as - there is no "fuse0" on some Xmega devices. + * jtag3.c: Fill in the missing pieces for Xmega support (both, + PDI and JTAG). + * jtagmkII.c (jtagmkII_set_xmega_params): Use "fuse1" rather + than "fuse0" memory space to fill in the NVM offset from, as + there is no "fuse0" on some Xmega devices. 2012-11-29 Joerg Wunsch - * avrdude.conf.in (ATmega256RFR2, ATmega128RFR2, ATmega64RFR2): - New devices + * avrdude.conf.in (ATmega256RFR2, ATmega128RFR2, ATmega64RFR2): + New devices 2012-11-28 Joerg Wunsch - First support for Atmel JTAGICE3. Guessed from USB sniffer - traces made by Knut Schwichtenberg, and by similarity to - JTAGICEmkII. - Still quite incomplete, just megaAVR/JTAG is done by now. - * jtag3.c: New file. - * jtag3.h: (Dito.) - * jtag3_private.h: (Dito.) - * pgm_type.c: Add new programmers - * avrdude.conf.in: (Dito.) - * usbdevs.h: Add new parameters - * Makefile.am: Add new files - * usb_libusb.c: Handle separate event endpoint, and larger - (USB 2.0) packet sizes + First support for Atmel JTAGICE3. Guessed from USB sniffer + traces made by Knut Schwichtenberg, and by similarity to + JTAGICEmkII. + Still quite incomplete, just megaAVR/JTAG is done by now. + * jtag3.c: New file. + * jtag3.h: (Dito.) + * jtag3_private.h: (Dito.) + * pgm_type.c: Add new programmers + * avrdude.conf.in: (Dito.) + * usbdevs.h: Add new parameters + * Makefile.am: Add new files + * usb_libusb.c: Handle separate event endpoint, and larger + (USB 2.0) packet sizes 2012-11-26 Joerg Wunsch - * jtagmkII.c: Change all the USB details (endpoint numbers, - max transfer size etc.) to a per-programmer adjustable value. - * serial.h: (Dito.) - * stk500v2.c: (Dito.) - * usbdevs.h: (Dito.) - * usb_libusb.c: (Dito.) + * jtagmkII.c: Change all the USB details (endpoint numbers, + max transfer size etc.) to a per-programmer adjustable value. + * serial.h: (Dito.) + * stk500v2.c: (Dito.) + * usbdevs.h: (Dito.) + * usb_libusb.c: (Dito.) 2012-11-20 Joerg Wunsch - * buspirate.c: Replace outdated FSF postal address by a reference to - the GPL info on their website. - * jtagmkII.c: (Dito.) - * avrftdi.c: (Dito.) - * wiring.c: (Dito.) - * linux_ppdev.h: (Dito.) - * serbb.h: (Dito.) - * usbtiny.h: (Dito.) - * confwin.c: (Dito.) - * buspirate.h: (Dito.) - * avrftdi.h: (Dito.) - * wiring.h: (Dito.) - * jtagmkII.h: (Dito.) - * pickit2.c: (Dito.) - * config.c: (Dito.) - * term.c: (Dito.) - * confwin.h: (Dito.) - * avrdude.1: (Dito.) - * windows/Makefile.am: (Dito.) - * config.h: (Dito.) - * pickit2.h: (Dito.) - * term.h: (Dito.) - * tools/get-hv-params.xsl: (Dito.) - * tools/get-stk600-cards.xsl: (Dito.) - * tools/get-stk600-devices.xsl: (Dito.) - * tools/get-dw-params.xsl: (Dito.) - * butterfly.c: (Dito.) - * configure.ac: (Dito.) - * doc/Makefile.am: (Dito.) - * pgm_type.c: (Dito.) - * butterfly.h: (Dito.) - * jtagmkI.c: (Dito.) - * ft245r.c: (Dito.) - * COPYING: (Dito.) - * pgm_type.h: (Dito.) - * jtagmkI.h: (Dito.) - * pindefs.h: (Dito.) - * config_gram.y: (Dito.) - * arduino.c: (Dito.) - * arduino.h: (Dito.) - * ser_win32.c: (Dito.) - * serbb_win32.c: (Dito.) - * avr910.c: (Dito.) - * stk500.c: (Dito.) - * freebsd_ppi.h: (Dito.) - * avr910.h: (Dito.) - * solaris_ecpp.h: (Dito.) - * stk500.h: (Dito.) - * jtagmkII_private.h: (Dito.) - * avrdude.h: (Dito.) - * bitbang.c: (Dito.) - * bitbang.h: (Dito.) - * avrpart.c: (Dito.) - * safemode.c: (Dito.) - * stk500generic.c: (Dito.) - * serial.h: (Dito.) - * avrpart.h: (Dito.) - * jtagmkI_private.h: (Dito.) - * ppi.c: (Dito.) - * avr.c: (Dito.) - * safemode.h: (Dito.) - * stk500generic.h: (Dito.) - * ser_avrdoper.c: (Dito.) - * avr.h: (Dito.) - * ppi.h: (Dito.) - * usbasp.c: (Dito.) - * lists.c: (Dito.) - * stk500v2.c: (Dito.) - * my_ddk_hidsdi.h: (Dito.) - * tpi.h: (Dito.) - * usbasp.h: (Dito.) - * lists.h: (Dito.) - * stk500v2.h: (Dito.) - * ppiwin.c: (Dito.) - * fileio.c: (Dito.) - * ser_posix.c: (Dito.) - * fileio.h: (Dito.) - * serbb_posix.c: (Dito.) - * usbdevs.h: (Dito.) - * par.c: (Dito.) - * update.c: (Dito.) - * pgm.c: (Dito.) - * main.c: (Dito.) - * par.h: (Dito.) - * update.h: (Dito.) - * lexer.l: (Dito.) - * Makefile.am: (Dito.) - * pgm.h: (Dito.) - * usb_libusb.c: (Dito.) - * usbtiny.c: (Dito.) + * buspirate.c: Replace outdated FSF postal address by a reference to + the GPL info on their website. + * jtagmkII.c: (Dito.) + * avrftdi.c: (Dito.) + * wiring.c: (Dito.) + * linux_ppdev.h: (Dito.) + * serbb.h: (Dito.) + * usbtiny.h: (Dito.) + * confwin.c: (Dito.) + * buspirate.h: (Dito.) + * avrftdi.h: (Dito.) + * wiring.h: (Dito.) + * jtagmkII.h: (Dito.) + * pickit2.c: (Dito.) + * config.c: (Dito.) + * term.c: (Dito.) + * confwin.h: (Dito.) + * avrdude.1: (Dito.) + * windows/Makefile.am: (Dito.) + * config.h: (Dito.) + * pickit2.h: (Dito.) + * term.h: (Dito.) + * tools/get-hv-params.xsl: (Dito.) + * tools/get-stk600-cards.xsl: (Dito.) + * tools/get-stk600-devices.xsl: (Dito.) + * tools/get-dw-params.xsl: (Dito.) + * butterfly.c: (Dito.) + * configure.ac: (Dito.) + * doc/Makefile.am: (Dito.) + * pgm_type.c: (Dito.) + * butterfly.h: (Dito.) + * jtagmkI.c: (Dito.) + * ft245r.c: (Dito.) + * COPYING: (Dito.) + * pgm_type.h: (Dito.) + * jtagmkI.h: (Dito.) + * pindefs.h: (Dito.) + * config_gram.y: (Dito.) + * arduino.c: (Dito.) + * arduino.h: (Dito.) + * ser_win32.c: (Dito.) + * serbb_win32.c: (Dito.) + * avr910.c: (Dito.) + * stk500.c: (Dito.) + * freebsd_ppi.h: (Dito.) + * avr910.h: (Dito.) + * solaris_ecpp.h: (Dito.) + * stk500.h: (Dito.) + * jtagmkII_private.h: (Dito.) + * avrdude.h: (Dito.) + * bitbang.c: (Dito.) + * bitbang.h: (Dito.) + * avrpart.c: (Dito.) + * safemode.c: (Dito.) + * stk500generic.c: (Dito.) + * serial.h: (Dito.) + * avrpart.h: (Dito.) + * jtagmkI_private.h: (Dito.) + * ppi.c: (Dito.) + * avr.c: (Dito.) + * safemode.h: (Dito.) + * stk500generic.h: (Dito.) + * ser_avrdoper.c: (Dito.) + * avr.h: (Dito.) + * ppi.h: (Dito.) + * usbasp.c: (Dito.) + * lists.c: (Dito.) + * stk500v2.c: (Dito.) + * my_ddk_hidsdi.h: (Dito.) + * tpi.h: (Dito.) + * usbasp.h: (Dito.) + * lists.h: (Dito.) + * stk500v2.h: (Dito.) + * ppiwin.c: (Dito.) + * fileio.c: (Dito.) + * ser_posix.c: (Dito.) + * fileio.h: (Dito.) + * serbb_posix.c: (Dito.) + * usbdevs.h: (Dito.) + * par.c: (Dito.) + * update.c: (Dito.) + * pgm.c: (Dito.) + * main.c: (Dito.) + * par.h: (Dito.) + * update.h: (Dito.) + * lexer.l: (Dito.) + * Makefile.am: (Dito.) + * pgm.h: (Dito.) + * usb_libusb.c: (Dito.) + * usbtiny.c: (Dito.) 2012-11-13 Rene Liebscher - bug #35186 inverting pins with "~" doesn't work for pin lists (i.e. vcc) - bug #37727 Add support for LM3S811 dev board as a programmer - * lexer.l,config_gram.y: accepting inverted pins at pin lists - syntax: ~num or ~(num,num,...) - * par.c: par_set_many_bits is now usable with inverted pins - * avrftdi.c: fixed wrong index in ftdi_pin_name - * avrdude.conf.in: added programmer lm3s811 + bug #35186 inverting pins with "~" doesn't work for pin lists (i.e. vcc) + bug #37727 Add support for LM3S811 dev board as a programmer + * lexer.l,config_gram.y: accepting inverted pins at pin lists + syntax: ~num or ~(num,num,...) + * par.c: par_set_many_bits is now usable with inverted pins + * avrftdi.c: fixed wrong index in ftdi_pin_name + * avrdude.conf.in: added programmer lm3s811 2012-11-04 Rene Liebscher - * lexer.l,config_gram.y,config.[hc]: changed reading of numbers to integers - except of default_bitclock which is the only real number. - No signs are allowed as negative values do not make sense for current - config values. - * buspirate.c: include own header file buspirate.h - * doc/.cvsignore: add programmers.texi to ignore list + * lexer.l,config_gram.y,config.[hc]: changed reading of numbers to integers + except of default_bitclock which is the only real number. + No signs are allowed as negative values do not make sense for current + config values. + * buspirate.c: include own header file buspirate.h + * doc/.cvsignore: add programmers.texi to ignore list 2012-09-06 Joerg Wunsch - * doc/Makefile.am: add EXTRA_DIST, replace $(srcdir) by - $(builddir) for generated files, so "make distcheck" - works again + * doc/Makefile.am: add EXTRA_DIST, replace $(srcdir) by + $(builddir) for generated files, so "make distcheck" + works again 2012-09-05 Rene Liebscher - * doc/Makefile.am: add $(srcdir) to name of generated files, so BSD make - find the files ( GNU make sees no difference if the - file is called version.texi or ./version.texi ) + * doc/Makefile.am: add $(srcdir) to name of generated files, so BSD make + find the files ( GNU make sees no difference if the + file is called version.texi or ./version.texi ) 2012-08-15 Rene Liebscher - patch #7184 Support for PICKit2 programmer - * Makefile.am: add pickit2 files - * pickit2.[ch]: new programmer implementation - * pgm_type.c: add pickit to list - * avrdude.1: documentation for pickit2 - * doc/avrdude.texi: documentation for pickit2 - * avrdude.conf.in: add pickit2 programmer entry + patch #7184 Support for PICKit2 programmer + * Makefile.am: add pickit2 files + * pickit2.[ch]: new programmer implementation + * pgm_type.c: add pickit to list + * avrdude.1: documentation for pickit2 + * doc/avrdude.texi: documentation for pickit2 + * avrdude.conf.in: add pickit2 programmer entry 2012-08-15 Rene Liebscher - bug #30559 Ft232 bit-bang support, see comment #30 - * ft245r.c: added semaphore workaround for MacOS X, - added pthread_testcancel in reader thread - - * configure.ac: added check for TYPE_232H in libftdi (not in libftdi < 0.20) - * avrftdi.c: do not use TYPE_232H if not declared + bug #30559 Ft232 bit-bang support, see comment #30 + * ft245r.c: added semaphore workaround for MacOS X, + added pthread_testcancel in reader thread + + * configure.ac: added check for TYPE_232H in libftdi (not in libftdi < 0.20) + * avrftdi.c: do not use TYPE_232H if not declared 2012-08-13 Hannes Weisbach - * avrftdi.c: fixes pin_limit for different FTDI devices (there was a mixup - between 2232C and 2232H) + * avrftdi.c: fixes pin_limit for different FTDI devices (there was a mixup + between 2232C and 2232H) 2012-07-29 Hannes Weisbach - * avrftdi.c: bugfixes (synchronisation) and maintenance (paged programming, - nicer output, separation of parameter checking and actual code) + * avrftdi.c: bugfixes (synchronisation) and maintenance (paged programming, + nicer output, separation of parameter checking and actual code) 2012-07-25 Joerg Wunsch - * jtagmkII.c (jtagmkII_memtype): return MTYPE_FLASH rather than - MTYPE_SPM for non-Xmega flash regions + * jtagmkII.c (jtagmkII_memtype): return MTYPE_FLASH rather than + MTYPE_SPM for non-Xmega flash regions 2012-07-20 Hannes Weisbach - * avrpart.c, avrpart.h: adds avr_pin_name() + * avrpart.c, avrpart.h: adds avr_pin_name() 2012-07-18 Joerg Wunsch - * configure.ac: check for libelf.h also in libelf/ - * fileio.c: include if configure found this - to be the case + * configure.ac: check for libelf.h also in libelf/ + * fileio.c: include if configure found this + to be the case 2012-06-13 Rene Liebscher - * configure.ac: Check for presence of - * ft245r.c: Depend on HAVE_PTHREAD_H - * Makefile.am: Add -lpthread if needed. + * configure.ac: Check for presence of + * ft245r.c: Depend on HAVE_PTHREAD_H + * Makefile.am: Add -lpthread if needed. 2012-06-07 Joerg Wunsch - * usbtiny.c (usbtiny_paged_load, usbtiny_paged_write): - fix breakage introduced by the recent page handling reorg; - it used to cause an infinite loop + * usbtiny.c (usbtiny_paged_load, usbtiny_paged_write): + fix breakage introduced by the recent page handling reorg; + it used to cause an infinite loop 2012-05-04 Joerg Wunsch - Xmega page erase implementation for XPROG (AVRISPmkII, STK600) - * stk500v2.c (stk600_xprog_page_erase): New function. + Xmega page erase implementation for XPROG (AVRISPmkII, STK600) + * stk500v2.c (stk600_xprog_page_erase): New function. 2012-05-04 Joerg Wunsch - Xmega page erase implementation for JTAGICEmkII - * jtagmkII.c: Handle flash pages sizes > 256 bytes, implement - page_erase() method - * avrdude.conf.in: Change flash pagesize for all Xmega devices - to 512 bytes - * avr.c: Implement auto_erase, using page_erase if available - * avr.h: Remove unused parameters from avr_read(), replace - unused parameter in avr_write)() by auto_erase - * stk500v2.c: Handle flash page sizes > 256 bytes - * update.c (do_op): Handle new updateflags parameter - * main.c: Implement auto_erase as page_erase if possible - * update.h (enum updateflags): New enum - * pgm.h (struct programmer_t): Add page_erase method + Xmega page erase implementation for JTAGICEmkII + * jtagmkII.c: Handle flash pages sizes > 256 bytes, implement + page_erase() method + * avrdude.conf.in: Change flash pagesize for all Xmega devices + to 512 bytes + * avr.c: Implement auto_erase, using page_erase if available + * avr.h: Remove unused parameters from avr_read(), replace + unused parameter in avr_write)() by auto_erase + * stk500v2.c: Handle flash page sizes > 256 bytes + * update.c (do_op): Handle new updateflags parameter + * main.c: Implement auto_erase as page_erase if possible + * update.h (enum updateflags): New enum + * pgm.h (struct programmer_t): Add page_erase method 2012-04-26 Joerg Wunsch - * jtagmkII.c (jtagmkII_paged_load, jtagmkII_paged_write): fix bug - in memory type calculation for Xmega "boot" memory region. + * jtagmkII.c (jtagmkII_paged_load, jtagmkII_paged_write): fix bug + in memory type calculation for Xmega "boot" memory region. 2012-04-25 Joerg Wunsch - * update.c (parse_op): do not assume default memtype here - * main.c: after locating the part information, determine default - memtype for all update options that didn't have a memtype - specified; this is "application" for Xmega parts, and "flash" for - everything else. + * update.c (parse_op): do not assume default memtype here + * main.c: after locating the part information, determine default + memtype for all update options that didn't have a memtype + specified; this is "application" for Xmega parts, and "flash" for + everything else. 2012-04-24 Joerg Wunsch - * fileio.c: Rework the way ELF file sections are considered: while - scanning the program header table, the offsets from a program - header entry must never be used directly when checking the bounds - of the current AVR memory region. Instead, they must always be - checked based on the corresponding section's entry. That way, - Xmega devices now properly take into account whether the segment - fits into any of the application/apptable/boot memory region. + * fileio.c: Rework the way ELF file sections are considered: while + scanning the program header table, the offsets from a program + header entry must never be used directly when checking the bounds + of the current AVR memory region. Instead, they must always be + checked based on the corresponding section's entry. That way, + Xmega devices now properly take into account whether the segment + fits into any of the application/apptable/boot memory region. 2012-04-20 Joerg Wunsch - bug #30756: When setting SUT to 64ms on XMEGA, avrdude doesn't - read device signature - * main.c: When reading the signature yields 0x000000 or 0xffffff, - retry (up to twice) after some progressive delay. + bug #30756: When setting SUT to 64ms on XMEGA, avrdude doesn't + read device signature + * main.c: When reading the signature yields 0x000000 or 0xffffff, + retry (up to twice) after some progressive delay. 2012-04-20 Joerg Wunsch - * avrdude.conf.in (ATxmega16D4, ATxmega32D4, ATxmega64D4, - ATxmega128D4): New devices. As Xmega D doesn't feature a fuse0 - memory cell, move that one out from the generic .xmega part into - the individual Xmega A parts. + * avrdude.conf.in (ATxmega16D4, ATxmega32D4, ATxmega64D4, + ATxmega128D4): New devices. As Xmega D doesn't feature a fuse0 + memory cell, move that one out from the generic .xmega part into + the individual Xmega A parts. 2012-04-19 Joerg Wunsch - bug #29019: pagel/bs2 warning when uploading using stk500 to xmega - * stk500.c (stk500_initialize): Insert dummy values for PAGEL and - BS2 if they are not present in the config file, in order to be able - to proceed with the stk500_set_extended_parms() anyway. + bug #29019: pagel/bs2 warning when uploading using stk500 to xmega + * stk500.c (stk500_initialize): Insert dummy values for PAGEL and + BS2 if they are not present in the config file, in order to be able + to proceed with the stk500_set_extended_parms() anyway. 2012-04-19 Joerg Wunsch - * stk500v2_private.h (struct pdata): add boot_start - * stk500v2.c: For the "flash" pseudo-memory of Xmega devices, - distinguish addresses between "application" and "boot" area. + * stk500v2_private.h (struct pdata): add boot_start + * stk500v2.c: For the "flash" pseudo-memory of Xmega devices, + distinguish addresses between "application" and "boot" area. 2012-04-18 Joerg Wunsch - * fileio.c (elf2b): When checking the bounds of the current - program header segment, subtract `low' from ph[n].p_paddr in order - to correct the magic section offsets for the AVR's non-flash - memory regions. + * fileio.c (elf2b): When checking the bounds of the current + program header segment, subtract `low' from ph[n].p_paddr in order + to correct the magic section offsets for the AVR's non-flash + memory regions. 2012-04-18 Joerg Wunsch - * fileio.c (elf_get_scn): Rather than trying to just match whether - any given section maps straight to a program header segment, use a - more sophisticated decision that matches any section as long as it - fits into the segment. This is needed for situations where the - program header segment spans a larger area than the section data - provided. (This can e.g. happen in an ELF file that contains no - data at address 0, like a bootloader only.) + * fileio.c (elf_get_scn): Rather than trying to just match whether + any given section maps straight to a program header segment, use a + more sophisticated decision that matches any section as long as it + fits into the segment. This is needed for situations where the + program header segment spans a larger area than the section data + provided. (This can e.g. happen in an ELF file that contains no + data at address 0, like a bootloader only.) 2012-04-13 Joerg Wunsch - bug #28744: Can't load bootloader to xmega128a1 (part 2, fix for - firmware >= V7.x) - * jtagmkII.c: Add firmware-version dependent handling of Xmega parameters. - V7.x firmware expects the NVM offsets being specified through the Xmega - parameters command, but left out as part of the memory address itself. - * jtagmkII_private.h: Add CMND_SET_XMEGA_PARAMS, and struct xmega_device_desc. - * config_gram.y: Add mcu_base keyword. - * avrpart.h: (Dito.) - * lexer.l: (Dito.) - * avrdude.conf.in (.xmega): add mcu_base, and data memory segment. + bug #28744: Can't load bootloader to xmega128a1 (part 2, fix for + firmware >= V7.x) + * jtagmkII.c: Add firmware-version dependent handling of Xmega parameters. + V7.x firmware expects the NVM offsets being specified through the Xmega + parameters command, but left out as part of the memory address itself. + * jtagmkII_private.h: Add CMND_SET_XMEGA_PARAMS, and struct xmega_device_desc. + * config_gram.y: Add mcu_base keyword. + * avrpart.h: (Dito.) + * lexer.l: (Dito.) + * avrdude.conf.in (.xmega): add mcu_base, and data memory segment. 2012-03-30 Joerg Wunsch - bug #28744: Can't load bootloader to xmega128a1 (part 1, fix for - firmware < V7.x) - * jtagmkII.c: When going to write to the boot section of flash, - use MTYPE_BOOT_FLASH rather than MTYPE_FLASH - * jtagmkII_private.h: add MTYPE_BOOT_FLASH constant + bug #28744: Can't load bootloader to xmega128a1 (part 1, fix for + firmware < V7.x) + * jtagmkII.c: When going to write to the boot section of flash, + use MTYPE_BOOT_FLASH rather than MTYPE_FLASH + * jtagmkII_private.h: add MTYPE_BOOT_FLASH constant 2012-03-30 Joerg Wunsch - * jtagmkII_private.h: Sort commands, response codes and events - into numerical order. + * jtagmkII_private.h: Sort commands, response codes and events + into numerical order. 2012-03-29 Joerg Wunsch - bug #30451: Accessing some Xmega memory sections gives not - supported error - * stk500v2.c: Handle all Xmega memory sections (except - "prodsig" which is not documented in AVR079) - * fileio.c: Treat the "boot", "application", and "apptable" - regions (which are actually subregions of "flash") all as - being flash, i.e. suppress trailing 0xFF bytes when reading - them - * avr.c: (Dito.) + bug #30451: Accessing some Xmega memory sections gives not + supported error + * stk500v2.c: Handle all Xmega memory sections (except + "prodsig" which is not documented in AVR079) + * fileio.c: Treat the "boot", "application", and "apptable" + regions (which are actually subregions of "flash") all as + being flash, i.e. suppress trailing 0xFF bytes when reading + them + * avr.c: (Dito.) 2012-03-20 Joerg Wunsch - * jtagmkII.c (jtagmkII_close): The GO command before signing off - turned out to be not required for normal megaAVR devices, and to - cause the exact opposite (i.e. the target stopping) on Xmega - devices being programmed to JTAG. However, programming Xmega - devcies through PDI *does* need the GO command. + * jtagmkII.c (jtagmkII_close): The GO command before signing off + turned out to be not required for normal megaAVR devices, and to + cause the exact opposite (i.e. the target stopping) on Xmega + devices being programmed to JTAG. However, programming Xmega + devcies through PDI *does* need the GO command. 2012-03-20 Joerg Wunsch - * configure.ac: Print a configuration summary at the end of the - configure run + * configure.ac: Print a configuration summary at the end of the + configure run 2012-02-11 Rene Liebscher - patch #7718: Merge global data of avrftdi in a private data structure - * avrftdi.[ch]: moved global data into private data structure, moved - private defines from header file into source file + patch #7718: Merge global data of avrftdi in a private data structure + * avrftdi.[ch]: moved global data into private data structure, moved + private defines from header file into source file 2012-02-06 Rene Liebscher - patch #7720 Bug in EEPROM write - * avrftdi.c: fixed wrong buffer address initialization in paged_write - * fileio.c: added #include + patch #7720 Bug in EEPROM write + * avrftdi.c: fixed wrong buffer address initialization in paged_write + * fileio.c: added #include 2012-02-05 Rene Liebscher - bug #30559 Ft232 bit-bang support - * ft245r.c: cancel reader thread before exiting program + bug #30559 Ft232 bit-bang support + * ft245r.c: cancel reader thread before exiting program 2012-02-04 Rene Liebscher - patch #7717 avrftdi_flash_write is broken - * avrftdi.c: fixed wrong buffer address initialization in paged_write - bug #35296 Extraneous newlines in output. - * main.c: fixed output of newlines at 100% progress + patch #7717 avrftdi_flash_write is broken + * avrftdi.c: fixed wrong buffer address initialization in paged_write + bug #35296 Extraneous newlines in output. + * main.c: fixed output of newlines at 100% progress 2012-02-03 Rene Liebscher - patch #7715 FT4232H support - * avrdude.conf.in: added programmer 4232h + patch #7715 FT4232H support + * avrdude.conf.in: added programmer 4232h 2012-02-03 Rene Liebscher - patch #7687: Autogenerating programmers and parts lists for docs - (generating the programmers lists) - * doc/avrdude.texi: Add include of generated table of programmers - * doc/Makefile.am: Add generating of table of programmers in programmers.texi + patch #7687: Autogenerating programmers and parts lists for docs + (generating the programmers lists) + * doc/avrdude.texi: Add include of generated table of programmers + * doc/Makefile.am: Add generating of table of programmers in programmers.texi 2012-02-03 Rene Liebscher - bug #34768 Proposition: Change the name of the AVR32 devices - * avrdude.conf.in: renamed ucr2 to uc3a0512 - * avrpart.c: added cast to avoid compiler warning + bug #34768 Proposition: Change the name of the AVR32 devices + * avrdude.conf.in: renamed ucr2 to uc3a0512 + * avrpart.c: added cast to avoid compiler warning 2012-02-03 Joerg Wunsch - * fileio.c (fileio_elf): Fix a copy'n-paste-o. + * fileio.c (fileio_elf): Fix a copy'n-paste-o. 2012-02-03 Joerg Wunsch - * par.c (par_desc): Move to end of file, outside the #if - HAVE_PARPORT + * par.c (par_desc): Move to end of file, outside the #if + HAVE_PARPORT 2012-02-02 Joerg Wunsch - Implement ELF file reading (finally). Requires libelf(3) to be - present on the host system. - * configure.ac (HAVE_LIBELF): Add logic to detect presence of - libelf(3) - * Makefile.am (avrdude_LDADD): Add @LIBELF@ - * fileio.h (FILEFMT): add FMT_ELF - * fileio.c: Implement ELF file reader. - * update.c (parse_op): add 'e' format specifier - * avrdude.1: Document the ELF file reading capability - * doc/avrdude.texi: (Dito.) + Implement ELF file reading (finally). Requires libelf(3) to be + present on the host system. + * configure.ac (HAVE_LIBELF): Add logic to detect presence of + libelf(3) + * Makefile.am (avrdude_LDADD): Add @LIBELF@ + * fileio.h (FILEFMT): add FMT_ELF + * fileio.c: Implement ELF file reader. + * update.c (parse_op): add 'e' format specifier + * avrdude.1: Document the ELF file reading capability + * doc/avrdude.texi: (Dito.) 2012-02-01 Rene Liebscher - bug #30559 Ft232 bit-bang support - * ft245r.[ch]: new programmer type implementation - * configure.ac: add pthread as link library - * avrdude.conf.in: added some new programmers - * Makefile.am: added new source files to compile - * pindefs.h: change PIN_MASK, PIN_INVERSE to highest bit of unsigned int - * pgm.[ch]: added generic function to print pin assignments (taken from par.c) - * par.c: moved pin assigment print function to pgm.c + bug #30559 Ft232 bit-bang support + * ft245r.[ch]: new programmer type implementation + * configure.ac: add pthread as link library + * avrdude.conf.in: added some new programmers + * Makefile.am: added new source files to compile + * pindefs.h: change PIN_MASK, PIN_INVERSE to highest bit of unsigned int + * pgm.[ch]: added generic function to print pin assignments (taken from par.c) + * par.c: moved pin assigment print function to pgm.c 2012-02-01 Joerg Wunsch - * lexer.l: Sort keyword tokens into alphabetic order. + * lexer.l: Sort keyword tokens into alphabetic order. 2012-01-31 Rene Liebscher - * config_gram.y, lexer.l: removed unused ID/TKN_ID definitions - * config.[hc]: removed unused function id(), use value.type to select - values + * config_gram.y, lexer.l: removed unused ID/TKN_ID definitions + * config.[hc]: removed unused function id(), use value.type to select + values 2012-01-31 Rene Liebscher - patch #7437 modifications to Bus Pirate module - patch #7686 Updating buspirate ascii mode to current firmware, use AUX - as clock generator, and setting of serial receive timeout - * buspirate.c: added paged_write, changed binary mode setup/detection, - added clock output on AUX pin - * avrdude.1: updated documentation - * doc/avrdude.texi: updated documentation + patch #7437 modifications to Bus Pirate module + patch #7686 Updating buspirate ascii mode to current firmware, use AUX + as clock generator, and setting of serial receive timeout + * buspirate.c: added paged_write, changed binary mode setup/detection, + added clock output on AUX pin + * avrdude.1: updated documentation + * doc/avrdude.texi: updated documentation 2012-01-31 Rene Liebscher - Parser does not need to know all programmer types now, new programmers - will update only the table in pgm_type.c. - * config_gram.y, lexer.l: removed programmer type keywords, - use now locate_programmer_type() function - * pgm_type.[ch]: added new files for table of programmer types - * main.c: allow list of programmer types by -c ?type - * avrdude.conf.in: changed all type keywords to quoted strings - * doc/avrdude.texi: changed description of type definition, list - of valid types is now included from generated file - * doc/Makefile.am: generate list of programmer types for doc - * all programmers [hc]: add xxx_desc string for description of programmer + Parser does not need to know all programmer types now, new programmers + will update only the table in pgm_type.c. + * config_gram.y, lexer.l: removed programmer type keywords, + use now locate_programmer_type() function + * pgm_type.[ch]: added new files for table of programmer types + * main.c: allow list of programmer types by -c ?type + * avrdude.conf.in: changed all type keywords to quoted strings + * doc/avrdude.texi: changed description of type definition, list + of valid types is now included from generated file + * doc/Makefile.am: generate list of programmer types for doc + * all programmers [hc]: add xxx_desc string for description of programmer 2012-01-30 Rene Liebscher - * configure.ac: fixed detection of yylex_destroy availability - by checking the version number of flex; bump required autoconf - version to 2.60 (for AC_PROG_SED) + * configure.ac: fixed detection of yylex_destroy availability + by checking the version number of flex; bump required autoconf + version to 2.60 (for AC_PROG_SED) 2012-01-30 Joerg Wunsch - * lexer.l: Replace the old, now-defunct #define YY_NO_UNPUT by - the new %option nounput. This gets rid of a compiler warning. + * lexer.l: Replace the old, now-defunct #define YY_NO_UNPUT by + the new %option nounput. This gets rid of a compiler warning. 2012-01-30 Joerg Wunsch - Add a connection_type attribute to each programmer, rather than - trying to hard-code the default port name in main.c. - * pgm.h: Add conntype to struct pgm. - * lexer.l: Extend grammar for connection_type. - * config_gram.y: (Dito.) - * config.h: Add DEFAULT_USB, for symmetry with default_parallel - and default_serial. - * main.c: Replace old default portname hack by avrdude.conf-based - knowledge. - * usbtiny.c: Drop an old hack that's no longer necessary. - * avrdude.conf.in: Add connection_type to each programmer - definition. + Add a connection_type attribute to each programmer, rather than + trying to hard-code the default port name in main.c. + * pgm.h: Add conntype to struct pgm. + * lexer.l: Extend grammar for connection_type. + * config_gram.y: (Dito.) + * config.h: Add DEFAULT_USB, for symmetry with default_parallel + and default_serial. + * main.c: Replace old default portname hack by avrdude.conf-based + knowledge. + * usbtiny.c: Drop an old hack that's no longer necessary. + * avrdude.conf.in: Add connection_type to each programmer + definition. 2012-01-27 Rene Liebscher - * avrdude.conf.in: used parent parts for some other parts, added - abstract .xmega part as parent for xmegas - * main.c: hide parts starting with '.' from parts list + * avrdude.conf.in: used parent parts for some other parts, added + abstract .xmega part as parent for xmegas + * main.c: hide parts starting with '.' from parts list 2012-01-22 Rene Liebscher - patch #7688: Implement parent programmers feature - * avrdude.conf.in: updated documentation comment and some programmers - have now parents - * config_gram.y: initpgm will now called at first use of programmer - in main. parser sets only the function pointer in the pgm structure. - Pin and pin lists definitions can now be empty to remove the parents - setting. - * doc/avrdude.texi: updated documentation - * main.c: added call to pgm->initpgm after locate_programmer - * pgm.[hc]: added field initpgm in structure, added function pgm_dup + patch #7688: Implement parent programmers feature + * avrdude.conf.in: updated documentation comment and some programmers + have now parents + * config_gram.y: initpgm will now called at first use of programmer + in main. parser sets only the function pointer in the pgm structure. + Pin and pin lists definitions can now be empty to remove the parents + setting. + * doc/avrdude.texi: updated documentation + * main.c: added call to pgm->initpgm after locate_programmer + * pgm.[hc]: added field initpgm in structure, added function pgm_dup 2012-01-21 Rene Liebscher - bug #21797: AT90PWM316: New part description - * avrdude.conf.in: added pwm316 with parent pwm3b but 16KB flash + bug #21797: AT90PWM316: New part description + * avrdude.conf.in: added pwm316 with parent pwm3b but 16KB flash 2012-01-20 Joerg Wunsch - * configure.ac: Check for presence of lusb_usb.h as an alternative - to usb.h; libusb-win32 switched to this name in version 1.2.5.0. - * avrftdi.c: Decide whether to include , or . - * ser_avrdoper.c: (Dito.) - * usbasp.c: (Dito.) - * usb_libusb.c: (Dito.) - * usbtiny.c: (Dito.) + * configure.ac: Check for presence of lusb_usb.h as an alternative + to usb.h; libusb-win32 switched to this name in version 1.2.5.0. + * avrftdi.c: Decide whether to include , or . + * ser_avrdoper.c: (Dito.) + * usbasp.c: (Dito.) + * usb_libusb.c: (Dito.) + * usbtiny.c: (Dito.) 2012-01-19 Rene Liebscher - * avr.c: Unsigned variable was used for return code of paged_write/load - functions. So a negative return code led never to a fallback to byte - functions. + * avr.c: Unsigned variable was used for return code of paged_write/load + functions. So a negative return code led never to a fallback to byte + functions. 2012-01-17 Rene Liebscher - bug #34302: Feature request : device configuration with parent classes - * config_gram.y: if memory section is overwritten old entry is removed - - (not in original patch) - * config_gram.y: if programmer or part is defined twice, a warning is - output and the first instance is removed - - General cleanup and free functions, so valgrind does not report any lost - blocks at program end. - * avrpart.[hc]: added avr_free_(opcode|mem|part) functions - * pgm.[hc]: added pgm_free function - * update.[hc]: added free_update functions - * config.[hc]: added cleanup_config function, use yylex_destroy to reset - the lexer after usage. (So it can be reused.) - * main.c: add cleanup_main function which is called by atexit() (This - frees all lists so that at program exit only really lost memory is - reported by valgrind.) - * usbasp.c: added libusb_free_device_list() and libusb_exit() calls to - avoid lost memory - * buspirate.c: moved memory allocation from initpgm to setup and added - free in teardown - * configure.ac: add definition of HAVE_YYLEX_DESTROY if $LEX is flex. - * Makefile.am: added . in front of SUBDIRS to build avrdude before trying - to use it for creating the part list for the docs. + bug #34302: Feature request : device configuration with parent classes + * config_gram.y: if memory section is overwritten old entry is removed + + (not in original patch) + * config_gram.y: if programmer or part is defined twice, a warning is + output and the first instance is removed + + General cleanup and free functions, so valgrind does not report any lost + blocks at program end. + * avrpart.[hc]: added avr_free_(opcode|mem|part) functions + * pgm.[hc]: added pgm_free function + * update.[hc]: added free_update functions + * config.[hc]: added cleanup_config function, use yylex_destroy to reset + the lexer after usage. (So it can be reused.) + * main.c: add cleanup_main function which is called by atexit() (This + frees all lists so that at program exit only really lost memory is + reported by valgrind.) + * usbasp.c: added libusb_free_device_list() and libusb_exit() calls to + avoid lost memory + * buspirate.c: moved memory allocation from initpgm to setup and added + free in teardown + * configure.ac: add definition of HAVE_YYLEX_DESTROY if $LEX is flex. + * Makefile.am: added . in front of SUBDIRS to build avrdude before trying + to use it for creating the part list for the docs. 2012-01-17 Rene Liebscher - * usbasp.c: USB vid/pid/vendor/product from config file are used, for - id "usbasp" nibobee and old usbasp are tried as they were currently - implemented within usbasp - * avrdude.conf.in: added usb params to "usbasp", added new entry "nibobee" - with params which were hardcoded in usbasp.c, and added an entry - "usbasb-clone" which only checks vid/pid. + * usbasp.c: USB vid/pid/vendor/product from config file are used, for + id "usbasp" nibobee and old usbasp are tried as they were currently + implemented within usbasp + * avrdude.conf.in: added usb params to "usbasp", added new entry "nibobee" + with params which were hardcoded in usbasp.c, and added an entry + "usbasb-clone" which only checks vid/pid. 2012-01-10 Rene Liebscher - bug #35261 avrftdi uses wrong interface in avrftdi_paged_(write|load) - * avrftdi.c: Fixed interface and implementation of avrftdi_paged_(write|load) - patch #7672 adding support for O-Link (FTDI based JTAG) as programmer - * avrdude.conf.in: added o-link entry + bug #35261 avrftdi uses wrong interface in avrftdi_paged_(write|load) + * avrftdi.c: Fixed interface and implementation of avrftdi_paged_(write|load) + patch #7672 adding support for O-Link (FTDI based JTAG) as programmer + * avrdude.conf.in: added o-link entry 2012-01-10 Rene Liebscher - patch #7699 Read additional config files - * main.c: Added reading of additional config files - * avrdude.1: updated man page - * doc/avrdude.texi: updated documentation + patch #7699 Read additional config files + * main.c: Added reading of additional config files + * avrdude.1: updated man page + * doc/avrdude.texi: updated documentation 2012-01-10 Joerg Wunsch - Submitted by Bob Frazier: - bug #35208: avrdude 5.11 on freebsd 8.2-STABLE does not reset - Arduino Uno properly - * arduino.c (arduino_open): Bump the timeout between pulling - the DTR and RTS lines low and high. + Submitted by Bob Frazier: + bug #35208: avrdude 5.11 on freebsd 8.2-STABLE does not reset + Arduino Uno properly + * arduino.c (arduino_open): Bump the timeout between pulling + the DTR and RTS lines low and high. 2012-01-08 Rene Liebscher - Fixed following findings reported by cppcheck - * avr910.c:625 (error) Possible null pointer dereference: cmd - otherwise it is redundant to check if cmd is null at line 624 - * avr910.c:626 (error) Possible null pointer dereference: cmd - otherwise it is redundant to check if cmd is null at line 624 - * avr910.c:168 (information) The scope of the variable 'devtype_1st' can be reduced - * avr910.c:169 (information) The scope of the variable 'dev_supported' can be reduced - * avrftdi.c:647 (error) Using sizeof for array given as function argument returns the size of pointer. - * stk500v2.c:3347 (error) Memory leak: b - * stk500v2.c:3452 (error) Memory leak: b - * usbasp.c:554 (error) Using sizeof for array given as function argument returns the size of pointer. - * usbasp.c:485 (information) The scope of the variable 'dly' can be reduced + Fixed following findings reported by cppcheck + * avr910.c:625 (error) Possible null pointer dereference: cmd - otherwise it is redundant to check if cmd is null at line 624 + * avr910.c:626 (error) Possible null pointer dereference: cmd - otherwise it is redundant to check if cmd is null at line 624 + * avr910.c:168 (information) The scope of the variable 'devtype_1st' can be reduced + * avr910.c:169 (information) The scope of the variable 'dev_supported' can be reduced + * avrftdi.c:647 (error) Using sizeof for array given as function argument returns the size of pointer. + * stk500v2.c:3347 (error) Memory leak: b + * stk500v2.c:3452 (error) Memory leak: b + * usbasp.c:554 (error) Using sizeof for array given as function argument returns the size of pointer. + * usbasp.c:485 (information) The scope of the variable 'dly' can be reduced 2012-01-03 Joerg Wunsch - Reported by Jason Kotzin: - * usbasp.c (usbasp_spi_paged_load, usbasp_spi_paged_write): - Fix buffer address calculation. + Reported by Jason Kotzin: + * usbasp.c (usbasp_spi_paged_load, usbasp_spi_paged_write): + Fix buffer address calculation. 2012-01-03 Rene Liebscher - patch #7629 add support for atmega48p - * avrdude.conf.in: Added m48p with parent m48 + different signature - - * avrdude.conf.in: made part parents (m88p = m88 + different signature, - m168p = m168 + different signature) + patch #7629 add support for atmega48p + * avrdude.conf.in: Added m48p with parent m48 + different signature + + * avrdude.conf.in: made part parents (m88p = m88 + different signature, + m168p = m168 + different signature) 2012-01-02 Rene Liebscher - bug #21663 AT90PWM efuse incorrect - bug #30438 efuse bits written as 0 on at90pwmxx parts - * avrdude.conf.in: (pwm2, pwm2b, pwm3, pwm3b) : Write - eight bits - - * avrdude.conf.in: made part parents (pwm3 = pwm2, pwm3b = pwm2b, - pwm2b = pwm2 + different signature) - - * ChangeLog-2011: New file, rotate ChangeLog for new year. + bug #21663 AT90PWM efuse incorrect + bug #30438 efuse bits written as 0 on at90pwmxx parts + * avrdude.conf.in: (pwm2, pwm2b, pwm3, pwm3b) : Write + eight bits + + * avrdude.conf.in: made part parents (pwm3 = pwm2, pwm3b = pwm2b, + pwm2b = pwm2 + different signature) + + * ChangeLog-2011: New file, rotate ChangeLog for new year. diff --git a/src/avrdude/ChangeLog-2013 b/src/avrdude/ChangeLog-2013 index 8e975ef6e9a..48739b7c201 100644 --- a/src/avrdude/ChangeLog-2013 +++ b/src/avrdude/ChangeLog-2013 @@ -1,618 +1,618 @@ 2013-12-15 Nils Springob - * pgm.c/pgm.h: fixed syntax error in const pointer to const + * pgm.c/pgm.h: fixed syntax error in const pointer to const 2013-12-05 Joerg Wunsch - * configure.ac: bump version to 6.1-svn-20131205 + * configure.ac: bump version to 6.1-svn-20131205 2013-12-05 Joerg Wunsch - bug #40817: Elf file support (possibly) not working on 6.0.1 windows build - * fileio.c (fileio): open file in binary mode also for FMT_ELF + bug #40817: Elf file support (possibly) not working on 6.0.1 windows build + * fileio.c (fileio): open file in binary mode also for FMT_ELF 2013-12-04 Rene Liebscher - Rework of bitbanging functions setpin, getpin, highpulsepin to make simplier use - of new pindefs data in pgm structure - * linuxgpio.c, bitbang.c, buspirate.c, par.c, pgm.h, term.c, serbb_*.c: changed - interface of setpin, getpin, highpulsepin to take pin function as parameter - (not the real number, which can be found by pgm->pinno[function]) + Rework of bitbanging functions setpin, getpin, highpulsepin to make simplier use + of new pindefs data in pgm structure + * linuxgpio.c, bitbang.c, buspirate.c, par.c, pgm.h, term.c, serbb_*.c: changed + interface of setpin, getpin, highpulsepin to take pin function as parameter + (not the real number, which can be found by pgm->pinno[function]) 2013-11-30 Rene Liebscher - bug #40748 linuxgpio doesn't work on Raspberry PI rev. 2. - * linuxgpio.c: fixed check for unused pins to ignore the inverse flag - * pindefs.c: fixed fill_old_pinlist to not create an empty mask with inverse flag set + bug #40748 linuxgpio doesn't work on Raspberry PI rev. 2. + * linuxgpio.c: fixed check for unused pins to ignore the inverse flag + * pindefs.c: fixed fill_old_pinlist to not create an empty mask with inverse flag set 2013-10-18 Nils Springob - * avrdude.conf.in (atmega1284): ATmega1284 variant added (same as ATmega1284p but with different signature) + * avrdude.conf.in (atmega1284): ATmega1284 variant added (same as ATmega1284p but with different signature) 2013-09-25 Hannes Weisbach - First part of patch #7720: - * avrdude.conf.in: Add UM232H and C232H programmers + First part of patch #7720: + * avrdude.conf.in: Add UM232H and C232H programmers 2013-09-22 Joerg Wunsch - Submitted by Daniel Rozsnyo: - bug #40085: Typo fix in fuses report (for 6.1-svn-20130917) - * main.c: Fix a typo. + Submitted by Daniel Rozsnyo: + bug #40085: Typo fix in fuses report (for 6.1-svn-20130917) + * main.c: Fix a typo. 2013-09-19 Hannes Weisbach - task #12798: Please cleanup #ifdef notyet entries in avrftdi.c - * avrftdi.c: ditto. - avrftdi.c: Remove DRYRUN-option. + task #12798: Please cleanup #ifdef notyet entries in avrftdi.c + * avrftdi.c: ditto. + avrftdi.c: Remove DRYRUN-option. 2013-09-17 Joerg Wunsch - bug #40055: AVRDUDE segfaults when writing eeprom - * main.c: Always clear the UF_AUTO_ERASE flag if either a - non-Xmega device was found, or the programmer does not offer a - page_erase method. + bug #40055: AVRDUDE segfaults when writing eeprom + * main.c: Always clear the UF_AUTO_ERASE flag if either a + non-Xmega device was found, or the programmer does not offer a + page_erase method. 2013-09-17 Joerg Wunsch - * configure.ac (AC_INIT): Bump version to post-6.0. + * configure.ac (AC_INIT): Bump version to post-6.0. 2013-09-17 Joerg Wunsch - * configure.ac (AC_INIT): Bump version to 6.0. + * configure.ac (AC_INIT): Bump version to 6.0. 2013-09-17 Joerg Wunsch - * jtag3.c (jtag3_initialize): Fix a buffer overflow by limiting - the flash page cache size to at most "readsize". For Xmegas with - a page size of 512 bytes, the maximum USB packet size was - overflowed, and subsequently, a memmove copied beyond the end of - the allocated buffer. - * jtag3.c (jtag3_read_byte): Add the correct offset also for the - various flash regions, so reading the apptable or boot regions - yields the correct data. + * jtag3.c (jtag3_initialize): Fix a buffer overflow by limiting + the flash page cache size to at most "readsize". For Xmegas with + a page size of 512 bytes, the maximum USB packet size was + overflowed, and subsequently, a memmove copied beyond the end of + the allocated buffer. + * jtag3.c (jtag3_read_byte): Add the correct offset also for the + various flash regions, so reading the apptable or boot regions + yields the correct data. 2013-09-16 Joerg Wunsch - Submitted by Joakim Lubeck: - bug #40040: Support for ATtiny20 and ATtiny40 - * avrdude.conf.in: Restructure the reduced-core tiny devices - to use a common entry .reduced_core_tiny; add ATtiny20 and - ATtiny40 + Submitted by Joakim Lubeck: + bug #40040: Support for ATtiny20 and ATtiny40 + * avrdude.conf.in: Restructure the reduced-core tiny devices + to use a common entry .reduced_core_tiny; add ATtiny20 and + ATtiny40 2013-09-15 Joerg Wunsch - Submitted by Joakim Lubeck: - bug #40033: Support for the XMegaE5 family - * avrdude.conf.in (ATxmega8E5, ATxmega16E5, ATxmega32E5): New - entries. + Submitted by Joakim Lubeck: + bug #40033: Support for the XMegaE5 family + * avrdude.conf.in (ATxmega8E5, ATxmega16E5, ATxmega32E5): New + entries. 2013-09-13 Joerg Wunsch - * stk500v2.c (stk500v2_set_sck_period): Revamp this to match the - description/pseudo-code in appnote AVR068. + * stk500v2.c (stk500v2_set_sck_period): Revamp this to match the + description/pseudo-code in appnote AVR068. 2013-09-13 Joerg Wunsch - Submitted by Stephen Roe: - patch #7710: usb_libusb: Check VID/PID before opening device - * usb_libusb.c (usbdev_open): Swap the sequence of verifying the - VID:PID, and opening the device. + Submitted by Stephen Roe: + patch #7710: usb_libusb: Check VID/PID before opening device + * usb_libusb.c (usbdev_open): Swap the sequence of verifying the + VID:PID, and opening the device. 2013-09-13 Joerg Wunsch - patch #8176: butterfly.c (AVR109 protocol implementation) clean-up and bug-fixing - * butterfly.c (butterfly_page_erase): Add dummy function to avoid - segfault when writing to EEPROM. + patch #8176: butterfly.c (AVR109 protocol implementation) clean-up and bug-fixing + * butterfly.c (butterfly_page_erase): Add dummy function to avoid + segfault when writing to EEPROM. 2013-09-13 Joerg Wunsch - bug #35474 Feature request: print fuse values in safemode output - * config_gram.y: New configuration token "default_safemode". - * lexer.l: (Dito.) - * avrdude.conf.in: (Dito.) - * config.h: Add variable default_safemode. - * config.c: (Dito.) - * main.c: Handle default_safemode, including -u option. - * avrdude.1: Document all this. - * doc/avrdude.texi: (Dito.) + bug #35474 Feature request: print fuse values in safemode output + * config_gram.y: New configuration token "default_safemode". + * lexer.l: (Dito.) + * avrdude.conf.in: (Dito.) + * config.h: Add variable default_safemode. + * config.c: (Dito.) + * main.c: Handle default_safemode, including -u option. + * avrdude.1: Document all this. + * doc/avrdude.texi: (Dito.) 2013-09-13 Joerg Wunsch - Submitted by HubertB: - patch #7657 Add ATmega406 support for avrdude using DRAGON + JTAG - * avrdude.conf.in (ATmega406): New entry. + Submitted by HubertB: + patch #7657 Add ATmega406 support for avrdude using DRAGON + JTAG + * avrdude.conf.in (ATmega406): New entry. 2013-09-13 Joerg Wunsch - Submitted by Marc de Hoop: - patch #7606 ATtiny43u support - * avrdude.conf.in (ATtiny43U): New entry. + Submitted by Marc de Hoop: + patch #7606 ATtiny43u support + * avrdude.conf.in (ATtiny43U): New entry. 2013-09-13 Joerg Wunsch - patch #5708 avrdude should make 10 synchronization attempts instead of just one - * stk500.c (stk500_getsync): Loop 10 times trying to get in - sync with the programmer. + patch #5708 avrdude should make 10 synchronization attempts instead of just one + * stk500.c (stk500_getsync): Loop 10 times trying to get in + sync with the programmer. 2013-09-13 Joerg Wunsch - Contributed by Ricardo Martins: - bug #36384 ATxmega32A4 usersig size - * avrdude.conf.in: Revamp all the ATxmega* entries. Add new - entries for ATxmega128A1U, ATxmega128A3U, ATxmega128A4U, - ATxmega128B1, ATxmega128B3, ATxmega128C3, ATxmega128D3, - ATxmega16A4U, ATxmega16C4, ATxmega192A3U, ATxmega192C3, - ATxmega192D3, ATxmega256A3BU, ATxmega256A3U, ATxmega256C3, - ATxmega256D3, ATxmega32A4U, ATxmega32C4, ATxmega384C3, - ATxmega384D3, ATxmega64A1U, ATxmega64A3U, ATxmega64A4U, - ATxmega64B1, ATxmega64B3, ATxmega64C3, ATxmega64D3 + Contributed by Ricardo Martins: + bug #36384 ATxmega32A4 usersig size + * avrdude.conf.in: Revamp all the ATxmega* entries. Add new + entries for ATxmega128A1U, ATxmega128A3U, ATxmega128A4U, + ATxmega128B1, ATxmega128B3, ATxmega128C3, ATxmega128D3, + ATxmega16A4U, ATxmega16C4, ATxmega192A3U, ATxmega192C3, + ATxmega192D3, ATxmega256A3BU, ATxmega256A3U, ATxmega256C3, + ATxmega256D3, ATxmega32A4U, ATxmega32C4, ATxmega384C3, + ATxmega384D3, ATxmega64A1U, ATxmega64A3U, ATxmega64A4U, + ATxmega64B1, ATxmega64B3, ATxmega64C3, ATxmega64D3 2013-09-13 Joerg Wunsch - bug #35456 The progress bar for STK500V2 programmer is "wrong". - * avr.c (avr_read, avr_write): Change the progress reporting for - paged read/write from per-address to per-considered-page. This - ought to give a realistic estimation about the time still to be - spent. + bug #35456 The progress bar for STK500V2 programmer is "wrong". + * avr.c (avr_read, avr_write): Change the progress reporting for + paged read/write from per-address to per-considered-page. This + ought to give a realistic estimation about the time still to be + spent. 2013-09-13 Joerg Wunsch - bug #34277: avrdude reads wrong byte order if using avr911 (aka butterfly) - * butterfly.c (butterfly_read_byte_flash): Swap bytes received. + bug #34277: avrdude reads wrong byte order if using avr911 (aka butterfly) + * butterfly.c (butterfly_read_byte_flash): Swap bytes received. 2013-09-12 Joerg Wunsch - bug #37768 Poll usbtiny 100 times at init time to handle low-clock devices - * doc/avrdude.texi: Add a FAQ entry about how to connect to a - target where the firmware has reduced the internal clock speed. + bug #37768 Poll usbtiny 100 times at init time to handle low-clock devices + * doc/avrdude.texi: Add a FAQ entry about how to connect to a + target where the firmware has reduced the internal clock speed. 2013-09-11 Joerg Wunsch - bug #28344 chip_erase_delay too short for ATmega324P, 644, 644P, and 1284P - * avrdude.conf: Bump the chip_erase_delay for all ATmega*4 devices - to 55 ms. While the datasheet still claims 9 ms, all the XML files - tell either 45 or 55 ms, depending on STK600 or not. + bug #28344 chip_erase_delay too short for ATmega324P, 644, 644P, and 1284P + * avrdude.conf: Bump the chip_erase_delay for all ATmega*4 devices + to 55 ms. While the datasheet still claims 9 ms, all the XML files + tell either 45 or 55 ms, depending on STK600 or not. 2013-09-11 Joerg Wunsch - * fileio.c (fileio): Don't exit(1) if something goes wrong; return - -1 instead. Don't refer to obsolete option -f to specify the file - format. + * fileio.c (fileio): Don't exit(1) if something goes wrong; return + -1 instead. Don't refer to obsolete option -f to specify the file + format. 2013-09-10 Joerg Wunsch - Submitted by Matthias Trute: - bug #36901 flashing Atmega32U4 EEPROM produces garbage on chip - * avrdude.conf.in (ATmega32U4): Fix EEPROM pagesize to 4, the - datasheet is wrong here. + Submitted by Matthias Trute: + bug #36901 flashing Atmega32U4 EEPROM produces garbage on chip + * avrdude.conf.in (ATmega32U4): Fix EEPROM pagesize to 4, the + datasheet is wrong here. 2013-09-09 Joerg Wunsch - * configure.ac: check for ar and ranlib in the target tool - namespace, rather than on the host. + * configure.ac: check for ar and ranlib in the target tool + namespace, rather than on the host. 2013-09-08 Joerg Wunsch - Fix byte-wise EEPROM and flash writes on Xmega - * jtagmkII_private.h (MTYPE_EEPROM_XMEGA): New memory type. - * jtagmkII.c (jtagmkII_write_byte): For Xmega EEPROM, use - memory type MTYPE_EEPROM_XMEGA; for flash writes, always - write 2 bytes starting on an even address. + Fix byte-wise EEPROM and flash writes on Xmega + * jtagmkII_private.h (MTYPE_EEPROM_XMEGA): New memory type. + * jtagmkII.c (jtagmkII_write_byte): For Xmega EEPROM, use + memory type MTYPE_EEPROM_XMEGA; for flash writes, always + write 2 bytes starting on an even address. 2013-09-08 Joerg Wunsch - * term.c: Implement the "verbose" terminal mode command. - * avrdude.1: Document this. - * doc/avrdude.texi: (Dito.) + * term.c: Implement the "verbose" terminal mode command. + * avrdude.1: Document this. + * doc/avrdude.texi: (Dito.) 2013-09-07 Joerg Wunsch - * jtag3.c (jtag3_write_byte): Do not attempt to start the paged - algorithm for EEPROM when being connected through debugWIRE. + * jtag3.c (jtag3_write_byte): Do not attempt to start the paged + algorithm for EEPROM when being connected through debugWIRE. 2013-09-06 Joerg Wunsch - Extend the single-byte algorithm to all devices, both flash and - EEPROM. (Flash cells must have been erased before though.) - * jtag3.c (jtag3_initialize): OCDEN no longer needs to be - considered; a session with "programming" purpose is sufficient - * jtag3.c (jtag3_write_byte): Use the paged algorithm for all - flash and EEPROM areas, not just Xmega. + Extend the single-byte algorithm to all devices, both flash and + EEPROM. (Flash cells must have been erased before though.) + * jtag3.c (jtag3_initialize): OCDEN no longer needs to be + considered; a session with "programming" purpose is sufficient + * jtag3.c (jtag3_write_byte): Use the paged algorithm for all + flash and EEPROM areas, not just Xmega. 2013-09-05 Joerg Wunsch - Fix single-byte EEPROM updates on Xmega: - * jtag3_private.h (MTYPE_EEPROM_XMEGA): New define. - * jtag3.c (jtag3_write_byte): When updating flash or - EEPROM on Xmega devices, resort to jtag3_paged_write() - after filling and modifying the page cache. - * jtag3.c (jtag3_paged_write): use MTYPE_EEPROM_XMEGA - where appropriate. - * jtag3.c (jtag3_initialize): Open with debugging intent - for Xmega devices, so single-byte EEPROM updates will - work. + Fix single-byte EEPROM updates on Xmega: + * jtag3_private.h (MTYPE_EEPROM_XMEGA): New define. + * jtag3.c (jtag3_write_byte): When updating flash or + EEPROM on Xmega devices, resort to jtag3_paged_write() + after filling and modifying the page cache. + * jtag3.c (jtag3_paged_write): use MTYPE_EEPROM_XMEGA + where appropriate. + * jtag3.c (jtag3_initialize): Open with debugging intent + for Xmega devices, so single-byte EEPROM updates will + work. 2013-09-04 Joerg Wunsch - Submitted by Matthias Neeracher: - bug #38732: Support for ATtiny1634 - * avrdude.conf.in (ATtiny1634): New entry. + Submitted by Matthias Neeracher: + bug #38732: Support for ATtiny1634 + * avrdude.conf.in (ATtiny1634): New entry. 2013-09-03 Joerg Wunsch - Submitted by Brane Ždralo: - patch #7769: Write flash fails for AVR910 programmers - * avr910.c (avr910_paged_write): Fix flash addresses in - 'A' command. + Submitted by Brane Ždralo: + patch #7769: Write flash fails for AVR910 programmers + * avr910.c (avr910_paged_write): Fix flash addresses in + 'A' command. 2013-09-03 Joerg Wunsch - Submitted by Fred (magister): - bug #38951: AVR109 use byte offset instead of word offset - patch #8045: AVR109 butterfly failing - * butterfly.c (butterfly_paged_load, butterfly_paged_write): - fix calculation of 'A' address when operating on flash memory. - It must be given in terms of 16-bit words rather than bytes. + Submitted by Fred (magister): + bug #38951: AVR109 use byte offset instead of word offset + patch #8045: AVR109 butterfly failing + * butterfly.c (butterfly_paged_load, butterfly_paged_write): + fix calculation of 'A' address when operating on flash memory. + It must be given in terms of 16-bit words rather than bytes. 2013-09-03 Rene Liebscher - * avrftdi.c, avrftdi_private.h: added tx buffer size, and use - smaller block sizes as larger sometimes hang + * avrftdi.c, avrftdi_private.h: added tx buffer size, and use + smaller block sizes as larger sometimes hang 2013-09-03 Joerg Wunsch - * avrdude.h: Remove the erase cycle counter (options -y / -Y). - * avr.c: (Dito.) - * main.c: (Dito.) - * avrdude.1: Undocument -y / -Y. - * doc/avrdude.texi: (Dito.) + * avrdude.h: Remove the erase cycle counter (options -y / -Y). + * avr.c: (Dito.) + * main.c: (Dito.) + * avrdude.1: Undocument -y / -Y. + * doc/avrdude.texi: (Dito.) 2013-09-03 Joerg Wunsch - bug #39691 Buffer overrun when reading EEPROM byte with JTAGICE3 - * jtag3.c (jtag3_initialize): initialize the eeprom_pagesize - private attribute so the page cache will actually be usable + bug #39691 Buffer overrun when reading EEPROM byte with JTAGICE3 + * jtag3.c (jtag3_initialize): initialize the eeprom_pagesize + private attribute so the page cache will actually be usable 2013-09-03 Joerg Wunsch - bug #38580 Current svn head, xmega and fuses, all fuses tied to fuse0 - * jtag3.c (jtag3_read_byte, jtag3_write_byte): Correctly apply the - relevant part of mem->offset as the address to operate on. + bug #38580 Current svn head, xmega and fuses, all fuses tied to fuse0 + * jtag3.c (jtag3_read_byte, jtag3_write_byte): Correctly apply the + relevant part of mem->offset as the address to operate on. 2013-09-03 Joerg Wunsch - * fileio.c: Fix "unused variable" warnings. - * avr.c: (Dito.) - * stk500v2.c: (Dito.) - * stk500.c: (Dito.) - * jtagmkII.c: (Dito.) - * term.c: (Dito.) - * ser_posix.c: (Dito.) + * fileio.c: Fix "unused variable" warnings. + * avr.c: (Dito.) + * stk500v2.c: (Dito.) + * stk500.c: (Dito.) + * jtagmkII.c: (Dito.) + * term.c: (Dito.) + * ser_posix.c: (Dito.) 2013-09-02 Joerg Wunsch - Submitted by Travis Griggs: - bug #38307: Can't write usersig of an xmega256a3 - * stk500v2.c (stk600_xprog_page_erase): allow erasing the usersig space. + Submitted by Travis Griggs: + bug #38307: Can't write usersig of an xmega256a3 + * stk500v2.c (stk600_xprog_page_erase): allow erasing the usersig space. 2013-09-02 Joerg Wunsch - Submitted by Robert Niemi: - bug #35800: Compilation error on certain systems if parport is disabled - * linux_ppdev.h: Conditionalize inclusion of and - on HAVE_PARPORT + Submitted by Robert Niemi: + bug #35800: Compilation error on certain systems if parport is disabled + * linux_ppdev.h: Conditionalize inclusion of and + on HAVE_PARPORT 2013-09-02 Joerg Wunsch - bug #39794: warnings when building avrdude 6.0rc1 under CentOS 6.4 - * pickit.c (usb_open_device): Use %p rather than %X to print "handle" - which is a pointer - * jtag3.c (jtag3_initialize): Initialize "flashsize" to be sure it - proceeds with a valid value. + bug #39794: warnings when building avrdude 6.0rc1 under CentOS 6.4 + * pickit.c (usb_open_device): Use %p rather than %X to print "handle" + which is a pointer + * jtag3.c (jtag3_initialize): Initialize "flashsize" to be sure it + proceeds with a valid value. 2013-09-02 Joerg Wunsch - bug #39794: warnings when building avrdude 6.0rc1 under CentOS 6.4 - * buspirate.c: Turn the "cmd" argument of the various methods into - a "const unsigned char *"; while doing this, declare all arrays being - passed as arguments to be pointers rather than arrays, as the latter - obfuscates the way arrays are being passed to a callee in C. - * avrftdi.c: (Dito.) - * pickit2.c: (Dito.) - * ft245r.c: (Dito.) - * avr910.c: (Dito.) - * stk500.c: (Dito.) - * bitbang.c: (Dito.) - * bitbang.h: (Dito.) - * avrftdi_tpi.c: (Dito.) - * avrftdi_tpi.h: (Dito.) - * usbasp.c: (Dito.) - * stk500v2.c: (Dito.) - * pgm.h: (Dito.) - * usbtiny.c: (Dito.) + bug #39794: warnings when building avrdude 6.0rc1 under CentOS 6.4 + * buspirate.c: Turn the "cmd" argument of the various methods into + a "const unsigned char *"; while doing this, declare all arrays being + passed as arguments to be pointers rather than arrays, as the latter + obfuscates the way arrays are being passed to a callee in C. + * avrftdi.c: (Dito.) + * pickit2.c: (Dito.) + * ft245r.c: (Dito.) + * avr910.c: (Dito.) + * stk500.c: (Dito.) + * bitbang.c: (Dito.) + * bitbang.h: (Dito.) + * avrftdi_tpi.c: (Dito.) + * avrftdi_tpi.h: (Dito.) + * usbasp.c: (Dito.) + * stk500v2.c: (Dito.) + * pgm.h: (Dito.) + * usbtiny.c: (Dito.) 2013-09-02 Joerg Wunsch - bug #38023: avrdude doesn't return an error code when attempting - to upload an invalid Intel HEX file - * fileio.c (ihex2b): Turn the "No end of file record found" warning - into an error if no valid record was found at all. + bug #38023: avrdude doesn't return an error code when attempting + to upload an invalid Intel HEX file + * fileio.c (ihex2b): Turn the "No end of file record found" warning + into an error if no valid record was found at all. 2013-09-02 Joerg Wunsch - Submitted by Claus-Justus Heine: - bug #38713: Compilation of the documentation breaks with texinfo-5 - * doc/avrdude.texi: Turn @itemx into @item, add @headitem to STK600 - Routing/Socket card table + Submitted by Claus-Justus Heine: + bug #38713: Compilation of the documentation breaks with texinfo-5 + * doc/avrdude.texi: Turn @itemx into @item, add @headitem to STK600 + Routing/Socket card table 2013-09-02 Joerg Wunsch - * usbasp.c: Add trace output for -vvv to non-TPI functions, too. + * usbasp.c: Add trace output for -vvv to non-TPI functions, too. 2013-09-01 Joerg Wunsch - * usbasp.c (usbasp_tpi_paged_load): Calculate correct - buffer address. - * usbasp.c (usbasp_tpi_paged_write): Calculate correct - buffer address; don't issue a SECTION_ERASE command for - each page (a CHIP_ERASE has been done before anyway); - remove the code that attempted to handle partial page - writes, as all writes are now done with a full page. + * usbasp.c (usbasp_tpi_paged_load): Calculate correct + buffer address. + * usbasp.c (usbasp_tpi_paged_write): Calculate correct + buffer address; don't issue a SECTION_ERASE command for + each page (a CHIP_ERASE has been done before anyway); + remove the code that attempted to handle partial page + writes, as all writes are now done with a full page. 2013-09-01 Joerg Wunsch - * usbasp.c: Add more trace output, by now only for the TPI - functions. + * usbasp.c: Add more trace output, by now only for the TPI + functions. 2013-08-31 Joerg Wunsch - * usbasp.c (usbasp_transmit): Add -vvvv trace output. + * usbasp.c (usbasp_transmit): Add -vvvv trace output. 2013-08-30 Joerg Wunsch - bug #39893: Verification failure with AVRISPmkII and Xmega - * stk500v2.c (stk600_xprog_page_erase): Fix argument that is - passed to stk600_xprog_memtype() + bug #39893: Verification failure with AVRISPmkII and Xmega + * stk500v2.c (stk600_xprog_page_erase): Fix argument that is + passed to stk600_xprog_memtype() 2013-07-11 Joerg Wunsch - * fileio.c (elf2b): replace elf_getshstrndx() by - elf_getshdrstrndx() as the former one is deprecated + * fileio.c (elf2b): replace elf_getshstrndx() by + elf_getshdrstrndx() as the former one is deprecated 2013-06-19 Rene Liebscher - use bitbanging on ftdi mpsse when wrong pins are used - * avrftdi.c, avrftdi_private.h: added additional pin check - and bitbanging fallback - * pindefs.[ch]: added a flag to enable/disable output - * ft245r.c: changes because of added flag above + use bitbanging on ftdi mpsse when wrong pins are used + * avrftdi.c, avrftdi_private.h: added additional pin check + and bitbanging fallback + * pindefs.[ch]: added a flag to enable/disable output + * ft245r.c: changes because of added flag above 2013-05-17 Joerg Wunsch - Submitted by "Malte" and John McCorquodale: - patch #7876 JTAGICE mkII fails to connect to attiny if debugwire - is enabled AND target has a very slow clock - * jtagmkII.c (jtagmkII_getsync): When leaving debugWIRE mode - temporarily, immediately retry with ISP, rather than leaving. - * stk500v2 (stk500v2_program_enable): Implemented similar logic - for the JTAGICE3. + Submitted by "Malte" and John McCorquodale: + patch #7876 JTAGICE mkII fails to connect to attiny if debugwire + is enabled AND target has a very slow clock + * jtagmkII.c (jtagmkII_getsync): When leaving debugWIRE mode + temporarily, immediately retry with ISP, rather than leaving. + * stk500v2 (stk500v2_program_enable): Implemented similar logic + for the JTAGICE3. 2013-05-16 Rene Liebscher - * configure.ac: reactivate check for TYPE_232H, which does not - exist in libftdi < 0.20 - * avrftdi*.*: changed include check for libftdi/libusb, deactivate - 232H if not available - * ft245r.c: changed include check for libftdi/libusb + * configure.ac: reactivate check for TYPE_232H, which does not + exist in libftdi < 0.20 + * avrftdi*.*: changed include check for libftdi/libusb, deactivate + 232H if not available + * ft245r.c: changed include check for libftdi/libusb 2013-05-08 Joerg Wunsch - * main.c (main): Add option -l logfile. - * avrdude.1: Document -l option. - * doc/avrdude.texi: (Dito.) + * main.c (main): Add option -l logfile. + * avrdude.1: Document -l option. + * doc/avrdude.texi: (Dito.) 2013-05-15 Rene Liebscher - * configure.ac: if both found libftdi and libftdi1 use only libftdi1 - * avrdude.conf.in: fixed buff pins of avrftdi programmers (low - active buffer need now inverted numbers) - * avrftdi*.*: accept also old libftdi (0.20 still works with it), - added powerup to initialize - * ft245r.c: accept libftdi1, code cleanup and make it more similar - to avrfdti (os they might be merged someday) + * configure.ac: if both found libftdi and libftdi1 use only libftdi1 + * avrdude.conf.in: fixed buff pins of avrftdi programmers (low + active buffer need now inverted numbers) + * avrftdi*.*: accept also old libftdi (0.20 still works with it), + added powerup to initialize + * ft245r.c: accept libftdi1, code cleanup and make it more similar + to avrfdti (os they might be merged someday) 2013-05-08 Joerg Wunsch - * configure.ac (AC_INIT): Bump version to 6.0rc1. + * configure.ac (AC_INIT): Bump version to 6.0rc1. 2013-05-07 Hannes Weisbach - * avrftdi_private.h: Change size of pin_checklist to N_PINS (from N_PINS-1) - * avrftdi.c: Adapt code to new size of pin_checklist. Remove pins_check() - from set_pin(). - Add pgm->power[up|down] functions as well as fill pgm->enable|disable with - proper content as suggested by Rene Liebscher. + * avrftdi_private.h: Change size of pin_checklist to N_PINS (from N_PINS-1) + * avrftdi.c: Adapt code to new size of pin_checklist. Remove pins_check() + from set_pin(). + Add pgm->power[up|down] functions as well as fill pgm->enable|disable with + proper content as suggested by Rene Liebscher. 2013-05-05 Rene Liebscher - * pindefs.h: use unsigned int if stdint.h is not available and UINT_MAX is 0xffffffff - otherwise use unsinged long - * ft245r.c: added support for more pin functions led, vcc, buff + * pindefs.h: use unsigned int if stdint.h is not available and UINT_MAX is 0xffffffff + otherwise use unsinged long + * ft245r.c: added support for more pin functions led, vcc, buff 2013-05-06 Hannes Weisbach - * avrftdi_tpi.c: instead of private set_pin() function pointer use the one - declared in struct PROGRAMMER. - * avrftdi_private.h: remove set_pin function pointer. Add pin_checklist_t - member to check pgm->setpin calls during runtime. - * avrftdi.c: remove set_pin function pointer init, add pgm->setpin init. - Convert avrftdi to new 0-based pindefs infrastructure. - * avrdude.conf.in: Change all avrftdi-based programmers' pin definitions to - 0-based. + * avrftdi_tpi.c: instead of private set_pin() function pointer use the one + declared in struct PROGRAMMER. + * avrftdi_private.h: remove set_pin function pointer. Add pin_checklist_t + member to check pgm->setpin calls during runtime. + * avrftdi.c: remove set_pin function pointer init, add pgm->setpin init. + Convert avrftdi to new 0-based pindefs infrastructure. + * avrdude.conf.in: Change all avrftdi-based programmers' pin definitions to + 0-based. 2013-05-06 Joerg Wunsch - * pindefs.h: Include "ac_cfg.h" before testing for HAVE_* macros. + * pindefs.h: Include "ac_cfg.h" before testing for HAVE_* macros. 2013-05-05 Rene Liebscher - * main.c: revert to rev 1159 (doing pgm_display after pgm_open) - * avrpart.[ch]: moved avr_pin_name to pindefs.[ch] - * pgm.c: moved pins_to_str to pindefs.[ch], added initialization of + * main.c: revert to rev 1159 (doing pgm_display after pgm_open) + * avrpart.[ch]: moved avr_pin_name to pindefs.[ch] + * pgm.c: moved pins_to_str to pindefs.[ch], added initialization of new pin definitions in pgm_new() - * pindefs.[ch]: added moved functions from other files, added a lot of + * pindefs.[ch]: added moved functions from other files, added a lot of documentation, reformatted files using astyle to have consistent spacing, added a new generic check function for pins - * ft245r.c: used new generic pin check function + * ft245r.c: used new generic pin check function 2013-05-03 Rene Liebscher - Create new pin definition data structures to support 0-based pin numbers, - and mixed inverse/non-inverse pin lists. - * avrftdi.c,buspirate.c,linuxgpio.c,par.c,serbb_*.c: added function call + Create new pin definition data structures to support 0-based pin numbers, + and mixed inverse/non-inverse pin lists. + * avrftdi.c,buspirate.c,linuxgpio.c,par.c,serbb_*.c: added function call to fill old pinno entries from new pin definitions. - * pindefs.[hc]: added data struct and helper functions for new pin definitions - * avrdude.conf.in: pins in entries using ftdi_syncbb are now 0-based - * config_gram.y: allow combinations of inverted and non-inverted pins in pin lists - * ft245r.c: reworked to work directly with the new pin definitions, + * pindefs.[hc]: added data struct and helper functions for new pin definitions + * avrdude.conf.in: pins in entries using ftdi_syncbb are now 0-based + * config_gram.y: allow combinations of inverted and non-inverted pins in pin lists + * ft245r.c: reworked to work directly with the new pin definitions, pins are now 0-based, inverse pins are supported, buff is supported - * pgm.[ch]: added new pin definitions field to programmer structure, + * pgm.[ch]: added new pin definitions field to programmer structure, adapted pin display functions 2013-05-03 Hannes Weisbach - * avrftdi_private.h: Remove update forward declaration from avrftdi_print to - avrftdi_log. - * avrftdi_tpi.c: Do all I/O in terms of pgm->cmd_tpi()-calls instead of - avrftdi_tpi_[read,write]_byte(). - Remove unnecessary set_pin call to set MOSI high, speeds up I/O. - Removes SKEY array, moves it to tpi.h. - Integrate new avr_tpi_[program_enable,chip_erase]() and functions into - avrftdi_tpi. - * avrftdi_tpi.h: Remove avrftdi_tpi_[program_enable,chip_erase] forward - declarations. - * avr.c: Adds avr_tpi_chip_erase() generic TPI chip erase function. - Adds avr_tpi_program_enable() - generic TPI external programming enable - function. Sets guard time, reads identification register, sends SKEY command - and key, checks NVMEN bit. The required guard time has to be passed as - parameter. - * tpi.h: Adds SKEY array including CMD_SKEY in "correct" order. + * avrftdi_private.h: Remove update forward declaration from avrftdi_print to + avrftdi_log. + * avrftdi_tpi.c: Do all I/O in terms of pgm->cmd_tpi()-calls instead of + avrftdi_tpi_[read,write]_byte(). + Remove unnecessary set_pin call to set MOSI high, speeds up I/O. + Removes SKEY array, moves it to tpi.h. + Integrate new avr_tpi_[program_enable,chip_erase]() and functions into + avrftdi_tpi. + * avrftdi_tpi.h: Remove avrftdi_tpi_[program_enable,chip_erase] forward + declarations. + * avr.c: Adds avr_tpi_chip_erase() generic TPI chip erase function. + Adds avr_tpi_program_enable() - generic TPI external programming enable + function. Sets guard time, reads identification register, sends SKEY command + and key, checks NVMEN bit. The required guard time has to be passed as + parameter. + * tpi.h: Adds SKEY array including CMD_SKEY in "correct" order. 2013-05-02 Hannes Weisbach - * avrftdi_private.h: Add libusb-1.0 include to fix include order in windows. - * NEWS: Add notice avrftdi supporting TPI - * avr.c: Fix avr_tpi_poll_nvmbsy() - poll read data instead of return code - * avrftdi_private.h, avrftdi.c: move logging #defines to from avrftdi.c to - avrftdi_private.h, so that they are available for avrftdi_tpi, too. + * avrftdi_private.h: Add libusb-1.0 include to fix include order in windows. + * NEWS: Add notice avrftdi supporting TPI + * avr.c: Fix avr_tpi_poll_nvmbsy() - poll read data instead of return code + * avrftdi_private.h, avrftdi.c: move logging #defines to from avrftdi.c to + avrftdi_private.h, so that they are available for avrftdi_tpi, too. 2013-04-30 Hannes Weisbach - * tpi.h: Add definition for TPI Identification Code - * avrftdi_tpi.c: Add TPI-support for FTDI-based programmers - * avrftdi_private.h: Add common include file for FTDI-based programmers + * tpi.h: Add definition for TPI Identification Code + * avrftdi_tpi.c: Add TPI-support for FTDI-based programmers + * avrftdi_private.h: Add common include file for FTDI-based programmers 2013-04-28 Hannes Weisbach - * avrftdic: Rework of textual output. Messages are divided by severity and - printed accordingly to the verbosity, as specified by the user. The provided - severity level are (ERROR, WARN, INFO, DEBUG, TRACE). Where "ERROR" messages - are always printed. Shortcut-macros including function, from which the - output was generated, and line number were also added. - Some log messages were updated and other code warnings removed. + * avrftdic: Rework of textual output. Messages are divided by severity and + printed accordingly to the verbosity, as specified by the user. The provided + severity level are (ERROR, WARN, INFO, DEBUG, TRACE). Where "ERROR" messages + are always printed. Shortcut-macros including function, from which the + output was generated, and line number were also added. + Some log messages were updated and other code warnings removed. 2013-04-27 Hannes Weisbach - * configure.ac: Add libftdi1 library check, remove TYPE_232H DECL check - * Makefile.am: Add @LIBFTDI1@ to avrdude_LDADD - * avrftdi.c: Update from libftdi0 to libftdi1. Use libftdi1's function to - find a device by vid/pid/serial instead of doing it ourself and add/update - error messages. avrftdi_print is changed so that a message is printed when - the verbosity level is greater or equal the message level, to have always-on - messages. - Fix a bug where the RX fifo of the FTDI chip is full, resulting in STALL/NAK - of the ongoing OUT request and subsequently timeout, because an IN request - cannot be issued due to the synchronous part of libftdi. This should fix - #38831 and #38659. + * configure.ac: Add libftdi1 library check, remove TYPE_232H DECL check + * Makefile.am: Add @LIBFTDI1@ to avrdude_LDADD + * avrftdi.c: Update from libftdi0 to libftdi1. Use libftdi1's function to + find a device by vid/pid/serial instead of doing it ourself and add/update + error messages. avrftdi_print is changed so that a message is printed when + the verbosity level is greater or equal the message level, to have always-on + messages. + Fix a bug where the RX fifo of the FTDI chip is full, resulting in STALL/NAK + of the ongoing OUT request and subsequently timeout, because an IN request + cannot be issued due to the synchronous part of libftdi. This should fix + #38831 and #38659. 2013-04-25 Joerg Wunsch - * configure.ac(AC_CONFIG_HEADERS): Replace the old AM_CONFIG_HEADER - by this; automake 1.13+ barfs. + * configure.ac(AC_CONFIG_HEADERS): Replace the old AM_CONFIG_HEADER + by this; automake 1.13+ barfs. 2013-03-12 Joerg Wunsch - * avrdude.conf.in (ATmega2564RFR2, ATmega1284RFR2, ATmega644RFR2): - New devices + * avrdude.conf.in (ATmega2564RFR2, ATmega1284RFR2, ATmega644RFR2): + New devices 2013-01-30 Rene Liebscher - patch #7724 Add TPI support for Bus Pirate using bitbang mode - * buspirate.[ch]: added support for BusPirate Bitbanging - * pgm_type.c: added entry for buspirate_bb - * avrdude.conf.in: added entry for buspirate_bb + patch #7724 Add TPI support for Bus Pirate using bitbang mode + * buspirate.[ch]: added support for BusPirate Bitbanging + * pgm_type.c: added entry for buspirate_bb + * avrdude.conf.in: added entry for buspirate_bb 2013-01-30 Rene Liebscher - patch #7936 Patch to support BusPirate AVR Extended Commands mode - * buspirate.c: added support for BusPirate AVR Extended Commands mode - * avrdude.1: added doc for nopagedread parameter - * doc/avrdude.texi: added doc for nopagedread parameter + patch #7936 Patch to support BusPirate AVR Extended Commands mode + * buspirate.c: added support for BusPirate AVR Extended Commands mode + * avrdude.1: added doc for nopagedread parameter + * doc/avrdude.texi: added doc for nopagedread parameter 2013-01-30 Rene Liebscher - patch #7723 Bus Pirate “raw-wire†mode which can run down to 5 kHz - * buspirate.c: added raw wire mode - * avrdude.1: added doc for rawfreq parameter - * doc/avrdude.texi: added doc for rawfreq parameter + patch #7723 Bus Pirate “raw-wire†mode which can run down to 5 kHz + * buspirate.c: added raw wire mode + * avrdude.1: added doc for rawfreq parameter + * doc/avrdude.texi: added doc for rawfreq parameter 2013-01-30 Rene Liebscher - bug #37977 Support for Openmoko Debug Board - * avrdude.conf.in: added openmoko entry + bug #37977 Support for Openmoko Debug Board + * avrdude.conf.in: added openmoko entry 2013-01-29 Rene Liebscher - patch #7932 Read USBtiny VID and PID from avrdude.conf if provided. - * avrdude.conf.in: added usbpid, usbvid to usbtiny - * usbtiny.[ch]: use usbpid, usbpid if provided in config file + patch #7932 Read USBtiny VID and PID from avrdude.conf if provided. + * avrdude.conf.in: added usbpid, usbvid to usbtiny + * usbtiny.[ch]: use usbpid, usbpid if provided in config file 2013-01-26 Joerg Wunsch - bug #38172: avrftdi: Incorrect information in avrdude.conf - * avrdude.conf.in (avrftdi): fix comments about ACBUS vs. ADBUS; - add a comment that the MPSSE signals are fixed by the FTDI - hardware and cannot be changed + bug #38172: avrftdi: Incorrect information in avrdude.conf + * avrdude.conf.in (avrftdi): fix comments about ACBUS vs. ADBUS; + add a comment that the MPSSE signals are fixed by the FTDI + hardware and cannot be changed 2013-01-09 Rene Liebscher - patch #7165 Add support for bitbanging GPIO lines using the Linux sysf GPIO interface - * doc/avrdude.texi,avrdude.1: added doc for linuxgpio - * avrdude.conf.in: added template for linuxgpio programmer - * config_gram.y: pin numbers restricted to [PIN_MIN, PIN_MAX] - * pindefs.h: added PIN_MIN, PIN_MAX, removed unused LED_ON/OFF - * configure.ac: configure option enable-linuxgpio, print of enabled options - * linuxgpio.[ch]: new source for linuxgpio programmer - * Makefile.am: added linuxgpio to sources list - * pgm_type.c: added linuxgpio to programmer types list + patch #7165 Add support for bitbanging GPIO lines using the Linux sysf GPIO interface + * doc/avrdude.texi,avrdude.1: added doc for linuxgpio + * avrdude.conf.in: added template for linuxgpio programmer + * config_gram.y: pin numbers restricted to [PIN_MIN, PIN_MAX] + * pindefs.h: added PIN_MIN, PIN_MAX, removed unused LED_ON/OFF + * configure.ac: configure option enable-linuxgpio, print of enabled options + * linuxgpio.[ch]: new source for linuxgpio programmer + * Makefile.am: added linuxgpio to sources list + * pgm_type.c: added linuxgpio to programmer types list 2013-01-08 Joerg Wunsch - * jtagmkI.c (jtagmkI_prmsg): replace a putchar() by putc(...stderr) - * jtagmkII.c (jtagmkII_prmsg): (Dito.) - * jtag3.c (jtag3_prevent, jtag3_prmsg): (Dito.) + * jtagmkI.c (jtagmkI_prmsg): replace a putchar() by putc(...stderr) + * jtagmkII.c (jtagmkII_prmsg): (Dito.) + * jtag3.c (jtag3_prevent, jtag3_prmsg): (Dito.) 2013-01-02 Joerg Wunsch - * usb_libusb.c (usbdev_open): Downgrade the max transfer size for - the main data endpoints when being forced so by the USB; this can - happen when attaching the JTAGICE3 to a USB 1.1 connection - * jtag3.c (jtag3_initialize): When detecting a downgraded max - transfer size on the JTAGICE3 (presumably, due to being connected - to USB 1.1 only), bail out as its firmware cannot properly handle - this (by now) + * usb_libusb.c (usbdev_open): Downgrade the max transfer size for + the main data endpoints when being forced so by the USB; this can + happen when attaching the JTAGICE3 to a USB 1.1 connection + * jtag3.c (jtag3_initialize): When detecting a downgraded max + transfer size on the JTAGICE3 (presumably, due to being connected + to USB 1.1 only), bail out as its firmware cannot properly handle + this (by now) 2013-01-02 Joerg Wunsch - * ChangeLog: annual ChangeLog rotation time + * ChangeLog: annual ChangeLog rotation time diff --git a/src/avrdude/ChangeLog-2014 b/src/avrdude/ChangeLog-2014 index 3fe7a53aa13..aa57d04c26a 100644 --- a/src/avrdude/ChangeLog-2014 +++ b/src/avrdude/ChangeLog-2014 @@ -1,697 +1,697 @@ 2014-11-26 Joerg Wunsch - * ser_win32.c (net_send): Properly declare argument 2 as being a - pointer to const data. + * ser_win32.c (net_send): Properly declare argument 2 as being a + pointer to const data. 2014-11-25 Joerg Wunsch - patch #8380: adds 500k 1M 2M baud to ser_posix.c - * ser_posix.c: Add a hack to allow for arbitrary baud rates on - Linux + patch #8380: adds 500k 1M 2M baud to ser_posix.c + * ser_posix.c: Add a hack to allow for arbitrary baud rates on + Linux 2014-11-25 Joerg Wunsch - patch #8437: [PATCH] Serial-over-ethernet for Win32 - * configure.ac: Check for ws2_32 library - * ser_win32.c: Add hooks for forwarding serial data over - TCP connections - * avrdude.1: Drop previous restriction of -P net: - * doc/avrdude.conf: (Dito.) + patch #8437: [PATCH] Serial-over-ethernet for Win32 + * configure.ac: Check for ws2_32 library + * ser_win32.c: Add hooks for forwarding serial data over + TCP connections + * avrdude.1: Drop previous restriction of -P net: + * doc/avrdude.conf: (Dito.) 2014-11-24 Joerg Wunsch - bug #42908: no external reset at JTAGICE3 - * jtag3.c (jtag3_initialize): Retry with external reset applied if - the first sign-on attempt fails. + bug #42908: no external reset at JTAGICE3 + * jtag3.c (jtag3_initialize): Retry with external reset applied if + the first sign-on attempt fails. 2014-11-23 Joerg Wunsch - * main.c: Allow the -B option argument to be suffixed with Hz, - kHz, or MHz, in order to specify a bitclock frequency rather than - period. - * avrdude.1: Document the -B option changes. - * doc/avrdude.texi: (Dito.) + * main.c: Allow the -B option argument to be suffixed with Hz, + kHz, or MHz, in order to specify a bitclock frequency rather than + period. + * avrdude.1: Document the -B option changes. + * doc/avrdude.texi: (Dito.) 2014-11-23 Joerg Wunsch - bug #40870: config nitpick: ATtiny25/45/85 have 1 calibration byte not 2 - * avrdude.conf.in (ATtiny25, ATtiny45, ATtiny85): Fix size of - "calibration" memory area + bug #40870: config nitpick: ATtiny25/45/85 have 1 calibration byte not 2 + * avrdude.conf.in (ATtiny25, ATtiny45, ATtiny85): Fix size of + "calibration" memory area 2014-11-23 Joerg Wunsch - bug #43137: Writing and reading incorrect pages when using jtagicemkI - * jtagmkI.c (jtagmkI_paged_write, jtagmkI_paged_load): correctly - calculate the size of a partial (non-pagesize) buffer + bug #43137: Writing and reading incorrect pages when using jtagicemkI + * jtagmkI.c (jtagmkI_paged_write, jtagmkI_paged_load): correctly + calculate the size of a partial (non-pagesize) buffer 2014-11-23 Joerg Wunsch - bug #43078: AVRDUDE crashes after sucessfully reading/writing eeprom - * jtag3.c (jtag3_edbg_recv_frame): Return correct length as - reported in the response packet, rather than full 512 byte which - are always reported by the CMSIS-DAP layer. Miscalculations - based on the wrongly reported length caused heap corruption - elsewhere, so this is presumably also a fix for bug #43078. + bug #43078: AVRDUDE crashes after sucessfully reading/writing eeprom + * jtag3.c (jtag3_edbg_recv_frame): Return correct length as + reported in the response packet, rather than full 512 byte which + are always reported by the CMSIS-DAP layer. Miscalculations + based on the wrongly reported length caused heap corruption + elsewhere, so this is presumably also a fix for bug #43078. 2014-11-20 Joerg Wunsch - bug #41561: AVRDUDE 6.0.1/USBasp doesn't write first bytes of - flash page - * usbasp.c (usbasp_spi_paged_write): Remove USBASP_BLOCKFLAG_LAST. - It is no longer needed, as we always write full pages now in paged - write mode. + bug #41561: AVRDUDE 6.0.1/USBasp doesn't write first bytes of + flash page + * usbasp.c (usbasp_spi_paged_write): Remove USBASP_BLOCKFLAG_LAST. + It is no longer needed, as we always write full pages now in paged + write mode. 2014-11-19 Joerg Wunsch - bug #43626: Inconsistent timeouts in stk500v2 - * stk500v2.c (stk500v2_recv): Add a reference to the bug report - but don't change anything, lest to break it somehow + bug #43626: Inconsistent timeouts in stk500v2 + * stk500v2.c (stk500v2_recv): Add a reference to the bug report + but don't change anything, lest to break it somehow 2014-11-14 Rene Liebscher - patch #8529 2 more ftdi_syncbb devices - * avrdude.conf.in: added 2 new programmers + patch #8529 2 more ftdi_syncbb devices + * avrdude.conf.in: added 2 new programmers 2014-11-14 Rene Liebscher - bug #40142 Floating point exception on Ubuntu 10.04 - * avr.c: avoid division by zero in report_progress(), eg. when - writing an empty eeprom file were total becomes 0 + bug #40142 Floating point exception on Ubuntu 10.04 + * avr.c: avoid division by zero in report_progress(), eg. when + writing an empty eeprom file were total becomes 0 2014-11-13 Rene Liebscher - patch #8504 buspirate: Also support "cpufreq" extended parameter + patch #8504 buspirate: Also support "cpufreq" extended parameter in binary mode - * buspirate.c: applied patch + switch off at disable (even when + * buspirate.c: applied patch + switch off at disable (even when a reset follows) + some general whitespace/tab cleanup 2014-10-15 Joerg Wunsch - bug #37441: lockbits in ATxmega + avrdude = problem - * fileio.c: replace strmcp(..., "lock") by strncmp(..., "lock", 4) - where applicable - * jtag3.c: (Dito.) - * jtagmkII.c: (Dito.) + bug #37441: lockbits in ATxmega + avrdude = problem + * fileio.c: replace strmcp(..., "lock") by strncmp(..., "lock", 4) + where applicable + * jtag3.c: (Dito.) + * jtagmkII.c: (Dito.) 2014-10-07 Joerg Wunsch - bug #42267: jtag3isp fails to read lock and fuse bytes directly - after changing lock byte - * stk500v2.c (stk500isp_write_byte): As a workaround for broken - tool firmware, add 10 ms of delay before returning from any - single-byte write operation. + bug #42267: jtag3isp fails to read lock and fuse bytes directly + after changing lock byte + * stk500v2.c (stk500isp_write_byte): As a workaround for broken + tool firmware, add 10 ms of delay before returning from any + single-byte write operation. 2014-10-06 Joerg Wunsch - * stk500v2.c: Use stk500isp_read_byte/stk500isp_write_byte for - every byte-wide access (rather than JTAGICE3 only). This finally - obsoletes the use of the prehistoric SPI_MULTI command where - AVRDUDE used to assemble all the low-level ISP stuff by itself. + * stk500v2.c: Use stk500isp_read_byte/stk500isp_write_byte for + every byte-wide access (rather than JTAGICE3 only). This finally + obsoletes the use of the prehistoric SPI_MULTI command where + AVRDUDE used to assemble all the low-level ISP stuff by itself. 2014-10-06 Joerg Wunsch - bug #22248: Read efuse error - * avrdude.conf.in (m168, m328, m48, m88, t1634, t26, t261, t461, - t861, t88): In efuse (or hfuse for t26) read operation, turn all - bits in byte 3 from "x" to "o" (output); this is a first step - towards fixing the symptoms mentioned in the bug, by unifying the - behaviour between different AVRs. Not touched are the historic - devices where the fuses are not documented to form a full byte - each (2333, 4433, 4434, 8535, m103, m161, m163). + bug #22248: Read efuse error + * avrdude.conf.in (m168, m328, m48, m88, t1634, t26, t261, t461, + t861, t88): In efuse (or hfuse for t26) read operation, turn all + bits in byte 3 from "x" to "o" (output); this is a first step + towards fixing the symptoms mentioned in the bug, by unifying the + behaviour between different AVRs. Not touched are the historic + devices where the fuses are not documented to form a full byte + each (2333, 4433, 4434, 8535, m103, m161, m163). 2014-09-22 Joerg Wunsch - bug #43268: usb_drain() call causes LUFA AVR-ISP MKII Code to Fail - * usb_libusb.c (usbdev_drain): Make this a dummy function only. + bug #43268: usb_drain() call causes LUFA AVR-ISP MKII Code to Fail + * usb_libusb.c (usbdev_drain): Make this a dummy function only. 2014-08-19 Rene Liebscher - patch #7694 Add support for the atmega32m1 - * avrdude.conf.in: added ATmega32M1 + patch #7694 Add support for the atmega32m1 + * avrdude.conf.in: added ATmega32M1 2014-08-18 Rene Liebscher - patch #8440 Print part id after signature - When printing the part signature also print the part id. - * avrpart.c (locate_part_by_signature): New function. - * libavrdude.h (locate_part_by_signature): New function. - * main.c (main): Use the new function to find the part and print its id. + patch #8440 Print part id after signature + When printing the part signature also print the part id. + * avrpart.c (locate_part_by_signature): New function. + * libavrdude.h (locate_part_by_signature): New function. + * main.c (main): Use the new function to find the part and print its id. 2014-08-18 Rene Liebscher - patch #8511 Fix reset on FT245R - * ft245r.c: applied patch + patch #8511 Fix reset on FT245R + * ft245r.c: applied patch 2014-08-18 Rene Liebscher - bug #43002 usbasp debug output typo - * usbasp.c: fixed typos + bug #43002 usbasp debug output typo + * usbasp.c: fixed typos 2014-07-16 Joerg Wunsch - bug #42662 clang warnings under FreeBSD 10.x - * avrftdi.h: Fix header guard macro name. - * pgm_type.c (programmers_types): Remove duplicate "const". + bug #42662 clang warnings under FreeBSD 10.x + * avrftdi.h: Fix header guard macro name. + * pgm_type.c (programmers_types): Remove duplicate "const". 2014-07-16 Rene Liebscher - bug #42662 clang warnings under FreeBSD 10.x - * avrftdi.c: remove warnings - * buspirate.c: (Dito.) - * dfu.c: (Dito.) - * fileio.c: (Dito.) - * libavrdude.h: (Dito.) - * pickit2.c: (Dito.) - * safemode.c: (Dito.) - * ser_avrdoper.c: (Dito.) - * ser_posix.c: (Dito.) - * ser_win32.c: (Dito.) - * stk500v2.c: (Dito.) - * usb_libusb.c: (Dito.) - * usbasp.c: (Dito.) - - * config_gram.y: fix problem when using parent part with usbpid lists + bug #42662 clang warnings under FreeBSD 10.x + * avrftdi.c: remove warnings + * buspirate.c: (Dito.) + * dfu.c: (Dito.) + * fileio.c: (Dito.) + * libavrdude.h: (Dito.) + * pickit2.c: (Dito.) + * safemode.c: (Dito.) + * ser_avrdoper.c: (Dito.) + * ser_posix.c: (Dito.) + * ser_win32.c: (Dito.) + * stk500v2.c: (Dito.) + * usb_libusb.c: (Dito.) + * usbasp.c: (Dito.) + + * config_gram.y: fix problem when using parent part with usbpid lists (existing list was extended not overwritten) 2014-07-11 Axel Wachtler - * avrftdi.c: rollback to vfprintf, fixed error from -r1305, (patch #8463) + * avrftdi.c: rollback to vfprintf, fixed error from -r1305, (patch #8463) 2014-06-23 Rene Liebscher - * linux_ppdev.h: added missing msg level for avrdude_message + * linux_ppdev.h: added missing msg level for avrdude_message in ppi_claim/ppi_release macros - * avrftdi.c: added break at end of default + * avrftdi.c: added break at end of default 2014-06-21 Rene Liebscher - patch #8419 fix ftdi_syncbb hang with libftdi 1 - * ft245r.c: set pthread cancel type to asynchronous, reorder ftdi_usb_close/deinit + patch #8419 fix ftdi_syncbb hang with libftdi 1 + * ft245r.c: set pthread cancel type to asynchronous, reorder ftdi_usb_close/deinit 2014-06-17 Rene Liebscher - * avrftdi_private.h: added missing msg level for avrdude_message + * avrftdi_private.h: added missing msg level for avrdude_message in E/E_VOID macros 2014-06-17 Rene Liebscher - Removing exit calls from config parser - * config.h: cleanup, left only internally needed definitions - * config.c: removed exit calls, use yyerror and yywarning - * config_gram.y: (Dito.) - * lexer.l: (Dito.) - * libavrdude.h: removed internal definitions of config parser - * main.c: removed yyerror, it is now in config.c - * jtagmkII.c: added missing free in error case - * pgm.c: replaced exits by returns - * pickit2.c: add missing return + Removing exit calls from config parser + * config.h: cleanup, left only internally needed definitions + * config.c: removed exit calls, use yyerror and yywarning + * config_gram.y: (Dito.) + * lexer.l: (Dito.) + * libavrdude.h: removed internal definitions of config parser + * main.c: removed yyerror, it is now in config.c + * jtagmkII.c: added missing free in error case + * pgm.c: replaced exits by returns + * pickit2.c: add missing return 2014-06-13 Axel Wachtler - + start removing global "verbose" variable, for avrdude library. * arduino.c: added verbose level in avrdude_message() - * avr910.c: (Dito.) - * avr.c: (Dito.) - * avrdude.h: (Dito.) - * avrftdi.c: (Dito.) - * avrpart.c: (Dito.) - * bitbang.c: (Dito.) - * buspirate.c: (Dito.) - * butterfly.c: (Dito.) - * config.c: (Dito.) - * config_gram.y: (Dito.) - * dfu.c: (Dito.) - * fileio.c: (Dito.) - * flip1.c: (Dito.) - * flip2.c: (Dito.) - * ft245r.c: (Dito.) - * jtag3.c: (Dito.) - * jtagmkI.c: (Dito.) - * jtagmkII.c: (Dito.) - * lexer.l: (Dito.) - * libavrdude.h: (Dito.) - * linuxgpio.c: (Dito.) - * main.c: (Dito.) - * par.c: (Dito.) - * pgm.c: (Dito.) - * pickit2.c: (Dito.) - * pindefs.c: (Dito.) - * ppi.c: (Dito.) - * ppiwin.c: (Dito.) - * safemode.c: (Dito.) - * ser_avrdoper.c: (Dito.) - * serbb_posix.c: (Dito.) - * serbb_win32.c: (Dito.) - * ser_posix.c: (Dito.) - * ser_win32.c: (Dito.) - * stk500.c: (Dito.) - * stk500generic.c: (Dito.) - * stk500v2.c: (Dito.) - * term.c: (Dito.) - * update.c: (Dito.) - * usbasp.c: (Dito.) - * usb_libusb.c: (Dito.) - * usbtiny.c: (Dito.) - * wiring.c: (Dito.) + * avr910.c: (Dito.) + * avr.c: (Dito.) + * avrdude.h: (Dito.) + * avrftdi.c: (Dito.) + * avrpart.c: (Dito.) + * bitbang.c: (Dito.) + * buspirate.c: (Dito.) + * butterfly.c: (Dito.) + * config.c: (Dito.) + * config_gram.y: (Dito.) + * dfu.c: (Dito.) + * fileio.c: (Dito.) + * flip1.c: (Dito.) + * flip2.c: (Dito.) + * ft245r.c: (Dito.) + * jtag3.c: (Dito.) + * jtagmkI.c: (Dito.) + * jtagmkII.c: (Dito.) + * lexer.l: (Dito.) + * libavrdude.h: (Dito.) + * linuxgpio.c: (Dito.) + * main.c: (Dito.) + * par.c: (Dito.) + * pgm.c: (Dito.) + * pickit2.c: (Dito.) + * pindefs.c: (Dito.) + * ppi.c: (Dito.) + * ppiwin.c: (Dito.) + * safemode.c: (Dito.) + * ser_avrdoper.c: (Dito.) + * serbb_posix.c: (Dito.) + * serbb_win32.c: (Dito.) + * ser_posix.c: (Dito.) + * ser_win32.c: (Dito.) + * stk500.c: (Dito.) + * stk500generic.c: (Dito.) + * stk500v2.c: (Dito.) + * term.c: (Dito.) + * update.c: (Dito.) + * usbasp.c: (Dito.) + * usb_libusb.c: (Dito.) + * usbtiny.c: (Dito.) + * wiring.c: (Dito.) 2014-06-11 Rene Liebscher - bug #42516 spelling-error-in-binary - * stk500v2.c, avrftdi.c, usbasp.c: fixed spelling errors + bug #42516 spelling-error-in-binary + * stk500v2.c, avrftdi.c, usbasp.c: fixed spelling errors 2014-06-01 Rene Liebscher - bug #42337 avrdude.conf updates for UM232H/CM232H - * avrdude.conf.in: fixed entries as proposed + bug #42337 avrdude.conf updates for UM232H/CM232H + * avrdude.conf.in: fixed entries as proposed 2014-05-19 Joerg Wunsch - bug #41854: avrdude 6.1 does not compile on systems without libUSB - Submitted by Didrik Madheden: - * flip1.c: Provide dummy functions for the #ifndef HAVE_LIBUSB case - * flip2.c: (Dito.) + bug #41854: avrdude 6.1 does not compile on systems without libUSB + Submitted by Didrik Madheden: + * flip1.c: Provide dummy functions for the #ifndef HAVE_LIBUSB case + * flip2.c: (Dito.) 2014-05-19 Joerg Wunsch - * libavrdude.h: Join the former "public" header files (avr.h avrpart.h pindefs.h - serial.h fileio.h safemode.h update.h pgm_type.h config.h confwin.h lists.h) into - a single header that can be included by anyone wanting to link against the - library - * avr.h: Remove file. - * avrpart.h: (Dito.) - * pindefs.h: (Dito.) - * serial.h: (Dito.) - * fileio.h: (Dito.) - * safemode.h: (Dito.) - * update.h: (Dito.) - * pgm.h: (Dito.) - * pgm_type.h: (Dito.) - * config.h: (Dito.) - * confwin.h: (Dito.) - * lists.h: (Dito.) - * Makefile.am: Adapt for new include file constellation; install shared lib - * configure.ac: Bump version date - * arduino.c: #include rather than a bunch of different headers - * avr910.c: (Dito.) - * avr910.h: (Dito.) - * avr.c: (Dito.) - * avrftdi.c: (Dito.) - * avrftdi_private.h: (Dito.) - * avrftdi_tpi.c: (Dito.) - * avrftdi_tpi.h: (Dito.) - * avr.h: (Dito.) - * avrpart.c: (Dito.) - * avrpart.h: (Dito.) - * bitbang.c: (Dito.) - * buspirate.c: (Dito.) - * butterfly.c: (Dito.) - * config.c: (Dito.) - * config_gram.y: (Dito.) - * config.h: (Dito.) - * confwin.c: (Dito.) - * confwin.h: (Dito.) - * dfu.c: (Dito.) - * fileio.c: (Dito.) - * fileio.h: (Dito.) - * flip1.c: (Dito.) - * flip1.h: (Dito.) - * flip2.c: (Dito.) - * flip2.h: (Dito.) - * ft245r.c: (Dito.) - * ft245r.h: (Dito.) - * jtag3.c: (Dito.) - * jtagmkI.c: (Dito.) - * jtagmkII.c: (Dito.) - * lexer.l: (Dito.) - * libavrdude.h: (Dito.) - * linuxgpio.c: (Dito.) - * lists.c: (Dito.) - * lists.h: (Dito.) - * main.c: (Dito.) - * par.c: (Dito.) - * pgm.c: (Dito.) - * pgm_type.c: (Dito.) - * pgm_type.h: (Dito.) - * pickit2.c: (Dito.) - * pickit2.h: (Dito.) - * pindefs.c: (Dito.) - * pindefs.h: (Dito.) - * ppi.c: (Dito.) - * ppiwin.c: (Dito.) - * safemode.c: (Dito.) - * safemode.h: (Dito.) - * ser_avrdoper.c: (Dito.) - * serbb_posix.c: (Dito.) - * serbb_win32.c: (Dito.) - * serial.h: (Dito.) - * ser_posix.c: (Dito.) - * ser_win32.c: (Dito.) - * stk500.c: (Dito.) - * stk500generic.c: (Dito.) - * stk500v2.c: (Dito.) - * stk500v2_private.h: (Dito.) - * term.c: (Dito.) - * term.h: (Dito.) - * update.c: (Dito.) - * update.h: (Dito.) - * usbasp.c: (Dito.) - * usbasp.h: (Dito.) - * usb_libusb.c: (Dito.) - * usbtiny.c: (Dito.) - * usbtiny.h: (Dito.) - * wiring.c: (Dito.) + * libavrdude.h: Join the former "public" header files (avr.h avrpart.h pindefs.h + serial.h fileio.h safemode.h update.h pgm_type.h config.h confwin.h lists.h) into + a single header that can be included by anyone wanting to link against the + library + * avr.h: Remove file. + * avrpart.h: (Dito.) + * pindefs.h: (Dito.) + * serial.h: (Dito.) + * fileio.h: (Dito.) + * safemode.h: (Dito.) + * update.h: (Dito.) + * pgm.h: (Dito.) + * pgm_type.h: (Dito.) + * config.h: (Dito.) + * confwin.h: (Dito.) + * lists.h: (Dito.) + * Makefile.am: Adapt for new include file constellation; install shared lib + * configure.ac: Bump version date + * arduino.c: #include rather than a bunch of different headers + * avr910.c: (Dito.) + * avr910.h: (Dito.) + * avr.c: (Dito.) + * avrftdi.c: (Dito.) + * avrftdi_private.h: (Dito.) + * avrftdi_tpi.c: (Dito.) + * avrftdi_tpi.h: (Dito.) + * avr.h: (Dito.) + * avrpart.c: (Dito.) + * avrpart.h: (Dito.) + * bitbang.c: (Dito.) + * buspirate.c: (Dito.) + * butterfly.c: (Dito.) + * config.c: (Dito.) + * config_gram.y: (Dito.) + * config.h: (Dito.) + * confwin.c: (Dito.) + * confwin.h: (Dito.) + * dfu.c: (Dito.) + * fileio.c: (Dito.) + * fileio.h: (Dito.) + * flip1.c: (Dito.) + * flip1.h: (Dito.) + * flip2.c: (Dito.) + * flip2.h: (Dito.) + * ft245r.c: (Dito.) + * ft245r.h: (Dito.) + * jtag3.c: (Dito.) + * jtagmkI.c: (Dito.) + * jtagmkII.c: (Dito.) + * lexer.l: (Dito.) + * libavrdude.h: (Dito.) + * linuxgpio.c: (Dito.) + * lists.c: (Dito.) + * lists.h: (Dito.) + * main.c: (Dito.) + * par.c: (Dito.) + * pgm.c: (Dito.) + * pgm_type.c: (Dito.) + * pgm_type.h: (Dito.) + * pickit2.c: (Dito.) + * pickit2.h: (Dito.) + * pindefs.c: (Dito.) + * pindefs.h: (Dito.) + * ppi.c: (Dito.) + * ppiwin.c: (Dito.) + * safemode.c: (Dito.) + * safemode.h: (Dito.) + * ser_avrdoper.c: (Dito.) + * serbb_posix.c: (Dito.) + * serbb_win32.c: (Dito.) + * serial.h: (Dito.) + * ser_posix.c: (Dito.) + * ser_win32.c: (Dito.) + * stk500.c: (Dito.) + * stk500generic.c: (Dito.) + * stk500v2.c: (Dito.) + * stk500v2_private.h: (Dito.) + * term.c: (Dito.) + * term.h: (Dito.) + * update.c: (Dito.) + * update.h: (Dito.) + * usbasp.c: (Dito.) + * usbasp.h: (Dito.) + * usb_libusb.c: (Dito.) + * usbtiny.c: (Dito.) + * usbtiny.h: (Dito.) + * wiring.c: (Dito.) 2014-05-19 Joerg Wunsch - * main.c: Cleanup unused include files. + * main.c: Cleanup unused include files. 2014-05-19 Joerg Wunsch - * linux_ppdev.h: Caught two more instances of exit() - * configure.ac: Add AC_CONFIG_MACRO_DIR as suggested by libtoolize - * Makefile.am: add -I m4 to ACLOCAL_AMFLAGS as suggested by libtoolize + * linux_ppdev.h: Caught two more instances of exit() + * configure.ac: Add AC_CONFIG_MACRO_DIR as suggested by libtoolize + * Makefile.am: add -I m4 to ACLOCAL_AMFLAGS as suggested by libtoolize 2014-05-16 Axel Wachtler - * arduino.c: Replacing all occurences of fprintf(stderr,...) with avrdude_message(...) - in potential library functions. - * avr910.c: (Dito.) - * avr.c: (Dito.) - * avrdude.h: (Dito.) - * avrftdi.c: (Dito.) - * avrftdi_private.h: (Dito.) - * avrpart.c: (Dito.) - * bitbang.c: (Dito.) - * buspirate.c: (Dito.) - * butterfly.c: (Dito.) - * config.c: (Dito.) - * config_gram.y: (Dito.) - * dfu.c: (Dito.) - * fileio.c: (Dito.) - * flip1.c: (Dito.) - * flip2.c: (Dito.) - * ft245r.c: (Dito.) - * jtag3.c: (Dito.) - * jtagmkI.c: (Dito.) - * jtagmkII.c: (Dito.) - * lexer.l: (Dito.) - * linuxgpio.c: (Dito.) - * linux_ppdev.h: (Dito.) - * main.c: (Dito.) - * par.c: (Dito.) - * pgm.c: (Dito.) - * pickit2.c: (Dito.) - * pindefs.c: (Dito.) - * ppi.c: (Dito.) - * ppiwin.c: (Dito.) - * safemode.c: (Dito.) - * ser_avrdoper.c: (Dito.) - * serbb_posix.c: (Dito.) - * serbb_win32.c: (Dito.) - * ser_posix.c: (Dito.) - * ser_win32.c: (Dito.) - * stk500.c: (Dito.) - * stk500generic.c: (Dito.) - * stk500v2.c: (Dito.) - * term.c: (Dito.) - * update.c: (Dito.) - * usbasp.c: (Dito.) - * usb_libusb.c: (Dito.) - * usbtiny.c: (Dito.) - * wiring.c: (Dito.) + * arduino.c: Replacing all occurences of fprintf(stderr,...) with avrdude_message(...) + in potential library functions. + * avr910.c: (Dito.) + * avr.c: (Dito.) + * avrdude.h: (Dito.) + * avrftdi.c: (Dito.) + * avrftdi_private.h: (Dito.) + * avrpart.c: (Dito.) + * bitbang.c: (Dito.) + * buspirate.c: (Dito.) + * butterfly.c: (Dito.) + * config.c: (Dito.) + * config_gram.y: (Dito.) + * dfu.c: (Dito.) + * fileio.c: (Dito.) + * flip1.c: (Dito.) + * flip2.c: (Dito.) + * ft245r.c: (Dito.) + * jtag3.c: (Dito.) + * jtagmkI.c: (Dito.) + * jtagmkII.c: (Dito.) + * lexer.l: (Dito.) + * linuxgpio.c: (Dito.) + * linux_ppdev.h: (Dito.) + * main.c: (Dito.) + * par.c: (Dito.) + * pgm.c: (Dito.) + * pickit2.c: (Dito.) + * pindefs.c: (Dito.) + * ppi.c: (Dito.) + * ppiwin.c: (Dito.) + * safemode.c: (Dito.) + * ser_avrdoper.c: (Dito.) + * serbb_posix.c: (Dito.) + * serbb_win32.c: (Dito.) + * ser_posix.c: (Dito.) + * ser_win32.c: (Dito.) + * stk500.c: (Dito.) + * stk500generic.c: (Dito.) + * stk500v2.c: (Dito.) + * term.c: (Dito.) + * update.c: (Dito.) + * usbasp.c: (Dito.) + * usb_libusb.c: (Dito.) + * usbtiny.c: (Dito.) + * wiring.c: (Dito.) 2014-05-16 Joerg Wunsch - * configure.ac: Bump version, add libtool hooks - * Makefile.am: First attempt to define building a shared library - (not to be installed by now) + * configure.ac: Bump version, add libtool hooks + * Makefile.am: First attempt to define building a shared library + (not to be installed by now) 2014-05-16 Joerg Wunsch - * dfu.c (dfu_open, dfu_init): Fix signature of the dummy functions - (in the !HAVE_LIBUSB case) to match prototypes. + * dfu.c (dfu_open, dfu_init): Fix signature of the dummy functions + (in the !HAVE_LIBUSB case) to match prototypes. 2014-05-16 Joerg Wunsch - * avr910.c: Replace all occurences of exit() in potential library - functions by appropriate return values - * avrftdi.c: (Dito.) - * bitbang.c: (Dito.) - * bitbang.h: (Dito.) - * buspirate.c: (Dito.) - * butterfly.c: (Dito.) - * config.c: (Dito.) - * flip2.c: (Dito.) - * ft245r.c: (Dito.) - * jtagmkI.c: (Dito.) - * jtagmkII.c: (Dito.) - * linuxgpio.c: (Dito.) - * main.c: (Dito.) - * par.c: (Dito.) - * pgm.c: (Dito.) - * pickit2.c: (Dito.) - * pindefs.c: (Dito.) - * pindefs.h: (Dito.) - * ser_avrdoper.c: (Dito.) - * ser_posix.c: (Dito.) - * ser_win32.c: (Dito.) - * serbb_posix.c: (Dito.) - * serbb_win32.c: (Dito.) - * stk500.c: (Dito.) - * stk500v2.c: (Dito.) + * avr910.c: Replace all occurences of exit() in potential library + functions by appropriate return values + * avrftdi.c: (Dito.) + * bitbang.c: (Dito.) + * bitbang.h: (Dito.) + * buspirate.c: (Dito.) + * butterfly.c: (Dito.) + * config.c: (Dito.) + * flip2.c: (Dito.) + * ft245r.c: (Dito.) + * jtagmkI.c: (Dito.) + * jtagmkII.c: (Dito.) + * linuxgpio.c: (Dito.) + * main.c: (Dito.) + * par.c: (Dito.) + * pgm.c: (Dito.) + * pickit2.c: (Dito.) + * pindefs.c: (Dito.) + * pindefs.h: (Dito.) + * ser_avrdoper.c: (Dito.) + * ser_posix.c: (Dito.) + * ser_win32.c: (Dito.) + * serbb_posix.c: (Dito.) + * serbb_win32.c: (Dito.) + * stk500.c: (Dito.) + * stk500v2.c: (Dito.) 2014-05-07 Rene Liebscher - bug #42310: New part description for AT90PWM216 - * avrdude.conf.in: added pwm216 entry + bug #42310: New part description for AT90PWM216 + * avrdude.conf.in: added pwm216 entry 2014-05-07 Rene Liebscher - bug #42158: Linux GPIO - Source Typo - * pindefs.h: fixed typo + bug #42158: Linux GPIO - Source Typo + * pindefs.h: fixed typo 2014-04-14 Rene Liebscher - bug #42056: double free or corruption triggered at exit - * pgm.c: copy usbpid list in pgm_dup + bug #42056: double free or corruption triggered at exit + * pgm.c: copy usbpid list in pgm_dup 2014-04-05 Joerg Wunsch - * avrdude.1: Remove the note that users might edit the system-wide - config file. This file will be overwritten by the next - installation, so it's not a good idea to manually modify it. - Using the -C +file option is a much better way for user - modifications. - * doc/avrdude.texi: (Dito.) - * avrdude.conf.in: Add a warning to not modify the file manually. + * avrdude.1: Remove the note that users might edit the system-wide + config file. This file will be overwritten by the next + installation, so it's not a good idea to manually modify it. + Using the -C +file option is a much better way for user + modifications. + * doc/avrdude.texi: (Dito.) + * avrdude.conf.in: Add a warning to not modify the file manually. 2014-03-13 Joerg Wunsch - * configure.ac (AC_INIT): Bump version for post-6.1. + * configure.ac (AC_INIT): Bump version for post-6.1. 2014-03-12 Joerg Wunsch - * configure.ac (AC_INIT): Bump version to 6.1. + * configure.ac (AC_INIT): Bump version to 6.1. 2014-03-12 Joerg Wunsch - * pgm.c (pgm_free): Cleanup police: destroy the p->usbpid - list when freeing the programmer struct. + * pgm.c (pgm_free): Cleanup police: destroy the p->usbpid + list when freeing the programmer struct. 2014-03-12 Joerg Wunsch - bug #40782: Verify errors for object size > 16 k on x32e5 due - to typo in avrdude.conf - * avrdude.conf.in (ATmega8E5, ATmega32E5): fix boot location + bug #40782: Verify errors for object size > 16 k on x32e5 due + to typo in avrdude.conf + * avrdude.conf.in (ATmega8E5, ATmega32E5): fix boot location 2014-02-28 Joerg Wunsch - * avrdude.conf.in (atmelice, atmelice_pdi, atmelice_dw, atmelice_isp): - New entries. - * avrdude.1: Document the Atmel-ICE addition. - * doc/avrdude.texi: (Dito.) - * usbdevs.c (USB_DEVICE_ATMEL_ICE): New entry. + * avrdude.conf.in (atmelice, atmelice_pdi, atmelice_dw, atmelice_isp): + New entries. + * avrdude.1: Document the Atmel-ICE addition. + * doc/avrdude.texi: (Dito.) + * usbdevs.c (USB_DEVICE_ATMEL_ICE): New entry. 2014-02-28 Joerg Wunsch - * main.c: Bump copyright year. + * main.c: Bump copyright year. 2014-02-28 Joerg Wunsch - * jtag3.c (jtag3_recv): avoid memmov'ing more data than available + * jtag3.c (jtag3_recv): avoid memmov'ing more data than available 2014-02-27 Joerg Wunsch - * avrdude.1: Documentation update for EDBG. - * doc/avrdude.texi: (Dito.) + * avrdude.1: Documentation update for EDBG. + * doc/avrdude.texi: (Dito.) 2014-02-27 Joerg Wunsch - * jtag3.c: For EDBG protocol, always use 512-byte block I/O. The - lower layers will split this according to the EP's maxsize. This - makes it work over USB 1.1 connections (albeit very slowly, due to - the interrupt transfers used). + * jtag3.c: For EDBG protocol, always use 512-byte block I/O. The + lower layers will split this according to the EP's maxsize. This + makes it work over USB 1.1 connections (albeit very slowly, due to + the interrupt transfers used). 2014-02-27 Joerg Wunsch - * config_gram.y: Turn the usbpid parameter of the programmer into - a list of PIDs. Make the JTAGICE3 programmer handle a list of - PIDs, by trying each of them in sequence. Use a single, central - jtag3_open_common() function to handle the common code of all - jtag3_open_* functions. Centralize all USB VID/PID definitions in - usbdevs.h. - * flip1.c: (Dito.) - * ft245r.c: (Dito.) - * stk500v2.c: (Dito.) - * jtag3.c: (Dito.) - * jtag3.h: (Dito.) - * flip2.c: (Dito.) - * usbdevs.h: (Dito.) - * pgm.c: (Dito.) - * serial.h: (Dito.) - * pgm.h: (Dito.) - * usbtiny.c: (Dito.) - * usbasp.c: (Dito.) - * avrftdi.c: (Dito.) - * usbtiny.h: (Dito.) - * avrdude.conf.in: (Dito.) - * usbasp.h: (Dito.) - * usb_libusb.c: (Dito.) + * config_gram.y: Turn the usbpid parameter of the programmer into + a list of PIDs. Make the JTAGICE3 programmer handle a list of + PIDs, by trying each of them in sequence. Use a single, central + jtag3_open_common() function to handle the common code of all + jtag3_open_* functions. Centralize all USB VID/PID definitions in + usbdevs.h. + * flip1.c: (Dito.) + * ft245r.c: (Dito.) + * stk500v2.c: (Dito.) + * jtag3.c: (Dito.) + * jtag3.h: (Dito.) + * flip2.c: (Dito.) + * usbdevs.h: (Dito.) + * pgm.c: (Dito.) + * serial.h: (Dito.) + * pgm.h: (Dito.) + * usbtiny.c: (Dito.) + * usbasp.c: (Dito.) + * avrftdi.c: (Dito.) + * usbtiny.h: (Dito.) + * avrdude.conf.in: (Dito.) + * usbasp.h: (Dito.) + * usb_libusb.c: (Dito.) 2014-02-27 Joerg Wunsch - * usb_libusb.c (usbdev_open): Replace all calls to exit(1) by - return -1 + * usb_libusb.c (usbdev_open): Replace all calls to exit(1) by + return -1 2014-02-26 Joerg Wunsch - * jtag3_private.h: Add EDBG/CMSIS-DAP specific constants. - * jtag3.c: Add EDBG/CMSIS-DAP protocol implementation. - * serial.h: (Dito.) - * usbdevs.h: (Dito.) - * usb_libusb.c: (Dito.) - * configure.ac: (Dito.) - * avrdude.conf.in: Add JTAGICE3 and XplainedPro entries using - EDBG. - * configure.ac: Bump version date. + * jtag3_private.h: Add EDBG/CMSIS-DAP specific constants. + * jtag3.c: Add EDBG/CMSIS-DAP protocol implementation. + * serial.h: (Dito.) + * usbdevs.h: (Dito.) + * usb_libusb.c: (Dito.) + * configure.ac: (Dito.) + * avrdude.conf.in: Add JTAGICE3 and XplainedPro entries using + EDBG. + * configure.ac: Bump version date. 2014-02-22 Joerg Wunsch - * usb_libusb.c (usbdev_recv_frame): Fix a bug where a new recv - request was issued even though all desired data had aldready - been received. + * usb_libusb.c (usbdev_recv_frame): Fix a bug where a new recv + request was issued even though all desired data had aldready + been received. 2014-02-21 Joerg Wunsch - * serial.h: Change the second parameter of the ser_open method - from "baud" into a "union pinfo", so the USB parameters can be - passed without hacks. - * arduino.c: (Dito.) - * avr910.c: (Dito.) - * buspirate.c: (Dito.) - * butterfly.c: (Dito.) - * jtag3.c: (Dito.) - * jtagmkI.c: (Dito.) - * jtagmkII.c: (Dito.) - * ser_avrdoper.c: (Dito.) - * ser_posix.c: (Dito.) - * ser_win32.c: (Dito.) - * stk500.c: (Dito.) - * stk500v2.c: (Dito.) - * usb_libusb.c: (Dito.) - * wiring.c: (Dito.) + * serial.h: Change the second parameter of the ser_open method + from "baud" into a "union pinfo", so the USB parameters can be + passed without hacks. + * arduino.c: (Dito.) + * avr910.c: (Dito.) + * buspirate.c: (Dito.) + * butterfly.c: (Dito.) + * jtag3.c: (Dito.) + * jtagmkI.c: (Dito.) + * jtagmkII.c: (Dito.) + * ser_avrdoper.c: (Dito.) + * ser_posix.c: (Dito.) + * ser_win32.c: (Dito.) + * stk500.c: (Dito.) + * stk500v2.c: (Dito.) + * usb_libusb.c: (Dito.) + * wiring.c: (Dito.) 2014-01-30 Joerg Wunsch - [bug #41402] dfu.c missing include - * dfu.c: include where uint16_t is defined + [bug #41402] dfu.c missing include + * dfu.c: include where uint16_t is defined 2014-01-28 Joerg Wunsch - * avrdude.conf.in (ATmega256RFR2 et al.): Fix EEPROM size. + * avrdude.conf.in (ATmega256RFR2 et al.): Fix EEPROM size. 2014-01-27 Joerg Wunsch - [bug #41357] OS X: Avrdude messes with the usb stack? - * usb_libusb.c (usbdev_close): Only issue the usb_reset() for - Linux systems, as these are the only ones that seem to require - it under some circumstances. + [bug #41357] OS X: Avrdude messes with the usb stack? + * usb_libusb.c (usbdev_close): Only issue the usb_reset() for + Linux systems, as these are the only ones that seem to require + it under some circumstances. 2014-01-22 Joerg Wunsch - * configure.ac (libelf): check against elf_getshdrstrndx() rather - than just elf_begin() only, so it is clear we found a sufficiently - recent libelf to work with. + * configure.ac (libelf): check against elf_getshdrstrndx() rather + than just elf_begin() only, so it is clear we found a sufficiently + recent libelf to work with. 2014-01-22 Joerg Wunsch - Contributed by Alan Horstmann: - bug #40897: AT Mega2560 not correctly programmed with stk500(v1) ISP (solution patch) - * stk500.c: Implement extended address byte handling. - * avrdude.conf.in (ATmega2560): enable stk500_devcode so - STK500v1 protocol actually starts at all. + Contributed by Alan Horstmann: + bug #40897: AT Mega2560 not correctly programmed with stk500(v1) ISP (solution patch) + * stk500.c: Implement extended address byte handling. + * avrdude.conf.in (ATmega2560): enable stk500_devcode so + STK500v1 protocol actually starts at all. 2014-01-17 Joerg Wunsch - * flip1.c: Implement the meat of FLIP version 1 protocol. - * avrdude.1: Document the new protocol. - * doc/avrdude.texi: (Dito.) + * flip1.c: Implement the meat of FLIP version 1 protocol. + * avrdude.1: Document the new protocol. + * doc/avrdude.texi: (Dito.) 2014-01-17 Joerg Wunsch - * flip2.c (flip2_page_erase): Remove unimplemented function. - * dfu.h: Correctly conditionalize vs. ; - add adjustable timeout (struct dfu_dev); add dfu_abort() - * dfu.c (dfu_abort): New function; implement adjustable timeout. + * flip2.c (flip2_page_erase): Remove unimplemented function. + * dfu.h: Correctly conditionalize vs. ; + add adjustable timeout (struct dfu_dev); add dfu_abort() + * dfu.c (dfu_abort): New function; implement adjustable timeout. 2014-01-17 Joerg Wunsch - * configure.ac (libhid): Turn from AC_TRY_RUN into - AC_TRY_COMPILE, so it also works for cross-compilation - setups. + * configure.ac (libhid): Turn from AC_TRY_RUN into + AC_TRY_COMPILE, so it also works for cross-compilation + setups. 2014-01-16 Joerg Wunsch - * dfu.c (dfu_init): Move the descriptor checks up into the - FLIP protocol implementation. - * flip2.c (flip2_initialize): (Dito.) - * flip1.c (flip1_initialize): (Dito.) + * dfu.c (dfu_init): Move the descriptor checks up into the + FLIP protocol implementation. + * flip2.c (flip2_initialize): (Dito.) + * flip1.c (flip1_initialize): (Dito.) 2014-01-16 Joerg Wunsch - * flip2.c: Rename from flip.c - * flip2.h: Rename from flip.h - * Makefile.am: Reflect the renaming. - * dfu.c: Update information how to get GPL. - * dfu.h: (Dito.) + * flip2.c: Rename from flip.c + * flip2.h: Rename from flip.h + * Makefile.am: Reflect the renaming. + * dfu.c: Update information how to get GPL. + * dfu.h: (Dito.) 2014-01-16 Joerg Wunsch - * flip.c (flip2_initialize): Check user is running on an Xmega - device. + * flip.c (flip2_initialize): Check user is running on an Xmega + device. 2014-01-15 Joerg Wunsch - * flip.c: Added some verbose-level messages (-vv) - * dfu.c: Added some verbose-level messages (-vvvv) + * flip.c: Added some verbose-level messages (-vv) + * dfu.c: Added some verbose-level messages (-vvvv) 2014-01-15 Joerg Wunsch - Submitted by Kirill Levchenko: - patch #7896: DFU FLIPv2 programming support - * pgm_type.c: Add the flip2 programmer type. - * config_gram.y: Allow for the usbid keyword in a device definition. - * avrdude.conf.in: Add usbpid values to those Xmega devices where - applicable. - * avrpart.h: Add usbpid device field. - * dfu.c: (New file.) - * dfu.h: (New file.) - * flip.c: (New file.) - * flip.h: (New file.) - * Makefile.am: Add new files. - * doc/avrdude.texi: Document the changes. - * avrdude.1: (Dito.) + Submitted by Kirill Levchenko: + patch #7896: DFU FLIPv2 programming support + * pgm_type.c: Add the flip2 programmer type. + * config_gram.y: Allow for the usbid keyword in a device definition. + * avrdude.conf.in: Add usbpid values to those Xmega devices where + applicable. + * avrpart.h: Add usbpid device field. + * dfu.c: (New file.) + * dfu.h: (New file.) + * flip.c: (New file.) + * flip.h: (New file.) + * Makefile.am: Add new files. + * doc/avrdude.texi: Document the changes. + * avrdude.1: (Dito.) 2014-01-15 Joerg Wunsch - * ChangeLog-2013: Annual changelog rotation. + * ChangeLog-2013: Annual changelog rotation. diff --git a/src/avrdude/ChangeLog-2015 b/src/avrdude/ChangeLog-2015 index edc274188e2..0b16e143aa7 100644 --- a/src/avrdude/ChangeLog-2015 +++ b/src/avrdude/ChangeLog-2015 @@ -1,54 +1,54 @@ 2015-12-15 Joerg Wunsch - * avrdude.1 (-C): Do not suggest users might change the - default config file. It will be overwritten by updates. + * avrdude.1 (-C): Do not suggest users might change the + default config file. It will be overwritten by updates. 2015-12-09 Joerg Wunsch - bug #46610: Floating point exception (core dumped) arch linux rpi2 - bug #46483: version 6.2. ser_open(): can't set attributes for device - * ser_posix.c: Back out change from patch #8380 + bug #46610: Floating point exception (core dumped) arch linux rpi2 + bug #46483: version 6.2. ser_open(): can't set attributes for device + * ser_posix.c: Back out change from patch #8380 2015-11-16 Joerg Wunsch - * configure.ac: Bump for post-release 6.2. + * configure.ac: Bump for post-release 6.2. 2015-11-16 Joerg Wunsch - * configure.ac: Released version 6.2. + * configure.ac: Released version 6.2. 2015-10-31 Joerg Wunsch - Submitted by Martino Facchin: - bug #45727: Wrong atmega8u2 flash parameters - * avrdude.conf.in (ATmega8U2): correct page and block size + Submitted by Martino Facchin: + bug #45727: Wrong atmega8u2 flash parameters + * avrdude.conf.in (ATmega8U2): correct page and block size 2015-10-31 Joerg Wunsch - Submitted by Pasquale Cocchini: - bug #46020: Add TIAO TUMPA to the conf file. - * avrdude.conf.in (tumpa): New entry. + Submitted by Pasquale Cocchini: + bug #46020: Add TIAO TUMPA to the conf file. + * avrdude.conf.in (tumpa): New entry. 2015-10-31 Joerg Wunsch - Submitted by Pasquale Cocchini: - bug #46021: Please add read in the memory lock section of ATtiny85 - * avrdude.conf.in (ATtiny25/45/85): add read pattern for lock bits + Submitted by Pasquale Cocchini: + bug #46021: Please add read in the memory lock section of ATtiny85 + * avrdude.conf.in (ATtiny25/45/85): add read pattern for lock bits 2015-10-31 Joerg Wunsch - * Makefile.am (libavrdude_a_SOURCES): reflect recent changes - (pgm.h is gone, config.h is new). + * Makefile.am (libavrdude_a_SOURCES): reflect recent changes + (pgm.h is gone, config.h is new). 2015-04-09 Joerg Wunsch - bug #44717: avrdude creates empty flash dump - * update.c (do_op): When about to write an empty flash dump file, - warn about this to avoid surprises. - * avrdude.1: Document the truncation of trailing 0xFF bytes for - flash memory areas. - * doc/avrdude.texi: (Dito.) + bug #44717: avrdude creates empty flash dump + * update.c (do_op): When about to write an empty flash dump file, + warn about this to avoid surprises. + * avrdude.1: Document the truncation of trailing 0xFF bytes for + flash memory areas. + * doc/avrdude.texi: (Dito.) 2015-04-09 Joerg Wunsch - Annual ChangeLog rotation. + Annual ChangeLog rotation. diff --git a/src/avrdude/Makefile.am b/src/avrdude/Makefile.am index d1ed47845a1..203a8173435 100644 --- a/src/avrdude/Makefile.am +++ b/src/avrdude/Makefile.am @@ -21,26 +21,26 @@ # EXTRA_DIST = \ - ChangeLog \ - ChangeLog-2001 \ - ChangeLog-2002 \ - ChangeLog-2003 \ - ChangeLog-2004-2006 \ - ChangeLog-2007 \ - ChangeLog-2008 \ - ChangeLog-2009 \ - ChangeLog-2010 \ - ChangeLog-2011 \ - ChangeLog-2012 \ - ChangeLog-2013 \ - avrdude.1 \ - avrdude.spec \ - bootstrap + ChangeLog \ + ChangeLog-2001 \ + ChangeLog-2002 \ + ChangeLog-2003 \ + ChangeLog-2004-2006 \ + ChangeLog-2007 \ + ChangeLog-2008 \ + ChangeLog-2009 \ + ChangeLog-2010 \ + ChangeLog-2011 \ + ChangeLog-2012 \ + ChangeLog-2013 \ + avrdude.1 \ + avrdude.spec \ + bootstrap CLEANFILES = \ - config_gram.c \ - config_gram.h \ - lexer.c + config_gram.c \ + config_gram.h \ + lexer.c BUILT_SOURCES = $(CLEANFILES) @@ -83,108 +83,108 @@ lib_LTLIBRARIES = libavrdude.la # # for why we don't want to have them. dist-hook: - rm -f \ - $(distdir)/lexer.c \ - $(distdir)/config_gram.c \ - $(distdir)/config_gram.h + rm -f \ + $(distdir)/lexer.c \ + $(distdir)/config_gram.c \ + $(distdir)/config_gram.h libavrdude_a_SOURCES = \ - config_gram.y \ - lexer.l \ - arduino.h \ - arduino.c \ - avr.c \ - avr910.c \ - avr910.h \ - avrdude.h \ - avrftdi.c \ - avrftdi.h \ - avrftdi_private.h \ - avrftdi_tpi.c \ - avrftdi_tpi.h \ - avrpart.c \ - bitbang.c \ - bitbang.h \ - buspirate.c \ - buspirate.h \ - butterfly.c \ - butterfly.h \ - config.c \ - config.h \ - confwin.c \ - crc16.c \ - crc16.h \ - dfu.c \ - dfu.h \ - fileio.c \ - flip1.c \ - flip1.h \ - flip2.c \ - flip2.h \ - freebsd_ppi.h \ - ft245r.c \ - ft245r.h \ - jtagmkI.c \ - jtagmkI.h \ - jtagmkI_private.h \ - jtagmkII.c \ - jtagmkII.h \ - jtagmkII_private.h \ - jtag3.c \ - jtag3.h \ - jtag3_private.h \ - libavrdude.h \ - linuxgpio.c \ - linuxgpio.h \ - linux_ppdev.h \ - lists.c \ - my_ddk_hidsdi.h \ - par.c \ - par.h \ - pgm.c \ - pgm_type.c \ - pickit2.c \ - pickit2.h \ - pindefs.c \ - ppi.c \ - ppi.h \ - ppiwin.c \ - safemode.c \ - serbb.h \ - serbb_posix.c \ - serbb_win32.c \ - ser_avrdoper.c \ - ser_posix.c \ - ser_win32.c \ - solaris_ecpp.h \ - stk500.c \ - stk500.h \ - stk500_private.h \ - stk500v2.c \ - stk500v2.h \ - stk500v2_private.h \ - stk500generic.c \ - stk500generic.h \ - tpi.h \ - usbasp.c \ - usbasp.h \ - usbdevs.h \ - usb_hidapi.c \ - usb_libusb.c \ - usbtiny.h \ - usbtiny.c \ - update.c \ - wiring.h \ - wiring.c + config_gram.y \ + lexer.l \ + arduino.h \ + arduino.c \ + avr.c \ + avr910.c \ + avr910.h \ + avrdude.h \ + avrftdi.c \ + avrftdi.h \ + avrftdi_private.h \ + avrftdi_tpi.c \ + avrftdi_tpi.h \ + avrpart.c \ + bitbang.c \ + bitbang.h \ + buspirate.c \ + buspirate.h \ + butterfly.c \ + butterfly.h \ + config.c \ + config.h \ + confwin.c \ + crc16.c \ + crc16.h \ + dfu.c \ + dfu.h \ + fileio.c \ + flip1.c \ + flip1.h \ + flip2.c \ + flip2.h \ + freebsd_ppi.h \ + ft245r.c \ + ft245r.h \ + jtagmkI.c \ + jtagmkI.h \ + jtagmkI_private.h \ + jtagmkII.c \ + jtagmkII.h \ + jtagmkII_private.h \ + jtag3.c \ + jtag3.h \ + jtag3_private.h \ + libavrdude.h \ + linuxgpio.c \ + linuxgpio.h \ + linux_ppdev.h \ + lists.c \ + my_ddk_hidsdi.h \ + par.c \ + par.h \ + pgm.c \ + pgm_type.c \ + pickit2.c \ + pickit2.h \ + pindefs.c \ + ppi.c \ + ppi.h \ + ppiwin.c \ + safemode.c \ + serbb.h \ + serbb_posix.c \ + serbb_win32.c \ + ser_avrdoper.c \ + ser_posix.c \ + ser_win32.c \ + solaris_ecpp.h \ + stk500.c \ + stk500.h \ + stk500_private.h \ + stk500v2.c \ + stk500v2.h \ + stk500v2_private.h \ + stk500generic.c \ + stk500generic.h \ + tpi.h \ + usbasp.c \ + usbasp.h \ + usbdevs.h \ + usb_hidapi.c \ + usb_libusb.c \ + usbtiny.h \ + usbtiny.c \ + update.c \ + wiring.h \ + wiring.c libavrdude_la_SOURCES = $(libavrdude_a_SOURCES) libavrdude_la_LDFLAGS = -version-info 1:0 include_HEADERS = libavrdude.h avrdude_SOURCES = \ - main.c \ - term.c \ - term.h + main.c \ + term.c \ + term.h man_MANS = avrdude.1 @@ -193,14 +193,14 @@ sysconf_DATA = avrdude.conf install-exec-local: backup-avrdude-conf distclean-local: - rm -f avrdude.conf + rm -f avrdude.conf # This will get run before the config file is installed. backup-avrdude-conf: - @echo "Backing up avrdude.conf in ${DESTDIR}${sysconfdir}" - @if test -e ${DESTDIR}${sysconfdir}/avrdude.conf; then \ - cp -pR ${DESTDIR}${sysconfdir}/avrdude.conf \ - ${DESTDIR}${sysconfdir}/avrdude.conf.bak; \ - fi + @echo "Backing up avrdude.conf in ${DESTDIR}${sysconfdir}" + @if test -e ${DESTDIR}${sysconfdir}/avrdude.conf; then \ + cp -pR ${DESTDIR}${sysconfdir}/avrdude.conf \ + ${DESTDIR}${sysconfdir}/avrdude.conf.bak; \ + fi ACLOCAL_AMFLAGS = -I m4 diff --git a/src/avrdude/Makefile.standalone b/src/avrdude/Makefile.standalone index d9a773771e8..45a821ee7b8 100644 --- a/src/avrdude/Makefile.standalone +++ b/src/avrdude/Makefile.standalone @@ -45,10 +45,10 @@ RM = rm all: $(TARGET) $(TARGET): $(OBJECTS) - $(CC) -o ./$@ $(OBJECTS) $(LDFLAGS) + $(CC) -o ./$@ $(OBJECTS) $(LDFLAGS) $(OBJECTS): %.o: %.c - $(CC) $(CFLAGS) -o $@ -c $< + $(CC) $(CFLAGS) -o $@ -c $< clean: - $(RM) -f $(OBJECTS) $(TARGET) + $(RM) -f $(OBJECTS) $(TARGET) diff --git a/src/avrdude/NEWS b/src/avrdude/NEWS index ced93cd359c..faa5c6832a0 100644 --- a/src/avrdude/NEWS +++ b/src/avrdude/NEWS @@ -407,11 +407,11 @@ Version 5.7: - ATXMEGA64A1 - ATXMEGA192A1 - - ATXMEGA256A1 + - ATXMEGA256A1 - ATXMEGA64A3 - ATXMEGA128A3 - ATXMEGA192A3 - - ATXMEGA256A3 + - ATXMEGA256A3 - ATXMEGA256A3B - ATXMEGA16A4 - ATXMEGA32A4 @@ -681,7 +681,7 @@ Version 4.1.0 * Add support for avr910 type programmers (mcu00100, pavr avr910, etc). * Support new devices: ATmega8535, ATtiny26 - + Version 4.0.0 diff --git a/src/avrdude/README b/src/avrdude/README index 2ca0009a32c..413d80bbfe1 100644 --- a/src/avrdude/README +++ b/src/avrdude/README @@ -1,9 +1,9 @@ -THIS IS A PRUSA3D BRANCH, WORKING AROUND A SPECIFIC PROBLEM +THIS IS A PRUSA3D BRANCH, WORKING AROUND A SPECIFIC PROBLEM IN THE EARLY I3 MK2 USB COMMUNICATION CHIPS. Some of the early Prusa3D i3 MK2 printers were shipped with a buggy USB communication controller firmware. This fork of avrdude contains -a workaround inside the stk500v2 protocol implementation. +a workaround inside the stk500v2 protocol implementation. The workaround depends on a specific behavior of the Arduino AVR 2560 bootloader, which is installed on the i3 MK2 printers: diff --git a/src/avrdude/arduino.c b/src/avrdude/arduino.c index e6008adeb88..794747eb385 100644 --- a/src/avrdude/arduino.c +++ b/src/avrdude/arduino.c @@ -59,13 +59,13 @@ static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m) return -1; if (buf[0] == Resp_STK_NOSYNC) { avrdude_message(MSG_INFO, "%s: stk500_cmd(): programmer is out of sync\n", - progname); - return -1; + progname); + return -1; } else if (buf[0] != Resp_STK_INSYNC) { avrdude_message(MSG_INFO, "\n%s: arduino_read_sig_bytes(): (a) protocol error, " "expect=0x%02x, resp=0x%02x\n", progname, Resp_STK_INSYNC, buf[0]); - return -2; + return -2; } if (buf[4] != Resp_STK_OK) { avrdude_message(MSG_INFO, "\n%s: arduino_read_sig_bytes(): (a) protocol error, " @@ -133,7 +133,7 @@ static int arduino_open(PROGRAMMER * pgm, char * port) return -1; } - /* Clear DTR and RTS to unload the RESET capacitor + /* Clear DTR and RTS to unload the RESET capacitor * (for example in Arduino) */ serial_set_dtr_rts(&pgm->fd, 0); usleep(250*1000); @@ -179,7 +179,7 @@ const char arduino_desc[] = "Arduino programmer"; void arduino_initpgm(PROGRAMMER * pgm) { /* This is mostly a STK500; just the signature is read - differently than on real STK500v1 + differently than on real STK500v1 and the DTR signal is set when opening the serial port for the Auto-Reset feature */ stk500_initpgm(pgm); diff --git a/src/avrdude/atmel-docs/EDBG/common/browserDetect.js b/src/avrdude/atmel-docs/EDBG/common/browserDetect.js index 2a7aa08a421..cf265159626 100644 --- a/src/avrdude/atmel-docs/EDBG/common/browserDetect.js +++ b/src/avrdude/atmel-docs/EDBG/common/browserDetect.js @@ -1,116 +1,116 @@ var BrowserDetect = { - init: function () { - this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; - this.version = this.searchVersion(navigator.userAgent) - || this.searchVersion(navigator.appVersion) - || "an unknown version"; - this.OS = this.searchString(this.dataOS) || "an unknown OS"; - }, - searchString: function (data) { - for (var i=0;i> Global @@ -21,22 +21,22 @@ .grid_1, .grid_2, .grid_3 { - display:inline; - float: left; - position: relative; - margin-left: 1%; - margin-right: 1%; + display:inline; + float: left; + position: relative; + margin-left: 1%; + margin-right: 1%; } /* Grid >> Children (Alpha ~ First, Omega ~ Last) ----------------------------------------------------------------------------------------------------*/ .alpha { - margin-left: 0; + margin-left: 0; } .omega { - margin-right: 0; + margin-right: 0; } /* Grid >> 3 Columns @@ -44,15 +44,15 @@ .container_3 .grid_1 { - width:31.333%; + width:31.333%; } .container_3 .grid_2 { - width:64.667%; + width:64.667%; } .container_3 .grid_3 { - width:98.0%; + width:98.0%; } @@ -62,11 +62,11 @@ .container_3 .prefix_1 { - padding-left:33.333%; + padding-left:33.333%; } .container_3 .prefix_2 { - padding-left:66.667%; + padding-left:66.667%; } @@ -76,11 +76,11 @@ .container_3 .suffix_1 { - padding-right:33.333%; + padding-right:33.333%; } .container_3 .suffix_2 { - padding-right:66.667%; + padding-right:66.667%; } @@ -90,11 +90,11 @@ .container_3 .push_1 { - left:33.333%; + left:33.333%; } .container_3 .push_2 { - left:66.667%; + left:66.667%; } @@ -104,11 +104,11 @@ .container_3 .pull_1 { - left:-33.333%; + left:-33.333%; } .container_3 .pull_2 { - left:-66.667%; + left:-66.667%; } @@ -120,35 +120,35 @@ /* http://sonspring.com/journal/clearing-floats */ .clear { - clear: both; - display: block; - overflow: hidden; - visibility: hidden; - width: 0; - height: 0; + clear: both; + display: block; + overflow: hidden; + visibility: hidden; + width: 0; + height: 0; } /* http://perishablepress.com/press/2008/02/05/lessons-learned-concerning-the-clearfix-css-hack */ .clearfix:after { - clear: both; - content: ' '; - display: block; - font-size: 0; - line-height: 0; - visibility: hidden; - width: 0; - height: 0; + clear: both; + content: ' '; + display: block; + font-size: 0; + line-height: 0; + visibility: hidden; + width: 0; + height: 0; } .clearfix { - display: inline-block; + display: inline-block; } * html .clearfix { - height: 1%; + height: 1%; } .clearfix { - display: block; + display: block; } \ No newline at end of file diff --git a/src/avrdude/atmel-docs/EDBG/common/css/index.css b/src/avrdude/atmel-docs/EDBG/common/css/index.css index eb1b8c24fb2..d43e7add3ec 100644 --- a/src/avrdude/atmel-docs/EDBG/common/css/index.css +++ b/src/avrdude/atmel-docs/EDBG/common/css/index.css @@ -1,14 +1,14 @@ body { font-size: 12px; - font-family: Verdana, Geneva, sans-serif; + font-family: Verdana, Geneva, sans-serif; } .a { - text-decoration: none; + text-decoration: none; } .title { - padding: 31px 0 0 0; + padding: 31px 0 0 0; } .group @@ -18,40 +18,40 @@ body { } .group_header { - color: #0066CB; - font: bold 14pt IntervalLight, sans-serif; - text-decoration: none; - padding: 8px; - background-color: #EEEEEE; - margin-top: 24px; - /*margin-bottom: 8px;*/ + color: #0066CB; + font: bold 14pt IntervalLight, sans-serif; + text-decoration: none; + padding: 8px; + background-color: #EEEEEE; + margin-top: 24px; + /*margin-bottom: 8px;*/ } -.products +.products { float:left; /*background:#FFF8F8;*/ } .product { - /*background: url("../images/panelbg.png") 0 0 no-repeat;*/ - width: 300px; - height: 130px; - /*margin-left: 20px;*/ - padding: 10px; - border: 1px solid #EEEEEE; + /*background: url("../images/panelbg.png") 0 0 no-repeat;*/ + width: 300px; + height: 130px; + /*margin-left: 20px;*/ + padding: 10px; + border: 1px solid #EEEEEE; display:block; float: left; } .product span { - font-size: 16px; - color: #0066CB; - margin-bottom: 8px; - clear:both; + font-size: 16px; + color: #0066CB; + margin-bottom: 8px; + clear:both; } -.product img +.product img { margin-right:12px; float:left; diff --git a/src/avrdude/atmel-docs/EDBG/common/css/positioning.css b/src/avrdude/atmel-docs/EDBG/common/css/positioning.css index 7c9658c412a..98a8b388bb1 100644 --- a/src/avrdude/atmel-docs/EDBG/common/css/positioning.css +++ b/src/avrdude/atmel-docs/EDBG/common/css/positioning.css @@ -1,4 +1,4 @@ -tr th .added { color: #E6E6FA; } +tr th .added { color: #E6E6FA; } tr th .changed {color: #99ff99; } div.added tr, div.added { background-color: #E6E6FA; } div.deleted tr, div.deleted { text-decoration: line-through; @@ -43,7 +43,7 @@ h2 { font: normal 12pt Arial, Helvetica, geneva; } #header h1 { - margin-top: 2px; + margin-top: 2px; } @@ -106,7 +106,7 @@ p.breadcrumbs { #content { position: relative; top: 90px; /*left: 240px;*/ - right: auto; bottom: 20px; + right: auto; bottom: 20px; /*margin: 0px 0px 0px 280px;*/ width: auto; height: inherit; @@ -116,7 +116,7 @@ p.breadcrumbs { overflow :scroll; overflow-x:auto; z-index: 1000; - + } #navheader { @@ -128,8 +128,8 @@ p.breadcrumbs { text-align: right; } -#content h1, #content h2 { -color: #404040 !important; +#content h1, #content h2 { +color: #404040 !important; font-size: 170%; font-weight: normal; } @@ -174,84 +174,84 @@ font-weight: normal; } .searchFieldSet {} -.title, div.toc>p{ font-weight: bold; } +.title, div.toc>p{ font-weight: bold; } p.breadcrumbs { display: inline; - margin-bottom: 0px; - margin-top: 33px; + margin-bottom: 0px; + margin-top: 33px; } p.breadcrumbs a { - padding-right: 12px; - margin-right: 5px; - text-decoration: none; - color: #575757; - text-transform: uppercase; - font-size: 10px; + padding-right: 12px; + margin-right: 5px; + text-decoration: none; + color: #575757; + text-transform: uppercase; + font-size: 10px; } p.breadcrumbs a:first-child {background: url(../images/breadcrumb-arrow-white.png) no-repeat right center;} p.breadcrumbs a:hover {text-decoration: underline;} -#star ul.star { - LIST-STYLE: none; - MARGIN: 0; - PADDING: 0; +#star ul.star { + LIST-STYLE: none; + MARGIN: 0; + PADDING: 0; WIDTH: 85px; - /* was 100 */ + /* was 100 */ HEIGHT: 20px; - LEFT: 1px; - TOP: -5px; - POSITION: relative; - FLOAT: right; + LEFT: 1px; + TOP: -5px; + POSITION: relative; + FLOAT: right; BACKGROUND: url('../images/starsSmall.png') repeat-x 0 -25px; } -#star li { - PADDING: 0; - MARGIN: 0; - FLOAT: right; - DISPLAY: block; +#star li { + PADDING: 0; + MARGIN: 0; + FLOAT: right; + DISPLAY: block; WIDTH: 85px; /* was 100 */ - HEIGHT: 20px; - TEXT-DECORATION: none; - text-indent: -9000px; - Z-INDEX: 20; - POSITION: absolute; - PADDING: 0; + HEIGHT: 20px; + TEXT-DECORATION: none; + text-indent: -9000px; + Z-INDEX: 20; + POSITION: absolute; + PADDING: 0; } -#star li.curr { - BACKGROUND: url('../images/starsSmall.png') left 25px; - FONT-SIZE: 1px; +#star li.curr { + BACKGROUND: url('../images/starsSmall.png') left 25px; + FONT-SIZE: 1px; } table.navLinks {margin-right: 20px;} table.navLinks td a { - text-decoration: none; - text-transform: uppercase; - color: black; - font-size: 11px; + text-decoration: none; + text-transform: uppercase; + color: black; + font-size: 11px; } a.navLinkPrevious { - padding-left: 12px; - background: url(../images/previous-arrow.png) no-repeat left center; + padding-left: 12px; + background: url(../images/previous-arrow.png) no-repeat left center; } a.navLinkNext { - padding-right: 12px; - background: url(../images/next-arrow.png) no-repeat right center; + padding-right: 12px; + background: url(../images/next-arrow.png) no-repeat right center; } a#showHideButton { - padding-left: 20px; - background: url(../images/sidebar.png) no-repeat left center; + padding-left: 20px; + background: url(../images/sidebar.png) no-repeat left center; } - + .filetree li span a { color: #777; } #treediv { -webkit-box-shadow: #CCC 0px 1px 2px 0px inset; } @@ -266,13 +266,13 @@ a#showHideButton { .writeronly {color : red;} -.remark, .remark .added, .remark .changed, .remark .deleted{ background: yellow;} +.remark, .remark .added, .remark .changed, .remark .deleted{ background: yellow;} tr th, tr th .internal, tr th .added, tr th .changed { - background: #00589E; - color: white; - font-weight: bold; - text-align: left; + background: #00589E; + color: white; + font-weight: bold; + text-align: left; } .statustext{ @@ -292,32 +292,32 @@ tr th, tr th .internal, tr th .added, tr th .changed { } #toolbar { - width: 100%; - height: 33px; - position: fixed; - top: 93px; - z-index: 99; - left: 280px; - color: #333; - line-height: 28px; - padding-left: 10px; + width: 100%; + height: 33px; + position: fixed; + top: 93px; + z-index: 99; + left: 280px; + color: #333; + line-height: 28px; + padding-left: 10px; } #toolbar-left { - position: relative; - left: 0px; + position: relative; + left: 0px; } - + body p.breadcrumbs { - margin: 0px; - padding: 0px; - line-height: 28px; + margin: 0px; + padding: 0px; + line-height: 28px; } /*body #content { - position: static; - margin-top: 126px; - top: 0px; + position: static; + margin-top: 126px; + top: 0px; }*/ body.sidebar #toolbar{left: 0px;} @@ -329,7 +329,7 @@ div#toolbar-left img {vertical-align: text-top;} div.note *, div.caution *, div.important *, div.tip *, div.warning * { background: inherit !important; color: inherit !important; - border: inherit /*!important*/; + border: inherit /*!important*/; } #content table thead, #content table th, #content table th p{ @@ -351,8 +351,8 @@ div.note *, div.caution *, div.important *, div.tip *, div.warning * { border: 0px solid; } -#sidebar -{ +#sidebar +{ position: fixed; margin: 0px; left: 0px; @@ -381,7 +381,7 @@ div.note *, div.caution *, div.important *, div.tip *, div.warning * { } #content { - margin: 0 0 0 0; + margin: 0 0 0 0; } } @@ -392,11 +392,11 @@ div.note *, div.caution *, div.important *, div.tip *, div.warning * { padding-bottom: 1em; } -#expanders dt { +#expanders dt { padding-bottom: 4px; border-bottom: 2px solid #cccccc; margin-top: 1em; - margin-bottom: 1em; + margin-bottom: 1em; background: url(../images/plus.png) 0px 7px no-repeat; /*background: pink;*/ cursor: pointer; @@ -419,23 +419,23 @@ div.note *, div.caution *, div.important *, div.tip *, div.warning * { } -#expanders dd { +#expanders dd { display: none; margin-bottom: 3em; /*background: yellow;*/ } #expanders .hitarea { - background: url(../images/ui-icons_217bc0_256x240.png) 0 -208px no-repeat; - height: 16px; - width: 16px; - float: left; - cursor: pointer; + background: url(../images/ui-icons_217bc0_256x240.png) 0 -208px no-repeat; + height: 16px; + width: 16px; + float: left; + cursor: pointer; } /* fix for IE6 */ /** html .hitarea { - display: inline; - float:none; + display: inline; + float:none; }*/ @@ -489,5 +489,5 @@ div.note *, div.caution *, div.important *, div.tip *, div.warning * { a.external { background: url("../images/external_link.gif") no-repeat scroll right top transparent; - padding: 0 13px 0 0; + padding: 0 13px 0 0; } \ No newline at end of file diff --git a/src/avrdude/atmel-docs/EDBG/common/css/print.css b/src/avrdude/atmel-docs/EDBG/common/css/print.css index a52a074e742..ca382f20b6c 100644 --- a/src/avrdude/atmel-docs/EDBG/common/css/print.css +++ b/src/avrdude/atmel-docs/EDBG/common/css/print.css @@ -7,22 +7,22 @@ body { #sidebar, #sidebar-resizer, #header-resizer, #header { display: none !important;} -#content { - position: absolute !important; - margin: 0px !important; - left: 0px !important; - right: auto !important; - top: 0px !important; - height: auto !important; - overflow: visible !important; - overflow-x: visible !important; - border-left: 0px solid #000000 !important; +#content { + position: absolute !important; + margin: 0px !important; + left: 0px !important; + right: auto !important; + top: 0px !important; + height: auto !important; + overflow: visible !important; + overflow-x: visible !important; + border-left: 0px solid #000000 !important; } .ui-layout-container { - overflow: visible !important; + overflow: visible !important; } .mediaobject { - text-align: left !important; + text-align: left !important; } \ No newline at end of file diff --git a/src/avrdude/atmel-docs/EDBG/common/jquery/jquery.ui.all.js b/src/avrdude/atmel-docs/EDBG/common/jquery/jquery.ui.all.js index 943d3b357f7..f3f3a4cda74 100644 --- a/src/avrdude/atmel-docs/EDBG/common/jquery/jquery.ui.all.js +++ b/src/avrdude/atmel-docs/EDBG/common/jquery/jquery.ui.all.js @@ -411,7 +411,7 @@ i[e]=("show"==g?"pos"==h?"+=":"-=":"pos"==h?"-=":"+=")+f;c.animate(i,{queue:!1,d * Based on highlight v3 by Johann Burkard * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html * Copyright (c) 2009 Bartek Szopka http://bartaz.github.com/sandbox.js/jquery.highlight.html - * Licensed under MIT license. + * Licensed under MIT license. */ jQuery.extend({highlight:function(a,c,b,e){if(a.nodeType===3){if(c=a.data.match(c)){b=document.createElement(b||"span");b.className=e||"highlight";a=a.splitText(c.index);a.splitText(c[0].length);e=a.cloneNode(true);b.appendChild(e);a.parentNode.replaceChild(b,a);return 1}}else if(a.nodeType===1&&a.childNodes&&!/(script|style)/i.test(a.tagName)&&!(a.tagName===b.toUpperCase()&&a.className===e))for(var d=0;d').appendTo("body"); - var d = { width: $c.width() - $c[0].clientWidth, height: $c.height() - $c[0].clientHeight }; - $c.remove(); - window.scrollbarWidth = d.width; - window.scrollbarHeight = d.height; - return dim.match(/^(width|height)$/) ? d[dim] : d; - } - - - /** - * Returns hash container 'display' and 'visibility' - * - * @see $.swap() - swaps CSS, runs callback, resets CSS - */ -, showInvisibly: function ($E, force) { - if (!$E) return {}; - if (!$E.jquery) $E = $($E); - var CSS = { - display: $E.css('display') - , visibility: $E.css('visibility') - }; - if (force || CSS.display === "none") { // only if not *already hidden* - $E.css({ display: "block", visibility: "hidden" }); // show element 'invisibly' so can be measured - return CSS; - } - else return {}; - } - - /** - * Returns data for setting size of an element (container or a pane). - * - * @see _create(), onWindowResize() for container, plus others for pane - * @return JSON Returns a hash of all dimensions: top, bottom, left, right, outerWidth, innerHeight, etc - */ -, getElementDimensions: function ($E) { - var - d = {} // dimensions hash - , x = d.css = {} // CSS hash - , i = {} // TEMP insets - , b, p // TEMP border, padding - , N = $.layout.cssNum - , off = $E.offset() - ; - d.offsetLeft = off.left; - d.offsetTop = off.top; - - $.each("Left,Right,Top,Bottom".split(","), function (idx, e) { // e = edge - b = x["border" + e] = $.layout.borderWidth($E, e); - p = x["padding"+ e] = $.layout.cssNum($E, "padding"+e); - i[e] = b + p; // total offset of content from outer side - d["inset"+ e] = p; - }); - - d.offsetWidth = $E.innerWidth(); // offsetWidth is used in calc when doing manual resize - d.offsetHeight = $E.innerHeight(); // ditto - d.outerWidth = $E.outerWidth(); - d.outerHeight = $E.outerHeight(); - d.innerWidth = max(0, d.outerWidth - i.Left - i.Right); - d.innerHeight = max(0, d.outerHeight - i.Top - i.Bottom); - - x.width = $E.width(); - x.height = $E.height(); - x.top = N($E,"top",true); - x.bottom = N($E,"bottom",true); - x.left = N($E,"left",true); - x.right = N($E,"right",true); - - //d.visible = $E.is(":visible");// && x.width > 0 && x.height > 0; - - return d; - } - -, getElementCSS: function ($E, list) { - var - CSS = {} - , style = $E[0].style - , props = list.split(",") - , sides = "Top,Bottom,Left,Right".split(",") - , attrs = "Color,Style,Width".split(",") - , p, s, a, i, j, k - ; - for (i=0; i < props.length; i++) { - p = props[i]; - if (p.match(/(border|padding|margin)$/)) - for (j=0; j < 4; j++) { - s = sides[j]; - if (p === "border") - for (k=0; k < 3; k++) { - a = attrs[k]; - CSS[p+s+a] = style[p+s+a]; - } - else - CSS[p+s] = style[p+s]; - } - else - CSS[p] = style[p]; - }; - return CSS - } - - /** - * Return the innerWidth for the current browser/doctype - * - * @see initPanes(), sizeMidPanes(), initHandles(), sizeHandles() - * @param {Array.} $E Must pass a jQuery object - first element is processed - * @param {number=} outerWidth (optional) Can pass a width, allowing calculations BEFORE element is resized - * @return {number} Returns the innerWidth of the elem by subtracting padding and borders - */ -, cssWidth: function ($E, outerWidth) { - var - b = $.layout.borderWidth - , n = $.layout.cssNum - ; - // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed - if (outerWidth <= 0) return 0; - - if (!$.support.boxModel) return outerWidth; - - // strip border and padding from outerWidth to get CSS Width - var W = outerWidth - - b($E, "Left") - - b($E, "Right") - - n($E, "paddingLeft") - - n($E, "paddingRight") - ; - - return max(0,W); - } - - /** - * Return the innerHeight for the current browser/doctype - * - * @see initPanes(), sizeMidPanes(), initHandles(), sizeHandles() - * @param {Array.} $E Must pass a jQuery object - first element is processed - * @param {number=} outerHeight (optional) Can pass a width, allowing calculations BEFORE element is resized - * @return {number} Returns the innerHeight of the elem by subtracting padding and borders - */ -, cssHeight: function ($E, outerHeight) { - var - b = $.layout.borderWidth - , n = $.layout.cssNum - ; - // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed - if (outerHeight <= 0) return 0; - - if (!$.support.boxModel) return outerHeight; - - // strip border and padding from outerHeight to get CSS Height - var H = outerHeight - - b($E, "Top") - - b($E, "Bottom") - - n($E, "paddingTop") - - n($E, "paddingBottom") - ; - - return max(0,H); - } - - /** - * Returns the 'current CSS numeric value' for a CSS property - 0 if property does not exist - * - * @see Called by many methods - * @param {Array.} $E Must pass a jQuery object - first element is processed - * @param {string} prop The name of the CSS property, eg: top, width, etc. - * @param {boolean=} [allowAuto=false] true = return 'auto' if that is value; false = return 0 - * @return {(string|number)} Usually used to get an integer value for position (top, left) or size (height, width) - */ -, cssNum: function ($E, prop, allowAuto) { - if (!$E.jquery) $E = $($E); - var CSS = $.layout.showInvisibly($E) - , p = $.curCSS($E[0], prop, true) - , v = allowAuto && p=="auto" ? p : (parseInt(p, 10) || 0); - $E.css( CSS ); // RESET - return v; - } - -, borderWidth: function (el, side) { - if (el.jquery) el = el[0]; - var b = "border"+ side.substr(0,1).toUpperCase() + side.substr(1); // left => Left - return $.curCSS(el, b+"Style", true) === "none" ? 0 : (parseInt($.curCSS(el, b+"Width", true), 10) || 0); - } - - /** - * Mouse-tracking utility - FUTURE REFERENCE - * - * init: if (!window.mouse) { - * window.mouse = { x: 0, y: 0 }; - * $(document).mousemove( $.layout.trackMouse ); - * } - * - * @param {Object} evt - * -, trackMouse: function (evt) { - window.mouse = { x: evt.clientX, y: evt.clientY }; - } - */ - - /** - * SUBROUTINE for preventPrematureSlideClose option - * - * @param {Object} evt - * @param {Object=} el - */ -, isMouseOverElem: function (evt, el) { - var - $E = $(el || this) - , d = $E.offset() - , T = d.top - , L = d.left - , R = L + $E.outerWidth() - , B = T + $E.outerHeight() - , x = evt.pageX // evt.clientX ? - , y = evt.pageY // evt.clientY ? - ; - // if X & Y are < 0, probably means is over an open SELECT - return ($.layout.browser.msie && x < 0 && y < 0) || ((x >= L && x <= R) && (y >= T && y <= B)); - } - - /** - * Message/Logging Utility - * - * @example $.layout.msg("My message"); // log text - * @example $.layout.msg("My message", true); // alert text - * @example $.layout.msg({ foo: "bar" }, "Title"); // log hash-data, with custom title - * @example $.layout.msg({ foo: "bar" }, true, "Title", { sort: false }); -OR- - * @example $.layout.msg({ foo: "bar" }, "Title", { sort: false, display: true }); // alert hash-data - * - * @param {(Object|string)} info String message OR Hash/Array - * @param {(Boolean|string|Object)=} [popup=false] True means alert-box - can be skipped - * @param {(Object|string)=} [debugTitle=""] Title for Hash data - can be skipped - * @param {Object=} [debutOpts={}] Extra options for debug output - */ -, msg: function (info, popup, debugTitle, debugOpts) { - if ($.isPlainObject(info) && window.debugData) { - if (typeof popup === "string") { - debugOpts = debugTitle; - debugTitle = popup; - } - else if (typeof debugTitle === "object") { - debugOpts = debugTitle; - debugTitle = null; - } - var t = debugTitle || "log( )" - , o = $.extend({ sort: false, returnHTML: false, display: false }, debugOpts); - if (popup === true || o.display) - debugData( info, t, o ); - else if (window.console) - console.log(debugData( info, t, o )); - } - else if (popup) - alert(info); - else if (window.console) - console.log(info); - else { - var id = "#layoutLogger" - , $l = $(id); - if (!$l.length) - $l = createLog(); - $l.children("ul").append('
  • '+ info.replace(/\/g,">") +'
  • '); - } - - function createLog () { - var pos = $.support.fixedPosition ? 'fixed' : 'absolute' - , $e = $('
    ' - + '
    ' - + 'XLayout console.log
    ' - + '
      ' - + '
      ' - ).appendTo("body"); - $e.css('left', $(window).width() - $e.outerWidth() - 5) - if ($.ui.draggable) $e.draggable({ handle: ':first-child' }); - return $e; - }; - } + version: "1.3.rc30.51" +, revision: 0.033005 // 1.3.0 final = 1.0300 - major(n+).minor(nn)+patch(nn+) + + // LANGUAGE CUSTOMIZATION +, language: { + // Tips and messages for resizers, togglers, custom buttons, etc. + Open: "Open" // eg: "Open Pane" + , Close: "Close" + , Resize: "Resize" + , Slide: "Slide Open" + , Pin: "Pin" + , Unpin: "Un-Pin" + , noRoomToOpenTip: "Not enough room to show this pane." + , minSizeWarning: "Panel has reached its minimum size" + , maxSizeWarning: "Panel has reached its maximum size" + // Developer error messages + , pane: "pane" // description of "layout pane element" + , selector: "selector" // description of "jQuery-selector" + , errButton: "Error Adding Button \n\nInvalid " + , errContainerMissing: "UI Layout Initialization Error\n\nThe specified layout-container does not exist." + , errCenterPaneMissing: "UI Layout Initialization Error\n\nThe center-pane element does not exist.\n\nThe center-pane is a required element." + , errContainerHeight: "UI Layout Initialization Warning\n\nThe layout-container \"CONTAINER\" has no height.\n\nTherefore the layout is 0-height and hence 'invisible'!" + } + + // can update code here if $.browser is phased out +, browser: { + mozilla: !!$.browser.mozilla + , webkit: !!$.browser.webkit || !!$.browser.safari // webkit = jQ 1.4 + , msie: !!$.browser.msie + , isIE6: !!$.browser.msie && $.browser.version == 6 + , version: $.browser.version // not used in Layout core, but may be used by plugins + } + + // *PREDEFINED* EFFECTS & DEFAULTS + // MUST list effect here - OR MUST set an fxSettings option (can be an empty hash: {}) +, effects: { + + // Pane Open/Close Animations + slide: { + all: { duration: "fast" } // eg: duration: 1000, easing: "easeOutBounce" + , north: { direction: "up" } + , south: { direction: "down" } + , east: { direction: "right"} + , west: { direction: "left" } + } + , drop: { + all: { duration: "slow" } + , north: { direction: "up" } + , south: { direction: "down" } + , east: { direction: "right"} + , west: { direction: "left" } + } + , scale: { + all: { duration: "fast" } + } + // these are not recommended, but can be used + , blind: {} + , clip: {} + , explode: {} + , fade: {} + , fold: {} + , puff: {} + + // Pane Resize Animations + , size: { + all: { easing: "swing" } + } + } + + // INTERNAL CONFIG DATA - DO NOT CHANGE THIS! +, config: { + optionRootKeys: "effects,panes,north,south,west,east,center".split(",") + , allPanes: "north,south,west,east,center".split(",") + , borderPanes: "north,south,west,east".split(",") + , oppositeEdge: { + north: "south" + , south: "north" + , east: "west" + , west: "east" + } + // offscreen data + , offscreenCSS: { left: "-99999px", right: "auto" } // used by hide/close if useOffscreenClose=true + , offscreenReset: "offscreenReset" // key used for data + // CSS used in multiple places + , hidden: { visibility: "hidden" } + , visible: { visibility: "visible" } + // layout element settings + , resizers: { + cssReq: { + position: "absolute" + , padding: 0 + , margin: 0 + , fontSize: "1px" + , textAlign: "left" // to counter-act "center" alignment! + , overflow: "hidden" // prevent toggler-button from overflowing + // SEE $.layout.defaults.zIndexes.resizer_normal + } + , cssDemo: { // DEMO CSS - applied if: options.PANE.applyDemoStyles=true + background: "#DDD" + , border: "none" + } + } + , togglers: { + cssReq: { + position: "absolute" + , display: "block" + , padding: 0 + , margin: 0 + , overflow: "hidden" + , textAlign: "center" + , fontSize: "1px" + , cursor: "pointer" + , zIndex: 1 + } + , cssDemo: { // DEMO CSS - applied if: options.PANE.applyDemoStyles=true + background: "#AAA" + } + } + , content: { + cssReq: { + position: "relative" /* contain floated or positioned elements */ + } + , cssDemo: { // DEMO CSS - applied if: options.PANE.applyDemoStyles=true + overflow: "auto" + , padding: "10px" + } + , cssDemoPane: { // DEMO CSS - REMOVE scrolling from 'pane' when it has a content-div + overflow: "hidden" + , padding: 0 + } + } + , panes: { // defaults for ALL panes - overridden by 'per-pane settings' below + cssReq: { + position: "absolute" + , margin: 0 + // $.layout.defaults.zIndexes.pane_normal + } + , cssDemo: { // DEMO CSS - applied if: options.PANE.applyDemoStyles=true + padding: "10px" + , background: "#FFF" + , border: "1px solid #BBB" + , overflow: "auto" + } + } + , north: { + side: "Top" + , sizeType: "Height" + , dir: "horz" + , cssReq: { + top: 0 + , bottom: "auto" + , left: 0 + , right: 0 + , width: "auto" + // height: DYNAMIC + } + } + , south: { + side: "Bottom" + , sizeType: "Height" + , dir: "horz" + , cssReq: { + top: "auto" + , bottom: 0 + , left: 0 + , right: 0 + , width: "auto" + // height: DYNAMIC + } + } + , east: { + side: "Right" + , sizeType: "Width" + , dir: "vert" + , cssReq: { + left: "auto" + , right: 0 + , top: "auto" // DYNAMIC + , bottom: "auto" // DYNAMIC + , height: "auto" + // width: DYNAMIC + } + } + , west: { + side: "Left" + , sizeType: "Width" + , dir: "vert" + , cssReq: { + left: 0 + , right: "auto" + , top: "auto" // DYNAMIC + , bottom: "auto" // DYNAMIC + , height: "auto" + // width: DYNAMIC + } + } + , center: { + dir: "center" + , cssReq: { + left: "auto" // DYNAMIC + , right: "auto" // DYNAMIC + , top: "auto" // DYNAMIC + , bottom: "auto" // DYNAMIC + , height: "auto" + , width: "auto" + } + } + } + + // CALLBACK FUNCTION NAMESPACE - used to store reusable callback functions +, callbacks: {} + +, getParentPaneElem: function (el) { + // must pass either a container or pane element + var $el = $(el) + , layout = $el.data("layout") || $el.data("parentLayout"); + if (layout) { + var $cont = layout.container; + // see if this container is directly-nested inside an outer-pane + if ($cont.data("layoutPane")) return $cont; + var $pane = $cont.closest("."+ $.layout.defaults.panes.paneClass); + // if a pane was found, return it + if ($pane.data("layoutPane")) return $pane; + } + return null; + } + +, getParentPaneInstance: function (el) { + // must pass either a container or pane element + var $pane = $.layout.getParentPaneElem(el); + return $pane ? $pane.data("layoutPane") : null; + } + +, getParentLayoutInstance: function (el) { + // must pass either a container or pane element + var $pane = $.layout.getParentPaneElem(el); + return $pane ? $pane.data("parentLayout") : null; + } + +, getEventObject: function (evt) { + return typeof evt === "object" && evt.stopPropagation ? evt : null; + } +, parsePaneName: function (evt_or_pane) { + // getEventObject() automatically calls .stopPropagation(), WHICH MUST BE DONE! + var evt = $.layout.getEventObject( evt_or_pane ); + if (evt) { + // ALWAYS stop propagation of events triggered in Layout! + evt.stopPropagation(); + return $(this).data("layoutEdge"); + } + else + return evt_or_pane; + } + + + // LAYOUT-PLUGIN REGISTRATION + // more plugins can added beyond this default list +, plugins: { + draggable: !!$.fn.draggable // resizing + , effects: { + core: !!$.effects // animimations (specific effects tested by initOptions) + , slide: $.effects && $.effects.slide // default effect + } + } + +// arrays of plugin or other methods to be triggered for events in *each layout* - will be passed 'Instance' +, onCreate: [] // runs when layout is just starting to be created - right after options are set +, onLoad: [] // runs after layout container and global events init, but before initPanes is called +, onReady: [] // runs after initialization *completes* - ie, after initPanes completes successfully +, onDestroy: [] // runs after layout is destroyed +, onUnload: [] // runs after layout is destroyed OR when page unloads +, afterOpen: [] // runs after setAsOpen() completes +, afterClose: [] // runs after setAsClosed() completes + + /* + * GENERIC UTILITY METHODS + */ + + // calculate and return the scrollbar width, as an integer +, scrollbarWidth: function () { return window.scrollbarWidth || $.layout.getScrollbarSize('width'); } +, scrollbarHeight: function () { return window.scrollbarHeight || $.layout.getScrollbarSize('height'); } +, getScrollbarSize: function (dim) { + var $c = $('
      ').appendTo("body"); + var d = { width: $c.width() - $c[0].clientWidth, height: $c.height() - $c[0].clientHeight }; + $c.remove(); + window.scrollbarWidth = d.width; + window.scrollbarHeight = d.height; + return dim.match(/^(width|height)$/) ? d[dim] : d; + } + + + /** + * Returns hash container 'display' and 'visibility' + * + * @see $.swap() - swaps CSS, runs callback, resets CSS + */ +, showInvisibly: function ($E, force) { + if (!$E) return {}; + if (!$E.jquery) $E = $($E); + var CSS = { + display: $E.css('display') + , visibility: $E.css('visibility') + }; + if (force || CSS.display === "none") { // only if not *already hidden* + $E.css({ display: "block", visibility: "hidden" }); // show element 'invisibly' so can be measured + return CSS; + } + else return {}; + } + + /** + * Returns data for setting size of an element (container or a pane). + * + * @see _create(), onWindowResize() for container, plus others for pane + * @return JSON Returns a hash of all dimensions: top, bottom, left, right, outerWidth, innerHeight, etc + */ +, getElementDimensions: function ($E) { + var + d = {} // dimensions hash + , x = d.css = {} // CSS hash + , i = {} // TEMP insets + , b, p // TEMP border, padding + , N = $.layout.cssNum + , off = $E.offset() + ; + d.offsetLeft = off.left; + d.offsetTop = off.top; + + $.each("Left,Right,Top,Bottom".split(","), function (idx, e) { // e = edge + b = x["border" + e] = $.layout.borderWidth($E, e); + p = x["padding"+ e] = $.layout.cssNum($E, "padding"+e); + i[e] = b + p; // total offset of content from outer side + d["inset"+ e] = p; + }); + + d.offsetWidth = $E.innerWidth(); // offsetWidth is used in calc when doing manual resize + d.offsetHeight = $E.innerHeight(); // ditto + d.outerWidth = $E.outerWidth(); + d.outerHeight = $E.outerHeight(); + d.innerWidth = max(0, d.outerWidth - i.Left - i.Right); + d.innerHeight = max(0, d.outerHeight - i.Top - i.Bottom); + + x.width = $E.width(); + x.height = $E.height(); + x.top = N($E,"top",true); + x.bottom = N($E,"bottom",true); + x.left = N($E,"left",true); + x.right = N($E,"right",true); + + //d.visible = $E.is(":visible");// && x.width > 0 && x.height > 0; + + return d; + } + +, getElementCSS: function ($E, list) { + var + CSS = {} + , style = $E[0].style + , props = list.split(",") + , sides = "Top,Bottom,Left,Right".split(",") + , attrs = "Color,Style,Width".split(",") + , p, s, a, i, j, k + ; + for (i=0; i < props.length; i++) { + p = props[i]; + if (p.match(/(border|padding|margin)$/)) + for (j=0; j < 4; j++) { + s = sides[j]; + if (p === "border") + for (k=0; k < 3; k++) { + a = attrs[k]; + CSS[p+s+a] = style[p+s+a]; + } + else + CSS[p+s] = style[p+s]; + } + else + CSS[p] = style[p]; + }; + return CSS + } + + /** + * Return the innerWidth for the current browser/doctype + * + * @see initPanes(), sizeMidPanes(), initHandles(), sizeHandles() + * @param {Array.} $E Must pass a jQuery object - first element is processed + * @param {number=} outerWidth (optional) Can pass a width, allowing calculations BEFORE element is resized + * @return {number} Returns the innerWidth of the elem by subtracting padding and borders + */ +, cssWidth: function ($E, outerWidth) { + var + b = $.layout.borderWidth + , n = $.layout.cssNum + ; + // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed + if (outerWidth <= 0) return 0; + + if (!$.support.boxModel) return outerWidth; + + // strip border and padding from outerWidth to get CSS Width + var W = outerWidth + - b($E, "Left") + - b($E, "Right") + - n($E, "paddingLeft") + - n($E, "paddingRight") + ; + + return max(0,W); + } + + /** + * Return the innerHeight for the current browser/doctype + * + * @see initPanes(), sizeMidPanes(), initHandles(), sizeHandles() + * @param {Array.} $E Must pass a jQuery object - first element is processed + * @param {number=} outerHeight (optional) Can pass a width, allowing calculations BEFORE element is resized + * @return {number} Returns the innerHeight of the elem by subtracting padding and borders + */ +, cssHeight: function ($E, outerHeight) { + var + b = $.layout.borderWidth + , n = $.layout.cssNum + ; + // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed + if (outerHeight <= 0) return 0; + + if (!$.support.boxModel) return outerHeight; + + // strip border and padding from outerHeight to get CSS Height + var H = outerHeight + - b($E, "Top") + - b($E, "Bottom") + - n($E, "paddingTop") + - n($E, "paddingBottom") + ; + + return max(0,H); + } + + /** + * Returns the 'current CSS numeric value' for a CSS property - 0 if property does not exist + * + * @see Called by many methods + * @param {Array.} $E Must pass a jQuery object - first element is processed + * @param {string} prop The name of the CSS property, eg: top, width, etc. + * @param {boolean=} [allowAuto=false] true = return 'auto' if that is value; false = return 0 + * @return {(string|number)} Usually used to get an integer value for position (top, left) or size (height, width) + */ +, cssNum: function ($E, prop, allowAuto) { + if (!$E.jquery) $E = $($E); + var CSS = $.layout.showInvisibly($E) + , p = $.curCSS($E[0], prop, true) + , v = allowAuto && p=="auto" ? p : (parseInt(p, 10) || 0); + $E.css( CSS ); // RESET + return v; + } + +, borderWidth: function (el, side) { + if (el.jquery) el = el[0]; + var b = "border"+ side.substr(0,1).toUpperCase() + side.substr(1); // left => Left + return $.curCSS(el, b+"Style", true) === "none" ? 0 : (parseInt($.curCSS(el, b+"Width", true), 10) || 0); + } + + /** + * Mouse-tracking utility - FUTURE REFERENCE + * + * init: if (!window.mouse) { + * window.mouse = { x: 0, y: 0 }; + * $(document).mousemove( $.layout.trackMouse ); + * } + * + * @param {Object} evt + * +, trackMouse: function (evt) { + window.mouse = { x: evt.clientX, y: evt.clientY }; + } + */ + + /** + * SUBROUTINE for preventPrematureSlideClose option + * + * @param {Object} evt + * @param {Object=} el + */ +, isMouseOverElem: function (evt, el) { + var + $E = $(el || this) + , d = $E.offset() + , T = d.top + , L = d.left + , R = L + $E.outerWidth() + , B = T + $E.outerHeight() + , x = evt.pageX // evt.clientX ? + , y = evt.pageY // evt.clientY ? + ; + // if X & Y are < 0, probably means is over an open SELECT + return ($.layout.browser.msie && x < 0 && y < 0) || ((x >= L && x <= R) && (y >= T && y <= B)); + } + + /** + * Message/Logging Utility + * + * @example $.layout.msg("My message"); // log text + * @example $.layout.msg("My message", true); // alert text + * @example $.layout.msg({ foo: "bar" }, "Title"); // log hash-data, with custom title + * @example $.layout.msg({ foo: "bar" }, true, "Title", { sort: false }); -OR- + * @example $.layout.msg({ foo: "bar" }, "Title", { sort: false, display: true }); // alert hash-data + * + * @param {(Object|string)} info String message OR Hash/Array + * @param {(Boolean|string|Object)=} [popup=false] True means alert-box - can be skipped + * @param {(Object|string)=} [debugTitle=""] Title for Hash data - can be skipped + * @param {Object=} [debutOpts={}] Extra options for debug output + */ +, msg: function (info, popup, debugTitle, debugOpts) { + if ($.isPlainObject(info) && window.debugData) { + if (typeof popup === "string") { + debugOpts = debugTitle; + debugTitle = popup; + } + else if (typeof debugTitle === "object") { + debugOpts = debugTitle; + debugTitle = null; + } + var t = debugTitle || "log( )" + , o = $.extend({ sort: false, returnHTML: false, display: false }, debugOpts); + if (popup === true || o.display) + debugData( info, t, o ); + else if (window.console) + console.log(debugData( info, t, o )); + } + else if (popup) + alert(info); + else if (window.console) + console.log(info); + else { + var id = "#layoutLogger" + , $l = $(id); + if (!$l.length) + $l = createLog(); + $l.children("ul").append('
    • '+ info.replace(/\/g,">") +'
    • '); + } + + function createLog () { + var pos = $.support.fixedPosition ? 'fixed' : 'absolute' + , $e = $('
      ' + + '
      ' + + 'XLayout console.log
      ' + + '
        ' + + '
        ' + ).appendTo("body"); + $e.css('left', $(window).width() - $e.outerWidth() - 5) + if ($.ui.draggable) $e.draggable({ handle: ':first-child' }); + return $e; + }; + } }; -var lang = $.layout.language; // alias used in defaults... +var lang = $.layout.language; // alias used in defaults... // DEFAULT OPTIONS - CHANGE IF DESIRED $.layout.defaults = { /* - * LAYOUT & LAYOUT-CONTAINER OPTIONS - * - none of these options are applicable to individual panes + * LAYOUT & LAYOUT-CONTAINER OPTIONS + * - none of these options are applicable to individual panes */ - name: "" // Not required, but useful for buttons and used for the state-cookie -, containerSelector: "" // ONLY used when specifying a childOptions - to find container-element that is NOT directly-nested -, containerClass: "ui-layout-container" // layout-container element -, scrollToBookmarkOnLoad: true // after creating a layout, scroll to bookmark in URL (.../page.htm#myBookmark) -, resizeWithWindow: true // bind thisLayout.resizeAll() to the window.resize event -, resizeWithWindowDelay: 200 // delay calling resizeAll because makes window resizing very jerky -, resizeWithWindowMaxDelay: 0 // 0 = none - force resize every XX ms while window is being resized -, onresizeall_start: null // CALLBACK when resizeAll() STARTS - NOT pane-specific -, onresizeall_end: null // CALLBACK when resizeAll() ENDS - NOT pane-specific -, onload_start: null // CALLBACK when Layout inits - after options initialized, but before elements -, onload_end: null // CALLBACK when Layout inits - after EVERYTHING has been initialized -, onunload_start: null // CALLBACK when Layout is destroyed OR onWindowUnload -, onunload_end: null // CALLBACK when Layout is destroyed OR onWindowUnload -, autoBindCustomButtons: false // search for buttons with ui-layout-button class and auto-bind them -, initPanes: true // false = DO NOT initialize the panes onLoad - will init later -, showErrorMessages: true // enables fatal error messages to warn developers of common errors -, showDebugMessages: false // display console-and-alert debug msgs - IF this Layout version _has_ debugging code! -// Changing this zIndex value will cause other zIndex values to automatically change -, zIndex: null // the PANE zIndex - resizers and masks will be +1 -// DO NOT CHANGE the zIndex values below unless you clearly understand their relationships -, zIndexes: { // set _default_ z-index values here... - pane_normal: 0 // normal z-index for panes - , content_mask: 1 // applied to overlays used to mask content INSIDE panes during resizing - , resizer_normal: 2 // normal z-index for resizer-bars - , pane_sliding: 100 // applied to *BOTH* the pane and its resizer when a pane is 'slid open' - , pane_animate: 1000 // applied to the pane when being animated - not applied to the resizer - , resizer_drag: 10000 // applied to the CLONED resizer-bar when being 'dragged' - } + name: "" // Not required, but useful for buttons and used for the state-cookie +, containerSelector: "" // ONLY used when specifying a childOptions - to find container-element that is NOT directly-nested +, containerClass: "ui-layout-container" // layout-container element +, scrollToBookmarkOnLoad: true // after creating a layout, scroll to bookmark in URL (.../page.htm#myBookmark) +, resizeWithWindow: true // bind thisLayout.resizeAll() to the window.resize event +, resizeWithWindowDelay: 200 // delay calling resizeAll because makes window resizing very jerky +, resizeWithWindowMaxDelay: 0 // 0 = none - force resize every XX ms while window is being resized +, onresizeall_start: null // CALLBACK when resizeAll() STARTS - NOT pane-specific +, onresizeall_end: null // CALLBACK when resizeAll() ENDS - NOT pane-specific +, onload_start: null // CALLBACK when Layout inits - after options initialized, but before elements +, onload_end: null // CALLBACK when Layout inits - after EVERYTHING has been initialized +, onunload_start: null // CALLBACK when Layout is destroyed OR onWindowUnload +, onunload_end: null // CALLBACK when Layout is destroyed OR onWindowUnload +, autoBindCustomButtons: false // search for buttons with ui-layout-button class and auto-bind them +, initPanes: true // false = DO NOT initialize the panes onLoad - will init later +, showErrorMessages: true // enables fatal error messages to warn developers of common errors +, showDebugMessages: false // display console-and-alert debug msgs - IF this Layout version _has_ debugging code! +// Changing this zIndex value will cause other zIndex values to automatically change +, zIndex: null // the PANE zIndex - resizers and masks will be +1 +// DO NOT CHANGE the zIndex values below unless you clearly understand their relationships +, zIndexes: { // set _default_ z-index values here... + pane_normal: 0 // normal z-index for panes + , content_mask: 1 // applied to overlays used to mask content INSIDE panes during resizing + , resizer_normal: 2 // normal z-index for resizer-bars + , pane_sliding: 100 // applied to *BOTH* the pane and its resizer when a pane is 'slid open' + , pane_animate: 1000 // applied to the pane when being animated - not applied to the resizer + , resizer_drag: 10000 // applied to the CLONED resizer-bar when being 'dragged' + } /* - * PANE DEFAULT SETTINGS - * - settings under the 'panes' key become the default settings for *all panes* - * - ALL pane-options can also be set specifically for each panes, which will override these 'default values' + * PANE DEFAULT SETTINGS + * - settings under the 'panes' key become the default settings for *all panes* + * - ALL pane-options can also be set specifically for each panes, which will override these 'default values' */ -, panes: { // default options for 'all panes' - will be overridden by 'per-pane settings' - applyDemoStyles: false // NOTE: renamed from applyDefaultStyles for clarity - , closable: true // pane can open & close - , resizable: true // when open, pane can be resized - , slidable: true // when closed, pane can 'slide open' over other panes - closes on mouse-out - , initClosed: false // true = init pane as 'closed' - , initHidden: false // true = init pane as 'hidden' - no resizer-bar/spacing - // SELECTORS - //, paneSelector: "" // MUST be pane-specific - jQuery selector for pane - , contentSelector: ".ui-layout-content" // INNER div/element to auto-size so only it scrolls, not the entire pane! - , contentIgnoreSelector: ".ui-layout-ignore" // element(s) to 'ignore' when measuring 'content' - , findNestedContent: false // true = $P.find(contentSelector), false = $P.children(contentSelector) - // GENERIC ROOT-CLASSES - for auto-generated classNames - , paneClass: "ui-layout-pane" // Layout Pane - , resizerClass: "ui-layout-resizer" // Resizer Bar - , togglerClass: "ui-layout-toggler" // Toggler Button - , buttonClass: "ui-layout-button" // CUSTOM Buttons - eg: '[ui-layout-button]-toggle/-open/-close/-pin' - // ELEMENT SIZE & SPACING - //, size: 100 // MUST be pane-specific -initial size of pane - , minSize: 0 // when manually resizing a pane - , maxSize: 0 // ditto, 0 = no limit - , spacing_open: 6 // space between pane and adjacent panes - when pane is 'open' - , spacing_closed: 6 // ditto - when pane is 'closed' - , togglerLength_open: 50 // Length = WIDTH of toggler button on north/south sides - HEIGHT on east/west sides - , togglerLength_closed: 50 // 100% OR -1 means 'full height/width of resizer bar' - 0 means 'hidden' - , togglerAlign_open: "center" // top/left, bottom/right, center, OR... - , togglerAlign_closed: "center" // 1 => nn = offset from top/left, -1 => -nn == offset from bottom/right - , togglerTip_open: lang.Close // Toggler tool-tip (title) - , togglerTip_closed: lang.Open // ditto - , togglerContent_open: "" // text or HTML to put INSIDE the toggler - , togglerContent_closed: "" // ditto - // RESIZING OPTIONS - , resizerDblClickToggle: true // - , autoResize: true // IF size is 'auto' or a percentage, then recalc 'pixel size' whenever the layout resizes - , autoReopen: true // IF a pane was auto-closed due to noRoom, reopen it when there is room? False = leave it closed - , resizerDragOpacity: 1 // option for ui.draggable - //, resizerCursor: "" // MUST be pane-specific - cursor when over resizer-bar - , maskContents: false // true = add DIV-mask over-or-inside this pane so can 'drag' over IFRAMES - , maskObjects: false // true = add IFRAME-mask over-or-inside this pane to cover objects/applets - content-mask will overlay this mask - , maskZindex: null // will override zIndexes.content_mask if specified - not applicable to iframe-panes - , resizingGrid: false // grid size that the resizers will snap-to during resizing, eg: [20,20] - , livePaneResizing: false // true = LIVE Resizing as resizer is dragged - , liveContentResizing: false // true = re-measure header/footer heights as resizer is dragged - , liveResizingTolerance: 1 // how many px change before pane resizes, to control performance - // TIPS & MESSAGES - also see lang object - , noRoomToOpenTip: lang.noRoomToOpenTip - , resizerTip: lang.Resize // Resizer tool-tip (title) - , sliderTip: lang.Slide // resizer-bar triggers 'sliding' when pane is closed - , sliderCursor: "pointer" // cursor when resizer-bar will trigger 'sliding' - , slideTrigger_open: "click" // click, dblclick, mouseenter - , slideTrigger_close: "mouseleave"// click, mouseleave - , slideDelay_open: 300 // applies only for mouseenter event - 0 = instant open - , slideDelay_close: 300 // applies only for mouseleave event (300ms is the minimum!) - , hideTogglerOnSlide: false // when pane is slid-open, should the toggler show? - , preventQuickSlideClose: $.layout.browser.webkit // Chrome triggers slideClosed as it is opening - , preventPrematureSlideClose: false // handle incorrect mouseleave trigger, like when over a SELECT-list in IE - // HOT-KEYS & MISC - , showOverflowOnHover: false // will bind allowOverflow() utility to pane.onMouseOver - , enableCursorHotkey: true // enabled 'cursor' hotkeys - //, customHotkey: "" // MUST be pane-specific - EITHER a charCode OR a character - , customHotkeyModifier: "SHIFT" // either 'SHIFT', 'CTRL' or 'CTRL+SHIFT' - NOT 'ALT' - // PANE ANIMATION - // NOTE: fxSss_open, fxSss_close & fxSss_size options (eg: fxName_open) are auto-generated if not passed - , fxName: "slide" // ('none' or blank), slide, drop, scale -- only relevant to 'open' & 'close', NOT 'size' - , fxSpeed: null // slow, normal, fast, 200, nnn - if passed, will OVERRIDE fxSettings.duration - , fxSettings: {} // can be passed, eg: { easing: "easeOutBounce", duration: 1500 } - , fxOpacityFix: true // tries to fix opacity in IE to restore anti-aliasing after animation - , animatePaneSizing: false // true = animate resizing after dragging resizer-bar OR sizePane() is called +, panes: { // default options for 'all panes' - will be overridden by 'per-pane settings' + applyDemoStyles: false // NOTE: renamed from applyDefaultStyles for clarity + , closable: true // pane can open & close + , resizable: true // when open, pane can be resized + , slidable: true // when closed, pane can 'slide open' over other panes - closes on mouse-out + , initClosed: false // true = init pane as 'closed' + , initHidden: false // true = init pane as 'hidden' - no resizer-bar/spacing + // SELECTORS + //, paneSelector: "" // MUST be pane-specific - jQuery selector for pane + , contentSelector: ".ui-layout-content" // INNER div/element to auto-size so only it scrolls, not the entire pane! + , contentIgnoreSelector: ".ui-layout-ignore" // element(s) to 'ignore' when measuring 'content' + , findNestedContent: false // true = $P.find(contentSelector), false = $P.children(contentSelector) + // GENERIC ROOT-CLASSES - for auto-generated classNames + , paneClass: "ui-layout-pane" // Layout Pane + , resizerClass: "ui-layout-resizer" // Resizer Bar + , togglerClass: "ui-layout-toggler" // Toggler Button + , buttonClass: "ui-layout-button" // CUSTOM Buttons - eg: '[ui-layout-button]-toggle/-open/-close/-pin' + // ELEMENT SIZE & SPACING + //, size: 100 // MUST be pane-specific -initial size of pane + , minSize: 0 // when manually resizing a pane + , maxSize: 0 // ditto, 0 = no limit + , spacing_open: 6 // space between pane and adjacent panes - when pane is 'open' + , spacing_closed: 6 // ditto - when pane is 'closed' + , togglerLength_open: 50 // Length = WIDTH of toggler button on north/south sides - HEIGHT on east/west sides + , togglerLength_closed: 50 // 100% OR -1 means 'full height/width of resizer bar' - 0 means 'hidden' + , togglerAlign_open: "center" // top/left, bottom/right, center, OR... + , togglerAlign_closed: "center" // 1 => nn = offset from top/left, -1 => -nn == offset from bottom/right + , togglerTip_open: lang.Close // Toggler tool-tip (title) + , togglerTip_closed: lang.Open // ditto + , togglerContent_open: "" // text or HTML to put INSIDE the toggler + , togglerContent_closed: "" // ditto + // RESIZING OPTIONS + , resizerDblClickToggle: true // + , autoResize: true // IF size is 'auto' or a percentage, then recalc 'pixel size' whenever the layout resizes + , autoReopen: true // IF a pane was auto-closed due to noRoom, reopen it when there is room? False = leave it closed + , resizerDragOpacity: 1 // option for ui.draggable + //, resizerCursor: "" // MUST be pane-specific - cursor when over resizer-bar + , maskContents: false // true = add DIV-mask over-or-inside this pane so can 'drag' over IFRAMES + , maskObjects: false // true = add IFRAME-mask over-or-inside this pane to cover objects/applets - content-mask will overlay this mask + , maskZindex: null // will override zIndexes.content_mask if specified - not applicable to iframe-panes + , resizingGrid: false // grid size that the resizers will snap-to during resizing, eg: [20,20] + , livePaneResizing: false // true = LIVE Resizing as resizer is dragged + , liveContentResizing: false // true = re-measure header/footer heights as resizer is dragged + , liveResizingTolerance: 1 // how many px change before pane resizes, to control performance + // TIPS & MESSAGES - also see lang object + , noRoomToOpenTip: lang.noRoomToOpenTip + , resizerTip: lang.Resize // Resizer tool-tip (title) + , sliderTip: lang.Slide // resizer-bar triggers 'sliding' when pane is closed + , sliderCursor: "pointer" // cursor when resizer-bar will trigger 'sliding' + , slideTrigger_open: "click" // click, dblclick, mouseenter + , slideTrigger_close: "mouseleave"// click, mouseleave + , slideDelay_open: 300 // applies only for mouseenter event - 0 = instant open + , slideDelay_close: 300 // applies only for mouseleave event (300ms is the minimum!) + , hideTogglerOnSlide: false // when pane is slid-open, should the toggler show? + , preventQuickSlideClose: $.layout.browser.webkit // Chrome triggers slideClosed as it is opening + , preventPrematureSlideClose: false // handle incorrect mouseleave trigger, like when over a SELECT-list in IE + // HOT-KEYS & MISC + , showOverflowOnHover: false // will bind allowOverflow() utility to pane.onMouseOver + , enableCursorHotkey: true // enabled 'cursor' hotkeys + //, customHotkey: "" // MUST be pane-specific - EITHER a charCode OR a character + , customHotkeyModifier: "SHIFT" // either 'SHIFT', 'CTRL' or 'CTRL+SHIFT' - NOT 'ALT' + // PANE ANIMATION + // NOTE: fxSss_open, fxSss_close & fxSss_size options (eg: fxName_open) are auto-generated if not passed + , fxName: "slide" // ('none' or blank), slide, drop, scale -- only relevant to 'open' & 'close', NOT 'size' + , fxSpeed: null // slow, normal, fast, 200, nnn - if passed, will OVERRIDE fxSettings.duration + , fxSettings: {} // can be passed, eg: { easing: "easeOutBounce", duration: 1500 } + , fxOpacityFix: true // tries to fix opacity in IE to restore anti-aliasing after animation + , animatePaneSizing: false // true = animate resizing after dragging resizer-bar OR sizePane() is called /* NOTE: Action-specific FX options are auto-generated from the options above if not specifically set: - fxName_open: "slide" // 'Open' pane animation - fnName_close: "slide" // 'Close' pane animation - fxName_size: "slide" // 'Size' pane animation - when animatePaneSizing = true - fxSpeed_open: null - fxSpeed_close: null - fxSpeed_size: null - fxSettings_open: {} - fxSettings_close: {} - fxSettings_size: {} - */ - // CHILD/NESTED LAYOUTS - , childOptions: null // Layout-options for nested/child layout - even {} is valid as options - , initChildLayout: true // true = child layout will be created as soon as _this_ layout completes initialization - , destroyChildLayout: true // true = destroy child-layout if this pane is destroyed - , resizeChildLayout: true // true = trigger child-layout.resizeAll() when this pane is resized - // PANE CALLBACKS - , triggerEventsOnLoad: false // true = trigger onopen OR onclose callbacks when layout initializes - , triggerEventsDuringLiveResize: true // true = trigger onresize callback REPEATEDLY if livePaneResizing==true - , onshow_start: null // CALLBACK when pane STARTS to Show - BEFORE onopen/onhide_start - , onshow_end: null // CALLBACK when pane ENDS being Shown - AFTER onopen/onhide_end - , onhide_start: null // CALLBACK when pane STARTS to Close - BEFORE onclose_start - , onhide_end: null // CALLBACK when pane ENDS being Closed - AFTER onclose_end - , onopen_start: null // CALLBACK when pane STARTS to Open - , onopen_end: null // CALLBACK when pane ENDS being Opened - , onclose_start: null // CALLBACK when pane STARTS to Close - , onclose_end: null // CALLBACK when pane ENDS being Closed - , onresize_start: null // CALLBACK when pane STARTS being Resized ***FOR ANY REASON*** - , onresize_end: null // CALLBACK when pane ENDS being Resized ***FOR ANY REASON*** - , onsizecontent_start: null // CALLBACK when sizing of content-element STARTS - , onsizecontent_end: null // CALLBACK when sizing of content-element ENDS - , onswap_start: null // CALLBACK when pane STARTS to Swap - , onswap_end: null // CALLBACK when pane ENDS being Swapped - , ondrag_start: null // CALLBACK when pane STARTS being ***MANUALLY*** Resized - , ondrag_end: null // CALLBACK when pane ENDS being ***MANUALLY*** Resized - } + fxName_open: "slide" // 'Open' pane animation + fnName_close: "slide" // 'Close' pane animation + fxName_size: "slide" // 'Size' pane animation - when animatePaneSizing = true + fxSpeed_open: null + fxSpeed_close: null + fxSpeed_size: null + fxSettings_open: {} + fxSettings_close: {} + fxSettings_size: {} + */ + // CHILD/NESTED LAYOUTS + , childOptions: null // Layout-options for nested/child layout - even {} is valid as options + , initChildLayout: true // true = child layout will be created as soon as _this_ layout completes initialization + , destroyChildLayout: true // true = destroy child-layout if this pane is destroyed + , resizeChildLayout: true // true = trigger child-layout.resizeAll() when this pane is resized + // PANE CALLBACKS + , triggerEventsOnLoad: false // true = trigger onopen OR onclose callbacks when layout initializes + , triggerEventsDuringLiveResize: true // true = trigger onresize callback REPEATEDLY if livePaneResizing==true + , onshow_start: null // CALLBACK when pane STARTS to Show - BEFORE onopen/onhide_start + , onshow_end: null // CALLBACK when pane ENDS being Shown - AFTER onopen/onhide_end + , onhide_start: null // CALLBACK when pane STARTS to Close - BEFORE onclose_start + , onhide_end: null // CALLBACK when pane ENDS being Closed - AFTER onclose_end + , onopen_start: null // CALLBACK when pane STARTS to Open + , onopen_end: null // CALLBACK when pane ENDS being Opened + , onclose_start: null // CALLBACK when pane STARTS to Close + , onclose_end: null // CALLBACK when pane ENDS being Closed + , onresize_start: null // CALLBACK when pane STARTS being Resized ***FOR ANY REASON*** + , onresize_end: null // CALLBACK when pane ENDS being Resized ***FOR ANY REASON*** + , onsizecontent_start: null // CALLBACK when sizing of content-element STARTS + , onsizecontent_end: null // CALLBACK when sizing of content-element ENDS + , onswap_start: null // CALLBACK when pane STARTS to Swap + , onswap_end: null // CALLBACK when pane ENDS being Swapped + , ondrag_start: null // CALLBACK when pane STARTS being ***MANUALLY*** Resized + , ondrag_end: null // CALLBACK when pane ENDS being ***MANUALLY*** Resized + } /* - * PANE-SPECIFIC SETTINGS - * - options listed below MUST be specified per-pane - they CANNOT be set under 'panes' - * - all options under the 'panes' key can also be set specifically for any pane - * - most options under the 'panes' key apply only to 'border-panes' - NOT the the center-pane + * PANE-SPECIFIC SETTINGS + * - options listed below MUST be specified per-pane - they CANNOT be set under 'panes' + * - all options under the 'panes' key can also be set specifically for any pane + * - most options under the 'panes' key apply only to 'border-panes' - NOT the the center-pane */ -, north: { - paneSelector: ".ui-layout-north" - , size: "auto" // eg: "auto", "30%", .30, 200 - , resizerCursor: "n-resize" // custom = url(myCursor.cur) - , customHotkey: "" // EITHER a charCode (43) OR a character ("o") - } -, south: { - paneSelector: ".ui-layout-south" - , size: "auto" - , resizerCursor: "s-resize" - , customHotkey: "" - } -, east: { - paneSelector: ".ui-layout-east" - , size: 200 - , resizerCursor: "e-resize" - , customHotkey: "" - } -, west: { - paneSelector: ".ui-layout-west" - , size: 200 - , resizerCursor: "w-resize" - , customHotkey: "" - } -, center: { - paneSelector: ".ui-layout-center" - , minWidth: 0 - , minHeight: 0 - } +, north: { + paneSelector: ".ui-layout-north" + , size: "auto" // eg: "auto", "30%", .30, 200 + , resizerCursor: "n-resize" // custom = url(myCursor.cur) + , customHotkey: "" // EITHER a charCode (43) OR a character ("o") + } +, south: { + paneSelector: ".ui-layout-south" + , size: "auto" + , resizerCursor: "s-resize" + , customHotkey: "" + } +, east: { + paneSelector: ".ui-layout-east" + , size: 200 + , resizerCursor: "e-resize" + , customHotkey: "" + } +, west: { + paneSelector: ".ui-layout-west" + , size: 200 + , resizerCursor: "w-resize" + , customHotkey: "" + } +, center: { + paneSelector: ".ui-layout-center" + , minWidth: 0 + , minHeight: 0 + } }; $.layout.optionsMap = { - // layout/global options - NOT pane-options - layout: ("stateManagement,effects,zIndexes," - + "name,zIndex,scrollToBookmarkOnLoad,showErrorMessages," - + "resizeWithWindow,resizeWithWindowDelay,resizeWithWindowMaxDelay," - + "onresizeall,onresizeall_start,onresizeall_end,onload,onunload,autoBindCustomButtons").split(",") -// borderPanes: [ ALL options that are NOT specified as 'layout' ] - // default.panes options that apply to the center-pane (most options apply _only_ to border-panes) -, center: ("paneClass,contentSelector,contentIgnoreSelector,findNestedContent,applyDemoStyles,triggerEventsOnLoad," - + "showOverflowOnHover,maskContents,maskObjects,liveContentResizing," - + "childOptions,initChildLayout,resizeChildLayout,destroyChildLayout," - + "onresize,onresize_start,onresize_end,onsizecontent,onsizecontent_start,onsizecontent_end").split(",") - // options that MUST be specifically set 'per-pane' - CANNOT set in the panes (defaults) key -, noDefault: ("paneSelector,resizerCursor,customHotkey").split(",") + // layout/global options - NOT pane-options + layout: ("stateManagement,effects,zIndexes," + + "name,zIndex,scrollToBookmarkOnLoad,showErrorMessages," + + "resizeWithWindow,resizeWithWindowDelay,resizeWithWindowMaxDelay," + + "onresizeall,onresizeall_start,onresizeall_end,onload,onunload,autoBindCustomButtons").split(",") +// borderPanes: [ ALL options that are NOT specified as 'layout' ] + // default.panes options that apply to the center-pane (most options apply _only_ to border-panes) +, center: ("paneClass,contentSelector,contentIgnoreSelector,findNestedContent,applyDemoStyles,triggerEventsOnLoad," + + "showOverflowOnHover,maskContents,maskObjects,liveContentResizing," + + "childOptions,initChildLayout,resizeChildLayout,destroyChildLayout," + + "onresize,onresize_start,onresize_end,onsizecontent,onsizecontent_start,onsizecontent_end").split(",") + // options that MUST be specifically set 'per-pane' - CANNOT set in the panes (defaults) key +, noDefault: ("paneSelector,resizerCursor,customHotkey").split(",") }; /** @@ -817,177 +817,177 @@ $.layout.optionsMap = { * In flat-format, subkeys are _currently_ separated with 2 underscores, like north__optName * Plugins may also call this method so they can transform their own data * - * @param {!Object} hash Data/options passed by user - may be a single level or nested levels - * @return {Object} Returns hash of minWidth & minHeight + * @param {!Object} hash Data/options passed by user - may be a single level or nested levels + * @return {Object} Returns hash of minWidth & minHeight */ $.layout.transformData = function (hash) { - var json = { panes: {}, center: {} } // init return object - , data, branch, optKey, keys, key, val, i, c; - - if (typeof hash !== "object") return json; // no options passed - - // convert all 'flat-keys' to 'sub-key' format - for (optKey in hash) { - branch = json; - data = $.layout.optionsMap.layout; - val = hash[ optKey ]; - keys = optKey.split("__"); // eg: west__size or north__fxSettings__duration - c = keys.length - 1; - // convert underscore-delimited to subkeys - for (i=0; i <= c; i++) { - key = keys[i]; - if (i === c) - branch[key] = val; - else if (!branch[key]) - branch[key] = {}; // create the subkey - // recurse to sub-key for next loop - if not done - branch = branch[key]; - } - } - - return json; + var json = { panes: {}, center: {} } // init return object + , data, branch, optKey, keys, key, val, i, c; + + if (typeof hash !== "object") return json; // no options passed + + // convert all 'flat-keys' to 'sub-key' format + for (optKey in hash) { + branch = json; + data = $.layout.optionsMap.layout; + val = hash[ optKey ]; + keys = optKey.split("__"); // eg: west__size or north__fxSettings__duration + c = keys.length - 1; + // convert underscore-delimited to subkeys + for (i=0; i <= c; i++) { + key = keys[i]; + if (i === c) + branch[key] = val; + else if (!branch[key]) + branch[key] = {}; // create the subkey + // recurse to sub-key for next loop - if not done + branch = branch[key]; + } + } + + return json; } // INTERNAL CONFIG DATA - DO NOT CHANGE THIS! $.layout.backwardCompatibility = { - // data used by renameOldOptions() - map: { - // OLD Option Name: NEW Option Name - applyDefaultStyles: "applyDemoStyles" - , resizeNestedLayout: "resizeChildLayout" - , resizeWhileDragging: "livePaneResizing" - , resizeContentWhileDragging: "liveContentResizing" - , triggerEventsWhileDragging: "triggerEventsDuringLiveResize" - , maskIframesOnResize: "maskContents" - , useStateCookie: "stateManagement.enabled" - , "cookie.autoLoad": "stateManagement.autoLoad" - , "cookie.autoSave": "stateManagement.autoSave" - , "cookie.keys": "stateManagement.stateKeys" - , "cookie.name": "stateManagement.cookie.name" - , "cookie.domain": "stateManagement.cookie.domain" - , "cookie.path": "stateManagement.cookie.path" - , "cookie.expires": "stateManagement.cookie.expires" - , "cookie.secure": "stateManagement.cookie.secure" - } - /** - * @param {Object} opts - */ -, renameOptions: function (opts) { - var map = $.layout.backwardCompatibility.map - , oldData, newData, value - ; - for (var itemPath in map) { - oldData = getBranch( itemPath ); - value = oldData.branch[ oldData.key ] - if (value !== undefined) { - newData = getBranch( map[itemPath], true ) - newData.branch[ newData.key ] = value; - delete oldData.branch[ oldData.key ]; - } - } - - /** - * @param {string} path - * @param {boolean=} [create=false] Create path if does not exist - */ - function getBranch (path, create) { - var a = path.split(".") // split keys into array - , c = a.length - 1 - , D = { branch: opts, key: a[c] } // init branch at top & set key (last item) - , i = 0, k, undef; - for (; i 0) { - if (autoHide && $E.data('autoHidden') && $E.innerHeight() > 0) { - $E.show().data('autoHidden', false); - if (!browser.mozilla) // FireFox refreshes iframes - IE does not - // make hidden, then visible to 'refresh' display after animation - $E.css(_c.hidden).css(_c.visible); - } - } - else if (autoHide && !$E.data('autoHidden')) - $E.hide().data('autoHidden', true); - } - - /** - * @param {(string|!Object)} el - * @param {number=} outerHeight - * @param {boolean=} [autoHide=false] - */ -, setOuterHeight = function (el, outerHeight, autoHide) { - var $E = el, h; - if (isStr(el)) $E = $Ps[el]; // west - else if (!el.jquery) $E = $(el); - h = cssH($E, outerHeight); - $E.css({ height: h, visibility: "visible" }); // may have been 'hidden' by sizeContent - if (h > 0 && $E.innerWidth() > 0) { - if (autoHide && $E.data('autoHidden')) { - $E.show().data('autoHidden', false); - if (!browser.mozilla) // FireFox refreshes iframes - IE does not - $E.css(_c.hidden).css(_c.visible); - } - } - else if (autoHide && !$E.data('autoHidden')) - $E.hide().data('autoHidden', true); - } - - /** - * @param {(string|!Object)} el - * @param {number=} outerSize - * @param {boolean=} [autoHide=false] - */ -, setOuterSize = function (el, outerSize, autoHide) { - if (_c[pane].dir=="horz") // pane = north or south - setOuterHeight(el, outerSize, autoHide); - else // pane = east or west - setOuterWidth(el, outerSize, autoHide); - } - - - /** - * Converts any 'size' params to a pixel/integer size, if not already - * If 'auto' or a decimal/percentage is passed as 'size', a pixel-size is calculated - * - /** - * @param {string} pane - * @param {(string|number)=} size - * @param {string=} [dir] - * @return {number} - */ -, _parseSize = function (pane, size, dir) { - if (!dir) dir = _c[pane].dir; - - if (isStr(size) && size.match(/%/)) - size = (size === '100%') ? -1 : parseInt(size, 10) / 100; // convert % to decimal - - if (size === 0) - return 0; - else if (size >= 1) - return parseInt(size, 10); - - var o = options, avail = 0; - if (dir=="horz") // north or south or center.minHeight - avail = sC.innerHeight - ($Ps.north ? o.north.spacing_open : 0) - ($Ps.south ? o.south.spacing_open : 0); - else if (dir=="vert") // east or west or center.minWidth - avail = sC.innerWidth - ($Ps.west ? o.west.spacing_open : 0) - ($Ps.east ? o.east.spacing_open : 0); - - if (size === -1) // -1 == 100% - return avail; - else if (size > 0) // percentage, eg: .25 - return round(avail * size); - else if (pane=="center") - return 0; - else { // size < 0 || size=='auto' || size==Missing || size==Invalid - // auto-size the pane - var dim = (dir === "horz" ? "height" : "width") - , $P = $Ps[pane] - , $C = dim === 'height' ? $Cs[pane] : false - , vis = $.layout.showInvisibly($P) // show pane invisibly if hidden - , szP = $P.css(dim) // SAVE current pane size - , szC = $C ? $C.css(dim) : 0 // SAVE current content size - ; - $P.css(dim, "auto"); - if ($C) $C.css(dim, "auto"); - size = (dim === "height") ? $P.outerHeight() : $P.outerWidth(); // MEASURE - $P.css(dim, szP).css(vis); // RESET size & visibility - if ($C) $C.css(dim, szC); - return size; - } - } - - /** - * Calculates current 'size' (outer-width or outer-height) of a border-pane - optionally with 'pane-spacing' added - * - * @param {(string|!Object)} pane - * @param {boolean=} [inclSpace=false] - * @return {number} Returns EITHER Width for east/west panes OR Height for north/south panes - adjusted for boxModel & browser - */ -, getPaneSize = function (pane, inclSpace) { - var - $P = $Ps[pane] - , o = options[pane] - , s = state[pane] - , oSp = (inclSpace ? o.spacing_open : 0) - , cSp = (inclSpace ? o.spacing_closed : 0) - ; - if (!$P || s.isHidden) - return 0; - else if (s.isClosed || (s.isSliding && inclSpace)) - return cSp; - else if (_c[pane].dir === "horz") - return $P.outerHeight() + oSp; - else // dir === "vert" - return $P.outerWidth() + oSp; - } - - /** - * Calculate min/max pane dimensions and limits for resizing - * - * @param {string} pane - * @param {boolean=} [slide=false] - */ -, setSizeLimits = function (pane, slide) { - if (!isInitialized()) return; - var - o = options[pane] - , s = state[pane] - , c = _c[pane] - , dir = c.dir - , side = c.side.toLowerCase() - , type = c.sizeType.toLowerCase() - , isSliding = (slide != undefined ? slide : s.isSliding) // only open() passes 'slide' param - , $P = $Ps[pane] - , paneSpacing = o.spacing_open - // measure the pane on the *opposite side* from this pane - , altPane = _c.oppositeEdge[pane] - , altS = state[altPane] - , $altP = $Ps[altPane] - , altPaneSize = (!$altP || altS.isVisible===false || altS.isSliding ? 0 : (dir=="horz" ? $altP.outerHeight() : $altP.outerWidth())) - , altPaneSpacing = ((!$altP || altS.isHidden ? 0 : options[altPane][ altS.isClosed !== false ? "spacing_closed" : "spacing_open" ]) || 0) - // limitSize prevents this pane from 'overlapping' opposite pane - , containerSize = (dir=="horz" ? sC.innerHeight : sC.innerWidth) - , minCenterDims = cssMinDims("center") - , minCenterSize = dir=="horz" ? max(options.center.minHeight, minCenterDims.minHeight) : max(options.center.minWidth, minCenterDims.minWidth) - // if pane is 'sliding', then ignore center and alt-pane sizes - because 'overlays' them - , limitSize = (containerSize - paneSpacing - (isSliding ? 0 : (_parseSize("center", minCenterSize, dir) + altPaneSize + altPaneSpacing))) - , minSize = s.minSize = max( _parseSize(pane, o.minSize), cssMinDims(pane).minSize ) - , maxSize = s.maxSize = min( (o.maxSize ? _parseSize(pane, o.maxSize) : 100000), limitSize ) - , r = s.resizerPosition = {} // used to set resizing limits - , top = sC.insetTop - , left = sC.insetLeft - , W = sC.innerWidth - , H = sC.innerHeight - , rW = o.spacing_open // subtract resizer-width to get top/left position for south/east - ; - switch (pane) { - case "north": r.min = top + minSize; - r.max = top + maxSize; - break; - case "west": r.min = left + minSize; - r.max = left + maxSize; - break; - case "south": r.min = top + H - maxSize - rW; - r.max = top + H - minSize - rW; - break; - case "east": r.min = left + W - maxSize - rW; - r.max = left + W - minSize - rW; - break; - }; - } - - /** - * Returns data for setting the size/position of center pane. Also used to set Height for east/west panes - * - * @return JSON Returns a hash of all dimensions: top, bottom, left, right, (outer) width and (outer) height - */ -, calcNewCenterPaneDims = function () { - var d = { - top: getPaneSize("north", true) // true = include 'spacing' value for pane - , bottom: getPaneSize("south", true) - , left: getPaneSize("west", true) - , right: getPaneSize("east", true) - , width: 0 - , height: 0 - }; - - // NOTE: sC = state.container - // calc center-pane outer dimensions - d.width = sC.innerWidth - d.left - d.right; // outerWidth - d.height = sC.innerHeight - d.bottom - d.top; // outerHeight - // add the 'container border/padding' to get final positions relative to the container - d.top += sC.insetTop; - d.bottom += sC.insetBottom; - d.left += sC.insetLeft; - d.right += sC.insetRight; - - return d; - } - - - /** - * @param {!Object} el - * @param {boolean=} [allStates=false] - */ -, getHoverClasses = function (el, allStates) { - var - $El = $(el) - , type = $El.data("layoutRole") - , pane = $El.data("layoutEdge") - , o = options[pane] - , root = o[type +"Class"] - , _pane = "-"+ pane // eg: "-west" - , _open = "-open" - , _closed = "-closed" - , _slide = "-sliding" - , _hover = "-hover " // NOTE the trailing space - , _state = $El.hasClass(root+_closed) ? _closed : _open - , _alt = _state === _closed ? _open : _closed - , classes = (root+_hover) + (root+_pane+_hover) + (root+_state+_hover) + (root+_pane+_state+_hover) - ; - if (allStates) // when 'removing' classes, also remove alternate-state classes - classes += (root+_alt+_hover) + (root+_pane+_alt+_hover); - - if (type=="resizer" && $El.hasClass(root+_slide)) - classes += (root+_slide+_hover) + (root+_pane+_slide+_hover); - - return $.trim(classes); - } -, addHover = function (evt, el) { - var $E = $(el || this); - if (evt && $E.data("layoutRole") === "toggler") - evt.stopPropagation(); // prevent triggering 'slide' on Resizer-bar - $E.addClass( getHoverClasses($E) ); - } -, removeHover = function (evt, el) { - var $E = $(el || this); - $E.removeClass( getHoverClasses($E, true) ); - } - -, onResizerEnter = function (evt) { // ALSO called by toggler.mouseenter - if ($.fn.disableSelection) - $("body").disableSelection(); - } -, onResizerLeave = function (evt, el) { - var - e = el || this // el is only passed when called by the timer - , pane = $(e).data("layoutEdge") - , name = pane +"ResizerLeave" - ; - timer.clear(pane+"_openSlider"); // cancel slideOpen timer, if set - timer.clear(name); // cancel enableSelection timer - may re/set below - // this method calls itself on a timer because it needs to allow - // enough time for dragging to kick-in and set the isResizing flag - // dragging has a 100ms delay set, so this delay must be >100 - if (!el) // 1st call - mouseleave event - timer.set(name, function(){ onResizerLeave(evt, e); }, 200); - // if user is resizing, then dragStop will enableSelection(), so can skip it here - else if (!state[pane].isResizing && $.fn.enableSelection) // 2nd call - by timer - $("body").enableSelection(); - } + /** + * Manages all internal timers + */ +, timer = { + data: {} + , set: function (s, fn, ms) { timer.clear(s); timer.data[s] = setTimeout(fn, ms); } + , clear: function (s) { var t=timer.data; if (t[s]) {clearTimeout(t[s]); delete t[s];} } + } + +, _log = function (msg, popup) { + $.layout.msg( options.name +' / '+ msg, (popup && options.showErrorMessages) ); + } + + /** + * Executes a Callback function after a trigger event, like resize, open or close + * + * @param {string} evtName Name of the layout callback, eg "onresize_start" + * @param {?string} pane This is passed only so we can pass the 'pane object' to the callback + * @param {?boolean} skipBoundEvents Accepts a function name, OR a comma-delimited array: [0]=function name, [1]=argument + */ +, _runCallbacks = function (evtName, pane, skipBoundEvents) { + var o = pane ? options[pane] : options + // names like onopen and onopen_end separate are interchangeable in options... + , lng = evtName + (evtName.match(/_/) ? "" : "_end") + , shrt = lng.match(/_end$/) ? lng.substr(0, lng.length - 4) : "" + , fn = o[lng] + , retVal = "NC" // NC = No Callback + , args = [] + ; + if (!fn && shrt) + fn = o[shrt]; + + // first trigger the callback set in the options + if (fn) { + //try { + // convert function name (string) to function object + if (isStr( fn )) { + if (fn.match(/,/)) { + // function name cannot contain a comma, + // so must be a function name AND a parameter to pass + args = fn.split(",") + , fn = eval(args[0]); + } + else // just the name of an external function? + fn = eval(fn); + } + // execute the callback, if exists + if ($.isFunction( fn )) { + if (args.length) + retVal = fn(args[1]); // pass the argument parsed from 'list' + else if (pane && $Ps[pane]) + // pass data: pane-name, pane-element, pane-state, pane-options, and layout-name + retVal = fn( pane, $Ps[pane], state[pane], options[pane], options.name ); + else // must be a layout/container callback - pass suitable info + retVal = fn( Instance, state, options, options.name ); + } + //} + //catch (ex) {} + } + + // trigger additional events bound directly to the pane + if (!skipBoundEvents && retVal !== false) { + if (pane) { // PANE events can be bound to each pane-elements + $Ps[pane].triggerHandler('layoutpane'+ lng, [ pane, $Ps[pane], state[pane], options[pane], options.name ]); + if (shrt) + $Ps[pane].triggerHandler('layoutpane'+ shrt, [ pane, $Ps[pane], state[pane], options[pane], options.name ]); + } + else // LAYOUT events can be bound to the container-element + $N.triggerHandler('layout'+ lng, [ pane, $Ps[pane], state[pane], options[pane], options.name ]); + } + + // ALWAYS resizeChildLayout after a resize event - even during initialization + if (evtName === "onresize_end" || evtName === "onsizecontent_end") + resizeChildLayout(pane); + + return retVal; + } + + + /** + * cure iframe display issues in IE & other browsers + */ +, _fixIframe = function (pane) { + if (browser.mozilla) return; // skip FireFox - it auto-refreshes iframes onShow + var $P = $Ps[pane]; + // if the 'pane' is an iframe, do it + if (state[pane].tagName === "IFRAME") + $P.css(_c.hidden).css(_c.visible); + else // ditto for any iframes INSIDE the pane + $P.find('IFRAME').css(_c.hidden).css(_c.visible); + } + + /** + * @param {string} pane Can accept ONLY a 'pane' (east, west, etc) + * @param {number=} outerSize (optional) Can pass a width, allowing calculations BEFORE element is resized + * @return {number} Returns the innerHeight/Width of el by subtracting padding and borders + */ +, cssSize = function (pane, outerSize) { + var fn = _c[pane].dir=="horz" ? cssH : cssW; + return fn($Ps[pane], outerSize); + } + + /** + * @param {string} pane Can accept ONLY a 'pane' (east, west, etc) + * @return {Object} Returns hash of minWidth & minHeight + */ +, cssMinDims = function (pane) { + // minWidth/Height means CSS width/height = 1px + var $P = $Ps[pane] + , dir = _c[pane].dir + , d = { + minWidth: 1001 - cssW($P, 1000) + , minHeight: 1001 - cssH($P, 1000) + } + ; + if (dir === "horz") d.minSize = d.minHeight; + if (dir === "vert") d.minSize = d.minWidth; + return d; + } + + // TODO: see if these methods can be made more useful... + // TODO: *maybe* return cssW/H from these so caller can use this info + + /** + * @param {(string|!Object)} el + * @param {number=} outerWidth + * @param {boolean=} [autoHide=false] + */ +, setOuterWidth = function (el, outerWidth, autoHide) { + var $E = el, w; + if (isStr(el)) $E = $Ps[el]; // west + else if (!el.jquery) $E = $(el); + w = cssW($E, outerWidth); + $E.css({ width: w }); + if (w > 0) { + if (autoHide && $E.data('autoHidden') && $E.innerHeight() > 0) { + $E.show().data('autoHidden', false); + if (!browser.mozilla) // FireFox refreshes iframes - IE does not + // make hidden, then visible to 'refresh' display after animation + $E.css(_c.hidden).css(_c.visible); + } + } + else if (autoHide && !$E.data('autoHidden')) + $E.hide().data('autoHidden', true); + } + + /** + * @param {(string|!Object)} el + * @param {number=} outerHeight + * @param {boolean=} [autoHide=false] + */ +, setOuterHeight = function (el, outerHeight, autoHide) { + var $E = el, h; + if (isStr(el)) $E = $Ps[el]; // west + else if (!el.jquery) $E = $(el); + h = cssH($E, outerHeight); + $E.css({ height: h, visibility: "visible" }); // may have been 'hidden' by sizeContent + if (h > 0 && $E.innerWidth() > 0) { + if (autoHide && $E.data('autoHidden')) { + $E.show().data('autoHidden', false); + if (!browser.mozilla) // FireFox refreshes iframes - IE does not + $E.css(_c.hidden).css(_c.visible); + } + } + else if (autoHide && !$E.data('autoHidden')) + $E.hide().data('autoHidden', true); + } + + /** + * @param {(string|!Object)} el + * @param {number=} outerSize + * @param {boolean=} [autoHide=false] + */ +, setOuterSize = function (el, outerSize, autoHide) { + if (_c[pane].dir=="horz") // pane = north or south + setOuterHeight(el, outerSize, autoHide); + else // pane = east or west + setOuterWidth(el, outerSize, autoHide); + } + + + /** + * Converts any 'size' params to a pixel/integer size, if not already + * If 'auto' or a decimal/percentage is passed as 'size', a pixel-size is calculated + * + /** + * @param {string} pane + * @param {(string|number)=} size + * @param {string=} [dir] + * @return {number} + */ +, _parseSize = function (pane, size, dir) { + if (!dir) dir = _c[pane].dir; + + if (isStr(size) && size.match(/%/)) + size = (size === '100%') ? -1 : parseInt(size, 10) / 100; // convert % to decimal + + if (size === 0) + return 0; + else if (size >= 1) + return parseInt(size, 10); + + var o = options, avail = 0; + if (dir=="horz") // north or south or center.minHeight + avail = sC.innerHeight - ($Ps.north ? o.north.spacing_open : 0) - ($Ps.south ? o.south.spacing_open : 0); + else if (dir=="vert") // east or west or center.minWidth + avail = sC.innerWidth - ($Ps.west ? o.west.spacing_open : 0) - ($Ps.east ? o.east.spacing_open : 0); + + if (size === -1) // -1 == 100% + return avail; + else if (size > 0) // percentage, eg: .25 + return round(avail * size); + else if (pane=="center") + return 0; + else { // size < 0 || size=='auto' || size==Missing || size==Invalid + // auto-size the pane + var dim = (dir === "horz" ? "height" : "width") + , $P = $Ps[pane] + , $C = dim === 'height' ? $Cs[pane] : false + , vis = $.layout.showInvisibly($P) // show pane invisibly if hidden + , szP = $P.css(dim) // SAVE current pane size + , szC = $C ? $C.css(dim) : 0 // SAVE current content size + ; + $P.css(dim, "auto"); + if ($C) $C.css(dim, "auto"); + size = (dim === "height") ? $P.outerHeight() : $P.outerWidth(); // MEASURE + $P.css(dim, szP).css(vis); // RESET size & visibility + if ($C) $C.css(dim, szC); + return size; + } + } + + /** + * Calculates current 'size' (outer-width or outer-height) of a border-pane - optionally with 'pane-spacing' added + * + * @param {(string|!Object)} pane + * @param {boolean=} [inclSpace=false] + * @return {number} Returns EITHER Width for east/west panes OR Height for north/south panes - adjusted for boxModel & browser + */ +, getPaneSize = function (pane, inclSpace) { + var + $P = $Ps[pane] + , o = options[pane] + , s = state[pane] + , oSp = (inclSpace ? o.spacing_open : 0) + , cSp = (inclSpace ? o.spacing_closed : 0) + ; + if (!$P || s.isHidden) + return 0; + else if (s.isClosed || (s.isSliding && inclSpace)) + return cSp; + else if (_c[pane].dir === "horz") + return $P.outerHeight() + oSp; + else // dir === "vert" + return $P.outerWidth() + oSp; + } + + /** + * Calculate min/max pane dimensions and limits for resizing + * + * @param {string} pane + * @param {boolean=} [slide=false] + */ +, setSizeLimits = function (pane, slide) { + if (!isInitialized()) return; + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , dir = c.dir + , side = c.side.toLowerCase() + , type = c.sizeType.toLowerCase() + , isSliding = (slide != undefined ? slide : s.isSliding) // only open() passes 'slide' param + , $P = $Ps[pane] + , paneSpacing = o.spacing_open + // measure the pane on the *opposite side* from this pane + , altPane = _c.oppositeEdge[pane] + , altS = state[altPane] + , $altP = $Ps[altPane] + , altPaneSize = (!$altP || altS.isVisible===false || altS.isSliding ? 0 : (dir=="horz" ? $altP.outerHeight() : $altP.outerWidth())) + , altPaneSpacing = ((!$altP || altS.isHidden ? 0 : options[altPane][ altS.isClosed !== false ? "spacing_closed" : "spacing_open" ]) || 0) + // limitSize prevents this pane from 'overlapping' opposite pane + , containerSize = (dir=="horz" ? sC.innerHeight : sC.innerWidth) + , minCenterDims = cssMinDims("center") + , minCenterSize = dir=="horz" ? max(options.center.minHeight, minCenterDims.minHeight) : max(options.center.minWidth, minCenterDims.minWidth) + // if pane is 'sliding', then ignore center and alt-pane sizes - because 'overlays' them + , limitSize = (containerSize - paneSpacing - (isSliding ? 0 : (_parseSize("center", minCenterSize, dir) + altPaneSize + altPaneSpacing))) + , minSize = s.minSize = max( _parseSize(pane, o.minSize), cssMinDims(pane).minSize ) + , maxSize = s.maxSize = min( (o.maxSize ? _parseSize(pane, o.maxSize) : 100000), limitSize ) + , r = s.resizerPosition = {} // used to set resizing limits + , top = sC.insetTop + , left = sC.insetLeft + , W = sC.innerWidth + , H = sC.innerHeight + , rW = o.spacing_open // subtract resizer-width to get top/left position for south/east + ; + switch (pane) { + case "north": r.min = top + minSize; + r.max = top + maxSize; + break; + case "west": r.min = left + minSize; + r.max = left + maxSize; + break; + case "south": r.min = top + H - maxSize - rW; + r.max = top + H - minSize - rW; + break; + case "east": r.min = left + W - maxSize - rW; + r.max = left + W - minSize - rW; + break; + }; + } + + /** + * Returns data for setting the size/position of center pane. Also used to set Height for east/west panes + * + * @return JSON Returns a hash of all dimensions: top, bottom, left, right, (outer) width and (outer) height + */ +, calcNewCenterPaneDims = function () { + var d = { + top: getPaneSize("north", true) // true = include 'spacing' value for pane + , bottom: getPaneSize("south", true) + , left: getPaneSize("west", true) + , right: getPaneSize("east", true) + , width: 0 + , height: 0 + }; + + // NOTE: sC = state.container + // calc center-pane outer dimensions + d.width = sC.innerWidth - d.left - d.right; // outerWidth + d.height = sC.innerHeight - d.bottom - d.top; // outerHeight + // add the 'container border/padding' to get final positions relative to the container + d.top += sC.insetTop; + d.bottom += sC.insetBottom; + d.left += sC.insetLeft; + d.right += sC.insetRight; + + return d; + } + + + /** + * @param {!Object} el + * @param {boolean=} [allStates=false] + */ +, getHoverClasses = function (el, allStates) { + var + $El = $(el) + , type = $El.data("layoutRole") + , pane = $El.data("layoutEdge") + , o = options[pane] + , root = o[type +"Class"] + , _pane = "-"+ pane // eg: "-west" + , _open = "-open" + , _closed = "-closed" + , _slide = "-sliding" + , _hover = "-hover " // NOTE the trailing space + , _state = $El.hasClass(root+_closed) ? _closed : _open + , _alt = _state === _closed ? _open : _closed + , classes = (root+_hover) + (root+_pane+_hover) + (root+_state+_hover) + (root+_pane+_state+_hover) + ; + if (allStates) // when 'removing' classes, also remove alternate-state classes + classes += (root+_alt+_hover) + (root+_pane+_alt+_hover); + + if (type=="resizer" && $El.hasClass(root+_slide)) + classes += (root+_slide+_hover) + (root+_pane+_slide+_hover); + + return $.trim(classes); + } +, addHover = function (evt, el) { + var $E = $(el || this); + if (evt && $E.data("layoutRole") === "toggler") + evt.stopPropagation(); // prevent triggering 'slide' on Resizer-bar + $E.addClass( getHoverClasses($E) ); + } +, removeHover = function (evt, el) { + var $E = $(el || this); + $E.removeClass( getHoverClasses($E, true) ); + } + +, onResizerEnter = function (evt) { // ALSO called by toggler.mouseenter + if ($.fn.disableSelection) + $("body").disableSelection(); + } +, onResizerLeave = function (evt, el) { + var + e = el || this // el is only passed when called by the timer + , pane = $(e).data("layoutEdge") + , name = pane +"ResizerLeave" + ; + timer.clear(pane+"_openSlider"); // cancel slideOpen timer, if set + timer.clear(name); // cancel enableSelection timer - may re/set below + // this method calls itself on a timer because it needs to allow + // enough time for dragging to kick-in and set the isResizing flag + // dragging has a 100ms delay set, so this delay must be >100 + if (!el) // 1st call - mouseleave event + timer.set(name, function(){ onResizerLeave(evt, e); }, 200); + // if user is resizing, then dragStop will enableSelection(), so can skip it here + else if (!state[pane].isResizing && $.fn.enableSelection) // 2nd call - by timer + $("body").enableSelection(); + } /* * ########################### @@ -1403,3219 +1403,3219 @@ $.fn.layout = function (opts) { * ########################### */ - /** - * Initialize the layout - called automatically whenever an instance of layout is created - * - * @see none - triggered onInit - * @return mixed true = fully initialized | false = panes not initialized (yet) | 'cancel' = abort - */ -, _create = function () { - // initialize config/options - initOptions(); - var o = options; - - // TEMP state so isInitialized returns true during init process - state.creatingLayout = true; - - // init plugins for this layout, if there are any (eg: stateManagement) - runPluginCallbacks( Instance, $.layout.onCreate ); - - // options & state have been initialized, so now run beforeLoad callback - // onload will CANCEL layout creation if it returns false - if (false === _runCallbacks("onload_start")) - return 'cancel'; - - // initialize the container element - _initContainer(); - - // bind hotkey function - keyDown - if required - initHotkeys(); - - // bind window.onunload - $(window).bind("unload."+ sID, unload); - - // init plugins for this layout, if there are any (eg: customButtons) - runPluginCallbacks( Instance, $.layout.onLoad ); - - // if layout elements are hidden, then layout WILL NOT complete initialization! - // initLayoutElements will set initialized=true and run the onload callback IF successful - if (o.initPanes) _initLayoutElements(); - - delete state.creatingLayout; - - return state.initialized; - } - - /** - * Initialize the layout IF not already - * - * @see All methods in Instance run this test - * @return boolean true = layoutElements have been initialized | false = panes are not initialized (yet) - */ -, isInitialized = function () { - if (state.initialized || state.creatingLayout) return true; // already initialized - else return _initLayoutElements(); // try to init panes NOW - } - - /** - * Initialize the layout - called automatically whenever an instance of layout is created - * - * @see _create() & isInitialized - * @return An object pointer to the instance created - */ -, _initLayoutElements = function (retry) { - // initialize config/options - var o = options; - - // CANNOT init panes inside a hidden container! - if (!$N.is(":visible")) { - // handle Chrome bug where popup window 'has no height' - // if layout is BODY element, try again in 50ms - // SEE: http://layout.jquery-dev.net/samples/test_popup_window.html - if ( !retry && browser.webkit && $N[0].tagName === "BODY" ) - setTimeout(function(){ _initLayoutElements(true); }, 50); - return false; - } - - // a center pane is required, so make sure it exists - if (!getPane("center").length) { - if (options.showErrorMessages) - _log( lang.errCenterPaneMissing, true ); - return false; - } - - // TEMP state so isInitialized returns true during init process - state.creatingLayout = true; - - // update Container dims - $.extend(sC, elDims( $N )); - - // initialize all layout elements - initPanes(); // size & position panes - calls initHandles() - which calls initResizable() - - if (o.scrollToBookmarkOnLoad) { - var l = self.location; - if (l.hash) l.replace( l.hash ); // scrollTo Bookmark - } - - // check to see if this layout 'nested' inside a pane - if (Instance.hasParentLayout) - o.resizeWithWindow = false; - // bind resizeAll() for 'this layout instance' to window.resize event - else if (o.resizeWithWindow) - $(window).bind("resize."+ sID, windowResize); - - delete state.creatingLayout; - state.initialized = true; - - // init plugins for this layout, if there are any - runPluginCallbacks( Instance, $.layout.onReady ); - - // now run the onload callback, if exists - _runCallbacks("onload_end"); - - return true; // elements initialized successfully - } - - /** - * Initialize nested layouts - called when _initLayoutElements completes - * - * NOT CURRENTLY USED - * - * @see _initLayoutElements - * @return An object pointer to the instance created - */ -, _initChildLayouts = function () { - $.each(_c.allPanes, function (idx, pane) { - if (options[pane].initChildLayout) - createChildLayout( pane ); - }); - } - - /** - * Initialize nested layouts for a specific pane - can optionally pass layout-options - * - * @see _initChildLayouts - * @param {string} pane The pane being opened, ie: north, south, east, or west - * @param {Object=} [opts] Layout-options - if passed, will OVERRRIDE options[pane].childOptions - * @return An object pointer to the layout instance created - or null - */ -, createChildLayout = function (evt_or_pane, opts) { - var pane = evtPane.call(this, evt_or_pane) - , $P = $Ps[pane] - , C = children - ; - if ($P) { - var $C = $Cs[pane] - , o = opts || options[pane].childOptions - , d = "layout" - // determine which element is supposed to be the 'child container' - // if pane has a 'containerSelector' OR a 'content-div', use those instead of the pane - , $Cont = o.containerSelector ? $P.find( o.containerSelector ) : ($C || $P) - , containerFound = $Cont.length - // see if a child-layout ALREADY exists on this element - , child = containerFound ? (C[pane] = $Cont.data(d) || null) : null - ; - // if no layout exists, but childOptions are set, try to create the layout now - if (!child && containerFound && o) - child = C[pane] = $Cont.eq(0).layout(o) || null; - if (child) - child.hasParentLayout = true; // set parent-flag in child - } - Instance[pane].child = C[pane]; // ALWAYS set pane-object pointer, even if null - } - -, windowResize = function () { - var delay = Number(options.resizeWithWindowDelay); - if (delay < 10) delay = 100; // MUST have a delay! - // resizing uses a delay-loop because the resize event fires repeatly - except in FF, but delay anyway - timer.clear("winResize"); // if already running - timer.set("winResize", function(){ - timer.clear("winResize"); - timer.clear("winResizeRepeater"); - var dims = elDims( $N ); - // only trigger resizeAll() if container has changed size - if (dims.innerWidth !== sC.innerWidth || dims.innerHeight !== sC.innerHeight) - resizeAll(); - }, delay); - // ALSO set fixed-delay timer, if not already running - if (!timer.data["winResizeRepeater"]) setWindowResizeRepeater(); - } - -, setWindowResizeRepeater = function () { - var delay = Number(options.resizeWithWindowMaxDelay); - if (delay > 0) - timer.set("winResizeRepeater", function(){ setWindowResizeRepeater(); resizeAll(); }, delay); - } - -, unload = function () { - var o = options; - - _runCallbacks("onunload_start"); - - // trigger plugin callabacks for this layout (eg: stateManagement) - runPluginCallbacks( Instance, $.layout.onUnload ); - - _runCallbacks("onunload_end"); - } - - /** - * Validate and initialize container CSS and events - * - * @see _create() - */ -, _initContainer = function () { - var - N = $N[0] - , tag = sC.tagName = N.tagName - , id = sC.id = N.id - , cls = sC.className = N.className - , o = options - , name = o.name - , fullPage= (tag === "BODY") - , props = "overflow,position,margin,padding,border" - , css = "layoutCSS" - , CSS = {} - , hid = "hidden" // used A LOT! - // see if this container is a 'pane' inside an outer-layout - , parent = $N.data("parentLayout") // parent-layout Instance - , pane = $N.data("layoutEdge") // pane-name in parent-layout - , isChild = parent && pane - ; - // sC -> state.container - sC.selector = $N.selector.split(".slice")[0]; - sC.ref = (o.name ? o.name +' layout / ' : '') + tag + (id ? "#"+id : cls ? '.['+cls+']' : ''); // used in messages - - $N .data({ - layout: Instance - , layoutContainer: sID // FLAG to indicate this is a layout-container - contains unique internal ID - }) - .addClass(o.containerClass) - ; - var layoutMethods = { - destroy: '' - , initPanes: '' - , resizeAll: 'resizeAll' - , resize: 'resizeAll' - } - , name; - // loop hash and bind all methods - include layoutID namespacing - for (name in layoutMethods) { - $N.bind("layout"+ name.toLowerCase() +"."+ sID, Instance[ layoutMethods[name] || name ]); - } - - // if this container is another layout's 'pane', then set child/parent pointers - if (isChild) { - // update parent flag - Instance.hasParentLayout = true; - // set pointers to THIS child-layout (Instance) in parent-layout - // NOTE: parent.PANE.child is an ALIAS to parent.children.PANE - parent[pane].child = parent.children[pane] = $N.data("layout"); - } - - // SAVE original container CSS for use in destroy() - if (!$N.data(css)) { - // handle props like overflow different for BODY & HTML - has 'system default' values - if (fullPage) { - CSS = $.extend( elCSS($N, props), { - height: $N.css("height") - , overflow: $N.css("overflow") - , overflowX: $N.css("overflowX") - , overflowY: $N.css("overflowY") - }); - // ALSO SAVE CSS - var $H = $("html"); - $H.data(css, { - height: "auto" // FF would return a fixed px-size! - , overflow: $H.css("overflow") - , overflowX: $H.css("overflowX") - , overflowY: $H.css("overflowY") - }); - } - else // handle props normally for non-body elements - CSS = elCSS($N, props+",top,bottom,left,right,width,height,overflow,overflowX,overflowY"); - - $N.data(css, CSS); - } - - try { // format html/body if this is a full page layout - if (fullPage) { - $("html").css({ - height: "100%" - , overflow: hid - , overflowX: hid - , overflowY: hid - }); - $("body").css({ - position: "relative" - , height: "100%" - , overflow: hid - , overflowX: hid - , overflowY: hid - , margin: 0 - , padding: 0 // TODO: test whether body-padding could be handled? - , border: "none" // a body-border creates problems because it cannot be measured! - }); - - // set current layout-container dimensions - $.extend(sC, elDims( $N )); - } - else { // set required CSS for overflow and position - // ENSURE container will not 'scroll' - CSS = { overflow: hid, overflowX: hid, overflowY: hid } - var - p = $N.css("position") - , h = $N.css("height") - ; - // if this is a NESTED layout, then container/outer-pane ALREADY has position and height - if (!isChild) { - if (!p || !p.match(/fixed|absolute|relative/)) - CSS.position = "relative"; // container MUST have a 'position' - /* - if (!h || h=="auto") - CSS.height = "100%"; // container MUST have a 'height' - */ - } - $N.css( CSS ); - - // set current layout-container dimensions - if ( $N.is(":visible") ) { - $.extend(sC, elDims( $N )); - if (o.showErrorMessages && sC.innerHeight < 1) - _log( lang.errContainerHeight.replace(/CONTAINER/, sC.ref), true ); - } - } - } catch (ex) {} - } - - /** - * Bind layout hotkeys - if options enabled - * - * @see _create() and addPane() - * @param {string=} [panes=""] The edge(s) to process - */ -, initHotkeys = function (panes) { - panes = panes ? panes.split(",") : _c.borderPanes; - // bind keyDown to capture hotkeys, if option enabled for ANY pane - $.each(panes, function (i, pane) { - var o = options[pane]; - if (o.enableCursorHotkey || o.customHotkey) { - $(document).bind("keydown."+ sID, keyDown); // only need to bind this ONCE - return false; // BREAK - binding was done - } - }); - } - - /** - * Build final OPTIONS data - * - * @see _create() - */ -, initOptions = function () { - var data, d, pane, key, val, i, c, o; - - // reprocess user's layout-options to have correct options sub-key structure - opts = $.layout.transformData( opts ); // panes = default subkey - - // auto-rename old options for backward compatibility - opts = $.layout.backwardCompatibility.renameAllOptions( opts ); - - // if user-options has 'panes' key (pane-defaults), process it... - if (!$.isEmptyObject(opts.panes)) { - // REMOVE any pane-defaults that MUST be set per-pane - data = $.layout.optionsMap.noDefault; - for (i=0, c=data.length; i 0) { - z.pane_normal = zo; - z.content_mask = max(zo+1, z.content_mask); // MIN = +1 - z.resizer_normal = max(zo+2, z.resizer_normal); // MIN = +2 - } - - function createFxOptions ( pane ) { - var o = options[pane] - , d = options.panes; - // ensure fxSettings key to avoid errors - if (!o.fxSettings) o.fxSettings = {}; - if (!d.fxSettings) d.fxSettings = {}; - - $.each(["_open","_close","_size"], function (i,n) { - var - sName = "fxName"+ n - , sSpeed = "fxSpeed"+ n - , sSettings = "fxSettings"+ n - // recalculate fxName according to specificity rules - , fxName = o[sName] = - o[sName] // options.west.fxName_open - || d[sName] // options.panes.fxName_open - || o.fxName // options.west.fxName - || d.fxName // options.panes.fxName - || "none" // MEANS $.layout.defaults.panes.fxName == "" || false || null || 0 - ; - // validate fxName to ensure is valid effect - MUST have effect-config data in options.effects - if (fxName === "none" || !$.effects || !$.effects[fxName] || !options.effects[fxName]) - fxName = o[sName] = "none"; // effect not loaded OR unrecognized fxName - - // set vars for effects subkeys to simplify logic - var fx = options.effects[fxName] || {} // effects.slide - , fx_all = fx.all || null // effects.slide.all - , fx_pane = fx[pane] || null // effects.slide.west - ; - // create fxSpeed[_open|_close|_size] - o[sSpeed] = - o[sSpeed] // options.west.fxSpeed_open - || d[sSpeed] // options.west.fxSpeed_open - || o.fxSpeed // options.west.fxSpeed - || d.fxSpeed // options.panes.fxSpeed - || null // DEFAULT - let fxSetting.duration control speed - ; - // create fxSettings[_open|_close|_size] - o[sSettings] = $.extend( - {} - , fx_all // effects.slide.all - , fx_pane // effects.slide.west - , d.fxSettings // options.panes.fxSettings - , o.fxSettings // options.west.fxSettings - , d[sSettings] // options.panes.fxSettings_open - , o[sSettings] // options.west.fxSettings_open - ); - }); - - // DONE creating action-specific-settings for this pane, - // so DELETE generic options - are no longer meaningful - delete o.fxName; - delete o.fxSpeed; - delete o.fxSettings; - } - - // DELETE 'panes' key now that we are done - values were copied to EACH pane - delete options.panes; - } - - /** - * Initialize module objects, styling, size and position for all panes - * - * @see _initElements() - * @param {string} pane The pane to process - */ -, getPane = function (pane) { - var sel = options[pane].paneSelector - if (sel.substr(0,1)==="#") // ID selector - // NOTE: elements selected 'by ID' DO NOT have to be 'children' - return $N.find(sel).eq(0); - else { // class or other selector - var $P = $N.children(sel).eq(0); - // look for the pane nested inside a 'form' element - return $P.length ? $P : $N.children("form:first").children(sel).eq(0); - } - } - -, initPanes = function () { - // NOTE: do north & south FIRST so we can measure their height - do center LAST - $.each(_c.allPanes, function (idx, pane) { - addPane( pane, true ); - }); - - // init the pane-handles NOW in case we have to hide or close the pane below - initHandles(); - - // now that all panes have been initialized and initially-sized, - // make sure there is really enough space available for each pane - $.each(_c.borderPanes, function (i, pane) { - if ($Ps[pane] && state[pane].isVisible) { // pane is OPEN - setSizeLimits(pane); - makePaneFit(pane); // pane may be Closed, Hidden or Resized by makePaneFit() - } - }); - // size center-pane AGAIN in case we 'closed' a border-pane in loop above - sizeMidPanes("center"); - - // Chrome/Webkit sometimes fires callbacks BEFORE it completes resizing! - // Before RC30.3, there was a 10ms delay here, but that caused layout - // to load asynchrously, which is BAD, so try skipping delay for now - - // process pane contents and callbacks, and init/resize child-layout if exists - $.each(_c.allPanes, function (i, pane) { - var o = options[pane]; - if ($Ps[pane]) { - if (state[pane].isVisible) { // pane is OPEN - sizeContent(pane); - // trigger pane.onResize if triggerEventsOnLoad = true - if (o.triggerEventsOnLoad) - _runCallbacks("onresize_end", pane); - else // automatic if onresize called, otherwise call it specifically - // resize child - IF inner-layout already exists (created before this layout) - resizeChildLayout(pane); - } - // init childLayout - even if pane is not visible - if (o.initChildLayout && o.childOptions) - createChildLayout(pane); - } - }); - } - - /** - * Add a pane to the layout - subroutine of initPanes() - * - * @see initPanes() - * @param {string} pane The pane to process - * @param {boolean=} [force=false] Size content after init - */ -, addPane = function (pane, force) { - if (!force && !isInitialized()) return; - var - o = options[pane] - , s = state[pane] - , c = _c[pane] - , fx = s.fx - , dir = c.dir - , spacing = o.spacing_open || 0 - , isCenter = (pane === "center") - , CSS = {} - , $P = $Ps[pane] - , size, minSize, maxSize - ; - // if pane-pointer already exists, remove the old one first - if ($P) - removePane( pane, false, true, false ); - else - $Cs[pane] = false; // init - - $P = $Ps[pane] = getPane(pane); - if (!$P.length) { - $Ps[pane] = false; // logic - return; - } - - // SAVE original Pane CSS - if (!$P.data("layoutCSS")) { - var props = "position,top,left,bottom,right,width,height,overflow,zIndex,display,backgroundColor,padding,margin,border"; - $P.data("layoutCSS", elCSS($P, props)); - } - - // create alias for pane data in Instance - initHandles will add more - Instance[pane] = { name: pane, pane: $Ps[pane], content: $Cs[pane], options: options[pane], state: state[pane], child: children[pane] }; - - // add classes, attributes & events - $P .data({ - parentLayout: Instance // pointer to Layout Instance - , layoutPane: Instance[pane] // NEW pointer to pane-alias-object - , layoutEdge: pane - , layoutRole: "pane" - }) - .css(c.cssReq).css("zIndex", options.zIndexes.pane_normal) - .css(o.applyDemoStyles ? c.cssDemo : {}) // demo styles - .addClass( o.paneClass +" "+ o.paneClass+"-"+pane ) // default = "ui-layout-pane ui-layout-pane-west" - may be a dupe of 'paneSelector' - .bind("mouseenter."+ sID, addHover ) - .bind("mouseleave."+ sID, removeHover ) - ; - var paneMethods = { - hide: '' - , show: '' - , toggle: '' - , close: '' - , open: '' - , slideOpen: '' - , slideClose: '' - , slideToggle: '' - , size: 'manualSizePane' - , sizePane: 'manualSizePane' - , sizeContent: '' - , sizeHandles: '' - , enableClosable: '' - , disableClosable: '' - , enableSlideable: '' - , disableSlideable: '' - , enableResizable: '' - , disableResizable: '' - , swapPanes: 'swapPanes' - , swap: 'swapPanes' - , move: 'swapPanes' - , removePane: 'removePane' - , remove: 'removePane' - , createChildLayout: '' - , resizeChildLayout: '' - , resizeAll: 'resizeAll' - , resizeLayout: 'resizeAll' - } - , name; - // loop hash and bind all methods - include layoutID namespacing - for (name in paneMethods) { - $P.bind("layoutpane"+ name.toLowerCase() +"."+ sID, Instance[ paneMethods[name] || name ]); - } - - // see if this pane has a 'scrolling-content element' - initContent(pane, false); // false = do NOT sizeContent() - called later - - if (!isCenter) { - // call _parseSize AFTER applying pane classes & styles - but before making visible (if hidden) - // if o.size is auto or not valid, then MEASURE the pane and use that as its 'size' - size = s.size = _parseSize(pane, o.size); - minSize = _parseSize(pane,o.minSize) || 1; - maxSize = _parseSize(pane,o.maxSize) || 100000; - if (size > 0) size = max(min(size, maxSize), minSize); - - // state for border-panes - s.isClosed = false; // true = pane is closed - s.isSliding = false; // true = pane is currently open by 'sliding' over adjacent panes - s.isResizing= false; // true = pane is in process of being resized - s.isHidden = false; // true = pane is hidden - no spacing, resizer or toggler is visible! - - // array for 'pin buttons' whose classNames are auto-updated on pane-open/-close - if (!s.pins) s.pins = []; - } - // states common to ALL panes - s.tagName = $P[0].tagName; - s.edge = pane; // useful if pane is (or about to be) 'swapped' - easy find out where it is (or is going) - s.noRoom = false; // true = pane 'automatically' hidden due to insufficient room - will unhide automatically - s.isVisible = true; // false = pane is invisible - closed OR hidden - simplify logic - - // set css-position to account for container borders & padding - switch (pane) { - case "north": CSS.top = sC.insetTop; - CSS.left = sC.insetLeft; - CSS.right = sC.insetRight; - break; - case "south": CSS.bottom = sC.insetBottom; - CSS.left = sC.insetLeft; - CSS.right = sC.insetRight; - break; - case "west": CSS.left = sC.insetLeft; // top, bottom & height set by sizeMidPanes() - break; - case "east": CSS.right = sC.insetRight; // ditto - break; - case "center": // top, left, width & height set by sizeMidPanes() - } - - if (dir === "horz") // north or south pane - CSS.height = cssH($P, size); - else if (dir === "vert") // east or west pane - CSS.width = cssW($P, size); - //else if (isCenter) {} - - $P.css(CSS); // apply size -- top, bottom & height will be set by sizeMidPanes - if (dir != "horz") sizeMidPanes(pane, true); // true = skipCallback - - // close or hide the pane if specified in settings - if (o.initClosed && o.closable && !o.initHidden) - close(pane, true, true); // true, true = force, noAnimation - else if (o.initHidden || o.initClosed) - hide(pane); // will be completely invisible - no resizer or spacing - else if (!s.noRoom) - // make the pane visible - in case was initially hidden - $P.css("display","block"); - // ELSE setAsOpen() - called later by initHandles() - - // RESET visibility now - pane will appear IF display:block - $P.css("visibility","visible"); - - // check option for auto-handling of pop-ups & drop-downs - if (o.showOverflowOnHover) - $P.hover( allowOverflow, resetOverflow ); - - // if manually adding a pane AFTER layout initialization, then... - if (state.initialized) { - initHandles( pane ); - initHotkeys( pane ); - resizeAll(); // will sizeContent if pane is visible - if (s.isVisible) { // pane is OPEN - if (o.triggerEventsOnLoad) - _runCallbacks("onresize_end", pane); - else // automatic if onresize called, otherwise call it specifically - // resize child - IF inner-layout already exists (created before this layout) - resizeChildLayout(pane); // a previously existing childLayout - } - if (o.initChildLayout && o.childOptions) - createChildLayout(pane); - } - } - - /** - * Initialize module objects, styling, size and position for all resize bars and toggler buttons - * - * @see _create() - * @param {string=} [panes=""] The edge(s) to process - */ -, initHandles = function (panes) { - panes = panes ? panes.split(",") : _c.borderPanes; - - // create toggler DIVs for each pane, and set object pointers for them, eg: $R.north = north toggler DIV - $.each(panes, function (i, pane) { - var $P = $Ps[pane]; - $Rs[pane] = false; // INIT - $Ts[pane] = false; - if (!$P) return; // pane does not exist - skip - - var - o = options[pane] - , s = state[pane] - , c = _c[pane] - , rClass = o.resizerClass - , tClass = o.togglerClass - , side = c.side.toLowerCase() - , spacing = (s.isVisible ? o.spacing_open : o.spacing_closed) - , _pane = "-"+ pane // used for classNames - , _state = (s.isVisible ? "-open" : "-closed") // used for classNames - , I = Instance[pane] - // INIT RESIZER BAR - , $R = I.resizer = $Rs[pane] = $("
        ") - // INIT TOGGLER BUTTON - , $T = I.toggler = (o.closable ? $Ts[pane] = $("
        ") : false) - ; - - //if (s.isVisible && o.resizable) ... handled by initResizable - if (!s.isVisible && o.slidable) - $R.attr("title", o.sliderTip).css("cursor", o.sliderCursor); - - $R // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "paneLeft-resizer" - .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-resizer" : "")) - .data({ - parentLayout: Instance - , layoutPane: Instance[pane] // NEW pointer to pane-alias-object - , layoutEdge: pane - , layoutRole: "resizer" - }) - .css(_c.resizers.cssReq).css("zIndex", options.zIndexes.resizer_normal) - .css(o.applyDemoStyles ? _c.resizers.cssDemo : {}) // add demo styles - .addClass(rClass +" "+ rClass+_pane) - .hover(addHover, removeHover) // ALWAYS add hover-classes, even if resizing is not enabled - handle with CSS instead - .hover(onResizerEnter, onResizerLeave) // ALWAYS NEED resizer.mouseleave to balance toggler.mouseenter - .appendTo($N) // append DIV to container - ; - - if ($T) { - $T // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "#paneLeft-toggler" - .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-toggler" : "")) - .data({ - parentLayout: Instance - , layoutPane: Instance[pane] // NEW pointer to pane-alias-object - , layoutEdge: pane - , layoutRole: "toggler" - }) - .css(_c.togglers.cssReq) // add base/required styles - .css(o.applyDemoStyles ? _c.togglers.cssDemo : {}) // add demo styles - .addClass(tClass +" "+ tClass+_pane) - .hover(addHover, removeHover) // ALWAYS add hover-classes, even if toggling is not enabled - handle with CSS instead - .bind("mouseenter", onResizerEnter) // NEED toggler.mouseenter because mouseenter MAY NOT fire on resizer - .appendTo($R) // append SPAN to resizer DIV - ; - // ADD INNER-SPANS TO TOGGLER - if (o.togglerContent_open) // ui-layout-open - $(""+ o.togglerContent_open +"") - .data({ - layoutEdge: pane - , layoutRole: "togglerContent" - }) - .data("layoutRole", "togglerContent") - .data("layoutEdge", pane) - .addClass("content content-open") - .css("display","none") - .appendTo( $T ) - //.hover( addHover, removeHover ) // use ui-layout-toggler-west-hover .content-open instead! - ; - if (o.togglerContent_closed) // ui-layout-closed - $(""+ o.togglerContent_closed +"") - .data({ - layoutEdge: pane - , layoutRole: "togglerContent" - }) - .addClass("content content-closed") - .css("display","none") - .appendTo( $T ) - //.hover( addHover, removeHover ) // use ui-layout-toggler-west-hover .content-closed instead! - ; - // ADD TOGGLER.click/.hover - enableClosable(pane); - } - - // add Draggable events - initResizable(pane); - - // ADD CLASSNAMES & SLIDE-BINDINGS - eg: class="resizer resizer-west resizer-open" - if (s.isVisible) - setAsOpen(pane); // onOpen will be called, but NOT onResize - else { - setAsClosed(pane); // onClose will be called - bindStartSlidingEvent(pane, true); // will enable events IF option is set - } - - }); - - // SET ALL HANDLE DIMENSIONS - sizeHandles(); - } - - - /** - * Initialize scrolling ui-layout-content div - if exists - * - * @see initPane() - or externally after an Ajax injection - * @param {string} [pane] The pane to process - * @param {boolean=} [resize=true] Size content after init - */ -, initContent = function (pane, resize) { - if (!isInitialized()) return; - var - o = options[pane] - , sel = o.contentSelector - , I = Instance[pane] - , $P = $Ps[pane] - , $C - ; - if (sel) $C = I.content = $Cs[pane] = (o.findNestedContent) - ? $P.find(sel).eq(0) // match 1-element only - : $P.children(sel).eq(0) - ; - if ($C && $C.length) { - $C.data("layoutRole", "content"); - // SAVE original Pane CSS - if (!$C.data("layoutCSS")) - $C.data("layoutCSS", elCSS($C, "height")); - $C.css( _c.content.cssReq ); - if (o.applyDemoStyles) { - $C.css( _c.content.cssDemo ); // add padding & overflow: auto to content-div - $P.css( _c.content.cssDemoPane ); // REMOVE padding/scrolling from pane - } - state[pane].content = {}; // init content state - if (resize !== false) sizeContent(pane); - // sizeContent() is called AFTER init of all elements - } - else - I.content = $Cs[pane] = false; - } - - - /** - * Add resize-bars to all panes that specify it in options - * -dependancy: $.fn.resizable - will skip if not found - * - * @see _create() - * @param {string=} [panes=""] The edge(s) to process - */ -, initResizable = function (panes) { - var draggingAvailable = $.layout.plugins.draggable - , side // set in start() - ; - panes = panes ? panes.split(",") : _c.borderPanes; - - $.each(panes, function (idx, pane) { - var o = options[pane]; - if (!draggingAvailable || !$Ps[pane] || !o.resizable) { - o.resizable = false; - return true; // skip to next - } - - var s = state[pane] - , z = options.zIndexes - , c = _c[pane] - , side = c.dir=="horz" ? "top" : "left" - , opEdge = _c.oppositeEdge[pane] - , masks = pane +",center,"+ opEdge + (c.dir=="horz" ? ",west,east" : "") - , $P = $Ps[pane] - , $R = $Rs[pane] - , base = o.resizerClass - , lastPos = 0 // used when live-resizing - , r, live // set in start because may change - // 'drag' classes are applied to the ORIGINAL resizer-bar while dragging is in process - , resizerClass = base+"-drag" // resizer-drag - , resizerPaneClass = base+"-"+pane+"-drag" // resizer-north-drag - // 'helper' class is applied to the CLONED resizer-bar while it is being dragged - , helperClass = base+"-dragging" // resizer-dragging - , helperPaneClass = base+"-"+pane+"-dragging" // resizer-north-dragging - , helperLimitClass = base+"-dragging-limit" // resizer-drag - , helperPaneLimitClass = base+"-"+pane+"-dragging-limit" // resizer-north-drag - , helperClassesSet = false // logic var - ; - - if (!s.isClosed) - $R.attr("title", o.resizerTip) - .css("cursor", o.resizerCursor); // n-resize, s-resize, etc - - $R.draggable({ - containment: $N[0] // limit resizing to layout container - , axis: (c.dir=="horz" ? "y" : "x") // limit resizing to horz or vert axis - , delay: 0 - , distance: 1 - , grid: o.resizingGrid - // basic format for helper - style it using class: .ui-draggable-dragging - , helper: "clone" - , opacity: o.resizerDragOpacity - , addClasses: false // avoid ui-state-disabled class when disabled - //, iframeFix: o.draggableIframeFix // TODO: consider using when bug is fixed - , zIndex: z.resizer_drag - - , start: function (e, ui) { - // REFRESH options & state pointers in case we used swapPanes - o = options[pane]; - s = state[pane]; - // re-read options - live = o.livePaneResizing; - - // ondrag_start callback - will CANCEL hide if returns false - // TODO: dragging CANNOT be cancelled like this, so see if there is a way? - if (false === _runCallbacks("ondrag_start", pane)) return false; - - s.isResizing = true; // prevent pane from closing while resizing - timer.clear(pane+"_closeSlider"); // just in case already triggered - - // SET RESIZER LIMITS - used in drag() - setSizeLimits(pane); // update pane/resizer state - r = s.resizerPosition; - lastPos = ui.position[ side ] - - $R.addClass( resizerClass +" "+ resizerPaneClass ); // add drag classes - helperClassesSet = false; // reset logic var - see drag() - - // DISABLE TEXT SELECTION (probably already done by resizer.mouseOver) - $('body').disableSelection(); - - // MASK PANES CONTAINING IFRAMES, APPLETS OR OTHER TROUBLESOME ELEMENTS - showMasks( masks ); - } - - , drag: function (e, ui) { - if (!helperClassesSet) { // can only add classes after clone has been added to the DOM - //$(".ui-draggable-dragging") - ui.helper - .addClass( helperClass +" "+ helperPaneClass ) // add helper classes - .css({ right: "auto", bottom: "auto" }) // fix dir="rtl" issue - .children().css("visibility","hidden") // hide toggler inside dragged resizer-bar - ; - helperClassesSet = true; - // draggable bug!? RE-SET zIndex to prevent E/W resize-bar showing through N/S pane! - if (s.isSliding) $Ps[pane].css("zIndex", z.pane_sliding); - } - // CONTAIN RESIZER-BAR TO RESIZING LIMITS - var limit = 0; - if (ui.position[side] < r.min) { - ui.position[side] = r.min; - limit = -1; - } - else if (ui.position[side] > r.max) { - ui.position[side] = r.max; - limit = 1; - } - // ADD/REMOVE dragging-limit CLASS - if (limit) { - ui.helper.addClass( helperLimitClass +" "+ helperPaneLimitClass ); // at dragging-limit - window.defaultStatus = (limit>0 && pane.match(/north|west/)) || (limit<0 && pane.match(/south|east/)) ? lang.maxSizeWarning : lang.minSizeWarning; - } - else { - ui.helper.removeClass( helperLimitClass +" "+ helperPaneLimitClass ); // not at dragging-limit - window.defaultStatus = ""; - } - // DYNAMICALLY RESIZE PANES IF OPTION ENABLED - // won't trigger unless resizer has actually moved! - if (live && Math.abs(ui.position[side] - lastPos) >= o.liveResizingTolerance) { - lastPos = ui.position[side]; - resizePanes(e, ui, pane) - } - } - - , stop: function (e, ui) { - $('body').enableSelection(); // RE-ENABLE TEXT SELECTION - window.defaultStatus = ""; // clear 'resizing limit' message from statusbar - $R.removeClass( resizerClass +" "+ resizerPaneClass ); // remove drag classes from Resizer - s.isResizing = false; - resizePanes(e, ui, pane, true, masks); // true = resizingDone - } - - }); - }); - - /** - * resizePanes - * - * Sub-routine called from stop() - and drag() if livePaneResizing - * - * @param {!Object} evt - * @param {!Object} ui - * @param {string} pane - * @param {boolean=} [resizingDone=false] - */ - var resizePanes = function (evt, ui, pane, resizingDone, masks) { - var dragPos = ui.position - , c = _c[pane] - , o = options[pane] - , s = state[pane] - , resizerPos - ; - switch (pane) { - case "north": resizerPos = dragPos.top; break; - case "west": resizerPos = dragPos.left; break; - case "south": resizerPos = sC.offsetHeight - dragPos.top - o.spacing_open; break; - case "east": resizerPos = sC.offsetWidth - dragPos.left - o.spacing_open; break; - }; - // remove container margin from resizer position to get the pane size - var newSize = resizerPos - sC["inset"+ c.side]; - - // Disable OR Resize Mask(s) created in drag.start - if (!resizingDone) { - // ensure we meet liveResizingTolerance criteria - if (Math.abs(newSize - s.size) < o.liveResizingTolerance) - return; // SKIP resize this time - // resize the pane - manualSizePane(pane, newSize, false, true); // true = noAnimation - sizeMasks(); // resize all visible masks - } - else { // resizingDone - // ondrag_end callback - if (false !== _runCallbacks("ondrag_end", pane)) - manualSizePane(pane, newSize, false, true); // true = noAnimation - hideMasks(); // hide all masks, which include panes with 'content/iframe-masks' - if (s.isSliding && masks) // RE-SHOW only 'object-masks' so objects won't show through sliding pane - showMasks( masks, true ); // true = onlyForObjects - } - }; - } - - /** - * sizeMask - * - * Needed to overlay a DIV over an IFRAME-pane because mask CANNOT be *inside* the pane - * Called when mask created, and during livePaneResizing - */ -, sizeMask = function () { - var $M = $(this) - , pane = $M.data("layoutMask") // eg: "west" - , s = state[pane] - ; - // only masks over an IFRAME-pane need manual resizing - if (s.tagName == "IFRAME" && s.isVisible) // no need to mask closed/hidden panes - $M.css({ - top: s.offsetTop - , left: s.offsetLeft - , width: s.outerWidth - , height: s.outerHeight - }); - /* ALT Method... - var $P = $Ps[pane]; - $M.css( $P.position() ).css({ width: $P[0].offsetWidth, height: $P[0].offsetHeight }); - */ - } -, sizeMasks = function () { - $Ms.each( sizeMask ); // resize all 'visible' masks - } - -, showMasks = function (panes, onlyForObjects) { - var a = panes ? panes.split(",") : $.layout.config.allPanes - , z = options.zIndexes - , o, s; - $.each(a, function(i,p){ - s = state[p]; - o = options[p]; - if (s.isVisible && ( (!onlyForObjects && o.maskContents) || o.maskObjects )) { - getMasks(p).each(function(){ - sizeMask.call(this); - this.style.zIndex = s.isSliding ? z.pane_sliding+1 : z.pane_normal+1 - this.style.display = "block"; - }); - } - }); - } - -, hideMasks = function () { - // ensure no pane is resizing - could be a timing issue - var skip; - $.each( $.layout.config.borderPanes, function(i,p){ - if (state[p].isResizing) { - skip = true; - return false; // BREAK - } - }); - if (!skip) - $Ms.hide(); // hide ALL masks - } - -, getMasks = function (pane) { - var $Masks = $([]) - , $M, i = 0, c = $Ms.length - ; - for (; i CSS - if (sC.tagName === "BODY" && ($N = $("html")).data(css)) // RESET CSS - $N.css( $N.data(css) ).removeData(css); - - // trigger plugins for this layout, if there are any - runPluginCallbacks( Instance, $.layout.onDestroy ); - - // trigger state-management and onunload callback - unload(); - - // clear the Instance of everything except for container & options (so could recreate) - // RE-CREATE: myLayout = myLayout.container.layout( myLayout.options ); - for (n in Instance) - if (!n.match(/^(container|options)$/)) delete Instance[ n ]; - // add a 'destroyed' flag to make it easy to check - Instance.destroyed = true; - - // if this is a child layout, CLEAR the child-pointer in the parent - /* for now the pointer REMAINS, but with only container, options and destroyed keys - if (parentPane) { - var layout = parentPane.pane.data("parentLayout"); - parentPane.child = layout.children[ parentPane.name ] = null; - } - */ - - return Instance; // for coding convenience - } - - /** - * Remove a pane from the layout - subroutine of destroy() - * - * @see destroy() - * @param {string} pane The pane to process - * @param {boolean=} [remove=false] Remove the DOM element? - * @param {boolean=} [skipResize=false] Skip calling resizeAll()? - */ -, removePane = function (evt_or_pane, remove, skipResize, destroyChild) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , $P = $Ps[pane] - , $C = $Cs[pane] - , $R = $Rs[pane] - , $T = $Ts[pane] - ; - //alert( '$P.length = '+ $P.length ); - // NOTE: elements can still exist even after remove() - // so check for missing data(), which is cleared by removed() - if ($P && $.isEmptyObject( $P.data() )) $P = false; - if ($C && $.isEmptyObject( $C.data() )) $C = false; - if ($R && $.isEmptyObject( $R.data() )) $R = false; - if ($T && $.isEmptyObject( $T.data() )) $T = false; - - if ($P) $P.stop(true, true); - - // check for a child layout - var o = options[pane] - , s = state[pane] - , d = "layout" - , css = "layoutCSS" - , child = children[pane] || ($P ? $P.data(d) : 0) || ($C ? $C.data(d) : 0) || null - , destroy = destroyChild !== undefined ? destroyChild : o.destroyChildLayout - ; - - // FIRST destroy the child-layout(s) - if (destroy && child && !child.destroyed) { - child.destroy(true); // tell child-layout to destroy ALL its child-layouts too - if (child.destroyed) // destroy was successful - child = null; // clear pointer for logic below - } - - if ($P && remove && !child) - $P.remove(); - else if ($P && $P[0]) { - // create list of ALL pane-classes that need to be removed - var root = o.paneClass // default="ui-layout-pane" - , pRoot = root +"-"+ pane // eg: "ui-layout-pane-west" - , _open = "-open" - , _sliding= "-sliding" - , _closed = "-closed" - , classes = [ root, root+_open, root+_closed, root+_sliding, // generic classes - pRoot, pRoot+_open, pRoot+_closed, pRoot+_sliding ] // pane-specific classes - ; - $.merge(classes, getHoverClasses($P, true)); // ADD hover-classes - // remove all Layout classes from pane-element - $P .removeClass( classes.join(" ") ) // remove ALL pane-classes - .removeData("parentLayout") - .removeData("layoutPane") - .removeData("layoutRole") - .removeData("layoutEdge") - .removeData("autoHidden") // in case set - .unbind("."+ sID) // remove ALL Layout events - // TODO: remove these extra unbind commands when jQuery is fixed - //.unbind("mouseenter"+ sID) - //.unbind("mouseleave"+ sID) - ; - // do NOT reset CSS if this pane/content is STILL the container of a nested layout! - // the nested layout will reset its 'container' CSS when/if it is destroyed - if ($C && $C.data(d)) { - // a content-div may not have a specific width, so give it one to contain the Layout - $C.width( $C.width() ); - child.resizeAll(); // now resize the Layout - } - else if ($C) - $C.css( $C.data(css) ).removeData(css).removeData("layoutRole"); - // remove pane AFTER content in case there was a nested layout - if (!$P.data(d)) - $P.css( $P.data(css) ).removeData(css); - } - - // REMOVE pane resizer and toggler elements - if ($T) $T.remove(); - if ($R) $R.remove(); - - // CLEAR all pointers and state data - Instance[pane] = $Ps[pane] = $Cs[pane] = $Rs[pane] = $Ts[pane] = children[pane] = false; - s = { removed: true }; - - if (!skipResize) - resizeAll(); - } + /** + * Initialize the layout - called automatically whenever an instance of layout is created + * + * @see none - triggered onInit + * @return mixed true = fully initialized | false = panes not initialized (yet) | 'cancel' = abort + */ +, _create = function () { + // initialize config/options + initOptions(); + var o = options; + + // TEMP state so isInitialized returns true during init process + state.creatingLayout = true; + + // init plugins for this layout, if there are any (eg: stateManagement) + runPluginCallbacks( Instance, $.layout.onCreate ); + + // options & state have been initialized, so now run beforeLoad callback + // onload will CANCEL layout creation if it returns false + if (false === _runCallbacks("onload_start")) + return 'cancel'; + + // initialize the container element + _initContainer(); + + // bind hotkey function - keyDown - if required + initHotkeys(); + + // bind window.onunload + $(window).bind("unload."+ sID, unload); + + // init plugins for this layout, if there are any (eg: customButtons) + runPluginCallbacks( Instance, $.layout.onLoad ); + + // if layout elements are hidden, then layout WILL NOT complete initialization! + // initLayoutElements will set initialized=true and run the onload callback IF successful + if (o.initPanes) _initLayoutElements(); + + delete state.creatingLayout; + + return state.initialized; + } + + /** + * Initialize the layout IF not already + * + * @see All methods in Instance run this test + * @return boolean true = layoutElements have been initialized | false = panes are not initialized (yet) + */ +, isInitialized = function () { + if (state.initialized || state.creatingLayout) return true; // already initialized + else return _initLayoutElements(); // try to init panes NOW + } + + /** + * Initialize the layout - called automatically whenever an instance of layout is created + * + * @see _create() & isInitialized + * @return An object pointer to the instance created + */ +, _initLayoutElements = function (retry) { + // initialize config/options + var o = options; + + // CANNOT init panes inside a hidden container! + if (!$N.is(":visible")) { + // handle Chrome bug where popup window 'has no height' + // if layout is BODY element, try again in 50ms + // SEE: http://layout.jquery-dev.net/samples/test_popup_window.html + if ( !retry && browser.webkit && $N[0].tagName === "BODY" ) + setTimeout(function(){ _initLayoutElements(true); }, 50); + return false; + } + + // a center pane is required, so make sure it exists + if (!getPane("center").length) { + if (options.showErrorMessages) + _log( lang.errCenterPaneMissing, true ); + return false; + } + + // TEMP state so isInitialized returns true during init process + state.creatingLayout = true; + + // update Container dims + $.extend(sC, elDims( $N )); + + // initialize all layout elements + initPanes(); // size & position panes - calls initHandles() - which calls initResizable() + + if (o.scrollToBookmarkOnLoad) { + var l = self.location; + if (l.hash) l.replace( l.hash ); // scrollTo Bookmark + } + + // check to see if this layout 'nested' inside a pane + if (Instance.hasParentLayout) + o.resizeWithWindow = false; + // bind resizeAll() for 'this layout instance' to window.resize event + else if (o.resizeWithWindow) + $(window).bind("resize."+ sID, windowResize); + + delete state.creatingLayout; + state.initialized = true; + + // init plugins for this layout, if there are any + runPluginCallbacks( Instance, $.layout.onReady ); + + // now run the onload callback, if exists + _runCallbacks("onload_end"); + + return true; // elements initialized successfully + } + + /** + * Initialize nested layouts - called when _initLayoutElements completes + * + * NOT CURRENTLY USED + * + * @see _initLayoutElements + * @return An object pointer to the instance created + */ +, _initChildLayouts = function () { + $.each(_c.allPanes, function (idx, pane) { + if (options[pane].initChildLayout) + createChildLayout( pane ); + }); + } + + /** + * Initialize nested layouts for a specific pane - can optionally pass layout-options + * + * @see _initChildLayouts + * @param {string} pane The pane being opened, ie: north, south, east, or west + * @param {Object=} [opts] Layout-options - if passed, will OVERRRIDE options[pane].childOptions + * @return An object pointer to the layout instance created - or null + */ +, createChildLayout = function (evt_or_pane, opts) { + var pane = evtPane.call(this, evt_or_pane) + , $P = $Ps[pane] + , C = children + ; + if ($P) { + var $C = $Cs[pane] + , o = opts || options[pane].childOptions + , d = "layout" + // determine which element is supposed to be the 'child container' + // if pane has a 'containerSelector' OR a 'content-div', use those instead of the pane + , $Cont = o.containerSelector ? $P.find( o.containerSelector ) : ($C || $P) + , containerFound = $Cont.length + // see if a child-layout ALREADY exists on this element + , child = containerFound ? (C[pane] = $Cont.data(d) || null) : null + ; + // if no layout exists, but childOptions are set, try to create the layout now + if (!child && containerFound && o) + child = C[pane] = $Cont.eq(0).layout(o) || null; + if (child) + child.hasParentLayout = true; // set parent-flag in child + } + Instance[pane].child = C[pane]; // ALWAYS set pane-object pointer, even if null + } + +, windowResize = function () { + var delay = Number(options.resizeWithWindowDelay); + if (delay < 10) delay = 100; // MUST have a delay! + // resizing uses a delay-loop because the resize event fires repeatly - except in FF, but delay anyway + timer.clear("winResize"); // if already running + timer.set("winResize", function(){ + timer.clear("winResize"); + timer.clear("winResizeRepeater"); + var dims = elDims( $N ); + // only trigger resizeAll() if container has changed size + if (dims.innerWidth !== sC.innerWidth || dims.innerHeight !== sC.innerHeight) + resizeAll(); + }, delay); + // ALSO set fixed-delay timer, if not already running + if (!timer.data["winResizeRepeater"]) setWindowResizeRepeater(); + } + +, setWindowResizeRepeater = function () { + var delay = Number(options.resizeWithWindowMaxDelay); + if (delay > 0) + timer.set("winResizeRepeater", function(){ setWindowResizeRepeater(); resizeAll(); }, delay); + } + +, unload = function () { + var o = options; + + _runCallbacks("onunload_start"); + + // trigger plugin callabacks for this layout (eg: stateManagement) + runPluginCallbacks( Instance, $.layout.onUnload ); + + _runCallbacks("onunload_end"); + } + + /** + * Validate and initialize container CSS and events + * + * @see _create() + */ +, _initContainer = function () { + var + N = $N[0] + , tag = sC.tagName = N.tagName + , id = sC.id = N.id + , cls = sC.className = N.className + , o = options + , name = o.name + , fullPage= (tag === "BODY") + , props = "overflow,position,margin,padding,border" + , css = "layoutCSS" + , CSS = {} + , hid = "hidden" // used A LOT! + // see if this container is a 'pane' inside an outer-layout + , parent = $N.data("parentLayout") // parent-layout Instance + , pane = $N.data("layoutEdge") // pane-name in parent-layout + , isChild = parent && pane + ; + // sC -> state.container + sC.selector = $N.selector.split(".slice")[0]; + sC.ref = (o.name ? o.name +' layout / ' : '') + tag + (id ? "#"+id : cls ? '.['+cls+']' : ''); // used in messages + + $N .data({ + layout: Instance + , layoutContainer: sID // FLAG to indicate this is a layout-container - contains unique internal ID + }) + .addClass(o.containerClass) + ; + var layoutMethods = { + destroy: '' + , initPanes: '' + , resizeAll: 'resizeAll' + , resize: 'resizeAll' + } + , name; + // loop hash and bind all methods - include layoutID namespacing + for (name in layoutMethods) { + $N.bind("layout"+ name.toLowerCase() +"."+ sID, Instance[ layoutMethods[name] || name ]); + } + + // if this container is another layout's 'pane', then set child/parent pointers + if (isChild) { + // update parent flag + Instance.hasParentLayout = true; + // set pointers to THIS child-layout (Instance) in parent-layout + // NOTE: parent.PANE.child is an ALIAS to parent.children.PANE + parent[pane].child = parent.children[pane] = $N.data("layout"); + } + + // SAVE original container CSS for use in destroy() + if (!$N.data(css)) { + // handle props like overflow different for BODY & HTML - has 'system default' values + if (fullPage) { + CSS = $.extend( elCSS($N, props), { + height: $N.css("height") + , overflow: $N.css("overflow") + , overflowX: $N.css("overflowX") + , overflowY: $N.css("overflowY") + }); + // ALSO SAVE CSS + var $H = $("html"); + $H.data(css, { + height: "auto" // FF would return a fixed px-size! + , overflow: $H.css("overflow") + , overflowX: $H.css("overflowX") + , overflowY: $H.css("overflowY") + }); + } + else // handle props normally for non-body elements + CSS = elCSS($N, props+",top,bottom,left,right,width,height,overflow,overflowX,overflowY"); + + $N.data(css, CSS); + } + + try { // format html/body if this is a full page layout + if (fullPage) { + $("html").css({ + height: "100%" + , overflow: hid + , overflowX: hid + , overflowY: hid + }); + $("body").css({ + position: "relative" + , height: "100%" + , overflow: hid + , overflowX: hid + , overflowY: hid + , margin: 0 + , padding: 0 // TODO: test whether body-padding could be handled? + , border: "none" // a body-border creates problems because it cannot be measured! + }); + + // set current layout-container dimensions + $.extend(sC, elDims( $N )); + } + else { // set required CSS for overflow and position + // ENSURE container will not 'scroll' + CSS = { overflow: hid, overflowX: hid, overflowY: hid } + var + p = $N.css("position") + , h = $N.css("height") + ; + // if this is a NESTED layout, then container/outer-pane ALREADY has position and height + if (!isChild) { + if (!p || !p.match(/fixed|absolute|relative/)) + CSS.position = "relative"; // container MUST have a 'position' + /* + if (!h || h=="auto") + CSS.height = "100%"; // container MUST have a 'height' + */ + } + $N.css( CSS ); + + // set current layout-container dimensions + if ( $N.is(":visible") ) { + $.extend(sC, elDims( $N )); + if (o.showErrorMessages && sC.innerHeight < 1) + _log( lang.errContainerHeight.replace(/CONTAINER/, sC.ref), true ); + } + } + } catch (ex) {} + } + + /** + * Bind layout hotkeys - if options enabled + * + * @see _create() and addPane() + * @param {string=} [panes=""] The edge(s) to process + */ +, initHotkeys = function (panes) { + panes = panes ? panes.split(",") : _c.borderPanes; + // bind keyDown to capture hotkeys, if option enabled for ANY pane + $.each(panes, function (i, pane) { + var o = options[pane]; + if (o.enableCursorHotkey || o.customHotkey) { + $(document).bind("keydown."+ sID, keyDown); // only need to bind this ONCE + return false; // BREAK - binding was done + } + }); + } + + /** + * Build final OPTIONS data + * + * @see _create() + */ +, initOptions = function () { + var data, d, pane, key, val, i, c, o; + + // reprocess user's layout-options to have correct options sub-key structure + opts = $.layout.transformData( opts ); // panes = default subkey + + // auto-rename old options for backward compatibility + opts = $.layout.backwardCompatibility.renameAllOptions( opts ); + + // if user-options has 'panes' key (pane-defaults), process it... + if (!$.isEmptyObject(opts.panes)) { + // REMOVE any pane-defaults that MUST be set per-pane + data = $.layout.optionsMap.noDefault; + for (i=0, c=data.length; i 0) { + z.pane_normal = zo; + z.content_mask = max(zo+1, z.content_mask); // MIN = +1 + z.resizer_normal = max(zo+2, z.resizer_normal); // MIN = +2 + } + + function createFxOptions ( pane ) { + var o = options[pane] + , d = options.panes; + // ensure fxSettings key to avoid errors + if (!o.fxSettings) o.fxSettings = {}; + if (!d.fxSettings) d.fxSettings = {}; + + $.each(["_open","_close","_size"], function (i,n) { + var + sName = "fxName"+ n + , sSpeed = "fxSpeed"+ n + , sSettings = "fxSettings"+ n + // recalculate fxName according to specificity rules + , fxName = o[sName] = + o[sName] // options.west.fxName_open + || d[sName] // options.panes.fxName_open + || o.fxName // options.west.fxName + || d.fxName // options.panes.fxName + || "none" // MEANS $.layout.defaults.panes.fxName == "" || false || null || 0 + ; + // validate fxName to ensure is valid effect - MUST have effect-config data in options.effects + if (fxName === "none" || !$.effects || !$.effects[fxName] || !options.effects[fxName]) + fxName = o[sName] = "none"; // effect not loaded OR unrecognized fxName + + // set vars for effects subkeys to simplify logic + var fx = options.effects[fxName] || {} // effects.slide + , fx_all = fx.all || null // effects.slide.all + , fx_pane = fx[pane] || null // effects.slide.west + ; + // create fxSpeed[_open|_close|_size] + o[sSpeed] = + o[sSpeed] // options.west.fxSpeed_open + || d[sSpeed] // options.west.fxSpeed_open + || o.fxSpeed // options.west.fxSpeed + || d.fxSpeed // options.panes.fxSpeed + || null // DEFAULT - let fxSetting.duration control speed + ; + // create fxSettings[_open|_close|_size] + o[sSettings] = $.extend( + {} + , fx_all // effects.slide.all + , fx_pane // effects.slide.west + , d.fxSettings // options.panes.fxSettings + , o.fxSettings // options.west.fxSettings + , d[sSettings] // options.panes.fxSettings_open + , o[sSettings] // options.west.fxSettings_open + ); + }); + + // DONE creating action-specific-settings for this pane, + // so DELETE generic options - are no longer meaningful + delete o.fxName; + delete o.fxSpeed; + delete o.fxSettings; + } + + // DELETE 'panes' key now that we are done - values were copied to EACH pane + delete options.panes; + } + + /** + * Initialize module objects, styling, size and position for all panes + * + * @see _initElements() + * @param {string} pane The pane to process + */ +, getPane = function (pane) { + var sel = options[pane].paneSelector + if (sel.substr(0,1)==="#") // ID selector + // NOTE: elements selected 'by ID' DO NOT have to be 'children' + return $N.find(sel).eq(0); + else { // class or other selector + var $P = $N.children(sel).eq(0); + // look for the pane nested inside a 'form' element + return $P.length ? $P : $N.children("form:first").children(sel).eq(0); + } + } + +, initPanes = function () { + // NOTE: do north & south FIRST so we can measure their height - do center LAST + $.each(_c.allPanes, function (idx, pane) { + addPane( pane, true ); + }); + + // init the pane-handles NOW in case we have to hide or close the pane below + initHandles(); + + // now that all panes have been initialized and initially-sized, + // make sure there is really enough space available for each pane + $.each(_c.borderPanes, function (i, pane) { + if ($Ps[pane] && state[pane].isVisible) { // pane is OPEN + setSizeLimits(pane); + makePaneFit(pane); // pane may be Closed, Hidden or Resized by makePaneFit() + } + }); + // size center-pane AGAIN in case we 'closed' a border-pane in loop above + sizeMidPanes("center"); + + // Chrome/Webkit sometimes fires callbacks BEFORE it completes resizing! + // Before RC30.3, there was a 10ms delay here, but that caused layout + // to load asynchrously, which is BAD, so try skipping delay for now + + // process pane contents and callbacks, and init/resize child-layout if exists + $.each(_c.allPanes, function (i, pane) { + var o = options[pane]; + if ($Ps[pane]) { + if (state[pane].isVisible) { // pane is OPEN + sizeContent(pane); + // trigger pane.onResize if triggerEventsOnLoad = true + if (o.triggerEventsOnLoad) + _runCallbacks("onresize_end", pane); + else // automatic if onresize called, otherwise call it specifically + // resize child - IF inner-layout already exists (created before this layout) + resizeChildLayout(pane); + } + // init childLayout - even if pane is not visible + if (o.initChildLayout && o.childOptions) + createChildLayout(pane); + } + }); + } + + /** + * Add a pane to the layout - subroutine of initPanes() + * + * @see initPanes() + * @param {string} pane The pane to process + * @param {boolean=} [force=false] Size content after init + */ +, addPane = function (pane, force) { + if (!force && !isInitialized()) return; + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , fx = s.fx + , dir = c.dir + , spacing = o.spacing_open || 0 + , isCenter = (pane === "center") + , CSS = {} + , $P = $Ps[pane] + , size, minSize, maxSize + ; + // if pane-pointer already exists, remove the old one first + if ($P) + removePane( pane, false, true, false ); + else + $Cs[pane] = false; // init + + $P = $Ps[pane] = getPane(pane); + if (!$P.length) { + $Ps[pane] = false; // logic + return; + } + + // SAVE original Pane CSS + if (!$P.data("layoutCSS")) { + var props = "position,top,left,bottom,right,width,height,overflow,zIndex,display,backgroundColor,padding,margin,border"; + $P.data("layoutCSS", elCSS($P, props)); + } + + // create alias for pane data in Instance - initHandles will add more + Instance[pane] = { name: pane, pane: $Ps[pane], content: $Cs[pane], options: options[pane], state: state[pane], child: children[pane] }; + + // add classes, attributes & events + $P .data({ + parentLayout: Instance // pointer to Layout Instance + , layoutPane: Instance[pane] // NEW pointer to pane-alias-object + , layoutEdge: pane + , layoutRole: "pane" + }) + .css(c.cssReq).css("zIndex", options.zIndexes.pane_normal) + .css(o.applyDemoStyles ? c.cssDemo : {}) // demo styles + .addClass( o.paneClass +" "+ o.paneClass+"-"+pane ) // default = "ui-layout-pane ui-layout-pane-west" - may be a dupe of 'paneSelector' + .bind("mouseenter."+ sID, addHover ) + .bind("mouseleave."+ sID, removeHover ) + ; + var paneMethods = { + hide: '' + , show: '' + , toggle: '' + , close: '' + , open: '' + , slideOpen: '' + , slideClose: '' + , slideToggle: '' + , size: 'manualSizePane' + , sizePane: 'manualSizePane' + , sizeContent: '' + , sizeHandles: '' + , enableClosable: '' + , disableClosable: '' + , enableSlideable: '' + , disableSlideable: '' + , enableResizable: '' + , disableResizable: '' + , swapPanes: 'swapPanes' + , swap: 'swapPanes' + , move: 'swapPanes' + , removePane: 'removePane' + , remove: 'removePane' + , createChildLayout: '' + , resizeChildLayout: '' + , resizeAll: 'resizeAll' + , resizeLayout: 'resizeAll' + } + , name; + // loop hash and bind all methods - include layoutID namespacing + for (name in paneMethods) { + $P.bind("layoutpane"+ name.toLowerCase() +"."+ sID, Instance[ paneMethods[name] || name ]); + } + + // see if this pane has a 'scrolling-content element' + initContent(pane, false); // false = do NOT sizeContent() - called later + + if (!isCenter) { + // call _parseSize AFTER applying pane classes & styles - but before making visible (if hidden) + // if o.size is auto or not valid, then MEASURE the pane and use that as its 'size' + size = s.size = _parseSize(pane, o.size); + minSize = _parseSize(pane,o.minSize) || 1; + maxSize = _parseSize(pane,o.maxSize) || 100000; + if (size > 0) size = max(min(size, maxSize), minSize); + + // state for border-panes + s.isClosed = false; // true = pane is closed + s.isSliding = false; // true = pane is currently open by 'sliding' over adjacent panes + s.isResizing= false; // true = pane is in process of being resized + s.isHidden = false; // true = pane is hidden - no spacing, resizer or toggler is visible! + + // array for 'pin buttons' whose classNames are auto-updated on pane-open/-close + if (!s.pins) s.pins = []; + } + // states common to ALL panes + s.tagName = $P[0].tagName; + s.edge = pane; // useful if pane is (or about to be) 'swapped' - easy find out where it is (or is going) + s.noRoom = false; // true = pane 'automatically' hidden due to insufficient room - will unhide automatically + s.isVisible = true; // false = pane is invisible - closed OR hidden - simplify logic + + // set css-position to account for container borders & padding + switch (pane) { + case "north": CSS.top = sC.insetTop; + CSS.left = sC.insetLeft; + CSS.right = sC.insetRight; + break; + case "south": CSS.bottom = sC.insetBottom; + CSS.left = sC.insetLeft; + CSS.right = sC.insetRight; + break; + case "west": CSS.left = sC.insetLeft; // top, bottom & height set by sizeMidPanes() + break; + case "east": CSS.right = sC.insetRight; // ditto + break; + case "center": // top, left, width & height set by sizeMidPanes() + } + + if (dir === "horz") // north or south pane + CSS.height = cssH($P, size); + else if (dir === "vert") // east or west pane + CSS.width = cssW($P, size); + //else if (isCenter) {} + + $P.css(CSS); // apply size -- top, bottom & height will be set by sizeMidPanes + if (dir != "horz") sizeMidPanes(pane, true); // true = skipCallback + + // close or hide the pane if specified in settings + if (o.initClosed && o.closable && !o.initHidden) + close(pane, true, true); // true, true = force, noAnimation + else if (o.initHidden || o.initClosed) + hide(pane); // will be completely invisible - no resizer or spacing + else if (!s.noRoom) + // make the pane visible - in case was initially hidden + $P.css("display","block"); + // ELSE setAsOpen() - called later by initHandles() + + // RESET visibility now - pane will appear IF display:block + $P.css("visibility","visible"); + + // check option for auto-handling of pop-ups & drop-downs + if (o.showOverflowOnHover) + $P.hover( allowOverflow, resetOverflow ); + + // if manually adding a pane AFTER layout initialization, then... + if (state.initialized) { + initHandles( pane ); + initHotkeys( pane ); + resizeAll(); // will sizeContent if pane is visible + if (s.isVisible) { // pane is OPEN + if (o.triggerEventsOnLoad) + _runCallbacks("onresize_end", pane); + else // automatic if onresize called, otherwise call it specifically + // resize child - IF inner-layout already exists (created before this layout) + resizeChildLayout(pane); // a previously existing childLayout + } + if (o.initChildLayout && o.childOptions) + createChildLayout(pane); + } + } + + /** + * Initialize module objects, styling, size and position for all resize bars and toggler buttons + * + * @see _create() + * @param {string=} [panes=""] The edge(s) to process + */ +, initHandles = function (panes) { + panes = panes ? panes.split(",") : _c.borderPanes; + + // create toggler DIVs for each pane, and set object pointers for them, eg: $R.north = north toggler DIV + $.each(panes, function (i, pane) { + var $P = $Ps[pane]; + $Rs[pane] = false; // INIT + $Ts[pane] = false; + if (!$P) return; // pane does not exist - skip + + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , rClass = o.resizerClass + , tClass = o.togglerClass + , side = c.side.toLowerCase() + , spacing = (s.isVisible ? o.spacing_open : o.spacing_closed) + , _pane = "-"+ pane // used for classNames + , _state = (s.isVisible ? "-open" : "-closed") // used for classNames + , I = Instance[pane] + // INIT RESIZER BAR + , $R = I.resizer = $Rs[pane] = $("
        ") + // INIT TOGGLER BUTTON + , $T = I.toggler = (o.closable ? $Ts[pane] = $("
        ") : false) + ; + + //if (s.isVisible && o.resizable) ... handled by initResizable + if (!s.isVisible && o.slidable) + $R.attr("title", o.sliderTip).css("cursor", o.sliderCursor); + + $R // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "paneLeft-resizer" + .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-resizer" : "")) + .data({ + parentLayout: Instance + , layoutPane: Instance[pane] // NEW pointer to pane-alias-object + , layoutEdge: pane + , layoutRole: "resizer" + }) + .css(_c.resizers.cssReq).css("zIndex", options.zIndexes.resizer_normal) + .css(o.applyDemoStyles ? _c.resizers.cssDemo : {}) // add demo styles + .addClass(rClass +" "+ rClass+_pane) + .hover(addHover, removeHover) // ALWAYS add hover-classes, even if resizing is not enabled - handle with CSS instead + .hover(onResizerEnter, onResizerLeave) // ALWAYS NEED resizer.mouseleave to balance toggler.mouseenter + .appendTo($N) // append DIV to container + ; + + if ($T) { + $T // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "#paneLeft-toggler" + .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-toggler" : "")) + .data({ + parentLayout: Instance + , layoutPane: Instance[pane] // NEW pointer to pane-alias-object + , layoutEdge: pane + , layoutRole: "toggler" + }) + .css(_c.togglers.cssReq) // add base/required styles + .css(o.applyDemoStyles ? _c.togglers.cssDemo : {}) // add demo styles + .addClass(tClass +" "+ tClass+_pane) + .hover(addHover, removeHover) // ALWAYS add hover-classes, even if toggling is not enabled - handle with CSS instead + .bind("mouseenter", onResizerEnter) // NEED toggler.mouseenter because mouseenter MAY NOT fire on resizer + .appendTo($R) // append SPAN to resizer DIV + ; + // ADD INNER-SPANS TO TOGGLER + if (o.togglerContent_open) // ui-layout-open + $(""+ o.togglerContent_open +"") + .data({ + layoutEdge: pane + , layoutRole: "togglerContent" + }) + .data("layoutRole", "togglerContent") + .data("layoutEdge", pane) + .addClass("content content-open") + .css("display","none") + .appendTo( $T ) + //.hover( addHover, removeHover ) // use ui-layout-toggler-west-hover .content-open instead! + ; + if (o.togglerContent_closed) // ui-layout-closed + $(""+ o.togglerContent_closed +"") + .data({ + layoutEdge: pane + , layoutRole: "togglerContent" + }) + .addClass("content content-closed") + .css("display","none") + .appendTo( $T ) + //.hover( addHover, removeHover ) // use ui-layout-toggler-west-hover .content-closed instead! + ; + // ADD TOGGLER.click/.hover + enableClosable(pane); + } + + // add Draggable events + initResizable(pane); + + // ADD CLASSNAMES & SLIDE-BINDINGS - eg: class="resizer resizer-west resizer-open" + if (s.isVisible) + setAsOpen(pane); // onOpen will be called, but NOT onResize + else { + setAsClosed(pane); // onClose will be called + bindStartSlidingEvent(pane, true); // will enable events IF option is set + } + + }); + + // SET ALL HANDLE DIMENSIONS + sizeHandles(); + } + + + /** + * Initialize scrolling ui-layout-content div - if exists + * + * @see initPane() - or externally after an Ajax injection + * @param {string} [pane] The pane to process + * @param {boolean=} [resize=true] Size content after init + */ +, initContent = function (pane, resize) { + if (!isInitialized()) return; + var + o = options[pane] + , sel = o.contentSelector + , I = Instance[pane] + , $P = $Ps[pane] + , $C + ; + if (sel) $C = I.content = $Cs[pane] = (o.findNestedContent) + ? $P.find(sel).eq(0) // match 1-element only + : $P.children(sel).eq(0) + ; + if ($C && $C.length) { + $C.data("layoutRole", "content"); + // SAVE original Pane CSS + if (!$C.data("layoutCSS")) + $C.data("layoutCSS", elCSS($C, "height")); + $C.css( _c.content.cssReq ); + if (o.applyDemoStyles) { + $C.css( _c.content.cssDemo ); // add padding & overflow: auto to content-div + $P.css( _c.content.cssDemoPane ); // REMOVE padding/scrolling from pane + } + state[pane].content = {}; // init content state + if (resize !== false) sizeContent(pane); + // sizeContent() is called AFTER init of all elements + } + else + I.content = $Cs[pane] = false; + } + + + /** + * Add resize-bars to all panes that specify it in options + * -dependancy: $.fn.resizable - will skip if not found + * + * @see _create() + * @param {string=} [panes=""] The edge(s) to process + */ +, initResizable = function (panes) { + var draggingAvailable = $.layout.plugins.draggable + , side // set in start() + ; + panes = panes ? panes.split(",") : _c.borderPanes; + + $.each(panes, function (idx, pane) { + var o = options[pane]; + if (!draggingAvailable || !$Ps[pane] || !o.resizable) { + o.resizable = false; + return true; // skip to next + } + + var s = state[pane] + , z = options.zIndexes + , c = _c[pane] + , side = c.dir=="horz" ? "top" : "left" + , opEdge = _c.oppositeEdge[pane] + , masks = pane +",center,"+ opEdge + (c.dir=="horz" ? ",west,east" : "") + , $P = $Ps[pane] + , $R = $Rs[pane] + , base = o.resizerClass + , lastPos = 0 // used when live-resizing + , r, live // set in start because may change + // 'drag' classes are applied to the ORIGINAL resizer-bar while dragging is in process + , resizerClass = base+"-drag" // resizer-drag + , resizerPaneClass = base+"-"+pane+"-drag" // resizer-north-drag + // 'helper' class is applied to the CLONED resizer-bar while it is being dragged + , helperClass = base+"-dragging" // resizer-dragging + , helperPaneClass = base+"-"+pane+"-dragging" // resizer-north-dragging + , helperLimitClass = base+"-dragging-limit" // resizer-drag + , helperPaneLimitClass = base+"-"+pane+"-dragging-limit" // resizer-north-drag + , helperClassesSet = false // logic var + ; + + if (!s.isClosed) + $R.attr("title", o.resizerTip) + .css("cursor", o.resizerCursor); // n-resize, s-resize, etc + + $R.draggable({ + containment: $N[0] // limit resizing to layout container + , axis: (c.dir=="horz" ? "y" : "x") // limit resizing to horz or vert axis + , delay: 0 + , distance: 1 + , grid: o.resizingGrid + // basic format for helper - style it using class: .ui-draggable-dragging + , helper: "clone" + , opacity: o.resizerDragOpacity + , addClasses: false // avoid ui-state-disabled class when disabled + //, iframeFix: o.draggableIframeFix // TODO: consider using when bug is fixed + , zIndex: z.resizer_drag + + , start: function (e, ui) { + // REFRESH options & state pointers in case we used swapPanes + o = options[pane]; + s = state[pane]; + // re-read options + live = o.livePaneResizing; + + // ondrag_start callback - will CANCEL hide if returns false + // TODO: dragging CANNOT be cancelled like this, so see if there is a way? + if (false === _runCallbacks("ondrag_start", pane)) return false; + + s.isResizing = true; // prevent pane from closing while resizing + timer.clear(pane+"_closeSlider"); // just in case already triggered + + // SET RESIZER LIMITS - used in drag() + setSizeLimits(pane); // update pane/resizer state + r = s.resizerPosition; + lastPos = ui.position[ side ] + + $R.addClass( resizerClass +" "+ resizerPaneClass ); // add drag classes + helperClassesSet = false; // reset logic var - see drag() + + // DISABLE TEXT SELECTION (probably already done by resizer.mouseOver) + $('body').disableSelection(); + + // MASK PANES CONTAINING IFRAMES, APPLETS OR OTHER TROUBLESOME ELEMENTS + showMasks( masks ); + } + + , drag: function (e, ui) { + if (!helperClassesSet) { // can only add classes after clone has been added to the DOM + //$(".ui-draggable-dragging") + ui.helper + .addClass( helperClass +" "+ helperPaneClass ) // add helper classes + .css({ right: "auto", bottom: "auto" }) // fix dir="rtl" issue + .children().css("visibility","hidden") // hide toggler inside dragged resizer-bar + ; + helperClassesSet = true; + // draggable bug!? RE-SET zIndex to prevent E/W resize-bar showing through N/S pane! + if (s.isSliding) $Ps[pane].css("zIndex", z.pane_sliding); + } + // CONTAIN RESIZER-BAR TO RESIZING LIMITS + var limit = 0; + if (ui.position[side] < r.min) { + ui.position[side] = r.min; + limit = -1; + } + else if (ui.position[side] > r.max) { + ui.position[side] = r.max; + limit = 1; + } + // ADD/REMOVE dragging-limit CLASS + if (limit) { + ui.helper.addClass( helperLimitClass +" "+ helperPaneLimitClass ); // at dragging-limit + window.defaultStatus = (limit>0 && pane.match(/north|west/)) || (limit<0 && pane.match(/south|east/)) ? lang.maxSizeWarning : lang.minSizeWarning; + } + else { + ui.helper.removeClass( helperLimitClass +" "+ helperPaneLimitClass ); // not at dragging-limit + window.defaultStatus = ""; + } + // DYNAMICALLY RESIZE PANES IF OPTION ENABLED + // won't trigger unless resizer has actually moved! + if (live && Math.abs(ui.position[side] - lastPos) >= o.liveResizingTolerance) { + lastPos = ui.position[side]; + resizePanes(e, ui, pane) + } + } + + , stop: function (e, ui) { + $('body').enableSelection(); // RE-ENABLE TEXT SELECTION + window.defaultStatus = ""; // clear 'resizing limit' message from statusbar + $R.removeClass( resizerClass +" "+ resizerPaneClass ); // remove drag classes from Resizer + s.isResizing = false; + resizePanes(e, ui, pane, true, masks); // true = resizingDone + } + + }); + }); + + /** + * resizePanes + * + * Sub-routine called from stop() - and drag() if livePaneResizing + * + * @param {!Object} evt + * @param {!Object} ui + * @param {string} pane + * @param {boolean=} [resizingDone=false] + */ + var resizePanes = function (evt, ui, pane, resizingDone, masks) { + var dragPos = ui.position + , c = _c[pane] + , o = options[pane] + , s = state[pane] + , resizerPos + ; + switch (pane) { + case "north": resizerPos = dragPos.top; break; + case "west": resizerPos = dragPos.left; break; + case "south": resizerPos = sC.offsetHeight - dragPos.top - o.spacing_open; break; + case "east": resizerPos = sC.offsetWidth - dragPos.left - o.spacing_open; break; + }; + // remove container margin from resizer position to get the pane size + var newSize = resizerPos - sC["inset"+ c.side]; + + // Disable OR Resize Mask(s) created in drag.start + if (!resizingDone) { + // ensure we meet liveResizingTolerance criteria + if (Math.abs(newSize - s.size) < o.liveResizingTolerance) + return; // SKIP resize this time + // resize the pane + manualSizePane(pane, newSize, false, true); // true = noAnimation + sizeMasks(); // resize all visible masks + } + else { // resizingDone + // ondrag_end callback + if (false !== _runCallbacks("ondrag_end", pane)) + manualSizePane(pane, newSize, false, true); // true = noAnimation + hideMasks(); // hide all masks, which include panes with 'content/iframe-masks' + if (s.isSliding && masks) // RE-SHOW only 'object-masks' so objects won't show through sliding pane + showMasks( masks, true ); // true = onlyForObjects + } + }; + } + + /** + * sizeMask + * + * Needed to overlay a DIV over an IFRAME-pane because mask CANNOT be *inside* the pane + * Called when mask created, and during livePaneResizing + */ +, sizeMask = function () { + var $M = $(this) + , pane = $M.data("layoutMask") // eg: "west" + , s = state[pane] + ; + // only masks over an IFRAME-pane need manual resizing + if (s.tagName == "IFRAME" && s.isVisible) // no need to mask closed/hidden panes + $M.css({ + top: s.offsetTop + , left: s.offsetLeft + , width: s.outerWidth + , height: s.outerHeight + }); + /* ALT Method... + var $P = $Ps[pane]; + $M.css( $P.position() ).css({ width: $P[0].offsetWidth, height: $P[0].offsetHeight }); + */ + } +, sizeMasks = function () { + $Ms.each( sizeMask ); // resize all 'visible' masks + } + +, showMasks = function (panes, onlyForObjects) { + var a = panes ? panes.split(",") : $.layout.config.allPanes + , z = options.zIndexes + , o, s; + $.each(a, function(i,p){ + s = state[p]; + o = options[p]; + if (s.isVisible && ( (!onlyForObjects && o.maskContents) || o.maskObjects )) { + getMasks(p).each(function(){ + sizeMask.call(this); + this.style.zIndex = s.isSliding ? z.pane_sliding+1 : z.pane_normal+1 + this.style.display = "block"; + }); + } + }); + } + +, hideMasks = function () { + // ensure no pane is resizing - could be a timing issue + var skip; + $.each( $.layout.config.borderPanes, function(i,p){ + if (state[p].isResizing) { + skip = true; + return false; // BREAK + } + }); + if (!skip) + $Ms.hide(); // hide ALL masks + } + +, getMasks = function (pane) { + var $Masks = $([]) + , $M, i = 0, c = $Ms.length + ; + for (; i CSS + if (sC.tagName === "BODY" && ($N = $("html")).data(css)) // RESET CSS + $N.css( $N.data(css) ).removeData(css); + + // trigger plugins for this layout, if there are any + runPluginCallbacks( Instance, $.layout.onDestroy ); + + // trigger state-management and onunload callback + unload(); + + // clear the Instance of everything except for container & options (so could recreate) + // RE-CREATE: myLayout = myLayout.container.layout( myLayout.options ); + for (n in Instance) + if (!n.match(/^(container|options)$/)) delete Instance[ n ]; + // add a 'destroyed' flag to make it easy to check + Instance.destroyed = true; + + // if this is a child layout, CLEAR the child-pointer in the parent + /* for now the pointer REMAINS, but with only container, options and destroyed keys + if (parentPane) { + var layout = parentPane.pane.data("parentLayout"); + parentPane.child = layout.children[ parentPane.name ] = null; + } + */ + + return Instance; // for coding convenience + } + + /** + * Remove a pane from the layout - subroutine of destroy() + * + * @see destroy() + * @param {string} pane The pane to process + * @param {boolean=} [remove=false] Remove the DOM element? + * @param {boolean=} [skipResize=false] Skip calling resizeAll()? + */ +, removePane = function (evt_or_pane, remove, skipResize, destroyChild) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , $P = $Ps[pane] + , $C = $Cs[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + ; + //alert( '$P.length = '+ $P.length ); + // NOTE: elements can still exist even after remove() + // so check for missing data(), which is cleared by removed() + if ($P && $.isEmptyObject( $P.data() )) $P = false; + if ($C && $.isEmptyObject( $C.data() )) $C = false; + if ($R && $.isEmptyObject( $R.data() )) $R = false; + if ($T && $.isEmptyObject( $T.data() )) $T = false; + + if ($P) $P.stop(true, true); + + // check for a child layout + var o = options[pane] + , s = state[pane] + , d = "layout" + , css = "layoutCSS" + , child = children[pane] || ($P ? $P.data(d) : 0) || ($C ? $C.data(d) : 0) || null + , destroy = destroyChild !== undefined ? destroyChild : o.destroyChildLayout + ; + + // FIRST destroy the child-layout(s) + if (destroy && child && !child.destroyed) { + child.destroy(true); // tell child-layout to destroy ALL its child-layouts too + if (child.destroyed) // destroy was successful + child = null; // clear pointer for logic below + } + + if ($P && remove && !child) + $P.remove(); + else if ($P && $P[0]) { + // create list of ALL pane-classes that need to be removed + var root = o.paneClass // default="ui-layout-pane" + , pRoot = root +"-"+ pane // eg: "ui-layout-pane-west" + , _open = "-open" + , _sliding= "-sliding" + , _closed = "-closed" + , classes = [ root, root+_open, root+_closed, root+_sliding, // generic classes + pRoot, pRoot+_open, pRoot+_closed, pRoot+_sliding ] // pane-specific classes + ; + $.merge(classes, getHoverClasses($P, true)); // ADD hover-classes + // remove all Layout classes from pane-element + $P .removeClass( classes.join(" ") ) // remove ALL pane-classes + .removeData("parentLayout") + .removeData("layoutPane") + .removeData("layoutRole") + .removeData("layoutEdge") + .removeData("autoHidden") // in case set + .unbind("."+ sID) // remove ALL Layout events + // TODO: remove these extra unbind commands when jQuery is fixed + //.unbind("mouseenter"+ sID) + //.unbind("mouseleave"+ sID) + ; + // do NOT reset CSS if this pane/content is STILL the container of a nested layout! + // the nested layout will reset its 'container' CSS when/if it is destroyed + if ($C && $C.data(d)) { + // a content-div may not have a specific width, so give it one to contain the Layout + $C.width( $C.width() ); + child.resizeAll(); // now resize the Layout + } + else if ($C) + $C.css( $C.data(css) ).removeData(css).removeData("layoutRole"); + // remove pane AFTER content in case there was a nested layout + if (!$P.data(d)) + $P.css( $P.data(css) ).removeData(css); + } + + // REMOVE pane resizer and toggler elements + if ($T) $T.remove(); + if ($R) $R.remove(); + + // CLEAR all pointers and state data + Instance[pane] = $Ps[pane] = $Cs[pane] = $Rs[pane] = $Ts[pane] = children[pane] = false; + s = { removed: true }; + + if (!skipResize) + resizeAll(); + } /* * ########################### - * ACTION METHODS + * ACTION METHODS * ########################### */ -, _hidePane = function (pane) { - var $P = $Ps[pane] - , o = options[pane] - , s = $P[0].style - ; - if (o.useOffscreenClose) { - if (!$P.data(_c.offscreenReset)) - $P.data(_c.offscreenReset, { left: s.left, right: s.right }); - $P.css( _c.offscreenCSS ); - } - else - $P.hide().removeData(_c.offscreenReset); - } - -, _showPane = function (pane) { - var $P = $Ps[pane] - , o = options[pane] - , off = _c.offscreenCSS - , old = $P.data(_c.offscreenReset) - , s = $P[0].style - ; - $P .show() // ALWAYS show, just in case - .removeData(_c.offscreenReset); - if (o.useOffscreenClose && old) { - if (s.left == off.left) - s.left = old.left; - if (s.right == off.right) - s.right = old.right; - } - } - - - /** - * Completely 'hides' a pane, including its spacing - as if it does not exist - * The pane is not actually 'removed' from the source, so can use 'show' to un-hide it - * - * @param {string} pane The pane being hidden, ie: north, south, east, or west - * @param {boolean=} [noAnimation=false] - */ -, hide = function (evt_or_pane, noAnimation) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , o = options[pane] - , s = state[pane] - , $P = $Ps[pane] - , $R = $Rs[pane] - ; - if (!$P || s.isHidden) return; // pane does not exist OR is already hidden - - // onhide_start callback - will CANCEL hide if returns false - if (state.initialized && false === _runCallbacks("onhide_start", pane)) return; - - s.isSliding = false; // just in case - - // now hide the elements - if ($R) $R.hide(); // hide resizer-bar - if (!state.initialized || s.isClosed) { - s.isClosed = true; // to trigger open-animation on show() - s.isHidden = true; - s.isVisible = false; - if (!state.initialized) - _hidePane(pane); // no animation when loading page - sizeMidPanes(_c[pane].dir === "horz" ? "" : "center"); - if (state.initialized || o.triggerEventsOnLoad) - _runCallbacks("onhide_end", pane); - } - else { - s.isHiding = true; // used by onclose - close(pane, false, noAnimation); // adjust all panes to fit - } - } - - /** - * Show a hidden pane - show as 'closed' by default unless openPane = true - * - * @param {string} pane The pane being opened, ie: north, south, east, or west - * @param {boolean=} [openPane=false] - * @param {boolean=} [noAnimation=false] - * @param {boolean=} [noAlert=false] - */ -, show = function (evt_or_pane, openPane, noAnimation, noAlert) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , o = options[pane] - , s = state[pane] - , $P = $Ps[pane] - , $R = $Rs[pane] - ; - if (!$P || !s.isHidden) return; // pane does not exist OR is not hidden - - // onshow_start callback - will CANCEL show if returns false - if (false === _runCallbacks("onshow_start", pane)) return; - - s.isSliding = false; // just in case - s.isShowing = true; // used by onopen/onclose - //s.isHidden = false; - will be set by open/close - if not cancelled - - // now show the elements - //if ($R) $R.show(); - will be shown by open/close - if (openPane === false) - close(pane, true); // true = force - else - open(pane, false, noAnimation, noAlert); // adjust all panes to fit - } - - - /** - * Toggles a pane open/closed by calling either open or close - * - * @param {string} pane The pane being toggled, ie: north, south, east, or west - * @param {boolean=} [slide=false] - */ -, toggle = function (evt_or_pane, slide) { - if (!isInitialized()) return; - var evt = evtObj(evt_or_pane) - , pane = evtPane.call(this, evt_or_pane) - , s = state[pane] - ; - if (evt) // called from to $R.dblclick OR triggerPaneEvent - evt.stopImmediatePropagation(); - if (s.isHidden) - show(pane); // will call 'open' after unhiding it - else if (s.isClosed) - open(pane, !!slide); - else - close(pane); - } - - - /** - * Utility method used during init or other auto-processes - * - * @param {string} pane The pane being closed - * @param {boolean=} [setHandles=false] - */ -, _closePane = function (pane, setHandles) { - var - $P = $Ps[pane] - , s = state[pane] - ; - _hidePane(pane); - s.isClosed = true; - s.isVisible = false; - // UNUSED: if (setHandles) setAsClosed(pane, true); // true = force - } - - /** - * Close the specified pane (animation optional), and resize all other panes as needed - * - * @param {string} pane The pane being closed, ie: north, south, east, or west - * @param {boolean=} [force=false] - * @param {boolean=} [noAnimation=false] - * @param {boolean=} [skipCallback=false] - */ -, close = function (evt_or_pane, force, noAnimation, skipCallback) { - var pane = evtPane.call(this, evt_or_pane); - // if pane has been initialized, but NOT the complete layout, close pane instantly - if (!state.initialized && $Ps[pane]) { - _closePane(pane); // INIT pane as closed - return; - } - if (!isInitialized()) return; - - var - $P = $Ps[pane] - , $R = $Rs[pane] - , $T = $Ts[pane] - , o = options[pane] - , s = state[pane] - , c = _c[pane] - , doFX, isShowing, isHiding, wasSliding; - - // QUEUE in case another action/animation is in progress - $N.queue(function( queueNext ){ - - if ( !$P - || (!o.closable && !s.isShowing && !s.isHiding) // invalid request // (!o.resizable && !o.closable) ??? - || (!force && s.isClosed && !s.isShowing) // already closed - ) return queueNext(); - - // onclose_start callback - will CANCEL hide if returns false - // SKIP if just 'showing' a hidden pane as 'closed' - var abort = !s.isShowing && false === _runCallbacks("onclose_start", pane); - - // transfer logic vars to temp vars - isShowing = s.isShowing; - isHiding = s.isHiding; - wasSliding = s.isSliding; - // now clear the logic vars (REQUIRED before aborting) - delete s.isShowing; - delete s.isHiding; - - if (abort) return queueNext(); - - doFX = !noAnimation && !s.isClosed && (o.fxName_close != "none"); - s.isMoving = true; - s.isClosed = true; - s.isVisible = false; - // update isHidden BEFORE sizing panes - if (isHiding) s.isHidden = true; - else if (isShowing) s.isHidden = false; - - if (s.isSliding) // pane is being closed, so UNBIND trigger events - bindStopSlidingEvents(pane, false); // will set isSliding=false - else // resize panes adjacent to this one - sizeMidPanes(_c[pane].dir === "horz" ? "" : "center", false); // false = NOT skipCallback - - // if this pane has a resizer bar, move it NOW - before animation - setAsClosed(pane); - - // CLOSE THE PANE - if (doFX) { // animate the close - // mask panes with objects - var masks = "center"+ (c.dir=="horz" ? ",west,east" : ""); - showMasks( masks, true ); // true = ONLY mask panes with maskObjects=true - lockPaneForFX(pane, true); // need to set left/top so animation will work - $P.hide( o.fxName_close, o.fxSettings_close, o.fxSpeed_close, function () { - lockPaneForFX(pane, false); // undo - if (s.isClosed) close_2(); - queueNext(); - }); - } - else { // hide the pane without animation - _hidePane(pane); - close_2(); - queueNext(); - }; - }); - - // SUBROUTINE - function close_2 () { - s.isMoving = false; - bindStartSlidingEvent(pane, true); // will enable if o.slidable = true - - // if opposite-pane was autoClosed, see if it can be autoOpened now - var altPane = _c.oppositeEdge[pane]; - if (state[ altPane ].noRoom) { - setSizeLimits( altPane ); - makePaneFit( altPane ); - } - - // hide any masks shown while closing - hideMasks(); - - if (!skipCallback && (state.initialized || o.triggerEventsOnLoad)) { - // onclose callback - UNLESS just 'showing' a hidden pane as 'closed' - if (!isShowing) _runCallbacks("onclose_end", pane); - // onhide OR onshow callback - if (isShowing) _runCallbacks("onshow_end", pane); - if (isHiding) _runCallbacks("onhide_end", pane); - } - } - } - - /** - * @param {string} pane The pane just closed, ie: north, south, east, or west - */ -, setAsClosed = function (pane) { - var - $P = $Ps[pane] - , $R = $Rs[pane] - , $T = $Ts[pane] - , o = options[pane] - , s = state[pane] - , side = _c[pane].side.toLowerCase() - , inset = "inset"+ _c[pane].side - , rClass = o.resizerClass - , tClass = o.togglerClass - , _pane = "-"+ pane // used for classNames - , _open = "-open" - , _sliding= "-sliding" - , _closed = "-closed" - ; - $R - .css(side, sC[inset]) // move the resizer - .removeClass( rClass+_open +" "+ rClass+_pane+_open ) - .removeClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) - .addClass( rClass+_closed +" "+ rClass+_pane+_closed ) - .unbind("dblclick."+ sID) - ; - // DISABLE 'resizing' when closed - do this BEFORE bindStartSlidingEvent? - if (o.resizable && $.layout.plugins.draggable) - $R - .draggable("disable") - .removeClass("ui-state-disabled") // do NOT apply disabled styling - not suitable here - .css("cursor", "default") - .attr("title","") - ; - - // if pane has a toggler button, adjust that too - if ($T) { - $T - .removeClass( tClass+_open +" "+ tClass+_pane+_open ) - .addClass( tClass+_closed +" "+ tClass+_pane+_closed ) - .attr("title", o.togglerTip_closed) // may be blank - ; - // toggler-content - if exists - $T.children(".content-open").hide(); - $T.children(".content-closed").css("display","block"); - } - - // sync any 'pin buttons' - syncPinBtns(pane, false); - - if (state.initialized) { - // resize 'length' and position togglers for adjacent panes - sizeHandles(); - } - } - - /** - * Open the specified pane (animation optional), and resize all other panes as needed - * - * @param {string} pane The pane being opened, ie: north, south, east, or west - * @param {boolean=} [slide=false] - * @param {boolean=} [noAnimation=false] - * @param {boolean=} [noAlert=false] - */ -, open = function (evt_or_pane, slide, noAnimation, noAlert) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , $P = $Ps[pane] - , $R = $Rs[pane] - , $T = $Ts[pane] - , o = options[pane] - , s = state[pane] - , c = _c[pane] - , doFX, isShowing - ; - // QUEUE in case another action/animation is in progress - $N.queue(function( queueNext ){ - - if ( !$P - || (!o.resizable && !o.closable && !s.isShowing) // invalid request - || (s.isVisible && !s.isSliding) // already open - ) return queueNext(); - - // pane can ALSO be unhidden by just calling show(), so handle this scenario - if (s.isHidden && !s.isShowing) { - queueNext(); // call before show() because it needs the queue free - show(pane, true); - return; - } - - if (o.autoResize && s.size != o.size) // resize pane to original size set in options - sizePane(pane, o.size, true, true, true); // true=skipCallback/forceResize/noAnimation - else - // make sure there is enough space available to open the pane - setSizeLimits(pane, slide); - - // onopen_start callback - will CANCEL open if returns false - var cbReturn = _runCallbacks("onopen_start", pane); - - if (cbReturn === "abort") - return queueNext(); - - // update pane-state again in case options were changed in onopen_start - if (cbReturn !== "NC") // NC = "No Callback" - setSizeLimits(pane, slide); - - if (s.minSize > s.maxSize) { // INSUFFICIENT ROOM FOR PANE TO OPEN! - syncPinBtns(pane, false); // make sure pin-buttons are reset - if (!noAlert && o.noRoomToOpenTip) - alert(o.noRoomToOpenTip); - return queueNext(); // ABORT - } - - if (slide) // START Sliding - will set isSliding=true - bindStopSlidingEvents(pane, true); // BIND trigger events to close sliding-pane - else if (s.isSliding) // PIN PANE (stop sliding) - open pane 'normally' instead - bindStopSlidingEvents(pane, false); // UNBIND trigger events - will set isSliding=false - else if (o.slidable) - bindStartSlidingEvent(pane, false); // UNBIND trigger events - - s.noRoom = false; // will be reset by makePaneFit if 'noRoom' - makePaneFit(pane); - - // transfer logic var to temp var - isShowing = s.isShowing; - // now clear the logic var - delete s.isShowing; - - doFX = !noAnimation && s.isClosed && (o.fxName_open != "none"); - s.isMoving = true; - s.isVisible = true; - s.isClosed = false; - // update isHidden BEFORE sizing panes - WHY??? Old? - if (isShowing) s.isHidden = false; - - if (doFX) { // ANIMATE - // mask panes with objects - var masks = "center"+ (c.dir=="horz" ? ",west,east" : ""); - if (s.isSliding) masks += ","+ _c.oppositeEdge[pane]; - showMasks( masks, true ); // true = ONLY mask panes with maskObjects=true - lockPaneForFX(pane, true); // need to set left/top so animation will work - $P.show( o.fxName_open, o.fxSettings_open, o.fxSpeed_open, function() { - lockPaneForFX(pane, false); // undo - if (s.isVisible) open_2(); // continue - queueNext(); - }); - } - else { // no animation - _showPane(pane);// just show pane and... - open_2(); // continue - queueNext(); - }; - }); - - // SUBROUTINE - function open_2 () { - s.isMoving = false; - - // cure iframe display issues - _fixIframe(pane); - - // NOTE: if isSliding, then other panes are NOT 'resized' - if (!s.isSliding) { // resize all panes adjacent to this one - hideMasks(); // remove any masks shown while opening - sizeMidPanes(_c[pane].dir=="vert" ? "center" : "", false); // false = NOT skipCallback - } - - // set classes, position handles and execute callbacks... - setAsOpen(pane); - }; - - } - - /** - * @param {string} pane The pane just opened, ie: north, south, east, or west - * @param {boolean=} [skipCallback=false] - */ -, setAsOpen = function (pane, skipCallback) { - var - $P = $Ps[pane] - , $R = $Rs[pane] - , $T = $Ts[pane] - , o = options[pane] - , s = state[pane] - , side = _c[pane].side.toLowerCase() - , inset = "inset"+ _c[pane].side - , rClass = o.resizerClass - , tClass = o.togglerClass - , _pane = "-"+ pane // used for classNames - , _open = "-open" - , _closed = "-closed" - , _sliding= "-sliding" - ; - $R - .css(side, sC[inset] + getPaneSize(pane)) // move the resizer - .removeClass( rClass+_closed +" "+ rClass+_pane+_closed ) - .addClass( rClass+_open +" "+ rClass+_pane+_open ) - ; - if (s.isSliding) - $R.addClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) - else // in case 'was sliding' - $R.removeClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) - - if (o.resizerDblClickToggle) - $R.bind("dblclick", toggle ); - removeHover( 0, $R ); // remove hover classes - if (o.resizable && $.layout.plugins.draggable) - $R .draggable("enable") - .css("cursor", o.resizerCursor) - .attr("title", o.resizerTip); - else if (!s.isSliding) - $R.css("cursor", "default"); // n-resize, s-resize, etc - - // if pane also has a toggler button, adjust that too - if ($T) { - $T .removeClass( tClass+_closed +" "+ tClass+_pane+_closed ) - .addClass( tClass+_open +" "+ tClass+_pane+_open ) - .attr("title", o.togglerTip_open); // may be blank - removeHover( 0, $T ); // remove hover classes - // toggler-content - if exists - $T.children(".content-closed").hide(); - $T.children(".content-open").css("display","block"); - } - - // sync any 'pin buttons' - syncPinBtns(pane, !s.isSliding); - - // update pane-state dimensions - BEFORE resizing content - $.extend(s, elDims($P)); - - if (state.initialized) { - // resize resizer & toggler sizes for all panes - sizeHandles(); - // resize content every time pane opens - to be sure - sizeContent(pane, true); // true = remeasure headers/footers, even if 'pane.isMoving' - } - - if (!skipCallback && (state.initialized || o.triggerEventsOnLoad) && $P.is(":visible")) { - // onopen callback - _runCallbacks("onopen_end", pane); - // onshow callback - TODO: should this be here? - if (s.isShowing) _runCallbacks("onshow_end", pane); - - // ALSO call onresize because layout-size *may* have changed while pane was closed - if (state.initialized) - _runCallbacks("onresize_end", pane); - } - - // TODO: Somehow sizePane("north") is being called after this point??? - } - - - /** - * slideOpen / slideClose / slideToggle - * - * Pass-though methods for sliding - */ -, slideOpen = function (evt_or_pane) { - if (!isInitialized()) return; - var evt = evtObj(evt_or_pane) - , pane = evtPane.call(this, evt_or_pane) - , s = state[pane] - , delay = options[pane].slideDelay_open - ; - // prevent event from triggering on NEW resizer binding created below - if (evt) evt.stopImmediatePropagation(); - - if (s.isClosed && evt && evt.type === "mouseenter" && delay > 0) - // trigger = mouseenter - use a delay - timer.set(pane+"_openSlider", open_NOW, delay); - else - open_NOW(); // will unbind events if is already open - - /** - * SUBROUTINE for timed open - */ - function open_NOW () { - if (!s.isClosed) // skip if no longer closed! - bindStopSlidingEvents(pane, true); // BIND trigger events to close sliding-pane - else if (!s.isMoving) - open(pane, true); // true = slide - open() will handle binding - }; - } - -, slideClose = function (evt_or_pane) { - if (!isInitialized()) return; - var evt = evtObj(evt_or_pane) - , pane = evtPane.call(this, evt_or_pane) - , o = options[pane] - , s = state[pane] - , delay = s.isMoving ? 1000 : 300 // MINIMUM delay - option may override - ; - if (s.isClosed || s.isResizing) - return; // skip if already closed OR in process of resizing - else if (o.slideTrigger_close === "click") - close_NOW(); // close immediately onClick - else if (o.preventQuickSlideClose && s.isMoving) - return; // handle Chrome quick-close on slide-open - else if (o.preventPrematureSlideClose && evt && $.layout.isMouseOverElem(evt, $Ps[pane])) - return; // handle incorrect mouseleave trigger, like when over a SELECT-list in IE - else if (evt) // trigger = mouseleave - use a delay - // 1 sec delay if 'opening', else .3 sec - timer.set(pane+"_closeSlider", close_NOW, max(o.slideDelay_close, delay)); - else // called programically - close_NOW(); - - /** - * SUBROUTINE for timed close - */ - function close_NOW () { - if (s.isClosed) // skip 'close' if already closed! - bindStopSlidingEvents(pane, false); // UNBIND trigger events - TODO: is this needed here? - else if (!s.isMoving) - close(pane); // close will handle unbinding - }; - } - - /** - * @param {string} pane The pane being opened, ie: north, south, east, or west - */ -, slideToggle = function (evt_or_pane) { - var pane = evtPane.call(this, evt_or_pane); - toggle(pane, true); - } - - - /** - * Must set left/top on East/South panes so animation will work properly - * - * @param {string} pane The pane to lock, 'east' or 'south' - any other is ignored! - * @param {boolean} doLock true = set left/top, false = remove - */ -, lockPaneForFX = function (pane, doLock) { - var $P = $Ps[pane] - , s = state[pane] - , o = options[pane] - , z = options.zIndexes - ; - if (doLock) { - $P.css({ zIndex: z.pane_animate }); // overlay all elements during animation - if (pane=="south") - $P.css({ top: sC.insetTop + sC.innerHeight - $P.outerHeight() }); - else if (pane=="east") - $P.css({ left: sC.insetLeft + sC.innerWidth - $P.outerWidth() }); - } - else { // animation DONE - RESET CSS - // TODO: see if this can be deleted. It causes a quick-close when sliding in Chrome - $P.css({ zIndex: (s.isSliding ? z.pane_sliding : z.pane_normal) }); - if (pane=="south") - $P.css({ top: "auto" }); - // if pane is positioned 'off-screen', then DO NOT screw with it! - else if (pane=="east" && !$P.css("left").match(/\-99999/)) - $P.css({ left: "auto" }); - // fix anti-aliasing in IE - only needed for animations that change opacity - if (browser.msie && o.fxOpacityFix && o.fxName_open != "slide" && $P.css("filter") && $P.css("opacity") == 1) - $P[0].style.removeAttribute('filter'); - } - } - - - /** - * Toggle sliding functionality of a specific pane on/off by adding removing 'slide open' trigger - * - * @see open(), close() - * @param {string} pane The pane to enable/disable, 'north', 'south', etc. - * @param {boolean} enable Enable or Disable sliding? - */ -, bindStartSlidingEvent = function (pane, enable) { - var o = options[pane] - , $P = $Ps[pane] - , $R = $Rs[pane] - , evtName = o.slideTrigger_open.toLowerCase() - ; - if (!$R || (enable && !o.slidable)) return; - - // make sure we have a valid event - if (evtName.match(/mouseover/)) - evtName = o.slideTrigger_open = "mouseenter"; - else if (!evtName.match(/click|dblclick|mouseenter/)) - evtName = o.slideTrigger_open = "click"; - - $R - // add or remove event - [enable ? "bind" : "unbind"](evtName +'.'+ sID, slideOpen) - // set the appropriate cursor & title/tip - .css("cursor", enable ? o.sliderCursor : "default") - .attr("title", enable ? o.sliderTip : "") - ; - } - - /** - * Add or remove 'mouseleave' events to 'slide close' when pane is 'sliding' open or closed - * Also increases zIndex when pane is sliding open - * See bindStartSlidingEvent for code to control 'slide open' - * - * @see slideOpen(), slideClose() - * @param {string} pane The pane to process, 'north', 'south', etc. - * @param {boolean} enable Enable or Disable events? - */ -, bindStopSlidingEvents = function (pane, enable) { - var o = options[pane] - , s = state[pane] - , c = _c[pane] - , z = options.zIndexes - , evtName = o.slideTrigger_close.toLowerCase() - , action = (enable ? "bind" : "unbind") - , $P = $Ps[pane] - , $R = $Rs[pane] - ; - s.isSliding = enable; // logic - timer.clear(pane+"_closeSlider"); // just in case - - // remove 'slideOpen' event from resizer - // ALSO will raise the zIndex of the pane & resizer - if (enable) bindStartSlidingEvent(pane, false); - - // RE/SET zIndex - increases when pane is sliding-open, resets to normal when not - $P.css("zIndex", enable ? z.pane_sliding : z.pane_normal); - $R.css("zIndex", enable ? z.pane_sliding+2 : z.resizer_normal); // NOTE: mask = pane_sliding+1 - - // make sure we have a valid event - if (!evtName.match(/click|mouseleave/)) - evtName = o.slideTrigger_close = "mouseleave"; // also catches 'mouseout' - - // add/remove slide triggers - $R[action](evtName, slideClose); // base event on resize - // need extra events for mouseleave - if (evtName === "mouseleave") { - // also close on pane.mouseleave - $P[action]("mouseleave."+ sID, slideClose); - // cancel timer when mouse moves between 'pane' and 'resizer' - $R[action]("mouseenter."+ sID, cancelMouseOut); - $P[action]("mouseenter."+ sID, cancelMouseOut); - } - - if (!enable) - timer.clear(pane+"_closeSlider"); - else if (evtName === "click" && !o.resizable) { - // IF pane is not resizable (which already has a cursor and tip) - // then set the a cursor & title/tip on resizer when sliding - $R.css("cursor", enable ? o.sliderCursor : "default"); - $R.attr("title", enable ? o.togglerTip_open : ""); // use Toggler-tip, eg: "Close Pane" - } - - // SUBROUTINE for mouseleave timer clearing - function cancelMouseOut (evt) { - timer.clear(pane+"_closeSlider"); - evt.stopPropagation(); - } - } - - - /** - * Hides/closes a pane if there is insufficient room - reverses this when there is room again - * MUST have already called setSizeLimits() before calling this method - * - * @param {string} pane The pane being resized - * @param {boolean=} [isOpening=false] Called from onOpen? - * @param {boolean=} [skipCallback=false] Should the onresize callback be run? - * @param {boolean=} [force=false] - */ -, makePaneFit = function (pane, isOpening, skipCallback, force) { - var - o = options[pane] - , s = state[pane] - , c = _c[pane] - , $P = $Ps[pane] - , $R = $Rs[pane] - , isSidePane = c.dir==="vert" - , hasRoom = false - ; - // special handling for center & east/west panes - if (pane === "center" || (isSidePane && s.noVerticalRoom)) { - // see if there is enough room to display the pane - // ERROR: hasRoom = s.minHeight <= s.maxHeight && (isSidePane || s.minWidth <= s.maxWidth); - hasRoom = (s.maxHeight >= 0); - if (hasRoom && s.noRoom) { // previously hidden due to noRoom, so show now - _showPane(pane); - if ($R) $R.show(); - s.isVisible = true; - s.noRoom = false; - if (isSidePane) s.noVerticalRoom = false; - _fixIframe(pane); - } - else if (!hasRoom && !s.noRoom) { // not currently hidden, so hide now - _hidePane(pane); - if ($R) $R.hide(); - s.isVisible = false; - s.noRoom = true; - } - } - - // see if there is enough room to fit the border-pane - if (pane === "center") { - // ignore center in this block - } - else if (s.minSize <= s.maxSize) { // pane CAN fit - hasRoom = true; - if (s.size > s.maxSize) // pane is too big - shrink it - sizePane(pane, s.maxSize, skipCallback, force, true); // true = noAnimation - else if (s.size < s.minSize) // pane is too small - enlarge it - sizePane(pane, s.minSize, skipCallback, force, true); - // need s.isVisible because new pseudoClose method keeps pane visible, but off-screen - else if ($R && s.isVisible && $P.is(":visible")) { - // make sure resizer-bar is positioned correctly - // handles situation where nested layout was 'hidden' when initialized - var side = c.side.toLowerCase() - , pos = s.size + sC["inset"+ c.side] - ; - if ($.layout.cssNum($R, side) != pos) $R.css( side, pos ); - } - - // if was previously hidden due to noRoom, then RESET because NOW there is room - if (s.noRoom) { - // s.noRoom state will be set by open or show - if (s.wasOpen && o.closable) { - if (o.autoReopen) - open(pane, false, true, true); // true = noAnimation, true = noAlert - else // leave the pane closed, so just update state - s.noRoom = false; - } - else - show(pane, s.wasOpen, true, true); // true = noAnimation, true = noAlert - } - } - else { // !hasRoom - pane CANNOT fit - if (!s.noRoom) { // pane not set as noRoom yet, so hide or close it now... - s.noRoom = true; // update state - s.wasOpen = !s.isClosed && !s.isSliding; - if (s.isClosed){} // SKIP - else if (o.closable) // 'close' if possible - close(pane, true, true); // true = force, true = noAnimation - else // 'hide' pane if cannot just be closed - hide(pane, true); // true = noAnimation - } - } - } - - - /** - * sizePane / manualSizePane - * sizePane is called only by internal methods whenever a pane needs to be resized - * manualSizePane is an exposed flow-through method allowing extra code when pane is 'manually resized' - * - * @param {string} pane The pane being resized - * @param {number} size The *desired* new size for this pane - will be validated - * @param {boolean=} [skipCallback=false] Should the onresize callback be run? - * @param {boolean=} [noAnimation=false] - */ -, manualSizePane = function (evt_or_pane, size, skipCallback, noAnimation) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , o = options[pane] - , s = state[pane] - // if resizing callbacks have been delayed and resizing is now DONE, force resizing to complete... - , forceResize = o.livePaneResizing && !s.isResizing - ; - // ANY call to manualSizePane disables autoResize - ie, percentage sizing - o.autoResize = false; - // flow-through... - sizePane(pane, size, skipCallback, forceResize, noAnimation); // will animate resize if option enabled - } - - /** - * @param {string} pane The pane being resized - * @param {number} size The *desired* new size for this pane - will be validated - * @param {boolean=} [skipCallback=false] Should the onresize callback be run? - * @param {boolean=} [force=false] Force resizing even if does not seem necessary - * @param {boolean=} [noAnimation=false] - */ -, sizePane = function (evt_or_pane, size, skipCallback, force, noAnimation) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) // probably NEVER called from event? - , o = options[pane] - , s = state[pane] - , $P = $Ps[pane] - , $R = $Rs[pane] - , side = _c[pane].side.toLowerCase() - , dimName = _c[pane].sizeType.toLowerCase() - , inset = "inset"+ _c[pane].side - , skipResizeWhileDragging = s.isResizing && !o.triggerEventsDuringLiveResize - , doFX = noAnimation !== true && o.animatePaneSizing - , oldSize, newSize - ; - // QUEUE in case another action/animation is in progress - $N.queue(function( queueNext ){ - // calculate 'current' min/max sizes - setSizeLimits(pane); // update pane-state - oldSize = s.size; - size = _parseSize(pane, size); // handle percentages & auto - size = max(size, _parseSize(pane, o.minSize)); - size = min(size, s.maxSize); - if (size < s.minSize) { // not enough room for pane! - queueNext(); // call before makePaneFit() because it needs the queue free - makePaneFit(pane, false, skipCallback); // will hide or close pane - return; - } - - // IF newSize is same as oldSize, then nothing to do - abort - if (!force && size === oldSize) - return queueNext(); - - // onresize_start callback CANNOT cancel resizing because this would break the layout! - if (!skipCallback && state.initialized && s.isVisible) - _runCallbacks("onresize_start", pane); - - // resize the pane, and make sure its visible - newSize = cssSize(pane, size); - - if (doFX && $P.is(":visible")) { // ANIMATE - var fx = $.layout.effects.size[pane] || $.layout.effects.size.all - , easing = o.fxSettings_size.easing || fx.easing - , z = options.zIndexes - , props = {}; - props[ dimName ] = newSize +'px'; - s.isMoving = true; - // overlay all elements during animation - $P.css({ zIndex: z.pane_animate }) - .show().animate( props, o.fxSpeed_size, easing, function(){ - // reset zIndex after animation - $P.css({ zIndex: (s.isSliding ? z.pane_sliding : z.pane_normal) }); - s.isMoving = false; - sizePane_2(); // continue - queueNext(); - }); - } - else { // no animation - $P.css( dimName, newSize ); // resize pane - // if pane is visible, then - if ($P.is(":visible")) - sizePane_2(); // continue - else { - // pane is NOT VISIBLE, so just update state data... - // when pane is *next opened*, it will have the new size - s.size = size; // update state.size - $.extend(s, elDims($P)); // update state dimensions - } - queueNext(); - }; - - }); - - // SUBROUTINE - function sizePane_2 () { - /* Panes are sometimes not sized precisely in some browsers!? - * This code will resize the pane up to 3 times to nudge the pane to the correct size - */ - var actual = dimName==='width' ? $P.outerWidth() : $P.outerHeight() - , tries = [{ - pane: pane - , count: 1 - , target: size - , actual: actual - , correct: (size === actual) - , attempt: size - , cssSize: newSize - }] - , lastTry = tries[0] - , msg = 'Inaccurate size after resizing the '+ pane +'-pane.' - ; - while ( !lastTry.correct ) { - thisTry = { pane: pane, count: lastTry.count+1, target: size }; - - if (lastTry.actual > size) - thisTry.attempt = max(0, lastTry.attempt - (lastTry.actual - size)); - else // lastTry.actual < size - thisTry.attempt = max(0, lastTry.attempt + (size - lastTry.actual)); - - thisTry.cssSize = cssSize(pane, thisTry.attempt); - $P.css( dimName, thisTry.cssSize ); - - thisTry.actual = dimName=='width' ? $P.outerWidth() : $P.outerHeight(); - thisTry.correct = (size === thisTry.actual); - - // if showDebugMessages, log attempts and alert the user of this *non-fatal error* - if (options.showDebugMessages) { - if ( tries.length === 1) { - _log(msg, false); - _log(lastTry, false); - } - _log(thisTry, false); - } - - // after 4 tries, is as close as its gonna get! - if (tries.length > 3) break; - - tries.push( thisTry ); - lastTry = tries[ tries.length - 1 ]; - } - // END TESTING CODE - - // update pane-state dimensions - s.size = size; - $.extend(s, elDims($P)); - - if (s.isVisible && $P.is(":visible")) { - // reposition the resizer-bar - if ($R) $R.css( side, size + sC[inset] ); - // resize the content-div - sizeContent(pane); - } - - if (!skipCallback && !skipResizeWhileDragging && state.initialized && s.isVisible) - _runCallbacks("onresize_end", pane); - - // resize all the adjacent panes, and adjust their toggler buttons - // when skipCallback passed, it means the controlling method will handle 'other panes' - if (!skipCallback) { - // also no callback if live-resize is in progress and NOT triggerEventsDuringLiveResize - if (!s.isSliding) sizeMidPanes(_c[pane].dir=="horz" ? "" : "center", skipResizeWhileDragging, force); - sizeHandles(); - } - - // if opposite-pane was autoClosed, see if it can be autoOpened now - var altPane = _c.oppositeEdge[pane]; - if (size < oldSize && state[ altPane ].noRoom) { - setSizeLimits( altPane ); - makePaneFit( altPane, false, skipCallback ); - } - - // DEBUG - ALERT user/developer so they know there was a sizing problem - if (options.showDebugMessages && tries.length > 1) - _log(msg +'\nSee the Error Console for details.', true); - } - } - - /** - * @see initPanes(), sizePane(), resizeAll(), open(), close(), hide() - * @param {string} panes The pane(s) being resized, comma-delmited string - * @param {boolean=} [skipCallback=false] Should the onresize callback be run? - * @param {boolean=} [force=false] - */ -, sizeMidPanes = function (panes, skipCallback, force) { - panes = (panes ? panes : "east,west,center").split(","); - - $.each(panes, function (i, pane) { - if (!$Ps[pane]) return; // NO PANE - skip - var - o = options[pane] - , s = state[pane] - , $P = $Ps[pane] - , $R = $Rs[pane] - , isCenter= (pane=="center") - , hasRoom = true - , CSS = {} - , newCenter = calcNewCenterPaneDims() - ; - // update pane-state dimensions - $.extend(s, elDims($P)); - - if (pane === "center") { - if (!force && s.isVisible && newCenter.width === s.outerWidth && newCenter.height === s.outerHeight) - return true; // SKIP - pane already the correct size - // set state for makePaneFit() logic - $.extend(s, cssMinDims(pane), { - maxWidth: newCenter.width - , maxHeight: newCenter.height - }); - CSS = newCenter; - // convert OUTER width/height to CSS width/height - CSS.width = cssW($P, CSS.width); - // NEW - allow pane to extend 'below' visible area rather than hide it - CSS.height = cssH($P, CSS.height); - hasRoom = CSS.width >= 0 && CSS.height >= 0; // height >= 0 = ALWAYS TRUE NOW - // during layout init, try to shrink east/west panes to make room for center - if (!state.initialized && o.minWidth > s.outerWidth) { - var - reqPx = o.minWidth - s.outerWidth - , minE = options.east.minSize || 0 - , minW = options.west.minSize || 0 - , sizeE = state.east.size - , sizeW = state.west.size - , newE = sizeE - , newW = sizeW - ; - if (reqPx > 0 && state.east.isVisible && sizeE > minE) { - newE = max( sizeE-minE, sizeE-reqPx ); - reqPx -= sizeE-newE; - } - if (reqPx > 0 && state.west.isVisible && sizeW > minW) { - newW = max( sizeW-minW, sizeW-reqPx ); - reqPx -= sizeW-newW; - } - // IF we found enough extra space, then resize the border panes as calculated - if (reqPx === 0) { - if (sizeE != minE) - sizePane('east', newE, true, force, true); // true = skipCallback/noAnimation - initPanes will handle when done - if (sizeW != minW) - sizePane('west', newW, true, force, true); - // now start over! - sizeMidPanes('center', skipCallback, force); - return; // abort this loop - } - } - } - else { // for east and west, set only the height, which is same as center height - // set state.min/maxWidth/Height for makePaneFit() logic - if (s.isVisible && !s.noVerticalRoom) - $.extend(s, elDims($P), cssMinDims(pane)) - if (!force && !s.noVerticalRoom && newCenter.height === s.outerHeight) - return true; // SKIP - pane already the correct size - // east/west have same top, bottom & height as center - CSS.top = newCenter.top; - CSS.bottom = newCenter.bottom; - // NEW - allow pane to extend 'below' visible area rather than hide it - CSS.height = cssH($P, newCenter.height); - s.maxHeight = CSS.height; - hasRoom = (s.maxHeight >= 0); // ALWAYS TRUE NOW - if (!hasRoom) s.noVerticalRoom = true; // makePaneFit() logic - } - - if (hasRoom) { - // resizeAll passes skipCallback because it triggers callbacks after ALL panes are resized - if (!skipCallback && state.initialized) - _runCallbacks("onresize_start", pane); - - $P.css(CSS); // apply the CSS to pane - sizeHandles(pane); // also update resizer length - if (s.noRoom && !s.isClosed && !s.isHidden) - makePaneFit(pane); // will re-open/show auto-closed/hidden pane - if (s.isVisible) { - $.extend(s, elDims($P)); // update pane dimensions - if (state.initialized) sizeContent(pane); // also resize the contents, if exists - } - } - else if (!s.noRoom && s.isVisible) // no room for pane - makePaneFit(pane); // will hide or close pane - - if (!s.isVisible) - return true; // DONE - next pane - - /* - * Extra CSS for IE6 or IE7 in Quirks-mode - add 'width' to NORTH/SOUTH panes - * Normally these panes have only 'left' & 'right' positions so pane auto-sizes - * ALSO required when pane is an IFRAME because will NOT default to 'full width' - */ - if (pane === "center") { // finished processing midPanes - var b = $.layout.browser; - var fix = b.isIE6 || (b.msie && !$.support.boxModel); - if ($Ps.north && (fix || state.north.tagName=="IFRAME")) - $Ps.north.css("width", cssW($Ps.north, sC.innerWidth)); - if ($Ps.south && (fix || state.south.tagName=="IFRAME")) - $Ps.south.css("width", cssW($Ps.south, sC.innerWidth)); - } - - // resizeAll passes skipCallback because it triggers callbacks after ALL panes are resized - if (!skipCallback && state.initialized) - _runCallbacks("onresize_end", pane); - }); - } - - - /** - * @see window.onresize(), callbacks or custom code - */ -, resizeAll = function () { - if (!state.initialized) { - _initLayoutElements(); - return; // no need to resize since we just initialized! - } - var oldW = sC.innerWidth - , oldH = sC.innerHeight - ; - // cannot size layout when 'container' is hidden or collapsed - if (!$N.is(":visible:") ) return; - $.extend( state.container, elDims( $N ) ); // UPDATE container dimensions - if (!sC.outerHeight) return; - - // onresizeall_start will CANCEL resizing if returns false - // state.container has already been set, so user can access this info for calcuations - if (false === _runCallbacks("onresizeall_start")) return false; - - var // see if container is now 'smaller' than before - shrunkH = (sC.innerHeight < oldH) - , shrunkW = (sC.innerWidth < oldW) - , $P, o, s, dir - ; - // NOTE special order for sizing: S-N-E-W - $.each(["south","north","east","west"], function (i, pane) { - if (!$Ps[pane]) return; // no pane - SKIP - s = state[pane]; - o = options[pane]; - dir = _c[pane].dir; - - if (o.autoResize && s.size != o.size) // resize pane to original size set in options - sizePane(pane, o.size, true, true, true); // true=skipCallback/forceResize/noAnimation - else { - setSizeLimits(pane); - makePaneFit(pane, false, true, true); // true=skipCallback/forceResize - } - }); - - sizeMidPanes("", true, true); // true=skipCallback, true=forceResize - sizeHandles(); // reposition the toggler elements - - // trigger all individual pane callbacks AFTER layout has finished resizing - o = options; // reuse alias - $.each(_c.allPanes, function (i, pane) { - $P = $Ps[pane]; - if (!$P) return; // SKIP - if (state[pane].isVisible) // undefined for non-existent panes - _runCallbacks("onresize_end", pane); // callback - if exists - }); - - _runCallbacks("onresizeall_end"); - //_triggerLayoutEvent(pane, 'resizeall'); - } - - /** - * Whenever a pane resizes or opens that has a nested layout, trigger resizeAll - * - * @param {string} pane The pane just resized or opened - */ -, resizeChildLayout = function (evt_or_pane) { - var pane = evtPane.call(this, evt_or_pane); - if (!options[pane].resizeChildLayout) return; - var $P = $Ps[pane] - , $C = $Cs[pane] - , d = "layout" - , P = Instance[pane] - , L = children[pane] - ; - // user may have manually set EITHER instance pointer, so handle that - if (P.child && !L) { - // have to reverse the pointers! - var el = P.child.container; - L = children[pane] = (el ? el.data(d) : 0) || null; // set pointer _directly_ to layout instance - } - - // if a layout-pointer exists, see if child has been destroyed - if (L && L.destroyed) - L = children[pane] = null; // clear child pointers - // no child layout pointer is set - see if there is a child layout NOW - if (!L) L = children[pane] = $P.data(d) || ($C ? $C.data(d) : 0) || null; // set/update child pointers - - // ALWAYS refresh the pane.child alias - P.child = children[pane]; - - if (L) L.resizeAll(); - } - - - /** - * IF pane has a content-div, then resize all elements inside pane to fit pane-height - * - * @param {string=} [panes=""] The pane(s) being resized - * @param {boolean=} [remeasure=false] Should the content (header/footer) be remeasured? - */ -, sizeContent = function (evt_or_panes, remeasure) { - if (!isInitialized()) return; - - var panes = evtPane.call(this, evt_or_panes); - panes = panes ? panes.split(",") : _c.allPanes; - - $.each(panes, function (idx, pane) { - var - $P = $Ps[pane] - , $C = $Cs[pane] - , o = options[pane] - , s = state[pane] - , m = s.content // m = measurements - ; - if (!$P || !$C || !$P.is(":visible")) return true; // NOT VISIBLE - skip - - // if content-element was REMOVED, update OR remove the pointer - if (!$C.length) { - initContent(pane, false); // false = do NOT sizeContent() - already there! - if (!$C) return; // no replacement element found - pointer have been removed - } - - // onsizecontent_start will CANCEL resizing if returns false - if (false === _runCallbacks("onsizecontent_start", pane)) return; - - // skip re-measuring offsets if live-resizing - if ((!s.isMoving && !s.isResizing) || o.liveContentResizing || remeasure || m.top == undefined) { - _measure(); - // if any footers are below pane-bottom, they may not measure correctly, - // so allow pane overflow and re-measure - if (m.hiddenFooters > 0 && $P.css("overflow") === "hidden") { - $P.css("overflow", "visible"); - _measure(); // remeasure while overflowing - $P.css("overflow", "hidden"); - } - } - // NOTE: spaceAbove/Below *includes* the pane paddingTop/Bottom, but not pane.borders - var newH = s.innerHeight - (m.spaceAbove - s.css.paddingTop) - (m.spaceBelow - s.css.paddingBottom); - - if (!$C.is(":visible") || m.height != newH) { - // size the Content element to fit new pane-size - will autoHide if not enough room - setOuterHeight($C, newH, true); // true=autoHide - m.height = newH; // save new height - }; - - if (state.initialized) - _runCallbacks("onsizecontent_end", pane); - - function _below ($E) { - return max(s.css.paddingBottom, (parseInt($E.css("marginBottom"), 10) || 0)); - }; - - function _measure () { - var - ignore = options[pane].contentIgnoreSelector - , $Fs = $C.nextAll().not(ignore || ':lt(0)') // not :lt(0) = ALL - , $Fs_vis = $Fs.filter(':visible') - , $F = $Fs_vis.filter(':last') - ; - m = { - top: $C[0].offsetTop - , height: $C.outerHeight() - , numFooters: $Fs.length - , hiddenFooters: $Fs.length - $Fs_vis.length - , spaceBelow: 0 // correct if no content footer ($E) - } - m.spaceAbove = m.top; // just for state - not used in calc - m.bottom = m.top + m.height; - if ($F.length) - //spaceBelow = (LastFooter.top + LastFooter.height) [footerBottom] - Content.bottom + max(LastFooter.marginBottom, pane.paddingBotom) - m.spaceBelow = ($F[0].offsetTop + $F.outerHeight()) - m.bottom + _below($F); - else // no footer - check marginBottom on Content element itself - m.spaceBelow = _below($C); - }; - }); - } - - - /** - * Called every time a pane is opened, closed, or resized to slide the togglers to 'center' and adjust their length if necessary - * - * @see initHandles(), open(), close(), resizeAll() - * @param {string=} [panes=""] The pane(s) being resized - */ -, sizeHandles = function (evt_or_panes) { - var panes = evtPane.call(this, evt_or_panes) - panes = panes ? panes.split(",") : _c.borderPanes; - - $.each(panes, function (i, pane) { - var - o = options[pane] - , s = state[pane] - , $P = $Ps[pane] - , $R = $Rs[pane] - , $T = $Ts[pane] - , $TC - ; - if (!$P || !$R) return; - - var - dir = _c[pane].dir - , _state = (s.isClosed ? "_closed" : "_open") - , spacing = o["spacing"+ _state] - , togAlign = o["togglerAlign"+ _state] - , togLen = o["togglerLength"+ _state] - , paneLen - , left - , offset - , CSS = {} - ; - - if (spacing === 0) { - $R.hide(); - return; - } - else if (!s.noRoom && !s.isHidden) // skip if resizer was hidden for any reason - $R.show(); // in case was previously hidden - - // Resizer Bar is ALWAYS same width/height of pane it is attached to - if (dir === "horz") { // north/south - //paneLen = $P.outerWidth(); // s.outerWidth || - paneLen = sC.innerWidth; // handle offscreen-panes - s.resizerLength = paneLen; - left = $.layout.cssNum($P, "left") - $R.css({ - width: cssW($R, paneLen) // account for borders & padding - , height: cssH($R, spacing) // ditto - , left: left > -9999 ? left : sC.insetLeft // handle offscreen-panes - }); - } - else { // east/west - paneLen = $P.outerHeight(); // s.outerHeight || - s.resizerLength = paneLen; - $R.css({ - height: cssH($R, paneLen) // account for borders & padding - , width: cssW($R, spacing) // ditto - , top: sC.insetTop + getPaneSize("north", true) // TODO: what if no North pane? - //, top: $.layout.cssNum($Ps["center"], "top") - }); - } - - // remove hover classes - removeHover( o, $R ); - - if ($T) { - if (togLen === 0 || (s.isSliding && o.hideTogglerOnSlide)) { - $T.hide(); // always HIDE the toggler when 'sliding' - return; - } - else - $T.show(); // in case was previously hidden - - if (!(togLen > 0) || togLen === "100%" || togLen > paneLen) { - togLen = paneLen; - offset = 0; - } - else { // calculate 'offset' based on options.PANE.togglerAlign_open/closed - if (isStr(togAlign)) { - switch (togAlign) { - case "top": - case "left": offset = 0; - break; - case "bottom": - case "right": offset = paneLen - togLen; - break; - case "middle": - case "center": - default: offset = round((paneLen - togLen) / 2); // 'default' catches typos - } - } - else { // togAlign = number - var x = parseInt(togAlign, 10); // - if (togAlign >= 0) offset = x; - else offset = paneLen - togLen + x; // NOTE: x is negative! - } - } - - if (dir === "horz") { // north/south - var width = cssW($T, togLen); - $T.css({ - width: width // account for borders & padding - , height: cssH($T, spacing) // ditto - , left: offset // TODO: VERIFY that toggler positions correctly for ALL values - , top: 0 - }); - // CENTER the toggler content SPAN - $T.children(".content").each(function(){ - $TC = $(this); - $TC.css("marginLeft", round((width-$TC.outerWidth())/2)); // could be negative - }); - } - else { // east/west - var height = cssH($T, togLen); - $T.css({ - height: height // account for borders & padding - , width: cssW($T, spacing) // ditto - , top: offset // POSITION the toggler - , left: 0 - }); - // CENTER the toggler content SPAN - $T.children(".content").each(function(){ - $TC = $(this); - $TC.css("marginTop", round((height-$TC.outerHeight())/2)); // could be negative - }); - } - - // remove ALL hover classes - removeHover( 0, $T ); - } - - // DONE measuring and sizing this resizer/toggler, so can be 'hidden' now - if (!state.initialized && (o.initHidden || s.noRoom)) { - $R.hide(); - if ($T) $T.hide(); - } - }); - } - - - /** - * @param {string} pane - */ -, enableClosable = function (evt_or_pane) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , $T = $Ts[pane] - , o = options[pane] - ; - if (!$T) return; - o.closable = true; - $T .bind("click."+ sID, function(evt){ evt.stopPropagation(); toggle(pane); }) - .css("visibility", "visible") - .css("cursor", "pointer") - .attr("title", state[pane].isClosed ? o.togglerTip_closed : o.togglerTip_open) // may be blank - .show(); - } - /** - * @param {string} pane - * @param {boolean=} [hide=false] - */ -, disableClosable = function (evt_or_pane, hide) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , $T = $Ts[pane] - ; - if (!$T) return; - options[pane].closable = false; - // is closable is disable, then pane MUST be open! - if (state[pane].isClosed) open(pane, false, true); - $T .unbind("."+ sID) - .css("visibility", hide ? "hidden" : "visible") // instead of hide(), which creates logic issues - .css("cursor", "default") - .attr("title", ""); - } - - - /** - * @param {string} pane - */ -, enableSlidable = function (evt_or_pane) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , $R = $Rs[pane] - ; - if (!$R || !$R.data('draggable')) return; - options[pane].slidable = true; - if (s.isClosed) - bindStartSlidingEvent(pane, true); - } - /** - * @param {string} pane - */ -, disableSlidable = function (evt_or_pane) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , $R = $Rs[pane] - ; - if (!$R) return; - options[pane].slidable = false; - if (state[pane].isSliding) - close(pane, false, true); - else { - bindStartSlidingEvent(pane, false); - $R .css("cursor", "default") - .attr("title", ""); - removeHover(null, $R[0]); // in case currently hovered - } - } - - - /** - * @param {string} pane - */ -, enableResizable = function (evt_or_pane) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , $R = $Rs[pane] - , o = options[pane] - ; - if (!$R || !$R.data('draggable')) return; - o.resizable = true; - $R.draggable("enable"); - if (!state[pane].isClosed) - $R .css("cursor", o.resizerCursor) - .attr("title", o.resizerTip); - } - /** - * @param {string} pane - */ -, disableResizable = function (evt_or_pane) { - if (!isInitialized()) return; - var pane = evtPane.call(this, evt_or_pane) - , $R = $Rs[pane] - ; - if (!$R || !$R.data('draggable')) return; - options[pane].resizable = false; - $R .draggable("disable") - .css("cursor", "default") - .attr("title", ""); - removeHover(null, $R[0]); // in case currently hovered - } - - - /** - * Move a pane from source-side (eg, west) to target-side (eg, east) - * If pane exists on target-side, move that to source-side, ie, 'swap' the panes - * - * @param {string} pane1 The pane/edge being swapped - * @param {string} pane2 ditto - */ -, swapPanes = function (evt_or_pane1, pane2) { - if (!isInitialized()) return; - var pane1 = evtPane.call(this, evt_or_pane1); - // change state.edge NOW so callbacks can know where pane is headed... - state[pane1].edge = pane2; - state[pane2].edge = pane1; - // run these even if NOT state.initialized - if (false === _runCallbacks("onswap_start", pane1) - || false === _runCallbacks("onswap_start", pane2) - ) { - state[pane1].edge = pane1; // reset - state[pane2].edge = pane2; - return; - } - - var - oPane1 = copy( pane1 ) - , oPane2 = copy( pane2 ) - , sizes = {} - ; - sizes[pane1] = oPane1 ? oPane1.state.size : 0; - sizes[pane2] = oPane2 ? oPane2.state.size : 0; - - // clear pointers & state - $Ps[pane1] = false; - $Ps[pane2] = false; - state[pane1] = {}; - state[pane2] = {}; - - // ALWAYS remove the resizer & toggler elements - if ($Ts[pane1]) $Ts[pane1].remove(); - if ($Ts[pane2]) $Ts[pane2].remove(); - if ($Rs[pane1]) $Rs[pane1].remove(); - if ($Rs[pane2]) $Rs[pane2].remove(); - $Rs[pane1] = $Rs[pane2] = $Ts[pane1] = $Ts[pane2] = false; - - // transfer element pointers and data to NEW Layout keys - move( oPane1, pane2 ); - move( oPane2, pane1 ); - - // cleanup objects - oPane1 = oPane2 = sizes = null; - - // make panes 'visible' again - if ($Ps[pane1]) $Ps[pane1].css(_c.visible); - if ($Ps[pane2]) $Ps[pane2].css(_c.visible); - - // fix any size discrepancies caused by swap - resizeAll(); - - // run these even if NOT state.initialized - _runCallbacks("onswap_end", pane1); - _runCallbacks("onswap_end", pane2); - - return; - - function copy (n) { // n = pane - var - $P = $Ps[n] - , $C = $Cs[n] - ; - return !$P ? false : { - pane: n - , P: $P ? $P[0] : false - , C: $C ? $C[0] : false - , state: $.extend(true, {}, state[n]) - , options: $.extend(true, {}, options[n]) - } - }; - - function move (oPane, pane) { - if (!oPane) return; - var - P = oPane.P - , C = oPane.C - , oldPane = oPane.pane - , c = _c[pane] - , side = c.side.toLowerCase() - , inset = "inset"+ c.side - // save pane-options that should be retained - , s = $.extend({}, state[pane]) - , o = options[pane] - // RETAIN side-specific FX Settings - more below - , fx = { resizerCursor: o.resizerCursor } - , re, size, pos - ; - $.each("fxName,fxSpeed,fxSettings".split(","), function (i, k) { - fx[k +"_open"] = o[k +"_open"]; - fx[k +"_close"] = o[k +"_close"]; - fx[k +"_size"] = o[k +"_size"]; - }); - - // update object pointers and attributes - $Ps[pane] = $(P) - .data({ - layoutPane: Instance[pane] // NEW pointer to pane-alias-object - , layoutEdge: pane - }) - .css(_c.hidden) - .css(c.cssReq) - ; - $Cs[pane] = C ? $(C) : false; - - // set options and state - options[pane] = $.extend({}, oPane.options, fx); - state[pane] = $.extend({}, oPane.state); - - // change classNames on the pane, eg: ui-layout-pane-east ==> ui-layout-pane-west - re = new RegExp(o.paneClass +"-"+ oldPane, "g"); - P.className = P.className.replace(re, o.paneClass +"-"+ pane); - - // ALWAYS regenerate the resizer & toggler elements - initHandles(pane); // create the required resizer & toggler - - // if moving to different orientation, then keep 'target' pane size - if (c.dir != _c[oldPane].dir) { - size = sizes[pane] || 0; - setSizeLimits(pane); // update pane-state - size = max(size, state[pane].minSize); - // use manualSizePane to disable autoResize - not useful after panes are swapped - manualSizePane(pane, size, true, true); // true/true = skipCallback/noAnimation - } - else // move the resizer here - $Rs[pane].css(side, sC[inset] + (state[pane].isVisible ? getPaneSize(pane) : 0)); - - - // ADD CLASSNAMES & SLIDE-BINDINGS - if (oPane.state.isVisible && !s.isVisible) - setAsOpen(pane, true); // true = skipCallback - else { - setAsClosed(pane); - bindStartSlidingEvent(pane, true); // will enable events IF option is set - } - - // DESTROY the object - oPane = null; - }; - } - - - /** - * INTERNAL method to sync pin-buttons when pane is opened or closed - * Unpinned means the pane is 'sliding' - ie, over-top of the adjacent panes - * - * @see open(), setAsOpen(), setAsClosed() - * @param {string} pane These are the params returned to callbacks by layout() - * @param {boolean} doPin True means set the pin 'down', False means 'up' - */ -, syncPinBtns = function (pane, doPin) { - if ($.layout.plugins.buttons) - $.each(state[pane].pins, function (i, selector) { - $.layout.buttons.setPinState(Instance, $(selector), pane, doPin); - }); - } - -; // END var DECLARATIONS - - /** - * Capture keys when enableCursorHotkey - toggle pane if hotkey pressed - * - * @see document.keydown() - */ - function keyDown (evt) { - if (!evt) return true; - var code = evt.keyCode; - if (code < 33) return true; // ignore special keys: ENTER, TAB, etc - - var - PANE = { - 38: "north" // Up Cursor - $.ui.keyCode.UP - , 40: "south" // Down Cursor - $.ui.keyCode.DOWN - , 37: "west" // Left Cursor - $.ui.keyCode.LEFT - , 39: "east" // Right Cursor - $.ui.keyCode.RIGHT - } - , ALT = evt.altKey // no worky! - , SHIFT = evt.shiftKey - , CTRL = evt.ctrlKey - , CURSOR = (CTRL && code >= 37 && code <= 40) - , o, k, m, pane - ; - - if (CURSOR && options[PANE[code]].enableCursorHotkey) // valid cursor-hotkey - pane = PANE[code]; - else if (CTRL || SHIFT) // check to see if this matches a custom-hotkey - $.each(_c.borderPanes, function (i, p) { // loop each pane to check its hotkey - o = options[p]; - k = o.customHotkey; - m = o.customHotkeyModifier; // if missing or invalid, treated as "CTRL+SHIFT" - if ((SHIFT && m=="SHIFT") || (CTRL && m=="CTRL") || (CTRL && SHIFT)) { // Modifier matches - if (k && code === (isNaN(k) || k <= 9 ? k.toUpperCase().charCodeAt(0) : k)) { // Key matches - pane = p; - return false; // BREAK - } - } - }); - - // validate pane - if (!pane || !$Ps[pane] || !options[pane].closable || state[pane].isHidden) - return true; - - toggle(pane); - - evt.stopPropagation(); - evt.returnValue = false; // CANCEL key - return false; - }; +, _hidePane = function (pane) { + var $P = $Ps[pane] + , o = options[pane] + , s = $P[0].style + ; + if (o.useOffscreenClose) { + if (!$P.data(_c.offscreenReset)) + $P.data(_c.offscreenReset, { left: s.left, right: s.right }); + $P.css( _c.offscreenCSS ); + } + else + $P.hide().removeData(_c.offscreenReset); + } + +, _showPane = function (pane) { + var $P = $Ps[pane] + , o = options[pane] + , off = _c.offscreenCSS + , old = $P.data(_c.offscreenReset) + , s = $P[0].style + ; + $P .show() // ALWAYS show, just in case + .removeData(_c.offscreenReset); + if (o.useOffscreenClose && old) { + if (s.left == off.left) + s.left = old.left; + if (s.right == off.right) + s.right = old.right; + } + } + + + /** + * Completely 'hides' a pane, including its spacing - as if it does not exist + * The pane is not actually 'removed' from the source, so can use 'show' to un-hide it + * + * @param {string} pane The pane being hidden, ie: north, south, east, or west + * @param {boolean=} [noAnimation=false] + */ +, hide = function (evt_or_pane, noAnimation) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + ; + if (!$P || s.isHidden) return; // pane does not exist OR is already hidden + + // onhide_start callback - will CANCEL hide if returns false + if (state.initialized && false === _runCallbacks("onhide_start", pane)) return; + + s.isSliding = false; // just in case + + // now hide the elements + if ($R) $R.hide(); // hide resizer-bar + if (!state.initialized || s.isClosed) { + s.isClosed = true; // to trigger open-animation on show() + s.isHidden = true; + s.isVisible = false; + if (!state.initialized) + _hidePane(pane); // no animation when loading page + sizeMidPanes(_c[pane].dir === "horz" ? "" : "center"); + if (state.initialized || o.triggerEventsOnLoad) + _runCallbacks("onhide_end", pane); + } + else { + s.isHiding = true; // used by onclose + close(pane, false, noAnimation); // adjust all panes to fit + } + } + + /** + * Show a hidden pane - show as 'closed' by default unless openPane = true + * + * @param {string} pane The pane being opened, ie: north, south, east, or west + * @param {boolean=} [openPane=false] + * @param {boolean=} [noAnimation=false] + * @param {boolean=} [noAlert=false] + */ +, show = function (evt_or_pane, openPane, noAnimation, noAlert) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + ; + if (!$P || !s.isHidden) return; // pane does not exist OR is not hidden + + // onshow_start callback - will CANCEL show if returns false + if (false === _runCallbacks("onshow_start", pane)) return; + + s.isSliding = false; // just in case + s.isShowing = true; // used by onopen/onclose + //s.isHidden = false; - will be set by open/close - if not cancelled + + // now show the elements + //if ($R) $R.show(); - will be shown by open/close + if (openPane === false) + close(pane, true); // true = force + else + open(pane, false, noAnimation, noAlert); // adjust all panes to fit + } + + + /** + * Toggles a pane open/closed by calling either open or close + * + * @param {string} pane The pane being toggled, ie: north, south, east, or west + * @param {boolean=} [slide=false] + */ +, toggle = function (evt_or_pane, slide) { + if (!isInitialized()) return; + var evt = evtObj(evt_or_pane) + , pane = evtPane.call(this, evt_or_pane) + , s = state[pane] + ; + if (evt) // called from to $R.dblclick OR triggerPaneEvent + evt.stopImmediatePropagation(); + if (s.isHidden) + show(pane); // will call 'open' after unhiding it + else if (s.isClosed) + open(pane, !!slide); + else + close(pane); + } + + + /** + * Utility method used during init or other auto-processes + * + * @param {string} pane The pane being closed + * @param {boolean=} [setHandles=false] + */ +, _closePane = function (pane, setHandles) { + var + $P = $Ps[pane] + , s = state[pane] + ; + _hidePane(pane); + s.isClosed = true; + s.isVisible = false; + // UNUSED: if (setHandles) setAsClosed(pane, true); // true = force + } + + /** + * Close the specified pane (animation optional), and resize all other panes as needed + * + * @param {string} pane The pane being closed, ie: north, south, east, or west + * @param {boolean=} [force=false] + * @param {boolean=} [noAnimation=false] + * @param {boolean=} [skipCallback=false] + */ +, close = function (evt_or_pane, force, noAnimation, skipCallback) { + var pane = evtPane.call(this, evt_or_pane); + // if pane has been initialized, but NOT the complete layout, close pane instantly + if (!state.initialized && $Ps[pane]) { + _closePane(pane); // INIT pane as closed + return; + } + if (!isInitialized()) return; + + var + $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , o = options[pane] + , s = state[pane] + , c = _c[pane] + , doFX, isShowing, isHiding, wasSliding; + + // QUEUE in case another action/animation is in progress + $N.queue(function( queueNext ){ + + if ( !$P + || (!o.closable && !s.isShowing && !s.isHiding) // invalid request // (!o.resizable && !o.closable) ??? + || (!force && s.isClosed && !s.isShowing) // already closed + ) return queueNext(); + + // onclose_start callback - will CANCEL hide if returns false + // SKIP if just 'showing' a hidden pane as 'closed' + var abort = !s.isShowing && false === _runCallbacks("onclose_start", pane); + + // transfer logic vars to temp vars + isShowing = s.isShowing; + isHiding = s.isHiding; + wasSliding = s.isSliding; + // now clear the logic vars (REQUIRED before aborting) + delete s.isShowing; + delete s.isHiding; + + if (abort) return queueNext(); + + doFX = !noAnimation && !s.isClosed && (o.fxName_close != "none"); + s.isMoving = true; + s.isClosed = true; + s.isVisible = false; + // update isHidden BEFORE sizing panes + if (isHiding) s.isHidden = true; + else if (isShowing) s.isHidden = false; + + if (s.isSliding) // pane is being closed, so UNBIND trigger events + bindStopSlidingEvents(pane, false); // will set isSliding=false + else // resize panes adjacent to this one + sizeMidPanes(_c[pane].dir === "horz" ? "" : "center", false); // false = NOT skipCallback + + // if this pane has a resizer bar, move it NOW - before animation + setAsClosed(pane); + + // CLOSE THE PANE + if (doFX) { // animate the close + // mask panes with objects + var masks = "center"+ (c.dir=="horz" ? ",west,east" : ""); + showMasks( masks, true ); // true = ONLY mask panes with maskObjects=true + lockPaneForFX(pane, true); // need to set left/top so animation will work + $P.hide( o.fxName_close, o.fxSettings_close, o.fxSpeed_close, function () { + lockPaneForFX(pane, false); // undo + if (s.isClosed) close_2(); + queueNext(); + }); + } + else { // hide the pane without animation + _hidePane(pane); + close_2(); + queueNext(); + }; + }); + + // SUBROUTINE + function close_2 () { + s.isMoving = false; + bindStartSlidingEvent(pane, true); // will enable if o.slidable = true + + // if opposite-pane was autoClosed, see if it can be autoOpened now + var altPane = _c.oppositeEdge[pane]; + if (state[ altPane ].noRoom) { + setSizeLimits( altPane ); + makePaneFit( altPane ); + } + + // hide any masks shown while closing + hideMasks(); + + if (!skipCallback && (state.initialized || o.triggerEventsOnLoad)) { + // onclose callback - UNLESS just 'showing' a hidden pane as 'closed' + if (!isShowing) _runCallbacks("onclose_end", pane); + // onhide OR onshow callback + if (isShowing) _runCallbacks("onshow_end", pane); + if (isHiding) _runCallbacks("onhide_end", pane); + } + } + } + + /** + * @param {string} pane The pane just closed, ie: north, south, east, or west + */ +, setAsClosed = function (pane) { + var + $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , o = options[pane] + , s = state[pane] + , side = _c[pane].side.toLowerCase() + , inset = "inset"+ _c[pane].side + , rClass = o.resizerClass + , tClass = o.togglerClass + , _pane = "-"+ pane // used for classNames + , _open = "-open" + , _sliding= "-sliding" + , _closed = "-closed" + ; + $R + .css(side, sC[inset]) // move the resizer + .removeClass( rClass+_open +" "+ rClass+_pane+_open ) + .removeClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) + .addClass( rClass+_closed +" "+ rClass+_pane+_closed ) + .unbind("dblclick."+ sID) + ; + // DISABLE 'resizing' when closed - do this BEFORE bindStartSlidingEvent? + if (o.resizable && $.layout.plugins.draggable) + $R + .draggable("disable") + .removeClass("ui-state-disabled") // do NOT apply disabled styling - not suitable here + .css("cursor", "default") + .attr("title","") + ; + + // if pane has a toggler button, adjust that too + if ($T) { + $T + .removeClass( tClass+_open +" "+ tClass+_pane+_open ) + .addClass( tClass+_closed +" "+ tClass+_pane+_closed ) + .attr("title", o.togglerTip_closed) // may be blank + ; + // toggler-content - if exists + $T.children(".content-open").hide(); + $T.children(".content-closed").css("display","block"); + } + + // sync any 'pin buttons' + syncPinBtns(pane, false); + + if (state.initialized) { + // resize 'length' and position togglers for adjacent panes + sizeHandles(); + } + } + + /** + * Open the specified pane (animation optional), and resize all other panes as needed + * + * @param {string} pane The pane being opened, ie: north, south, east, or west + * @param {boolean=} [slide=false] + * @param {boolean=} [noAnimation=false] + * @param {boolean=} [noAlert=false] + */ +, open = function (evt_or_pane, slide, noAnimation, noAlert) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , o = options[pane] + , s = state[pane] + , c = _c[pane] + , doFX, isShowing + ; + // QUEUE in case another action/animation is in progress + $N.queue(function( queueNext ){ + + if ( !$P + || (!o.resizable && !o.closable && !s.isShowing) // invalid request + || (s.isVisible && !s.isSliding) // already open + ) return queueNext(); + + // pane can ALSO be unhidden by just calling show(), so handle this scenario + if (s.isHidden && !s.isShowing) { + queueNext(); // call before show() because it needs the queue free + show(pane, true); + return; + } + + if (o.autoResize && s.size != o.size) // resize pane to original size set in options + sizePane(pane, o.size, true, true, true); // true=skipCallback/forceResize/noAnimation + else + // make sure there is enough space available to open the pane + setSizeLimits(pane, slide); + + // onopen_start callback - will CANCEL open if returns false + var cbReturn = _runCallbacks("onopen_start", pane); + + if (cbReturn === "abort") + return queueNext(); + + // update pane-state again in case options were changed in onopen_start + if (cbReturn !== "NC") // NC = "No Callback" + setSizeLimits(pane, slide); + + if (s.minSize > s.maxSize) { // INSUFFICIENT ROOM FOR PANE TO OPEN! + syncPinBtns(pane, false); // make sure pin-buttons are reset + if (!noAlert && o.noRoomToOpenTip) + alert(o.noRoomToOpenTip); + return queueNext(); // ABORT + } + + if (slide) // START Sliding - will set isSliding=true + bindStopSlidingEvents(pane, true); // BIND trigger events to close sliding-pane + else if (s.isSliding) // PIN PANE (stop sliding) - open pane 'normally' instead + bindStopSlidingEvents(pane, false); // UNBIND trigger events - will set isSliding=false + else if (o.slidable) + bindStartSlidingEvent(pane, false); // UNBIND trigger events + + s.noRoom = false; // will be reset by makePaneFit if 'noRoom' + makePaneFit(pane); + + // transfer logic var to temp var + isShowing = s.isShowing; + // now clear the logic var + delete s.isShowing; + + doFX = !noAnimation && s.isClosed && (o.fxName_open != "none"); + s.isMoving = true; + s.isVisible = true; + s.isClosed = false; + // update isHidden BEFORE sizing panes - WHY??? Old? + if (isShowing) s.isHidden = false; + + if (doFX) { // ANIMATE + // mask panes with objects + var masks = "center"+ (c.dir=="horz" ? ",west,east" : ""); + if (s.isSliding) masks += ","+ _c.oppositeEdge[pane]; + showMasks( masks, true ); // true = ONLY mask panes with maskObjects=true + lockPaneForFX(pane, true); // need to set left/top so animation will work + $P.show( o.fxName_open, o.fxSettings_open, o.fxSpeed_open, function() { + lockPaneForFX(pane, false); // undo + if (s.isVisible) open_2(); // continue + queueNext(); + }); + } + else { // no animation + _showPane(pane);// just show pane and... + open_2(); // continue + queueNext(); + }; + }); + + // SUBROUTINE + function open_2 () { + s.isMoving = false; + + // cure iframe display issues + _fixIframe(pane); + + // NOTE: if isSliding, then other panes are NOT 'resized' + if (!s.isSliding) { // resize all panes adjacent to this one + hideMasks(); // remove any masks shown while opening + sizeMidPanes(_c[pane].dir=="vert" ? "center" : "", false); // false = NOT skipCallback + } + + // set classes, position handles and execute callbacks... + setAsOpen(pane); + }; + + } + + /** + * @param {string} pane The pane just opened, ie: north, south, east, or west + * @param {boolean=} [skipCallback=false] + */ +, setAsOpen = function (pane, skipCallback) { + var + $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , o = options[pane] + , s = state[pane] + , side = _c[pane].side.toLowerCase() + , inset = "inset"+ _c[pane].side + , rClass = o.resizerClass + , tClass = o.togglerClass + , _pane = "-"+ pane // used for classNames + , _open = "-open" + , _closed = "-closed" + , _sliding= "-sliding" + ; + $R + .css(side, sC[inset] + getPaneSize(pane)) // move the resizer + .removeClass( rClass+_closed +" "+ rClass+_pane+_closed ) + .addClass( rClass+_open +" "+ rClass+_pane+_open ) + ; + if (s.isSliding) + $R.addClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) + else // in case 'was sliding' + $R.removeClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) + + if (o.resizerDblClickToggle) + $R.bind("dblclick", toggle ); + removeHover( 0, $R ); // remove hover classes + if (o.resizable && $.layout.plugins.draggable) + $R .draggable("enable") + .css("cursor", o.resizerCursor) + .attr("title", o.resizerTip); + else if (!s.isSliding) + $R.css("cursor", "default"); // n-resize, s-resize, etc + + // if pane also has a toggler button, adjust that too + if ($T) { + $T .removeClass( tClass+_closed +" "+ tClass+_pane+_closed ) + .addClass( tClass+_open +" "+ tClass+_pane+_open ) + .attr("title", o.togglerTip_open); // may be blank + removeHover( 0, $T ); // remove hover classes + // toggler-content - if exists + $T.children(".content-closed").hide(); + $T.children(".content-open").css("display","block"); + } + + // sync any 'pin buttons' + syncPinBtns(pane, !s.isSliding); + + // update pane-state dimensions - BEFORE resizing content + $.extend(s, elDims($P)); + + if (state.initialized) { + // resize resizer & toggler sizes for all panes + sizeHandles(); + // resize content every time pane opens - to be sure + sizeContent(pane, true); // true = remeasure headers/footers, even if 'pane.isMoving' + } + + if (!skipCallback && (state.initialized || o.triggerEventsOnLoad) && $P.is(":visible")) { + // onopen callback + _runCallbacks("onopen_end", pane); + // onshow callback - TODO: should this be here? + if (s.isShowing) _runCallbacks("onshow_end", pane); + + // ALSO call onresize because layout-size *may* have changed while pane was closed + if (state.initialized) + _runCallbacks("onresize_end", pane); + } + + // TODO: Somehow sizePane("north") is being called after this point??? + } + + + /** + * slideOpen / slideClose / slideToggle + * + * Pass-though methods for sliding + */ +, slideOpen = function (evt_or_pane) { + if (!isInitialized()) return; + var evt = evtObj(evt_or_pane) + , pane = evtPane.call(this, evt_or_pane) + , s = state[pane] + , delay = options[pane].slideDelay_open + ; + // prevent event from triggering on NEW resizer binding created below + if (evt) evt.stopImmediatePropagation(); + + if (s.isClosed && evt && evt.type === "mouseenter" && delay > 0) + // trigger = mouseenter - use a delay + timer.set(pane+"_openSlider", open_NOW, delay); + else + open_NOW(); // will unbind events if is already open + + /** + * SUBROUTINE for timed open + */ + function open_NOW () { + if (!s.isClosed) // skip if no longer closed! + bindStopSlidingEvents(pane, true); // BIND trigger events to close sliding-pane + else if (!s.isMoving) + open(pane, true); // true = slide - open() will handle binding + }; + } + +, slideClose = function (evt_or_pane) { + if (!isInitialized()) return; + var evt = evtObj(evt_or_pane) + , pane = evtPane.call(this, evt_or_pane) + , o = options[pane] + , s = state[pane] + , delay = s.isMoving ? 1000 : 300 // MINIMUM delay - option may override + ; + if (s.isClosed || s.isResizing) + return; // skip if already closed OR in process of resizing + else if (o.slideTrigger_close === "click") + close_NOW(); // close immediately onClick + else if (o.preventQuickSlideClose && s.isMoving) + return; // handle Chrome quick-close on slide-open + else if (o.preventPrematureSlideClose && evt && $.layout.isMouseOverElem(evt, $Ps[pane])) + return; // handle incorrect mouseleave trigger, like when over a SELECT-list in IE + else if (evt) // trigger = mouseleave - use a delay + // 1 sec delay if 'opening', else .3 sec + timer.set(pane+"_closeSlider", close_NOW, max(o.slideDelay_close, delay)); + else // called programically + close_NOW(); + + /** + * SUBROUTINE for timed close + */ + function close_NOW () { + if (s.isClosed) // skip 'close' if already closed! + bindStopSlidingEvents(pane, false); // UNBIND trigger events - TODO: is this needed here? + else if (!s.isMoving) + close(pane); // close will handle unbinding + }; + } + + /** + * @param {string} pane The pane being opened, ie: north, south, east, or west + */ +, slideToggle = function (evt_or_pane) { + var pane = evtPane.call(this, evt_or_pane); + toggle(pane, true); + } + + + /** + * Must set left/top on East/South panes so animation will work properly + * + * @param {string} pane The pane to lock, 'east' or 'south' - any other is ignored! + * @param {boolean} doLock true = set left/top, false = remove + */ +, lockPaneForFX = function (pane, doLock) { + var $P = $Ps[pane] + , s = state[pane] + , o = options[pane] + , z = options.zIndexes + ; + if (doLock) { + $P.css({ zIndex: z.pane_animate }); // overlay all elements during animation + if (pane=="south") + $P.css({ top: sC.insetTop + sC.innerHeight - $P.outerHeight() }); + else if (pane=="east") + $P.css({ left: sC.insetLeft + sC.innerWidth - $P.outerWidth() }); + } + else { // animation DONE - RESET CSS + // TODO: see if this can be deleted. It causes a quick-close when sliding in Chrome + $P.css({ zIndex: (s.isSliding ? z.pane_sliding : z.pane_normal) }); + if (pane=="south") + $P.css({ top: "auto" }); + // if pane is positioned 'off-screen', then DO NOT screw with it! + else if (pane=="east" && !$P.css("left").match(/\-99999/)) + $P.css({ left: "auto" }); + // fix anti-aliasing in IE - only needed for animations that change opacity + if (browser.msie && o.fxOpacityFix && o.fxName_open != "slide" && $P.css("filter") && $P.css("opacity") == 1) + $P[0].style.removeAttribute('filter'); + } + } + + + /** + * Toggle sliding functionality of a specific pane on/off by adding removing 'slide open' trigger + * + * @see open(), close() + * @param {string} pane The pane to enable/disable, 'north', 'south', etc. + * @param {boolean} enable Enable or Disable sliding? + */ +, bindStartSlidingEvent = function (pane, enable) { + var o = options[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , evtName = o.slideTrigger_open.toLowerCase() + ; + if (!$R || (enable && !o.slidable)) return; + + // make sure we have a valid event + if (evtName.match(/mouseover/)) + evtName = o.slideTrigger_open = "mouseenter"; + else if (!evtName.match(/click|dblclick|mouseenter/)) + evtName = o.slideTrigger_open = "click"; + + $R + // add or remove event + [enable ? "bind" : "unbind"](evtName +'.'+ sID, slideOpen) + // set the appropriate cursor & title/tip + .css("cursor", enable ? o.sliderCursor : "default") + .attr("title", enable ? o.sliderTip : "") + ; + } + + /** + * Add or remove 'mouseleave' events to 'slide close' when pane is 'sliding' open or closed + * Also increases zIndex when pane is sliding open + * See bindStartSlidingEvent for code to control 'slide open' + * + * @see slideOpen(), slideClose() + * @param {string} pane The pane to process, 'north', 'south', etc. + * @param {boolean} enable Enable or Disable events? + */ +, bindStopSlidingEvents = function (pane, enable) { + var o = options[pane] + , s = state[pane] + , c = _c[pane] + , z = options.zIndexes + , evtName = o.slideTrigger_close.toLowerCase() + , action = (enable ? "bind" : "unbind") + , $P = $Ps[pane] + , $R = $Rs[pane] + ; + s.isSliding = enable; // logic + timer.clear(pane+"_closeSlider"); // just in case + + // remove 'slideOpen' event from resizer + // ALSO will raise the zIndex of the pane & resizer + if (enable) bindStartSlidingEvent(pane, false); + + // RE/SET zIndex - increases when pane is sliding-open, resets to normal when not + $P.css("zIndex", enable ? z.pane_sliding : z.pane_normal); + $R.css("zIndex", enable ? z.pane_sliding+2 : z.resizer_normal); // NOTE: mask = pane_sliding+1 + + // make sure we have a valid event + if (!evtName.match(/click|mouseleave/)) + evtName = o.slideTrigger_close = "mouseleave"; // also catches 'mouseout' + + // add/remove slide triggers + $R[action](evtName, slideClose); // base event on resize + // need extra events for mouseleave + if (evtName === "mouseleave") { + // also close on pane.mouseleave + $P[action]("mouseleave."+ sID, slideClose); + // cancel timer when mouse moves between 'pane' and 'resizer' + $R[action]("mouseenter."+ sID, cancelMouseOut); + $P[action]("mouseenter."+ sID, cancelMouseOut); + } + + if (!enable) + timer.clear(pane+"_closeSlider"); + else if (evtName === "click" && !o.resizable) { + // IF pane is not resizable (which already has a cursor and tip) + // then set the a cursor & title/tip on resizer when sliding + $R.css("cursor", enable ? o.sliderCursor : "default"); + $R.attr("title", enable ? o.togglerTip_open : ""); // use Toggler-tip, eg: "Close Pane" + } + + // SUBROUTINE for mouseleave timer clearing + function cancelMouseOut (evt) { + timer.clear(pane+"_closeSlider"); + evt.stopPropagation(); + } + } + + + /** + * Hides/closes a pane if there is insufficient room - reverses this when there is room again + * MUST have already called setSizeLimits() before calling this method + * + * @param {string} pane The pane being resized + * @param {boolean=} [isOpening=false] Called from onOpen? + * @param {boolean=} [skipCallback=false] Should the onresize callback be run? + * @param {boolean=} [force=false] + */ +, makePaneFit = function (pane, isOpening, skipCallback, force) { + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , isSidePane = c.dir==="vert" + , hasRoom = false + ; + // special handling for center & east/west panes + if (pane === "center" || (isSidePane && s.noVerticalRoom)) { + // see if there is enough room to display the pane + // ERROR: hasRoom = s.minHeight <= s.maxHeight && (isSidePane || s.minWidth <= s.maxWidth); + hasRoom = (s.maxHeight >= 0); + if (hasRoom && s.noRoom) { // previously hidden due to noRoom, so show now + _showPane(pane); + if ($R) $R.show(); + s.isVisible = true; + s.noRoom = false; + if (isSidePane) s.noVerticalRoom = false; + _fixIframe(pane); + } + else if (!hasRoom && !s.noRoom) { // not currently hidden, so hide now + _hidePane(pane); + if ($R) $R.hide(); + s.isVisible = false; + s.noRoom = true; + } + } + + // see if there is enough room to fit the border-pane + if (pane === "center") { + // ignore center in this block + } + else if (s.minSize <= s.maxSize) { // pane CAN fit + hasRoom = true; + if (s.size > s.maxSize) // pane is too big - shrink it + sizePane(pane, s.maxSize, skipCallback, force, true); // true = noAnimation + else if (s.size < s.minSize) // pane is too small - enlarge it + sizePane(pane, s.minSize, skipCallback, force, true); + // need s.isVisible because new pseudoClose method keeps pane visible, but off-screen + else if ($R && s.isVisible && $P.is(":visible")) { + // make sure resizer-bar is positioned correctly + // handles situation where nested layout was 'hidden' when initialized + var side = c.side.toLowerCase() + , pos = s.size + sC["inset"+ c.side] + ; + if ($.layout.cssNum($R, side) != pos) $R.css( side, pos ); + } + + // if was previously hidden due to noRoom, then RESET because NOW there is room + if (s.noRoom) { + // s.noRoom state will be set by open or show + if (s.wasOpen && o.closable) { + if (o.autoReopen) + open(pane, false, true, true); // true = noAnimation, true = noAlert + else // leave the pane closed, so just update state + s.noRoom = false; + } + else + show(pane, s.wasOpen, true, true); // true = noAnimation, true = noAlert + } + } + else { // !hasRoom - pane CANNOT fit + if (!s.noRoom) { // pane not set as noRoom yet, so hide or close it now... + s.noRoom = true; // update state + s.wasOpen = !s.isClosed && !s.isSliding; + if (s.isClosed){} // SKIP + else if (o.closable) // 'close' if possible + close(pane, true, true); // true = force, true = noAnimation + else // 'hide' pane if cannot just be closed + hide(pane, true); // true = noAnimation + } + } + } + + + /** + * sizePane / manualSizePane + * sizePane is called only by internal methods whenever a pane needs to be resized + * manualSizePane is an exposed flow-through method allowing extra code when pane is 'manually resized' + * + * @param {string} pane The pane being resized + * @param {number} size The *desired* new size for this pane - will be validated + * @param {boolean=} [skipCallback=false] Should the onresize callback be run? + * @param {boolean=} [noAnimation=false] + */ +, manualSizePane = function (evt_or_pane, size, skipCallback, noAnimation) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , o = options[pane] + , s = state[pane] + // if resizing callbacks have been delayed and resizing is now DONE, force resizing to complete... + , forceResize = o.livePaneResizing && !s.isResizing + ; + // ANY call to manualSizePane disables autoResize - ie, percentage sizing + o.autoResize = false; + // flow-through... + sizePane(pane, size, skipCallback, forceResize, noAnimation); // will animate resize if option enabled + } + + /** + * @param {string} pane The pane being resized + * @param {number} size The *desired* new size for this pane - will be validated + * @param {boolean=} [skipCallback=false] Should the onresize callback be run? + * @param {boolean=} [force=false] Force resizing even if does not seem necessary + * @param {boolean=} [noAnimation=false] + */ +, sizePane = function (evt_or_pane, size, skipCallback, force, noAnimation) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) // probably NEVER called from event? + , o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , side = _c[pane].side.toLowerCase() + , dimName = _c[pane].sizeType.toLowerCase() + , inset = "inset"+ _c[pane].side + , skipResizeWhileDragging = s.isResizing && !o.triggerEventsDuringLiveResize + , doFX = noAnimation !== true && o.animatePaneSizing + , oldSize, newSize + ; + // QUEUE in case another action/animation is in progress + $N.queue(function( queueNext ){ + // calculate 'current' min/max sizes + setSizeLimits(pane); // update pane-state + oldSize = s.size; + size = _parseSize(pane, size); // handle percentages & auto + size = max(size, _parseSize(pane, o.minSize)); + size = min(size, s.maxSize); + if (size < s.minSize) { // not enough room for pane! + queueNext(); // call before makePaneFit() because it needs the queue free + makePaneFit(pane, false, skipCallback); // will hide or close pane + return; + } + + // IF newSize is same as oldSize, then nothing to do - abort + if (!force && size === oldSize) + return queueNext(); + + // onresize_start callback CANNOT cancel resizing because this would break the layout! + if (!skipCallback && state.initialized && s.isVisible) + _runCallbacks("onresize_start", pane); + + // resize the pane, and make sure its visible + newSize = cssSize(pane, size); + + if (doFX && $P.is(":visible")) { // ANIMATE + var fx = $.layout.effects.size[pane] || $.layout.effects.size.all + , easing = o.fxSettings_size.easing || fx.easing + , z = options.zIndexes + , props = {}; + props[ dimName ] = newSize +'px'; + s.isMoving = true; + // overlay all elements during animation + $P.css({ zIndex: z.pane_animate }) + .show().animate( props, o.fxSpeed_size, easing, function(){ + // reset zIndex after animation + $P.css({ zIndex: (s.isSliding ? z.pane_sliding : z.pane_normal) }); + s.isMoving = false; + sizePane_2(); // continue + queueNext(); + }); + } + else { // no animation + $P.css( dimName, newSize ); // resize pane + // if pane is visible, then + if ($P.is(":visible")) + sizePane_2(); // continue + else { + // pane is NOT VISIBLE, so just update state data... + // when pane is *next opened*, it will have the new size + s.size = size; // update state.size + $.extend(s, elDims($P)); // update state dimensions + } + queueNext(); + }; + + }); + + // SUBROUTINE + function sizePane_2 () { + /* Panes are sometimes not sized precisely in some browsers!? + * This code will resize the pane up to 3 times to nudge the pane to the correct size + */ + var actual = dimName==='width' ? $P.outerWidth() : $P.outerHeight() + , tries = [{ + pane: pane + , count: 1 + , target: size + , actual: actual + , correct: (size === actual) + , attempt: size + , cssSize: newSize + }] + , lastTry = tries[0] + , msg = 'Inaccurate size after resizing the '+ pane +'-pane.' + ; + while ( !lastTry.correct ) { + thisTry = { pane: pane, count: lastTry.count+1, target: size }; + + if (lastTry.actual > size) + thisTry.attempt = max(0, lastTry.attempt - (lastTry.actual - size)); + else // lastTry.actual < size + thisTry.attempt = max(0, lastTry.attempt + (size - lastTry.actual)); + + thisTry.cssSize = cssSize(pane, thisTry.attempt); + $P.css( dimName, thisTry.cssSize ); + + thisTry.actual = dimName=='width' ? $P.outerWidth() : $P.outerHeight(); + thisTry.correct = (size === thisTry.actual); + + // if showDebugMessages, log attempts and alert the user of this *non-fatal error* + if (options.showDebugMessages) { + if ( tries.length === 1) { + _log(msg, false); + _log(lastTry, false); + } + _log(thisTry, false); + } + + // after 4 tries, is as close as its gonna get! + if (tries.length > 3) break; + + tries.push( thisTry ); + lastTry = tries[ tries.length - 1 ]; + } + // END TESTING CODE + + // update pane-state dimensions + s.size = size; + $.extend(s, elDims($P)); + + if (s.isVisible && $P.is(":visible")) { + // reposition the resizer-bar + if ($R) $R.css( side, size + sC[inset] ); + // resize the content-div + sizeContent(pane); + } + + if (!skipCallback && !skipResizeWhileDragging && state.initialized && s.isVisible) + _runCallbacks("onresize_end", pane); + + // resize all the adjacent panes, and adjust their toggler buttons + // when skipCallback passed, it means the controlling method will handle 'other panes' + if (!skipCallback) { + // also no callback if live-resize is in progress and NOT triggerEventsDuringLiveResize + if (!s.isSliding) sizeMidPanes(_c[pane].dir=="horz" ? "" : "center", skipResizeWhileDragging, force); + sizeHandles(); + } + + // if opposite-pane was autoClosed, see if it can be autoOpened now + var altPane = _c.oppositeEdge[pane]; + if (size < oldSize && state[ altPane ].noRoom) { + setSizeLimits( altPane ); + makePaneFit( altPane, false, skipCallback ); + } + + // DEBUG - ALERT user/developer so they know there was a sizing problem + if (options.showDebugMessages && tries.length > 1) + _log(msg +'\nSee the Error Console for details.', true); + } + } + + /** + * @see initPanes(), sizePane(), resizeAll(), open(), close(), hide() + * @param {string} panes The pane(s) being resized, comma-delmited string + * @param {boolean=} [skipCallback=false] Should the onresize callback be run? + * @param {boolean=} [force=false] + */ +, sizeMidPanes = function (panes, skipCallback, force) { + panes = (panes ? panes : "east,west,center").split(","); + + $.each(panes, function (i, pane) { + if (!$Ps[pane]) return; // NO PANE - skip + var + o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , isCenter= (pane=="center") + , hasRoom = true + , CSS = {} + , newCenter = calcNewCenterPaneDims() + ; + // update pane-state dimensions + $.extend(s, elDims($P)); + + if (pane === "center") { + if (!force && s.isVisible && newCenter.width === s.outerWidth && newCenter.height === s.outerHeight) + return true; // SKIP - pane already the correct size + // set state for makePaneFit() logic + $.extend(s, cssMinDims(pane), { + maxWidth: newCenter.width + , maxHeight: newCenter.height + }); + CSS = newCenter; + // convert OUTER width/height to CSS width/height + CSS.width = cssW($P, CSS.width); + // NEW - allow pane to extend 'below' visible area rather than hide it + CSS.height = cssH($P, CSS.height); + hasRoom = CSS.width >= 0 && CSS.height >= 0; // height >= 0 = ALWAYS TRUE NOW + // during layout init, try to shrink east/west panes to make room for center + if (!state.initialized && o.minWidth > s.outerWidth) { + var + reqPx = o.minWidth - s.outerWidth + , minE = options.east.minSize || 0 + , minW = options.west.minSize || 0 + , sizeE = state.east.size + , sizeW = state.west.size + , newE = sizeE + , newW = sizeW + ; + if (reqPx > 0 && state.east.isVisible && sizeE > minE) { + newE = max( sizeE-minE, sizeE-reqPx ); + reqPx -= sizeE-newE; + } + if (reqPx > 0 && state.west.isVisible && sizeW > minW) { + newW = max( sizeW-minW, sizeW-reqPx ); + reqPx -= sizeW-newW; + } + // IF we found enough extra space, then resize the border panes as calculated + if (reqPx === 0) { + if (sizeE != minE) + sizePane('east', newE, true, force, true); // true = skipCallback/noAnimation - initPanes will handle when done + if (sizeW != minW) + sizePane('west', newW, true, force, true); + // now start over! + sizeMidPanes('center', skipCallback, force); + return; // abort this loop + } + } + } + else { // for east and west, set only the height, which is same as center height + // set state.min/maxWidth/Height for makePaneFit() logic + if (s.isVisible && !s.noVerticalRoom) + $.extend(s, elDims($P), cssMinDims(pane)) + if (!force && !s.noVerticalRoom && newCenter.height === s.outerHeight) + return true; // SKIP - pane already the correct size + // east/west have same top, bottom & height as center + CSS.top = newCenter.top; + CSS.bottom = newCenter.bottom; + // NEW - allow pane to extend 'below' visible area rather than hide it + CSS.height = cssH($P, newCenter.height); + s.maxHeight = CSS.height; + hasRoom = (s.maxHeight >= 0); // ALWAYS TRUE NOW + if (!hasRoom) s.noVerticalRoom = true; // makePaneFit() logic + } + + if (hasRoom) { + // resizeAll passes skipCallback because it triggers callbacks after ALL panes are resized + if (!skipCallback && state.initialized) + _runCallbacks("onresize_start", pane); + + $P.css(CSS); // apply the CSS to pane + sizeHandles(pane); // also update resizer length + if (s.noRoom && !s.isClosed && !s.isHidden) + makePaneFit(pane); // will re-open/show auto-closed/hidden pane + if (s.isVisible) { + $.extend(s, elDims($P)); // update pane dimensions + if (state.initialized) sizeContent(pane); // also resize the contents, if exists + } + } + else if (!s.noRoom && s.isVisible) // no room for pane + makePaneFit(pane); // will hide or close pane + + if (!s.isVisible) + return true; // DONE - next pane + + /* + * Extra CSS for IE6 or IE7 in Quirks-mode - add 'width' to NORTH/SOUTH panes + * Normally these panes have only 'left' & 'right' positions so pane auto-sizes + * ALSO required when pane is an IFRAME because will NOT default to 'full width' + */ + if (pane === "center") { // finished processing midPanes + var b = $.layout.browser; + var fix = b.isIE6 || (b.msie && !$.support.boxModel); + if ($Ps.north && (fix || state.north.tagName=="IFRAME")) + $Ps.north.css("width", cssW($Ps.north, sC.innerWidth)); + if ($Ps.south && (fix || state.south.tagName=="IFRAME")) + $Ps.south.css("width", cssW($Ps.south, sC.innerWidth)); + } + + // resizeAll passes skipCallback because it triggers callbacks after ALL panes are resized + if (!skipCallback && state.initialized) + _runCallbacks("onresize_end", pane); + }); + } + + + /** + * @see window.onresize(), callbacks or custom code + */ +, resizeAll = function () { + if (!state.initialized) { + _initLayoutElements(); + return; // no need to resize since we just initialized! + } + var oldW = sC.innerWidth + , oldH = sC.innerHeight + ; + // cannot size layout when 'container' is hidden or collapsed + if (!$N.is(":visible:") ) return; + $.extend( state.container, elDims( $N ) ); // UPDATE container dimensions + if (!sC.outerHeight) return; + + // onresizeall_start will CANCEL resizing if returns false + // state.container has already been set, so user can access this info for calcuations + if (false === _runCallbacks("onresizeall_start")) return false; + + var // see if container is now 'smaller' than before + shrunkH = (sC.innerHeight < oldH) + , shrunkW = (sC.innerWidth < oldW) + , $P, o, s, dir + ; + // NOTE special order for sizing: S-N-E-W + $.each(["south","north","east","west"], function (i, pane) { + if (!$Ps[pane]) return; // no pane - SKIP + s = state[pane]; + o = options[pane]; + dir = _c[pane].dir; + + if (o.autoResize && s.size != o.size) // resize pane to original size set in options + sizePane(pane, o.size, true, true, true); // true=skipCallback/forceResize/noAnimation + else { + setSizeLimits(pane); + makePaneFit(pane, false, true, true); // true=skipCallback/forceResize + } + }); + + sizeMidPanes("", true, true); // true=skipCallback, true=forceResize + sizeHandles(); // reposition the toggler elements + + // trigger all individual pane callbacks AFTER layout has finished resizing + o = options; // reuse alias + $.each(_c.allPanes, function (i, pane) { + $P = $Ps[pane]; + if (!$P) return; // SKIP + if (state[pane].isVisible) // undefined for non-existent panes + _runCallbacks("onresize_end", pane); // callback - if exists + }); + + _runCallbacks("onresizeall_end"); + //_triggerLayoutEvent(pane, 'resizeall'); + } + + /** + * Whenever a pane resizes or opens that has a nested layout, trigger resizeAll + * + * @param {string} pane The pane just resized or opened + */ +, resizeChildLayout = function (evt_or_pane) { + var pane = evtPane.call(this, evt_or_pane); + if (!options[pane].resizeChildLayout) return; + var $P = $Ps[pane] + , $C = $Cs[pane] + , d = "layout" + , P = Instance[pane] + , L = children[pane] + ; + // user may have manually set EITHER instance pointer, so handle that + if (P.child && !L) { + // have to reverse the pointers! + var el = P.child.container; + L = children[pane] = (el ? el.data(d) : 0) || null; // set pointer _directly_ to layout instance + } + + // if a layout-pointer exists, see if child has been destroyed + if (L && L.destroyed) + L = children[pane] = null; // clear child pointers + // no child layout pointer is set - see if there is a child layout NOW + if (!L) L = children[pane] = $P.data(d) || ($C ? $C.data(d) : 0) || null; // set/update child pointers + + // ALWAYS refresh the pane.child alias + P.child = children[pane]; + + if (L) L.resizeAll(); + } + + + /** + * IF pane has a content-div, then resize all elements inside pane to fit pane-height + * + * @param {string=} [panes=""] The pane(s) being resized + * @param {boolean=} [remeasure=false] Should the content (header/footer) be remeasured? + */ +, sizeContent = function (evt_or_panes, remeasure) { + if (!isInitialized()) return; + + var panes = evtPane.call(this, evt_or_panes); + panes = panes ? panes.split(",") : _c.allPanes; + + $.each(panes, function (idx, pane) { + var + $P = $Ps[pane] + , $C = $Cs[pane] + , o = options[pane] + , s = state[pane] + , m = s.content // m = measurements + ; + if (!$P || !$C || !$P.is(":visible")) return true; // NOT VISIBLE - skip + + // if content-element was REMOVED, update OR remove the pointer + if (!$C.length) { + initContent(pane, false); // false = do NOT sizeContent() - already there! + if (!$C) return; // no replacement element found - pointer have been removed + } + + // onsizecontent_start will CANCEL resizing if returns false + if (false === _runCallbacks("onsizecontent_start", pane)) return; + + // skip re-measuring offsets if live-resizing + if ((!s.isMoving && !s.isResizing) || o.liveContentResizing || remeasure || m.top == undefined) { + _measure(); + // if any footers are below pane-bottom, they may not measure correctly, + // so allow pane overflow and re-measure + if (m.hiddenFooters > 0 && $P.css("overflow") === "hidden") { + $P.css("overflow", "visible"); + _measure(); // remeasure while overflowing + $P.css("overflow", "hidden"); + } + } + // NOTE: spaceAbove/Below *includes* the pane paddingTop/Bottom, but not pane.borders + var newH = s.innerHeight - (m.spaceAbove - s.css.paddingTop) - (m.spaceBelow - s.css.paddingBottom); + + if (!$C.is(":visible") || m.height != newH) { + // size the Content element to fit new pane-size - will autoHide if not enough room + setOuterHeight($C, newH, true); // true=autoHide + m.height = newH; // save new height + }; + + if (state.initialized) + _runCallbacks("onsizecontent_end", pane); + + function _below ($E) { + return max(s.css.paddingBottom, (parseInt($E.css("marginBottom"), 10) || 0)); + }; + + function _measure () { + var + ignore = options[pane].contentIgnoreSelector + , $Fs = $C.nextAll().not(ignore || ':lt(0)') // not :lt(0) = ALL + , $Fs_vis = $Fs.filter(':visible') + , $F = $Fs_vis.filter(':last') + ; + m = { + top: $C[0].offsetTop + , height: $C.outerHeight() + , numFooters: $Fs.length + , hiddenFooters: $Fs.length - $Fs_vis.length + , spaceBelow: 0 // correct if no content footer ($E) + } + m.spaceAbove = m.top; // just for state - not used in calc + m.bottom = m.top + m.height; + if ($F.length) + //spaceBelow = (LastFooter.top + LastFooter.height) [footerBottom] - Content.bottom + max(LastFooter.marginBottom, pane.paddingBotom) + m.spaceBelow = ($F[0].offsetTop + $F.outerHeight()) - m.bottom + _below($F); + else // no footer - check marginBottom on Content element itself + m.spaceBelow = _below($C); + }; + }); + } + + + /** + * Called every time a pane is opened, closed, or resized to slide the togglers to 'center' and adjust their length if necessary + * + * @see initHandles(), open(), close(), resizeAll() + * @param {string=} [panes=""] The pane(s) being resized + */ +, sizeHandles = function (evt_or_panes) { + var panes = evtPane.call(this, evt_or_panes) + panes = panes ? panes.split(",") : _c.borderPanes; + + $.each(panes, function (i, pane) { + var + o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , $TC + ; + if (!$P || !$R) return; + + var + dir = _c[pane].dir + , _state = (s.isClosed ? "_closed" : "_open") + , spacing = o["spacing"+ _state] + , togAlign = o["togglerAlign"+ _state] + , togLen = o["togglerLength"+ _state] + , paneLen + , left + , offset + , CSS = {} + ; + + if (spacing === 0) { + $R.hide(); + return; + } + else if (!s.noRoom && !s.isHidden) // skip if resizer was hidden for any reason + $R.show(); // in case was previously hidden + + // Resizer Bar is ALWAYS same width/height of pane it is attached to + if (dir === "horz") { // north/south + //paneLen = $P.outerWidth(); // s.outerWidth || + paneLen = sC.innerWidth; // handle offscreen-panes + s.resizerLength = paneLen; + left = $.layout.cssNum($P, "left") + $R.css({ + width: cssW($R, paneLen) // account for borders & padding + , height: cssH($R, spacing) // ditto + , left: left > -9999 ? left : sC.insetLeft // handle offscreen-panes + }); + } + else { // east/west + paneLen = $P.outerHeight(); // s.outerHeight || + s.resizerLength = paneLen; + $R.css({ + height: cssH($R, paneLen) // account for borders & padding + , width: cssW($R, spacing) // ditto + , top: sC.insetTop + getPaneSize("north", true) // TODO: what if no North pane? + //, top: $.layout.cssNum($Ps["center"], "top") + }); + } + + // remove hover classes + removeHover( o, $R ); + + if ($T) { + if (togLen === 0 || (s.isSliding && o.hideTogglerOnSlide)) { + $T.hide(); // always HIDE the toggler when 'sliding' + return; + } + else + $T.show(); // in case was previously hidden + + if (!(togLen > 0) || togLen === "100%" || togLen > paneLen) { + togLen = paneLen; + offset = 0; + } + else { // calculate 'offset' based on options.PANE.togglerAlign_open/closed + if (isStr(togAlign)) { + switch (togAlign) { + case "top": + case "left": offset = 0; + break; + case "bottom": + case "right": offset = paneLen - togLen; + break; + case "middle": + case "center": + default: offset = round((paneLen - togLen) / 2); // 'default' catches typos + } + } + else { // togAlign = number + var x = parseInt(togAlign, 10); // + if (togAlign >= 0) offset = x; + else offset = paneLen - togLen + x; // NOTE: x is negative! + } + } + + if (dir === "horz") { // north/south + var width = cssW($T, togLen); + $T.css({ + width: width // account for borders & padding + , height: cssH($T, spacing) // ditto + , left: offset // TODO: VERIFY that toggler positions correctly for ALL values + , top: 0 + }); + // CENTER the toggler content SPAN + $T.children(".content").each(function(){ + $TC = $(this); + $TC.css("marginLeft", round((width-$TC.outerWidth())/2)); // could be negative + }); + } + else { // east/west + var height = cssH($T, togLen); + $T.css({ + height: height // account for borders & padding + , width: cssW($T, spacing) // ditto + , top: offset // POSITION the toggler + , left: 0 + }); + // CENTER the toggler content SPAN + $T.children(".content").each(function(){ + $TC = $(this); + $TC.css("marginTop", round((height-$TC.outerHeight())/2)); // could be negative + }); + } + + // remove ALL hover classes + removeHover( 0, $T ); + } + + // DONE measuring and sizing this resizer/toggler, so can be 'hidden' now + if (!state.initialized && (o.initHidden || s.noRoom)) { + $R.hide(); + if ($T) $T.hide(); + } + }); + } + + + /** + * @param {string} pane + */ +, enableClosable = function (evt_or_pane) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , $T = $Ts[pane] + , o = options[pane] + ; + if (!$T) return; + o.closable = true; + $T .bind("click."+ sID, function(evt){ evt.stopPropagation(); toggle(pane); }) + .css("visibility", "visible") + .css("cursor", "pointer") + .attr("title", state[pane].isClosed ? o.togglerTip_closed : o.togglerTip_open) // may be blank + .show(); + } + /** + * @param {string} pane + * @param {boolean=} [hide=false] + */ +, disableClosable = function (evt_or_pane, hide) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , $T = $Ts[pane] + ; + if (!$T) return; + options[pane].closable = false; + // is closable is disable, then pane MUST be open! + if (state[pane].isClosed) open(pane, false, true); + $T .unbind("."+ sID) + .css("visibility", hide ? "hidden" : "visible") // instead of hide(), which creates logic issues + .css("cursor", "default") + .attr("title", ""); + } + + + /** + * @param {string} pane + */ +, enableSlidable = function (evt_or_pane) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , $R = $Rs[pane] + ; + if (!$R || !$R.data('draggable')) return; + options[pane].slidable = true; + if (s.isClosed) + bindStartSlidingEvent(pane, true); + } + /** + * @param {string} pane + */ +, disableSlidable = function (evt_or_pane) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , $R = $Rs[pane] + ; + if (!$R) return; + options[pane].slidable = false; + if (state[pane].isSliding) + close(pane, false, true); + else { + bindStartSlidingEvent(pane, false); + $R .css("cursor", "default") + .attr("title", ""); + removeHover(null, $R[0]); // in case currently hovered + } + } + + + /** + * @param {string} pane + */ +, enableResizable = function (evt_or_pane) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , $R = $Rs[pane] + , o = options[pane] + ; + if (!$R || !$R.data('draggable')) return; + o.resizable = true; + $R.draggable("enable"); + if (!state[pane].isClosed) + $R .css("cursor", o.resizerCursor) + .attr("title", o.resizerTip); + } + /** + * @param {string} pane + */ +, disableResizable = function (evt_or_pane) { + if (!isInitialized()) return; + var pane = evtPane.call(this, evt_or_pane) + , $R = $Rs[pane] + ; + if (!$R || !$R.data('draggable')) return; + options[pane].resizable = false; + $R .draggable("disable") + .css("cursor", "default") + .attr("title", ""); + removeHover(null, $R[0]); // in case currently hovered + } + + + /** + * Move a pane from source-side (eg, west) to target-side (eg, east) + * If pane exists on target-side, move that to source-side, ie, 'swap' the panes + * + * @param {string} pane1 The pane/edge being swapped + * @param {string} pane2 ditto + */ +, swapPanes = function (evt_or_pane1, pane2) { + if (!isInitialized()) return; + var pane1 = evtPane.call(this, evt_or_pane1); + // change state.edge NOW so callbacks can know where pane is headed... + state[pane1].edge = pane2; + state[pane2].edge = pane1; + // run these even if NOT state.initialized + if (false === _runCallbacks("onswap_start", pane1) + || false === _runCallbacks("onswap_start", pane2) + ) { + state[pane1].edge = pane1; // reset + state[pane2].edge = pane2; + return; + } + + var + oPane1 = copy( pane1 ) + , oPane2 = copy( pane2 ) + , sizes = {} + ; + sizes[pane1] = oPane1 ? oPane1.state.size : 0; + sizes[pane2] = oPane2 ? oPane2.state.size : 0; + + // clear pointers & state + $Ps[pane1] = false; + $Ps[pane2] = false; + state[pane1] = {}; + state[pane2] = {}; + + // ALWAYS remove the resizer & toggler elements + if ($Ts[pane1]) $Ts[pane1].remove(); + if ($Ts[pane2]) $Ts[pane2].remove(); + if ($Rs[pane1]) $Rs[pane1].remove(); + if ($Rs[pane2]) $Rs[pane2].remove(); + $Rs[pane1] = $Rs[pane2] = $Ts[pane1] = $Ts[pane2] = false; + + // transfer element pointers and data to NEW Layout keys + move( oPane1, pane2 ); + move( oPane2, pane1 ); + + // cleanup objects + oPane1 = oPane2 = sizes = null; + + // make panes 'visible' again + if ($Ps[pane1]) $Ps[pane1].css(_c.visible); + if ($Ps[pane2]) $Ps[pane2].css(_c.visible); + + // fix any size discrepancies caused by swap + resizeAll(); + + // run these even if NOT state.initialized + _runCallbacks("onswap_end", pane1); + _runCallbacks("onswap_end", pane2); + + return; + + function copy (n) { // n = pane + var + $P = $Ps[n] + , $C = $Cs[n] + ; + return !$P ? false : { + pane: n + , P: $P ? $P[0] : false + , C: $C ? $C[0] : false + , state: $.extend(true, {}, state[n]) + , options: $.extend(true, {}, options[n]) + } + }; + + function move (oPane, pane) { + if (!oPane) return; + var + P = oPane.P + , C = oPane.C + , oldPane = oPane.pane + , c = _c[pane] + , side = c.side.toLowerCase() + , inset = "inset"+ c.side + // save pane-options that should be retained + , s = $.extend({}, state[pane]) + , o = options[pane] + // RETAIN side-specific FX Settings - more below + , fx = { resizerCursor: o.resizerCursor } + , re, size, pos + ; + $.each("fxName,fxSpeed,fxSettings".split(","), function (i, k) { + fx[k +"_open"] = o[k +"_open"]; + fx[k +"_close"] = o[k +"_close"]; + fx[k +"_size"] = o[k +"_size"]; + }); + + // update object pointers and attributes + $Ps[pane] = $(P) + .data({ + layoutPane: Instance[pane] // NEW pointer to pane-alias-object + , layoutEdge: pane + }) + .css(_c.hidden) + .css(c.cssReq) + ; + $Cs[pane] = C ? $(C) : false; + + // set options and state + options[pane] = $.extend({}, oPane.options, fx); + state[pane] = $.extend({}, oPane.state); + + // change classNames on the pane, eg: ui-layout-pane-east ==> ui-layout-pane-west + re = new RegExp(o.paneClass +"-"+ oldPane, "g"); + P.className = P.className.replace(re, o.paneClass +"-"+ pane); + + // ALWAYS regenerate the resizer & toggler elements + initHandles(pane); // create the required resizer & toggler + + // if moving to different orientation, then keep 'target' pane size + if (c.dir != _c[oldPane].dir) { + size = sizes[pane] || 0; + setSizeLimits(pane); // update pane-state + size = max(size, state[pane].minSize); + // use manualSizePane to disable autoResize - not useful after panes are swapped + manualSizePane(pane, size, true, true); // true/true = skipCallback/noAnimation + } + else // move the resizer here + $Rs[pane].css(side, sC[inset] + (state[pane].isVisible ? getPaneSize(pane) : 0)); + + + // ADD CLASSNAMES & SLIDE-BINDINGS + if (oPane.state.isVisible && !s.isVisible) + setAsOpen(pane, true); // true = skipCallback + else { + setAsClosed(pane); + bindStartSlidingEvent(pane, true); // will enable events IF option is set + } + + // DESTROY the object + oPane = null; + }; + } + + + /** + * INTERNAL method to sync pin-buttons when pane is opened or closed + * Unpinned means the pane is 'sliding' - ie, over-top of the adjacent panes + * + * @see open(), setAsOpen(), setAsClosed() + * @param {string} pane These are the params returned to callbacks by layout() + * @param {boolean} doPin True means set the pin 'down', False means 'up' + */ +, syncPinBtns = function (pane, doPin) { + if ($.layout.plugins.buttons) + $.each(state[pane].pins, function (i, selector) { + $.layout.buttons.setPinState(Instance, $(selector), pane, doPin); + }); + } + +; // END var DECLARATIONS + + /** + * Capture keys when enableCursorHotkey - toggle pane if hotkey pressed + * + * @see document.keydown() + */ + function keyDown (evt) { + if (!evt) return true; + var code = evt.keyCode; + if (code < 33) return true; // ignore special keys: ENTER, TAB, etc + + var + PANE = { + 38: "north" // Up Cursor - $.ui.keyCode.UP + , 40: "south" // Down Cursor - $.ui.keyCode.DOWN + , 37: "west" // Left Cursor - $.ui.keyCode.LEFT + , 39: "east" // Right Cursor - $.ui.keyCode.RIGHT + } + , ALT = evt.altKey // no worky! + , SHIFT = evt.shiftKey + , CTRL = evt.ctrlKey + , CURSOR = (CTRL && code >= 37 && code <= 40) + , o, k, m, pane + ; + + if (CURSOR && options[PANE[code]].enableCursorHotkey) // valid cursor-hotkey + pane = PANE[code]; + else if (CTRL || SHIFT) // check to see if this matches a custom-hotkey + $.each(_c.borderPanes, function (i, p) { // loop each pane to check its hotkey + o = options[p]; + k = o.customHotkey; + m = o.customHotkeyModifier; // if missing or invalid, treated as "CTRL+SHIFT" + if ((SHIFT && m=="SHIFT") || (CTRL && m=="CTRL") || (CTRL && SHIFT)) { // Modifier matches + if (k && code === (isNaN(k) || k <= 9 ? k.toUpperCase().charCodeAt(0) : k)) { // Key matches + pane = p; + return false; // BREAK + } + } + }); + + // validate pane + if (!pane || !$Ps[pane] || !options[pane].closable || state[pane].isHidden) + return true; + + toggle(pane); + + evt.stopPropagation(); + evt.returnValue = false; // CANCEL key + return false; + }; /* * ###################################### - * UTILITY METHODS - * called externally or by initButtons + * UTILITY METHODS + * called externally or by initButtons * ###################################### */ - /** - * Change/reset a pane overflow setting & zIndex to allow popups/drop-downs to work - * - * @param {Object=} [el] (optional) Can also be 'bound' to a click, mouseOver, or other event - */ - function allowOverflow (el) { - if (!isInitialized()) return; - if (this && this.tagName) el = this; // BOUND to element - var $P; - if (isStr(el)) - $P = $Ps[el]; - else if ($(el).data("layoutRole")) - $P = $(el); - else - $(el).parents().each(function(){ - if ($(this).data("layoutRole")) { - $P = $(this); - return false; // BREAK - } - }); - if (!$P || !$P.length) return; // INVALID - - var - pane = $P.data("layoutEdge") - , s = state[pane] - ; - - // if pane is already raised, then reset it before doing it again! - // this would happen if allowOverflow is attached to BOTH the pane and an element - if (s.cssSaved) - resetOverflow(pane); // reset previous CSS before continuing - - // if pane is raised by sliding or resizing, or its closed, then abort - if (s.isSliding || s.isResizing || s.isClosed) { - s.cssSaved = false; - return; - } - - var - newCSS = { zIndex: (options.zIndexes.resizer_normal + 1) } - , curCSS = {} - , of = $P.css("overflow") - , ofX = $P.css("overflowX") - , ofY = $P.css("overflowY") - ; - // determine which, if any, overflow settings need to be changed - if (of != "visible") { - curCSS.overflow = of; - newCSS.overflow = "visible"; - } - if (ofX && !ofX.match(/visible|auto/)) { - curCSS.overflowX = ofX; - newCSS.overflowX = "visible"; - } - if (ofY && !ofY.match(/visible|auto/)) { - curCSS.overflowY = ofX; - newCSS.overflowY = "visible"; - } - - // save the current overflow settings - even if blank! - s.cssSaved = curCSS; - - // apply new CSS to raise zIndex and, if necessary, make overflow 'visible' - $P.css( newCSS ); - - // make sure the zIndex of all other panes is normal - $.each(_c.allPanes, function(i, p) { - if (p != pane) resetOverflow(p); - }); - - }; - /** - * @param {Object=} [el] (optional) Can also be 'bound' to a click, mouseOver, or other event - */ - function resetOverflow (el) { - if (!isInitialized()) return; - if (this && this.tagName) el = this; // BOUND to element - var $P; - if (isStr(el)) - $P = $Ps[el]; - else if ($(el).data("layoutRole")) - $P = $(el); - else - $(el).parents().each(function(){ - if ($(this).data("layoutRole")) { - $P = $(this); - return false; // BREAK - } - }); - if (!$P || !$P.length) return; // INVALID - - var - pane = $P.data("layoutEdge") - , s = state[pane] - , CSS = s.cssSaved || {} - ; - // reset the zIndex - if (!s.isSliding && !s.isResizing) - $P.css("zIndex", options.zIndexes.pane_normal); - - // reset Overflow - if necessary - $P.css( CSS ); - - // clear var - s.cssSaved = false; - }; + /** + * Change/reset a pane overflow setting & zIndex to allow popups/drop-downs to work + * + * @param {Object=} [el] (optional) Can also be 'bound' to a click, mouseOver, or other event + */ + function allowOverflow (el) { + if (!isInitialized()) return; + if (this && this.tagName) el = this; // BOUND to element + var $P; + if (isStr(el)) + $P = $Ps[el]; + else if ($(el).data("layoutRole")) + $P = $(el); + else + $(el).parents().each(function(){ + if ($(this).data("layoutRole")) { + $P = $(this); + return false; // BREAK + } + }); + if (!$P || !$P.length) return; // INVALID + + var + pane = $P.data("layoutEdge") + , s = state[pane] + ; + + // if pane is already raised, then reset it before doing it again! + // this would happen if allowOverflow is attached to BOTH the pane and an element + if (s.cssSaved) + resetOverflow(pane); // reset previous CSS before continuing + + // if pane is raised by sliding or resizing, or its closed, then abort + if (s.isSliding || s.isResizing || s.isClosed) { + s.cssSaved = false; + return; + } + + var + newCSS = { zIndex: (options.zIndexes.resizer_normal + 1) } + , curCSS = {} + , of = $P.css("overflow") + , ofX = $P.css("overflowX") + , ofY = $P.css("overflowY") + ; + // determine which, if any, overflow settings need to be changed + if (of != "visible") { + curCSS.overflow = of; + newCSS.overflow = "visible"; + } + if (ofX && !ofX.match(/visible|auto/)) { + curCSS.overflowX = ofX; + newCSS.overflowX = "visible"; + } + if (ofY && !ofY.match(/visible|auto/)) { + curCSS.overflowY = ofX; + newCSS.overflowY = "visible"; + } + + // save the current overflow settings - even if blank! + s.cssSaved = curCSS; + + // apply new CSS to raise zIndex and, if necessary, make overflow 'visible' + $P.css( newCSS ); + + // make sure the zIndex of all other panes is normal + $.each(_c.allPanes, function(i, p) { + if (p != pane) resetOverflow(p); + }); + + }; + /** + * @param {Object=} [el] (optional) Can also be 'bound' to a click, mouseOver, or other event + */ + function resetOverflow (el) { + if (!isInitialized()) return; + if (this && this.tagName) el = this; // BOUND to element + var $P; + if (isStr(el)) + $P = $Ps[el]; + else if ($(el).data("layoutRole")) + $P = $(el); + else + $(el).parents().each(function(){ + if ($(this).data("layoutRole")) { + $P = $(this); + return false; // BREAK + } + }); + if (!$P || !$P.length) return; // INVALID + + var + pane = $P.data("layoutEdge") + , s = state[pane] + , CSS = s.cssSaved || {} + ; + // reset the zIndex + if (!s.isSliding && !s.isResizing) + $P.css("zIndex", options.zIndexes.pane_normal); + + // reset Overflow - if necessary + $P.css( CSS ); + + // clear var + s.cssSaved = false; + }; /* * ##################### @@ -4623,93 +4623,93 @@ $.fn.layout = function (opts) { * ##################### */ - // validate that container exists - var $N = $(this).eq(0); // FIRST matching Container element - if (!$N.length) { - if (options.showErrorMessages) - _log( lang.errContainerMissing, true ); - return null; - }; - - // Users retrieve Instance of a layout with: $N.layout() OR $N.data("layout") - // return the Instance-pointer if layout has already been initialized - if ($N.data("layoutContainer") && $N.data("layout")) - return $N.data("layout"); // cached pointer - - // init global vars - var - $Ps = {} // Panes x5 - set in initPanes() - , $Cs = {} // Content x5 - set in initPanes() - , $Rs = {} // Resizers x4 - set in initHandles() - , $Ts = {} // Togglers x4 - set in initHandles() - , $Ms = $([]) // Masks - up to 2 masks per pane (IFRAME + DIV) - // aliases for code brevity - , sC = state.container // alias for easy access to 'container dimensions' - , sID = state.id // alias for unique layout ID/namespace - eg: "layout435" - ; - - // create Instance object to expose data & option Properties, and primary action Methods - var Instance = { - // layout data - options: options // property - options hash - , state: state // property - dimensions hash - // object pointers - , container: $N // property - object pointers for layout container - , panes: $Ps // property - object pointers for ALL Panes: panes.north, panes.center - , contents: $Cs // property - object pointers for ALL Content: contents.north, contents.center - , resizers: $Rs // property - object pointers for ALL Resizers, eg: resizers.north - , togglers: $Ts // property - object pointers for ALL Togglers, eg: togglers.north - // border-pane open/close - , hide: hide // method - ditto - , show: show // method - ditto - , toggle: toggle // method - pass a 'pane' ("north", "west", etc) - , open: open // method - ditto - , close: close // method - ditto - , slideOpen: slideOpen // method - ditto - , slideClose: slideClose // method - ditto - , slideToggle: slideToggle // method - ditto - // pane actions - , setSizeLimits: setSizeLimits // method - pass a 'pane' - update state min/max data - , _sizePane: sizePane // method -intended for user by plugins only! - , sizePane: manualSizePane // method - pass a 'pane' AND an 'outer-size' in pixels or percent, or 'auto' - , sizeContent: sizeContent // method - pass a 'pane' - , swapPanes: swapPanes // method - pass TWO 'panes' - will swap them - // pane element methods - , initContent: initContent // method - ditto - , addPane: addPane // method - pass a 'pane' - , removePane: removePane // method - pass a 'pane' to remove from layout, add 'true' to delete the pane-elem - , createChildLayout: createChildLayout// method - pass a 'pane' and (optional) layout-options (OVERRIDES options[pane].childOptions - // special pane option setting - , enableClosable: enableClosable // method - pass a 'pane' - , disableClosable: disableClosable // method - ditto - , enableSlidable: enableSlidable // method - ditto - , disableSlidable: disableSlidable // method - ditto - , enableResizable: enableResizable // method - ditto - , disableResizable: disableResizable// method - ditto - // utility methods for panes - , allowOverflow: allowOverflow // utility - pass calling element (this) - , resetOverflow: resetOverflow // utility - ditto - // layout control - , destroy: destroy // method - no parameters - , initPanes: isInitialized // method - no parameters - , resizeAll: resizeAll // method - no parameters - // callback triggering - , runCallbacks: _runCallbacks // method - pass evtName & pane (if a pane-event), eg: trigger("onopen", "west") - // alias collections of options, state and children - created in addPane and extended elsewhere - , hasParentLayout: false // set by initContainer() - , children: children // pointers to child-layouts, eg: Instance.children["west"] - , north: false // alias group: { name: pane, pane: $Ps[pane], options: options[pane], state: state[pane], child: children[pane] } - , south: false // ditto - , west: false // ditto - , east: false // ditto - , center: false // ditto - }; - - // create the border layout NOW - if (_create() === 'cancel') // onload_start callback returned false to CANCEL layout creation - return null; - else // true OR false -- if layout-elements did NOT init (hidden or do not exist), can auto-init later - return Instance; // return the Instance object + // validate that container exists + var $N = $(this).eq(0); // FIRST matching Container element + if (!$N.length) { + if (options.showErrorMessages) + _log( lang.errContainerMissing, true ); + return null; + }; + + // Users retrieve Instance of a layout with: $N.layout() OR $N.data("layout") + // return the Instance-pointer if layout has already been initialized + if ($N.data("layoutContainer") && $N.data("layout")) + return $N.data("layout"); // cached pointer + + // init global vars + var + $Ps = {} // Panes x5 - set in initPanes() + , $Cs = {} // Content x5 - set in initPanes() + , $Rs = {} // Resizers x4 - set in initHandles() + , $Ts = {} // Togglers x4 - set in initHandles() + , $Ms = $([]) // Masks - up to 2 masks per pane (IFRAME + DIV) + // aliases for code brevity + , sC = state.container // alias for easy access to 'container dimensions' + , sID = state.id // alias for unique layout ID/namespace - eg: "layout435" + ; + + // create Instance object to expose data & option Properties, and primary action Methods + var Instance = { + // layout data + options: options // property - options hash + , state: state // property - dimensions hash + // object pointers + , container: $N // property - object pointers for layout container + , panes: $Ps // property - object pointers for ALL Panes: panes.north, panes.center + , contents: $Cs // property - object pointers for ALL Content: contents.north, contents.center + , resizers: $Rs // property - object pointers for ALL Resizers, eg: resizers.north + , togglers: $Ts // property - object pointers for ALL Togglers, eg: togglers.north + // border-pane open/close + , hide: hide // method - ditto + , show: show // method - ditto + , toggle: toggle // method - pass a 'pane' ("north", "west", etc) + , open: open // method - ditto + , close: close // method - ditto + , slideOpen: slideOpen // method - ditto + , slideClose: slideClose // method - ditto + , slideToggle: slideToggle // method - ditto + // pane actions + , setSizeLimits: setSizeLimits // method - pass a 'pane' - update state min/max data + , _sizePane: sizePane // method -intended for user by plugins only! + , sizePane: manualSizePane // method - pass a 'pane' AND an 'outer-size' in pixels or percent, or 'auto' + , sizeContent: sizeContent // method - pass a 'pane' + , swapPanes: swapPanes // method - pass TWO 'panes' - will swap them + // pane element methods + , initContent: initContent // method - ditto + , addPane: addPane // method - pass a 'pane' + , removePane: removePane // method - pass a 'pane' to remove from layout, add 'true' to delete the pane-elem + , createChildLayout: createChildLayout// method - pass a 'pane' and (optional) layout-options (OVERRIDES options[pane].childOptions + // special pane option setting + , enableClosable: enableClosable // method - pass a 'pane' + , disableClosable: disableClosable // method - ditto + , enableSlidable: enableSlidable // method - ditto + , disableSlidable: disableSlidable // method - ditto + , enableResizable: enableResizable // method - ditto + , disableResizable: disableResizable// method - ditto + // utility methods for panes + , allowOverflow: allowOverflow // utility - pass calling element (this) + , resetOverflow: resetOverflow // utility - ditto + // layout control + , destroy: destroy // method - no parameters + , initPanes: isInitialized // method - no parameters + , resizeAll: resizeAll // method - no parameters + // callback triggering + , runCallbacks: _runCallbacks // method - pass evtName & pane (if a pane-event), eg: trigger("onopen", "west") + // alias collections of options, state and children - created in addPane and extended elsewhere + , hasParentLayout: false // set by initContainer() + , children: children // pointers to child-layouts, eg: Instance.children["west"] + , north: false // alias group: { name: pane, pane: $Ps[pane], options: options[pane], state: state[pane], child: children[pane] } + , south: false // ditto + , west: false // ditto + , east: false // ditto + , center: false // ditto + }; + + // create the border layout NOW + if (_create() === 'cancel') // onload_start callback returned false to CANCEL layout creation + return null; + else // true OR false -- if layout-elements did NOT init (hidden or do not exist), can auto-init later + return Instance; // return the Instance object } @@ -4720,7 +4720,7 @@ $.fn.layout = function (opts) { * jquery.layout.state 1.0 * $Date$ * - * Copyright (c) 2010 + * Copyright (c) 2010 * Kevin Dalman (http://allpro.net) * * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html) @@ -4732,336 +4732,336 @@ $.fn.layout = function (opts) { * @support: http://groups.google.com/group/jquery-ui-layout */ /* - * State-management options stored in options.stateManagement, which includes a .cookie hash - * Default options saves ALL KEYS for ALL PANES, ie: pane.size, pane.isClosed, pane.isHidden + * State-management options stored in options.stateManagement, which includes a .cookie hash + * Default options saves ALL KEYS for ALL PANES, ie: pane.size, pane.isClosed, pane.isHidden * - * // STATE/COOKIE OPTIONS - * @example $(el).layout({ - stateManagement: { - enabled: true - , stateKeys: "east.size,west.size,east.isClosed,west.isClosed" - , cookie: { name: "appLayout", path: "/" } - } - }) - * @example $(el).layout({ stateManagement__enabled: true }) // enable auto-state-management using cookies - * @example $(el).layout({ stateManagement__cookie: { name: "appLayout", path: "/" } }) - * @example $(el).layout({ stateManagement__cookie__name: "appLayout", stateManagement__cookie__path: "/" }) + * // STATE/COOKIE OPTIONS + * @example $(el).layout({ + stateManagement: { + enabled: true + , stateKeys: "east.size,west.size,east.isClosed,west.isClosed" + , cookie: { name: "appLayout", path: "/" } + } + }) + * @example $(el).layout({ stateManagement__enabled: true }) // enable auto-state-management using cookies + * @example $(el).layout({ stateManagement__cookie: { name: "appLayout", path: "/" } }) + * @example $(el).layout({ stateManagement__cookie__name: "appLayout", stateManagement__cookie__path: "/" }) * - * // STATE/COOKIE METHODS - * @example myLayout.saveCookie( "west.isClosed,north.size,south.isHidden", {expires: 7} ); - * @example myLayout.loadCookie(); - * @example myLayout.deleteCookie(); - * @example var JSON = myLayout.readState(); // CURRENT Layout State - * @example var JSON = myLayout.readCookie(); // SAVED Layout State (from cookie) - * @example var JSON = myLayout.state.stateData; // LAST LOADED Layout State (cookie saved in layout.state hash) + * // STATE/COOKIE METHODS + * @example myLayout.saveCookie( "west.isClosed,north.size,south.isHidden", {expires: 7} ); + * @example myLayout.loadCookie(); + * @example myLayout.deleteCookie(); + * @example var JSON = myLayout.readState(); // CURRENT Layout State + * @example var JSON = myLayout.readCookie(); // SAVED Layout State (from cookie) + * @example var JSON = myLayout.state.stateData; // LAST LOADED Layout State (cookie saved in layout.state hash) * - * CUSTOM STATE-MANAGEMENT (eg, saved in a database) - * @example var JSON = myLayout.readState( "west.isClosed,north.size,south.isHidden" ); - * @example myLayout.loadState( JSON ); + * CUSTOM STATE-MANAGEMENT (eg, saved in a database) + * @example var JSON = myLayout.readState( "west.isClosed,north.size,south.isHidden" ); + * @example myLayout.loadState( JSON ); */ /** - * UI COOKIE UTILITY + * UI COOKIE UTILITY * - * A $.cookie OR $.ui.cookie namespace *should be standard*, but until then... - * This creates $.ui.cookie so Layout does not need the cookie.jquery.js plugin - * NOTE: This utility is REQUIRED by the layout.state plugin + * A $.cookie OR $.ui.cookie namespace *should be standard*, but until then... + * This creates $.ui.cookie so Layout does not need the cookie.jquery.js plugin + * NOTE: This utility is REQUIRED by the layout.state plugin * - * Cookie methods in Layout are created as part of State Management + * Cookie methods in Layout are created as part of State Management */ if (!$.ui) $.ui = {}; $.ui.cookie = { - // cookieEnabled is not in DOM specs, but DOES works in all browsers,including IE6 - acceptsCookies: !!navigator.cookieEnabled - -, read: function (name) { - var - c = document.cookie - , cs = c ? c.split(';') : [] - , pair // loop var - ; - for (var i=0, n=cs.length; i < n; i++) { - pair = $.trim(cs[i]).split('='); // name=value pair - if (pair[0] == name) // found the layout cookie - return decodeURIComponent(pair[1]); - - } - return null; - } - -, write: function (name, val, cookieOpts) { - var - params = '' - , date = '' - , clear = false - , o = cookieOpts || {} - , x = o.expires - ; - if (x && x.toUTCString) - date = x; - else if (x === null || typeof x === 'number') { - date = new Date(); - if (x > 0) - date.setDate(date.getDate() + x); - else { - date.setFullYear(1970); - clear = true; - } - } - if (date) params += ';expires='+ date.toUTCString(); - if (o.path) params += ';path='+ o.path; - if (o.domain) params += ';domain='+ o.domain; - if (o.secure) params += ';secure'; - document.cookie = name +'='+ (clear ? "" : encodeURIComponent( val )) + params; // write or clear cookie - } - -, clear: function (name) { - $.ui.cookie.write(name, '', {expires: -1}); - } + // cookieEnabled is not in DOM specs, but DOES works in all browsers,including IE6 + acceptsCookies: !!navigator.cookieEnabled + +, read: function (name) { + var + c = document.cookie + , cs = c ? c.split(';') : [] + , pair // loop var + ; + for (var i=0, n=cs.length; i < n; i++) { + pair = $.trim(cs[i]).split('='); // name=value pair + if (pair[0] == name) // found the layout cookie + return decodeURIComponent(pair[1]); + + } + return null; + } + +, write: function (name, val, cookieOpts) { + var + params = '' + , date = '' + , clear = false + , o = cookieOpts || {} + , x = o.expires + ; + if (x && x.toUTCString) + date = x; + else if (x === null || typeof x === 'number') { + date = new Date(); + if (x > 0) + date.setDate(date.getDate() + x); + else { + date.setFullYear(1970); + clear = true; + } + } + if (date) params += ';expires='+ date.toUTCString(); + if (o.path) params += ';path='+ o.path; + if (o.domain) params += ';domain='+ o.domain; + if (o.secure) params += ';secure'; + document.cookie = name +'='+ (clear ? "" : encodeURIComponent( val )) + params; // write or clear cookie + } + +, clear: function (name) { + $.ui.cookie.write(name, '', {expires: -1}); + } }; // if cookie.jquery.js is not loaded, create an alias to replicate it // this may be useful to other plugins or code dependent on that plugin if (!$.cookie) $.cookie = function (k, v, o) { - var C = $.ui.cookie; - if (v === null) - C.clear(k); - else if (v === undefined) - return C.read(k); - else - C.write(k, v, o); + var C = $.ui.cookie; + if (v === null) + C.clear(k); + else if (v === undefined) + return C.read(k); + else + C.write(k, v, o); }; // tell Layout that the state plugin is available $.layout.plugins.stateManagement = true; -// Add State-Management options to layout.defaults +// Add State-Management options to layout.defaults $.layout.config.optionRootKeys.push("stateManagement"); $.layout.defaults.stateManagement = { - enabled: false // true = enable state-management, even if not using cookies -, autoSave: true // Save a state-cookie when page exits? -, autoLoad: true // Load the state-cookie when Layout inits? - // List state-data to save - must be pane-specific -, stateKeys: "north.size,south.size,east.size,west.size,"+ - "north.isClosed,south.isClosed,east.isClosed,west.isClosed,"+ - "north.isHidden,south.isHidden,east.isHidden,west.isHidden" -, cookie: { - name: "" // If not specified, will use Layout.name, else just "Layout" - , domain: "" // blank = current domain - , path: "" // blank = current page, '/' = entire website - , expires: "" // 'days' to keep cookie - leave blank for 'session cookie' - , secure: false - } + enabled: false // true = enable state-management, even if not using cookies +, autoSave: true // Save a state-cookie when page exits? +, autoLoad: true // Load the state-cookie when Layout inits? + // List state-data to save - must be pane-specific +, stateKeys: "north.size,south.size,east.size,west.size,"+ + "north.isClosed,south.isClosed,east.isClosed,west.isClosed,"+ + "north.isHidden,south.isHidden,east.isHidden,west.isHidden" +, cookie: { + name: "" // If not specified, will use Layout.name, else just "Layout" + , domain: "" // blank = current domain + , path: "" // blank = current page, '/' = entire website + , expires: "" // 'days' to keep cookie - leave blank for 'session cookie' + , secure: false + } }; // Set stateManagement as a layout-option, NOT a pane-option $.layout.optionsMap.layout.push("stateManagement"); /* - * State Management methods + * State Management methods */ $.layout.state = { - /** - * Get the current layout state and save it to a cookie - * - * myLayout.saveCookie( keys, cookieOpts ) - * - * @param {Object} inst - * @param {(string|Array)=} keys - * @param {Object=} opts - */ - saveCookie: function (inst, keys, cookieOpts) { - var o = inst.options - , oS = o.stateManagement - , oC = $.extend(true, {}, oS.cookie, cookieOpts || null) - , data = inst.state.stateData = inst.readState( keys || oS.stateKeys ) // read current panes-state - ; - $.ui.cookie.write( oC.name || o.name || "Layout", $.layout.state.encodeJSON(data), oC ); - return $.extend(true, {}, data); // return COPY of state.stateData data - } - - /** - * Remove the state cookie - * - * @param {Object} inst - */ -, deleteCookie: function (inst) { - var o = inst.options; - $.ui.cookie.clear( o.stateManagement.cookie.name || o.name || "Layout" ); - } - - /** - * Read & return data from the cookie - as JSON - * - * @param {Object} inst - */ -, readCookie: function (inst) { - var o = inst.options; - var c = $.ui.cookie.read( o.stateManagement.cookie.name || o.name || "Layout" ); - // convert cookie string back to a hash and return it - return c ? $.layout.state.decodeJSON(c) : {}; - } - - /** - * Get data from the cookie and USE IT to loadState - * - * @param {Object} inst - */ -, loadCookie: function (inst) { - var c = $.layout.state.readCookie(inst); // READ the cookie - if (c) { - inst.state.stateData = $.extend(true, {}, c); // SET state.stateData - inst.loadState(c); // LOAD the retrieved state - } - return c; - } - - /** - * Update layout options from the cookie, if one exists - * - * @param {Object} inst - * @param {Object=} stateData - * @param {boolean=} animate - */ -, loadState: function (inst, stateData, animate) { - stateData = $.layout.transformData( stateData ); // panes = default subkey - if ($.isEmptyObject( stateData )) return; - $.extend(true, inst.options, stateData); // update layout options - // if layout has already been initialized, then UPDATE layout state - if (inst.state.initialized) { - var pane, vis, o, s, h, c - , noAnimate = (animate===false) - ; - $.each($.layout.config.borderPanes, function (idx, pane) { - state = inst.state[pane]; - o = stateData[ pane ]; - if (typeof o != 'object') return; // no key, continue - s = o.size; - c = o.initClosed; - h = o.initHidden; - vis = state.isVisible; - // resize BEFORE opening - if (!vis) - inst.sizePane(pane, s, false, false); - if (h === true) inst.hide(pane, noAnimate); - else if (c === false) inst.open (pane, false, noAnimate); - else if (c === true) inst.close(pane, false, noAnimate); - else if (h === false) inst.show (pane, false, noAnimate); - // resize AFTER any other actions - if (vis) - inst.sizePane(pane, s, false, noAnimate); // animate resize if option passed - }); - }; - } - - /** - * Get the *current layout state* and return it as a hash - * - * @param {Object=} inst - * @param {(string|Array)=} keys - */ -, readState: function (inst, keys) { - var - data = {} - , alt = { isClosed: 'initClosed', isHidden: 'initHidden' } - , state = inst.state - , panes = $.layout.config.allPanes - , pair, pane, key, val - ; - if (!keys) keys = inst.options.stateManagement.stateKeys; // if called by user - if ($.isArray(keys)) keys = keys.join(","); - // convert keys to an array and change delimiters from '__' to '.' - keys = keys.replace(/__/g, ".").split(','); - // loop keys and create a data hash - for (var i=0, n=keys.length; i < n; i++) { - pair = keys[i].split("."); - pane = pair[0]; - key = pair[1]; - if ($.inArray(pane, panes) < 0) continue; // bad pane! - val = state[ pane ][ key ]; - if (val == undefined) continue; - if (key=="isClosed" && state[pane]["isSliding"]) - val = true; // if sliding, then *really* isClosed - ( data[pane] || (data[pane]={}) )[ alt[key] ? alt[key] : key ] = val; - } - return data; - } - - /** - * Stringify a JSON hash so can save in a cookie or db-field - */ -, encodeJSON: function (JSON) { - return parse(JSON); - function parse (h) { - var D=[], i=0, k, v, t; // k = key, v = value - for (k in h) { - v = h[k]; - t = typeof v; - if (t == 'string') // STRING - add quotes - v = '"'+ v +'"'; - else if (t == 'object') // SUB-KEY - recurse into it - v = parse(v); - D[i++] = '"'+ k +'":'+ v; - } - return '{'+ D.join(',') +'}'; - }; - } - - /** - * Convert stringified JSON back to a hash object - * @see $.parseJSON(), adding in jQuery 1.4.1 - */ -, decodeJSON: function (str) { - try { return $.parseJSON ? $.parseJSON(str) : window["eval"]("("+ str +")") || {}; } - catch (e) { return {}; } - } - - -, _create: function (inst) { - var _ = $.layout.state; - // ADD State-Management plugin methods to inst - $.extend( inst, { - // readCookie - update options from cookie - returns hash of cookie data - readCookie: function () { return _.readCookie(inst); } - // deleteCookie - , deleteCookie: function () { _.deleteCookie(inst); } - // saveCookie - optionally pass keys-list and cookie-options (hash) - , saveCookie: function (keys, cookieOpts) { return _.saveCookie(inst, keys, cookieOpts); } - // loadCookie - readCookie and use to loadState() - returns hash of cookie data - , loadCookie: function () { return _.loadCookie(inst); } - // loadState - pass a hash of state to use to update options - , loadState: function (stateData, animate) { _.loadState(inst, stateData, animate); } - // readState - returns hash of current layout-state - , readState: function (keys) { return _.readState(inst, keys); } - // add JSON utility methods too... - , encodeJSON: _.encodeJSON - , decodeJSON: _.decodeJSON - }); - - // init state.stateData key, even if plugin is initially disabled - inst.state.stateData = {}; - - // read and load cookie-data per options - var oS = inst.options.stateManagement; - if (oS.enabled) { - if (oS.autoLoad) // update the options from the cookie - inst.loadCookie(); - else // don't modify options - just store cookie data in state.stateData - inst.state.stateData = inst.readCookie(); - } - } - -, _unload: function (inst) { - var oS = inst.options.stateManagement; - if (oS.enabled) { - if (oS.autoSave) // save a state-cookie automatically - inst.saveCookie(); - else // don't save a cookie, but do store state-data in state.stateData key - inst.state.stateData = inst.readState(); - } - } + /** + * Get the current layout state and save it to a cookie + * + * myLayout.saveCookie( keys, cookieOpts ) + * + * @param {Object} inst + * @param {(string|Array)=} keys + * @param {Object=} opts + */ + saveCookie: function (inst, keys, cookieOpts) { + var o = inst.options + , oS = o.stateManagement + , oC = $.extend(true, {}, oS.cookie, cookieOpts || null) + , data = inst.state.stateData = inst.readState( keys || oS.stateKeys ) // read current panes-state + ; + $.ui.cookie.write( oC.name || o.name || "Layout", $.layout.state.encodeJSON(data), oC ); + return $.extend(true, {}, data); // return COPY of state.stateData data + } + + /** + * Remove the state cookie + * + * @param {Object} inst + */ +, deleteCookie: function (inst) { + var o = inst.options; + $.ui.cookie.clear( o.stateManagement.cookie.name || o.name || "Layout" ); + } + + /** + * Read & return data from the cookie - as JSON + * + * @param {Object} inst + */ +, readCookie: function (inst) { + var o = inst.options; + var c = $.ui.cookie.read( o.stateManagement.cookie.name || o.name || "Layout" ); + // convert cookie string back to a hash and return it + return c ? $.layout.state.decodeJSON(c) : {}; + } + + /** + * Get data from the cookie and USE IT to loadState + * + * @param {Object} inst + */ +, loadCookie: function (inst) { + var c = $.layout.state.readCookie(inst); // READ the cookie + if (c) { + inst.state.stateData = $.extend(true, {}, c); // SET state.stateData + inst.loadState(c); // LOAD the retrieved state + } + return c; + } + + /** + * Update layout options from the cookie, if one exists + * + * @param {Object} inst + * @param {Object=} stateData + * @param {boolean=} animate + */ +, loadState: function (inst, stateData, animate) { + stateData = $.layout.transformData( stateData ); // panes = default subkey + if ($.isEmptyObject( stateData )) return; + $.extend(true, inst.options, stateData); // update layout options + // if layout has already been initialized, then UPDATE layout state + if (inst.state.initialized) { + var pane, vis, o, s, h, c + , noAnimate = (animate===false) + ; + $.each($.layout.config.borderPanes, function (idx, pane) { + state = inst.state[pane]; + o = stateData[ pane ]; + if (typeof o != 'object') return; // no key, continue + s = o.size; + c = o.initClosed; + h = o.initHidden; + vis = state.isVisible; + // resize BEFORE opening + if (!vis) + inst.sizePane(pane, s, false, false); + if (h === true) inst.hide(pane, noAnimate); + else if (c === false) inst.open (pane, false, noAnimate); + else if (c === true) inst.close(pane, false, noAnimate); + else if (h === false) inst.show (pane, false, noAnimate); + // resize AFTER any other actions + if (vis) + inst.sizePane(pane, s, false, noAnimate); // animate resize if option passed + }); + }; + } + + /** + * Get the *current layout state* and return it as a hash + * + * @param {Object=} inst + * @param {(string|Array)=} keys + */ +, readState: function (inst, keys) { + var + data = {} + , alt = { isClosed: 'initClosed', isHidden: 'initHidden' } + , state = inst.state + , panes = $.layout.config.allPanes + , pair, pane, key, val + ; + if (!keys) keys = inst.options.stateManagement.stateKeys; // if called by user + if ($.isArray(keys)) keys = keys.join(","); + // convert keys to an array and change delimiters from '__' to '.' + keys = keys.replace(/__/g, ".").split(','); + // loop keys and create a data hash + for (var i=0, n=keys.length; i < n; i++) { + pair = keys[i].split("."); + pane = pair[0]; + key = pair[1]; + if ($.inArray(pane, panes) < 0) continue; // bad pane! + val = state[ pane ][ key ]; + if (val == undefined) continue; + if (key=="isClosed" && state[pane]["isSliding"]) + val = true; // if sliding, then *really* isClosed + ( data[pane] || (data[pane]={}) )[ alt[key] ? alt[key] : key ] = val; + } + return data; + } + + /** + * Stringify a JSON hash so can save in a cookie or db-field + */ +, encodeJSON: function (JSON) { + return parse(JSON); + function parse (h) { + var D=[], i=0, k, v, t; // k = key, v = value + for (k in h) { + v = h[k]; + t = typeof v; + if (t == 'string') // STRING - add quotes + v = '"'+ v +'"'; + else if (t == 'object') // SUB-KEY - recurse into it + v = parse(v); + D[i++] = '"'+ k +'":'+ v; + } + return '{'+ D.join(',') +'}'; + }; + } + + /** + * Convert stringified JSON back to a hash object + * @see $.parseJSON(), adding in jQuery 1.4.1 + */ +, decodeJSON: function (str) { + try { return $.parseJSON ? $.parseJSON(str) : window["eval"]("("+ str +")") || {}; } + catch (e) { return {}; } + } + + +, _create: function (inst) { + var _ = $.layout.state; + // ADD State-Management plugin methods to inst + $.extend( inst, { + // readCookie - update options from cookie - returns hash of cookie data + readCookie: function () { return _.readCookie(inst); } + // deleteCookie + , deleteCookie: function () { _.deleteCookie(inst); } + // saveCookie - optionally pass keys-list and cookie-options (hash) + , saveCookie: function (keys, cookieOpts) { return _.saveCookie(inst, keys, cookieOpts); } + // loadCookie - readCookie and use to loadState() - returns hash of cookie data + , loadCookie: function () { return _.loadCookie(inst); } + // loadState - pass a hash of state to use to update options + , loadState: function (stateData, animate) { _.loadState(inst, stateData, animate); } + // readState - returns hash of current layout-state + , readState: function (keys) { return _.readState(inst, keys); } + // add JSON utility methods too... + , encodeJSON: _.encodeJSON + , decodeJSON: _.decodeJSON + }); + + // init state.stateData key, even if plugin is initially disabled + inst.state.stateData = {}; + + // read and load cookie-data per options + var oS = inst.options.stateManagement; + if (oS.enabled) { + if (oS.autoLoad) // update the options from the cookie + inst.loadCookie(); + else // don't modify options - just store cookie data in state.stateData + inst.state.stateData = inst.readCookie(); + } + } + +, _unload: function (inst) { + var oS = inst.options.stateManagement; + if (oS.enabled) { + if (oS.autoSave) // save a state-cookie automatically + inst.saveCookie(); + else // don't save a cookie, but do store state-data in state.stateData key + inst.state.stateData = inst.readState(); + } + } }; @@ -5076,7 +5076,7 @@ $.layout.onUnload.push( $.layout.state._unload ); * jquery.layout.buttons 1.0 * $Date$ * - * Copyright (c) 2010 + * Copyright (c) 2010 * Kevin Dalman (http://allpro.net) * * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html) @@ -5093,7 +5093,7 @@ $.layout.onUnload.push( $.layout.state._unload ); // tell Layout that the state plugin is available $.layout.plugins.buttons = true; -// Add buttons options to layout.defaults +// Add buttons options to layout.defaults $.layout.defaults.autoBindCustomButtons = false; // Specify autoBindCustomButtons as a layout-option, NOT a pane-option $.layout.optionsMap.layout.push("autoBindCustomButtons"); @@ -5101,250 +5101,250 @@ $.layout.optionsMap.layout.push("autoBindCustomButtons"); var lang = $.layout.language; /* - * Button methods + * Button methods */ $.layout.buttons = { - /** - * Searches for .ui-layout-button-xxx elements and auto-binds them as layout-buttons - * - * @see _create() - * - * @param {Object} inst Layout Instance object - */ - init: function (inst) { - var pre = "ui-layout-button-" - , layout = inst.options.name || "" - , name; - $.each("toggle,open,close,pin,toggle-slide,open-slide".split(","), function (i, action) { - $.each($.layout.config.borderPanes, function (ii, pane) { - $("."+pre+action+"-"+pane).each(function(){ - // if button was previously 'bound', data.layoutName was set, but is blank if layout has no 'name' - name = $(this).data("layoutName") || $(this).attr("layoutName"); - if (name == undefined || name === layout) - inst.bindButton(this, action, pane); - }); - }); - }); - } - - /** - * Helper function to validate params received by addButton utilities - * - * Two classes are added to the element, based on the buttonClass... - * The type of button is appended to create the 2nd className: - * - ui-layout-button-pin // action btnClass - * - ui-layout-button-pin-west // action btnClass + pane - * - ui-layout-button-toggle - * - ui-layout-button-open - * - ui-layout-button-close - * - * @param {Object} inst Layout Instance object - * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" - * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. - * - * @return {Array.} If both params valid, the element matching 'selector' in a jQuery wrapper - otherwise returns null - */ -, get: function (inst, selector, pane, action) { - var $E = $(selector) - , o = inst.options - , err = o.showErrorMessages - ; - if (!$E.length) { // element not found - if (err) $.layout.msg(lang.errButton + lang.selector +": "+ selector, true); - } - else if ($.inArray(pane, $.layout.config.borderPanes) < 0) { // invalid 'pane' sepecified - if (err) $.layout.msg(lang.errButton + lang.pane +": "+ pane, true); - $E = $(""); // NO BUTTON - } - else { // VALID - var btn = o[pane].buttonClass +"-"+ action; - $E .addClass( btn +" "+ btn +"-"+ pane ) - .data("layoutName", o.name); // add layout identifier - even if blank! - } - return $E; - } - - - /** - * NEW syntax for binding layout-buttons - will eventually replace addToggle, addOpen, etc. - * - * @param {Object} inst Layout Instance object - * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" - * @param {string} action - * @param {string} pane - */ -, bind: function (inst, selector, action, pane) { - var _ = $.layout.buttons; - switch (action.toLowerCase()) { - case "toggle": _.addToggle (inst, selector, pane); break; - case "open": _.addOpen (inst, selector, pane); break; - case "close": _.addClose (inst, selector, pane); break; - case "pin": _.addPin (inst, selector, pane); break; - case "toggle-slide": _.addToggle (inst, selector, pane, true); break; - case "open-slide": _.addOpen (inst, selector, pane, true); break; - } - return inst; - } - - /** - * Add a custom Toggler button for a pane - * - * @param {Object} inst Layout Instance object - * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" - * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. - * @param {boolean=} slide true = slide-open, false = pin-open - */ -, addToggle: function (inst, selector, pane, slide) { - $.layout.buttons.get(inst, selector, pane, "toggle") - .click(function(evt){ - inst.toggle(pane, !!slide); - evt.stopPropagation(); - }); - return inst; - } - - /** - * Add a custom Open button for a pane - * - * @param {Object} inst Layout Instance object - * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" - * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. - * @param {boolean=} slide true = slide-open, false = pin-open - */ -, addOpen: function (inst, selector, pane, slide) { - $.layout.buttons.get(inst, selector, pane, "open") - .attr("title", lang.Open) - .click(function (evt) { - inst.open(pane, !!slide); - evt.stopPropagation(); - }); - return inst; - } - - /** - * Add a custom Close button for a pane - * - * @param {Object} inst Layout Instance object - * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" - * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. - */ -, addClose: function (inst, selector, pane) { - $.layout.buttons.get(inst, selector, pane, "close") - .attr("title", lang.Close) - .click(function (evt) { - inst.close(pane); - evt.stopPropagation(); - }); - return inst; - } - - /** - * Add a custom Pin button for a pane - * - * Four classes are added to the element, based on the paneClass for the associated pane... - * Assuming the default paneClass and the pin is 'up', these classes are added for a west-pane pin: - * - ui-layout-pane-pin - * - ui-layout-pane-west-pin - * - ui-layout-pane-pin-up - * - ui-layout-pane-west-pin-up - * - * @param {Object} inst Layout Instance object - * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" - * @param {string} pane Name of the pane the pin is for: 'north', 'south', etc. - */ -, addPin: function (inst, selector, pane) { - var _ = $.layout.buttons - , $E = _.get(inst, selector, pane, "pin"); - if ($E.length) { - var s = inst.state[pane]; - $E.click(function (evt) { - _.setPinState(inst, $(this), pane, (s.isSliding || s.isClosed)); - if (s.isSliding || s.isClosed) inst.open( pane ); // change from sliding to open - else inst.close( pane ); // slide-closed - evt.stopPropagation(); - }); - // add up/down pin attributes and classes - _.setPinState(inst, $E, pane, (!s.isClosed && !s.isSliding)); - // add this pin to the pane data so we can 'sync it' automatically - // PANE.pins key is an array so we can store multiple pins for each pane - s.pins.push( selector ); // just save the selector string - } - return inst; - } - - /** - * Change the class of the pin button to make it look 'up' or 'down' - * - * @see addPin(), syncPins() - * - * @param {Object} inst Layout Instance object - * @param {Array.} $Pin The pin-span element in a jQuery wrapper - * @param {string} pane These are the params returned to callbacks by layout() - * @param {boolean} doPin true = set the pin 'down', false = set it 'up' - */ -, setPinState: function (inst, $Pin, pane, doPin) { - var updown = $Pin.attr("pin"); - if (updown && doPin === (updown=="down")) return; // already in correct state - var - pin = inst.options[pane].buttonClass +"-pin" - , side = pin +"-"+ pane - , UP = pin +"-up "+ side +"-up" - , DN = pin +"-down "+side +"-down" - ; - $Pin - .attr("pin", doPin ? "down" : "up") // logic - .attr("title", doPin ? lang.Unpin : lang.Pin) - .removeClass( doPin ? UP : DN ) - .addClass( doPin ? DN : UP ) - ; - } - - /** - * INTERNAL function to sync 'pin buttons' when pane is opened or closed - * Unpinned means the pane is 'sliding' - ie, over-top of the adjacent panes - * - * @see open(), close() - * - * @param {Object} inst Layout Instance object - * @param {string} pane These are the params returned to callbacks by layout() - * @param {boolean} doPin True means set the pin 'down', False means 'up' - */ -, syncPinBtns: function (inst, pane, doPin) { - // REAL METHOD IS _INSIDE_ LAYOUT - THIS IS HERE JUST FOR REFERENCE - $.each(state[pane].pins, function (i, selector) { - $.layout.buttons.setPinState(inst, $(selector), pane, doPin); - }); - } - - -, _load: function (inst) { - var _ = $.layout.buttons; - // ADD Button methods to Layout Instance - // Note: sel = jQuery Selector string - $.extend( inst, { - bindButton: function (sel, action, pane) { return _.bind(inst, sel, action, pane); } - // DEPRECATED METHODS - , addToggleBtn: function (sel, pane, slide) { return _.addToggle(inst, sel, pane, slide); } - , addOpenBtn: function (sel, pane, slide) { return _.addOpen(inst, sel, pane, slide); } - , addCloseBtn: function (sel, pane) { return _.addClose(inst, sel, pane); } - , addPinBtn: function (sel, pane) { return _.addPin(inst, sel, pane); } - }); - - // init state array to hold pin-buttons - for (var i=0; i<4; i++) { - var pane = $.layout.config.borderPanes[i]; - inst.state[pane].pins = []; - } - - // auto-init buttons onLoad if option is enabled - if ( inst.options.autoBindCustomButtons ) - _.init(inst); - } - -, _unload: function (inst) { - // TODO: unbind all buttons??? - } + /** + * Searches for .ui-layout-button-xxx elements and auto-binds them as layout-buttons + * + * @see _create() + * + * @param {Object} inst Layout Instance object + */ + init: function (inst) { + var pre = "ui-layout-button-" + , layout = inst.options.name || "" + , name; + $.each("toggle,open,close,pin,toggle-slide,open-slide".split(","), function (i, action) { + $.each($.layout.config.borderPanes, function (ii, pane) { + $("."+pre+action+"-"+pane).each(function(){ + // if button was previously 'bound', data.layoutName was set, but is blank if layout has no 'name' + name = $(this).data("layoutName") || $(this).attr("layoutName"); + if (name == undefined || name === layout) + inst.bindButton(this, action, pane); + }); + }); + }); + } + + /** + * Helper function to validate params received by addButton utilities + * + * Two classes are added to the element, based on the buttonClass... + * The type of button is appended to create the 2nd className: + * - ui-layout-button-pin // action btnClass + * - ui-layout-button-pin-west // action btnClass + pane + * - ui-layout-button-toggle + * - ui-layout-button-open + * - ui-layout-button-close + * + * @param {Object} inst Layout Instance object + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. + * + * @return {Array.} If both params valid, the element matching 'selector' in a jQuery wrapper - otherwise returns null + */ +, get: function (inst, selector, pane, action) { + var $E = $(selector) + , o = inst.options + , err = o.showErrorMessages + ; + if (!$E.length) { // element not found + if (err) $.layout.msg(lang.errButton + lang.selector +": "+ selector, true); + } + else if ($.inArray(pane, $.layout.config.borderPanes) < 0) { // invalid 'pane' sepecified + if (err) $.layout.msg(lang.errButton + lang.pane +": "+ pane, true); + $E = $(""); // NO BUTTON + } + else { // VALID + var btn = o[pane].buttonClass +"-"+ action; + $E .addClass( btn +" "+ btn +"-"+ pane ) + .data("layoutName", o.name); // add layout identifier - even if blank! + } + return $E; + } + + + /** + * NEW syntax for binding layout-buttons - will eventually replace addToggle, addOpen, etc. + * + * @param {Object} inst Layout Instance object + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} action + * @param {string} pane + */ +, bind: function (inst, selector, action, pane) { + var _ = $.layout.buttons; + switch (action.toLowerCase()) { + case "toggle": _.addToggle (inst, selector, pane); break; + case "open": _.addOpen (inst, selector, pane); break; + case "close": _.addClose (inst, selector, pane); break; + case "pin": _.addPin (inst, selector, pane); break; + case "toggle-slide": _.addToggle (inst, selector, pane, true); break; + case "open-slide": _.addOpen (inst, selector, pane, true); break; + } + return inst; + } + + /** + * Add a custom Toggler button for a pane + * + * @param {Object} inst Layout Instance object + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. + * @param {boolean=} slide true = slide-open, false = pin-open + */ +, addToggle: function (inst, selector, pane, slide) { + $.layout.buttons.get(inst, selector, pane, "toggle") + .click(function(evt){ + inst.toggle(pane, !!slide); + evt.stopPropagation(); + }); + return inst; + } + + /** + * Add a custom Open button for a pane + * + * @param {Object} inst Layout Instance object + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. + * @param {boolean=} slide true = slide-open, false = pin-open + */ +, addOpen: function (inst, selector, pane, slide) { + $.layout.buttons.get(inst, selector, pane, "open") + .attr("title", lang.Open) + .click(function (evt) { + inst.open(pane, !!slide); + evt.stopPropagation(); + }); + return inst; + } + + /** + * Add a custom Close button for a pane + * + * @param {Object} inst Layout Instance object + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. + */ +, addClose: function (inst, selector, pane) { + $.layout.buttons.get(inst, selector, pane, "close") + .attr("title", lang.Close) + .click(function (evt) { + inst.close(pane); + evt.stopPropagation(); + }); + return inst; + } + + /** + * Add a custom Pin button for a pane + * + * Four classes are added to the element, based on the paneClass for the associated pane... + * Assuming the default paneClass and the pin is 'up', these classes are added for a west-pane pin: + * - ui-layout-pane-pin + * - ui-layout-pane-west-pin + * - ui-layout-pane-pin-up + * - ui-layout-pane-west-pin-up + * + * @param {Object} inst Layout Instance object + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the pin is for: 'north', 'south', etc. + */ +, addPin: function (inst, selector, pane) { + var _ = $.layout.buttons + , $E = _.get(inst, selector, pane, "pin"); + if ($E.length) { + var s = inst.state[pane]; + $E.click(function (evt) { + _.setPinState(inst, $(this), pane, (s.isSliding || s.isClosed)); + if (s.isSliding || s.isClosed) inst.open( pane ); // change from sliding to open + else inst.close( pane ); // slide-closed + evt.stopPropagation(); + }); + // add up/down pin attributes and classes + _.setPinState(inst, $E, pane, (!s.isClosed && !s.isSliding)); + // add this pin to the pane data so we can 'sync it' automatically + // PANE.pins key is an array so we can store multiple pins for each pane + s.pins.push( selector ); // just save the selector string + } + return inst; + } + + /** + * Change the class of the pin button to make it look 'up' or 'down' + * + * @see addPin(), syncPins() + * + * @param {Object} inst Layout Instance object + * @param {Array.} $Pin The pin-span element in a jQuery wrapper + * @param {string} pane These are the params returned to callbacks by layout() + * @param {boolean} doPin true = set the pin 'down', false = set it 'up' + */ +, setPinState: function (inst, $Pin, pane, doPin) { + var updown = $Pin.attr("pin"); + if (updown && doPin === (updown=="down")) return; // already in correct state + var + pin = inst.options[pane].buttonClass +"-pin" + , side = pin +"-"+ pane + , UP = pin +"-up "+ side +"-up" + , DN = pin +"-down "+side +"-down" + ; + $Pin + .attr("pin", doPin ? "down" : "up") // logic + .attr("title", doPin ? lang.Unpin : lang.Pin) + .removeClass( doPin ? UP : DN ) + .addClass( doPin ? DN : UP ) + ; + } + + /** + * INTERNAL function to sync 'pin buttons' when pane is opened or closed + * Unpinned means the pane is 'sliding' - ie, over-top of the adjacent panes + * + * @see open(), close() + * + * @param {Object} inst Layout Instance object + * @param {string} pane These are the params returned to callbacks by layout() + * @param {boolean} doPin True means set the pin 'down', False means 'up' + */ +, syncPinBtns: function (inst, pane, doPin) { + // REAL METHOD IS _INSIDE_ LAYOUT - THIS IS HERE JUST FOR REFERENCE + $.each(state[pane].pins, function (i, selector) { + $.layout.buttons.setPinState(inst, $(selector), pane, doPin); + }); + } + + +, _load: function (inst) { + var _ = $.layout.buttons; + // ADD Button methods to Layout Instance + // Note: sel = jQuery Selector string + $.extend( inst, { + bindButton: function (sel, action, pane) { return _.bind(inst, sel, action, pane); } + // DEPRECATED METHODS + , addToggleBtn: function (sel, pane, slide) { return _.addToggle(inst, sel, pane, slide); } + , addOpenBtn: function (sel, pane, slide) { return _.addOpen(inst, sel, pane, slide); } + , addCloseBtn: function (sel, pane) { return _.addClose(inst, sel, pane); } + , addPinBtn: function (sel, pane) { return _.addPin(inst, sel, pane); } + }); + + // init state array to hold pin-buttons + for (var i=0; i<4; i++) { + var pane = $.layout.config.borderPanes[i]; + inst.state[pane].pins = []; + } + + // auto-init buttons onLoad if option is enabled + if ( inst.options.autoBindCustomButtons ) + _.init(inst); + } + +, _unload: function (inst) { + // TODO: unbind all buttons??? + } }; @@ -5358,7 +5358,7 @@ $.layout.onLoad.push( $.layout.buttons._load ); * jquery.layout.browserZoom 1.0 * $Date$ * - * Copyright (c) 2012 + * Copyright (c) 2012 * Kevin Dalman (http://allpro.net) * * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html) @@ -5379,66 +5379,66 @@ $.layout.defaults.browserZoomCheckInterval = 1000; $.layout.optionsMap.layout.push("browserZoomCheckInterval"); /* - * browserZoom methods + * browserZoom methods */ $.layout.browserZoom = { - _init: function (inst) { - // abort if browser does not need this check - if ($.layout.browserZoom.ratio() !== false) - $.layout.browserZoom._setTimer(inst); - } - -, _setTimer: function (inst) { - // abort if layout destroyed or browser does not need this check - if (inst.destroyed) return; - var o = inst.options - , s = inst.state - // don't need check if inst has parentLayout, but check occassionally in case parent destroyed! - // MINIMUM 100ms interval, for performance - , ms = inst.hasParentLayout ? 5000 : Math.max( o.browserZoomCheckInterval, 100 ) - ; - // set the timer - setTimeout(function(){ - if (inst.destroyed || !o.resizeWithWindow) return; - var d = $.layout.browserZoom.ratio(); - if (d !== s.browserZoom) { - s.browserZoom = d; - inst.resizeAll(); - } - // set a NEW timeout - $.layout.browserZoom._setTimer(inst); - } - , ms ); - } - -, ratio: function () { - var w = window - , s = screen - , d = document - , dE = d.documentElement || d.body - , b = $.layout.browser - , v = b.version - , r, sW, cW - ; - // we can ignore all browsers that fire window.resize event onZoom - if ((b.msie && v > 8) - || !b.msie - ) return false; // don't need to track zoom - - if (s.deviceXDPI) - return calc(s.deviceXDPI, s.systemXDPI); - // everything below is just for future reference! - if (b.webkit && (r = d.body.getBoundingClientRect)) - return calc((r.left - r.right), d.body.offsetWidth); - if (b.webkit && (sW = w.outerWidth)) - return calc(sW, w.innerWidth); - if ((sW = s.width) && (cW = dE.clientWidth)) - return calc(sW, cW); - return false; // no match, so cannot - or don't need to - track zoom - - function calc (x,y) { return (parseInt(x,10) / parseInt(y,10) * 100).toFixed(); } - } + _init: function (inst) { + // abort if browser does not need this check + if ($.layout.browserZoom.ratio() !== false) + $.layout.browserZoom._setTimer(inst); + } + +, _setTimer: function (inst) { + // abort if layout destroyed or browser does not need this check + if (inst.destroyed) return; + var o = inst.options + , s = inst.state + // don't need check if inst has parentLayout, but check occassionally in case parent destroyed! + // MINIMUM 100ms interval, for performance + , ms = inst.hasParentLayout ? 5000 : Math.max( o.browserZoomCheckInterval, 100 ) + ; + // set the timer + setTimeout(function(){ + if (inst.destroyed || !o.resizeWithWindow) return; + var d = $.layout.browserZoom.ratio(); + if (d !== s.browserZoom) { + s.browserZoom = d; + inst.resizeAll(); + } + // set a NEW timeout + $.layout.browserZoom._setTimer(inst); + } + , ms ); + } + +, ratio: function () { + var w = window + , s = screen + , d = document + , dE = d.documentElement || d.body + , b = $.layout.browser + , v = b.version + , r, sW, cW + ; + // we can ignore all browsers that fire window.resize event onZoom + if ((b.msie && v > 8) + || !b.msie + ) return false; // don't need to track zoom + + if (s.deviceXDPI) + return calc(s.deviceXDPI, s.systemXDPI); + // everything below is just for future reference! + if (b.webkit && (r = d.body.getBoundingClientRect)) + return calc((r.left - r.right), d.body.offsetWidth); + if (b.webkit && (sW = w.outerWidth)) + return calc(sW, w.innerWidth); + if ((sW = s.width) && (cW = dE.clientWidth)) + return calc(sW, cW); + return false; // no match, so cannot - or don't need to - track zoom + + function calc (x,y) { return (parseInt(x,10) / parseInt(y,10) * 100).toFixed(); } + } }; // add initialization method to Layout's onLoad array of functions diff --git a/src/avrdude/atmel-docs/EDBG/common/jquery/theme-redmond/jquery-ui-1.8.2.custom.css b/src/avrdude/atmel-docs/EDBG/common/jquery/theme-redmond/jquery-ui-1.8.2.custom.css index 0b1736320b8..fb7ae2d6122 100644 --- a/src/avrdude/atmel-docs/EDBG/common/jquery/theme-redmond/jquery-ui-1.8.2.custom.css +++ b/src/avrdude/atmel-docs/EDBG/common/jquery/theme-redmond/jquery-ui-1.8.2.custom.css @@ -300,7 +300,7 @@ .ui-selectable-helper { border:1px dotted black } /* Autocomplete ----------------------------------*/ -.ui-autocomplete { position: absolute; cursor: default; } +.ui-autocomplete { position: absolute; cursor: default; } .ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; } /* workarounds */ @@ -309,33 +309,33 @@ /* Menu ----------------------------------*/ .ui-menu { - list-style:none; - padding: 2px; - margin: 0; - display:block; + list-style:none; + padding: 2px; + margin: 0; + display:block; } .ui-menu .ui-menu { - margin-top: -3px; + margin-top: -3px; } .ui-menu .ui-menu-item { - margin:0; - padding: 0; - zoom: 1; - float: left; - clear: left; - width: 100%; + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; } .ui-menu .ui-menu-item a { - text-decoration:none; - display:block; - padding:.2em .4em; - line-height:1.5; - zoom:1; + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; } .ui-menu .ui-menu-item a.ui-state-hover, .ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; + font-weight: normal; + margin: -1px; } /* Button ----------------------------------*/ @@ -343,8 +343,8 @@ .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } /*button text element */ .ui-button .ui-button-text { display: block; line-height: 1.4; } @@ -376,7 +376,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad ----------------------------------*/ .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } .ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } diff --git a/src/avrdude/atmel-docs/EDBG/common/jquery/treeview/jquery.treeview.css b/src/avrdude/atmel-docs/EDBG/common/jquery/treeview/jquery.treeview.css index d7e2c002a4f..0ea76217138 100644 --- a/src/avrdude/atmel-docs/EDBG/common/jquery/treeview/jquery.treeview.css +++ b/src/avrdude/atmel-docs/EDBG/common/jquery/treeview/jquery.treeview.css @@ -1,35 +1,35 @@ -.treeview, .treeview ul { - padding: 0; - margin: 0; - list-style: none; +.treeview, .treeview ul { + padding: 0; + margin: 0; + list-style: none; } .treeview ul { - background-color: white; - margin-top: 4px; + background-color: white; + margin-top: 4px; } .treeview .hitarea { - background: url(images/treeview-default.gif) -64px -25px no-repeat; - height: 16px; - width: 16px; - margin-left: -16px; - float: left; - cursor: pointer; + background: url(images/treeview-default.gif) -64px -25px no-repeat; + height: 16px; + width: 16px; + margin-left: -16px; + float: left; + cursor: pointer; } /* fix for IE6 */ * html .hitarea { - display: inline; - float:none; + display: inline; + float:none; } -.treeview li { - margin: 0; - padding: 3px 0 3px 16px; +.treeview li { + margin: 0; + padding: 3px 0 3px 16px; } .treeview a.selected { - background-color: #eee; + background-color: #eee; } #treecontrol { margin: 1em 0; display: none; } @@ -42,23 +42,23 @@ .treeview .expandable-hitarea { background-position: -80px -3px; } .treeview li.last { background-position: 0 -1766px } -.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(images/treeview-default.gif); } +.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(images/treeview-default.gif); } .treeview li.lastCollapsable { background-position: 0 -111px } .treeview li.lastExpandable { background-position: -32px -67px } .treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; } .treeview-red li { background-image: url(images/treeview-red-line.gif); } -.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(images/treeview-red.gif); } +.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(images/treeview-red.gif); } .treeview-black li { background-image: url(images/treeview-black-line.gif); } -.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(images/treeview-black.gif); } +.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(images/treeview-black.gif); } .treeview-gray li { background-image: url(images/treeview-gray-line.gif); } -.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(images/treeview-gray.gif); } +.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(images/treeview-gray.gif); } .treeview-famfamfam li { background-image: url(images/treeview-famfamfam-line.gif); } -.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(images/treeview-famfamfam.gif); } +.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(images/treeview-famfamfam.gif); } .filetree li { padding: 3px 0 2px 16px; } @@ -71,15 +71,15 @@ html, body {height:100%; margin: 0; padding: 0; } /* html>body { - font-size: 16px; - font-size: 68.75%; + font-size: 16px; + font-size: 68.75%; } Reset Base Font Size */ /* body { - font-family: Verdana, helvetica, arial, sans-serif; - font-size: 68.75%; - background: #fff; - color: #333; -} */ + font-family: Verdana, helvetica, arial, sans-serif; + font-size: 68.75%; + background: #fff; + color: #333; +} */ a img { border: none; } \ No newline at end of file diff --git a/src/avrdude/atmel-docs/EDBG/common/jquery/treeview/jquery.treeview.min.js b/src/avrdude/atmel-docs/EDBG/common/jquery/treeview/jquery.treeview.min.js index f9b490d3ee8..0104781bc4e 100644 --- a/src/avrdude/atmel-docs/EDBG/common/jquery/treeview/jquery.treeview.min.js +++ b/src/avrdude/atmel-docs/EDBG/common/jquery/treeview/jquery.treeview.min.js @@ -1,6 +1,6 @@ /* * Treeview 1.4 - jQuery plugin to hide and show branches of a tree - * + * * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ * http://docs.jquery.com/Plugins/Treeview * diff --git a/src/avrdude/atmel-docs/EDBG/common/main.js b/src/avrdude/atmel-docs/EDBG/common/main.js index 96b6a86c652..d3f0acf1793 100644 --- a/src/avrdude/atmel-docs/EDBG/common/main.js +++ b/src/avrdude/atmel-docs/EDBG/common/main.js @@ -10,30 +10,30 @@ var noAnimations=false; $(document).ready(function() { - /* Local addition */ - $("a").filter(function() { - return this.hostname && this.hostname !== location.hostname; - }).addClass('external'); + /* Local addition */ + $("a").filter(function() { + return this.hostname && this.hostname !== location.hostname; + }).addClass('external'); - // When you click on a link to an anchor, scroll down - // 105 px to cope with the fact that the banner - // hides the top 95px or so of the page. - // This code deals with the problem when - // you click on a link within a page. - $('a[href*=#]').click(function() { - if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') - && location.hostname == this.hostname) { - var $target = $(this.hash); - $target = $target.length && $target - || $('[name=' + this.hash.slice(1) +']'); - if (!(this.hash == "#searchDiv" || this.hash == "#treeDiv" || this.hash == "") && $target.length) { - var targetOffset = $target.offset().top - 120; - $('html,body') - .animate({scrollTop: targetOffset}, 200); - return false; - } - } - }); + // When you click on a link to an anchor, scroll down + // 105 px to cope with the fact that the banner + // hides the top 95px or so of the page. + // This code deals with the problem when + // you click on a link within a page. + $('a[href*=#]').click(function() { + if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') + && location.hostname == this.hostname) { + var $target = $(this.hash); + $target = $target.length && $target + || $('[name=' + this.hash.slice(1) +']'); + if (!(this.hash == "#searchDiv" || this.hash == "#treeDiv" || this.hash == "") && $target.length) { + var targetOffset = $target.offset().top - 120; + $('html,body') + .animate({scrollTop: targetOffset}, 200); + return false; + } + } + }); // $("#showHideHighlight").button(); //add jquery button styling to 'Go' button //Generate tabs in nav-pane with JQuery @@ -58,7 +58,7 @@ $(document).ready(function() { $("#tocLoading").attr("style", "display:none;"); // $("#ulTreeDiv").attr("style","display:block;"); - //.searchButton is the css class applied to 'Go' button + //.searchButton is the css class applied to 'Go' button $(function() { $("button", ".searchButton").button(); @@ -80,16 +80,16 @@ $(document).ready(function() { syncToc(); //Synchronize the toc tree with the content pane, when loading the page. //$("#doSearch").button(); //add jquery button styling to 'Go' button - // When you click on a link to an anchor, scroll down + // When you click on a link to an anchor, scroll down // 120 px to cope with the fact that the banner // hides the top 95px or so of the page. - // This code deals with the problem when - // you click on a link from another page. + // This code deals with the problem when + // you click on a link from another page. var hash = window.location.hash; - if(hash){ - var targetOffset = $(hash).offset().top - 120; - $('html,body').animate({scrollTop: targetOffset}, 200); - return false; + if(hash){ + var targetOffset = $(hash).offset().top - 120; + $('html,body').animate({scrollTop: targetOffset}, 200); + return false; } }); @@ -213,7 +213,7 @@ function showHideToc() { if (showHideButton != undefined && showHideButton.hasClass("pointLeft")) { //Hide TOC showHideButton.removeClass('pointLeft').addClass('pointRight'); - + if(noAnimations) { leftNavigation.css("display", "none"); content.css("margin", "125px 0 0 0"); @@ -244,7 +244,7 @@ function searchHighlight(searchText) { highlightOn = true; if (searchText != undefined) { var wList; - var sList = new Array(); //stem list + var sList = new Array(); //stem list //Highlight the search terms searchText = searchText.toLowerCase().replace(/<\//g, "_st_").replace(/\$_/g, "_di_").replace(/\.|%2C|%3B|%21|%3A|@|\/|\*/g, " ").replace(/(%20)+/g, " ").replace(/_st_/g, " EDBG interface overview - - Atmel EDBG-based Tools Protocols

      • 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